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