Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / vm / GlobalObject.h
blob68e4dea261edd779fde976cc5087a66c9b3140ba
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_GlobalObject_h
8 #define vm_GlobalObject_h
10 #include "js/GlobalObject.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/EnumeratedArray.h"
15 #include <stdint.h>
16 #include <type_traits>
18 #include "jsexn.h"
19 #include "jsfriendapi.h"
20 #include "jspubtd.h"
21 #include "jstypes.h"
22 #include "NamespaceImports.h"
24 #include "gc/AllocKind.h"
25 #include "js/CallArgs.h"
26 #include "js/Class.h"
27 #include "js/ErrorReport.h"
28 #include "js/PropertyDescriptor.h"
29 #include "js/RootingAPI.h"
30 #include "js/TypeDecls.h"
31 #include "js/Value.h"
32 #include "vm/ArrayObject.h"
33 #include "vm/JSAtomState.h"
34 #include "vm/JSContext.h"
35 #include "vm/JSFunction.h"
36 #include "vm/JSObject.h"
37 #include "vm/NativeObject.h"
38 #include "vm/Realm.h"
39 #include "vm/RegExpShared.h"
40 #include "vm/Shape.h"
41 #include "vm/StringType.h"
43 struct JSFunctionSpec;
44 class JSJitInfo;
45 struct JSPrincipals;
46 struct JSPropertySpec;
48 namespace JS {
49 class JS_PUBLIC_API RealmOptions;
52 namespace js {
54 class ArgumentsObject;
55 class GlobalScope;
56 class GlobalLexicalEnvironmentObject;
57 class PlainObject;
58 class PropertyIteratorObject;
59 class RegExpStatics;
61 namespace gc {
62 class FinalizationRegistryGlobalData;
63 } // namespace gc
65 // Fixed slot capacities for PlainObjects. The global has a cached Shape for
66 // PlainObject with default prototype for each of these values.
67 enum class PlainObjectSlotsKind {
68 Slots0,
69 Slots2,
70 Slots4,
71 Slots8,
72 Slots12,
73 Slots16,
74 Limit
77 static PlainObjectSlotsKind PlainObjectSlotsKindFromAllocKind(
78 gc::AllocKind kind) {
79 switch (kind) {
80 case gc::AllocKind::OBJECT0:
81 return PlainObjectSlotsKind::Slots0;
82 case gc::AllocKind::OBJECT2:
83 return PlainObjectSlotsKind::Slots2;
84 case gc::AllocKind::OBJECT4:
85 return PlainObjectSlotsKind::Slots4;
86 case gc::AllocKind::OBJECT8:
87 return PlainObjectSlotsKind::Slots8;
88 case gc::AllocKind::OBJECT12:
89 return PlainObjectSlotsKind::Slots12;
90 case gc::AllocKind::OBJECT16:
91 return PlainObjectSlotsKind::Slots16;
92 default:
93 break;
95 MOZ_CRASH("Invalid kind");
98 // Data attached to a GlobalObject. This is freed when clearing the Realm's
99 // global_ only because this way we don't need to add a finalizer to all
100 // GlobalObject JSClasses.
101 class GlobalObjectData {
102 friend class js::GlobalObject;
104 GlobalObjectData(const GlobalObjectData&) = delete;
105 void operator=(const GlobalObjectData&) = delete;
107 public:
108 explicit GlobalObjectData(Zone* zone);
110 ~GlobalObjectData();
112 // The global environment record's [[VarNames]] list that contains all
113 // names declared using FunctionDeclaration, GeneratorDeclaration, and
114 // VariableDeclaration declarations in global code in this global's realm.
115 // Names are only removed from this list by a |delete IdentifierReference|
116 // that successfully removes that global property.
117 using VarNamesSet =
118 GCHashSet<HeapPtr<JSAtom*>, DefaultHasher<JSAtom*>, CellAllocPolicy>;
119 VarNamesSet varNames;
121 // The original values for built-in constructors (with their prototype
122 // objects) based on JSProtoKey.
124 // This is necessary to implement spec language speaking in terms of "the
125 // original Array prototype object", or "as if by the expression new Array()"
126 // referring to the original Array constructor. The actual (writable and even
127 // deletable) Object, Array, &c. properties are not stored here.
128 struct ConstructorWithProto {
129 HeapPtr<JSObject*> constructor;
130 HeapPtr<JSObject*> prototype;
132 using CtorArray =
133 mozilla::EnumeratedArray<JSProtoKey, JSProto_LIMIT, ConstructorWithProto>;
134 CtorArray builtinConstructors;
136 // Built-in prototypes for this global. Note that this is different from the
137 // set of built-in constructors/prototypes based on JSProtoKey.
138 enum class ProtoKind {
139 IteratorProto,
140 ArrayIteratorProto,
141 StringIteratorProto,
142 RegExpStringIteratorProto,
143 GeneratorObjectProto,
144 AsyncIteratorProto,
145 AsyncFromSyncIteratorProto,
146 AsyncGeneratorProto,
147 MapIteratorProto,
148 SetIteratorProto,
149 WrapForValidIteratorProto,
150 IteratorHelperProto,
151 AsyncIteratorHelperProto,
153 Limit
155 using ProtoArray =
156 mozilla::EnumeratedArray<ProtoKind, ProtoKind::Limit, HeapPtr<JSObject*>>;
157 ProtoArray builtinProtos;
159 HeapPtr<GlobalScope*> emptyGlobalScope;
161 // The lexical environment for global let/const/class bindings.
162 HeapPtr<GlobalLexicalEnvironmentObject*> lexicalEnvironment;
164 // The WindowProxy associated with this global.
165 HeapPtr<JSObject*> windowProxy;
167 // Functions and other top-level values for self-hosted code. The "computed"
168 // holder is used as the target of `SetIntrinsic` calls, but the same property
169 // may also be cached on the normal intrinsics holder for `GetIntrinsic`.
170 HeapPtr<NativeObject*> intrinsicsHolder;
171 HeapPtr<NativeObject*> computedIntrinsicsHolder;
173 // Cache used to optimize certain for-of operations.
174 HeapPtr<NativeObject*> forOfPICChain;
176 // List of source URLs for this realm. This is used by the debugger.
177 HeapPtr<ArrayObject*> sourceURLsHolder;
179 // Realm-specific object that can be used as key in WeakMaps.
180 HeapPtr<PlainObject*> realmKeyObject;
182 // The unique %ThrowTypeError% function for this global.
183 HeapPtr<JSFunction*> throwTypeError;
185 // The unique %eval% function (for indirect eval) for this global.
186 HeapPtr<JSFunction*> eval;
188 // Empty iterator object used for for-in with null/undefined.
189 HeapPtr<PropertyIteratorObject*> emptyIterator;
191 // Cached shape for new arrays with Array.prototype as prototype.
192 HeapPtr<SharedShape*> arrayShapeWithDefaultProto;
194 // Shape for PlainObject with %Object.prototype% as proto, for each object
195 // AllocKind.
196 using PlainObjectShapeArray = mozilla::EnumeratedArray<
197 PlainObjectSlotsKind, PlainObjectSlotsKind::Limit, HeapPtr<SharedShape*>>;
198 PlainObjectShapeArray plainObjectShapesWithDefaultProto;
200 // Shape for JSFunction with %Function.prototype% as proto, for both
201 // non-extended and extended functions.
202 HeapPtr<SharedShape*> functionShapeWithDefaultProto;
203 HeapPtr<SharedShape*> extendedFunctionShapeWithDefaultProto;
205 // Shape for BoundFunctionObject with %Function.prototype% as proto.
206 HeapPtr<SharedShape*> boundFunctionShapeWithDefaultProto;
208 // Global state for regular expressions.
209 RegExpRealm regExpRealm;
211 HeapPtr<ArgumentsObject*> mappedArgumentsTemplate;
212 HeapPtr<ArgumentsObject*> unmappedArgumentsTemplate;
214 HeapPtr<PlainObject*> iterResultTemplate;
215 HeapPtr<PlainObject*> iterResultWithoutPrototypeTemplate;
217 // Lazily initialized script source object to use for scripts cloned from the
218 // self-hosting stencil.
219 HeapPtr<ScriptSourceObject*> selfHostingScriptSource;
221 UniquePtr<gc::FinalizationRegistryGlobalData> finalizationRegistryData;
223 // The number of times that one of the following has occurred:
224 // 1. A property of this GlobalObject is deleted.
225 // 2. A data property of this GlobalObject is converted to an accessor,
226 // or vice versa.
227 // 3. A property is defined on the global lexical that shadows a property on
228 // this GlobalObject.
229 uint32_t generationCount = 0;
231 // Whether the |globalThis| property has been resolved on the global object.
232 bool globalThisResolved = false;
234 void trace(JSTracer* trc, GlobalObject* global);
235 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
236 JS::ClassInfo* info) const;
238 static constexpr size_t offsetOfLexicalEnvironment() {
239 static_assert(sizeof(lexicalEnvironment) == sizeof(uintptr_t),
240 "JIT code assumes field is pointer-sized");
241 return offsetof(GlobalObjectData, lexicalEnvironment);
243 static constexpr size_t offsetOfRegExpRealm() {
244 return offsetof(GlobalObjectData, regExpRealm);
248 class GlobalObject : public NativeObject {
249 enum : unsigned {
250 GLOBAL_DATA_SLOT = JSCLASS_GLOBAL_APPLICATION_SLOTS,
252 // Total reserved-slot count for global objects.
253 RESERVED_SLOTS
256 // The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and
257 // we won't expose GlobalObject, so just assert that the two values are
258 // synchronized.
259 static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS,
260 "global object slot counts are inconsistent");
262 // Ensure GlobalObjectData is only one dereference away.
263 static_assert(GLOBAL_DATA_SLOT < MAX_FIXED_SLOTS,
264 "GlobalObjectData should be stored in a fixed slot for "
265 "performance reasons");
267 using ProtoKind = GlobalObjectData::ProtoKind;
269 GlobalObjectData* maybeData() {
270 Value v = getReservedSlot(GLOBAL_DATA_SLOT);
271 return static_cast<GlobalObjectData*>(v.toPrivate());
273 const GlobalObjectData* maybeData() const {
274 Value v = getReservedSlot(GLOBAL_DATA_SLOT);
275 return static_cast<const GlobalObjectData*>(v.toPrivate());
278 GlobalObjectData& data() { return *maybeData(); }
279 const GlobalObjectData& data() const { return *maybeData(); }
281 void initBuiltinProto(ProtoKind kind, JSObject* proto) {
282 MOZ_ASSERT(proto);
283 data().builtinProtos[kind].init(proto);
285 bool hasBuiltinProto(ProtoKind kind) const {
286 return bool(data().builtinProtos[kind]);
288 JSObject* maybeBuiltinProto(ProtoKind kind) const {
289 return data().builtinProtos[kind];
291 JSObject& getBuiltinProto(ProtoKind kind) const {
292 MOZ_ASSERT(hasBuiltinProto(kind));
293 return *data().builtinProtos[kind];
296 public:
297 GlobalLexicalEnvironmentObject& lexicalEnvironment() {
298 return *data().lexicalEnvironment;
300 GlobalScope& emptyGlobalScope() const;
302 void traceData(JSTracer* trc, GlobalObject* global) {
303 data().trace(trc, global);
305 void releaseData(JS::GCContext* gcx);
307 void addSizeOfData(mozilla::MallocSizeOf mallocSizeOf,
308 JS::ClassInfo* info) const {
309 if (maybeData()) {
310 data().addSizeOfIncludingThis(mallocSizeOf, info);
314 void setOriginalEval(JSFunction* evalFun) {
315 MOZ_ASSERT(!data().eval);
316 data().eval.init(evalFun);
319 bool hasConstructor(JSProtoKey key) const {
320 return bool(data().builtinConstructors[key].constructor);
322 JSObject& getConstructor(JSProtoKey key) const {
323 MOZ_ASSERT(hasConstructor(key));
324 return *maybeGetConstructor(key);
327 static bool skipDeselectedConstructor(JSContext* cx, JSProtoKey key);
329 private:
330 enum class IfClassIsDisabled { DoNothing, Throw };
332 static bool resolveConstructor(JSContext* cx, Handle<GlobalObject*> global,
333 JSProtoKey key, IfClassIsDisabled mode);
335 public:
336 static bool ensureConstructor(JSContext* cx, Handle<GlobalObject*> global,
337 JSProtoKey key) {
338 if (global->isStandardClassResolved(key)) {
339 return true;
341 return resolveConstructor(cx, global, key, IfClassIsDisabled::Throw);
344 static JSObject* getOrCreateConstructor(JSContext* cx, JSProtoKey key) {
345 MOZ_ASSERT(key != JSProto_Null);
346 Handle<GlobalObject*> global = cx->global();
347 if (!GlobalObject::ensureConstructor(cx, global, key)) {
348 return nullptr;
350 return &global->getConstructor(key);
353 static JSObject* getOrCreatePrototype(JSContext* cx, JSProtoKey key) {
354 MOZ_ASSERT(key != JSProto_Null);
355 Handle<GlobalObject*> global = cx->global();
356 if (!GlobalObject::ensureConstructor(cx, global, key)) {
357 return nullptr;
359 return &global->getPrototype(key);
362 static JS::Handle<JSObject*> getOrCreatePrototypeHandle(JSContext* cx,
363 JSProtoKey key) {
364 MOZ_ASSERT(key != JSProto_Null);
365 Handle<GlobalObject*> global = cx->global();
366 if (!GlobalObject::ensureConstructor(cx, global, key)) {
367 return nullptr;
369 return global->getPrototypeHandle(key);
372 JSObject* maybeGetConstructor(JSProtoKey protoKey) const {
373 MOZ_ASSERT(JSProto_Null < protoKey);
374 MOZ_ASSERT(protoKey < JSProto_LIMIT);
375 return data().builtinConstructors[protoKey].constructor;
378 JSObject* maybeGetPrototype(JSProtoKey protoKey) const {
379 MOZ_ASSERT(JSProto_Null < protoKey);
380 MOZ_ASSERT(protoKey < JSProto_LIMIT);
381 return data().builtinConstructors[protoKey].prototype;
384 static bool maybeResolveGlobalThis(JSContext* cx,
385 Handle<GlobalObject*> global,
386 bool* resolved);
388 void setConstructor(JSProtoKey key, JSObject* obj) {
389 MOZ_ASSERT(obj);
390 data().builtinConstructors[key].constructor = obj;
393 bool hasPrototype(JSProtoKey key) const {
394 return bool(data().builtinConstructors[key].prototype);
396 JSObject& getPrototype(JSProtoKey key) const {
397 MOZ_ASSERT(hasPrototype(key));
398 return *maybeGetPrototype(key);
401 JS::Handle<JSObject*> getPrototypeHandle(JSProtoKey protoKey) const {
402 MOZ_ASSERT(hasPrototype(protoKey));
403 MOZ_ASSERT(JSProto_Null < protoKey);
404 MOZ_ASSERT(protoKey < JSProto_LIMIT);
405 return Handle<JSObject*>::fromMarkedLocation(
406 &data().builtinConstructors[protoKey].prototype.get());
409 void setPrototype(JSProtoKey key, JSObject* obj) {
410 MOZ_ASSERT(obj);
411 data().builtinConstructors[key].prototype = obj;
415 * Lazy standard classes need a way to indicate they have been initialized.
416 * Otherwise, when we delete them, we might accidentally recreate them via
417 * a lazy initialization. We use the presence of an object in the constructor
418 * array to indicate that they've been initialized.
420 * Note: A few builtin objects, like JSON and Math, are not constructors,
421 * so getConstructor is a bit of a misnomer.
423 bool isStandardClassResolved(JSProtoKey key) const {
424 return hasConstructor(key);
427 private:
428 bool classIsInitialized(JSProtoKey key) const {
429 bool inited = hasConstructor(key);
430 MOZ_ASSERT(inited == hasPrototype(key));
431 return inited;
434 bool functionObjectClassesInitialized() const {
435 bool inited = classIsInitialized(JSProto_Function);
436 MOZ_ASSERT(inited == classIsInitialized(JSProto_Object));
437 return inited;
440 // Disallow use of unqualified JSObject::create in GlobalObject.
441 static GlobalObject* create(...) = delete;
443 friend struct ::JSRuntime;
444 static GlobalObject* createInternal(JSContext* cx, const JSClass* clasp);
446 public:
447 static GlobalObject* new_(JSContext* cx, const JSClass* clasp,
448 JSPrincipals* principals,
449 JS::OnNewGlobalHookOption hookOption,
450 const JS::RealmOptions& options);
453 * Create a constructor function with the specified name and length using
454 * ctor, a method which creates objects with the given class.
456 static JSFunction* createConstructor(
457 JSContext* cx, JSNative ctor, JSAtom* name, unsigned length,
458 gc::AllocKind kind = gc::AllocKind::FUNCTION,
459 const JSJitInfo* jitInfo = nullptr);
462 * Create an object to serve as [[Prototype]] for instances of the given
463 * class, using |Object.prototype| as its [[Prototype]]. Users creating
464 * prototype objects with particular internal structure (e.g. reserved
465 * slots guaranteed to contain values of particular types) must immediately
466 * complete the minimal initialization to make the returned object safe to
467 * touch.
469 static NativeObject* createBlankPrototype(
470 JSContext* cx, Handle<GlobalObject*> global, const JSClass* clasp,
471 ObjectFlags objFlags = ObjectFlags());
474 * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
475 * of the returned blank prototype.
477 static NativeObject* createBlankPrototypeInheriting(JSContext* cx,
478 const JSClass* clasp,
479 HandleObject proto);
481 template <typename T>
482 static T* createBlankPrototypeInheriting(JSContext* cx, HandleObject proto) {
483 NativeObject* res = createBlankPrototypeInheriting(cx, &T::class_, proto);
484 return res ? &res->template as<T>() : nullptr;
487 template <typename T>
488 static T* createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global,
489 ObjectFlags objFlags = ObjectFlags()) {
490 NativeObject* res = createBlankPrototype(cx, global, &T::class_, objFlags);
491 return res ? &res->template as<T>() : nullptr;
494 // Object, Function, and eval are eagerly resolved when creating the global.
495 JSObject& getObjectPrototype() {
496 MOZ_ASSERT(functionObjectClassesInitialized());
497 return getPrototype(JSProto_Object);
499 Handle<JSObject*> getObjectPrototypeHandle() {
500 MOZ_ASSERT(functionObjectClassesInitialized());
501 return getPrototypeHandle(JSProto_Object);
503 JSObject& getFunctionConstructor() {
504 MOZ_ASSERT(functionObjectClassesInitialized());
505 return getConstructor(JSProto_Function);
507 JSObject& getFunctionPrototype() {
508 MOZ_ASSERT(functionObjectClassesInitialized());
509 return getPrototype(JSProto_Function);
511 JSFunction& getEvalFunction() {
512 MOZ_ASSERT(data().eval);
513 return *data().eval;
516 static NativeObject* getOrCreateArrayPrototype(JSContext* cx,
517 Handle<GlobalObject*> global) {
518 if (!ensureConstructor(cx, global, JSProto_Array)) {
519 return nullptr;
521 return &global->getPrototype(JSProto_Array).as<NativeObject>();
524 NativeObject* maybeGetArrayPrototype() {
525 if (classIsInitialized(JSProto_Array)) {
526 return &getPrototype(JSProto_Array).as<NativeObject>();
528 return nullptr;
531 static JSObject* getOrCreateBooleanPrototype(JSContext* cx,
532 Handle<GlobalObject*> global) {
533 if (!ensureConstructor(cx, global, JSProto_Boolean)) {
534 return nullptr;
536 return &global->getPrototype(JSProto_Boolean);
539 static JSObject* getOrCreateNumberPrototype(JSContext* cx,
540 Handle<GlobalObject*> global) {
541 if (!ensureConstructor(cx, global, JSProto_Number)) {
542 return nullptr;
544 return &global->getPrototype(JSProto_Number);
547 static JSObject* getOrCreateStringPrototype(JSContext* cx,
548 Handle<GlobalObject*> global) {
549 if (!ensureConstructor(cx, global, JSProto_String)) {
550 return nullptr;
552 return &global->getPrototype(JSProto_String);
555 static JSObject* getOrCreateSymbolPrototype(JSContext* cx,
556 Handle<GlobalObject*> global) {
557 if (!ensureConstructor(cx, global, JSProto_Symbol)) {
558 return nullptr;
560 return &global->getPrototype(JSProto_Symbol);
563 static JSObject* getOrCreateBigIntPrototype(JSContext* cx,
564 Handle<GlobalObject*> global) {
565 if (!ensureConstructor(cx, global, JSProto_BigInt)) {
566 return nullptr;
568 return &global->getPrototype(JSProto_BigInt);
571 #ifdef ENABLE_RECORD_TUPLE
572 static JSObject* getOrCreateRecordPrototype(JSContext* cx,
573 Handle<GlobalObject*> global) {
574 if (!ensureConstructor(cx, global, JSProto_Record)) {
575 return nullptr;
577 return &global->getPrototype(JSProto_Record);
580 static JSObject* getOrCreateTuplePrototype(JSContext* cx,
581 Handle<GlobalObject*> global) {
582 if (!ensureConstructor(cx, global, JSProto_Tuple)) {
583 return nullptr;
585 return &global->getPrototype(JSProto_Tuple);
587 #endif
589 static JSObject* getOrCreatePromisePrototype(JSContext* cx,
590 Handle<GlobalObject*> global) {
591 if (!ensureConstructor(cx, global, JSProto_Promise)) {
592 return nullptr;
594 return &global->getPrototype(JSProto_Promise);
597 static JSObject* getOrCreateRegExpPrototype(JSContext* cx,
598 Handle<GlobalObject*> global) {
599 if (!ensureConstructor(cx, global, JSProto_RegExp)) {
600 return nullptr;
602 return &global->getPrototype(JSProto_RegExp);
605 JSObject* maybeGetRegExpPrototype() {
606 if (classIsInitialized(JSProto_RegExp)) {
607 return &getPrototype(JSProto_RegExp);
609 return nullptr;
612 static JSObject* getOrCreateSavedFramePrototype(
613 JSContext* cx, Handle<GlobalObject*> global) {
614 if (!ensureConstructor(cx, global, JSProto_SavedFrame)) {
615 return nullptr;
617 return &global->getPrototype(JSProto_SavedFrame);
620 static JSObject* getOrCreateArrayBufferConstructor(
621 JSContext* cx, Handle<GlobalObject*> global) {
622 if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) {
623 return nullptr;
625 return &global->getConstructor(JSProto_ArrayBuffer);
628 static JSObject* getOrCreateArrayBufferPrototype(
629 JSContext* cx, Handle<GlobalObject*> global) {
630 if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) {
631 return nullptr;
633 return &global->getPrototype(JSProto_ArrayBuffer);
636 static JSObject* getOrCreateSharedArrayBufferPrototype(
637 JSContext* cx, Handle<GlobalObject*> global) {
638 if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) {
639 return nullptr;
641 return &global->getPrototype(JSProto_SharedArrayBuffer);
644 static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx,
645 Handle<GlobalObject*> global,
646 JSExnType exnType) {
647 JSProtoKey key = GetExceptionProtoKey(exnType);
648 if (!ensureConstructor(cx, global, key)) {
649 return nullptr;
651 return &global->getPrototype(key);
654 static JSFunction* getOrCreateErrorConstructor(JSContext* cx,
655 Handle<GlobalObject*> global) {
656 if (!ensureConstructor(cx, global, JSProto_Error)) {
657 return nullptr;
659 return &global->getConstructor(JSProto_Error).as<JSFunction>();
662 static JSObject* getOrCreateErrorPrototype(JSContext* cx,
663 Handle<GlobalObject*> global) {
664 return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR);
667 static NativeObject* getOrCreateSetPrototype(JSContext* cx,
668 Handle<GlobalObject*> global) {
669 if (!ensureConstructor(cx, global, JSProto_Set)) {
670 return nullptr;
672 return &global->getPrototype(JSProto_Set).as<NativeObject>();
675 static NativeObject* getOrCreateWeakSetPrototype(
676 JSContext* cx, Handle<GlobalObject*> global) {
677 if (!ensureConstructor(cx, global, JSProto_WeakSet)) {
678 return nullptr;
680 return &global->getPrototype(JSProto_WeakSet).as<NativeObject>();
683 static JSFunction* getOrCreateTypedArrayConstructor(
684 JSContext* cx, Handle<GlobalObject*> global) {
685 if (!ensureConstructor(cx, global, JSProto_TypedArray)) {
686 return nullptr;
688 return &global->getConstructor(JSProto_TypedArray).as<JSFunction>();
691 static JSObject* getOrCreateTypedArrayPrototype(
692 JSContext* cx, Handle<GlobalObject*> global) {
693 if (!ensureConstructor(cx, global, JSProto_TypedArray)) {
694 return nullptr;
696 return &global->getPrototype(JSProto_TypedArray);
699 private:
700 using ObjectInitOp = bool (*)(JSContext*, Handle<GlobalObject*>);
701 using ObjectInitWithTagOp = bool (*)(JSContext*, Handle<GlobalObject*>,
702 Handle<JSAtom*>);
704 static JSObject* getOrCreateBuiltinProto(JSContext* cx,
705 Handle<GlobalObject*> global,
706 ProtoKind kind, ObjectInitOp init) {
707 if (JSObject* proto = global->maybeBuiltinProto(kind)) {
708 return proto;
711 return createBuiltinProto(cx, global, kind, init);
714 static JSObject* getOrCreateBuiltinProto(JSContext* cx,
715 Handle<GlobalObject*> global,
716 ProtoKind kind, Handle<JSAtom*> tag,
717 ObjectInitWithTagOp init) {
718 if (JSObject* proto = global->maybeBuiltinProto(kind)) {
719 return proto;
722 return createBuiltinProto(cx, global, kind, tag, init);
725 static JSObject* createBuiltinProto(JSContext* cx,
726 Handle<GlobalObject*> global,
727 ProtoKind kind, ObjectInitOp init);
728 static JSObject* createBuiltinProto(JSContext* cx,
729 Handle<GlobalObject*> global,
730 ProtoKind kind, Handle<JSAtom*> tag,
731 ObjectInitWithTagOp init);
733 static JSObject* createIteratorPrototype(JSContext* cx,
734 Handle<GlobalObject*> global);
736 public:
737 static JSObject* getOrCreateIteratorPrototype(JSContext* cx,
738 Handle<GlobalObject*> global) {
739 if (JSObject* proto = global->maybeBuiltinProto(ProtoKind::IteratorProto)) {
740 return proto;
742 return createIteratorPrototype(cx, global);
745 static NativeObject* getOrCreateArrayIteratorPrototype(
746 JSContext* cx, Handle<GlobalObject*> global);
748 static JSObject* getOrCreateStringIteratorPrototype(
749 JSContext* cx, Handle<GlobalObject*> global);
751 static JSObject* getOrCreateRegExpStringIteratorPrototype(
752 JSContext* cx, Handle<GlobalObject*> global);
754 void setGeneratorObjectPrototype(JSObject* obj) {
755 initBuiltinProto(ProtoKind::GeneratorObjectProto, obj);
758 static JSObject* getOrCreateGeneratorObjectPrototype(
759 JSContext* cx, Handle<GlobalObject*> global) {
760 if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) {
761 return nullptr;
763 return &global->getBuiltinProto(ProtoKind::GeneratorObjectProto);
766 static JSObject* getOrCreateGeneratorFunctionPrototype(
767 JSContext* cx, Handle<GlobalObject*> global) {
768 if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) {
769 return nullptr;
771 return &global->getPrototype(JSProto_GeneratorFunction);
774 static JSObject* getOrCreateGeneratorFunction(JSContext* cx,
775 Handle<GlobalObject*> global) {
776 if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) {
777 return nullptr;
779 return &global->getConstructor(JSProto_GeneratorFunction);
782 static JSObject* getOrCreateAsyncFunctionPrototype(
783 JSContext* cx, Handle<GlobalObject*> global) {
784 if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) {
785 return nullptr;
787 return &global->getPrototype(JSProto_AsyncFunction);
790 static JSObject* getOrCreateAsyncFunction(JSContext* cx,
791 Handle<GlobalObject*> global) {
792 if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) {
793 return nullptr;
795 return &global->getConstructor(JSProto_AsyncFunction);
798 static JSObject* createAsyncIteratorPrototype(JSContext* cx,
799 Handle<GlobalObject*> global);
801 static JSObject* getOrCreateAsyncIteratorPrototype(
802 JSContext* cx, Handle<GlobalObject*> global) {
803 if (JSObject* proto =
804 global->maybeBuiltinProto(ProtoKind::AsyncIteratorProto)) {
805 return proto;
807 return createAsyncIteratorPrototype(cx, global);
810 static JSObject* getOrCreateAsyncFromSyncIteratorPrototype(
811 JSContext* cx, Handle<GlobalObject*> global) {
812 return getOrCreateBuiltinProto(cx, global,
813 ProtoKind::AsyncFromSyncIteratorProto,
814 initAsyncFromSyncIteratorProto);
817 static JSObject* getOrCreateAsyncGenerator(JSContext* cx,
818 Handle<GlobalObject*> global) {
819 if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) {
820 return nullptr;
822 return &global->getPrototype(JSProto_AsyncGeneratorFunction);
825 static JSObject* getOrCreateAsyncGeneratorFunction(
826 JSContext* cx, Handle<GlobalObject*> global) {
827 if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) {
828 return nullptr;
830 return &global->getConstructor(JSProto_AsyncGeneratorFunction);
833 void setAsyncGeneratorPrototype(JSObject* obj) {
834 initBuiltinProto(ProtoKind::AsyncGeneratorProto, obj);
837 static JSObject* getOrCreateAsyncGeneratorPrototype(
838 JSContext* cx, Handle<GlobalObject*> global) {
839 if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) {
840 return nullptr;
842 return &global->getBuiltinProto(ProtoKind::AsyncGeneratorProto);
845 static JSObject* getOrCreateMapIteratorPrototype(
846 JSContext* cx, Handle<GlobalObject*> global) {
847 return getOrCreateBuiltinProto(cx, global, ProtoKind::MapIteratorProto,
848 initMapIteratorProto);
851 static JSObject* getOrCreateSetIteratorPrototype(
852 JSContext* cx, Handle<GlobalObject*> global) {
853 return getOrCreateBuiltinProto(cx, global, ProtoKind::SetIteratorProto,
854 initSetIteratorProto);
857 static JSObject* getOrCreateDataViewPrototype(JSContext* cx,
858 Handle<GlobalObject*> global) {
859 if (!ensureConstructor(cx, global, JSProto_DataView)) {
860 return nullptr;
862 return &global->getPrototype(JSProto_DataView);
865 static JSObject* getOrCreatePromiseConstructor(JSContext* cx,
866 Handle<GlobalObject*> global) {
867 if (!ensureConstructor(cx, global, JSProto_Promise)) {
868 return nullptr;
870 return &global->getConstructor(JSProto_Promise);
873 static NativeObject* getOrCreateWrapForValidIteratorPrototype(
874 JSContext* cx, Handle<GlobalObject*> global);
876 static NativeObject* getOrCreateIteratorHelperPrototype(
877 JSContext* cx, Handle<GlobalObject*> global);
879 static NativeObject* getOrCreateAsyncIteratorHelperPrototype(
880 JSContext* cx, Handle<GlobalObject*> global);
881 static bool initAsyncIteratorHelperProto(JSContext* cx,
882 Handle<GlobalObject*> global);
884 NativeObject& getIntrinsicsHolder() const {
885 MOZ_ASSERT(data().intrinsicsHolder);
886 return *data().intrinsicsHolder;
889 static bool createIntrinsicsHolder(JSContext* cx,
890 Handle<GlobalObject*> global);
892 NativeObject* getComputedIntrinsicsHolder() {
893 return data().computedIntrinsicsHolder;
895 void setComputedIntrinsicsHolder(NativeObject* holder) {
896 data().computedIntrinsicsHolder = holder;
899 // If a self-hosting intrinsic with the given |name| exists, it's stored in
900 // |*vp| and this function returns true. Else it returns false.
901 bool maybeGetIntrinsicValue(PropertyName* name, Value* vp, JSContext* cx) {
902 NativeObject& holder = getIntrinsicsHolder();
904 if (mozilla::Maybe<PropertyInfo> prop = holder.lookup(cx, name)) {
905 *vp = holder.getSlot(prop->slot());
906 return true;
909 return false;
912 static bool getIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
913 Handle<PropertyName*> name,
914 MutableHandleValue value) {
915 // `undefined` in self-hosted JS code should be emitted as JSOp::Undefined.
916 MOZ_ASSERT(name != cx->names().undefined);
918 if (global->maybeGetIntrinsicValue(name, value.address(), cx)) {
919 return true;
921 return getIntrinsicValueSlow(cx, global, name, value);
924 static bool getIntrinsicValueSlow(JSContext* cx, Handle<GlobalObject*> global,
925 Handle<PropertyName*> name,
926 MutableHandleValue value);
928 static bool addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
929 Handle<PropertyName*> name, HandleValue value);
931 static inline bool setIntrinsicValue(JSContext* cx,
932 Handle<GlobalObject*> global,
933 Handle<PropertyName*> name,
934 HandleValue value);
936 static bool getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
937 Handle<PropertyName*> selfHostedName,
938 Handle<JSAtom*> name, unsigned nargs,
939 MutableHandleValue funVal);
941 static RegExpStatics* getRegExpStatics(JSContext* cx,
942 Handle<GlobalObject*> global);
944 static JSObject* getOrCreateThrowTypeError(JSContext* cx,
945 Handle<GlobalObject*> global);
947 RegExpRealm& regExpRealm() { return data().regExpRealm; }
949 // Infallibly test whether the given value is the eval function for this
950 // global.
951 bool valueIsEval(const Value& val);
953 void removeFromVarNames(JSAtom* name) { data().varNames.remove(name); }
955 // Whether the given name is in [[VarNames]].
956 bool isInVarNames(JSAtom* name) { return data().varNames.has(name); }
958 // Add a name to [[VarNames]]. Reports OOM on failure.
959 [[nodiscard]] bool addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name);
961 static ArgumentsObject* getOrCreateArgumentsTemplateObject(JSContext* cx,
962 bool mapped);
963 ArgumentsObject* maybeArgumentsTemplateObject(bool mapped) const;
965 static const size_t IterResultObjectValueSlot = 0;
966 static const size_t IterResultObjectDoneSlot = 1;
967 static js::PlainObject* getOrCreateIterResultTemplateObject(JSContext* cx);
968 static js::PlainObject* getOrCreateIterResultWithoutPrototypeTemplateObject(
969 JSContext* cx);
971 private:
972 enum class WithObjectPrototype { No, Yes };
973 static js::PlainObject* createIterResultTemplateObject(
974 JSContext* cx, WithObjectPrototype withProto);
976 public:
977 static ScriptSourceObject* getOrCreateSelfHostingScriptSourceObject(
978 JSContext* cx, Handle<GlobalObject*> global);
980 // Implemented in vm/Iteration.cpp.
981 static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
982 template <ProtoKind Kind, const JSClass* ProtoClass,
983 const JSFunctionSpec* Methods>
984 static bool initObjectIteratorProto(JSContext* cx,
985 Handle<GlobalObject*> global,
986 Handle<JSAtom*> tag);
988 // Implemented in vm/AsyncIteration.cpp.
989 static bool initAsyncIteratorProto(JSContext* cx,
990 Handle<GlobalObject*> global);
991 static bool initAsyncFromSyncIteratorProto(JSContext* cx,
992 Handle<GlobalObject*> global);
994 // Implemented in builtin/MapObject.cpp.
995 static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
996 static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
998 static bool initStandardClasses(JSContext* cx, Handle<GlobalObject*> global);
1000 // Disallow GC as it may mutate the vector.
1001 Realm::DebuggerVector& getDebuggers(const JS::AutoRequireNoGC& nogc) const {
1002 return realm()->getDebuggers(nogc);
1004 bool hasDebuggers() const { return realm()->hasDebuggers(); }
1006 inline NativeObject* getForOfPICObject() { return data().forOfPICChain; }
1007 static NativeObject* getOrCreateForOfPICObject(JSContext* cx,
1008 Handle<GlobalObject*> global);
1010 JSObject* maybeWindowProxy() const { return data().windowProxy; }
1012 void setWindowProxy(JSObject* windowProxy) {
1013 // Note: the global must always be associated with the same WindowProxy.
1014 // CacheIR optimizations rely on this by baking in the WindowProxy for the
1015 // global.
1016 MOZ_ASSERT(!data().windowProxy);
1017 data().windowProxy.init(windowProxy);
1020 ArrayObject* getSourceURLsHolder() const { return data().sourceURLsHolder; }
1022 void setSourceURLsHolder(ArrayObject* holder) {
1023 data().sourceURLsHolder = holder;
1025 void clearSourceURLSHolder() {
1026 // This is called at the start of shrinking GCs, so avoids barriers.
1027 data().sourceURLsHolder.unbarrieredSet(nullptr);
1030 SharedShape* maybeArrayShapeWithDefaultProto() const {
1031 return data().arrayShapeWithDefaultProto;
1034 static SharedShape* getArrayShapeWithDefaultProto(JSContext* cx) {
1035 if (SharedShape* shape = cx->global()->data().arrayShapeWithDefaultProto;
1036 MOZ_LIKELY(shape)) {
1037 return shape;
1039 return createArrayShapeWithDefaultProto(cx);
1041 static SharedShape* createArrayShapeWithDefaultProto(JSContext* cx);
1043 static SharedShape* getPlainObjectShapeWithDefaultProto(JSContext* cx,
1044 gc::AllocKind kind) {
1045 PlainObjectSlotsKind slotsKind = PlainObjectSlotsKindFromAllocKind(kind);
1046 SharedShape* shape =
1047 cx->global()->data().plainObjectShapesWithDefaultProto[slotsKind];
1048 if (MOZ_LIKELY(shape)) {
1049 return shape;
1051 return createPlainObjectShapeWithDefaultProto(cx, kind);
1053 static SharedShape* createPlainObjectShapeWithDefaultProto(
1054 JSContext* cx, gc::AllocKind kind);
1056 static SharedShape* getFunctionShapeWithDefaultProto(JSContext* cx,
1057 bool extended) {
1058 GlobalObjectData& data = cx->global()->data();
1059 SharedShape* shape = extended ? data.extendedFunctionShapeWithDefaultProto
1060 : data.functionShapeWithDefaultProto;
1061 if (MOZ_LIKELY(shape)) {
1062 return shape;
1064 return createFunctionShapeWithDefaultProto(cx, extended);
1066 static SharedShape* createFunctionShapeWithDefaultProto(JSContext* cx,
1067 bool extended);
1069 SharedShape* maybeBoundFunctionShapeWithDefaultProto() const {
1070 return data().boundFunctionShapeWithDefaultProto;
1072 void setBoundFunctionShapeWithDefaultProto(SharedShape* shape) {
1073 data().boundFunctionShapeWithDefaultProto = shape;
1076 static PropertyIteratorObject* getOrCreateEmptyIterator(JSContext* cx);
1078 // Returns an object that represents the realm, used by embedder.
1079 static JSObject* getOrCreateRealmKeyObject(JSContext* cx,
1080 Handle<GlobalObject*> global);
1082 gc::FinalizationRegistryGlobalData* getOrCreateFinalizationRegistryData();
1083 gc::FinalizationRegistryGlobalData* maybeFinalizationRegistryData() const {
1084 return data().finalizationRegistryData.get();
1087 static size_t offsetOfGlobalDataSlot() {
1088 return getFixedSlotOffset(GLOBAL_DATA_SLOT);
1091 uint32_t generationCount() const { return data().generationCount; }
1092 const void* addressOfGenerationCount() const {
1093 return &data().generationCount;
1095 void bumpGenerationCount() {
1096 MOZ_RELEASE_ASSERT(data().generationCount < UINT32_MAX);
1097 data().generationCount++;
1102 * Unless otherwise specified, define ctor.prototype = proto as non-enumerable,
1103 * non-configurable, and non-writable; and define proto.constructor = ctor as
1104 * non-enumerable but configurable and writable.
1106 extern bool LinkConstructorAndPrototype(
1107 JSContext* cx, JSObject* ctor, JSObject* proto,
1108 unsigned prototypeAttrs = JSPROP_PERMANENT | JSPROP_READONLY,
1109 unsigned constructorAttrs = 0);
1112 * Define properties and/or functions on any object. Either ps or fs, or both,
1113 * may be null.
1115 extern bool DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
1116 const JSPropertySpec* ps,
1117 const JSFunctionSpec* fs);
1119 extern bool DefineToStringTag(JSContext* cx, HandleObject obj, JSAtom* tag);
1122 * Convenience templates to generic constructor and prototype creation functions
1123 * for ClassSpecs.
1126 template <JSNative ctor, unsigned length, gc::AllocKind kind,
1127 const JSJitInfo* jitInfo = nullptr>
1128 JSObject* GenericCreateConstructor(JSContext* cx, JSProtoKey key) {
1129 // Note - We duplicate the trick from ClassName() so that we don't need to
1130 // include vm/JSAtomUtils-inl.h here.
1131 PropertyName* name = (&cx->names().Null)[key];
1132 return GlobalObject::createConstructor(cx, ctor, name, length, kind, jitInfo);
1135 template <typename T>
1136 JSObject* GenericCreatePrototype(JSContext* cx, JSProtoKey key) {
1137 static_assert(
1138 !std::is_same_v<T, PlainObject>,
1139 "creating Object.prototype is very special and isn't handled here");
1140 MOZ_ASSERT(&T::class_ == ProtoKeyToClass(key),
1141 "type mismatch--probably too much copy/paste in your ClassSpec");
1142 MOZ_ASSERT(
1143 InheritanceProtoKeyForStandardClass(key) == JSProto_Object,
1144 "subclasses (of anything but Object) can't use GenericCreatePrototype");
1145 return GlobalObject::createBlankPrototype(cx, cx->global(), &T::protoClass_);
1148 inline JSProtoKey StandardProtoKeyOrNull(const JSObject* obj) {
1149 return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
1152 JSObject* NewTenuredObjectWithFunctionPrototype(JSContext* cx,
1153 Handle<GlobalObject*> global);
1155 } // namespace js
1157 template <>
1158 inline bool JSObject::is<js::GlobalObject>() const {
1159 return !!(getClass()->flags & JSCLASS_IS_GLOBAL);
1162 #endif /* vm_GlobalObject_h */