/work/obj-fuzz/dist/include/mozilla/dom/DOMJSClass.h
Line | Count | Source (jump to first uncovered line) |
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 file, |
5 | | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_dom_DOMJSClass_h |
8 | | #define mozilla_dom_DOMJSClass_h |
9 | | |
10 | | #include "jsapi.h" |
11 | | #include "jsfriendapi.h" |
12 | | #include "js/Wrapper.h" |
13 | | #include "mozilla/Assertions.h" |
14 | | #include "mozilla/Attributes.h" |
15 | | #include "mozilla/Likely.h" |
16 | | |
17 | | #include "mozilla/dom/PrototypeList.h" // auto-generated |
18 | | |
19 | | #include "mozilla/dom/JSSlots.h" |
20 | | |
21 | | class nsCycleCollectionParticipant; |
22 | | |
23 | | // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. |
24 | 118 | #define DOM_PROTOTYPE_SLOT JSCLASS_GLOBAL_SLOT_COUNT |
25 | | |
26 | | // Keep this count up to date with any extra global slots added above. |
27 | 3 | #define DOM_GLOBAL_SLOTS 1 |
28 | | |
29 | | // We use these flag bits for the new bindings. |
30 | 3.11M | #define JSCLASS_DOM_GLOBAL JSCLASS_USERBIT1 |
31 | 0 | #define JSCLASS_IS_DOMIFACEANDPROTOJSCLASS JSCLASS_USERBIT2 |
32 | | |
33 | | namespace mozilla { |
34 | | namespace dom { |
35 | | |
36 | | /** |
37 | | * Returns true if code running in the given JSContext is allowed to access |
38 | | * [SecureContext] API on the given JSObject. |
39 | | * |
40 | | * [SecureContext] API exposure is restricted to use by code in a Secure |
41 | | * Contexts: |
42 | | * |
43 | | * https://w3c.github.io/webappsec-secure-contexts/ |
44 | | * |
45 | | * Since we want [SecureContext] exposure to depend on the privileges of the |
46 | | * running code (rather than the privileges of an object's creator), this |
47 | | * function checks to see whether the given JSContext's Realm is flagged |
48 | | * as a Secure Context. That allows us to make sure that system principal code |
49 | | * (which is marked as a Secure Context) can access Secure Context API on an |
50 | | * object in a different realm, regardless of whether the other realm is a |
51 | | * Secure Context or not. |
52 | | * |
53 | | * Checking the JSContext's Realm doesn't work for expanded principal |
54 | | * globals accessing a Secure Context web page though (e.g. those used by frame |
55 | | * scripts). To handle that we fall back to checking whether the JSObject came |
56 | | * from a Secure Context. |
57 | | * |
58 | | * Note: We'd prefer this function to live in BindingUtils.h, but we need to |
59 | | * call it in this header, and BindingUtils.h includes us (i.e. we'd have a |
60 | | * circular dependency between headers if it lived there). |
61 | | */ |
62 | | inline bool |
63 | | IsSecureContextOrObjectIsFromSecureContext(JSContext* aCx, JSObject* aObj) |
64 | 0 | { |
65 | 0 | MOZ_ASSERT(!js::IsWrapper(aObj)); |
66 | 0 | return JS::GetIsSecureContext(js::GetContextRealm(aCx)) || |
67 | 0 | JS::GetIsSecureContext(js::GetNonCCWObjectRealm(aObj)); |
68 | 0 | } |
69 | | |
70 | | typedef bool |
71 | | (* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper, |
72 | | JS::Handle<JSObject*> obj, JS::Handle<jsid> id, |
73 | | JS::MutableHandle<JS::PropertyDescriptor> desc); |
74 | | |
75 | | typedef bool |
76 | | (* EnumerateOwnProperties)(JSContext* cx, JS::Handle<JSObject*> wrapper, |
77 | | JS::Handle<JSObject*> obj, |
78 | | JS::AutoIdVector& props); |
79 | | |
80 | | typedef bool |
81 | | (* DeleteNamedProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper, |
82 | | JS::Handle<JSObject*> obj, JS::Handle<jsid> id, |
83 | | JS::ObjectOpResult& opresult); |
84 | | |
85 | | // Returns true if the given global is of a type whose bit is set in |
86 | | // aNonExposedGlobals. |
87 | | bool |
88 | | IsNonExposedGlobal(JSContext* aCx, JSObject* aGlobal, |
89 | | uint32_t aNonExposedGlobals); |
90 | | |
91 | | struct ConstantSpec |
92 | | { |
93 | | const char* name; |
94 | | JS::Value value; |
95 | | }; |
96 | | |
97 | | typedef bool (*PropertyEnabled)(JSContext* cx, JSObject* global); |
98 | | |
99 | | namespace GlobalNames { |
100 | | // The names of our possible globals. These are the names of the actual |
101 | | // interfaces, not of the global names used to refer to them in IDL [Exposed] |
102 | | // annotations. |
103 | | static const uint32_t Window = 1u << 0; |
104 | | static const uint32_t BackstagePass = 1u << 1; |
105 | | static const uint32_t DedicatedWorkerGlobalScope = 1u << 2; |
106 | | static const uint32_t SharedWorkerGlobalScope = 1u << 3; |
107 | | static const uint32_t ServiceWorkerGlobalScope = 1u << 4; |
108 | | static const uint32_t WorkerDebuggerGlobalScope = 1u << 5; |
109 | | static const uint32_t WorkletGlobalScope = 1u << 6; |
110 | | static const uint32_t AudioWorkletGlobalScope = 1u << 7; |
111 | | } // namespace GlobalNames |
112 | | |
113 | | struct PrefableDisablers { |
114 | 4 | inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const { |
115 | 4 | // Reading "enabled" on a worker thread is technically undefined behavior, |
116 | 4 | // because it's written only on main threads, with no barriers of any sort. |
117 | 4 | // So we want to avoid doing that. But we don't particularly want to make |
118 | 4 | // expensive NS_IsMainThread calls here. |
119 | 4 | // |
120 | 4 | // The good news is that "enabled" is only written for things that have a |
121 | 4 | // Pref annotation, and such things can never be exposed on non-Window |
122 | 4 | // globals; our IDL parser enforces that. So as long as we check our |
123 | 4 | // exposure set before checking "enabled" we will be ok. |
124 | 4 | if (nonExposedGlobals && |
125 | 4 | IsNonExposedGlobal(cx, JS::GetNonCCWObjectGlobal(obj), |
126 | 4 | nonExposedGlobals)) { |
127 | 0 | return false; |
128 | 0 | } |
129 | 4 | if (!enabled) { |
130 | 0 | return false; |
131 | 0 | } |
132 | 4 | if (secureContext && !IsSecureContextOrObjectIsFromSecureContext(cx, obj)) { |
133 | 0 | return false; |
134 | 0 | } |
135 | 4 | if (enabledFunc && !enabledFunc(cx, JS::GetNonCCWObjectGlobal(obj))) { |
136 | 1 | return false; |
137 | 1 | } |
138 | 3 | return true; |
139 | 3 | } |
140 | | |
141 | | // A boolean indicating whether this set of specs is enabled. Not const |
142 | | // because it will change at runtime if the corresponding pref is changed. |
143 | | bool enabled; |
144 | | |
145 | | // A boolean indicating whether a Secure Context is required. |
146 | | const bool secureContext; |
147 | | |
148 | | // Bitmask of global names that we should not be exposed in. |
149 | | const uint16_t nonExposedGlobals; |
150 | | |
151 | | // A function pointer to a function that can say the property is disabled |
152 | | // even if "enabled" is set to true. If the pointer is null the value of |
153 | | // "enabled" is used as-is. |
154 | | const PropertyEnabled enabledFunc; |
155 | | }; |
156 | | |
157 | | template<typename T> |
158 | | struct Prefable { |
159 | 6 | inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const { |
160 | 6 | MOZ_ASSERT(!js::IsWrapper(obj)); |
161 | 6 | if (MOZ_LIKELY(!disablers)) { |
162 | 2 | return true; |
163 | 2 | } |
164 | 4 | return disablers->isEnabled(cx, obj); |
165 | 4 | } mozilla::dom::Prefable<JSFunctionSpec const>::isEnabled(JSContext*, JS::Handle<JSObject*>) const Line | Count | Source | 159 | 5 | inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const { | 160 | 5 | MOZ_ASSERT(!js::IsWrapper(obj)); | 161 | 5 | if (MOZ_LIKELY(!disablers)) { | 162 | 1 | return true; | 163 | 1 | } | 164 | 4 | return disablers->isEnabled(cx, obj); | 165 | 4 | } |
mozilla::dom::Prefable<JSPropertySpec const>::isEnabled(JSContext*, JS::Handle<JSObject*>) const Line | Count | Source | 159 | 1 | inline bool isEnabled(JSContext* cx, JS::Handle<JSObject*> obj) const { | 160 | 1 | MOZ_ASSERT(!js::IsWrapper(obj)); | 161 | 1 | if (MOZ_LIKELY(!disablers)) { | 162 | 1 | return true; | 163 | 1 | } | 164 | 0 | return disablers->isEnabled(cx, obj); | 165 | 0 | } |
Unexecuted instantiation: mozilla::dom::Prefable<mozilla::dom::ConstantSpec const>::isEnabled(JSContext*, JS::Handle<JSObject*>) const |
166 | | |
167 | | // Things that can disable this set of specs. |nullptr| means "cannot be |
168 | | // disabled". |
169 | | PrefableDisablers* const disablers; |
170 | | |
171 | | // Array of specs, terminated in whatever way is customary for T. |
172 | | // Null to indicate a end-of-array for Prefable, when such an |
173 | | // indicator is needed. |
174 | | const T* const specs; |
175 | | }; |
176 | | |
177 | | enum PropertyType { |
178 | | eStaticMethod, |
179 | | eStaticAttribute, |
180 | | eMethod, |
181 | | eAttribute, |
182 | | eUnforgeableMethod, |
183 | | eUnforgeableAttribute, |
184 | | eConstant, |
185 | | ePropertyTypeCount |
186 | | }; |
187 | | |
188 | | #define NUM_BITS_PROPERTY_INFO_TYPE 3 |
189 | | #define NUM_BITS_PROPERTY_INFO_PREF_INDEX 13 |
190 | | #define NUM_BITS_PROPERTY_INFO_SPEC_INDEX 16 |
191 | | |
192 | | struct PropertyInfo { |
193 | | private: |
194 | | // MSVC generates static initializers if we store a jsid here, even if |
195 | | // PropertyInfo has a constexpr constructor. See bug 1460341 and bug 1464036. |
196 | | uintptr_t mIdBits; |
197 | | public: |
198 | | // One of PropertyType, will be used for accessing the corresponding Duo in |
199 | | // NativePropertiesN.duos[]. |
200 | | uint32_t type: NUM_BITS_PROPERTY_INFO_TYPE; |
201 | | // The index to the corresponding Preable in Duo.mPrefables[]. |
202 | | uint32_t prefIndex: NUM_BITS_PROPERTY_INFO_PREF_INDEX; |
203 | | // The index to the corresponding spec in Duo.mPrefables[prefIndex].specs[]. |
204 | | uint32_t specIndex: NUM_BITS_PROPERTY_INFO_SPEC_INDEX; |
205 | | |
206 | 28 | void SetId(jsid aId) { |
207 | 28 | static_assert(sizeof(jsid) == sizeof(mIdBits), "jsid should fit in mIdBits"); |
208 | 28 | mIdBits = JSID_BITS(aId); |
209 | 28 | } |
210 | 200 | MOZ_ALWAYS_INLINE jsid Id() const { |
211 | 200 | return jsid::fromRawBits(mIdBits); |
212 | 200 | } |
213 | | }; |
214 | | |
215 | | static_assert(ePropertyTypeCount <= 1ull << NUM_BITS_PROPERTY_INFO_TYPE, |
216 | | "We have property type count that is > (1 << NUM_BITS_PROPERTY_INFO_TYPE)"); |
217 | | |
218 | | // Conceptually, NativeProperties has seven (Prefable<T>*, PropertyInfo*) duos |
219 | | // (where T is one of JSFunctionSpec, JSPropertySpec, or ConstantSpec), one for |
220 | | // each of: static methods and attributes, methods and attributes, unforgeable |
221 | | // methods and attributes, and constants. |
222 | | // |
223 | | // That's 14 pointers, but in most instances most of the duos are all null, and |
224 | | // there are many instances. To save space we use a variable-length type, |
225 | | // NativePropertiesN<N>, to hold the data and getters to access it. It has N |
226 | | // actual duos (stored in duos[]), plus four bits for each of the 7 possible |
227 | | // duos: 1 bit that states if that duo is present, and 3 that state that duo's |
228 | | // offset (if present) in duos[]. |
229 | | // |
230 | | // All duo accesses should be done via the getters, which contain assertions |
231 | | // that check we don't overrun the end of the struct. (The duo data members are |
232 | | // public only so they can be statically initialized.) These assertions should |
233 | | // never fail so long as (a) accesses to the variable-length part are guarded by |
234 | | // appropriate Has*() calls, and (b) all instances are well-formed, i.e. the |
235 | | // value of N matches the number of mHas* members that are true. |
236 | | // |
237 | | // We store all the property ids a NativePropertiesN owns in a single array of |
238 | | // PropertyInfo structs. Each struct contains an id and the information needed |
239 | | // to find the corresponding Prefable for the enabled check, as well as the |
240 | | // information needed to find the correct property descriptor in the |
241 | | // Prefable. We also store an array of indices into the PropertyInfo array, |
242 | | // sorted by bits of the corresponding jsid. Given a jsid, this allows us to |
243 | | // binary search for the index of the corresponding PropertyInfo, if any. |
244 | | // |
245 | | // Finally, we define a typedef of NativePropertiesN<7>, NativeProperties, which |
246 | | // we use as a "base" type used to refer to all instances of NativePropertiesN. |
247 | | // (7 is used because that's the maximum valid parameter, though any other |
248 | | // value 1..6 could also be used.) This is reasonable because of the |
249 | | // aforementioned assertions in the getters. Upcast() is used to convert |
250 | | // specific instances to this "base" type. |
251 | | // |
252 | | template <int N> |
253 | | struct NativePropertiesN { |
254 | | // Duo structs are stored in the duos[] array, and each element in the array |
255 | | // could require a different T. Therefore, we can't use the correct type for |
256 | | // mPrefables. Instead we use void* and cast to the correct type in the |
257 | | // getters. |
258 | | struct Duo { |
259 | | const /*Prefable<const T>*/ void* const mPrefables; |
260 | | PropertyInfo* const mPropertyInfos; |
261 | | }; |
262 | | |
263 | 4 | constexpr const NativePropertiesN<7>* Upcast() const { |
264 | 4 | return reinterpret_cast<const NativePropertiesN<7>*>(this); |
265 | 4 | } mozilla::dom::NativePropertiesN<1>::Upcast() const Line | Count | Source | 263 | 2 | constexpr const NativePropertiesN<7>* Upcast() const { | 264 | 2 | return reinterpret_cast<const NativePropertiesN<7>*>(this); | 265 | 2 | } |
mozilla::dom::NativePropertiesN<2>::Upcast() const Line | Count | Source | 263 | 2 | constexpr const NativePropertiesN<7>* Upcast() const { | 264 | 2 | return reinterpret_cast<const NativePropertiesN<7>*>(this); | 265 | 2 | } |
Unexecuted instantiation: mozilla::dom::NativePropertiesN<3>::Upcast() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<4>::Upcast() const |
266 | | |
267 | 2 | const PropertyInfo* PropertyInfos() const { |
268 | 2 | return duos[0].mPropertyInfos; |
269 | 2 | } |
270 | | |
271 | | #define DO(SpecT, FieldName) \ |
272 | | public: \ |
273 | | /* The bitfields indicating the duo's presence and (if present) offset. */ \ |
274 | | const uint32_t mHas##FieldName##s:1; \ |
275 | | const uint32_t m##FieldName##sOffset:3; \ |
276 | | private: \ |
277 | 9 | const Duo* FieldName##sDuo() const { \ |
278 | 9 | MOZ_ASSERT(Has##FieldName##s()); \ |
279 | 9 | return &duos[m##FieldName##sOffset]; \ |
280 | 9 | } \ mozilla::dom::NativePropertiesN<7>::StaticMethodsDuo() const Line | Count | Source | 277 | 6 | const Duo* FieldName##sDuo() const { \ | 278 | 6 | MOZ_ASSERT(Has##FieldName##s()); \ | 279 | 6 | return &duos[m##FieldName##sOffset]; \ | 280 | 6 | } \ |
mozilla::dom::NativePropertiesN<7>::StaticAttributesDuo() const Line | Count | Source | 277 | 3 | const Duo* FieldName##sDuo() const { \ | 278 | 3 | MOZ_ASSERT(Has##FieldName##s()); \ | 279 | 3 | return &duos[m##FieldName##sOffset]; \ | 280 | 3 | } \ |
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::ConstantsDuo() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::MethodsDuo() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::AttributesDuo() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableMethodsDuo() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableAttributesDuo() const |
281 | | public: \ |
282 | 20 | bool Has##FieldName##s() const { \ |
283 | 20 | return mHas##FieldName##s; \ |
284 | 20 | } \ mozilla::dom::NativePropertiesN<7>::HasStaticMethods() const Line | Count | Source | 282 | 4 | bool Has##FieldName##s() const { \ | 283 | 4 | return mHas##FieldName##s; \ | 284 | 4 | } \ |
mozilla::dom::NativePropertiesN<7>::HasStaticAttributes() const Line | Count | Source | 282 | 4 | bool Has##FieldName##s() const { \ | 283 | 4 | return mHas##FieldName##s; \ | 284 | 4 | } \ |
mozilla::dom::NativePropertiesN<7>::HasConstants() const Line | Count | Source | 282 | 4 | bool Has##FieldName##s() const { \ | 283 | 4 | return mHas##FieldName##s; \ | 284 | 4 | } \ |
mozilla::dom::NativePropertiesN<7>::HasMethods() const Line | Count | Source | 282 | 2 | bool Has##FieldName##s() const { \ | 283 | 2 | return mHas##FieldName##s; \ | 284 | 2 | } \ |
mozilla::dom::NativePropertiesN<7>::HasAttributes() const Line | Count | Source | 282 | 2 | bool Has##FieldName##s() const { \ | 283 | 2 | return mHas##FieldName##s; \ | 284 | 2 | } \ |
mozilla::dom::NativePropertiesN<7>::HasUnforgeableMethods() const Line | Count | Source | 282 | 2 | bool Has##FieldName##s() const { \ | 283 | 2 | return mHas##FieldName##s; \ | 284 | 2 | } \ |
mozilla::dom::NativePropertiesN<7>::HasUnforgeableAttributes() const Line | Count | Source | 282 | 2 | bool Has##FieldName##s() const { \ | 283 | 2 | return mHas##FieldName##s; \ | 284 | 2 | } \ |
|
285 | 6 | const Prefable<const SpecT>* FieldName##s() const { \ |
286 | 6 | return static_cast<const Prefable<const SpecT>*> \ |
287 | 6 | (FieldName##sDuo()->mPrefables); \ |
288 | 6 | } \ mozilla::dom::NativePropertiesN<7>::StaticMethods() const Line | Count | Source | 285 | 4 | const Prefable<const SpecT>* FieldName##s() const { \ | 286 | 4 | return static_cast<const Prefable<const SpecT>*> \ | 287 | 4 | (FieldName##sDuo()->mPrefables); \ | 288 | 4 | } \ |
mozilla::dom::NativePropertiesN<7>::StaticAttributes() const Line | Count | Source | 285 | 2 | const Prefable<const SpecT>* FieldName##s() const { \ | 286 | 2 | return static_cast<const Prefable<const SpecT>*> \ | 287 | 2 | (FieldName##sDuo()->mPrefables); \ | 288 | 2 | } \ |
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::Constants() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::Methods() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::Attributes() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableMethods() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableAttributes() const |
289 | 3 | PropertyInfo* FieldName##PropertyInfos() const { \ |
290 | 3 | return FieldName##sDuo()->mPropertyInfos; \ |
291 | 3 | } mozilla::dom::NativePropertiesN<7>::StaticMethodPropertyInfos() const Line | Count | Source | 289 | 2 | PropertyInfo* FieldName##PropertyInfos() const { \ | 290 | 2 | return FieldName##sDuo()->mPropertyInfos; \ | 291 | 2 | } |
mozilla::dom::NativePropertiesN<7>::StaticAttributePropertyInfos() const Line | Count | Source | 289 | 1 | PropertyInfo* FieldName##PropertyInfos() const { \ | 290 | 1 | return FieldName##sDuo()->mPropertyInfos; \ | 291 | 1 | } |
Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::MethodPropertyInfos() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::AttributePropertyInfos() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableMethodPropertyInfos() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::UnforgeableAttributePropertyInfos() const Unexecuted instantiation: mozilla::dom::NativePropertiesN<7>::ConstantPropertyInfos() const |
292 | | |
293 | | DO(JSFunctionSpec, StaticMethod) |
294 | | DO(JSPropertySpec, StaticAttribute) |
295 | | DO(JSFunctionSpec, Method) |
296 | | DO(JSPropertySpec, Attribute) |
297 | | DO(JSFunctionSpec, UnforgeableMethod) |
298 | | DO(JSPropertySpec, UnforgeableAttribute) |
299 | | DO(ConstantSpec, Constant) |
300 | | |
301 | | #undef DO |
302 | | |
303 | | // The index to the iterator method in MethodPropertyInfos() array. |
304 | | const int16_t iteratorAliasMethodIndex; |
305 | | // The number of PropertyInfo structs that the duos manage. This is the total |
306 | | // count across all duos. |
307 | | const uint16_t propertyInfoCount; |
308 | | // The sorted indices array from sorting property ids, which will be used when |
309 | | // we binary search for a property. |
310 | | uint16_t* sortedPropertyIndices; |
311 | | |
312 | | const Duo duos[N]; |
313 | | }; |
314 | | |
315 | | // Ensure the struct has the expected size. The 8 is for the bitfields plus |
316 | | // iteratorAliasMethodIndex and idsLength; the rest is for the idsSortedIndex, |
317 | | // and duos[]. |
318 | | static_assert(sizeof(NativePropertiesN<1>) == 8 + 3*sizeof(void*), "1 size"); |
319 | | static_assert(sizeof(NativePropertiesN<2>) == 8 + 5*sizeof(void*), "2 size"); |
320 | | static_assert(sizeof(NativePropertiesN<3>) == 8 + 7*sizeof(void*), "3 size"); |
321 | | static_assert(sizeof(NativePropertiesN<4>) == 8 + 9*sizeof(void*), "4 size"); |
322 | | static_assert(sizeof(NativePropertiesN<5>) == 8 + 11*sizeof(void*), "5 size"); |
323 | | static_assert(sizeof(NativePropertiesN<6>) == 8 + 13*sizeof(void*), "6 size"); |
324 | | static_assert(sizeof(NativePropertiesN<7>) == 8 + 15*sizeof(void*), "7 size"); |
325 | | |
326 | | // The "base" type. |
327 | | typedef NativePropertiesN<7> NativeProperties; |
328 | | |
329 | | struct NativePropertiesHolder |
330 | | { |
331 | | const NativeProperties* regular; |
332 | | const NativeProperties* chromeOnly; |
333 | | }; |
334 | | |
335 | | // Helper structure for Xrays for DOM binding objects. The same instance is used |
336 | | // for instances, interface objects and interface prototype objects of a |
337 | | // specific interface. |
338 | | struct NativePropertyHooks |
339 | | { |
340 | | // The hook to call for resolving indexed or named properties. May be null if |
341 | | // there can't be any. |
342 | | ResolveOwnProperty mResolveOwnProperty; |
343 | | // The hook to call for enumerating indexed or named properties. May be null |
344 | | // if there can't be any. |
345 | | EnumerateOwnProperties mEnumerateOwnProperties; |
346 | | // The hook to call to delete a named property. May be null if there are no |
347 | | // named properties or no named property deleter. On success (true return) |
348 | | // the "found" argument will be set to true if there was in fact such a named |
349 | | // property and false otherwise. If it's set to false, the caller is expected |
350 | | // to proceed with whatever deletion behavior it would have if there were no |
351 | | // named properties involved at all (i.e. if the hook were null). If it's set |
352 | | // to true, it will indicate via opresult whether the delete actually |
353 | | // succeeded. |
354 | | DeleteNamedProperty mDeleteNamedProperty; |
355 | | |
356 | | // The property arrays for this interface. |
357 | | NativePropertiesHolder mNativeProperties; |
358 | | |
359 | | // This will be set to the ID of the interface prototype object for the |
360 | | // interface, if it has one. If it doesn't have one it will be set to |
361 | | // prototypes::id::_ID_Count. |
362 | | prototypes::ID mPrototypeID; |
363 | | |
364 | | // This will be set to the ID of the interface object for the interface, if it |
365 | | // has one. If it doesn't have one it will be set to |
366 | | // constructors::id::_ID_Count. |
367 | | constructors::ID mConstructorID; |
368 | | |
369 | | // The NativePropertyHooks instance for the parent interface (for |
370 | | // ShimInterfaceInfo). |
371 | | const NativePropertyHooks* mProtoHooks; |
372 | | |
373 | | // The JSClass to use for expandos on our Xrays. Can be null, in which case |
374 | | // Xrays will use a default class of their choice. |
375 | | const JSClass* mXrayExpandoClass; |
376 | | }; |
377 | | |
378 | | enum DOMObjectType : uint8_t { |
379 | | eInstance, |
380 | | eGlobalInstance, |
381 | | eInterface, |
382 | | eInterfacePrototype, |
383 | | eGlobalInterfacePrototype, |
384 | | eNamedPropertiesObject |
385 | | }; |
386 | | |
387 | | inline |
388 | | bool |
389 | | IsInstance(DOMObjectType type) |
390 | 0 | { |
391 | 0 | return type == eInstance || type == eGlobalInstance; |
392 | 0 | } |
393 | | |
394 | | inline |
395 | | bool |
396 | | IsInterfacePrototype(DOMObjectType type) |
397 | 0 | { |
398 | 0 | return type == eInterfacePrototype || type == eGlobalInterfacePrototype; |
399 | 0 | } |
400 | | |
401 | | typedef JSObject* (*AssociatedGlobalGetter)(JSContext* aCx, |
402 | | JS::Handle<JSObject*> aObj); |
403 | | |
404 | | typedef JSObject* (*ProtoGetter)(JSContext* aCx); |
405 | | |
406 | | /** |
407 | | * Returns a handle to the relevant WebIDL prototype object for the current |
408 | | * compartment global (which may be a handle to null on out of memory). Once |
409 | | * allocated, the prototype object is guaranteed to exist as long as the global |
410 | | * does, since the global traces its array of WebIDL prototypes and |
411 | | * constructors. |
412 | | */ |
413 | | typedef JS::Handle<JSObject*> (*ProtoHandleGetter)(JSContext* aCx); |
414 | | |
415 | | // Special JSClass for reflected DOM objects. |
416 | | struct DOMJSClass |
417 | | { |
418 | | // It would be nice to just inherit from JSClass, but that precludes pure |
419 | | // compile-time initialization of the form |DOMJSClass = {...};|, since C++ |
420 | | // only allows brace initialization for aggregate/POD types. |
421 | | const js::Class mBase; |
422 | | |
423 | | // A list of interfaces that this object implements, in order of decreasing |
424 | | // derivedness. |
425 | | const prototypes::ID mInterfaceChain[MAX_PROTOTYPE_CHAIN_LENGTH]; |
426 | | |
427 | | // We store the DOM object in reserved slot with index DOM_OBJECT_SLOT or in |
428 | | // the proxy private if we use a proxy object. |
429 | | // Sometimes it's an nsISupports and sometimes it's not; this class tells |
430 | | // us which it is. |
431 | | const bool mDOMObjectIsISupports; |
432 | | |
433 | | const NativePropertyHooks* mNativeHooks; |
434 | | |
435 | | // A callback to find the associated global for our C++ object. Note that |
436 | | // this is used in cases when that global is _changing_, so it will not match |
437 | | // the global of the JSObject* passed in to this function! |
438 | | AssociatedGlobalGetter mGetAssociatedGlobal; |
439 | | ProtoHandleGetter mGetProto; |
440 | | |
441 | | // This stores the CC participant for the native, null if this class does not |
442 | | // implement cycle collection or if it inherits from nsISupports (we can get |
443 | | // the CC participant by QI'ing in that case). |
444 | | nsCycleCollectionParticipant* mParticipant; |
445 | | |
446 | 3 | static const DOMJSClass* FromJSClass(const JSClass* base) { |
447 | 3 | MOZ_ASSERT(base->flags & JSCLASS_IS_DOMJSCLASS); |
448 | 3 | return reinterpret_cast<const DOMJSClass*>(base); |
449 | 3 | } |
450 | | |
451 | 3 | static const DOMJSClass* FromJSClass(const js::Class* base) { |
452 | 3 | return FromJSClass(Jsvalify(base)); |
453 | 3 | } |
454 | | |
455 | 3 | const JSClass* ToJSClass() const { return Jsvalify(&mBase); } |
456 | | }; |
457 | | |
458 | | // Special JSClass for DOM interface and interface prototype objects. |
459 | | struct DOMIfaceAndProtoJSClass |
460 | | { |
461 | | // It would be nice to just inherit from js::Class, but that precludes pure |
462 | | // compile-time initialization of the form |
463 | | // |DOMJSInterfaceAndPrototypeClass = {...};|, since C++ only allows brace |
464 | | // initialization for aggregate/POD types. |
465 | | const js::Class mBase; |
466 | | |
467 | | // Either eInterface, eInterfacePrototype, eGlobalInterfacePrototype or |
468 | | // eNamedPropertiesObject. |
469 | | DOMObjectType mType; // uint8_t |
470 | | |
471 | | // Boolean indicating whether this object wants a @@hasInstance property |
472 | | // pointing to InterfaceHasInstance defined on it. Only ever true for the |
473 | | // eInterface case. |
474 | | bool wantsInterfaceHasInstance; |
475 | | |
476 | | const prototypes::ID mPrototypeID; // uint16_t |
477 | | const uint32_t mDepth; |
478 | | |
479 | | const NativePropertyHooks* mNativeHooks; |
480 | | |
481 | | // The value to return for toString() on this interface or interface prototype |
482 | | // object. |
483 | | const char* mToString; |
484 | | |
485 | | ProtoGetter mGetParentProto; |
486 | | |
487 | 2 | static const DOMIfaceAndProtoJSClass* FromJSClass(const JSClass* base) { |
488 | 2 | MOZ_ASSERT(base->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS); |
489 | 2 | return reinterpret_cast<const DOMIfaceAndProtoJSClass*>(base); |
490 | 2 | } |
491 | 2 | static const DOMIfaceAndProtoJSClass* FromJSClass(const js::Class* base) { |
492 | 2 | return FromJSClass(Jsvalify(base)); |
493 | 2 | } |
494 | | |
495 | 0 | const JSClass* ToJSClass() const { return Jsvalify(&mBase); } |
496 | | }; |
497 | | |
498 | | class ProtoAndIfaceCache; |
499 | | |
500 | | inline bool |
501 | | DOMGlobalHasProtoAndIFaceCache(JSObject* global) |
502 | 54 | { |
503 | 54 | MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); |
504 | 54 | // This can be undefined if we GC while creating the global |
505 | 54 | return !js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).isUndefined(); |
506 | 54 | } |
507 | | |
508 | | inline bool |
509 | | HasProtoAndIfaceCache(JSObject* global) |
510 | 0 | { |
511 | 0 | if (!(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL)) { |
512 | 0 | return false; |
513 | 0 | } |
514 | 0 | return DOMGlobalHasProtoAndIFaceCache(global); |
515 | 0 | } |
516 | | |
517 | | inline ProtoAndIfaceCache* |
518 | | GetProtoAndIfaceCache(JSObject* global) |
519 | 58 | { |
520 | 58 | MOZ_ASSERT(js::GetObjectClass(global)->flags & JSCLASS_DOM_GLOBAL); |
521 | 58 | return static_cast<ProtoAndIfaceCache*>( |
522 | 58 | js::GetReservedSlot(global, DOM_PROTOTYPE_SLOT).toPrivate()); |
523 | 58 | } |
524 | | |
525 | | } // namespace dom |
526 | | } // namespace mozilla |
527 | | |
528 | | #endif /* mozilla_dom_DOMJSClass_h */ |