Object.h (5143B)
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 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef js_public_Object_h 8 #define js_public_Object_h 9 10 #include "js/shadow/Object.h" // JS::shadow::Object 11 12 #include "mozilla/Assertions.h" // MOZ_ASSERT 13 14 #include <stddef.h> // size_t 15 #include <stdint.h> // uint32_t 16 17 #include "jstypes.h" // JS_PUBLIC_API 18 19 #include "js/Class.h" // js::ESClass, JSCLASS_RESERVED_SLOTS 20 #include "js/Realm.h" // JS::GetCompartmentForRealm 21 #include "js/RootingAPI.h" // JS::{,Mutable}Handle 22 #include "js/Value.h" // JS::Value 23 24 struct JS_PUBLIC_API JSContext; 25 class JS_PUBLIC_API JSObject; 26 27 namespace JS { 28 29 class JS_PUBLIC_API Compartment; 30 31 /** 32 * Determine the ECMAScript "class" -- Date, String, RegExp, and all the other 33 * builtin object types (described in ECMAScript in terms of an objecting having 34 * "an [[ArrayBufferData]] internal slot" or similar language for other kinds of 35 * object -- of the provided object. 36 * 37 * If this function is passed a wrapper that can be unwrapped, the determination 38 * is performed on that object. If the wrapper can't be unwrapped, and it's not 39 * a wrapper that prefers to treat this operation as a failure, this function 40 * will indicate that the object is |js::ESClass::Other|. 41 */ 42 extern JS_PUBLIC_API bool GetBuiltinClass(JSContext* cx, Handle<JSObject*> obj, 43 js::ESClass* cls); 44 45 /** Get the |JSClass| of an object. */ 46 inline const JSClass* GetClass(const JSObject* obj) { 47 return reinterpret_cast<const shadow::Object*>(obj)->shape->base->clasp; 48 } 49 50 /** 51 * Get the |JS::Compartment*| of an object. 52 * 53 * Note that the compartment of an object in this realm, that is a 54 * cross-compartment wrapper around an object from another realm, is the 55 * compartment of this realm. 56 */ 57 static MOZ_ALWAYS_INLINE Compartment* GetCompartment(JSObject* obj) { 58 Realm* realm = reinterpret_cast<shadow::Object*>(obj)->shape->base->realm; 59 return GetCompartmentForRealm(realm); 60 } 61 62 /** 63 * Get the value stored in a reserved slot in an object. 64 * 65 * If |obj| is known to be a proxy and you're willing to use friend APIs, 66 * |js::GetProxyReservedSlot| in "js/Proxy.h" is very slightly more efficient. 67 */ 68 inline const Value& GetReservedSlot(JSObject* obj, size_t slot) { 69 MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetClass(obj))); 70 return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot); 71 } 72 73 namespace detail { 74 75 extern JS_PUBLIC_API void SetReservedSlotWithBarrier(JSObject* obj, size_t slot, 76 const Value& value); 77 78 } // namespace detail 79 80 /** 81 * Store a value in an object's reserved slot. 82 * 83 * This can be used with both native objects and proxies. However, if |obj| is 84 * known to be a proxy, |js::SetProxyReservedSlot| in "js/Proxy.h" is very 85 * slightly more efficient. 86 */ 87 inline void SetReservedSlot(JSObject* obj, size_t slot, const Value& value) { 88 MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetClass(obj))); 89 auto* sobj = reinterpret_cast<shadow::Object*>(obj); 90 if (sobj->slotRef(slot).isGCThing() || value.isGCThing()) { 91 detail::SetReservedSlotWithBarrier(obj, slot, value); 92 } else { 93 sobj->slotRef(slot) = value; 94 } 95 } 96 97 /** 98 * Helper function to get the pointer value (or nullptr if not set) from an 99 * object's reserved slot. The slot must contain either a PrivateValue(T*) or 100 * UndefinedValue. 101 */ 102 template <typename T> 103 inline T* GetMaybePtrFromReservedSlot(JSObject* obj, size_t slot) { 104 Value v = GetReservedSlot(obj, slot); 105 return v.isUndefined() ? nullptr : static_cast<T*>(v.toPrivate()); 106 } 107 108 /** 109 * Helper function to get the pointer value (or nullptr if not set) from the 110 * object's first reserved slot. Must only be used for objects with a JSClass 111 * that has the JSCLASS_SLOT0_IS_NSISUPPORTS flag. 112 */ 113 template <typename T> 114 inline T* GetObjectISupports(JSObject* obj) { 115 MOZ_ASSERT(GetClass(obj)->slot0IsISupports()); 116 return GetMaybePtrFromReservedSlot<T>(obj, 0); 117 } 118 119 /** 120 * Helper function to store |PrivateValue(nsISupportsValue)| in the object's 121 * first reserved slot. Must only be used for objects with a JSClass that has 122 * the JSCLASS_SLOT0_IS_NSISUPPORTS flag. 123 * 124 * Note: the pointer is opaque to the JS engine (including the GC) so it's the 125 * embedding's responsibility to trace or free this value. 126 */ 127 inline void SetObjectISupports(JSObject* obj, void* nsISupportsValue) { 128 MOZ_ASSERT(GetClass(obj)->slot0IsISupports()); 129 SetReservedSlot(obj, 0, PrivateValue(nsISupportsValue)); 130 } 131 132 } // namespace JS 133 134 // JSObject* is an aligned pointer, but this information isn't available in the 135 // public header. We specialize HasFreeLSB here so that JS::Result<JSObject*> 136 // compiles. 137 138 namespace mozilla { 139 namespace detail { 140 template <> 141 struct HasFreeLSB<JSObject*> { 142 static constexpr bool value = true; 143 }; 144 } // namespace detail 145 } // namespace mozilla 146 147 #endif // js_public_Object_h