From 6ad790bd22c85f2ad459275fefff879632977d28 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 9 Aug 2021 15:25:09 +0000 Subject: [PATCH] Bug 1723715 part 13 - Move builtin constructors to GlobalObjectData. r=jonco This replaces the JS_OFF_THREAD_CONSTRUCTOR MagicValue for off-thread constructors with the same placeholder object we use for the prototype. These constructors aren't used by off-thread parsing and handling this another way requires a lot of complexity. With Stencil work the off-thread global will hopefully be removed eventually. Differential Revision: https://phabricator.services.mozilla.com/D121993 --- js/public/Class.h | 2 +- js/public/Value.h | 3 - js/src/builtin/Array.cpp | 10 +-- js/src/debugger/Debugger.cpp | 3 +- js/src/jit/CacheIR.cpp | 4 +- js/src/shell/js.cpp | 4 +- js/src/vm/GlobalObject.cpp | 49 ++++++----- js/src/vm/GlobalObject.h | 158 +++++++++++++++++----------------- js/src/vm/HelperThreads.cpp | 2 +- js/src/vm/JSFunction.cpp | 5 +- js/src/vm/JSObject.cpp | 10 ++- js/src/vm/PromiseLookup.cpp | 8 +- js/src/vm/StructuredClone.cpp | 3 +- js/src/wasm/WasmJS.cpp | 12 ++- js/src/wasm/WasmModule.cpp | 15 ++-- 15 files changed, 143 insertions(+), 145 deletions(-) diff --git a/js/public/Class.h b/js/public/Class.h index 0eb2c1e1b42c..c7724f1e40e5 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -572,7 +572,7 @@ static const uint32_t JSCLASS_FOREGROUND_FINALIZE = // application. static const uint32_t JSCLASS_GLOBAL_APPLICATION_SLOTS = 5; static const uint32_t JSCLASS_GLOBAL_SLOT_COUNT = - JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 2; + JSCLASS_GLOBAL_APPLICATION_SLOTS + 2; static constexpr uint32_t JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(uint32_t n) { return JSCLASS_IS_GLOBAL | diff --git a/js/public/Value.h b/js/public/Value.h index 3f3bd3cf8257..da31c42afbd1 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -241,9 +241,6 @@ enum JSWhyMagic { /** arguments object can't be created because environment is dead. */ JS_MISSING_ARGUMENTS, - /** standard constructors are not created for off-thread parsing. */ - JS_OFF_THREAD_CONSTRUCTOR, - /** for local use */ JS_GENERIC_MAGIC, diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp index 1d36eec7be88..d9fcdbfa07fe 100644 --- a/js/src/builtin/Array.cpp +++ b/js/src/builtin/Array.cpp @@ -4044,12 +4044,10 @@ void js::ArraySpeciesLookup::initialize(JSContext* cx) { return; } - // Get the canonical Array constructor. - const Value& arrayCtorValue = cx->global()->getConstructor(JSProto_Array); - MOZ_ASSERT(arrayCtorValue.isObject(), - "The Array constructor is initialized iff Array.prototype is " - "initialized"); - JSFunction* arrayCtor = &arrayCtorValue.toObject().as(); + // Get the canonical Array constructor. The Array constructor must be + // initialized if Array.prototype is initialized. + JSObject& arrayCtorObject = cx->global()->getConstructor(JSProto_Array); + JSFunction* arrayCtor = &arrayCtorObject.as(); // Shortcut returns below means Array[@@species] will never be // optimizable, set to disabled now, and clear it later when we succeed. diff --git a/js/src/debugger/Debugger.cpp b/js/src/debugger/Debugger.cpp index a6a67e58528d..ba80ca435ff3 100644 --- a/js/src/debugger/Debugger.cpp +++ b/js/src/debugger/Debugger.cpp @@ -6730,7 +6730,8 @@ extern JS_PUBLIC_API bool JS_DefineDebuggerObject(JSContext* cx, if (!debuggeeWouldRunProto) { return false; } - debuggeeWouldRunCtor = global->getConstructor(JSProto_DebuggeeWouldRun); + debuggeeWouldRunCtor = + ObjectValue(global->getConstructor(JSProto_DebuggeeWouldRun)); RootedId debuggeeWouldRunId( cx, NameToId(ClassName(JSProto_DebuggeeWouldRun, cx))); if (!DefineDataProperty(cx, debugCtor, debuggeeWouldRunId, diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index 2f7e227f9755..782dd7dd30d5 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -4626,8 +4626,8 @@ AttachDecision InstanceOfIRGenerator::tryAttachStub() { return AttachDecision::NoAction; } - Value funProto = cx_->global()->getPrototype(JSProto_Function); - if (hasInstanceHolder != &funProto.toObject()) { + JSObject& funProto = cx_->global()->getPrototype(JSProto_Function); + if (hasInstanceHolder != &funProto) { trackAttached(IRGenerator::NotAttached); return AttachDecision::NoAction; } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 3c1c5236d8a1..72c7b52a5f6b 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -7940,8 +7940,8 @@ static bool GetSharedObject(JSContext* cx, unsigned argc, Value* vp) { JSProto_WebAssembly)) { return false; } - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmMemory).toObject()); + RootedObject proto(cx, + &cx->global()->getPrototype(JSProto_WasmMemory)); newObj = WasmMemoryObject::create(cx, maybesab, proto); MOZ_ASSERT_IF(newObj, newObj->as().isShared()); if (!newObj) { diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index a8f9017a4f19..8f71d4dd08c9 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -274,8 +274,7 @@ bool GlobalObject::resolveConstructor(JSContext* cx, // for Function, which is a problem. So if Function is being resolved // before Object.prototype exists, we just resolve Object instead, since we // know that Function will also be resolved before we return. - if (key == JSProto_Function && - global->getPrototype(JSProto_Object).isUndefined()) { + if (key == JSProto_Function && !global->hasPrototype(JSProto_Object)) { return resolveConstructor(cx, global, JSProto_Object, IfClassIsDisabled::DoNothing); } @@ -316,7 +315,7 @@ bool GlobalObject::resolveConstructor(JSContext* cx, // criteria that protects entry into this function. MOZ_ASSERT(!global->isStandardClassResolved(key)); - global->setPrototype(key, ObjectValue(*proto)); + global->setPrototype(key, proto); } } @@ -335,7 +334,7 @@ bool GlobalObject::resolveConstructor(JSContext* cx, } } - global->setConstructor(key, ObjectValue(*ctor)); + global->setConstructor(key, ctor); } if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) { @@ -403,9 +402,9 @@ bool GlobalObject::resolveConstructor(JSContext* cx, } // Infallible operations that modify the global object. - global->setConstructor(key, ObjectValue(*ctor)); + global->setConstructor(key, ctor); if (proto) { - global->setPrototype(key, ObjectValue(*proto)); + global->setPrototype(key, proto); } } @@ -476,7 +475,7 @@ const JSClass GlobalObject::OffThreadPlaceholderObject::class_ = { "off-thread-prototype-placeholder", JSCLASS_HAS_RESERVED_SLOTS(1)}; /* static */ GlobalObject::OffThreadPlaceholderObject* -GlobalObject::OffThreadPlaceholderObject::New(JSContext* cx, unsigned slot) { +GlobalObject::OffThreadPlaceholderObject::New(JSContext* cx, JSProtoKey key) { Rooted placeholder(cx); placeholder = NewObjectWithGivenProto(cx, nullptr); @@ -484,7 +483,7 @@ GlobalObject::OffThreadPlaceholderObject::New(JSContext* cx, unsigned slot) { return nullptr; } - placeholder->setReservedSlot(SlotIndexOrProtoKindSlot, Int32Value(slot)); + placeholder->setReservedSlot(ProtoKeyOrProtoKindSlot, Int32Value(key)); return placeholder; } @@ -497,14 +496,14 @@ GlobalObject::OffThreadPlaceholderObject::New(JSContext* cx, ProtoKind kind) { return nullptr; } - placeholder->setReservedSlot(SlotIndexOrProtoKindSlot, + placeholder->setReservedSlot(ProtoKeyOrProtoKindSlot, Int32Value(-int32_t(kind))); return placeholder; } inline int32_t -GlobalObject::OffThreadPlaceholderObject::getSlotIndexOrProtoKind() const { - return getReservedSlot(SlotIndexOrProtoKindSlot).toInt32(); +GlobalObject::OffThreadPlaceholderObject::getProtoKeyOrProtoKind() const { + return getReservedSlot(ProtoKeyOrProtoKindSlot).toInt32(); } /* static */ @@ -523,7 +522,7 @@ bool GlobalObject::resolveOffThreadConstructor(JSContext* cx, key == JSProto_AsyncGeneratorFunction); Rooted placeholder(cx); - placeholder = OffThreadPlaceholderObject::New(cx, prototypeSlot(key)); + placeholder = OffThreadPlaceholderObject::New(cx, key); if (!placeholder) { return false; } @@ -533,8 +532,11 @@ bool GlobalObject::resolveOffThreadConstructor(JSContext* cx, return false; } - global->setPrototype(key, ObjectValue(*placeholder)); - global->setConstructor(key, MagicValue(JS_OFF_THREAD_CONSTRUCTOR)); + // Use the placeholder for both constructor and prototype. The constructor + // isn't used off-thread, but we need to initialize both at the same time to + // satisfy invariants. + global->setPrototype(key, placeholder); + global->setConstructor(key, placeholder); return true; } @@ -563,9 +565,10 @@ JSObject* GlobalObject::createOffThreadBuiltinProto( JSObject* GlobalObject::getPrototypeForOffThreadPlaceholder(JSObject* obj) { auto placeholder = &obj->as(); - int32_t value = placeholder->getSlotIndexOrProtoKind(); + int32_t value = placeholder->getProtoKeyOrProtoKind(); if (value >= 0) { - return &getSlot(value).toObject(); + MOZ_ASSERT(value < int32_t(JSProto_LIMIT)); + return &getPrototype(JSProtoKey(value)); } MOZ_ASSERT(-value < int32_t(ProtoKind::Limit)); return &getBuiltinProto(ProtoKind(-value)); @@ -589,8 +592,8 @@ bool GlobalObject::initBuiltinConstructor(JSContext* cx, return false; } - global->setConstructor(key, ObjectValue(*ctor)); - global->setPrototype(key, ObjectValue(*proto)); + global->setConstructor(key, ctor); + global->setPrototype(key, proto); return true; } @@ -1126,7 +1129,7 @@ JSObject* GlobalObject::createIteratorPrototype(JSContext* cx, if (!ensureConstructor(cx, global, JSProto_Iterator)) { return nullptr; } - JSObject* proto = &global->getPrototype(JSProto_Iterator).toObject(); + JSObject* proto = &global->getPrototype(JSProto_Iterator); global->initBuiltinProto(ProtoKind::IteratorProto, proto); return proto; } @@ -1142,7 +1145,7 @@ JSObject* GlobalObject::createAsyncIteratorPrototype( if (!ensureConstructor(cx, global, JSProto_AsyncIterator)) { return nullptr; } - JSObject* proto = &global->getPrototype(JSProto_AsyncIterator).toObject(); + JSObject* proto = &global->getPrototype(JSProto_AsyncIterator); global->initBuiltinProto(ProtoKind::AsyncIteratorProto, proto); return proto; } @@ -1154,6 +1157,12 @@ void GlobalObject::releaseData(JSFreeOp* fop) { } void GlobalObjectData::trace(JSTracer* trc) { + for (auto& ctorWithProto : builtinConstructors) { + TraceNullableEdge(trc, &ctorWithProto.constructor, "global-builtin-ctor"); + TraceNullableEdge(trc, &ctorWithProto.prototype, + "global-builtin-ctor-proto"); + } + for (auto& proto : builtinProtos) { TraceNullableEdge(trc, &proto, "global-builtin-proto"); } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 6d8ed36cf49d..59cc86950b95 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -68,6 +68,21 @@ class GlobalObjectData { public: GlobalObjectData() = default; + // The original values for built-in constructors (with their prototype + // objects) based on JSProtoKey. + // + // This is necessary to implement spec language speaking in terms of "the + // original Array prototype object", or "as if by the expression new Array()" + // referring to the original Array constructor. The actual (writable and even + // deletable) Object, Array, &c. properties are not stored here. + struct ConstructorWithProto { + HeapPtr constructor; + HeapPtr prototype; + }; + using CtorArray = + mozilla::EnumeratedArray; + CtorArray builtinConstructors; + // Built-in prototypes for this global. Note that this is different from the // set of built-in constructors/prototypes based on JSProtoKey. enum class ProtoKind { @@ -159,15 +174,8 @@ class GlobalObject : public NativeObject { /* Count of slots set aside for application use. */ static const unsigned APPLICATION_SLOTS = JSCLASS_GLOBAL_APPLICATION_SLOTS; - /* - * Count of slots to store built-in prototypes and initial visible - * properties for the constructors. - */ - static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 2; - enum : unsigned { - /* One-off properties stored after slots for built-ins. */ - GLOBAL_DATA_SLOT = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS, + GLOBAL_DATA_SLOT = APPLICATION_SLOTS, WINDOW_PROXY, /* Total reserved-slot count for global objects. */ @@ -184,16 +192,6 @@ class GlobalObject : public NativeObject { using ProtoKind = GlobalObjectData::ProtoKind; - static unsigned constructorSlot(JSProtoKey key) { - MOZ_ASSERT(key < JSProto_LIMIT); - return APPLICATION_SLOTS + key; - } - - static unsigned prototypeSlot(JSProtoKey key) { - MOZ_ASSERT(key < JSProto_LIMIT); - return APPLICATION_SLOTS + JSProto_LIMIT + key; - } - GlobalObjectData* maybeData() { Value v = getReservedSlot(GLOBAL_DATA_SLOT); return static_cast(v.toPrivate()); @@ -237,9 +235,14 @@ class GlobalObject : public NativeObject { data().eval.init(evalFun); } - Value getConstructor(JSProtoKey key) const { - return getReservedSlot(constructorSlot(key)); + bool hasConstructor(JSProtoKey key) const { + return bool(data().builtinConstructors[key].constructor); } + JSObject& getConstructor(JSProtoKey key) const { + MOZ_ASSERT(hasConstructor(key)); + return *maybeGetConstructor(key); + } + static bool skipDeselectedConstructor(JSContext* cx, JSProtoKey key); static bool initBuiltinConstructor(JSContext* cx, Handle global, @@ -267,7 +270,7 @@ class GlobalObject : public NativeObject { if (!GlobalObject::ensureConstructor(cx, global, key)) { return nullptr; } - return &global->getConstructor(key).toObject(); + return &global->getConstructor(key); } static JSObject* getOrCreatePrototype(JSContext* cx, JSProtoKey key) { @@ -276,61 +279,60 @@ class GlobalObject : public NativeObject { if (!GlobalObject::ensureConstructor(cx, global, key)) { return nullptr; } - return &global->getPrototype(key).toObject(); + return &global->getPrototype(key); } JSObject* maybeGetConstructor(JSProtoKey protoKey) const { MOZ_ASSERT(JSProto_Null < protoKey); MOZ_ASSERT(protoKey < JSProto_LIMIT); - const Value& v = getConstructor(protoKey); - return v.isObject() ? &v.toObject() : nullptr; + return data().builtinConstructors[protoKey].constructor; } JSObject* maybeGetPrototype(JSProtoKey protoKey) const { MOZ_ASSERT(JSProto_Null < protoKey); MOZ_ASSERT(protoKey < JSProto_LIMIT); - const Value& v = getPrototype(protoKey); - return v.isObject() ? &v.toObject() : nullptr; + return data().builtinConstructors[protoKey].prototype; } static bool maybeResolveGlobalThis(JSContext* cx, Handle global, bool* resolved); - void setConstructor(JSProtoKey key, const Value& v) { - setReservedSlot(constructorSlot(key), v); + void setConstructor(JSProtoKey key, JSObject* obj) { + MOZ_ASSERT(obj); + data().builtinConstructors[key].constructor = obj; } - Value getPrototype(JSProtoKey key) const { - return getReservedSlot(prototypeSlot(key)); + bool hasPrototype(JSProtoKey key) const { + return bool(data().builtinConstructors[key].prototype); + } + JSObject& getPrototype(JSProtoKey key) const { + MOZ_ASSERT(hasPrototype(key)); + return *maybeGetPrototype(key); } - void setPrototype(JSProtoKey key, const Value& value) { - setReservedSlot(prototypeSlot(key), value); + void setPrototype(JSProtoKey key, JSObject* obj) { + MOZ_ASSERT(obj); + data().builtinConstructors[key].prototype = obj; } /* * Lazy standard classes need a way to indicate they have been initialized. * Otherwise, when we delete them, we might accidentally recreate them via - * a lazy initialization. We use the presence of an object in the - * getConstructor(key) reserved slot to indicate that they've been - * initialized. + * a lazy initialization. We use the presence of an object in the constructor + * array to indicate that they've been initialized. * * Note: A few builtin objects, like JSON and Math, are not constructors, * so getConstructor is a bit of a misnomer. */ bool isStandardClassResolved(JSProtoKey key) const { - // If the constructor is undefined, then it hasn't been initialized. - Value value = getConstructor(key); - MOZ_ASSERT(value.isUndefined() || value.isObject() || - value.isMagic(JS_OFF_THREAD_CONSTRUCTOR)); - return !value.isUndefined(); + return hasConstructor(key); } private: bool classIsInitialized(JSProtoKey key) const { - bool inited = !getConstructor(key).isUndefined(); - MOZ_ASSERT(inited == !getPrototype(key).isUndefined()); + bool inited = hasConstructor(key); + MOZ_ASSERT(inited == hasPrototype(key)); return inited; } @@ -400,7 +402,7 @@ class GlobalObject : public NativeObject { return nullptr; } } - return &global->getPrototype(JSProto_Object).toObject(); + return &global->getPrototype(JSProto_Object); } static JSObject* getOrCreateFunctionConstructor( @@ -410,7 +412,7 @@ class GlobalObject : public NativeObject { return nullptr; } } - return &global->getConstructor(JSProto_Function).toObject(); + return &global->getConstructor(JSProto_Function); } static JSObject* getOrCreateFunctionPrototype(JSContext* cx, @@ -420,7 +422,7 @@ class GlobalObject : public NativeObject { return nullptr; } } - return &global->getPrototype(JSProto_Function).toObject(); + return &global->getPrototype(JSProto_Function); } static NativeObject* getOrCreateArrayPrototype(JSContext* cx, @@ -428,12 +430,12 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Array)) { return nullptr; } - return &global->getPrototype(JSProto_Array).toObject().as(); + return &global->getPrototype(JSProto_Array).as(); } NativeObject* maybeGetArrayPrototype() { if (classIsInitialized(JSProto_Array)) { - return &getPrototype(JSProto_Array).toObject().as(); + return &getPrototype(JSProto_Array).as(); } return nullptr; } @@ -443,7 +445,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Boolean)) { return nullptr; } - return &global->getPrototype(JSProto_Boolean).toObject(); + return &global->getPrototype(JSProto_Boolean); } static JSObject* getOrCreateNumberPrototype(JSContext* cx, @@ -451,7 +453,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Number)) { return nullptr; } - return &global->getPrototype(JSProto_Number).toObject(); + return &global->getPrototype(JSProto_Number); } static JSObject* getOrCreateStringPrototype(JSContext* cx, @@ -459,7 +461,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_String)) { return nullptr; } - return &global->getPrototype(JSProto_String).toObject(); + return &global->getPrototype(JSProto_String); } static JSObject* getOrCreateSymbolPrototype(JSContext* cx, @@ -467,7 +469,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Symbol)) { return nullptr; } - return &global->getPrototype(JSProto_Symbol).toObject(); + return &global->getPrototype(JSProto_Symbol); } static JSObject* getOrCreateBigIntPrototype(JSContext* cx, @@ -475,7 +477,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_BigInt)) { return nullptr; } - return &global->getPrototype(JSProto_BigInt).toObject(); + return &global->getPrototype(JSProto_BigInt); } static JSObject* getOrCreatePromisePrototype(JSContext* cx, @@ -483,7 +485,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Promise)) { return nullptr; } - return &global->getPrototype(JSProto_Promise).toObject(); + return &global->getPrototype(JSProto_Promise); } static JSObject* getOrCreateRegExpPrototype(JSContext* cx, @@ -491,12 +493,12 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_RegExp)) { return nullptr; } - return &global->getPrototype(JSProto_RegExp).toObject(); + return &global->getPrototype(JSProto_RegExp); } JSObject* maybeGetRegExpPrototype() { if (classIsInitialized(JSProto_RegExp)) { - return &getPrototype(JSProto_RegExp).toObject(); + return &getPrototype(JSProto_RegExp); } return nullptr; } @@ -506,7 +508,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_SavedFrame)) { return nullptr; } - return &global->getPrototype(JSProto_SavedFrame).toObject(); + return &global->getPrototype(JSProto_SavedFrame); } static JSObject* getOrCreateArrayBufferConstructor( @@ -514,7 +516,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) { return nullptr; } - return &global->getConstructor(JSProto_ArrayBuffer).toObject(); + return &global->getConstructor(JSProto_ArrayBuffer); } static JSObject* getOrCreateArrayBufferPrototype( @@ -522,7 +524,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) { return nullptr; } - return &global->getPrototype(JSProto_ArrayBuffer).toObject(); + return &global->getPrototype(JSProto_ArrayBuffer); } static JSObject* getOrCreateSharedArrayBufferPrototype( @@ -530,7 +532,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) { return nullptr; } - return &global->getPrototype(JSProto_SharedArrayBuffer).toObject(); + return &global->getPrototype(JSProto_SharedArrayBuffer); } static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx, @@ -540,7 +542,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, key)) { return nullptr; } - return &global->getPrototype(key).toObject(); + return &global->getPrototype(key); } static JSFunction* getOrCreateErrorConstructor(JSContext* cx, @@ -548,7 +550,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Error)) { return nullptr; } - return &global->getConstructor(JSProto_Error).toObject().as(); + return &global->getConstructor(JSProto_Error).as(); } static JSObject* getOrCreateErrorPrototype(JSContext* cx, @@ -561,7 +563,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Set)) { return nullptr; } - return &global->getPrototype(JSProto_Set).toObject().as(); + return &global->getPrototype(JSProto_Set).as(); } static NativeObject* getOrCreateWeakSetPrototype( @@ -569,7 +571,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_WeakSet)) { return nullptr; } - return &global->getPrototype(JSProto_WeakSet).toObject().as(); + return &global->getPrototype(JSProto_WeakSet).as(); } static bool ensureModulePrototypesCreated(JSContext* cx, @@ -611,9 +613,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_TypedArray)) { return nullptr; } - return &global->getConstructor(JSProto_TypedArray) - .toObject() - .as(); + return &global->getConstructor(JSProto_TypedArray).as(); } static JSObject* getOrCreateTypedArrayPrototype( @@ -621,7 +621,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_TypedArray)) { return nullptr; } - return &global->getPrototype(JSProto_TypedArray).toObject(); + return &global->getPrototype(JSProto_TypedArray); } private: @@ -703,7 +703,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { return nullptr; } - return &global->getPrototype(JSProto_GeneratorFunction).toObject(); + return &global->getPrototype(JSProto_GeneratorFunction); } static JSObject* getOrCreateGeneratorFunction(JSContext* cx, @@ -711,7 +711,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { return nullptr; } - return &global->getConstructor(JSProto_GeneratorFunction).toObject(); + return &global->getConstructor(JSProto_GeneratorFunction); } static JSObject* getOrCreateAsyncFunctionPrototype( @@ -719,7 +719,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) { return nullptr; } - return &global->getPrototype(JSProto_AsyncFunction).toObject(); + return &global->getPrototype(JSProto_AsyncFunction); } static JSObject* getOrCreateAsyncFunction(JSContext* cx, @@ -727,7 +727,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) { return nullptr; } - return &global->getConstructor(JSProto_AsyncFunction).toObject(); + return &global->getConstructor(JSProto_AsyncFunction); } static JSObject* createAsyncIteratorPrototype(JSContext* cx, @@ -754,7 +754,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) { return nullptr; } - return &global->getPrototype(JSProto_AsyncGeneratorFunction).toObject(); + return &global->getPrototype(JSProto_AsyncGeneratorFunction); } static JSObject* getOrCreateAsyncGeneratorFunction( @@ -762,7 +762,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) { return nullptr; } - return &global->getConstructor(JSProto_AsyncGeneratorFunction).toObject(); + return &global->getConstructor(JSProto_AsyncGeneratorFunction); } void setAsyncGeneratorPrototype(JSObject* obj) { @@ -794,7 +794,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_DataView)) { return nullptr; } - return &global->getPrototype(JSProto_DataView).toObject(); + return &global->getPrototype(JSProto_DataView); } static JSObject* getOrCreatePromiseConstructor(JSContext* cx, @@ -802,7 +802,7 @@ class GlobalObject : public NativeObject { if (!ensureConstructor(cx, global, JSProto_Promise)) { return nullptr; } - return &global->getConstructor(JSProto_Promise).toObject(); + return &global->getConstructor(JSProto_Promise); } static NativeObject* getOrCreateWrapForValidIteratorPrototype( @@ -972,13 +972,13 @@ class GlobalObject : public NativeObject { // A class used in place of a prototype during off-thread parsing. struct OffThreadPlaceholderObject : public NativeObject { - // The slot either stores a slot index (Int32Value >= 0) or a ProtoKind + // The slot either stores a JSProtoKey (Int32Value >= 0) or a ProtoKind // (Int32Value < 0). - static const int32_t SlotIndexOrProtoKindSlot = 0; + static const int32_t ProtoKeyOrProtoKindSlot = 0; static const JSClass class_; - static OffThreadPlaceholderObject* New(JSContext* cx, unsigned slot); + static OffThreadPlaceholderObject* New(JSContext* cx, JSProtoKey key); static OffThreadPlaceholderObject* New(JSContext* cx, ProtoKind kind); - inline int32_t getSlotIndexOrProtoKind() const; + inline int32_t getProtoKeyOrProtoKind() const; }; static bool isOffThreadPrototypePlaceholder(JSObject* obj) { diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index ca1e2efcc110..284617cd867e 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -1044,7 +1044,7 @@ static bool EnsureConstructor(JSContext* cx, Handle global, } // Set the used-as-prototype flag here because we can't GC in mergeRealms. - RootedObject proto(cx, &global->getPrototype(key).toObject()); + RootedObject proto(cx, &global->getPrototype(key)); return JSObject::setIsUsedAsPrototype(cx, proto); } diff --git a/js/src/vm/JSFunction.cpp b/js/src/vm/JSFunction.cpp index 40ded1f64c61..d8c8be3ba18c 100644 --- a/js/src/vm/JSFunction.cpp +++ b/js/src/vm/JSFunction.cpp @@ -798,8 +798,7 @@ static void fun_trace(JSTracer* trc, JSObject* obj) { static JSObject* CreateFunctionConstructor(JSContext* cx, JSProtoKey key) { Rooted global(cx, cx->global()); - RootedObject functionProto( - cx, &global->getPrototype(JSProto_Function).toObject()); + RootedObject functionProto(cx, &global->getPrototype(JSProto_Function)); RootedObject functionCtor( cx, NewFunctionWithProto( @@ -822,7 +821,7 @@ static bool FunctionPrototype(JSContext* cx, unsigned argc, Value* vp) { static JSObject* CreateFunctionPrototype(JSContext* cx, JSProtoKey key) { Rooted self(cx, cx->global()); - RootedObject objectProto(cx, &self->getPrototype(JSProto_Object).toObject()); + RootedObject objectProto(cx, &self->getPrototype(JSProto_Object)); return NewFunctionWithProto( cx, FunctionPrototype, 0, FunctionFlags::NATIVE_FUN, nullptr, diff --git a/js/src/vm/JSObject.cpp b/js/src/vm/JSObject.cpp index 37465cee6679..cfab111c768a 100644 --- a/js/src/vm/JSObject.cpp +++ b/js/src/vm/JSObject.cpp @@ -1796,8 +1796,7 @@ bool js::GetObjectFromIncumbentGlobal(JSContext* cx, MutableHandleObject obj) { } static bool IsStandardPrototype(JSObject* obj, JSProtoKey key) { - Value v = obj->nonCCWGlobal().getPrototype(key); - return v.isObject() && obj == &v.toObject(); + return obj->nonCCWGlobal().maybeGetPrototype(key) == obj; } JSProtoKey JS::IdentifyStandardInstance(JSObject* obj) { @@ -1835,10 +1834,13 @@ JSProtoKey JS::IdentifyStandardConstructor(JSObject* obj) { return JSProto_Null; } + static_assert(JSProto_Null == 0, + "Loop below can start at 1 to skip JSProto_Null"); + GlobalObject& global = obj->as().global(); - for (size_t k = 0; k < JSProto_LIMIT; ++k) { + for (size_t k = 1; k < JSProto_LIMIT; ++k) { JSProtoKey key = static_cast(k); - if (global.getConstructor(key) == ObjectValue(*obj)) { + if (global.maybeGetConstructor(key) == obj) { return key; } } diff --git a/js/src/vm/PromiseLookup.cpp b/js/src/vm/PromiseLookup.cpp index 157c0b8991d7..dbbe3e435e56 100644 --- a/js/src/vm/PromiseLookup.cpp +++ b/js/src/vm/PromiseLookup.cpp @@ -30,13 +30,13 @@ using JS::Value; using js::NativeObject; JSFunction* js::PromiseLookup::getPromiseConstructor(JSContext* cx) { - const Value& val = cx->global()->getConstructor(JSProto_Promise); - return val.isObject() ? &val.toObject().as() : nullptr; + JSObject* obj = cx->global()->maybeGetConstructor(JSProto_Promise); + return obj ? &obj->as() : nullptr; } NativeObject* js::PromiseLookup::getPromisePrototype(JSContext* cx) { - const Value& val = cx->global()->getPrototype(JSProto_Promise); - return val.isObject() ? &val.toObject().as() : nullptr; + JSObject* obj = cx->global()->maybeGetPrototype(JSProto_Promise); + return obj ? &obj->as() : nullptr; } bool js::PromiseLookup::isDataPropertyNative(JSContext* cx, NativeObject* obj, diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 6d4c96a95cdf..377086703728 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -2492,8 +2492,7 @@ bool JSStructuredCloneReader::readSharedWasmMemory(uint32_t nbytes, cx, &payload.toObject().as()); // Construct the memory. - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmMemory).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmMemory)); RootedObject memory(cx, WasmMemoryObject::create(cx, sab, proto)); if (!memory) { return false; diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp index 2a914b3e3735..c0a1c6d83fd0 100644 --- a/js/src/wasm/WasmJS.cpp +++ b/js/src/wasm/WasmJS.cpp @@ -3903,8 +3903,7 @@ WasmExceptionObject* WasmExceptionObject::create(JSContext* cx, wasm::SharedExceptionTag tag, HandleArrayBufferObject values, HandleArrayObject refs) { - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmException).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmException)); AutoSetNewObjectMetadata metadata(cx); RootedWasmExceptionObject obj( @@ -4141,7 +4140,7 @@ class AsyncInstantiateTask : public OffThreadPromiseTask { bool resolve(JSContext* cx, Handle promise) override { RootedObject instanceProto( - cx, &cx->global()->getPrototype(JSProto_WasmInstance).toObject()); + cx, &cx->global()->getPrototype(JSProto_WasmInstance)); RootedWasmInstanceObject instanceObj(cx); if (!module_->instantiate(cx, imports_.get(), instanceProto, @@ -4158,8 +4157,8 @@ class AsyncInstantiateTask : public OffThreadPromiseTask { return RejectWithPendingException(cx, promise); } - RootedObject moduleProto( - cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject()); + RootedObject moduleProto(cx, + &cx->global()->getPrototype(JSProto_WasmModule)); RootedObject moduleObj( cx, WasmModuleObject::create(cx, *module_, moduleProto)); if (!moduleObj) { @@ -4207,8 +4206,7 @@ static bool AsyncInstantiate(JSContext* cx, const Module& module, static bool ResolveCompile(JSContext* cx, const Module& module, Handle promise) { - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule)); RootedObject moduleObj(cx, WasmModuleObject::create(cx, module, proto)); if (!moduleObj) { return RejectWithPendingException(cx, promise); diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp index 6e922dbe93aa..185fac2121b4 100644 --- a/js/src/wasm/WasmModule.cpp +++ b/js/src/wasm/WasmModule.cpp @@ -350,8 +350,7 @@ JSObject* Module::createObject(JSContext* cx) const { return nullptr; } - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmModule).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmModule)); return WasmModuleObject::create(cx, *this, proto); } @@ -741,8 +740,7 @@ bool Module::instantiateMemory(JSContext* cx, return false; } - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmMemory).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmMemory)); memory.set(WasmMemoryObject::create(cx, buffer, proto)); if (!memory) { return false; @@ -788,8 +786,7 @@ bool Module::instantiateLocalTag(JSContext* cx, const TagDesc& ed, if (ed.isExport) { // If the tag description is exported, create an export tag // object for it. - RootedObject proto(cx, - &cx->global()->getPrototype(JSProto_WasmTag).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTag)); RootedWasmTagObject tagObj(cx, WasmTagObject::create(cx, ed.type, proto)); if (!tagObj) { return false; @@ -875,8 +872,7 @@ bool Module::instantiateLocalTable(JSContext* cx, const TableDesc& td, SharedTable table; Rooted tableObj(cx); if (td.importedOrExported) { - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmTable).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmTable)); tableObj.set(WasmTableObject::create(cx, td.initialLength, td.maximumLength, td.elemType, proto)); if (!tableObj) { @@ -950,8 +946,7 @@ static bool EnsureExportedGlobalObject(JSContext* cx, val.set(Val(global.type())); } - RootedObject proto( - cx, &cx->global()->getPrototype(JSProto_WasmGlobal).toObject()); + RootedObject proto(cx, &cx->global()->getPrototype(JSProto_WasmGlobal)); RootedWasmGlobalObject go( cx, WasmGlobalObject::create(cx, val, global.isMutable(), proto)); if (!go) {