diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/vm/GlobalObject.h | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | js/src/vm/GlobalObject.h | 998 |
1 files changed, 998 insertions, 0 deletions
diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h new file mode 100644 index 0000000000..8cc6a9d51d --- /dev/null +++ b/js/src/vm/GlobalObject.h @@ -0,0 +1,998 @@ +/* -*- 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 <stdint.h> +#include <type_traits> + +#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<GlobalObject*> global, + JSProtoKey key, HandleObject ctor, + HandleObject proto); + + private: + enum class IfClassIsDisabled { DoNothing, Throw }; + + static bool resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, + JSProtoKey key, IfClassIsDisabled mode); + + public: + static bool ensureConstructor(JSContext* cx, Handle<GlobalObject*> 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<GlobalObject*> 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<GlobalObject*> 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<GlobalObject*> 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<GlobalObject*> global, + Handle<TaggedProto> 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<GlobalObject*> 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 <typename T> + static T* createBlankPrototypeInheriting(JSContext* cx, HandleObject proto) { + NativeObject* res = createBlankPrototypeInheriting(cx, &T::class_, proto); + return res ? &res->template as<T>() : nullptr; + } + + template <typename T> + static T* createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global) { + NativeObject* res = createBlankPrototype(cx, global, &T::class_); + return res ? &res->template as<T>() : nullptr; + } + + static JSObject* getOrCreateObjectPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!global->functionObjectClassesInitialized()) { + if (!ensureConstructor(cx, global, JSProto_Object)) { + return nullptr; + } + } + return &global->getPrototype(JSProto_Object).toObject(); + } + + static JSObject* getOrCreateFunctionConstructor( + JSContext* cx, Handle<GlobalObject*> global) { + if (!global->functionObjectClassesInitialized()) { + if (!ensureConstructor(cx, global, JSProto_Object)) { + return nullptr; + } + } + return &global->getConstructor(JSProto_Function).toObject(); + } + + static JSObject* getOrCreateFunctionPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!global->functionObjectClassesInitialized()) { + if (!ensureConstructor(cx, global, JSProto_Object)) { + return nullptr; + } + } + return &global->getPrototype(JSProto_Function).toObject(); + } + + static NativeObject* getOrCreateArrayPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Array)) { + return nullptr; + } + return &global->getPrototype(JSProto_Array).toObject().as<NativeObject>(); + } + + NativeObject* maybeGetArrayPrototype() { + if (classIsInitialized(JSProto_Array)) { + return &getPrototype(JSProto_Array).toObject().as<NativeObject>(); + } + return nullptr; + } + + static JSObject* getOrCreateBooleanPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Boolean)) { + return nullptr; + } + return &global->getPrototype(JSProto_Boolean).toObject(); + } + + static JSObject* getOrCreateNumberPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Number)) { + return nullptr; + } + return &global->getPrototype(JSProto_Number).toObject(); + } + + static JSObject* getOrCreateStringPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_String)) { + return nullptr; + } + return &global->getPrototype(JSProto_String).toObject(); + } + + static JSObject* getOrCreateSymbolPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Symbol)) { + return nullptr; + } + return &global->getPrototype(JSProto_Symbol).toObject(); + } + + static JSObject* getOrCreateBigIntPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_BigInt)) { + return nullptr; + } + return &global->getPrototype(JSProto_BigInt).toObject(); + } + + static JSObject* getOrCreatePromisePrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Promise)) { + return nullptr; + } + return &global->getPrototype(JSProto_Promise).toObject(); + } + + static JSObject* getOrCreateRegExpPrototype(JSContext* cx, + Handle<GlobalObject*> 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<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_SavedFrame)) { + return nullptr; + } + return &global->getPrototype(JSProto_SavedFrame).toObject(); + } + + static JSObject* getOrCreateArrayBufferConstructor( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) { + return nullptr; + } + return &global->getConstructor(JSProto_ArrayBuffer).toObject(); + } + + static JSObject* getOrCreateArrayBufferPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) { + return nullptr; + } + return &global->getPrototype(JSProto_ArrayBuffer).toObject(); + } + + static JSObject* getOrCreateSharedArrayBufferPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) { + return nullptr; + } + return &global->getPrototype(JSProto_SharedArrayBuffer).toObject(); + } + + static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx, + Handle<GlobalObject*> 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<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Error)) { + return nullptr; + } + return &global->getConstructor(JSProto_Error).toObject().as<JSFunction>(); + } + + static JSObject* getOrCreateErrorPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR); + } + + static NativeObject* getOrCreateSetPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Set)) { + return nullptr; + } + return &global->getPrototype(JSProto_Set).toObject().as<NativeObject>(); + } + + static NativeObject* getOrCreateWeakSetPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_WeakSet)) { + return nullptr; + } + return &global->getPrototype(JSProto_WeakSet).toObject().as<NativeObject>(); + } + + static bool ensureModulePrototypesCreated(JSContext* cx, + Handle<GlobalObject*> global); + + static JSObject* getOrCreateModulePrototype(JSContext* cx, + Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto); + } + + static JSObject* getOrCreateImportEntryPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, IMPORT_ENTRY_PROTO, + initImportEntryProto); + } + + static JSObject* getOrCreateExportEntryPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO, + initExportEntryProto); + } + + static JSObject* getOrCreateRequestedModulePrototype( + JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, REQUESTED_MODULE_PROTO, + initRequestedModuleProto); + } + + static JSFunction* getOrCreateTypedArrayConstructor( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_TypedArray)) { + return nullptr; + } + return &global->getConstructor(JSProto_TypedArray) + .toObject() + .as<JSFunction>(); + } + + static JSObject* getOrCreateTypedArrayPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_TypedArray)) { + return nullptr; + } + return &global->getPrototype(JSProto_TypedArray).toObject(); + } + + private: + using ObjectInitOp = bool (*)(JSContext*, Handle<GlobalObject*>); + using ObjectInitWithTagOp = bool (*)(JSContext*, Handle<GlobalObject*>, + HandleAtom); + + static JSObject* getOrCreateObject(JSContext* cx, + Handle<GlobalObject*> 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<GlobalObject*> 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<GlobalObject*> global, + unsigned slot, ObjectInitOp init); + static JSObject* createObject(JSContext* cx, Handle<GlobalObject*> global, + unsigned slot, HandleAtom tag, + ObjectInitWithTagOp init); + + static JSObject* createIteratorPrototype(JSContext* cx, + Handle<GlobalObject*> global); + + public: + static JSObject* getOrCreateIteratorPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (global->getReservedSlot(ITERATOR_PROTO).isObject()) { + return &global->getReservedSlot(ITERATOR_PROTO).toObject(); + } + return createIteratorPrototype(cx, global); + } + + static NativeObject* getOrCreateArrayIteratorPrototype( + JSContext* cx, Handle<GlobalObject*> global); + + NativeObject* maybeGetArrayIteratorPrototype() { + Value v = getSlotRef(ARRAY_ITERATOR_PROTO); + if (v.isObject()) { + return &v.toObject().as<NativeObject>(); + } + return nullptr; + } + + static JSObject* getOrCreateStringIteratorPrototype( + JSContext* cx, Handle<GlobalObject*> global); + + static JSObject* getOrCreateRegExpStringIteratorPrototype( + JSContext* cx, Handle<GlobalObject*> global); + + void setGeneratorObjectPrototype(JSObject* obj) { + setSlot(GENERATOR_OBJECT_PROTO, ObjectValue(*obj)); + } + + static JSObject* getOrCreateGeneratorObjectPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { + return nullptr; + } + return &global->getSlot(GENERATOR_OBJECT_PROTO).toObject(); + } + + static JSObject* getOrCreateGeneratorFunctionPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { + return nullptr; + } + return &global->getPrototype(JSProto_GeneratorFunction).toObject(); + } + + static JSObject* getOrCreateGeneratorFunction(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) { + return nullptr; + } + return &global->getConstructor(JSProto_GeneratorFunction).toObject(); + } + + static JSObject* getOrCreateAsyncFunctionPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) { + return nullptr; + } + return &global->getPrototype(JSProto_AsyncFunction).toObject(); + } + + static JSObject* getOrCreateAsyncFunction(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) { + return nullptr; + } + return &global->getConstructor(JSProto_AsyncFunction).toObject(); + } + + static JSObject* createAsyncIteratorPrototype(JSContext* cx, + Handle<GlobalObject*> global); + + static JSObject* getOrCreateAsyncIteratorPrototype( + JSContext* cx, Handle<GlobalObject*> 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<GlobalObject*> global) { + return getOrCreateObject(cx, global, ASYNC_FROM_SYNC_ITERATOR_PROTO, + initAsyncFromSyncIteratorProto); + } + + static JSObject* getOrCreateAsyncGenerator(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) { + return nullptr; + } + return &global->getPrototype(JSProto_AsyncGeneratorFunction).toObject(); + } + + static JSObject* getOrCreateAsyncGeneratorFunction( + JSContext* cx, Handle<GlobalObject*> 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<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) { + return nullptr; + } + return &global->getSlot(ASYNC_GENERATOR_PROTO).toObject(); + } + + static JSObject* getOrCreateMapIteratorPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO, + initMapIteratorProto); + } + + static JSObject* getOrCreateSetIteratorPrototype( + JSContext* cx, Handle<GlobalObject*> global) { + return getOrCreateObject(cx, global, SET_ITERATOR_PROTO, + initSetIteratorProto); + } + + static JSObject* getOrCreateDataViewPrototype(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_DataView)) { + return nullptr; + } + return &global->getPrototype(JSProto_DataView).toObject(); + } + + static JSObject* getOrCreatePromiseConstructor(JSContext* cx, + Handle<GlobalObject*> global) { + if (!ensureConstructor(cx, global, JSProto_Promise)) { + return nullptr; + } + return &global->getConstructor(JSProto_Promise).toObject(); + } + + static NativeObject* getOrCreateWrapForValidIteratorPrototype( + JSContext* cx, Handle<GlobalObject*> global); + + static NativeObject* getOrCreateIteratorHelperPrototype( + JSContext* cx, Handle<GlobalObject*> global); + + static NativeObject* getOrCreateAsyncIteratorHelperPrototype( + JSContext* cx, Handle<GlobalObject*> global); + static bool initAsyncIteratorHelperProto(JSContext* cx, + Handle<GlobalObject*> global); + + static NativeObject* getIntrinsicsHolder(JSContext* cx, + Handle<GlobalObject*> 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<NativeObject>(); + 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<bool> exists = maybeExistingIntrinsicValue(name, &val); + MOZ_ASSERT(exists, "intrinsic must already have been added to holder"); + + return val; + } + + static bool maybeGetIntrinsicValue(JSContext* cx, + Handle<GlobalObject*> global, + Handle<PropertyName*> 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<GlobalObject*> 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<GlobalObject*> global, + HandlePropertyName name, HandleValue value); + + static inline bool setIntrinsicValue(JSContext* cx, + Handle<GlobalObject*> global, + HandlePropertyName name, + HandleValue value); + + static bool getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global, + HandlePropertyName selfHostedName, + HandleAtom name, unsigned nargs, + MutableHandleValue funVal); + + static RegExpStatics* getRegExpStatics(JSContext* cx, + Handle<GlobalObject*> global); + + static JSObject* getOrCreateThrowTypeError(JSContext* cx, + Handle<GlobalObject*> global); + + static bool isRuntimeCodeGenEnabled(JSContext* cx, HandleString code, + Handle<GlobalObject*> global); + + static bool getOrCreateEval(JSContext* cx, Handle<GlobalObject*> 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<GlobalObject*> global); + template <unsigned Slot, const JSClass* ProtoClass, + const JSFunctionSpec* Methods> + static bool initObjectIteratorProto(JSContext* cx, + Handle<GlobalObject*> global, + HandleAtom tag); + + // Implemented in vm/AsyncIteration.cpp. + static bool initAsyncIteratorProto(JSContext* cx, + Handle<GlobalObject*> global); + static bool initAsyncFromSyncIteratorProto(JSContext* cx, + Handle<GlobalObject*> global); + + // Implemented in builtin/MapObject.cpp. + static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global); + static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global); + + // Implemented in builtin/ModuleObject.cpp + static bool initModuleProto(JSContext* cx, Handle<GlobalObject*> global); + static bool initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global); + static bool initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global); + static bool initRequestedModuleProto(JSContext* cx, + Handle<GlobalObject*> global); + + static bool initStandardClasses(JSContext* cx, Handle<GlobalObject*> global); + static bool initSelfHostingBuiltins(JSContext* cx, + Handle<GlobalObject*> 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<NativeObject>(); + } + static NativeObject* getOrCreateForOfPICObject(JSContext* cx, + Handle<GlobalObject*> 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<OffThreadPlaceholderObject>(); + } + + JSObject* getPrototypeForOffThreadPlaceholder(JSObject* placeholder); + + private: + static bool resolveOffThreadConstructor(JSContext* cx, + Handle<GlobalObject*> global, + JSProtoKey key); + static JSObject* createOffThreadObject(JSContext* cx, + Handle<GlobalObject*> 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 <JSNative ctor, unsigned length, gc::AllocKind kind, + const JSJitInfo* jitInfo = nullptr> +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 <typename T> +JSObject* GenericCreatePrototype(JSContext* cx, JSProtoKey key) { + static_assert( + !std::is_same_v<T, PlainObject>, + "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<GlobalObject*> global); + +} // namespace js + +template <> +inline bool JSObject::is<js::GlobalObject>() const { + return !!(getClass()->flags & JSCLASS_IS_GLOBAL); +} + +#endif /* vm_GlobalObject_h */ |