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 #include "vm/GlobalObject.h"
10 #include "jsfriendapi.h"
12 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
13 # include "builtin/AsyncDisposableStackObject.h"
15 #include "builtin/AtomicsObject.h"
16 #include "builtin/BigInt.h"
17 #include "builtin/DataViewObject.h"
18 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
19 # include "builtin/DisposableStackObject.h"
21 #ifdef JS_HAS_INTL_API
22 # include "builtin/intl/Collator.h"
23 # include "builtin/intl/DateTimeFormat.h"
24 # include "builtin/intl/DisplayNames.h"
25 # include "builtin/intl/ListFormat.h"
26 # include "builtin/intl/Locale.h"
27 # include "builtin/intl/NumberFormat.h"
28 # include "builtin/intl/PluralRules.h"
29 # include "builtin/intl/RelativeTimeFormat.h"
30 # include "builtin/intl/Segmenter.h"
32 #include "builtin/FinalizationRegistryObject.h"
33 #include "builtin/MapObject.h"
34 #include "builtin/ShadowRealm.h"
35 #include "builtin/Symbol.h"
36 #ifdef JS_HAS_TEMPORAL_API
37 # include "builtin/temporal/Duration.h"
38 # include "builtin/temporal/Instant.h"
39 # include "builtin/temporal/PlainDate.h"
40 # include "builtin/temporal/PlainDateTime.h"
41 # include "builtin/temporal/PlainMonthDay.h"
42 # include "builtin/temporal/PlainTime.h"
43 # include "builtin/temporal/PlainYearMonth.h"
44 # include "builtin/temporal/Temporal.h"
45 # include "builtin/temporal/TemporalNow.h"
46 # include "builtin/temporal/ZonedDateTime.h"
48 #include "builtin/WeakMapObject.h"
49 #include "builtin/WeakRefObject.h"
50 #include "builtin/WeakSetObject.h"
51 #include "debugger/DebugAPI.h"
52 #include "frontend/CompilationStencil.h"
53 #include "gc/FinalizationObservers.h"
55 #include "gc/GCContext.h"
56 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
57 #include "js/friend/WindowProxy.h" // js::ToWindowProxyIfWindow
58 #include "js/Prefs.h" // JS::Prefs
59 #include "js/PropertyAndElement.h" // JS_DefineFunctions, JS_DefineProperties
60 #include "js/ProtoKey.h"
61 #include "vm/AsyncFunction.h"
62 #include "vm/AsyncIteration.h"
63 #include "vm/BooleanObject.h"
64 #include "vm/Compartment.h"
65 #include "vm/DateObject.h"
66 #include "vm/EnvironmentObject.h"
67 #include "vm/ErrorObject.h"
68 #include "vm/GeneratorObject.h"
69 #include "vm/JSContext.h"
70 #include "vm/NumberObject.h"
72 #include "vm/PlainObject.h"
73 #include "vm/RegExpObject.h"
74 #include "vm/RegExpStatics.h"
75 #include "vm/SelfHosting.h"
76 #include "vm/StringObject.h"
77 #include "wasm/WasmFeatures.h"
78 #include "wasm/WasmJS.h"
79 #ifdef ENABLE_RECORD_TUPLE
80 # include "vm/RecordType.h"
81 # include "vm/TupleType.h"
84 #include "gc/GCContext-inl.h"
85 #include "vm/JSObject-inl.h"
86 #include "vm/Realm-inl.h"
92 extern const JSClass IntlClass
;
93 extern const JSClass JSONClass
;
94 extern const JSClass MathClass
;
95 extern const JSClass ReflectClass
;
99 static constexpr const JSClass
* const protoTable
[JSProto_LIMIT
] = {
100 #define INIT_FUNC(name, clasp) clasp,
101 #define INIT_FUNC_DUMMY(name, clasp) nullptr,
102 JS_FOR_PROTOTYPES(INIT_FUNC
, INIT_FUNC_DUMMY
)
103 #undef INIT_FUNC_DUMMY
107 JS_PUBLIC_API
const JSClass
* js::ProtoKeyToClass(JSProtoKey key
) {
108 MOZ_ASSERT(key
< JSProto_LIMIT
);
109 return protoTable
[key
];
112 static bool IsAsyncIteratorHelpersEnabled() {
114 return JS::Prefs::experimental_async_iterator_helpers();
121 bool GlobalObject::skipDeselectedConstructor(JSContext
* cx
, JSProtoKey key
) {
125 case JSProto_Function
:
126 case JSProto_BoundFunction
:
128 case JSProto_Boolean
:
136 case JSProto_InternalError
:
137 case JSProto_Iterator
:
138 case JSProto_AggregateError
:
139 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
140 case JSProto_SuppressedError
:
141 case JSProto_DisposableStack
:
142 case JSProto_AsyncDisposableStack
:
144 case JSProto_EvalError
:
145 case JSProto_RangeError
:
146 case JSProto_ReferenceError
:
147 case JSProto_SyntaxError
:
148 case JSProto_TypeError
:
149 case JSProto_URIError
:
150 case JSProto_DebuggeeWouldRun
:
151 case JSProto_CompileError
:
152 case JSProto_LinkError
:
153 case JSProto_RuntimeError
:
154 case JSProto_ArrayBuffer
:
155 case JSProto_Int8Array
:
156 case JSProto_Uint8Array
:
157 case JSProto_Int16Array
:
158 case JSProto_Uint16Array
:
159 case JSProto_Int32Array
:
160 case JSProto_Uint32Array
:
161 case JSProto_Float32Array
:
162 case JSProto_Float64Array
:
163 case JSProto_Uint8ClampedArray
:
164 case JSProto_BigInt64Array
:
165 case JSProto_BigUint64Array
:
168 case JSProto_WeakMap
:
171 case JSProto_DataView
:
173 case JSProto_Reflect
:
174 case JSProto_WeakSet
:
175 case JSProto_TypedArray
:
176 case JSProto_SavedFrame
:
177 case JSProto_Promise
:
178 case JSProto_AsyncFunction
:
179 case JSProto_GeneratorFunction
:
180 case JSProto_AsyncGeneratorFunction
:
181 #ifdef ENABLE_RECORD_TUPLE
187 case JSProto_WebAssembly
:
188 return !wasm::HasSupport(cx
);
190 case JSProto_WasmModule
:
191 case JSProto_WasmInstance
:
192 case JSProto_WasmMemory
:
193 case JSProto_WasmTable
:
194 case JSProto_WasmGlobal
:
195 case JSProto_WasmTag
:
196 #ifdef ENABLE_WASM_TYPE_REFLECTIONS
197 case JSProto_WasmFunction
:
199 #ifdef ENABLE_WASM_JSPI
200 case JSProto_WasmSuspending
:
202 case JSProto_WasmException
:
205 #ifdef JS_HAS_INTL_API
207 case JSProto_Collator
:
208 case JSProto_DateTimeFormat
:
209 case JSProto_DisplayNames
:
211 case JSProto_ListFormat
:
212 case JSProto_NumberFormat
:
213 case JSProto_PluralRules
:
214 case JSProto_RelativeTimeFormat
:
217 case JSProto_Segmenter
:
218 # if defined(MOZ_ICU4X)
225 #ifdef JS_HAS_TEMPORAL_API
226 case JSProto_Temporal
:
227 case JSProto_Duration
:
228 case JSProto_Instant
:
229 case JSProto_PlainDate
:
230 case JSProto_PlainDateTime
:
231 case JSProto_PlainMonthDay
:
232 case JSProto_PlainTime
:
233 case JSProto_PlainYearMonth
:
234 case JSProto_TemporalNow
:
235 case JSProto_ZonedDateTime
:
239 // Return true if the given constructor has been disabled at run-time.
240 case JSProto_Atomics
:
241 case JSProto_SharedArrayBuffer
:
242 return !cx
->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
244 case JSProto_WeakRef
:
245 case JSProto_FinalizationRegistry
:
246 return JS::GetWeakRefsEnabled() == JS::WeakRefSpecifier::Disabled
;
248 case JSProto_AsyncIterator
:
249 return !IsAsyncIteratorHelpersEnabled();
251 case JSProto_ShadowRealm
:
252 return !JS::Prefs::experimental_shadow_realms();
254 case JSProto_Float16Array
:
255 return !JS::Prefs::experimental_float16array();
258 MOZ_CRASH("unexpected JSProtoKey");
262 static bool ShouldFreezeBuiltin(JSProtoKey key
) {
263 // We can't freeze Reflect because JS_InitReflectParse defines Reflect.parse.
264 if (key
== JSProto_Reflect
) {
267 // We can't freeze Date because some browser tests use the Sinon library which
268 // redefines Date.now.
269 if (key
== JSProto_Date
) {
275 static unsigned GetAttrsForResolvedGlobal(GlobalObject
* global
,
277 unsigned attrs
= JSPROP_RESOLVING
;
278 if (global
->realm()->creationOptions().freezeBuiltins() &&
279 ShouldFreezeBuiltin(key
)) {
280 attrs
|= JSPROP_PERMANENT
| JSPROP_READONLY
;
286 bool GlobalObject::resolveConstructor(JSContext
* cx
,
287 Handle
<GlobalObject
*> global
,
288 JSProtoKey key
, IfClassIsDisabled mode
) {
289 MOZ_ASSERT(key
!= JSProto_Null
);
290 MOZ_ASSERT(key
!= JSProto_BoundFunction
,
291 "bound functions don't have their own proto object");
292 MOZ_ASSERT(!global
->isStandardClassResolved(key
));
293 MOZ_ASSERT(cx
->compartment() == global
->compartment());
295 // |global| must be same-compartment but make sure we're in its realm: the
296 // code below relies on this.
297 AutoRealm
ar(cx
, global
);
299 // Prohibit collection of allocation metadata. Metadata builders shouldn't
300 // need to observe lazily-constructed prototype objects coming into
301 // existence. And assertions start to fail when the builder itself attempts
302 // an allocation that re-entrantly tries to create the same prototype.
303 AutoSuppressAllocationMetadataBuilder
suppressMetadata(cx
);
305 // Constructor resolution may execute self-hosted scripts. These
306 // self-hosted scripts do not call out to user code by construction. Allow
307 // all scripts to execute, even in debuggee compartments that are paused.
308 AutoSuppressDebuggeeNoExecuteChecks
suppressNX(cx
);
310 // Some classes can be disabled at compile time, others at run time;
311 // if a feature is compile-time disabled, clasp is null.
312 const JSClass
* clasp
= ProtoKeyToClass(key
);
313 if (!clasp
|| skipDeselectedConstructor(cx
, key
)) {
314 if (mode
== IfClassIsDisabled::Throw
) {
315 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
316 JSMSG_CONSTRUCTOR_DISABLED
,
317 clasp
? clasp
->name
: "constructor");
323 // Class spec must have a constructor defined.
324 if (!clasp
->specDefined()) {
328 bool isObjectOrFunction
= key
== JSProto_Function
|| key
== JSProto_Object
;
330 // We need to create the prototype first, and immediately stash it in the
331 // slot. This is so the following bootstrap ordering is possible:
332 // * Object.prototype
333 // * Function.prototype
337 // We get the above when Object is resolved before Function. If Function
338 // is resolved before Object, we'll end up re-entering resolveConstructor
339 // for Function, which is a problem. So if Function is being resolved
340 // before Object.prototype exists, we just resolve Object instead, since we
341 // know that Function will also be resolved before we return.
342 if (key
== JSProto_Function
&& !global
->hasPrototype(JSProto_Object
)) {
343 return resolveConstructor(cx
, global
, JSProto_Object
,
344 IfClassIsDisabled::DoNothing
);
347 // %IteratorPrototype%.map.[[Prototype]] is %Generator% and
348 // %Generator%.prototype.[[Prototype]] is %IteratorPrototype%.
349 if (key
== JSProto_GeneratorFunction
&&
350 !global
->hasPrototype(JSProto_Iterator
)) {
351 if (!getOrCreateIteratorPrototype(cx
, global
)) {
355 // If iterator helpers are enabled, populating %IteratorPrototype% will
356 // have recursively gone through here.
357 if (global
->isStandardClassResolved(key
)) {
362 // We don't always have a prototype (i.e. Math and JSON). If we don't,
363 // |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
364 // should all be null.
365 RootedObject
proto(cx
);
366 if (ClassObjectCreationOp createPrototype
=
367 clasp
->specCreatePrototypeHook()) {
368 proto
= createPrototype(cx
, key
);
373 if (isObjectOrFunction
) {
374 // Make sure that creating the prototype didn't recursively resolve
375 // our own constructor. We can't just assert that there's no
376 // prototype; OOMs can result in incomplete resolutions in which
377 // the prototype is saved but not the constructor. So use the same
378 // criteria that protects entry into this function.
379 MOZ_ASSERT(!global
->isStandardClassResolved(key
));
381 global
->setPrototype(key
, proto
);
385 // Create the constructor.
386 RootedObject
ctor(cx
, clasp
->specCreateConstructorHook()(cx
, key
));
391 RootedId
id(cx
, NameToId(ClassName(key
, cx
)));
392 if (isObjectOrFunction
) {
393 if (clasp
->specShouldDefineConstructor()) {
394 RootedValue
ctorValue(cx
, ObjectValue(*ctor
));
395 unsigned attrs
= GetAttrsForResolvedGlobal(global
, key
);
396 if (!DefineDataProperty(cx
, global
, id
, ctorValue
, attrs
)) {
401 global
->setConstructor(key
, ctor
);
404 if (const JSFunctionSpec
* funs
= clasp
->specPrototypeFunctions()) {
405 if (!JS_DefineFunctions(cx
, proto
, funs
)) {
409 if (const JSPropertySpec
* props
= clasp
->specPrototypeProperties()) {
410 if (!JS_DefineProperties(cx
, proto
, props
)) {
414 if (const JSFunctionSpec
* funs
= clasp
->specConstructorFunctions()) {
415 if (!JS_DefineFunctions(cx
, ctor
, funs
)) {
419 if (const JSPropertySpec
* props
= clasp
->specConstructorProperties()) {
420 if (!JS_DefineProperties(cx
, ctor
, props
)) {
425 // If the prototype exists, link it with the constructor.
426 if (proto
&& !LinkConstructorAndPrototype(cx
, ctor
, proto
)) {
430 // Call the post-initialization hook, if provided.
431 if (FinishClassInitOp finishInit
= clasp
->specFinishInitHook()) {
432 if (!finishInit(cx
, ctor
, proto
)) {
437 if (ShouldFreezeBuiltin(key
)) {
438 if (!JS::MaybeFreezeCtorAndPrototype(cx
, ctor
, proto
)) {
443 // If the prototype exists, mark the object as used as a prototype to enable
444 // Watchtower observation of protos which may not yet actually have an
445 // instance which yet uses it as a proto!
447 // You might well be asking: "Why not set IsUsedAsPrototype when constructing
448 // the proto object?". This ends up leading to a fair amount of complexity in
449 // how standard protos are linked together and the properties we want to
450 // enforce. Generally, it's fine if we don't watch for mutations on protos
451 // until they get exposed to user code.
452 if (proto
&& !JSObject::setFlag(cx
, proto
, ObjectFlag::IsUsedAsPrototype
)) {
456 if (!isObjectOrFunction
) {
457 // Any operations that modifies the global object should be placed
458 // after any other fallible operations.
460 // Fallible operation that modifies the global object.
461 if (clasp
->specShouldDefineConstructor()) {
462 bool shouldReallyDefine
= true;
464 // On the web, it isn't presently possible to expose the global
465 // "SharedArrayBuffer" property unless the page is cross-site-isolated.
466 // Only define this constructor if an option on the realm indicates that
467 // it should be defined.
468 if (key
== JSProto_SharedArrayBuffer
) {
469 const JS::RealmCreationOptions
& options
=
470 global
->realm()->creationOptions();
472 MOZ_ASSERT(options
.getSharedMemoryAndAtomicsEnabled(),
473 "shouldn't be defining SharedArrayBuffer if shared memory "
476 shouldReallyDefine
= options
.defineSharedArrayBufferConstructor();
479 if (shouldReallyDefine
) {
480 RootedValue
ctorValue(cx
, ObjectValue(*ctor
));
481 unsigned attrs
= GetAttrsForResolvedGlobal(global
, key
);
482 if (!DefineDataProperty(cx
, global
, id
, ctorValue
, attrs
)) {
488 // Infallible operations that modify the global object.
489 global
->setConstructor(key
, ctor
);
491 global
->setPrototype(key
, proto
);
498 // Resolve a "globalThis" self-referential property if necessary,
499 // per a stage-3 proposal. https://github.com/tc39/ecma262/pull/702
501 // We could also do this in |FinishObjectClassInit| to trim the global
502 // resolve hook. Unfortunately, |ToWindowProxyIfWindow| doesn't work then:
503 // the browser's |nsGlobalWindow::SetNewDocument| invokes Object init
504 // *before* it sets the global's WindowProxy using |js::SetWindowProxy|.
506 // Refactoring global object creation code to support this approach is a
507 // challenge for another day.
509 bool GlobalObject::maybeResolveGlobalThis(JSContext
* cx
,
510 Handle
<GlobalObject
*> global
,
512 if (!global
->data().globalThisResolved
) {
513 RootedValue
v(cx
, ObjectValue(*ToWindowProxyIfWindow(global
)));
514 if (!DefineDataProperty(cx
, global
, cx
->names().globalThis
, v
,
520 global
->data().globalThisResolved
= true;
527 JSObject
* GlobalObject::createBuiltinProto(JSContext
* cx
,
528 Handle
<GlobalObject
*> global
,
529 ProtoKind kind
, ObjectInitOp init
) {
530 if (!init(cx
, global
)) {
534 return &global
->getBuiltinProto(kind
);
537 JSObject
* GlobalObject::createBuiltinProto(JSContext
* cx
,
538 Handle
<GlobalObject
*> global
,
539 ProtoKind kind
, Handle
<JSAtom
*> tag
,
540 ObjectInitWithTagOp init
) {
541 if (!init(cx
, global
, tag
)) {
545 return &global
->getBuiltinProto(kind
);
548 static bool ThrowTypeError(JSContext
* cx
, unsigned argc
, Value
* vp
) {
549 ThrowTypeErrorBehavior(cx
);
554 JSObject
* GlobalObject::getOrCreateThrowTypeError(
555 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
556 if (JSFunction
* fun
= global
->data().throwTypeError
) {
560 // Construct the unique [[%ThrowTypeError%]] function object, used only for
561 // "callee" and "caller" accessors on strict mode arguments objects. (The
562 // spec also uses this for "arguments" and "caller" on various functions,
563 // but we're experimenting with implementing them using accessors on
564 // |Function.prototype| right now.)
566 RootedFunction
throwTypeError(
567 cx
, NewNativeFunction(cx
, ThrowTypeError
, 0, nullptr));
568 if (!throwTypeError
|| !PreventExtensions(cx
, throwTypeError
)) {
572 // The "length" property of %ThrowTypeError% is non-configurable.
573 Rooted
<PropertyDescriptor
> nonConfigurableDesc(cx
,
574 PropertyDescriptor::Empty());
575 nonConfigurableDesc
.setConfigurable(false);
577 RootedId
lengthId(cx
, NameToId(cx
->names().length
));
578 ObjectOpResult lengthResult
;
579 if (!NativeDefineProperty(cx
, throwTypeError
, lengthId
, nonConfigurableDesc
,
583 MOZ_ASSERT(lengthResult
);
585 // The "name" property of %ThrowTypeError% is non-configurable, adjust
586 // the default property attributes accordingly.
587 RootedId
nameId(cx
, NameToId(cx
->names().name
));
588 ObjectOpResult nameResult
;
589 if (!NativeDefineProperty(cx
, throwTypeError
, nameId
, nonConfigurableDesc
,
593 MOZ_ASSERT(nameResult
);
595 global
->data().throwTypeError
.init(throwTypeError
);
596 return throwTypeError
;
599 GlobalObject
* GlobalObject::createInternal(JSContext
* cx
,
600 const JSClass
* clasp
) {
601 MOZ_ASSERT(clasp
->flags
& JSCLASS_IS_GLOBAL
);
602 MOZ_ASSERT(clasp
->isTrace(JS_GlobalObjectTraceHook
));
604 ObjectFlags objectFlags
= {
605 ObjectFlag::QualifiedVarObj
,
606 ObjectFlag::GenerationCountedGlobal
,
610 NewTenuredObjectWithGivenProto(cx
, clasp
, nullptr, objectFlags
);
615 Rooted
<GlobalObject
*> global(cx
, &obj
->as
<GlobalObject
>());
617 // Global holds both variables qualified with `var` and those that are not.
618 MOZ_ASSERT(global
->isUnqualifiedVarObj());
619 MOZ_ASSERT(global
->isQualifiedVarObj());
621 // Global objects support generation counts.
622 MOZ_ASSERT(global
->isGenerationCountedGlobal());
625 auto data
= cx
->make_unique
<GlobalObjectData
>(cx
->zone());
629 // Note: it's important for the realm's global to be initialized at the
630 // same time as the global's GlobalObjectData, because we free the global's
631 // data when Realm::global_ is cleared.
632 cx
->realm()->initGlobal(*global
);
633 InitReservedSlot(global
, GLOBAL_DATA_SLOT
, data
.release(),
634 MemoryUse::GlobalObjectData
);
637 Rooted
<GlobalLexicalEnvironmentObject
*> lexical(
638 cx
, GlobalLexicalEnvironmentObject::create(cx
, global
));
642 global
->data().lexicalEnvironment
.init(lexical
);
644 Rooted
<GlobalScope
*> emptyGlobalScope(
645 cx
, GlobalScope::createEmpty(cx
, ScopeKind::Global
));
646 if (!emptyGlobalScope
) {
649 global
->data().emptyGlobalScope
.init(emptyGlobalScope
);
651 if (!GlobalObject::createIntrinsicsHolder(cx
, global
)) {
659 GlobalObject
* GlobalObject::new_(JSContext
* cx
, const JSClass
* clasp
,
660 JSPrincipals
* principals
,
661 JS::OnNewGlobalHookOption hookOption
,
662 const JS::RealmOptions
& options
) {
663 MOZ_ASSERT(!cx
->isExceptionPending());
664 MOZ_ASSERT_IF(cx
->zone(), !cx
->zone()->isAtomsZone());
666 // If we are creating a new global in an existing compartment, make sure the
667 // compartment has a live global at all times (by rooting it here).
669 Rooted
<GlobalObject
*> existingGlobal(cx
);
670 const JS::RealmCreationOptions
& creationOptions
= options
.creationOptions();
671 if (creationOptions
.compartmentSpecifier() ==
672 JS::CompartmentSpecifier::ExistingCompartment
) {
673 Compartment
* comp
= creationOptions
.compartment();
674 existingGlobal
= &comp
->firstGlobal();
677 Realm
* realm
= NewRealm(cx
, principals
, options
);
682 Rooted
<GlobalObject
*> global(cx
);
684 AutoRealmUnchecked
ar(cx
, realm
);
685 global
= GlobalObject::createInternal(cx
, clasp
);
690 // Make transactional initialization of these constructors by discarding the
691 // incompletely initialized global if an error occur. This also ensures the
692 // global's prototype chain is initialized (in FinishObjectClassInit).
693 if (!ensureConstructor(cx
, global
, JSProto_Object
) ||
694 !ensureConstructor(cx
, global
, JSProto_Function
)) {
698 // Create a shape for plain objects with zero slots. This is required to be
699 // present in case allocating dynamic slots for objects fails, so we can
700 // leave a valid object in the heap.
701 if (!createPlainObjectShapeWithDefaultProto(cx
, gc::AllocKind::OBJECT0
)) {
705 realm
->clearInitializingGlobal();
706 if (hookOption
== JS::FireOnNewGlobalHook
) {
707 JS_FireOnNewGlobalObject(cx
, global
);
714 GlobalScope
& GlobalObject::emptyGlobalScope() const {
715 return *data().emptyGlobalScope
;
718 bool GlobalObject::valueIsEval(const Value
& val
) {
719 return val
.isObject() && data().eval
== &val
.toObject();
723 bool GlobalObject::initStandardClasses(JSContext
* cx
,
724 Handle
<GlobalObject
*> global
) {
725 /* Define a top-level property 'undefined' with the undefined value. */
726 if (!DefineDataProperty(
727 cx
, global
, cx
->names().undefined
, UndefinedHandleValue
,
728 JSPROP_PERMANENT
| JSPROP_READONLY
| JSPROP_RESOLVING
)) {
732 // Resolve a "globalThis" self-referential property if necessary.
734 if (!GlobalObject::maybeResolveGlobalThis(cx
, global
, &resolved
)) {
738 for (size_t k
= 0; k
< JSProto_LIMIT
; ++k
) {
739 JSProtoKey key
= static_cast<JSProtoKey
>(k
);
740 if (key
!= JSProto_Null
&& key
!= JSProto_BoundFunction
&&
741 !global
->isStandardClassResolved(key
)) {
742 if (!resolveConstructor(cx
, global
, static_cast<JSProtoKey
>(k
),
743 IfClassIsDisabled::DoNothing
)) {
752 JSFunction
* GlobalObject::createConstructor(JSContext
* cx
, Native ctor
,
753 JSAtom
* nameArg
, unsigned length
,
755 const JSJitInfo
* jitInfo
) {
756 Rooted
<JSAtom
*> name(cx
, nameArg
);
757 JSFunction
* fun
= NewNativeConstructor(cx
, ctor
, length
, name
, kind
);
763 fun
->setJitInfo(jitInfo
);
769 static NativeObject
* CreateBlankProto(JSContext
* cx
, const JSClass
* clasp
,
771 ObjectFlags objFlags
) {
772 MOZ_ASSERT(!clasp
->isJSFunction());
774 if (clasp
== &PlainObject::class_
) {
775 // NOTE: There should be no reason currently to support this. It could
776 // however be added later if needed.
777 MOZ_ASSERT(objFlags
.isEmpty());
778 return NewPlainObjectWithProto(cx
, proto
, TenuredObject
);
781 return NewTenuredObjectWithGivenProto(cx
, clasp
, proto
, objFlags
);
785 NativeObject
* GlobalObject::createBlankPrototype(JSContext
* cx
,
786 Handle
<GlobalObject
*> global
,
787 const JSClass
* clasp
,
788 ObjectFlags objFlags
) {
789 RootedObject
objectProto(cx
, &global
->getObjectPrototype());
790 return CreateBlankProto(cx
, clasp
, objectProto
, objFlags
);
794 NativeObject
* GlobalObject::createBlankPrototypeInheriting(JSContext
* cx
,
795 const JSClass
* clasp
,
796 HandleObject proto
) {
797 return CreateBlankProto(cx
, clasp
, proto
, ObjectFlags());
800 bool js::LinkConstructorAndPrototype(JSContext
* cx
, JSObject
* ctor_
,
801 JSObject
* proto_
, unsigned prototypeAttrs
,
802 unsigned constructorAttrs
) {
803 RootedObject
ctor(cx
, ctor_
), proto(cx
, proto_
);
805 RootedValue
protoVal(cx
, ObjectValue(*proto
));
806 RootedValue
ctorVal(cx
, ObjectValue(*ctor
));
808 return DefineDataProperty(cx
, ctor
, cx
->names().prototype
, protoVal
,
810 DefineDataProperty(cx
, proto
, cx
->names().constructor
, ctorVal
,
814 bool js::DefinePropertiesAndFunctions(JSContext
* cx
, HandleObject obj
,
815 const JSPropertySpec
* ps
,
816 const JSFunctionSpec
* fs
) {
817 if (ps
&& !JS_DefineProperties(cx
, obj
, ps
)) {
820 if (fs
&& !JS_DefineFunctions(cx
, obj
, fs
)) {
826 bool js::DefineToStringTag(JSContext
* cx
, HandleObject obj
, JSAtom
* tag
) {
827 RootedId
toStringTagId(
828 cx
, PropertyKey::Symbol(cx
->wellKnownSymbols().toStringTag
));
829 RootedValue
tagString(cx
, StringValue(tag
));
830 return DefineDataProperty(cx
, obj
, toStringTagId
, tagString
, JSPROP_READONLY
);
834 NativeObject
* GlobalObject::getOrCreateForOfPICObject(
835 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
837 NativeObject
* forOfPIC
= global
->getForOfPICObject();
842 forOfPIC
= ForOfPIC::createForOfPICObject(cx
, global
);
846 global
->data().forOfPICChain
.init(forOfPIC
);
851 JSObject
* GlobalObject::getOrCreateRealmKeyObject(
852 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
854 if (PlainObject
* key
= global
->data().realmKeyObject
) {
858 PlainObject
* key
= NewPlainObject(cx
);
863 global
->data().realmKeyObject
.init(key
);
868 RegExpStatics
* GlobalObject::getRegExpStatics(JSContext
* cx
,
869 Handle
<GlobalObject
*> global
) {
872 if (!global
->regExpRealm().regExpStatics
) {
873 auto statics
= RegExpStatics::create(cx
);
877 global
->regExpRealm().regExpStatics
= std::move(statics
);
880 return global
->regExpRealm().regExpStatics
.get();
883 gc::FinalizationRegistryGlobalData
*
884 GlobalObject::getOrCreateFinalizationRegistryData() {
885 if (!data().finalizationRegistryData
) {
886 data().finalizationRegistryData
=
887 MakeUnique
<gc::FinalizationRegistryGlobalData
>(zone());
890 return maybeFinalizationRegistryData();
893 #ifndef NIGHTLY_BUILD
894 bool GlobalObject::addToVarNames(JSContext
* cx
, JS::Handle
<JSAtom
*> name
) {
897 if (!data().varNames
.put(name
)) {
898 ReportOutOfMemory(cx
);
907 bool GlobalObject::createIntrinsicsHolder(JSContext
* cx
,
908 Handle
<GlobalObject
*> global
) {
909 Rooted
<NativeObject
*> intrinsicsHolder(
910 cx
, NewPlainObjectWithProto(cx
, nullptr, TenuredObject
));
911 if (!intrinsicsHolder
) {
915 // Install the intrinsics holder on the global.
916 global
->data().intrinsicsHolder
.init(intrinsicsHolder
);
921 bool GlobalObject::getSelfHostedFunction(JSContext
* cx
,
922 Handle
<GlobalObject
*> global
,
923 Handle
<PropertyName
*> selfHostedName
,
924 Handle
<JSAtom
*> name
, unsigned nargs
,
925 MutableHandleValue funVal
) {
926 if (global
->maybeGetIntrinsicValue(selfHostedName
, funVal
.address(), cx
)) {
927 RootedFunction
fun(cx
, &funVal
.toObject().as
<JSFunction
>());
928 if (fun
->fullExplicitName() == name
) {
932 if (fun
->fullExplicitName() == selfHostedName
) {
933 // This function was initially cloned because it was called by
934 // other self-hosted code, so the clone kept its self-hosted name,
935 // instead of getting the name it's intended to have in content
936 // compartments. This can happen when a lazy builtin is initialized
937 // after self-hosted code for another builtin used the same
938 // function. In that case, we need to change the function's name,
939 // which is ok because it can't have been exposed to content
945 // The function might be installed multiple times on the same or
946 // different builtins, under different property names, so its name
947 // might be neither "selfHostedName" nor "name". In that case, its
948 // canonical name must've been set using the `_SetCanonicalName`
950 cx
->runtime()->assertSelfHostedFunctionHasCanonicalName(selfHostedName
);
954 // Don't collect metadata for self-hosted functions or intrinsics.
955 // This is similar to the suppression in GlobalObject::resolveConstructor.
956 AutoSuppressAllocationMetadataBuilder
suppressMetadata(cx
);
958 JSRuntime
* runtime
= cx
->runtime();
959 frontend::ScriptIndex index
=
960 runtime
->getSelfHostedScriptIndexRange(selfHostedName
)->start
;
962 runtime
->selfHostStencil().instantiateSelfHostedLazyFunction(
963 cx
, runtime
->selfHostStencilInput().atomCache
, index
, name
);
967 MOZ_ASSERT(fun
->nargs() == nargs
);
968 funVal
.setObject(*fun
);
970 return GlobalObject::addIntrinsicValue(cx
, global
, selfHostedName
, funVal
);
974 bool GlobalObject::getIntrinsicValueSlow(JSContext
* cx
,
975 Handle
<GlobalObject
*> global
,
976 Handle
<PropertyName
*> name
,
977 MutableHandleValue value
) {
978 // Don't collect metadata for self-hosted functions or intrinsics.
979 // This is similar to the suppression in GlobalObject::resolveConstructor.
980 AutoSuppressAllocationMetadataBuilder
suppressMetadata(cx
);
982 // If this is a C++ intrinsic, simply define the function on the intrinsics
984 if (const JSFunctionSpec
* spec
= js::FindIntrinsicSpec(name
)) {
985 RootedId
id(cx
, NameToId(name
));
986 RootedFunction
fun(cx
, JS::NewFunctionFromSpec(cx
, spec
, id
));
990 fun
->setIsIntrinsic();
992 value
.setObject(*fun
);
993 return GlobalObject::addIntrinsicValue(cx
, global
, name
, value
);
996 if (!cx
->runtime()->getSelfHostedValue(cx
, name
, value
)) {
1000 // It's possible in certain edge cases that cloning the value ended up
1001 // defining the intrinsic. For instance, cloning can call NewArray, which
1002 // resolves Array.prototype, which defines some self-hosted functions. If this
1003 // happens we use the value already defined on the intrinsics holder.
1004 if (global
->maybeGetIntrinsicValue(name
, value
.address(), cx
)) {
1008 return GlobalObject::addIntrinsicValue(cx
, global
, name
, value
);
1012 bool GlobalObject::addIntrinsicValue(JSContext
* cx
,
1013 Handle
<GlobalObject
*> global
,
1014 Handle
<PropertyName
*> name
,
1015 HandleValue value
) {
1016 Rooted
<NativeObject
*> holder(cx
, &global
->getIntrinsicsHolder());
1018 RootedId
id(cx
, NameToId(name
));
1019 MOZ_ASSERT(!holder
->containsPure(id
));
1021 constexpr PropertyFlags propFlags
= {PropertyFlag::Configurable
,
1022 PropertyFlag::Writable
};
1024 if (!NativeObject::addProperty(cx
, holder
, id
, propFlags
, &slot
)) {
1027 holder
->initSlot(slot
, value
);
1032 JSObject
* GlobalObject::createIteratorPrototype(JSContext
* cx
,
1033 Handle
<GlobalObject
*> global
) {
1034 if (!ensureConstructor(cx
, global
, JSProto_Iterator
)) {
1037 JSObject
* proto
= &global
->getPrototype(JSProto_Iterator
);
1042 JSObject
* GlobalObject::createAsyncIteratorPrototype(
1043 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
1044 if (!IsAsyncIteratorHelpersEnabled()) {
1045 return getOrCreateBuiltinProto(cx
, global
, ProtoKind::AsyncIteratorProto
,
1046 initAsyncIteratorProto
);
1049 if (!ensureConstructor(cx
, global
, JSProto_AsyncIterator
)) {
1052 JSObject
* proto
= &global
->getPrototype(JSProto_AsyncIterator
);
1053 global
->initBuiltinProto(ProtoKind::AsyncIteratorProto
, proto
);
1057 void GlobalObject::releaseData(JS::GCContext
* gcx
) {
1058 GlobalObjectData
* data
= maybeData();
1059 setReservedSlot(GLOBAL_DATA_SLOT
, PrivateValue(nullptr));
1060 gcx
->delete_(this, data
, MemoryUse::GlobalObjectData
);
1063 GlobalObjectData::GlobalObjectData(Zone
* zone
)
1064 #ifndef NIGHTLY_BUILD
1070 GlobalObjectData::~GlobalObjectData() = default;
1072 void GlobalObjectData::trace(JSTracer
* trc
, GlobalObject
* global
) {
1073 #ifndef NIGHTLY_BUILD
1074 // Atoms are always tenured so don't need to be traced during minor GC.
1075 if (trc
->runtime()->heapState() != JS::HeapState::MinorCollecting
) {
1076 varNames
.trace(trc
);
1080 for (auto& ctorWithProto
: builtinConstructors
) {
1081 TraceNullableEdge(trc
, &ctorWithProto
.constructor
, "global-builtin-ctor");
1082 TraceNullableEdge(trc
, &ctorWithProto
.prototype
,
1083 "global-builtin-ctor-proto");
1086 for (auto& proto
: builtinProtos
) {
1087 TraceNullableEdge(trc
, &proto
, "global-builtin-proto");
1090 TraceNullableEdge(trc
, &emptyGlobalScope
, "global-empty-scope");
1092 TraceNullableEdge(trc
, &lexicalEnvironment
, "global-lexical-env");
1093 TraceNullableEdge(trc
, &windowProxy
, "global-window-proxy");
1094 TraceNullableEdge(trc
, &intrinsicsHolder
, "global-intrinsics-holder");
1095 TraceNullableEdge(trc
, &computedIntrinsicsHolder
,
1096 "global-computed-intrinsics-holder");
1097 TraceNullableEdge(trc
, &forOfPICChain
, "global-for-of-pic");
1098 TraceNullableEdge(trc
, &sourceURLsHolder
, "global-source-urls");
1099 TraceNullableEdge(trc
, &realmKeyObject
, "global-realm-key");
1100 TraceNullableEdge(trc
, &throwTypeError
, "global-throw-type-error");
1101 TraceNullableEdge(trc
, &eval
, "global-eval");
1102 TraceNullableEdge(trc
, &emptyIterator
, "global-empty-iterator");
1104 TraceNullableEdge(trc
, &arrayShapeWithDefaultProto
, "global-array-shape");
1106 for (auto& shape
: plainObjectShapesWithDefaultProto
) {
1107 TraceNullableEdge(trc
, &shape
, "global-plain-shape");
1110 TraceNullableEdge(trc
, &functionShapeWithDefaultProto
,
1111 "global-function-shape");
1112 TraceNullableEdge(trc
, &extendedFunctionShapeWithDefaultProto
,
1113 "global-ext-function-shape");
1115 TraceNullableEdge(trc
, &boundFunctionShapeWithDefaultProto
,
1116 "global-bound-function-shape");
1118 regExpRealm
.trace(trc
);
1120 TraceNullableEdge(trc
, &mappedArgumentsTemplate
, "mapped-arguments-template");
1121 TraceNullableEdge(trc
, &unmappedArgumentsTemplate
,
1122 "unmapped-arguments-template");
1124 TraceNullableEdge(trc
, &iterResultTemplate
, "iter-result-template_");
1125 TraceNullableEdge(trc
, &iterResultWithoutPrototypeTemplate
,
1126 "iter-result-without-prototype-template");
1128 TraceNullableEdge(trc
, &selfHostingScriptSource
,
1129 "self-hosting-script-source");
1131 if (finalizationRegistryData
) {
1132 finalizationRegistryData
->trace(trc
);
1136 void GlobalObjectData::addSizeOfIncludingThis(
1137 mozilla::MallocSizeOf mallocSizeOf
, JS::ClassInfo
* info
) const {
1138 info
->objectsMallocHeapGlobalData
+= mallocSizeOf(this);
1140 if (regExpRealm
.regExpStatics
) {
1141 info
->objectsMallocHeapGlobalData
+=
1142 regExpRealm
.regExpStatics
->sizeOfIncludingThis(mallocSizeOf
);
1145 #ifndef NIGHTLY_BUILD
1146 info
->objectsMallocHeapGlobalVarNamesSet
+=
1147 varNames
.shallowSizeOfExcludingThis(mallocSizeOf
);