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 #include "builtin/AtomicsObject.h"
13 #include "builtin/BigInt.h"
14 #include "builtin/DataViewObject.h"
15 #ifdef JS_HAS_INTL_API
16 # include "builtin/intl/Collator.h"
17 # include "builtin/intl/DateTimeFormat.h"
18 # include "builtin/intl/DisplayNames.h"
19 # include "builtin/intl/ListFormat.h"
20 # include "builtin/intl/Locale.h"
21 # include "builtin/intl/NumberFormat.h"
22 # include "builtin/intl/PluralRules.h"
23 # include "builtin/intl/RelativeTimeFormat.h"
25 #include "builtin/FinalizationRegistryObject.h"
26 #include "builtin/MapObject.h"
27 #include "builtin/ShadowRealm.h"
28 #include "builtin/Symbol.h"
29 #ifdef JS_HAS_TEMPORAL_API
30 # include "builtin/temporal/Calendar.h"
31 # include "builtin/temporal/Duration.h"
32 # include "builtin/temporal/Instant.h"
33 # include "builtin/temporal/PlainDate.h"
34 # include "builtin/temporal/PlainDateTime.h"
35 # include "builtin/temporal/PlainMonthDay.h"
36 # include "builtin/temporal/PlainTime.h"
37 # include "builtin/temporal/PlainYearMonth.h"
38 # include "builtin/temporal/Temporal.h"
39 # include "builtin/temporal/TemporalNow.h"
40 # include "builtin/temporal/TimeZone.h"
41 # include "builtin/temporal/ZonedDateTime.h"
43 #include "builtin/WeakMapObject.h"
44 #include "builtin/WeakRefObject.h"
45 #include "builtin/WeakSetObject.h"
46 #include "debugger/DebugAPI.h"
47 #include "frontend/CompilationStencil.h"
48 #include "gc/FinalizationObservers.h"
50 #include "gc/GCContext.h"
51 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
52 #include "js/friend/WindowProxy.h" // js::ToWindowProxyIfWindow
53 #include "js/PropertyAndElement.h" // JS_DefineFunctions, JS_DefineProperties
54 #include "js/ProtoKey.h"
55 #include "vm/AsyncFunction.h"
56 #include "vm/AsyncIteration.h"
57 #include "vm/BooleanObject.h"
58 #include "vm/Compartment.h"
59 #include "vm/DateObject.h"
60 #include "vm/EnvironmentObject.h"
61 #include "vm/ErrorObject.h"
62 #include "vm/GeneratorObject.h"
63 #include "vm/JSContext.h"
64 #include "vm/NumberObject.h"
66 #include "vm/PlainObject.h"
67 #include "vm/RegExpObject.h"
68 #include "vm/RegExpStatics.h"
69 #include "vm/SelfHosting.h"
70 #include "vm/StringObject.h"
71 #include "wasm/WasmFeatures.h"
72 #include "wasm/WasmJS.h"
73 #ifdef ENABLE_RECORD_TUPLE
74 # include "vm/RecordType.h"
75 # include "vm/TupleType.h"
78 #include "gc/GCContext-inl.h"
79 #include "vm/JSObject-inl.h"
80 #include "vm/Realm-inl.h"
86 extern const JSClass IntlClass
;
87 extern const JSClass JSONClass
;
88 extern const JSClass MathClass
;
89 extern const JSClass ReflectClass
;
93 static const JSClass
* const protoTable
[JSProto_LIMIT
] = {
94 #define INIT_FUNC(name, clasp) clasp,
95 #define INIT_FUNC_DUMMY(name, clasp) nullptr,
96 JS_FOR_PROTOTYPES(INIT_FUNC
, INIT_FUNC_DUMMY
)
97 #undef INIT_FUNC_DUMMY
101 JS_PUBLIC_API
const JSClass
* js::ProtoKeyToClass(JSProtoKey key
) {
102 MOZ_ASSERT(key
< JSProto_LIMIT
);
103 return protoTable
[key
];
107 bool GlobalObject::skipDeselectedConstructor(JSContext
* cx
, JSProtoKey key
) {
111 case JSProto_Function
:
112 case JSProto_BoundFunction
:
114 case JSProto_Boolean
:
122 case JSProto_InternalError
:
123 case JSProto_AggregateError
:
124 case JSProto_EvalError
:
125 case JSProto_RangeError
:
126 case JSProto_ReferenceError
:
127 case JSProto_SyntaxError
:
128 case JSProto_TypeError
:
129 case JSProto_URIError
:
130 case JSProto_DebuggeeWouldRun
:
131 case JSProto_CompileError
:
132 case JSProto_LinkError
:
133 case JSProto_RuntimeError
:
134 case JSProto_ArrayBuffer
:
135 case JSProto_Int8Array
:
136 case JSProto_Uint8Array
:
137 case JSProto_Int16Array
:
138 case JSProto_Uint16Array
:
139 case JSProto_Int32Array
:
140 case JSProto_Uint32Array
:
141 case JSProto_Float32Array
:
142 case JSProto_Float64Array
:
143 case JSProto_Uint8ClampedArray
:
144 case JSProto_BigInt64Array
:
145 case JSProto_BigUint64Array
:
148 case JSProto_WeakMap
:
151 case JSProto_DataView
:
153 case JSProto_Reflect
:
154 case JSProto_WeakSet
:
155 case JSProto_TypedArray
:
156 case JSProto_SavedFrame
:
157 case JSProto_Promise
:
158 case JSProto_AsyncFunction
:
159 case JSProto_GeneratorFunction
:
160 case JSProto_AsyncGeneratorFunction
:
161 #ifdef ENABLE_RECORD_TUPLE
167 case JSProto_WebAssembly
:
168 return !wasm::HasSupport(cx
);
170 case JSProto_WasmModule
:
171 case JSProto_WasmInstance
:
172 case JSProto_WasmMemory
:
173 case JSProto_WasmTable
:
174 case JSProto_WasmGlobal
:
175 case JSProto_WasmTag
:
176 #ifdef ENABLE_WASM_TYPE_REFLECTIONS
177 case JSProto_WasmFunction
:
179 case JSProto_WasmException
:
182 #ifdef JS_HAS_INTL_API
184 case JSProto_Collator
:
185 case JSProto_DateTimeFormat
:
186 case JSProto_DisplayNames
:
188 case JSProto_ListFormat
:
189 case JSProto_NumberFormat
:
190 case JSProto_PluralRules
:
191 case JSProto_RelativeTimeFormat
:
195 #ifdef JS_HAS_TEMPORAL_API
196 case JSProto_Temporal
:
197 case JSProto_Calendar
:
198 case JSProto_Duration
:
199 case JSProto_Instant
:
200 case JSProto_PlainDate
:
201 case JSProto_PlainDateTime
:
202 case JSProto_PlainMonthDay
:
203 case JSProto_PlainTime
:
204 case JSProto_PlainYearMonth
:
205 case JSProto_TemporalNow
:
206 case JSProto_TimeZone
:
207 case JSProto_ZonedDateTime
:
211 // Return true if the given constructor has been disabled at run-time.
212 case JSProto_Atomics
:
213 case JSProto_SharedArrayBuffer
:
214 return !cx
->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
216 case JSProto_WeakRef
:
217 case JSProto_FinalizationRegistry
:
218 return cx
->realm()->creationOptions().getWeakRefsEnabled() ==
219 JS::WeakRefSpecifier::Disabled
;
221 case JSProto_Iterator
:
222 case JSProto_AsyncIterator
:
223 return !cx
->realm()->creationOptions().getIteratorHelpersEnabled();
225 case JSProto_ShadowRealm
:
226 return !cx
->realm()->creationOptions().getShadowRealmsEnabled();
229 MOZ_CRASH("unexpected JSProtoKey");
233 static bool ShouldFreezeBuiltin(JSProtoKey key
) {
234 // We can't freeze Reflect because JS_InitReflectParse defines Reflect.parse.
235 if (key
== JSProto_Reflect
) {
238 // We can't freeze Date because some browser tests use the Sinon library which
239 // redefines Date.now.
240 if (key
== JSProto_Date
) {
246 static unsigned GetAttrsForResolvedGlobal(GlobalObject
* global
,
248 unsigned attrs
= JSPROP_RESOLVING
;
249 if (global
->realm()->creationOptions().freezeBuiltins() &&
250 ShouldFreezeBuiltin(key
)) {
251 attrs
|= JSPROP_PERMANENT
| JSPROP_READONLY
;
257 bool GlobalObject::resolveConstructor(JSContext
* cx
,
258 Handle
<GlobalObject
*> global
,
259 JSProtoKey key
, IfClassIsDisabled mode
) {
260 MOZ_ASSERT(key
!= JSProto_Null
);
261 MOZ_ASSERT(key
!= JSProto_BoundFunction
,
262 "bound functions don't have their own proto object");
263 MOZ_ASSERT(!global
->isStandardClassResolved(key
));
264 MOZ_ASSERT(cx
->compartment() == global
->compartment());
266 // |global| must be same-compartment but make sure we're in its realm: the
267 // code below relies on this.
268 AutoRealm
ar(cx
, global
);
270 // Prohibit collection of allocation metadata. Metadata builders shouldn't
271 // need to observe lazily-constructed prototype objects coming into
272 // existence. And assertions start to fail when the builder itself attempts
273 // an allocation that re-entrantly tries to create the same prototype.
274 AutoSuppressAllocationMetadataBuilder
suppressMetadata(cx
);
276 // Constructor resolution may execute self-hosted scripts. These
277 // self-hosted scripts do not call out to user code by construction. Allow
278 // all scripts to execute, even in debuggee compartments that are paused.
279 AutoSuppressDebuggeeNoExecuteChecks
suppressNX(cx
);
281 // Some classes can be disabled at compile time, others at run time;
282 // if a feature is compile-time disabled, clasp is null.
283 const JSClass
* clasp
= ProtoKeyToClass(key
);
284 if (!clasp
|| skipDeselectedConstructor(cx
, key
)) {
285 if (mode
== IfClassIsDisabled::Throw
) {
286 JS_ReportErrorNumberASCII(cx
, GetErrorMessage
, nullptr,
287 JSMSG_CONSTRUCTOR_DISABLED
,
288 clasp
? clasp
->name
: "constructor");
294 // Class spec must have a constructor defined.
295 if (!clasp
->specDefined()) {
299 bool isObjectOrFunction
= key
== JSProto_Function
|| key
== JSProto_Object
;
301 // We need to create the prototype first, and immediately stash it in the
302 // slot. This is so the following bootstrap ordering is possible:
303 // * Object.prototype
304 // * Function.prototype
308 // We get the above when Object is resolved before Function. If Function
309 // is resolved before Object, we'll end up re-entering resolveConstructor
310 // for Function, which is a problem. So if Function is being resolved
311 // before Object.prototype exists, we just resolve Object instead, since we
312 // know that Function will also be resolved before we return.
313 if (key
== JSProto_Function
&& !global
->hasPrototype(JSProto_Object
)) {
314 return resolveConstructor(cx
, global
, JSProto_Object
,
315 IfClassIsDisabled::DoNothing
);
318 // %IteratorPrototype%.map.[[Prototype]] is %Generator% and
319 // %Generator%.prototype.[[Prototype]] is %IteratorPrototype%.
320 // A workaround in initIteratorProto prevents runaway mutual recursion while
321 // setting these up. Ensure the workaround is triggered already:
322 if (key
== JSProto_GeneratorFunction
&&
323 !global
->hasBuiltinProto(ProtoKind::IteratorProto
)) {
324 if (!getOrCreateIteratorPrototype(cx
, global
)) {
328 // If iterator helpers are enabled, populating %IteratorPrototype% will
329 // have recursively gone through here.
330 if (global
->isStandardClassResolved(key
)) {
335 // We don't always have a prototype (i.e. Math and JSON). If we don't,
336 // |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
337 // should all be null.
338 RootedObject
proto(cx
);
339 if (ClassObjectCreationOp createPrototype
=
340 clasp
->specCreatePrototypeHook()) {
341 proto
= createPrototype(cx
, key
);
346 if (isObjectOrFunction
) {
347 // Make sure that creating the prototype didn't recursively resolve
348 // our own constructor. We can't just assert that there's no
349 // prototype; OOMs can result in incomplete resolutions in which
350 // the prototype is saved but not the constructor. So use the same
351 // criteria that protects entry into this function.
352 MOZ_ASSERT(!global
->isStandardClassResolved(key
));
354 global
->setPrototype(key
, proto
);
358 // Create the constructor.
359 RootedObject
ctor(cx
, clasp
->specCreateConstructorHook()(cx
, key
));
364 RootedId
id(cx
, NameToId(ClassName(key
, cx
)));
365 if (isObjectOrFunction
) {
366 if (clasp
->specShouldDefineConstructor()) {
367 RootedValue
ctorValue(cx
, ObjectValue(*ctor
));
368 unsigned attrs
= GetAttrsForResolvedGlobal(global
, key
);
369 if (!DefineDataProperty(cx
, global
, id
, ctorValue
, attrs
)) {
374 global
->setConstructor(key
, ctor
);
377 if (const JSFunctionSpec
* funs
= clasp
->specPrototypeFunctions()) {
378 if (!JS_DefineFunctions(cx
, proto
, funs
)) {
382 if (const JSPropertySpec
* props
= clasp
->specPrototypeProperties()) {
383 if (!JS_DefineProperties(cx
, proto
, props
)) {
387 if (const JSFunctionSpec
* funs
= clasp
->specConstructorFunctions()) {
388 if (!JS_DefineFunctions(cx
, ctor
, funs
)) {
392 if (const JSPropertySpec
* props
= clasp
->specConstructorProperties()) {
393 if (!JS_DefineProperties(cx
, ctor
, props
)) {
398 // If the prototype exists, link it with the constructor.
399 if (proto
&& !LinkConstructorAndPrototype(cx
, ctor
, proto
)) {
403 // Call the post-initialization hook, if provided.
404 if (FinishClassInitOp finishInit
= clasp
->specFinishInitHook()) {
405 if (!finishInit(cx
, ctor
, proto
)) {
410 if (ShouldFreezeBuiltin(key
)) {
411 if (!JS::MaybeFreezeCtorAndPrototype(cx
, ctor
, proto
)) {
416 if (!isObjectOrFunction
) {
417 // Any operations that modifies the global object should be placed
418 // after any other fallible operations.
420 // Fallible operation that modifies the global object.
421 if (clasp
->specShouldDefineConstructor()) {
422 bool shouldReallyDefine
= true;
424 // On the web, it isn't presently possible to expose the global
425 // "SharedArrayBuffer" property unless the page is cross-site-isolated.
426 // Only define this constructor if an option on the realm indicates that
427 // it should be defined.
428 if (key
== JSProto_SharedArrayBuffer
) {
429 const JS::RealmCreationOptions
& options
=
430 global
->realm()->creationOptions();
432 MOZ_ASSERT(options
.getSharedMemoryAndAtomicsEnabled(),
433 "shouldn't be defining SharedArrayBuffer if shared memory "
436 shouldReallyDefine
= options
.defineSharedArrayBufferConstructor();
439 if (shouldReallyDefine
) {
440 RootedValue
ctorValue(cx
, ObjectValue(*ctor
));
441 unsigned attrs
= GetAttrsForResolvedGlobal(global
, key
);
442 if (!DefineDataProperty(cx
, global
, id
, ctorValue
, attrs
)) {
448 // Infallible operations that modify the global object.
449 global
->setConstructor(key
, ctor
);
451 global
->setPrototype(key
, proto
);
458 // Resolve a "globalThis" self-referential property if necessary,
459 // per a stage-3 proposal. https://github.com/tc39/ecma262/pull/702
461 // We could also do this in |FinishObjectClassInit| to trim the global
462 // resolve hook. Unfortunately, |ToWindowProxyIfWindow| doesn't work then:
463 // the browser's |nsGlobalWindow::SetNewDocument| invokes Object init
464 // *before* it sets the global's WindowProxy using |js::SetWindowProxy|.
466 // Refactoring global object creation code to support this approach is a
467 // challenge for another day.
469 bool GlobalObject::maybeResolveGlobalThis(JSContext
* cx
,
470 Handle
<GlobalObject
*> global
,
472 if (!global
->data().globalThisResolved
) {
473 RootedValue
v(cx
, ObjectValue(*ToWindowProxyIfWindow(global
)));
474 if (!DefineDataProperty(cx
, global
, cx
->names().globalThis
, v
,
480 global
->data().globalThisResolved
= true;
487 JSObject
* GlobalObject::createBuiltinProto(JSContext
* cx
,
488 Handle
<GlobalObject
*> global
,
489 ProtoKind kind
, ObjectInitOp init
) {
490 if (!init(cx
, global
)) {
494 return &global
->getBuiltinProto(kind
);
497 JSObject
* GlobalObject::createBuiltinProto(JSContext
* cx
,
498 Handle
<GlobalObject
*> global
,
499 ProtoKind kind
, Handle
<JSAtom
*> tag
,
500 ObjectInitWithTagOp init
) {
501 if (!init(cx
, global
, tag
)) {
505 return &global
->getBuiltinProto(kind
);
508 static bool ThrowTypeError(JSContext
* cx
, unsigned argc
, Value
* vp
) {
509 ThrowTypeErrorBehavior(cx
);
514 JSObject
* GlobalObject::getOrCreateThrowTypeError(
515 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
516 if (JSFunction
* fun
= global
->data().throwTypeError
) {
520 // Construct the unique [[%ThrowTypeError%]] function object, used only for
521 // "callee" and "caller" accessors on strict mode arguments objects. (The
522 // spec also uses this for "arguments" and "caller" on various functions,
523 // but we're experimenting with implementing them using accessors on
524 // |Function.prototype| right now.)
526 RootedFunction
throwTypeError(
527 cx
, NewNativeFunction(cx
, ThrowTypeError
, 0, nullptr));
528 if (!throwTypeError
|| !PreventExtensions(cx
, throwTypeError
)) {
532 // The "length" property of %ThrowTypeError% is non-configurable.
533 Rooted
<PropertyDescriptor
> nonConfigurableDesc(cx
,
534 PropertyDescriptor::Empty());
535 nonConfigurableDesc
.setConfigurable(false);
537 RootedId
lengthId(cx
, NameToId(cx
->names().length
));
538 ObjectOpResult lengthResult
;
539 if (!NativeDefineProperty(cx
, throwTypeError
, lengthId
, nonConfigurableDesc
,
543 MOZ_ASSERT(lengthResult
);
545 // The "name" property of %ThrowTypeError% is non-configurable, adjust
546 // the default property attributes accordingly.
547 RootedId
nameId(cx
, NameToId(cx
->names().name
));
548 ObjectOpResult nameResult
;
549 if (!NativeDefineProperty(cx
, throwTypeError
, nameId
, nonConfigurableDesc
,
553 MOZ_ASSERT(nameResult
);
555 global
->data().throwTypeError
.init(throwTypeError
);
556 return throwTypeError
;
559 GlobalObject
* GlobalObject::createInternal(JSContext
* cx
,
560 const JSClass
* clasp
) {
561 MOZ_ASSERT(clasp
->flags
& JSCLASS_IS_GLOBAL
);
562 MOZ_ASSERT(clasp
->isTrace(JS_GlobalObjectTraceHook
));
564 JSObject
* obj
= NewTenuredObjectWithGivenProto(cx
, clasp
, nullptr);
569 Rooted
<GlobalObject
*> global(cx
, &obj
->as
<GlobalObject
>());
570 MOZ_ASSERT(global
->isUnqualifiedVarObj());
573 auto data
= cx
->make_unique
<GlobalObjectData
>(cx
->zone());
577 // Note: it's important for the realm's global to be initialized at the
578 // same time as the global's GlobalObjectData, because we free the global's
579 // data when Realm::global_ is cleared.
580 cx
->realm()->initGlobal(*global
);
581 InitReservedSlot(global
, GLOBAL_DATA_SLOT
, data
.release(),
582 MemoryUse::GlobalObjectData
);
585 Rooted
<GlobalLexicalEnvironmentObject
*> lexical(
586 cx
, GlobalLexicalEnvironmentObject::create(cx
, global
));
590 global
->data().lexicalEnvironment
.init(lexical
);
592 Rooted
<GlobalScope
*> emptyGlobalScope(
593 cx
, GlobalScope::createEmpty(cx
, ScopeKind::Global
));
594 if (!emptyGlobalScope
) {
597 global
->data().emptyGlobalScope
.init(emptyGlobalScope
);
599 if (!GlobalObject::createIntrinsicsHolder(cx
, global
)) {
603 if (!JSObject::setQualifiedVarObj(cx
, global
)) {
606 if (!JSObject::setGenerationCountedGlobal(cx
, global
)) {
614 GlobalObject
* GlobalObject::new_(JSContext
* cx
, const JSClass
* clasp
,
615 JSPrincipals
* principals
,
616 JS::OnNewGlobalHookOption hookOption
,
617 const JS::RealmOptions
& options
) {
618 MOZ_ASSERT(!cx
->isExceptionPending());
619 MOZ_ASSERT_IF(cx
->zone(), !cx
->zone()->isAtomsZone());
621 // If we are creating a new global in an existing compartment, make sure the
622 // compartment has a live global at all times (by rooting it here).
624 Rooted
<GlobalObject
*> existingGlobal(cx
);
625 const JS::RealmCreationOptions
& creationOptions
= options
.creationOptions();
626 if (creationOptions
.compartmentSpecifier() ==
627 JS::CompartmentSpecifier::ExistingCompartment
) {
628 Compartment
* comp
= creationOptions
.compartment();
629 existingGlobal
= &comp
->firstGlobal();
632 Realm
* realm
= NewRealm(cx
, principals
, options
);
637 Rooted
<GlobalObject
*> global(cx
);
639 AutoRealmUnchecked
ar(cx
, realm
);
640 global
= GlobalObject::createInternal(cx
, clasp
);
645 // Make transactional initialization of these constructors by discarding the
646 // incompletely initialized global if an error occur. This also ensures the
647 // global's prototype chain is initialized (in FinishObjectClassInit).
648 if (!ensureConstructor(cx
, global
, JSProto_Object
) ||
649 !ensureConstructor(cx
, global
, JSProto_Function
)) {
653 realm
->clearInitializingGlobal();
654 if (hookOption
== JS::FireOnNewGlobalHook
) {
655 JS_FireOnNewGlobalObject(cx
, global
);
662 GlobalScope
& GlobalObject::emptyGlobalScope() const {
663 return *data().emptyGlobalScope
;
666 bool GlobalObject::valueIsEval(const Value
& val
) {
667 return val
.isObject() && data().eval
== &val
.toObject();
671 bool GlobalObject::initStandardClasses(JSContext
* cx
,
672 Handle
<GlobalObject
*> global
) {
673 /* Define a top-level property 'undefined' with the undefined value. */
674 if (!DefineDataProperty(
675 cx
, global
, cx
->names().undefined
, UndefinedHandleValue
,
676 JSPROP_PERMANENT
| JSPROP_READONLY
| JSPROP_RESOLVING
)) {
680 // Resolve a "globalThis" self-referential property if necessary.
682 if (!GlobalObject::maybeResolveGlobalThis(cx
, global
, &resolved
)) {
686 for (size_t k
= 0; k
< JSProto_LIMIT
; ++k
) {
687 JSProtoKey key
= static_cast<JSProtoKey
>(k
);
688 if (key
!= JSProto_Null
&& key
!= JSProto_BoundFunction
&&
689 !global
->isStandardClassResolved(key
)) {
690 if (!resolveConstructor(cx
, global
, static_cast<JSProtoKey
>(k
),
691 IfClassIsDisabled::DoNothing
)) {
700 JSFunction
* GlobalObject::createConstructor(JSContext
* cx
, Native ctor
,
701 JSAtom
* nameArg
, unsigned length
,
703 const JSJitInfo
* jitInfo
) {
704 Rooted
<JSAtom
*> name(cx
, nameArg
);
705 JSFunction
* fun
= NewNativeConstructor(cx
, ctor
, length
, name
, kind
);
711 fun
->setJitInfo(jitInfo
);
717 static NativeObject
* CreateBlankProto(JSContext
* cx
, const JSClass
* clasp
,
719 ObjectFlags objFlags
) {
720 MOZ_ASSERT(!clasp
->isJSFunction());
722 if (clasp
== &PlainObject::class_
) {
723 // NOTE: There should be no reason currently to support this. It could
724 // however be added later if needed.
725 MOZ_ASSERT(objFlags
.isEmpty());
726 return NewPlainObjectWithProto(cx
, proto
, TenuredObject
);
729 return NewTenuredObjectWithGivenProto(cx
, clasp
, proto
, objFlags
);
733 NativeObject
* GlobalObject::createBlankPrototype(JSContext
* cx
,
734 Handle
<GlobalObject
*> global
,
735 const JSClass
* clasp
,
736 ObjectFlags objFlags
) {
737 RootedObject
objectProto(cx
, &global
->getObjectPrototype());
738 return CreateBlankProto(cx
, clasp
, objectProto
, objFlags
);
742 NativeObject
* GlobalObject::createBlankPrototypeInheriting(JSContext
* cx
,
743 const JSClass
* clasp
,
744 HandleObject proto
) {
745 return CreateBlankProto(cx
, clasp
, proto
, ObjectFlags());
748 bool js::LinkConstructorAndPrototype(JSContext
* cx
, JSObject
* ctor_
,
749 JSObject
* proto_
, unsigned prototypeAttrs
,
750 unsigned constructorAttrs
) {
751 RootedObject
ctor(cx
, ctor_
), proto(cx
, proto_
);
753 RootedValue
protoVal(cx
, ObjectValue(*proto
));
754 RootedValue
ctorVal(cx
, ObjectValue(*ctor
));
756 return DefineDataProperty(cx
, ctor
, cx
->names().prototype
, protoVal
,
758 DefineDataProperty(cx
, proto
, cx
->names().constructor
, ctorVal
,
762 bool js::DefinePropertiesAndFunctions(JSContext
* cx
, HandleObject obj
,
763 const JSPropertySpec
* ps
,
764 const JSFunctionSpec
* fs
) {
765 if (ps
&& !JS_DefineProperties(cx
, obj
, ps
)) {
768 if (fs
&& !JS_DefineFunctions(cx
, obj
, fs
)) {
774 bool js::DefineToStringTag(JSContext
* cx
, HandleObject obj
, JSAtom
* tag
) {
775 RootedId
toStringTagId(
776 cx
, PropertyKey::Symbol(cx
->wellKnownSymbols().toStringTag
));
777 RootedValue
tagString(cx
, StringValue(tag
));
778 return DefineDataProperty(cx
, obj
, toStringTagId
, tagString
, JSPROP_READONLY
);
782 NativeObject
* GlobalObject::getOrCreateForOfPICObject(
783 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
785 NativeObject
* forOfPIC
= global
->getForOfPICObject();
790 forOfPIC
= ForOfPIC::createForOfPICObject(cx
, global
);
794 global
->data().forOfPICChain
.init(forOfPIC
);
799 JSObject
* GlobalObject::getOrCreateRealmKeyObject(
800 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
802 if (PlainObject
* key
= global
->data().realmKeyObject
) {
806 PlainObject
* key
= NewPlainObject(cx
);
811 global
->data().realmKeyObject
.init(key
);
816 RegExpStatics
* GlobalObject::getRegExpStatics(JSContext
* cx
,
817 Handle
<GlobalObject
*> global
) {
820 if (!global
->regExpRealm().regExpStatics
) {
821 auto statics
= RegExpStatics::create(cx
);
825 global
->regExpRealm().regExpStatics
= std::move(statics
);
828 return global
->regExpRealm().regExpStatics
.get();
831 gc::FinalizationRegistryGlobalData
*
832 GlobalObject::getOrCreateFinalizationRegistryData() {
833 if (!data().finalizationRegistryData
) {
834 data().finalizationRegistryData
=
835 MakeUnique
<gc::FinalizationRegistryGlobalData
>(zone());
838 return maybeFinalizationRegistryData();
841 bool GlobalObject::addToVarNames(JSContext
* cx
, JS::Handle
<JSAtom
*> name
) {
844 if (!data().varNames
.put(name
)) {
845 ReportOutOfMemory(cx
);
853 bool GlobalObject::createIntrinsicsHolder(JSContext
* cx
,
854 Handle
<GlobalObject
*> global
) {
855 Rooted
<NativeObject
*> intrinsicsHolder(
856 cx
, NewPlainObjectWithProto(cx
, nullptr, TenuredObject
));
857 if (!intrinsicsHolder
) {
861 // Install the intrinsics holder on the global.
862 global
->data().intrinsicsHolder
.init(intrinsicsHolder
);
867 bool GlobalObject::getSelfHostedFunction(JSContext
* cx
,
868 Handle
<GlobalObject
*> global
,
869 Handle
<PropertyName
*> selfHostedName
,
870 Handle
<JSAtom
*> name
, unsigned nargs
,
871 MutableHandleValue funVal
) {
872 if (global
->maybeGetIntrinsicValue(selfHostedName
, funVal
.address(), cx
)) {
873 RootedFunction
fun(cx
, &funVal
.toObject().as
<JSFunction
>());
874 if (fun
->fullExplicitName() == name
) {
878 if (fun
->fullExplicitName() == selfHostedName
) {
879 // This function was initially cloned because it was called by
880 // other self-hosted code, so the clone kept its self-hosted name,
881 // instead of getting the name it's intended to have in content
882 // compartments. This can happen when a lazy builtin is initialized
883 // after self-hosted code for another builtin used the same
884 // function. In that case, we need to change the function's name,
885 // which is ok because it can't have been exposed to content
891 // The function might be installed multiple times on the same or
892 // different builtins, under different property names, so its name
893 // might be neither "selfHostedName" nor "name". In that case, its
894 // canonical name must've been set using the `_SetCanonicalName`
896 cx
->runtime()->assertSelfHostedFunctionHasCanonicalName(selfHostedName
);
900 JSRuntime
* runtime
= cx
->runtime();
901 frontend::ScriptIndex index
=
902 runtime
->getSelfHostedScriptIndexRange(selfHostedName
)->start
;
904 runtime
->selfHostStencil().instantiateSelfHostedLazyFunction(
905 cx
, runtime
->selfHostStencilInput().atomCache
, index
, name
);
909 MOZ_ASSERT(fun
->nargs() == nargs
);
910 funVal
.setObject(*fun
);
912 return GlobalObject::addIntrinsicValue(cx
, global
, selfHostedName
, funVal
);
916 bool GlobalObject::getIntrinsicValueSlow(JSContext
* cx
,
917 Handle
<GlobalObject
*> global
,
918 Handle
<PropertyName
*> name
,
919 MutableHandleValue value
) {
920 // If this is a C++ intrinsic, simply define the function on the intrinsics
922 if (const JSFunctionSpec
* spec
= js::FindIntrinsicSpec(name
)) {
923 RootedId
id(cx
, NameToId(name
));
924 RootedFunction
fun(cx
, JS::NewFunctionFromSpec(cx
, spec
, id
));
928 fun
->setIsIntrinsic();
930 value
.setObject(*fun
);
931 return GlobalObject::addIntrinsicValue(cx
, global
, name
, value
);
934 if (!cx
->runtime()->getSelfHostedValue(cx
, name
, value
)) {
938 // It's possible in certain edge cases that cloning the value ended up
939 // defining the intrinsic. For instance, cloning can call NewArray, which
940 // resolves Array.prototype, which defines some self-hosted functions. If this
941 // happens we use the value already defined on the intrinsics holder.
942 if (global
->maybeGetIntrinsicValue(name
, value
.address(), cx
)) {
946 return GlobalObject::addIntrinsicValue(cx
, global
, name
, value
);
950 bool GlobalObject::addIntrinsicValue(JSContext
* cx
,
951 Handle
<GlobalObject
*> global
,
952 Handle
<PropertyName
*> name
,
954 Rooted
<NativeObject
*> holder(cx
, &global
->getIntrinsicsHolder());
956 RootedId
id(cx
, NameToId(name
));
957 MOZ_ASSERT(!holder
->containsPure(id
));
959 constexpr PropertyFlags propFlags
= {PropertyFlag::Configurable
,
960 PropertyFlag::Writable
};
962 if (!NativeObject::addProperty(cx
, holder
, id
, propFlags
, &slot
)) {
965 holder
->initSlot(slot
, value
);
970 JSObject
* GlobalObject::createIteratorPrototype(JSContext
* cx
,
971 Handle
<GlobalObject
*> global
) {
972 if (!cx
->realm()->creationOptions().getIteratorHelpersEnabled()) {
973 return getOrCreateBuiltinProto(cx
, global
, ProtoKind::IteratorProto
,
977 if (!ensureConstructor(cx
, global
, JSProto_Iterator
)) {
980 JSObject
* proto
= &global
->getPrototype(JSProto_Iterator
);
981 global
->initBuiltinProto(ProtoKind::IteratorProto
, proto
);
986 JSObject
* GlobalObject::createAsyncIteratorPrototype(
987 JSContext
* cx
, Handle
<GlobalObject
*> global
) {
988 if (!cx
->realm()->creationOptions().getIteratorHelpersEnabled()) {
989 return getOrCreateBuiltinProto(cx
, global
, ProtoKind::AsyncIteratorProto
,
990 initAsyncIteratorProto
);
993 if (!ensureConstructor(cx
, global
, JSProto_AsyncIterator
)) {
996 JSObject
* proto
= &global
->getPrototype(JSProto_AsyncIterator
);
997 global
->initBuiltinProto(ProtoKind::AsyncIteratorProto
, proto
);
1001 void GlobalObject::releaseData(JS::GCContext
* gcx
) {
1002 GlobalObjectData
* data
= maybeData();
1003 setReservedSlot(GLOBAL_DATA_SLOT
, PrivateValue(nullptr));
1004 gcx
->delete_(this, data
, MemoryUse::GlobalObjectData
);
1007 GlobalObjectData::GlobalObjectData(Zone
* zone
) : varNames(zone
) {}
1009 GlobalObjectData::~GlobalObjectData() = default;
1011 void GlobalObjectData::trace(JSTracer
* trc
, GlobalObject
* global
) {
1012 // Atoms are always tenured so don't need to be traced during minor GC.
1013 if (trc
->runtime()->heapState() != JS::HeapState::MinorCollecting
) {
1014 varNames
.trace(trc
);
1017 for (auto& ctorWithProto
: builtinConstructors
) {
1018 TraceNullableEdge(trc
, &ctorWithProto
.constructor
, "global-builtin-ctor");
1019 TraceNullableEdge(trc
, &ctorWithProto
.prototype
,
1020 "global-builtin-ctor-proto");
1023 for (auto& proto
: builtinProtos
) {
1024 TraceNullableEdge(trc
, &proto
, "global-builtin-proto");
1027 TraceNullableEdge(trc
, &emptyGlobalScope
, "global-empty-scope");
1029 TraceNullableEdge(trc
, &lexicalEnvironment
, "global-lexical-env");
1030 TraceNullableEdge(trc
, &windowProxy
, "global-window-proxy");
1031 TraceNullableEdge(trc
, &intrinsicsHolder
, "global-intrinsics-holder");
1032 TraceNullableEdge(trc
, &computedIntrinsicsHolder
,
1033 "global-computed-intrinsics-holder");
1034 TraceNullableEdge(trc
, &forOfPICChain
, "global-for-of-pic");
1035 TraceNullableEdge(trc
, &sourceURLsHolder
, "global-source-urls");
1036 TraceNullableEdge(trc
, &realmKeyObject
, "global-realm-key");
1037 TraceNullableEdge(trc
, &throwTypeError
, "global-throw-type-error");
1038 TraceNullableEdge(trc
, &eval
, "global-eval");
1039 TraceNullableEdge(trc
, &emptyIterator
, "global-empty-iterator");
1041 TraceNullableEdge(trc
, &arrayShapeWithDefaultProto
, "global-array-shape");
1043 for (auto& shape
: plainObjectShapesWithDefaultProto
) {
1044 TraceNullableEdge(trc
, &shape
, "global-plain-shape");
1047 TraceNullableEdge(trc
, &functionShapeWithDefaultProto
,
1048 "global-function-shape");
1049 TraceNullableEdge(trc
, &extendedFunctionShapeWithDefaultProto
,
1050 "global-ext-function-shape");
1052 TraceNullableEdge(trc
, &boundFunctionShapeWithDefaultProto
,
1053 "global-bound-function-shape");
1055 regExpRealm
.trace(trc
);
1057 TraceNullableEdge(trc
, &mappedArgumentsTemplate
, "mapped-arguments-template");
1058 TraceNullableEdge(trc
, &unmappedArgumentsTemplate
,
1059 "unmapped-arguments-template");
1061 TraceNullableEdge(trc
, &iterResultTemplate
, "iter-result-template_");
1062 TraceNullableEdge(trc
, &iterResultWithoutPrototypeTemplate
,
1063 "iter-result-without-prototype-template");
1065 TraceNullableEdge(trc
, &selfHostingScriptSource
,
1066 "self-hosting-script-source");
1068 if (finalizationRegistryData
) {
1069 finalizationRegistryData
->trace(trc
);
1073 void GlobalObjectData::addSizeOfIncludingThis(
1074 mozilla::MallocSizeOf mallocSizeOf
, JS::ClassInfo
* info
) const {
1075 info
->objectsMallocHeapGlobalData
+= mallocSizeOf(this);
1077 if (regExpRealm
.regExpStatics
) {
1078 info
->objectsMallocHeapGlobalData
+=
1079 regExpRealm
.regExpStatics
->sizeOfIncludingThis(mallocSizeOf
);
1082 info
->objectsMallocHeapGlobalVarNamesSet
+=
1083 varNames
.shallowSizeOfExcludingThis(mallocSizeOf
);