Bug 1865597 - Add error checking when initializing parallel marking and disable on...
[gecko.git] / js / src / vm / GlobalObject.cpp
blob5bfd0c98a7a43b572797f6f2d53588d7c0d3d92b
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"
9 #include "jsapi.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"
24 #endif
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"
42 #endif
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"
49 #include "gc/GC.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"
65 #include "vm/PIC.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"
76 #endif
78 #include "gc/GCContext-inl.h"
79 #include "vm/JSObject-inl.h"
80 #include "vm/Realm-inl.h"
82 using namespace js;
84 namespace js {
86 extern const JSClass IntlClass;
87 extern const JSClass JSONClass;
88 extern const JSClass MathClass;
89 extern const JSClass ReflectClass;
91 } // namespace js
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
98 #undef INIT_FUNC
101 JS_PUBLIC_API const JSClass* js::ProtoKeyToClass(JSProtoKey key) {
102 MOZ_ASSERT(key < JSProto_LIMIT);
103 return protoTable[key];
106 /* static */
107 bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) {
108 switch (key) {
109 case JSProto_Null:
110 case JSProto_Object:
111 case JSProto_Function:
112 case JSProto_BoundFunction:
113 case JSProto_Array:
114 case JSProto_Boolean:
115 case JSProto_JSON:
116 case JSProto_Date:
117 case JSProto_Math:
118 case JSProto_Number:
119 case JSProto_String:
120 case JSProto_RegExp:
121 case JSProto_Error:
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:
146 case JSProto_BigInt:
147 case JSProto_Proxy:
148 case JSProto_WeakMap:
149 case JSProto_Map:
150 case JSProto_Set:
151 case JSProto_DataView:
152 case JSProto_Symbol:
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
162 case JSProto_Record:
163 case JSProto_Tuple:
164 #endif
165 return false;
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:
178 #endif
179 case JSProto_WasmException:
180 return false;
182 #ifdef JS_HAS_INTL_API
183 case JSProto_Intl:
184 case JSProto_Collator:
185 case JSProto_DateTimeFormat:
186 case JSProto_DisplayNames:
187 case JSProto_Locale:
188 case JSProto_ListFormat:
189 case JSProto_NumberFormat:
190 case JSProto_PluralRules:
191 case JSProto_RelativeTimeFormat:
192 return false;
193 #endif
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:
208 return false;
209 #endif
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();
228 default:
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) {
236 return false;
238 // We can't freeze Date because some browser tests use the Sinon library which
239 // redefines Date.now.
240 if (key == JSProto_Date) {
241 return false;
243 return true;
246 static unsigned GetAttrsForResolvedGlobal(GlobalObject* global,
247 JSProtoKey key) {
248 unsigned attrs = JSPROP_RESOLVING;
249 if (global->realm()->creationOptions().freezeBuiltins() &&
250 ShouldFreezeBuiltin(key)) {
251 attrs |= JSPROP_PERMANENT | JSPROP_READONLY;
253 return attrs;
256 /* static*/
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");
289 return false;
291 return true;
294 // Class spec must have a constructor defined.
295 if (!clasp->specDefined()) {
296 return true;
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
305 // * Function
306 // * Object
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)) {
325 return false;
328 // If iterator helpers are enabled, populating %IteratorPrototype% will
329 // have recursively gone through here.
330 if (global->isStandardClassResolved(key)) {
331 return true;
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);
342 if (!proto) {
343 return false;
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));
360 if (!ctor) {
361 return false;
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)) {
370 return false;
374 global->setConstructor(key, ctor);
377 if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
378 if (!JS_DefineFunctions(cx, proto, funs)) {
379 return false;
382 if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
383 if (!JS_DefineProperties(cx, proto, props)) {
384 return false;
387 if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
388 if (!JS_DefineFunctions(cx, ctor, funs)) {
389 return false;
392 if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
393 if (!JS_DefineProperties(cx, ctor, props)) {
394 return false;
398 // If the prototype exists, link it with the constructor.
399 if (proto && !LinkConstructorAndPrototype(cx, ctor, proto)) {
400 return false;
403 // Call the post-initialization hook, if provided.
404 if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
405 if (!finishInit(cx, ctor, proto)) {
406 return false;
410 if (ShouldFreezeBuiltin(key)) {
411 if (!JS::MaybeFreezeCtorAndPrototype(cx, ctor, proto)) {
412 return false;
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 "
434 "is disabled");
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)) {
443 return false;
448 // Infallible operations that modify the global object.
449 global->setConstructor(key, ctor);
450 if (proto) {
451 global->setPrototype(key, proto);
455 return true;
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.
468 /* static */
469 bool GlobalObject::maybeResolveGlobalThis(JSContext* cx,
470 Handle<GlobalObject*> global,
471 bool* resolved) {
472 if (!global->data().globalThisResolved) {
473 RootedValue v(cx, ObjectValue(*ToWindowProxyIfWindow(global)));
474 if (!DefineDataProperty(cx, global, cx->names().globalThis, v,
475 JSPROP_RESOLVING)) {
476 return false;
479 *resolved = true;
480 global->data().globalThisResolved = true;
483 return true;
486 /* static */
487 JSObject* GlobalObject::createBuiltinProto(JSContext* cx,
488 Handle<GlobalObject*> global,
489 ProtoKind kind, ObjectInitOp init) {
490 if (!init(cx, global)) {
491 return nullptr;
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)) {
502 return nullptr;
505 return &global->getBuiltinProto(kind);
508 static bool ThrowTypeError(JSContext* cx, unsigned argc, Value* vp) {
509 ThrowTypeErrorBehavior(cx);
510 return false;
513 /* static */
514 JSObject* GlobalObject::getOrCreateThrowTypeError(
515 JSContext* cx, Handle<GlobalObject*> global) {
516 if (JSFunction* fun = global->data().throwTypeError) {
517 return fun;
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)) {
529 return nullptr;
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,
540 lengthResult)) {
541 return nullptr;
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,
550 nameResult)) {
551 return nullptr;
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);
565 if (!obj) {
566 return nullptr;
569 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
570 MOZ_ASSERT(global->isUnqualifiedVarObj());
573 auto data = cx->make_unique<GlobalObjectData>(cx->zone());
574 if (!data) {
575 return nullptr;
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));
587 if (!lexical) {
588 return nullptr;
590 global->data().lexicalEnvironment.init(lexical);
592 Rooted<GlobalScope*> emptyGlobalScope(
593 cx, GlobalScope::createEmpty(cx, ScopeKind::Global));
594 if (!emptyGlobalScope) {
595 return nullptr;
597 global->data().emptyGlobalScope.init(emptyGlobalScope);
599 if (!GlobalObject::createIntrinsicsHolder(cx, global)) {
600 return nullptr;
603 if (!JSObject::setQualifiedVarObj(cx, global)) {
604 return nullptr;
606 if (!JSObject::setGenerationCountedGlobal(cx, global)) {
607 return nullptr;
610 return global;
613 /* static */
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).
623 // See bug 1530364.
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);
633 if (!realm) {
634 return nullptr;
637 Rooted<GlobalObject*> global(cx);
639 AutoRealmUnchecked ar(cx, realm);
640 global = GlobalObject::createInternal(cx, clasp);
641 if (!global) {
642 return nullptr;
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)) {
650 return nullptr;
653 realm->clearInitializingGlobal();
654 if (hookOption == JS::FireOnNewGlobalHook) {
655 JS_FireOnNewGlobalObject(cx, global);
659 return 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();
670 /* static */
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)) {
677 return false;
680 // Resolve a "globalThis" self-referential property if necessary.
681 bool resolved;
682 if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) {
683 return false;
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)) {
692 return false;
696 return true;
699 /* static */
700 JSFunction* GlobalObject::createConstructor(JSContext* cx, Native ctor,
701 JSAtom* nameArg, unsigned length,
702 gc::AllocKind kind,
703 const JSJitInfo* jitInfo) {
704 Rooted<JSAtom*> name(cx, nameArg);
705 JSFunction* fun = NewNativeConstructor(cx, ctor, length, name, kind);
706 if (!fun) {
707 return nullptr;
710 if (jitInfo) {
711 fun->setJitInfo(jitInfo);
714 return fun;
717 static NativeObject* CreateBlankProto(JSContext* cx, const JSClass* clasp,
718 HandleObject proto,
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);
732 /* static */
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);
741 /* static */
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,
757 prototypeAttrs) &&
758 DefineDataProperty(cx, proto, cx->names().constructor, ctorVal,
759 constructorAttrs);
762 bool js::DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
763 const JSPropertySpec* ps,
764 const JSFunctionSpec* fs) {
765 if (ps && !JS_DefineProperties(cx, obj, ps)) {
766 return false;
768 if (fs && !JS_DefineFunctions(cx, obj, fs)) {
769 return false;
771 return true;
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);
781 /* static */
782 NativeObject* GlobalObject::getOrCreateForOfPICObject(
783 JSContext* cx, Handle<GlobalObject*> global) {
784 cx->check(global);
785 NativeObject* forOfPIC = global->getForOfPICObject();
786 if (forOfPIC) {
787 return forOfPIC;
790 forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
791 if (!forOfPIC) {
792 return nullptr;
794 global->data().forOfPICChain.init(forOfPIC);
795 return forOfPIC;
798 /* static */
799 JSObject* GlobalObject::getOrCreateRealmKeyObject(
800 JSContext* cx, Handle<GlobalObject*> global) {
801 cx->check(global);
802 if (PlainObject* key = global->data().realmKeyObject) {
803 return key;
806 PlainObject* key = NewPlainObject(cx);
807 if (!key) {
808 return nullptr;
811 global->data().realmKeyObject.init(key);
812 return key;
815 /* static */
816 RegExpStatics* GlobalObject::getRegExpStatics(JSContext* cx,
817 Handle<GlobalObject*> global) {
818 MOZ_ASSERT(cx);
820 if (!global->regExpRealm().regExpStatics) {
821 auto statics = RegExpStatics::create(cx);
822 if (!statics) {
823 return nullptr;
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) {
842 MOZ_ASSERT(name);
844 if (!data().varNames.put(name)) {
845 ReportOutOfMemory(cx);
846 return false;
849 return true;
852 /* static */
853 bool GlobalObject::createIntrinsicsHolder(JSContext* cx,
854 Handle<GlobalObject*> global) {
855 Rooted<NativeObject*> intrinsicsHolder(
856 cx, NewPlainObjectWithProto(cx, nullptr, TenuredObject));
857 if (!intrinsicsHolder) {
858 return false;
861 // Install the intrinsics holder on the global.
862 global->data().intrinsicsHolder.init(intrinsicsHolder);
863 return true;
866 /* static */
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) {
875 return true;
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
886 // before.
887 fun->setAtom(name);
888 return true;
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`
895 // intrinsic.
896 cx->runtime()->assertSelfHostedFunctionHasCanonicalName(selfHostedName);
897 return true;
900 JSRuntime* runtime = cx->runtime();
901 frontend::ScriptIndex index =
902 runtime->getSelfHostedScriptIndexRange(selfHostedName)->start;
903 JSFunction* fun =
904 runtime->selfHostStencil().instantiateSelfHostedLazyFunction(
905 cx, runtime->selfHostStencilInput().atomCache, index, name);
906 if (!fun) {
907 return false;
909 MOZ_ASSERT(fun->nargs() == nargs);
910 funVal.setObject(*fun);
912 return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
915 /* static */
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
921 // holder.
922 if (const JSFunctionSpec* spec = js::FindIntrinsicSpec(name)) {
923 RootedId id(cx, NameToId(name));
924 RootedFunction fun(cx, JS::NewFunctionFromSpec(cx, spec, id));
925 if (!fun) {
926 return false;
928 fun->setIsIntrinsic();
930 value.setObject(*fun);
931 return GlobalObject::addIntrinsicValue(cx, global, name, value);
934 if (!cx->runtime()->getSelfHostedValue(cx, name, value)) {
935 return false;
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)) {
943 return true;
946 return GlobalObject::addIntrinsicValue(cx, global, name, value);
949 /* static */
950 bool GlobalObject::addIntrinsicValue(JSContext* cx,
951 Handle<GlobalObject*> global,
952 Handle<PropertyName*> name,
953 HandleValue value) {
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};
961 uint32_t slot;
962 if (!NativeObject::addProperty(cx, holder, id, propFlags, &slot)) {
963 return false;
965 holder->initSlot(slot, value);
966 return true;
969 /* static */
970 JSObject* GlobalObject::createIteratorPrototype(JSContext* cx,
971 Handle<GlobalObject*> global) {
972 if (!cx->realm()->creationOptions().getIteratorHelpersEnabled()) {
973 return getOrCreateBuiltinProto(cx, global, ProtoKind::IteratorProto,
974 initIteratorProto);
977 if (!ensureConstructor(cx, global, JSProto_Iterator)) {
978 return nullptr;
980 JSObject* proto = &global->getPrototype(JSProto_Iterator);
981 global->initBuiltinProto(ProtoKind::IteratorProto, proto);
982 return proto;
985 /* static */
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)) {
994 return nullptr;
996 JSObject* proto = &global->getPrototype(JSProto_AsyncIterator);
997 global->initBuiltinProto(ProtoKind::AsyncIteratorProto, proto);
998 return 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);