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