/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef vm_GlobalObject_h #define vm_GlobalObject_h #include "mozilla/Assertions.h" #include "mozilla/DebugOnly.h" #include #include #include "jsapi.h" #include "jsexn.h" #include "jsfriendapi.h" #include "jspubtd.h" #include "jstypes.h" #include "NamespaceImports.h" #include "gc/AllocKind.h" #include "gc/Rooting.h" #include "js/CallArgs.h" #include "js/Class.h" #include "js/ErrorReport.h" #include "js/PropertyDescriptor.h" #include "js/RootingAPI.h" #include "js/ScalarType.h" // js::Scalar::Type #include "js/TypeDecls.h" #include "js/Value.h" #include "vm/JSContext.h" #include "vm/JSFunction.h" #include "vm/JSObject.h" #include "vm/NativeObject.h" #include "vm/Realm.h" #include "vm/Runtime.h" #include "vm/Shape.h" #include "vm/StringType.h" struct JSFunctionSpec; class JSJitInfo; struct JSPrincipals; struct JSPropertySpec; namespace JS { class JS_PUBLIC_API RealmOptions; }; namespace js { class GlobalScope; class LexicalEnvironmentObject; class PlainObject; class RegExpStatics; /* * Global object slots are reserved as follows: * * [0, APPLICATION_SLOTS) * Pre-reserved slots in all global objects set aside for the embedding's * use. As with all reserved slots these start out as UndefinedValue() and * are traced for GC purposes. Apart from that the engine never touches * these slots, so the embedding can do whatever it wants with them. * [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT) * Stores the original value of the constructor for the corresponding * JSProtoKey. * [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT) * Stores the prototype, if any, for the constructor for the corresponding * JSProtoKey offset from JSProto_LIMIT. * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, RESERVED_SLOTS) * Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics, * the original eval for this global object (implementing |var eval = * otherWindow.eval; eval(...)| as an indirect eval), a bit indicating * whether this object has been cleared (see JS_ClearScope), and a cache for * whether eval is allowed (per the global's Content Security Policy). * * The two JSProto_LIMIT-sized ranges are necessary to implement * js::FindClassObject, and 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 in reserved slots. */ 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 { /* Various function values needed by the engine. */ EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS, THROWTYPEERROR, /* One-off properties stored after slots for built-ins. */ EMPTY_GLOBAL_SCOPE, ITERATOR_PROTO, ARRAY_ITERATOR_PROTO, STRING_ITERATOR_PROTO, REGEXP_STRING_ITERATOR_PROTO, GENERATOR_OBJECT_PROTO, ASYNC_ITERATOR_PROTO, ASYNC_FROM_SYNC_ITERATOR_PROTO, ASYNC_GENERATOR_PROTO, MAP_ITERATOR_PROTO, SET_ITERATOR_PROTO, WRAP_FOR_VALID_ITERATOR_PROTO, ITERATOR_HELPER_PROTO, ASYNC_ITERATOR_HELPER_PROTO, MODULE_PROTO, IMPORT_ENTRY_PROTO, EXPORT_ENTRY_PROTO, REQUESTED_MODULE_PROTO, REGEXP_STATICS, RUNTIME_CODEGEN_ENABLED, INTRINSICS, FOR_OF_PIC_CHAIN, WINDOW_PROXY, GLOBAL_THIS_RESOLVED, INSTRUMENTATION, SOURCE_URLS, /* Total reserved-slot count for global objects. */ RESERVED_SLOTS }; /* * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and * we won't expose GlobalObject, so just assert that the two values are * synchronized. */ static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS, "global object slot counts are inconsistent"); 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; } public: LexicalEnvironmentObject& lexicalEnvironment() const; GlobalScope& emptyGlobalScope() const; void setOriginalEval(JSObject* evalobj) { MOZ_ASSERT(getSlotRef(EVAL).isUndefined()); setSlot(EVAL, ObjectValue(*evalobj)); } Value getConstructor(JSProtoKey key) const { return getSlot(constructorSlot(key)); } static bool skipDeselectedConstructor(JSContext* cx, JSProtoKey key); static bool initBuiltinConstructor(JSContext* cx, Handle global, JSProtoKey key, HandleObject ctor, HandleObject proto); private: enum class IfClassIsDisabled { DoNothing, Throw }; static bool resolveConstructor(JSContext* cx, Handle global, JSProtoKey key, IfClassIsDisabled mode); public: static bool ensureConstructor(JSContext* cx, Handle global, JSProtoKey key) { if (global->isStandardClassResolved(key)) { return true; } return resolveConstructor(cx, global, key, IfClassIsDisabled::Throw); } static JSObject* getOrCreateConstructor(JSContext* cx, JSProtoKey key) { MOZ_ASSERT(key != JSProto_Null); Handle global = cx->global(); if (!GlobalObject::ensureConstructor(cx, global, key)) { return nullptr; } return &global->getConstructor(key).toObject(); } static JSObject* getOrCreatePrototype(JSContext* cx, JSProtoKey key) { MOZ_ASSERT(key != JSProto_Null); Handle global = cx->global(); if (!GlobalObject::ensureConstructor(cx, global, key)) { return nullptr; } return &global->getPrototype(key).toObject(); } 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; } 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; } static bool maybeResolveGlobalThis(JSContext* cx, Handle global, bool* resolved); void setConstructor(JSProtoKey key, const Value& v) { setSlot(constructorSlot(key), v); } Value getPrototype(JSProtoKey key) const { return getSlot(prototypeSlot(key)); } void setPrototype(JSProtoKey key, const Value& value) { setSlot(prototypeSlot(key), value); } /* * 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. * * 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(); } private: bool classIsInitialized(JSProtoKey key) const { bool inited = !getConstructor(key).isUndefined(); MOZ_ASSERT(inited == !getPrototype(key).isUndefined()); return inited; } bool functionObjectClassesInitialized() const { bool inited = classIsInitialized(JSProto_Function); MOZ_ASSERT(inited == classIsInitialized(JSProto_Object)); return inited; } // Disallow use of unqualified JSObject::create in GlobalObject. static GlobalObject* create(...) = delete; friend struct ::JSRuntime; static GlobalObject* createInternal(JSContext* cx, const JSClass* clasp); public: static GlobalObject* new_(JSContext* cx, const JSClass* clasp, JSPrincipals* principals, JS::OnNewGlobalHookOption hookOption, const JS::RealmOptions& options); /* * For bootstrapping, whether to splice a prototype for the global object. */ bool shouldSplicePrototype(); /* Set a new prototype for the global object during bootstrapping. */ static bool splicePrototype(JSContext* cx, Handle global, Handle proto); /* * Create a constructor function with the specified name and length using * ctor, a method which creates objects with the given class. */ static JSFunction* createConstructor( JSContext* cx, JSNative ctor, JSAtom* name, unsigned length, gc::AllocKind kind = gc::AllocKind::FUNCTION, const JSJitInfo* jitInfo = nullptr); /* * Create an object to serve as [[Prototype]] for instances of the given * class, using |Object.prototype| as its [[Prototype]]. Users creating * prototype objects with particular internal structure (e.g. reserved * slots guaranteed to contain values of particular types) must immediately * complete the minimal initialization to make the returned object safe to * touch. */ static NativeObject* createBlankPrototype(JSContext* cx, Handle global, const JSClass* clasp); /* * Identical to createBlankPrototype, but uses proto as the [[Prototype]] * of the returned blank prototype. */ static NativeObject* createBlankPrototypeInheriting(JSContext* cx, const JSClass* clasp, HandleObject proto); template static T* createBlankPrototypeInheriting(JSContext* cx, HandleObject proto) { NativeObject* res = createBlankPrototypeInheriting(cx, &T::class_, proto); return res ? &res->template as() : nullptr; } template static T* createBlankPrototype(JSContext* cx, Handle global) { NativeObject* res = createBlankPrototype(cx, global, &T::class_); return res ? &res->template as() : nullptr; } static JSObject* getOrCreateObjectPrototype(JSContext* cx, Handle global) { if (!global->functionObjectClassesInitialized()) { if (!ensureConstructor(cx, global, JSProto_Object)) { return nullptr; } } return &global->getPrototype(JSProto_Object).toObject(); } static JSObject* getOrCreateFunctionConstructor( JSContext* cx, Handle global) { if (!global->functionObjectClassesInitialized()) { if (!ensureConstructor(cx, global, JSProto_Object)) { return nullptr; } } return &global->getConstructor(JSProto_Function).toObject(); } static JSObject* getOrCreateFunctionPrototype(JSContext* cx, Handle global) { if (!global->functionObjectClassesInitialized()) { if (!ensureConstructor(cx, global, JSProto_Object)) { return nullptr; } } return &global->getPrototype(JSProto_Function).toObject(); } static NativeObject* getOrCreateArrayPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Array)) { return nullptr; } return &global->getPrototype(JSProto_Array).toObject().as(); } NativeObject* maybeGetArrayPrototype() { if (classIsInitialized(JSProto_Array)) { return &getPrototype(JSProto_Array).toObject().as(); } return nullptr; } static JSObject* getOrCreateBooleanPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Boolean)) { return nullptr; } return &global->getPrototype(JSProto_Boolean).toObject(); } static JSObject* getOrCreateNumberPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Number)) { return nullptr; } return &global->getPrototype(JSProto_Number).toObject(); } static JSObject* getOrCreateStringPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_String)) { return nullptr; } return &global->getPrototype(JSProto_String).toObject(); } static JSObject* getOrCreateSymbolPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Symbol)) { return nullptr; } return &global->getPrototype(JSProto_Symbol).toObject(); } static JSObject* getOrCreateBigIntPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_BigInt)) { return nullptr; } return &global->getPrototype(JSProto_BigInt).toObject(); } static JSObject* getOrCreatePromisePrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Promise)) { return nullptr; } return &global->getPrototype(JSProto_Promise).toObject(); } static JSObject* getOrCreateRegExpPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_RegExp)) { return nullptr; } return &global->getPrototype(JSProto_RegExp).toObject(); } JSObject* maybeGetRegExpPrototype() { if (classIsInitialized(JSProto_RegExp)) { return &getPrototype(JSProto_RegExp).toObject(); } return nullptr; } static JSObject* getOrCreateSavedFramePrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_SavedFrame)) { return nullptr; } return &global->getPrototype(JSProto_SavedFrame).toObject(); } static JSObject* getOrCreateArrayBufferConstructor( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) { return nullptr; } return &global->getConstructor(JSProto_ArrayBuffer).toObject(); } static JSObject* getOrCreateArrayBufferPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) { return nullptr; } return &global->getPrototype(JSProto_ArrayBuffer).toObject(); } static JSObject* getOrCreateSharedArrayBufferPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) { return nullptr; } return &global->getPrototype(JSProto_SharedArrayBuffer).toObject(); } static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx, Handle global, JSExnType exnType) { JSProtoKey key = GetExceptionProtoKey(exnType); if (!ensureConstructor(cx, global, key)) { return nullptr; } return &global->getPrototype(key).toObject(); } static JSFunction* getOrCreateErrorConstructor(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Error)) { return nullptr; } return &global->getConstructor(JSProto_Error).toObject().as(); } static JSObject* getOrCreateErrorPrototype(JSContext* cx, Handle global) { return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR); } static NativeObject* getOrCreateSetPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Set)) { return nullptr; } return &global->getPrototype(JSProto_Set).toObject().as(); } static NativeObject* getOrCreateWeakSetPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_WeakSet)) { return nullptr; } return &global->getPrototype(JSProto_WeakSet).toObject().as(); } static bool ensureModulePrototypesCreated(JSContext* cx, Handle global); static JSObject* getOrCreateModulePrototype(JSContext* cx, Handle global) { return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto); } static JSObject* getOrCreateImportEntryPrototype( JSContext* cx, Handle global) { return getOrCreateObject(cx, global, IMPORT_ENTRY_PROTO, initImportEntryProto); } static JSObject* getOrCreateExportEntryPrototype( JSContext* cx, Handle global) { return getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO, initExportEntryProto); } static JSObject* getOrCreateRequestedModulePrototype( JSContext* cx, Handle global) { return getOrCreateObject(cx, global, REQUESTED_MODULE_PROTO, initRequestedModuleProto); } static JSFunction* getOrCreateTypedArrayConstructor( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_TypedArray)) { return nullptr; } return &global->getConstructor(JSProto_TypedArray) .toObject() .as(); } static JSObject* getOrCreateTypedArrayPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_TypedArray)) { return nullptr; } return &global->getPrototype(JSProto_TypedArray).toObject(); } private: using ObjectInitOp = bool (*)(JSContext*, Handle); using ObjectInitWithTagOp = bool (*)(JSContext*, Handle, HandleAtom); static JSObject* getOrCreateObject(JSContext* cx, Handle global, unsigned slot, ObjectInitOp init) { Value v = global->getSlotRef(slot); if (v.isObject()) { return &v.toObject(); } return createObject(cx, global, slot, init); } static JSObject* getOrCreateObject(JSContext* cx, Handle global, unsigned slot, HandleAtom tag, ObjectInitWithTagOp init) { Value v = global->getSlotRef(slot); if (v.isObject()) { return &v.toObject(); } return createObject(cx, global, slot, tag, init); } static JSObject* createObject(JSContext* cx, Handle global, unsigned slot, ObjectInitOp init); static JSObject* createObject(JSContext* cx, Handle global, unsigned slot, HandleAtom tag, ObjectInitWithTagOp init); static JSObject* createIteratorPrototype(JSContext* cx, Handle global); public: static JSObject* getOrCreateIteratorPrototype(JSContext* cx, Handle global) { if (global->getReservedSlot(ITERATOR_PROTO).isObject()) { return &global->getReservedSlot(ITERATOR_PROTO).toObject(); } return createIteratorPrototype(cx, global); } static NativeObject* getOrCreateArrayIteratorPrototype( JSContext* cx, Handle global); NativeObject* maybeGetArrayIteratorPrototype() { Value v = getSlotRef(ARRAY_ITERATOR_PROTO); if (v.isObject()) { return &v.toObject().as(); } return nullptr; } static JSObject* getOrCreateStringIteratorPrototype( JSContext* cx, Handle global); static JSObject* getOrCreateRegExpStringIteratorPrototype( JSContext* cx, Handle global); void setGeneratorObjectPrototype(JSObject* obj) { setSlot(GENERATOR_OBJECT_PROTO, ObjectValue(*obj)); } static JSObject* getOrCreateGeneratorObjectPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { return nullptr; } return &global->getSlot(GENERATOR_OBJECT_PROTO).toObject(); } static JSObject* getOrCreateGeneratorFunctionPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { return nullptr; } return &global->getPrototype(JSProto_GeneratorFunction).toObject(); } static JSObject* getOrCreateGeneratorFunction(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { return nullptr; } return &global->getConstructor(JSProto_GeneratorFunction).toObject(); } static JSObject* getOrCreateAsyncFunctionPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) { return nullptr; } return &global->getPrototype(JSProto_AsyncFunction).toObject(); } static JSObject* getOrCreateAsyncFunction(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) { return nullptr; } return &global->getConstructor(JSProto_AsyncFunction).toObject(); } static JSObject* createAsyncIteratorPrototype(JSContext* cx, Handle global); static JSObject* getOrCreateAsyncIteratorPrototype( JSContext* cx, Handle global) { if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject()) { return &global->getReservedSlot(ASYNC_ITERATOR_PROTO).toObject(); } return createAsyncIteratorPrototype(cx, global); // return getOrCreateObject(cx, global, ASYNC_ITERATOR_PROTO, // initAsyncIteratorProto); } static JSObject* getOrCreateAsyncFromSyncIteratorPrototype( JSContext* cx, Handle global) { return getOrCreateObject(cx, global, ASYNC_FROM_SYNC_ITERATOR_PROTO, initAsyncFromSyncIteratorProto); } static JSObject* getOrCreateAsyncGenerator(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) { return nullptr; } return &global->getPrototype(JSProto_AsyncGeneratorFunction).toObject(); } static JSObject* getOrCreateAsyncGeneratorFunction( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) { return nullptr; } return &global->getConstructor(JSProto_AsyncGeneratorFunction).toObject(); } void setAsyncGeneratorPrototype(JSObject* obj) { setSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*obj)); } static JSObject* getOrCreateAsyncGeneratorPrototype( JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) { return nullptr; } return &global->getSlot(ASYNC_GENERATOR_PROTO).toObject(); } static JSObject* getOrCreateMapIteratorPrototype( JSContext* cx, Handle global) { return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO, initMapIteratorProto); } static JSObject* getOrCreateSetIteratorPrototype( JSContext* cx, Handle global) { return getOrCreateObject(cx, global, SET_ITERATOR_PROTO, initSetIteratorProto); } static JSObject* getOrCreateDataViewPrototype(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_DataView)) { return nullptr; } return &global->getPrototype(JSProto_DataView).toObject(); } static JSObject* getOrCreatePromiseConstructor(JSContext* cx, Handle global) { if (!ensureConstructor(cx, global, JSProto_Promise)) { return nullptr; } return &global->getConstructor(JSProto_Promise).toObject(); } static NativeObject* getOrCreateWrapForValidIteratorPrototype( JSContext* cx, Handle global); static NativeObject* getOrCreateIteratorHelperPrototype( JSContext* cx, Handle global); static NativeObject* getOrCreateAsyncIteratorHelperPrototype( JSContext* cx, Handle global); static bool initAsyncIteratorHelperProto(JSContext* cx, Handle global); static NativeObject* getIntrinsicsHolder(JSContext* cx, Handle global); bool maybeExistingIntrinsicValue(PropertyName* name, Value* vp) { Value slot = getReservedSlot(INTRINSICS); // If we're in the self-hosting compartment itself, the // intrinsics-holder isn't initialized at this point. if (slot.isUndefined()) { *vp = UndefinedValue(); return false; } NativeObject* holder = &slot.toObject().as(); Shape* shape = holder->lookupPure(name); if (!shape) { *vp = UndefinedValue(); return false; } *vp = holder->getSlot(shape->slot()); return true; } Value existingIntrinsicValue(PropertyName* name) { Value val; mozilla::DebugOnly exists = maybeExistingIntrinsicValue(name, &val); MOZ_ASSERT(exists, "intrinsic must already have been added to holder"); return val; } static bool maybeGetIntrinsicValue(JSContext* cx, Handle global, Handle name, MutableHandleValue vp, bool* exists) { NativeObject* holder = getIntrinsicsHolder(cx, global); if (!holder) { return false; } if (Shape* shape = holder->lookup(cx, name)) { vp.set(holder->getSlot(shape->slot())); *exists = true; } else { *exists = false; } return true; } static bool getIntrinsicValue(JSContext* cx, Handle global, HandlePropertyName name, MutableHandleValue value) { bool exists = false; if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value, &exists)) { return false; } if (exists) { return true; } if (!cx->runtime()->cloneSelfHostedValue(cx, name, value)) { return false; } return GlobalObject::addIntrinsicValue(cx, global, name, value); } static bool addIntrinsicValue(JSContext* cx, Handle global, HandlePropertyName name, HandleValue value); static inline bool setIntrinsicValue(JSContext* cx, Handle global, HandlePropertyName name, HandleValue value); static bool getSelfHostedFunction(JSContext* cx, Handle global, HandlePropertyName selfHostedName, HandleAtom name, unsigned nargs, MutableHandleValue funVal); static RegExpStatics* getRegExpStatics(JSContext* cx, Handle global); static JSObject* getOrCreateThrowTypeError(JSContext* cx, Handle global); static bool isRuntimeCodeGenEnabled(JSContext* cx, HandleString code, Handle global); static bool getOrCreateEval(JSContext* cx, Handle global, MutableHandleObject eval); // Infallibly test whether the given value is the eval function for this // global. bool valueIsEval(const Value& val); // Implemented in vm/Iteration.cpp. static bool initIteratorProto(JSContext* cx, Handle global); template static bool initObjectIteratorProto(JSContext* cx, Handle global, HandleAtom tag); // Implemented in vm/AsyncIteration.cpp. static bool initAsyncIteratorProto(JSContext* cx, Handle global); static bool initAsyncFromSyncIteratorProto(JSContext* cx, Handle global); // Implemented in builtin/MapObject.cpp. static bool initMapIteratorProto(JSContext* cx, Handle global); static bool initSetIteratorProto(JSContext* cx, Handle global); // Implemented in builtin/ModuleObject.cpp static bool initModuleProto(JSContext* cx, Handle global); static bool initImportEntryProto(JSContext* cx, Handle global); static bool initExportEntryProto(JSContext* cx, Handle global); static bool initRequestedModuleProto(JSContext* cx, Handle global); static bool initStandardClasses(JSContext* cx, Handle global); static bool initSelfHostingBuiltins(JSContext* cx, Handle global, const JSFunctionSpec* builtins); Realm::DebuggerVector& getDebuggers() const { return realm()->getDebuggers(); } inline NativeObject* getForOfPICObject() { Value forOfPIC = getReservedSlot(FOR_OF_PIC_CHAIN); if (forOfPIC.isUndefined()) { return nullptr; } return &forOfPIC.toObject().as(); } static NativeObject* getOrCreateForOfPICObject(JSContext* cx, Handle global); JSObject* windowProxy() const { return &getReservedSlot(WINDOW_PROXY).toObject(); } JSObject* maybeWindowProxy() const { Value v = getReservedSlot(WINDOW_PROXY); MOZ_ASSERT(v.isObject() || v.isUndefined()); return v.isObject() ? &v.toObject() : nullptr; } void setWindowProxy(JSObject* windowProxy) { setReservedSlot(WINDOW_PROXY, ObjectValue(*windowProxy)); } JSObject* getInstrumentationHolder() const { Value v = getReservedSlot(INSTRUMENTATION); MOZ_ASSERT(v.isObject() || v.isUndefined()); return v.isObject() ? &v.toObject() : nullptr; } void setInstrumentationHolder(JSObject* instrumentation) { setReservedSlot(INSTRUMENTATION, ObjectValue(*instrumentation)); } JSObject* getSourceURLsHolder() const { Value v = getReservedSlot(SOURCE_URLS); MOZ_ASSERT(v.isObject() || v.isUndefined()); return v.isObject() ? &v.toObject() : nullptr; } void setSourceURLsHolder(JSObject* holder) { setReservedSlot(SOURCE_URLS, ObjectValue(*holder)); } void clearSourceURLSHolder() { // This is called at the start of shrinking GCs, so avoids barriers. getSlotRef(SOURCE_URLS).unbarrieredSet(UndefinedValue()); } // A class used in place of a prototype during off-thread parsing. struct OffThreadPlaceholderObject : public NativeObject { static const int32_t SlotIndexSlot = 0; static const JSClass class_; static OffThreadPlaceholderObject* New(JSContext* cx, unsigned slot); inline int32_t getSlotIndex() const; }; static bool isOffThreadPrototypePlaceholder(JSObject* obj) { return obj->is(); } JSObject* getPrototypeForOffThreadPlaceholder(JSObject* placeholder); private: static bool resolveOffThreadConstructor(JSContext* cx, Handle global, JSProtoKey key); static JSObject* createOffThreadObject(JSContext* cx, Handle global, unsigned slot); }; /* * Unless otherwise specified, define ctor.prototype = proto as non-enumerable, * non-configurable, and non-writable; and define proto.constructor = ctor as * non-enumerable but configurable and writable. */ extern bool LinkConstructorAndPrototype( JSContext* cx, JSObject* ctor, JSObject* proto, unsigned prototypeAttrs = JSPROP_PERMANENT | JSPROP_READONLY, unsigned constructorAttrs = 0); /* * Define properties and/or functions on any object. Either ps or fs, or both, * may be null. */ extern bool DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj, const JSPropertySpec* ps, const JSFunctionSpec* fs); extern bool DefineToStringTag(JSContext* cx, HandleObject obj, JSAtom* tag); /* * Convenience templates to generic constructor and prototype creation functions * for ClassSpecs. */ template JSObject* GenericCreateConstructor(JSContext* cx, JSProtoKey key) { // Note - We duplicate the trick from ClassName() so that we don't need to // include vm/JSAtom-inl.h here. PropertyName* name = (&cx->names().Null)[key]; return GlobalObject::createConstructor(cx, ctor, name, length, kind, jitInfo); } template JSObject* GenericCreatePrototype(JSContext* cx, JSProtoKey key) { static_assert( !std::is_same_v, "creating Object.prototype is very special and isn't handled here"); MOZ_ASSERT(&T::class_ == ProtoKeyToClass(key), "type mismatch--probably too much copy/paste in your ClassSpec"); MOZ_ASSERT( InheritanceProtoKeyForStandardClass(key) == JSProto_Object, "subclasses (of anything but Object) can't use GenericCreatePrototype"); return GlobalObject::createBlankPrototype(cx, cx->global(), &T::protoClass_); } inline JSProtoKey StandardProtoKeyOrNull(const JSObject* obj) { return JSCLASS_CACHED_PROTO_KEY(obj->getClass()); } JSObject* NewTenuredObjectWithFunctionPrototype(JSContext* cx, Handle global); } // namespace js template <> inline bool JSObject::is() const { return !!(getClass()->flags & JSCLASS_IS_GLOBAL); } #endif /* vm_GlobalObject_h */