Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef nsXBLMaybeCompiled_h__
8 : #define nsXBLMaybeCompiled_h__
9 :
10 : #include "js/GCAPI.h"
11 :
12 : /*
13 : * A union containing either a pointer representing uncompiled source or a
14 : * JSObject* representing the compiled result. The class is templated on the
15 : * source object type.
16 : *
17 : * The purpose of abstracting this as a separate class is to allow it to be
18 : * wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject
19 : * pointer, when present.
20 : *
21 : * No implementation of rootKind() is provided, which prevents
22 : * Root<nsXBLMaybeCompiled<UncompiledT>> from being used.
23 : */
24 : template <class UncompiledT>
25 : class nsXBLMaybeCompiled
26 : {
27 : public:
28 3867 : nsXBLMaybeCompiled() : mUncompiled(BIT_UNCOMPILED) {}
29 :
30 0 : explicit nsXBLMaybeCompiled(UncompiledT* uncompiled)
31 0 : : mUncompiled(reinterpret_cast<uintptr_t>(uncompiled) | BIT_UNCOMPILED) {}
32 :
33 1289 : explicit nsXBLMaybeCompiled(JSObject* compiled) : mCompiled(compiled) {}
34 :
35 14095 : bool IsCompiled() const
36 : {
37 14095 : return !(mUncompiled & BIT_UNCOMPILED);
38 : }
39 :
40 1289 : UncompiledT* GetUncompiled() const
41 : {
42 1289 : MOZ_ASSERT(!IsCompiled(), "Attempt to get compiled function as uncompiled");
43 1289 : uintptr_t unmasked = mUncompiled & ~BIT_UNCOMPILED;
44 1289 : return reinterpret_cast<UncompiledT*>(unmasked);
45 : }
46 :
47 1146 : JSObject* GetJSFunction() const
48 : {
49 1146 : MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
50 1146 : if (mCompiled) {
51 968 : JS::ExposeObjectToActiveJS(mCompiled);
52 : }
53 1146 : return mCompiled;
54 : }
55 :
56 : // This is appropriate for use in tracing methods, etc.
57 579 : JSObject* GetJSFunctionPreserveColor() const
58 : {
59 579 : MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
60 579 : return mCompiled;
61 : }
62 :
63 : private:
64 2578 : JSObject*& UnsafeGetJSFunction()
65 : {
66 2578 : MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
67 2578 : return mCompiled;
68 : }
69 :
70 : enum { BIT_UNCOMPILED = 1 << 0 };
71 :
72 : union
73 : {
74 : // An pointer that represents the function before being compiled, with
75 : // BIT_UNCOMPILED set.
76 : uintptr_t mUncompiled;
77 :
78 : // The JS object for the compiled result.
79 : JSObject* mCompiled;
80 : };
81 :
82 : friend struct js::BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>;
83 : };
84 :
85 : /* Add support for JS::Heap<nsXBLMaybeCompiled>. */
86 : namespace JS {
87 :
88 : template <class UncompiledT>
89 : struct GCPolicy<nsXBLMaybeCompiled<UncompiledT>>
90 : {
91 2578 : static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
92 : };
93 :
94 : } // namespace JS
95 :
96 : namespace js {
97 :
98 : template <class UncompiledT>
99 : struct BarrierMethods<nsXBLMaybeCompiled<UncompiledT>>
100 : {
101 : typedef struct BarrierMethods<JSObject *> Base;
102 :
103 2578 : static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp,
104 : nsXBLMaybeCompiled<UncompiledT> prev,
105 : nsXBLMaybeCompiled<UncompiledT> next)
106 : {
107 2578 : if (next.IsCompiled()) {
108 2578 : Base::postBarrier(&functionp->UnsafeGetJSFunction(),
109 1289 : prev.IsCompiled() ? prev.UnsafeGetJSFunction() : nullptr,
110 : next.UnsafeGetJSFunction());
111 1289 : } else if (prev.IsCompiled()) {
112 0 : Base::postBarrier(&prev.UnsafeGetJSFunction(),
113 : prev.UnsafeGetJSFunction(),
114 : nullptr);
115 : }
116 2578 : }
117 : static void exposeToJS(nsXBLMaybeCompiled<UncompiledT> fun) {
118 : if (fun.IsCompiled()) {
119 : JS::ExposeObjectToActiveJS(fun.UnsafeGetJSFunction());
120 : }
121 : }
122 : };
123 :
124 : template <class T>
125 : struct IsHeapConstructibleType<nsXBLMaybeCompiled<T>>
126 : { // Yes, this is the exception to the rule. Sorry.
127 : static constexpr bool value = true;
128 : };
129 :
130 : template <class UncompiledT, class Wrapper>
131 1289 : class HeapBase<nsXBLMaybeCompiled<UncompiledT>, Wrapper>
132 : {
133 5270 : const Wrapper& wrapper() const {
134 5270 : return *static_cast<const Wrapper*>(this);
135 : }
136 :
137 2380 : Wrapper& wrapper() {
138 2380 : return *static_cast<Wrapper*>(this);
139 : }
140 :
141 5270 : const nsXBLMaybeCompiled<UncompiledT>* extract() const {
142 5270 : return wrapper().address();
143 : }
144 :
145 1091 : nsXBLMaybeCompiled<UncompiledT>* extract() {
146 1091 : return wrapper().unsafeGet();
147 : }
148 :
149 : public:
150 2256 : bool IsCompiled() const { return extract()->IsCompiled(); }
151 1289 : UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); }
152 1146 : JSObject* GetJSFunction() const { return extract()->GetJSFunction(); }
153 579 : JSObject* GetJSFunctionPreserveColor() const { return extract()->GetJSFunctionPreserveColor(); }
154 :
155 0 : void SetUncompiled(UncompiledT* source) {
156 0 : wrapper() = nsXBLMaybeCompiled<UncompiledT>(source);
157 0 : }
158 :
159 1289 : void SetJSFunction(JSObject* function) {
160 1289 : wrapper() = nsXBLMaybeCompiled<UncompiledT>(function);
161 1289 : }
162 :
163 1091 : JS::Heap<JSObject*>& AsHeapObject()
164 : {
165 1091 : MOZ_ASSERT(extract()->IsCompiled());
166 1091 : return *reinterpret_cast<JS::Heap<JSObject*>*>(this);
167 : }
168 : };
169 :
170 : } /* namespace js */
171 :
172 : #endif // nsXBLMaybeCompiled_h__
|