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