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