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/. */
6
7 #include "vm/GlobalObject.h"
8
9 #include "jsapi.h"
10 #include "jsdate.h"
11 #include "jsexn.h"
12 #include "jsfriendapi.h"
13
14 #include "builtin/AtomicsObject.h"
15 #include "builtin/BigInt.h"
16 #include "builtin/DataViewObject.h"
17 #include "builtin/Eval.h"
18 #ifdef JS_HAS_INTL_API
19 # include "builtin/intl/Collator.h"
20 # include "builtin/intl/DateTimeFormat.h"
21 # include "builtin/intl/DisplayNames.h"
22 # include "builtin/intl/ListFormat.h"
23 # include "builtin/intl/Locale.h"
24 # include "builtin/intl/NumberFormat.h"
25 # include "builtin/intl/PluralRules.h"
26 # include "builtin/intl/RelativeTimeFormat.h"
27 #endif
28 #include "builtin/FinalizationRegistryObject.h"
29 #include "builtin/MapObject.h"
30 #include "builtin/ModuleObject.h"
31 #include "builtin/Object.h"
32 #include "builtin/RegExp.h"
33 #include "builtin/SelfHostingDefines.h"
34 #include "builtin/Stream.h"
35 #include "builtin/streams/QueueingStrategies.h" // js::{ByteLength,Count}QueueingStrategy
36 #include "builtin/streams/ReadableStream.h" // js::ReadableStream
37 #include "builtin/streams/ReadableStreamController.h" // js::Readable{StreamDefault,ByteStream}Controller
38 #include "builtin/streams/ReadableStreamReader.h" // js::ReadableStreamDefaultReader
39 #include "builtin/Symbol.h"
40 #include "builtin/WeakMapObject.h"
41 #include "builtin/WeakRefObject.h"
42 #include "builtin/WeakSetObject.h"
43 #include "debugger/DebugAPI.h"
44 #include "frontend/CompilationStencil.h"
45 #include "gc/FinalizationObservers.h"
46 #include "gc/FreeOp.h"
47 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
48 #include "js/friend/WindowProxy.h" // js::ToWindowProxyIfWindow
49 #include "js/PropertyAndElement.h" // JS_DefineFunctions, JS_DefineProperties
50 #include "js/ProtoKey.h"
51 #include "vm/AsyncFunction.h"
52 #include "vm/AsyncIteration.h"
53 #include "vm/BooleanObject.h"
54 #include "vm/DateObject.h"
55 #include "vm/EnvironmentObject.h"
56 #include "vm/ErrorObject.h"
57 #include "vm/GeneratorObject.h"
58 #include "vm/HelperThreads.h"
59 #include "vm/JSContext.h"
60 #include "vm/NumberObject.h"
61 #include "vm/PIC.h"
62 #include "vm/RegExpStatics.h"
63 #include "vm/SelfHosting.h"
64 #include "vm/StringObject.h"
65 #include "wasm/WasmJS.h"
66 #ifdef ENABLE_RECORD_TUPLE
67 # include "vm/RecordType.h"
68 # include "vm/TupleType.h"
69 #endif
70
71 #include "gc/FreeOp-inl.h"
72 #include "vm/JSObject-inl.h"
73 #include "vm/JSScript-inl.h"
74 #include "vm/NativeObject-inl.h"
75 #include "vm/Realm-inl.h"
76
77 using namespace js;
78
79 namespace js {
80
81 extern const JSClass IntlClass;
82 extern const JSClass JSONClass;
83 extern const JSClass MathClass;
84 extern const JSClass ReflectClass;
85
86 } // namespace js
87
88 static const JSClass* const protoTable[JSProto_LIMIT] = {
89 #define INIT_FUNC(name, clasp) clasp,
90 #define INIT_FUNC_DUMMY(name, clasp) nullptr,
91 JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
92 #undef INIT_FUNC_DUMMY
93 #undef INIT_FUNC
94 };
95
ProtoKeyToClass(JSProtoKey key)96 JS_PUBLIC_API const JSClass* js::ProtoKeyToClass(JSProtoKey key) {
97 MOZ_ASSERT(key < JSProto_LIMIT);
98 return protoTable[key];
99 }
100
101 /* static */
skipDeselectedConstructor(JSContext * cx,JSProtoKey key)102 bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) {
103 switch (key) {
104 case JSProto_Null:
105 case JSProto_Object:
106 case JSProto_Function:
107 case JSProto_Array:
108 case JSProto_Boolean:
109 case JSProto_JSON:
110 case JSProto_Date:
111 case JSProto_Math:
112 case JSProto_Number:
113 case JSProto_String:
114 case JSProto_RegExp:
115 case JSProto_Error:
116 case JSProto_InternalError:
117 case JSProto_AggregateError:
118 case JSProto_EvalError:
119 case JSProto_RangeError:
120 case JSProto_ReferenceError:
121 case JSProto_SyntaxError:
122 case JSProto_TypeError:
123 case JSProto_URIError:
124 case JSProto_DebuggeeWouldRun:
125 case JSProto_CompileError:
126 case JSProto_LinkError:
127 case JSProto_RuntimeError:
128 case JSProto_ArrayBuffer:
129 case JSProto_Int8Array:
130 case JSProto_Uint8Array:
131 case JSProto_Int16Array:
132 case JSProto_Uint16Array:
133 case JSProto_Int32Array:
134 case JSProto_Uint32Array:
135 case JSProto_Float32Array:
136 case JSProto_Float64Array:
137 case JSProto_Uint8ClampedArray:
138 case JSProto_BigInt64Array:
139 case JSProto_BigUint64Array:
140 case JSProto_BigInt:
141 case JSProto_Proxy:
142 case JSProto_WeakMap:
143 case JSProto_Map:
144 case JSProto_Set:
145 case JSProto_DataView:
146 case JSProto_Symbol:
147 case JSProto_Reflect:
148 case JSProto_WeakSet:
149 case JSProto_TypedArray:
150 case JSProto_SavedFrame:
151 case JSProto_Promise:
152 case JSProto_AsyncFunction:
153 case JSProto_GeneratorFunction:
154 case JSProto_AsyncGeneratorFunction:
155 #ifdef ENABLE_RECORD_TUPLE
156 case JSProto_Record:
157 case JSProto_Tuple:
158 #endif
159 return false;
160
161 case JSProto_WebAssembly:
162 return !wasm::HasSupport(cx);
163
164 case JSProto_WasmModule:
165 case JSProto_WasmInstance:
166 case JSProto_WasmMemory:
167 case JSProto_WasmTable:
168 case JSProto_WasmGlobal:
169 case JSProto_WasmTag:
170 #ifdef ENABLE_WASM_TYPE_REFLECTIONS
171 case JSProto_WasmFunction:
172 #endif
173 case JSProto_WasmException:
174 return false;
175
176 #ifdef JS_HAS_INTL_API
177 case JSProto_Intl:
178 case JSProto_Collator:
179 case JSProto_DateTimeFormat:
180 case JSProto_DisplayNames:
181 case JSProto_Locale:
182 case JSProto_ListFormat:
183 case JSProto_NumberFormat:
184 case JSProto_PluralRules:
185 case JSProto_RelativeTimeFormat:
186 return false;
187 #endif
188 #ifndef MOZ_DOM_STREAMS
189 case JSProto_ReadableStream:
190 case JSProto_ReadableStreamDefaultReader:
191 case JSProto_ReadableStreamDefaultController:
192 case JSProto_ReadableByteStreamController:
193 case JSProto_ByteLengthQueuingStrategy:
194 case JSProto_CountQueuingStrategy:
195 return !cx->realm()->creationOptions().getStreamsEnabled();
196 #endif
197
198 // Return true if the given constructor has been disabled at run-time.
199 case JSProto_Atomics:
200 case JSProto_SharedArrayBuffer:
201 return !cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
202
203 case JSProto_WeakRef:
204 case JSProto_FinalizationRegistry:
205 return cx->realm()->creationOptions().getWeakRefsEnabled() ==
206 JS::WeakRefSpecifier::Disabled;
207
208 case JSProto_Iterator:
209 case JSProto_AsyncIterator:
210 return !cx->realm()->creationOptions().getIteratorHelpersEnabled();
211
212 default:
213 MOZ_CRASH("unexpected JSProtoKey");
214 }
215 }
216
217 /* static*/
resolveConstructor(JSContext * cx,Handle<GlobalObject * > global,JSProtoKey key,IfClassIsDisabled mode)218 bool GlobalObject::resolveConstructor(JSContext* cx,
219 Handle<GlobalObject*> global,
220 JSProtoKey key, IfClassIsDisabled mode) {
221 MOZ_ASSERT(key != JSProto_Null);
222 MOZ_ASSERT(!global->isStandardClassResolved(key));
223 MOZ_ASSERT(cx->compartment() == global->compartment());
224
225 // |global| must be same-compartment but make sure we're in its realm: the
226 // code below relies on this.
227 AutoRealm ar(cx, global);
228
229 MOZ_ASSERT(!cx->isHelperThreadContext());
230
231 // Prohibit collection of allocation metadata. Metadata builders shouldn't
232 // need to observe lazily-constructed prototype objects coming into
233 // existence. And assertions start to fail when the builder itself attempts
234 // an allocation that re-entrantly tries to create the same prototype.
235 AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
236
237 // Constructor resolution may execute self-hosted scripts. These
238 // self-hosted scripts do not call out to user code by construction. Allow
239 // all scripts to execute, even in debuggee compartments that are paused.
240 AutoSuppressDebuggeeNoExecuteChecks suppressNX(cx);
241
242 // Some classes can be disabled at compile time, others at run time;
243 // if a feature is compile-time disabled, clasp is null.
244 const JSClass* clasp = ProtoKeyToClass(key);
245 if (!clasp || skipDeselectedConstructor(cx, key)) {
246 if (mode == IfClassIsDisabled::Throw) {
247 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
248 JSMSG_CONSTRUCTOR_DISABLED,
249 clasp ? clasp->name : "constructor");
250 return false;
251 }
252 return true;
253 }
254
255 // Class spec must have a constructor defined.
256 if (!clasp->specDefined()) {
257 return true;
258 }
259
260 bool isObjectOrFunction = key == JSProto_Function || key == JSProto_Object;
261
262 // We need to create the prototype first, and immediately stash it in the
263 // slot. This is so the following bootstrap ordering is possible:
264 // * Object.prototype
265 // * Function.prototype
266 // * Function
267 // * Object
268 //
269 // We get the above when Object is resolved before Function. If Function
270 // is resolved before Object, we'll end up re-entering resolveConstructor
271 // for Function, which is a problem. So if Function is being resolved
272 // before Object.prototype exists, we just resolve Object instead, since we
273 // know that Function will also be resolved before we return.
274 if (key == JSProto_Function && !global->hasPrototype(JSProto_Object)) {
275 return resolveConstructor(cx, global, JSProto_Object,
276 IfClassIsDisabled::DoNothing);
277 }
278
279 // %IteratorPrototype%.map.[[Prototype]] is %Generator% and
280 // %Generator%.prototype.[[Prototype]] is %IteratorPrototype%.
281 // A workaround in initIteratorProto prevents runaway mutual recursion while
282 // setting these up. Ensure the workaround is triggered already:
283 if (key == JSProto_GeneratorFunction &&
284 !global->hasBuiltinProto(ProtoKind::IteratorProto)) {
285 if (!getOrCreateIteratorPrototype(cx, global)) {
286 return false;
287 }
288
289 // If iterator helpers are enabled, populating %IteratorPrototype% will
290 // have recursively gone through here.
291 if (global->isStandardClassResolved(key)) {
292 return true;
293 }
294 }
295
296 // We don't always have a prototype (i.e. Math and JSON). If we don't,
297 // |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
298 // should all be null.
299 RootedObject proto(cx);
300 if (ClassObjectCreationOp createPrototype =
301 clasp->specCreatePrototypeHook()) {
302 proto = createPrototype(cx, key);
303 if (!proto) {
304 return false;
305 }
306
307 if (isObjectOrFunction) {
308 // Make sure that creating the prototype didn't recursively resolve
309 // our own constructor. We can't just assert that there's no
310 // prototype; OOMs can result in incomplete resolutions in which
311 // the prototype is saved but not the constructor. So use the same
312 // criteria that protects entry into this function.
313 MOZ_ASSERT(!global->isStandardClassResolved(key));
314
315 global->setPrototype(key, proto);
316 }
317 }
318
319 // Create the constructor.
320 RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
321 if (!ctor) {
322 return false;
323 }
324
325 RootedId id(cx, NameToId(ClassName(key, cx)));
326 if (isObjectOrFunction) {
327 if (clasp->specShouldDefineConstructor()) {
328 RootedValue ctorValue(cx, ObjectValue(*ctor));
329 if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
330 return false;
331 }
332 }
333
334 global->setConstructor(key, ctor);
335 }
336
337 if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
338 if (!JS_DefineFunctions(cx, proto, funs)) {
339 return false;
340 }
341 }
342 if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
343 if (!JS_DefineProperties(cx, proto, props)) {
344 return false;
345 }
346 }
347 if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
348 if (!JS_DefineFunctions(cx, ctor, funs)) {
349 return false;
350 }
351 }
352 if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
353 if (!JS_DefineProperties(cx, ctor, props)) {
354 return false;
355 }
356 }
357
358 // If the prototype exists, link it with the constructor.
359 if (proto && !LinkConstructorAndPrototype(cx, ctor, proto)) {
360 return false;
361 }
362
363 // Call the post-initialization hook, if provided.
364 if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
365 if (!finishInit(cx, ctor, proto)) {
366 return false;
367 }
368 }
369
370 if (!isObjectOrFunction) {
371 // Any operations that modifies the global object should be placed
372 // after any other fallible operations.
373
374 // Fallible operation that modifies the global object.
375 if (clasp->specShouldDefineConstructor()) {
376 bool shouldReallyDefine = true;
377
378 // On the web, it isn't presently possible to expose the global
379 // "SharedArrayBuffer" property unless the page is cross-site-isolated.
380 // Only define this constructor if an option on the realm indicates that
381 // it should be defined.
382 if (key == JSProto_SharedArrayBuffer) {
383 const JS::RealmCreationOptions& options =
384 global->realm()->creationOptions();
385
386 MOZ_ASSERT(options.getSharedMemoryAndAtomicsEnabled(),
387 "shouldn't be defining SharedArrayBuffer if shared memory "
388 "is disabled");
389
390 shouldReallyDefine = options.defineSharedArrayBufferConstructor();
391 }
392
393 if (shouldReallyDefine) {
394 RootedValue ctorValue(cx, ObjectValue(*ctor));
395 if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
396 return false;
397 }
398 }
399 }
400
401 // Infallible operations that modify the global object.
402 global->setConstructor(key, ctor);
403 if (proto) {
404 global->setPrototype(key, proto);
405 }
406 }
407
408 return true;
409 }
410
411 // Resolve a "globalThis" self-referential property if necessary,
412 // per a stage-3 proposal. https://github.com/tc39/ecma262/pull/702
413 //
414 // We could also do this in |FinishObjectClassInit| to trim the global
415 // resolve hook. Unfortunately, |ToWindowProxyIfWindow| doesn't work then:
416 // the browser's |nsGlobalWindow::SetNewDocument| invokes Object init
417 // *before* it sets the global's WindowProxy using |js::SetWindowProxy|.
418 //
419 // Refactoring global object creation code to support this approach is a
420 // challenge for another day.
421 /* static */
maybeResolveGlobalThis(JSContext * cx,Handle<GlobalObject * > global,bool * resolved)422 bool GlobalObject::maybeResolveGlobalThis(JSContext* cx,
423 Handle<GlobalObject*> global,
424 bool* resolved) {
425 if (!global->data().globalThisResolved) {
426 RootedValue v(cx, ObjectValue(*ToWindowProxyIfWindow(global)));
427 if (!DefineDataProperty(cx, global, cx->names().globalThis, v,
428 JSPROP_RESOLVING)) {
429 return false;
430 }
431
432 *resolved = true;
433 global->data().globalThisResolved = true;
434 }
435
436 return true;
437 }
438
439 /* static */
createBuiltinProto(JSContext * cx,Handle<GlobalObject * > global,ProtoKind kind,ObjectInitOp init)440 JSObject* GlobalObject::createBuiltinProto(JSContext* cx,
441 Handle<GlobalObject*> global,
442 ProtoKind kind, ObjectInitOp init) {
443 MOZ_ASSERT(!cx->isHelperThreadContext());
444 if (!init(cx, global)) {
445 return nullptr;
446 }
447
448 return &global->getBuiltinProto(kind);
449 }
450
createBuiltinProto(JSContext * cx,Handle<GlobalObject * > global,ProtoKind kind,HandleAtom tag,ObjectInitWithTagOp init)451 JSObject* GlobalObject::createBuiltinProto(JSContext* cx,
452 Handle<GlobalObject*> global,
453 ProtoKind kind, HandleAtom tag,
454 ObjectInitWithTagOp init) {
455 MOZ_ASSERT(!cx->isHelperThreadContext());
456 if (!init(cx, global, tag)) {
457 return nullptr;
458 }
459
460 return &global->getBuiltinProto(kind);
461 }
462
463 /* static */
initBuiltinConstructor(JSContext * cx,Handle<GlobalObject * > global,JSProtoKey key,HandleObject ctor,HandleObject proto)464 bool GlobalObject::initBuiltinConstructor(JSContext* cx,
465 Handle<GlobalObject*> global,
466 JSProtoKey key, HandleObject ctor,
467 HandleObject proto) {
468 MOZ_ASSERT(!global->empty()); // reserved slots already allocated
469 MOZ_ASSERT(key != JSProto_Null);
470 MOZ_ASSERT(ctor);
471 MOZ_ASSERT(proto);
472
473 RootedId id(cx, NameToId(ClassName(key, cx)));
474 MOZ_ASSERT(!global->lookup(cx, id));
475
476 RootedValue ctorValue(cx, ObjectValue(*ctor));
477 if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
478 return false;
479 }
480
481 global->setConstructor(key, ctor);
482 global->setPrototype(key, proto);
483 return true;
484 }
485
ThrowTypeError(JSContext * cx,unsigned argc,Value * vp)486 static bool ThrowTypeError(JSContext* cx, unsigned argc, Value* vp) {
487 ThrowTypeErrorBehavior(cx);
488 return false;
489 }
490
491 /* static */
getOrCreateThrowTypeError(JSContext * cx,Handle<GlobalObject * > global)492 JSObject* GlobalObject::getOrCreateThrowTypeError(
493 JSContext* cx, Handle<GlobalObject*> global) {
494 if (JSFunction* fun = global->data().throwTypeError) {
495 return fun;
496 }
497
498 // Construct the unique [[%ThrowTypeError%]] function object, used only for
499 // "callee" and "caller" accessors on strict mode arguments objects. (The
500 // spec also uses this for "arguments" and "caller" on various functions,
501 // but we're experimenting with implementing them using accessors on
502 // |Function.prototype| right now.)
503
504 RootedFunction throwTypeError(
505 cx, NewNativeFunction(cx, ThrowTypeError, 0, nullptr));
506 if (!throwTypeError || !PreventExtensions(cx, throwTypeError)) {
507 return nullptr;
508 }
509
510 // The "length" property of %ThrowTypeError% is non-configurable.
511 Rooted<PropertyDescriptor> nonConfigurableDesc(cx,
512 PropertyDescriptor::Empty());
513 nonConfigurableDesc.setConfigurable(false);
514
515 RootedId lengthId(cx, NameToId(cx->names().length));
516 ObjectOpResult lengthResult;
517 if (!NativeDefineProperty(cx, throwTypeError, lengthId, nonConfigurableDesc,
518 lengthResult)) {
519 return nullptr;
520 }
521 MOZ_ASSERT(lengthResult);
522
523 // The "name" property of %ThrowTypeError% is non-configurable, adjust
524 // the default property attributes accordingly.
525 RootedId nameId(cx, NameToId(cx->names().name));
526 ObjectOpResult nameResult;
527 if (!NativeDefineProperty(cx, throwTypeError, nameId, nonConfigurableDesc,
528 nameResult)) {
529 return nullptr;
530 }
531 MOZ_ASSERT(nameResult);
532
533 global->data().throwTypeError.init(throwTypeError);
534 return throwTypeError;
535 }
536
createInternal(JSContext * cx,const JSClass * clasp)537 GlobalObject* GlobalObject::createInternal(JSContext* cx,
538 const JSClass* clasp) {
539 MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
540 MOZ_ASSERT(clasp->isTrace(JS_GlobalObjectTraceHook));
541
542 JSObject* obj = NewTenuredObjectWithGivenProto(cx, clasp, nullptr);
543 if (!obj) {
544 return nullptr;
545 }
546
547 Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
548 MOZ_ASSERT(global->isUnqualifiedVarObj());
549
550 {
551 auto data = cx->make_unique<GlobalObjectData>(cx->zone());
552 if (!data) {
553 return nullptr;
554 }
555 // Note: it's important for the realm's global to be initialized at the
556 // same time as the global's GlobalObjectData, because we free the global's
557 // data when Realm::global_ is cleared.
558 cx->realm()->initGlobal(*global);
559 InitReservedSlot(global, GLOBAL_DATA_SLOT, data.release(),
560 MemoryUse::GlobalObjectData);
561 }
562
563 Rooted<GlobalLexicalEnvironmentObject*> lexical(
564 cx, GlobalLexicalEnvironmentObject::create(cx, global));
565 if (!lexical) {
566 return nullptr;
567 }
568 global->data().lexicalEnvironment.init(lexical);
569
570 Rooted<GlobalScope*> emptyGlobalScope(
571 cx, GlobalScope::createEmpty(cx, ScopeKind::Global));
572 if (!emptyGlobalScope) {
573 return nullptr;
574 }
575 global->data().emptyGlobalScope.init(emptyGlobalScope);
576
577 if (!JSObject::setQualifiedVarObj(cx, global)) {
578 return nullptr;
579 }
580
581 return global;
582 }
583
584 /* static */
new_(JSContext * cx,const JSClass * clasp,JSPrincipals * principals,JS::OnNewGlobalHookOption hookOption,const JS::RealmOptions & options)585 GlobalObject* GlobalObject::new_(JSContext* cx, const JSClass* clasp,
586 JSPrincipals* principals,
587 JS::OnNewGlobalHookOption hookOption,
588 const JS::RealmOptions& options) {
589 MOZ_ASSERT(!cx->isExceptionPending());
590 MOZ_ASSERT_IF(cx->zone(), !cx->zone()->isAtomsZone());
591
592 // If we are creating a new global in an existing compartment, make sure the
593 // compartment has a live global at all times (by rooting it here).
594 // See bug 1530364.
595 Rooted<GlobalObject*> existingGlobal(cx);
596 const JS::RealmCreationOptions& creationOptions = options.creationOptions();
597 if (creationOptions.compartmentSpecifier() ==
598 JS::CompartmentSpecifier::ExistingCompartment) {
599 Compartment* comp = creationOptions.compartment();
600 existingGlobal = &comp->firstGlobal();
601 }
602
603 Realm* realm = NewRealm(cx, principals, options);
604 if (!realm) {
605 return nullptr;
606 }
607
608 Rooted<GlobalObject*> global(cx);
609 {
610 AutoRealmUnchecked ar(cx, realm);
611 global = GlobalObject::createInternal(cx, clasp);
612 if (!global) {
613 return nullptr;
614 }
615
616 if (hookOption == JS::FireOnNewGlobalHook) {
617 JS_FireOnNewGlobalObject(cx, global);
618 }
619 }
620
621 return global;
622 }
623
emptyGlobalScope() const624 GlobalScope& GlobalObject::emptyGlobalScope() const {
625 return *data().emptyGlobalScope;
626 }
627
628 /* static */
getOrCreateEval(JSContext * cx,Handle<GlobalObject * > global,MutableHandleObject eval)629 bool GlobalObject::getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
630 MutableHandleObject eval) {
631 if (!getOrCreateObjectPrototype(cx, global)) {
632 return false;
633 }
634 eval.set(global->data().eval);
635 MOZ_ASSERT(eval);
636 return true;
637 }
638
valueIsEval(const Value & val)639 bool GlobalObject::valueIsEval(const Value& val) {
640 return val.isObject() && data().eval == &val.toObject();
641 }
642
643 /* static */
initStandardClasses(JSContext * cx,Handle<GlobalObject * > global)644 bool GlobalObject::initStandardClasses(JSContext* cx,
645 Handle<GlobalObject*> global) {
646 /* Define a top-level property 'undefined' with the undefined value. */
647 if (!DefineDataProperty(
648 cx, global, cx->names().undefined, UndefinedHandleValue,
649 JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING)) {
650 return false;
651 }
652
653 // Resolve a "globalThis" self-referential property if necessary.
654 bool resolved;
655 if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) {
656 return false;
657 }
658
659 for (size_t k = 0; k < JSProto_LIMIT; ++k) {
660 JSProtoKey key = static_cast<JSProtoKey>(k);
661 if (key != JSProto_Null && !global->isStandardClassResolved(key)) {
662 if (!resolveConstructor(cx, global, static_cast<JSProtoKey>(k),
663 IfClassIsDisabled::DoNothing)) {
664 return false;
665 }
666 }
667 }
668 return true;
669 }
670
671 /* static */
isRuntimeCodeGenEnabled(JSContext * cx,HandleString code,Handle<GlobalObject * > global)672 bool GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, HandleString code,
673 Handle<GlobalObject*> global) {
674 // If there are callbacks, make sure that the CSP callback is installed
675 // and that it permits runtime code generation.
676 JSCSPEvalChecker allows =
677 cx->runtime()->securityCallbacks->contentSecurityPolicyAllows;
678 if (allows) {
679 return allows(cx, code);
680 }
681
682 return true;
683 }
684
685 /* static */
createConstructor(JSContext * cx,Native ctor,JSAtom * nameArg,unsigned length,gc::AllocKind kind,const JSJitInfo * jitInfo)686 JSFunction* GlobalObject::createConstructor(JSContext* cx, Native ctor,
687 JSAtom* nameArg, unsigned length,
688 gc::AllocKind kind,
689 const JSJitInfo* jitInfo) {
690 RootedAtom name(cx, nameArg);
691 JSFunction* fun = NewNativeConstructor(cx, ctor, length, name, kind);
692 if (!fun) {
693 return nullptr;
694 }
695
696 if (jitInfo) {
697 fun->setJitInfo(jitInfo);
698 }
699
700 return fun;
701 }
702
CreateBlankProto(JSContext * cx,const JSClass * clasp,HandleObject proto)703 static NativeObject* CreateBlankProto(JSContext* cx, const JSClass* clasp,
704 HandleObject proto) {
705 MOZ_ASSERT(!clasp->isJSFunction());
706
707 if (clasp == &PlainObject::class_) {
708 return NewPlainObjectWithProto(cx, proto, TenuredObject);
709 }
710
711 return NewTenuredObjectWithGivenProto(cx, clasp, proto);
712 }
713
714 /* static */
createBlankPrototype(JSContext * cx,Handle<GlobalObject * > global,const JSClass * clasp)715 NativeObject* GlobalObject::createBlankPrototype(JSContext* cx,
716 Handle<GlobalObject*> global,
717 const JSClass* clasp) {
718 RootedObject objectProto(cx, getOrCreateObjectPrototype(cx, global));
719 if (!objectProto) {
720 return nullptr;
721 }
722
723 return CreateBlankProto(cx, clasp, objectProto);
724 }
725
726 /* static */
createBlankPrototypeInheriting(JSContext * cx,const JSClass * clasp,HandleObject proto)727 NativeObject* GlobalObject::createBlankPrototypeInheriting(JSContext* cx,
728 const JSClass* clasp,
729 HandleObject proto) {
730 return CreateBlankProto(cx, clasp, proto);
731 }
732
LinkConstructorAndPrototype(JSContext * cx,JSObject * ctor_,JSObject * proto_,unsigned prototypeAttrs,unsigned constructorAttrs)733 bool js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_,
734 JSObject* proto_, unsigned prototypeAttrs,
735 unsigned constructorAttrs) {
736 RootedObject ctor(cx, ctor_), proto(cx, proto_);
737
738 RootedValue protoVal(cx, ObjectValue(*proto));
739 RootedValue ctorVal(cx, ObjectValue(*ctor));
740
741 return DefineDataProperty(cx, ctor, cx->names().prototype, protoVal,
742 prototypeAttrs) &&
743 DefineDataProperty(cx, proto, cx->names().constructor, ctorVal,
744 constructorAttrs);
745 }
746
DefinePropertiesAndFunctions(JSContext * cx,HandleObject obj,const JSPropertySpec * ps,const JSFunctionSpec * fs)747 bool js::DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
748 const JSPropertySpec* ps,
749 const JSFunctionSpec* fs) {
750 if (ps && !JS_DefineProperties(cx, obj, ps)) {
751 return false;
752 }
753 if (fs && !JS_DefineFunctions(cx, obj, fs)) {
754 return false;
755 }
756 return true;
757 }
758
DefineToStringTag(JSContext * cx,HandleObject obj,JSAtom * tag)759 bool js::DefineToStringTag(JSContext* cx, HandleObject obj, JSAtom* tag) {
760 RootedId toStringTagId(
761 cx, PropertyKey::Symbol(cx->wellKnownSymbols().toStringTag));
762 RootedValue tagString(cx, StringValue(tag));
763 return DefineDataProperty(cx, obj, toStringTagId, tagString, JSPROP_READONLY);
764 }
765
766 /* static */
getOrCreateForOfPICObject(JSContext * cx,Handle<GlobalObject * > global)767 NativeObject* GlobalObject::getOrCreateForOfPICObject(
768 JSContext* cx, Handle<GlobalObject*> global) {
769 cx->check(global);
770 NativeObject* forOfPIC = global->getForOfPICObject();
771 if (forOfPIC) {
772 return forOfPIC;
773 }
774
775 forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
776 if (!forOfPIC) {
777 return nullptr;
778 }
779 global->data().forOfPICChain.init(forOfPIC);
780 return forOfPIC;
781 }
782
783 /* static */
getOrCreateRealmKeyObject(JSContext * cx,Handle<GlobalObject * > global)784 JSObject* GlobalObject::getOrCreateRealmKeyObject(
785 JSContext* cx, Handle<GlobalObject*> global) {
786 cx->check(global);
787 if (PlainObject* key = global->data().realmKeyObject) {
788 return key;
789 }
790
791 PlainObject* key = NewPlainObject(cx);
792 if (!key) {
793 return nullptr;
794 }
795
796 global->data().realmKeyObject.init(key);
797 return key;
798 }
799
800 /* static */
getRegExpStatics(JSContext * cx,Handle<GlobalObject * > global)801 RegExpStatics* GlobalObject::getRegExpStatics(JSContext* cx,
802 Handle<GlobalObject*> global) {
803 MOZ_ASSERT(cx);
804
805 if (!global->data().regExpStatics) {
806 auto statics = RegExpStatics::create(cx);
807 if (!statics) {
808 return nullptr;
809 }
810 global->data().regExpStatics = std::move(statics);
811 }
812
813 return global->data().regExpStatics.get();
814 }
815
816 gc::FinalizationRegistryGlobalData*
getOrCreateFinalizationRegistryData()817 GlobalObject::getOrCreateFinalizationRegistryData() {
818 if (!data().finalizationRegistryData) {
819 data().finalizationRegistryData =
820 MakeUnique<gc::FinalizationRegistryGlobalData>(zone());
821 }
822
823 return maybeFinalizationRegistryData();
824 }
825
addToVarNames(JSContext * cx,JS::Handle<JSAtom * > name)826 bool GlobalObject::addToVarNames(JSContext* cx, JS::Handle<JSAtom*> name) {
827 MOZ_ASSERT(name);
828
829 if (!data().varNames.put(name)) {
830 ReportOutOfMemory(cx);
831 return false;
832 }
833
834 return true;
835 }
836
837 /* static */
getIntrinsicsHolder(JSContext * cx,Handle<GlobalObject * > global)838 NativeObject* GlobalObject::getIntrinsicsHolder(JSContext* cx,
839 Handle<GlobalObject*> global) {
840 if (NativeObject* holder = global->data().intrinsicsHolder) {
841 return holder;
842 }
843
844 Rooted<NativeObject*> intrinsicsHolder(
845 cx, NewPlainObjectWithProto(cx, nullptr, TenuredObject));
846 if (!intrinsicsHolder) {
847 return nullptr;
848 }
849
850 // Define a top-level property 'undefined' with the undefined value.
851 if (!DefineDataProperty(cx, intrinsicsHolder, cx->names().undefined,
852 UndefinedHandleValue,
853 JSPROP_PERMANENT | JSPROP_READONLY)) {
854 return nullptr;
855 }
856
857 // Install the intrinsics holder on the global.
858 global->data().intrinsicsHolder.init(intrinsicsHolder);
859 return intrinsicsHolder;
860 }
861
862 /* static */
getSelfHostedFunction(JSContext * cx,Handle<GlobalObject * > global,HandlePropertyName selfHostedName,HandleAtom name,unsigned nargs,MutableHandleValue funVal)863 bool GlobalObject::getSelfHostedFunction(JSContext* cx,
864 Handle<GlobalObject*> global,
865 HandlePropertyName selfHostedName,
866 HandleAtom name, unsigned nargs,
867 MutableHandleValue funVal) {
868 bool exists = false;
869 if (!GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal,
870 &exists)) {
871 return false;
872 }
873 if (exists) {
874 RootedFunction fun(cx, &funVal.toObject().as<JSFunction>());
875 if (fun->explicitName() == name) {
876 return true;
877 }
878
879 if (fun->explicitName() == selfHostedName) {
880 // This function was initially cloned because it was called by
881 // other self-hosted code, so the clone kept its self-hosted name,
882 // instead of getting the name it's intended to have in content
883 // compartments. This can happen when a lazy builtin is initialized
884 // after self-hosted code for another builtin used the same
885 // function. In that case, we need to change the function's name,
886 // which is ok because it can't have been exposed to content
887 // before.
888 fun->setAtom(name);
889 return true;
890 }
891
892 // The function might be installed multiple times on the same or
893 // different builtins, under different property names, so its name
894 // might be neither "selfHostedName" nor "name". In that case, its
895 // canonical name must've been set using the `_SetCanonicalName`
896 // intrinsic.
897 cx->runtime()->assertSelfHostedFunctionHasCanonicalName(selfHostedName);
898 return true;
899 }
900
901 JSRuntime* runtime = cx->runtime();
902 frontend::ScriptIndex index =
903 runtime->getSelfHostedScriptIndexRange(selfHostedName)->start;
904 JSFunction* fun =
905 runtime->selfHostStencil().instantiateSelfHostedLazyFunction(
906 cx, runtime->selfHostStencilInput().atomCache, index, name);
907 if (!fun) {
908 return false;
909 }
910 MOZ_ASSERT(fun->nargs() == nargs);
911 funVal.setObject(*fun);
912
913 return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
914 }
915
916 /* static */
getIntrinsicValueSlow(JSContext * cx,Handle<GlobalObject * > global,HandlePropertyName name,MutableHandleValue value)917 bool GlobalObject::getIntrinsicValueSlow(JSContext* cx,
918 Handle<GlobalObject*> global,
919 HandlePropertyName name,
920 MutableHandleValue value) {
921 // If this is a C++ intrinsic, simply define the function on the intrinsics
922 // holder.
923 if (const JSFunctionSpec* spec = js::FindIntrinsicSpec(name)) {
924 RootedNativeObject holder(cx,
925 GlobalObject::getIntrinsicsHolder(cx, global));
926 if (!holder) {
927 return false;
928 }
929
930 RootedId id(cx, NameToId(name));
931 RootedFunction fun(cx, JS::NewFunctionFromSpec(cx, spec, id));
932 if (!fun) {
933 return false;
934 }
935 fun->setIsIntrinsic();
936
937 value.setObject(*fun);
938 return GlobalObject::addIntrinsicValue(cx, global, name, value);
939 }
940
941 if (!cx->runtime()->getSelfHostedValue(cx, name, value)) {
942 return false;
943 }
944
945 // It's possible in certain edge cases that cloning the value ended up
946 // defining the intrinsic. For instance, cloning can call NewArray, which
947 // resolves Array.prototype, which defines some self-hosted functions. If this
948 // happens we use the value already defined on the intrinsics holder.
949 bool exists = false;
950 if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value, &exists)) {
951 return false;
952 }
953 if (exists) {
954 return true;
955 }
956
957 return GlobalObject::addIntrinsicValue(cx, global, name, value);
958 }
959
960 /* static */
addIntrinsicValue(JSContext * cx,Handle<GlobalObject * > global,HandlePropertyName name,HandleValue value)961 bool GlobalObject::addIntrinsicValue(JSContext* cx,
962 Handle<GlobalObject*> global,
963 HandlePropertyName name,
964 HandleValue value) {
965 RootedNativeObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
966 if (!holder) {
967 return false;
968 }
969
970 RootedId id(cx, NameToId(name));
971 MOZ_ASSERT(!holder->containsPure(id));
972
973 constexpr PropertyFlags propFlags = {PropertyFlag::Configurable,
974 PropertyFlag::Writable};
975 uint32_t slot;
976 if (!NativeObject::addProperty(cx, holder, id, propFlags, &slot)) {
977 return false;
978 }
979 holder->initSlot(slot, value);
980 return true;
981 }
982
983 /* static */
ensureModulePrototypesCreated(JSContext * cx,Handle<GlobalObject * > global)984 bool GlobalObject::ensureModulePrototypesCreated(JSContext* cx,
985 Handle<GlobalObject*> global) {
986 return getOrCreateModulePrototype(cx, global) &&
987 getOrCreateImportEntryPrototype(cx, global) &&
988 getOrCreateExportEntryPrototype(cx, global) &&
989 getOrCreateRequestedModulePrototype(cx, global);
990 }
991
992 /* static */
createIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)993 JSObject* GlobalObject::createIteratorPrototype(JSContext* cx,
994 Handle<GlobalObject*> global) {
995 if (!cx->realm()->creationOptions().getIteratorHelpersEnabled()) {
996 return getOrCreateBuiltinProto(cx, global, ProtoKind::IteratorProto,
997 initIteratorProto);
998 }
999
1000 if (!ensureConstructor(cx, global, JSProto_Iterator)) {
1001 return nullptr;
1002 }
1003 JSObject* proto = &global->getPrototype(JSProto_Iterator);
1004 global->initBuiltinProto(ProtoKind::IteratorProto, proto);
1005 return proto;
1006 }
1007
1008 /* static */
createAsyncIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)1009 JSObject* GlobalObject::createAsyncIteratorPrototype(
1010 JSContext* cx, Handle<GlobalObject*> global) {
1011 if (!cx->realm()->creationOptions().getIteratorHelpersEnabled()) {
1012 return getOrCreateBuiltinProto(cx, global, ProtoKind::AsyncIteratorProto,
1013 initAsyncIteratorProto);
1014 }
1015
1016 if (!ensureConstructor(cx, global, JSProto_AsyncIterator)) {
1017 return nullptr;
1018 }
1019 JSObject* proto = &global->getPrototype(JSProto_AsyncIterator);
1020 global->initBuiltinProto(ProtoKind::AsyncIteratorProto, proto);
1021 return proto;
1022 }
1023
releaseData(JSFreeOp * fop)1024 void GlobalObject::releaseData(JSFreeOp* fop) {
1025 GlobalObjectData* data = maybeData();
1026 setReservedSlot(GLOBAL_DATA_SLOT, PrivateValue(nullptr));
1027 fop->delete_(this, data, MemoryUse::GlobalObjectData);
1028 }
1029
GlobalObjectData(Zone * zone)1030 GlobalObjectData::GlobalObjectData(Zone* zone) : varNames(zone) {}
1031
trace(JSTracer * trc,GlobalObject * global)1032 void GlobalObjectData::trace(JSTracer* trc, GlobalObject* global) {
1033 // Atoms are always tenured.
1034 if (!JS::RuntimeHeapIsMinorCollecting()) {
1035 varNames.trace(trc);
1036 }
1037
1038 for (auto& ctorWithProto : builtinConstructors) {
1039 TraceNullableEdge(trc, &ctorWithProto.constructor, "global-builtin-ctor");
1040 TraceNullableEdge(trc, &ctorWithProto.prototype,
1041 "global-builtin-ctor-proto");
1042 }
1043
1044 for (auto& proto : builtinProtos) {
1045 TraceNullableEdge(trc, &proto, "global-builtin-proto");
1046 }
1047
1048 TraceNullableEdge(trc, &emptyGlobalScope, "global-empty-scope");
1049
1050 TraceNullableEdge(trc, &lexicalEnvironment, "global-lexical-env");
1051 TraceNullableEdge(trc, &windowProxy, "global-window-proxy");
1052 TraceNullableEdge(trc, &intrinsicsHolder, "global-intrinsics-holder");
1053 TraceNullableEdge(trc, &computedIntrinsicsHolder,
1054 "global-computed-intrinsics-holder");
1055 TraceNullableEdge(trc, &forOfPICChain, "global-for-of-pic");
1056 TraceNullableEdge(trc, &sourceURLsHolder, "global-source-urls");
1057 TraceNullableEdge(trc, &realmKeyObject, "global-realm-key");
1058 TraceNullableEdge(trc, &throwTypeError, "global-throw-type-error");
1059 TraceNullableEdge(trc, &eval, "global-eval");
1060 TraceNullableEdge(trc, &emptyIterator, "global-empty-iterator");
1061
1062 TraceNullableEdge(trc, &arrayShapeWithDefaultProto, "global-array-shape");
1063
1064 for (auto& shape : plainObjectShapesWithDefaultProto) {
1065 TraceNullableEdge(trc, &shape, "global-plain-shape");
1066 }
1067
1068 TraceNullableEdge(trc, &functionShapeWithDefaultProto,
1069 "global-function-shape");
1070 TraceNullableEdge(trc, &extendedFunctionShapeWithDefaultProto,
1071 "global-ext-function-shape");
1072
1073 if (regExpStatics) {
1074 regExpStatics->trace(trc);
1075 }
1076
1077 TraceNullableEdge(trc, &mappedArgumentsTemplate, "mapped-arguments-template");
1078 TraceNullableEdge(trc, &unmappedArgumentsTemplate,
1079 "unmapped-arguments-template");
1080
1081 TraceNullableEdge(trc, &iterResultTemplate, "iter-result-template_");
1082 TraceNullableEdge(trc, &iterResultWithoutPrototypeTemplate,
1083 "iter-result-without-prototype-template");
1084
1085 TraceNullableEdge(trc, &selfHostingScriptSource,
1086 "self-hosting-script-source");
1087
1088 if (finalizationRegistryData) {
1089 finalizationRegistryData->trace(trc);
1090 }
1091 }
1092
addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,JS::ClassInfo * info) const1093 void GlobalObjectData::addSizeOfIncludingThis(
1094 mozilla::MallocSizeOf mallocSizeOf, JS::ClassInfo* info) const {
1095 info->objectsMallocHeapGlobalData += mallocSizeOf(this);
1096
1097 if (regExpStatics) {
1098 info->objectsMallocHeapGlobalData +=
1099 regExpStatics->sizeOfIncludingThis(mallocSizeOf);
1100 }
1101
1102 info->objectsMallocHeapGlobalVarNamesSet +=
1103 varNames.shallowSizeOfExcludingThis(mallocSizeOf);
1104 }
1105