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