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 "jsdate.h"
10 #include "jsexn.h"
11 #include "jsfriendapi.h"
12 
13 #include "builtin/AtomicsObject.h"
14 #include "builtin/BigInt.h"
15 #include "builtin/DataViewObject.h"
16 #include "builtin/Eval.h"
17 #ifdef JS_HAS_INTL_API
18 #  include "builtin/intl/Collator.h"
19 #  include "builtin/intl/DateTimeFormat.h"
20 #  include "builtin/intl/DisplayNames.h"
21 #  include "builtin/intl/ListFormat.h"
22 #  include "builtin/intl/Locale.h"
23 #  include "builtin/intl/NumberFormat.h"
24 #  include "builtin/intl/PluralRules.h"
25 #  include "builtin/intl/RelativeTimeFormat.h"
26 #endif
27 #include "builtin/FinalizationRegistryObject.h"
28 #include "builtin/MapObject.h"
29 #include "builtin/ModuleObject.h"
30 #include "builtin/Object.h"
31 #include "builtin/RegExp.h"
32 #include "builtin/SelfHostingDefines.h"
33 #include "builtin/Stream.h"
34 #include "builtin/streams/QueueingStrategies.h"  // js::{ByteLength,Count}QueueingStrategy
35 #include "builtin/streams/ReadableStream.h"  // js::ReadableStream
36 #include "builtin/streams/ReadableStreamController.h"  // js::Readable{StreamDefault,ByteStream}Controller
37 #include "builtin/streams/ReadableStreamReader.h"  // js::ReadableStreamDefaultReader
38 #include "builtin/streams/WritableStream.h"        // js::WritableStream
39 #include "builtin/streams/WritableStreamDefaultController.h"  // js::WritableStreamDefaultController
40 #include "builtin/streams/WritableStreamDefaultWriter.h"  // js::WritableStreamDefaultWriter
41 #include "builtin/Symbol.h"
42 #include "builtin/WeakMapObject.h"
43 #include "builtin/WeakRefObject.h"
44 #include "builtin/WeakSetObject.h"
45 #include "debugger/DebugAPI.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/OffThreadScriptCompilation.h"  // js::UseOffThreadParseGlobal
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/RegExpStaticsObject.h"
64 #include "vm/StringObject.h"
65 
66 #include "gc/FreeOp-inl.h"
67 #include "vm/JSObject-inl.h"
68 #include "vm/JSScript-inl.h"
69 #include "vm/NativeObject-inl.h"
70 #include "vm/Realm-inl.h"
71 
72 using namespace js;
73 
74 namespace js {
75 
76 extern const JSClass IntlClass;
77 extern const JSClass JSONClass;
78 extern const JSClass MathClass;
79 extern const JSClass ReflectClass;
80 
81 }  // namespace js
82 
83 static const JSClass* const protoTable[JSProto_LIMIT] = {
84 #define INIT_FUNC(name, clasp) clasp,
85 #define INIT_FUNC_DUMMY(name, clasp) nullptr,
86     JS_FOR_PROTOTYPES(INIT_FUNC, INIT_FUNC_DUMMY)
87 #undef INIT_FUNC_DUMMY
88 #undef INIT_FUNC
89 };
90 
ProtoKeyToClass(JSProtoKey key)91 JS_PUBLIC_API const JSClass* js::ProtoKeyToClass(JSProtoKey key) {
92   MOZ_ASSERT(key < JSProto_LIMIT);
93   return protoTable[key];
94 }
95 
96 /* static */
skipDeselectedConstructor(JSContext * cx,JSProtoKey key)97 bool GlobalObject::skipDeselectedConstructor(JSContext* cx, JSProtoKey key) {
98   switch (key) {
99     case JSProto_Null:
100     case JSProto_Object:
101     case JSProto_Function:
102     case JSProto_Array:
103     case JSProto_Boolean:
104     case JSProto_JSON:
105     case JSProto_Date:
106     case JSProto_Math:
107     case JSProto_Number:
108     case JSProto_String:
109     case JSProto_RegExp:
110     case JSProto_Error:
111     case JSProto_InternalError:
112     case JSProto_AggregateError:
113     case JSProto_EvalError:
114     case JSProto_RangeError:
115     case JSProto_ReferenceError:
116     case JSProto_SyntaxError:
117     case JSProto_TypeError:
118     case JSProto_URIError:
119     case JSProto_DebuggeeWouldRun:
120     case JSProto_CompileError:
121     case JSProto_LinkError:
122     case JSProto_RuntimeError:
123     case JSProto_ArrayBuffer:
124     case JSProto_Int8Array:
125     case JSProto_Uint8Array:
126     case JSProto_Int16Array:
127     case JSProto_Uint16Array:
128     case JSProto_Int32Array:
129     case JSProto_Uint32Array:
130     case JSProto_Float32Array:
131     case JSProto_Float64Array:
132     case JSProto_Uint8ClampedArray:
133     case JSProto_BigInt64Array:
134     case JSProto_BigUint64Array:
135     case JSProto_BigInt:
136     case JSProto_Proxy:
137     case JSProto_WeakMap:
138     case JSProto_Map:
139     case JSProto_Set:
140     case JSProto_DataView:
141     case JSProto_Symbol:
142     case JSProto_Reflect:
143     case JSProto_WeakSet:
144     case JSProto_TypedArray:
145     case JSProto_SavedFrame:
146     case JSProto_Promise:
147     case JSProto_AsyncFunction:
148     case JSProto_GeneratorFunction:
149     case JSProto_AsyncGeneratorFunction:
150       return false;
151 
152     case JSProto_WebAssembly:
153       return !wasm::HasSupport(cx);
154 
155     case JSProto_WasmModule:
156     case JSProto_WasmInstance:
157     case JSProto_WasmMemory:
158     case JSProto_WasmTable:
159     case JSProto_WasmGlobal:
160     case JSProto_WasmException:
161     case JSProto_WasmRuntimeException:
162       return false;
163 
164 #ifdef JS_HAS_INTL_API
165     case JSProto_Intl:
166     case JSProto_Collator:
167     case JSProto_DateTimeFormat:
168     case JSProto_DisplayNames:
169     case JSProto_Locale:
170     case JSProto_ListFormat:
171     case JSProto_NumberFormat:
172     case JSProto_PluralRules:
173     case JSProto_RelativeTimeFormat:
174       return false;
175 #endif
176 
177     case JSProto_ReadableStream:
178     case JSProto_ReadableStreamDefaultReader:
179     case JSProto_ReadableStreamDefaultController:
180     case JSProto_ReadableByteStreamController:
181     case JSProto_ByteLengthQueuingStrategy:
182     case JSProto_CountQueuingStrategy:
183       return !cx->realm()->creationOptions().getStreamsEnabled();
184 
185     case JSProto_WritableStream:
186     case JSProto_WritableStreamDefaultController:
187     case JSProto_WritableStreamDefaultWriter: {
188       const auto& realmOptions = cx->realm()->creationOptions();
189       return !realmOptions.getStreamsEnabled() ||
190              !realmOptions.getWritableStreamsEnabled();
191     }
192 
193     // Return true if the given constructor has been disabled at run-time.
194     case JSProto_Atomics:
195     case JSProto_SharedArrayBuffer:
196       return !cx->realm()->creationOptions().getSharedMemoryAndAtomicsEnabled();
197 
198     case JSProto_WeakRef:
199     case JSProto_FinalizationRegistry:
200       return cx->realm()->creationOptions().getWeakRefsEnabled() ==
201              JS::WeakRefSpecifier::Disabled;
202 
203     case JSProto_Iterator:
204     case JSProto_AsyncIterator:
205       return !cx->realm()->creationOptions().getIteratorHelpersEnabled();
206 
207     default:
208       MOZ_CRASH("unexpected JSProtoKey");
209   }
210 }
211 
212 /* static*/
resolveConstructor(JSContext * cx,Handle<GlobalObject * > global,JSProtoKey key,IfClassIsDisabled mode)213 bool GlobalObject::resolveConstructor(JSContext* cx,
214                                       Handle<GlobalObject*> global,
215                                       JSProtoKey key, IfClassIsDisabled mode) {
216   MOZ_ASSERT(key != JSProto_Null);
217   MOZ_ASSERT(!global->isStandardClassResolved(key));
218   MOZ_ASSERT(cx->compartment() == global->compartment());
219 
220   // |global| must be same-compartment but make sure we're in its realm: the
221   // code below relies on this.
222   AutoRealm ar(cx, global);
223 
224   if (global->zone()->createdForHelperThread()) {
225     return resolveOffThreadConstructor(cx, global, key);
226   }
227 
228   MOZ_ASSERT(!cx->isHelperThreadContext());
229 
230   // Prohibit collection of allocation metadata. Metadata builders shouldn't
231   // need to observe lazily-constructed prototype objects coming into
232   // existence. And assertions start to fail when the builder itself attempts
233   // an allocation that re-entrantly tries to create the same prototype.
234   AutoSuppressAllocationMetadataBuilder suppressMetadata(cx);
235 
236   // Constructor resolution may execute self-hosted scripts. These
237   // self-hosted scripts do not call out to user code by construction. Allow
238   // all scripts to execute, even in debuggee compartments that are paused.
239   AutoSuppressDebuggeeNoExecuteChecks suppressNX(cx);
240 
241   // Some classes can be disabled at compile time, others at run time;
242   // if a feature is compile-time disabled, clasp is null.
243   const JSClass* clasp = ProtoKeyToClass(key);
244   if (!clasp || skipDeselectedConstructor(cx, key)) {
245     if (mode == IfClassIsDisabled::Throw) {
246       JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
247                                 JSMSG_CONSTRUCTOR_DISABLED,
248                                 clasp ? clasp->name : "constructor");
249       return false;
250     }
251     return true;
252   }
253 
254   // Class spec must have a constructor defined.
255   if (!clasp->specDefined()) {
256     return true;
257   }
258 
259   bool isObjectOrFunction = key == JSProto_Function || key == JSProto_Object;
260 
261   // We need to create the prototype first, and immediately stash it in the
262   // slot. This is so the following bootstrap ordering is possible:
263   // * Object.prototype
264   // * Function.prototype
265   // * Function
266   // * Object
267   //
268   // We get the above when Object is resolved before Function. If Function
269   // is resolved before Object, we'll end up re-entering resolveConstructor
270   // for Function, which is a problem. So if Function is being resolved
271   // before Object.prototype exists, we just resolve Object instead, since we
272   // know that Function will also be resolved before we return.
273   if (key == JSProto_Function &&
274       global->getPrototype(JSProto_Object).isUndefined()) {
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->getSlotRef(ITERATOR_PROTO).isObject()) {
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, ObjectValue(*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, ObjectValue(*ctor));
335   }
336 
337   // If we're operating on the self-hosting global, we don't want any
338   // functions and properties on the builtins and their prototypes.
339   if (!cx->runtime()->isSelfHostingGlobal(global)) {
340     if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
341       if (!JS_DefineFunctions(cx, proto, funs)) {
342         return false;
343       }
344     }
345     if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
346       if (!JS_DefineProperties(cx, proto, props)) {
347         return false;
348       }
349     }
350     if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
351       if (!JS_DefineFunctions(cx, ctor, funs)) {
352         return false;
353       }
354     }
355     if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
356       if (!JS_DefineProperties(cx, ctor, props)) {
357         return false;
358       }
359     }
360   }
361 
362   // If the prototype exists, link it with the constructor.
363   if (proto && !LinkConstructorAndPrototype(cx, ctor, proto)) {
364     return false;
365   }
366 
367   // Call the post-initialization hook, if provided.
368   if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
369     if (!finishInit(cx, ctor, proto)) {
370       return false;
371     }
372   }
373 
374   if (!isObjectOrFunction) {
375     // Any operations that modifies the global object should be placed
376     // after any other fallible operations.
377 
378     // Fallible operation that modifies the global object.
379     if (clasp->specShouldDefineConstructor()) {
380       bool shouldReallyDefine = true;
381 
382       // On the web, it isn't presently possible to expose the global
383       // "SharedArrayBuffer" property unless the page is cross-site-isolated.
384       // Only define this constructor if an option on the realm indicates that
385       // it should be defined.
386       if (key == JSProto_SharedArrayBuffer) {
387         const JS::RealmCreationOptions& options =
388             global->realm()->creationOptions();
389 
390         MOZ_ASSERT(options.getSharedMemoryAndAtomicsEnabled(),
391                    "shouldn't be defining SharedArrayBuffer if shared memory "
392                    "is disabled");
393 
394         shouldReallyDefine = options.defineSharedArrayBufferConstructor();
395       }
396 
397       if (shouldReallyDefine) {
398         RootedValue ctorValue(cx, ObjectValue(*ctor));
399         if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
400           return false;
401         }
402       }
403     }
404 
405     // Infallible operations that modify the global object.
406     global->setConstructor(key, ObjectValue(*ctor));
407     if (proto) {
408       global->setPrototype(key, ObjectValue(*proto));
409     }
410   }
411 
412   return true;
413 }
414 
415 // Resolve a "globalThis" self-referential property if necessary,
416 // per a stage-3 proposal. https://github.com/tc39/ecma262/pull/702
417 //
418 // We could also do this in |FinishObjectClassInit| to trim the global
419 // resolve hook.  Unfortunately, |ToWindowProxyIfWindow| doesn't work then:
420 // the browser's |nsGlobalWindow::SetNewDocument| invokes Object init
421 // *before* it sets the global's WindowProxy using |js::SetWindowProxy|.
422 //
423 // Refactoring global object creation code to support this approach is a
424 // challenge for another day.
425 /* static */
maybeResolveGlobalThis(JSContext * cx,Handle<GlobalObject * > global,bool * resolved)426 bool GlobalObject::maybeResolveGlobalThis(JSContext* cx,
427                                           Handle<GlobalObject*> global,
428                                           bool* resolved) {
429   if (global->getSlot(GLOBAL_THIS_RESOLVED).isUndefined()) {
430     RootedValue v(cx, ObjectValue(*ToWindowProxyIfWindow(global)));
431     if (!DefineDataProperty(cx, global, cx->names().globalThis, v,
432                             JSPROP_RESOLVING)) {
433       return false;
434     }
435 
436     *resolved = true;
437     global->setSlot(GLOBAL_THIS_RESOLVED, BooleanValue(true));
438   }
439 
440   return true;
441 }
442 
443 /* static */
createObject(JSContext * cx,Handle<GlobalObject * > global,unsigned slot,ObjectInitOp init)444 JSObject* GlobalObject::createObject(JSContext* cx,
445                                      Handle<GlobalObject*> global,
446                                      unsigned slot, ObjectInitOp init) {
447   if (global->zone()->createdForHelperThread()) {
448     return createOffThreadObject(cx, global, slot);
449   }
450 
451   MOZ_ASSERT(!cx->isHelperThreadContext());
452   if (!init(cx, global)) {
453     return nullptr;
454   }
455 
456   return &global->getSlot(slot).toObject();
457 }
458 
createObject(JSContext * cx,Handle<GlobalObject * > global,unsigned slot,HandleAtom tag,ObjectInitWithTagOp init)459 JSObject* GlobalObject::createObject(JSContext* cx,
460                                      Handle<GlobalObject*> global,
461                                      unsigned slot, HandleAtom tag,
462                                      ObjectInitWithTagOp init) {
463   if (global->zone()->createdForHelperThread()) {
464     return createOffThreadObject(cx, global, slot);
465   }
466 
467   MOZ_ASSERT(!cx->isHelperThreadContext());
468   if (!init(cx, global, tag)) {
469     return nullptr;
470   }
471 
472   return &global->getSlot(slot).toObject();
473 }
474 
475 const JSClass GlobalObject::OffThreadPlaceholderObject::class_ = {
476     "off-thread-prototype-placeholder", JSCLASS_HAS_RESERVED_SLOTS(1)};
477 
478 /* static */ GlobalObject::OffThreadPlaceholderObject*
New(JSContext * cx,unsigned slot)479 GlobalObject::OffThreadPlaceholderObject::New(JSContext* cx, unsigned slot) {
480   Rooted<OffThreadPlaceholderObject*> placeholder(cx);
481   placeholder =
482       NewObjectWithGivenProto<OffThreadPlaceholderObject>(cx, nullptr);
483   if (!placeholder) {
484     return nullptr;
485   }
486 
487   placeholder->setReservedSlot(SlotIndexSlot, Int32Value(slot));
488   return placeholder;
489 }
490 
getSlotIndex() const491 inline int32_t GlobalObject::OffThreadPlaceholderObject::getSlotIndex() const {
492   return getReservedSlot(SlotIndexSlot).toInt32();
493 }
494 
495 /* static */
resolveOffThreadConstructor(JSContext * cx,Handle<GlobalObject * > global,JSProtoKey key)496 bool GlobalObject::resolveOffThreadConstructor(JSContext* cx,
497                                                Handle<GlobalObject*> global,
498                                                JSProtoKey key) {
499   // Don't resolve constructors for off-thread parse globals. Instead create a
500   // placeholder object for the prototype which we can use to find the real
501   // prototype when the off-thread compartment is merged back into the target
502   // compartment.
503 
504   MOZ_ASSERT(global->zone()->createdForHelperThread());
505   MOZ_ASSERT(key == JSProto_Object || key == JSProto_Function ||
506              key == JSProto_Array || key == JSProto_RegExp ||
507              key == JSProto_AsyncFunction || key == JSProto_GeneratorFunction ||
508              key == JSProto_AsyncGeneratorFunction);
509 
510   Rooted<OffThreadPlaceholderObject*> placeholder(cx);
511   placeholder = OffThreadPlaceholderObject::New(cx, prototypeSlot(key));
512   if (!placeholder) {
513     return false;
514   }
515 
516   if (key == JSProto_Object &&
517       !JSObject::setFlag(cx, placeholder, ObjectFlag::ImmutablePrototype)) {
518     return false;
519   }
520 
521   global->setPrototype(key, ObjectValue(*placeholder));
522   global->setConstructor(key, MagicValue(JS_OFF_THREAD_CONSTRUCTOR));
523   return true;
524 }
525 
526 /* static */
createOffThreadObject(JSContext * cx,Handle<GlobalObject * > global,unsigned slot)527 JSObject* GlobalObject::createOffThreadObject(JSContext* cx,
528                                               Handle<GlobalObject*> global,
529                                               unsigned slot) {
530   // Don't create prototype objects for off-thread parse globals. Instead
531   // create a placeholder object which we can use to find the real prototype
532   // when the off-thread compartment is merged back into the target
533   // compartment.
534 
535   MOZ_ASSERT(global->zone()->createdForHelperThread());
536   MOZ_ASSERT(slot == MODULE_PROTO || slot == IMPORT_ENTRY_PROTO ||
537              slot == EXPORT_ENTRY_PROTO || slot == REQUESTED_MODULE_PROTO);
538 
539   auto placeholder = OffThreadPlaceholderObject::New(cx, slot);
540   if (!placeholder) {
541     return nullptr;
542   }
543 
544   global->setSlot(slot, ObjectValue(*placeholder));
545   return placeholder;
546 }
547 
getPrototypeForOffThreadPlaceholder(JSObject * obj)548 JSObject* GlobalObject::getPrototypeForOffThreadPlaceholder(JSObject* obj) {
549   auto placeholder = &obj->as<OffThreadPlaceholderObject>();
550   return &getSlot(placeholder->getSlotIndex()).toObject();
551 }
552 
553 /* static */
initBuiltinConstructor(JSContext * cx,Handle<GlobalObject * > global,JSProtoKey key,HandleObject ctor,HandleObject proto)554 bool GlobalObject::initBuiltinConstructor(JSContext* cx,
555                                           Handle<GlobalObject*> global,
556                                           JSProtoKey key, HandleObject ctor,
557                                           HandleObject proto) {
558   MOZ_ASSERT(!global->empty());  // reserved slots already allocated
559   MOZ_ASSERT(key != JSProto_Null);
560   MOZ_ASSERT(ctor);
561   MOZ_ASSERT(proto);
562 
563   RootedId id(cx, NameToId(ClassName(key, cx)));
564   MOZ_ASSERT(!global->lookup(cx, id));
565 
566   RootedValue ctorValue(cx, ObjectValue(*ctor));
567   if (!DefineDataProperty(cx, global, id, ctorValue, JSPROP_RESOLVING)) {
568     return false;
569   }
570 
571   global->setConstructor(key, ObjectValue(*ctor));
572   global->setPrototype(key, ObjectValue(*proto));
573   return true;
574 }
575 
ThrowTypeError(JSContext * cx,unsigned argc,Value * vp)576 static bool ThrowTypeError(JSContext* cx, unsigned argc, Value* vp) {
577   ThrowTypeErrorBehavior(cx);
578   return false;
579 }
580 
581 /* static */
getOrCreateThrowTypeError(JSContext * cx,Handle<GlobalObject * > global)582 JSObject* GlobalObject::getOrCreateThrowTypeError(
583     JSContext* cx, Handle<GlobalObject*> global) {
584   Value v = global->getReservedSlot(THROWTYPEERROR);
585   if (v.isObject()) {
586     return &v.toObject();
587   }
588   MOZ_ASSERT(v.isUndefined());
589 
590   // Construct the unique [[%ThrowTypeError%]] function object, used only for
591   // "callee" and "caller" accessors on strict mode arguments objects.  (The
592   // spec also uses this for "arguments" and "caller" on various functions,
593   // but we're experimenting with implementing them using accessors on
594   // |Function.prototype| right now.)
595 
596   RootedFunction throwTypeError(
597       cx, NewNativeFunction(cx, ThrowTypeError, 0, nullptr));
598   if (!throwTypeError || !PreventExtensions(cx, throwTypeError)) {
599     return nullptr;
600   }
601 
602   // The "length" property of %ThrowTypeError% is non-configurable.
603   Rooted<PropertyDescriptor> nonConfigurableDesc(cx,
604                                                  PropertyDescriptor::Empty());
605   nonConfigurableDesc.setConfigurable(false);
606 
607   RootedId lengthId(cx, NameToId(cx->names().length));
608   ObjectOpResult lengthResult;
609   if (!NativeDefineProperty(cx, throwTypeError, lengthId, nonConfigurableDesc,
610                             lengthResult)) {
611     return nullptr;
612   }
613   MOZ_ASSERT(lengthResult);
614 
615   // The "name" property of %ThrowTypeError% is non-configurable, adjust
616   // the default property attributes accordingly.
617   RootedId nameId(cx, NameToId(cx->names().name));
618   ObjectOpResult nameResult;
619   if (!NativeDefineProperty(cx, throwTypeError, nameId, nonConfigurableDesc,
620                             nameResult)) {
621     return nullptr;
622   }
623   MOZ_ASSERT(nameResult);
624 
625   global->setReservedSlot(THROWTYPEERROR, ObjectValue(*throwTypeError));
626   return throwTypeError;
627 }
628 
createInternal(JSContext * cx,const JSClass * clasp)629 GlobalObject* GlobalObject::createInternal(JSContext* cx,
630                                            const JSClass* clasp) {
631   MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL);
632   MOZ_ASSERT(clasp->isTrace(JS_GlobalObjectTraceHook));
633 
634   JSObject* obj = NewTenuredObjectWithGivenProto(cx, clasp, nullptr);
635   if (!obj) {
636     return nullptr;
637   }
638 
639   Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
640   MOZ_ASSERT(global->isUnqualifiedVarObj());
641 
642   // Initialize the private slot to null if present, as GC can call class
643   // hooks before the caller gets to set this to a non-garbage value.
644   if (clasp->flags & JSCLASS_HAS_PRIVATE) {
645     global->setPrivate(nullptr);
646   }
647 
648   Rooted<GlobalLexicalEnvironmentObject*> lexical(
649       cx, GlobalLexicalEnvironmentObject::create(cx, global));
650   if (!lexical) {
651     return nullptr;
652   }
653 
654   Rooted<GlobalScope*> emptyGlobalScope(
655       cx, GlobalScope::createEmpty(cx, ScopeKind::Global));
656   if (!emptyGlobalScope) {
657     return nullptr;
658   }
659   global->setReservedSlot(EMPTY_GLOBAL_SCOPE,
660                           PrivateGCThingValue(emptyGlobalScope));
661 
662   cx->realm()->initGlobal(*global, *lexical);
663 
664   if (!JSObject::setQualifiedVarObj(cx, global)) {
665     return nullptr;
666   }
667 
668   return global;
669 }
670 
671 /* static */
new_(JSContext * cx,const JSClass * clasp,JSPrincipals * principals,JS::OnNewGlobalHookOption hookOption,const JS::RealmOptions & options)672 GlobalObject* GlobalObject::new_(JSContext* cx, const JSClass* clasp,
673                                  JSPrincipals* principals,
674                                  JS::OnNewGlobalHookOption hookOption,
675                                  const JS::RealmOptions& options) {
676   MOZ_ASSERT(!cx->isExceptionPending());
677   MOZ_ASSERT_IF(cx->zone(), !cx->zone()->isAtomsZone());
678 
679   // If we are creating a new global in an existing compartment, make sure the
680   // compartment has a live global at all times (by rooting it here).
681   // See bug 1530364.
682   Rooted<GlobalObject*> existingGlobal(cx);
683   const JS::RealmCreationOptions& creationOptions = options.creationOptions();
684   if (creationOptions.compartmentSpecifier() ==
685       JS::CompartmentSpecifier::ExistingCompartment) {
686     Compartment* comp = creationOptions.compartment();
687     existingGlobal = &comp->firstGlobal();
688   }
689 
690   Realm* realm = NewRealm(cx, principals, options);
691   if (!realm) {
692     return nullptr;
693   }
694 
695   Rooted<GlobalObject*> global(cx);
696   {
697     AutoRealmUnchecked ar(cx, realm);
698     global = GlobalObject::createInternal(cx, clasp);
699     if (!global) {
700       return nullptr;
701     }
702 
703     if (hookOption == JS::FireOnNewGlobalHook) {
704       JS_FireOnNewGlobalObject(cx, global);
705     }
706   }
707 
708   return global;
709 }
710 
lexicalEnvironment() const711 GlobalLexicalEnvironmentObject& GlobalObject::lexicalEnvironment() const {
712   // The lexical environment is marked when marking the global, so we don't need
713   // a read barrier here because we know the global is live.
714   return *realm()->unbarrieredLexicalEnvironment();
715 }
716 
emptyGlobalScope() const717 GlobalScope& GlobalObject::emptyGlobalScope() const {
718   const Value& v = getReservedSlot(EMPTY_GLOBAL_SCOPE);
719   MOZ_ASSERT(v.isPrivateGCThing() && v.traceKind() == JS::TraceKind::Scope);
720   return static_cast<Scope*>(v.toGCThing())->as<GlobalScope>();
721 }
722 
723 /* static */
getOrCreateEval(JSContext * cx,Handle<GlobalObject * > global,MutableHandleObject eval)724 bool GlobalObject::getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
725                                    MutableHandleObject eval) {
726   if (!getOrCreateObjectPrototype(cx, global)) {
727     return false;
728   }
729   eval.set(&global->getSlot(EVAL).toObject());
730   return true;
731 }
732 
valueIsEval(const Value & val)733 bool GlobalObject::valueIsEval(const Value& val) {
734   Value eval = getSlot(EVAL);
735   return eval.isObject() && eval == val;
736 }
737 
738 /* static */
initStandardClasses(JSContext * cx,Handle<GlobalObject * > global)739 bool GlobalObject::initStandardClasses(JSContext* cx,
740                                        Handle<GlobalObject*> global) {
741   /* Define a top-level property 'undefined' with the undefined value. */
742   if (!DefineDataProperty(
743           cx, global, cx->names().undefined, UndefinedHandleValue,
744           JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING)) {
745     return false;
746   }
747 
748   // Resolve a "globalThis" self-referential property if necessary.
749   bool resolved;
750   if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) {
751     return false;
752   }
753 
754   for (size_t k = 0; k < JSProto_LIMIT; ++k) {
755     JSProtoKey key = static_cast<JSProtoKey>(k);
756     if (key != JSProto_Null && !global->isStandardClassResolved(key)) {
757       if (!resolveConstructor(cx, global, static_cast<JSProtoKey>(k),
758                               IfClassIsDisabled::DoNothing)) {
759         return false;
760       }
761     }
762   }
763   return true;
764 }
765 
766 /* static */
initSelfHostingBuiltins(JSContext * cx,Handle<GlobalObject * > global,const JSFunctionSpec * builtins)767 bool GlobalObject::initSelfHostingBuiltins(JSContext* cx,
768                                            Handle<GlobalObject*> global,
769                                            const JSFunctionSpec* builtins) {
770   return DefineFunctions(cx, global, builtins, AsIntrinsic);
771 }
772 
773 /* static */
isRuntimeCodeGenEnabled(JSContext * cx,HandleString code,Handle<GlobalObject * > global)774 bool GlobalObject::isRuntimeCodeGenEnabled(JSContext* cx, HandleString code,
775                                            Handle<GlobalObject*> global) {
776   HeapSlot& v = global->getSlotRef(RUNTIME_CODEGEN_ENABLED);
777   if (v.isUndefined()) {
778     /*
779      * If there are callbacks, make sure that the CSP callback is installed
780      * and that it permits runtime code generation.
781      */
782     JSCSPEvalChecker allows =
783         cx->runtime()->securityCallbacks->contentSecurityPolicyAllows;
784     if (allows) {
785       return allows(cx, code);
786     }
787 
788     // Let's cache the result only if the contentSecurityPolicyAllows callback
789     // is not set. In this way, contentSecurityPolicyAllows callback is executed
790     // each time, with the current HandleValue code.
791     v.set(global, HeapSlot::Slot, RUNTIME_CODEGEN_ENABLED, JS::TrueValue());
792   }
793   return !v.isFalse();
794 }
795 
796 /* static */
createConstructor(JSContext * cx,Native ctor,JSAtom * nameArg,unsigned length,gc::AllocKind kind,const JSJitInfo * jitInfo)797 JSFunction* GlobalObject::createConstructor(JSContext* cx, Native ctor,
798                                             JSAtom* nameArg, unsigned length,
799                                             gc::AllocKind kind,
800                                             const JSJitInfo* jitInfo) {
801   RootedAtom name(cx, nameArg);
802   JSFunction* fun = NewNativeConstructor(cx, ctor, length, name, kind);
803   if (!fun) {
804     return nullptr;
805   }
806 
807   if (jitInfo) {
808     fun->setJitInfo(jitInfo);
809   }
810 
811   return fun;
812 }
813 
CreateBlankProto(JSContext * cx,const JSClass * clasp,HandleObject proto)814 static NativeObject* CreateBlankProto(JSContext* cx, const JSClass* clasp,
815                                       HandleObject proto) {
816   MOZ_ASSERT(clasp != &JSFunction::class_);
817 
818   RootedObject blankProto(cx, NewTenuredObjectWithGivenProto(cx, clasp, proto));
819   if (!blankProto) {
820     return nullptr;
821   }
822 
823   return &blankProto->as<NativeObject>();
824 }
825 
826 /* static */
createBlankPrototype(JSContext * cx,Handle<GlobalObject * > global,const JSClass * clasp)827 NativeObject* GlobalObject::createBlankPrototype(JSContext* cx,
828                                                  Handle<GlobalObject*> global,
829                                                  const JSClass* clasp) {
830   RootedObject objectProto(cx, getOrCreateObjectPrototype(cx, global));
831   if (!objectProto) {
832     return nullptr;
833   }
834 
835   return CreateBlankProto(cx, clasp, objectProto);
836 }
837 
838 /* static */
createBlankPrototypeInheriting(JSContext * cx,const JSClass * clasp,HandleObject proto)839 NativeObject* GlobalObject::createBlankPrototypeInheriting(JSContext* cx,
840                                                            const JSClass* clasp,
841                                                            HandleObject proto) {
842   return CreateBlankProto(cx, clasp, proto);
843 }
844 
LinkConstructorAndPrototype(JSContext * cx,JSObject * ctor_,JSObject * proto_,unsigned prototypeAttrs,unsigned constructorAttrs)845 bool js::LinkConstructorAndPrototype(JSContext* cx, JSObject* ctor_,
846                                      JSObject* proto_, unsigned prototypeAttrs,
847                                      unsigned constructorAttrs) {
848   RootedObject ctor(cx, ctor_), proto(cx, proto_);
849 
850   RootedValue protoVal(cx, ObjectValue(*proto));
851   RootedValue ctorVal(cx, ObjectValue(*ctor));
852 
853   return DefineDataProperty(cx, ctor, cx->names().prototype, protoVal,
854                             prototypeAttrs) &&
855          DefineDataProperty(cx, proto, cx->names().constructor, ctorVal,
856                             constructorAttrs);
857 }
858 
DefinePropertiesAndFunctions(JSContext * cx,HandleObject obj,const JSPropertySpec * ps,const JSFunctionSpec * fs)859 bool js::DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
860                                       const JSPropertySpec* ps,
861                                       const JSFunctionSpec* fs) {
862   if (ps && !JS_DefineProperties(cx, obj, ps)) {
863     return false;
864   }
865   if (fs && !JS_DefineFunctions(cx, obj, fs)) {
866     return false;
867   }
868   return true;
869 }
870 
DefineToStringTag(JSContext * cx,HandleObject obj,JSAtom * tag)871 bool js::DefineToStringTag(JSContext* cx, HandleObject obj, JSAtom* tag) {
872   RootedId toStringTagId(cx,
873                          SYMBOL_TO_JSID(cx->wellKnownSymbols().toStringTag));
874   RootedValue tagString(cx, StringValue(tag));
875   return DefineDataProperty(cx, obj, toStringTagId, tagString, JSPROP_READONLY);
876 }
877 
878 /* static */
getOrCreateForOfPICObject(JSContext * cx,Handle<GlobalObject * > global)879 NativeObject* GlobalObject::getOrCreateForOfPICObject(
880     JSContext* cx, Handle<GlobalObject*> global) {
881   cx->check(global);
882   NativeObject* forOfPIC = global->getForOfPICObject();
883   if (forOfPIC) {
884     return forOfPIC;
885   }
886 
887   forOfPIC = ForOfPIC::createForOfPICObject(cx, global);
888   if (!forOfPIC) {
889     return nullptr;
890   }
891   global->setReservedSlot(FOR_OF_PIC_CHAIN, ObjectValue(*forOfPIC));
892   return forOfPIC;
893 }
894 
895 /* static */
getOrCreateRealmKeyObject(JSContext * cx,Handle<GlobalObject * > global)896 JSObject* GlobalObject::getOrCreateRealmKeyObject(
897     JSContext* cx, Handle<GlobalObject*> global) {
898   cx->check(global);
899   Value v = global->getReservedSlot(REALM_KEY_OBJECT);
900   if (v.isObject()) {
901     return &v.toObject();
902   }
903 
904   PlainObject* key = NewBuiltinClassInstance<PlainObject>(cx);
905   if (!key) {
906     return nullptr;
907   }
908 
909   global->setReservedSlot(REALM_KEY_OBJECT, ObjectValue(*key));
910   return key;
911 }
912 
913 /* static */
getRegExpStatics(JSContext * cx,Handle<GlobalObject * > global)914 RegExpStatics* GlobalObject::getRegExpStatics(JSContext* cx,
915                                               Handle<GlobalObject*> global) {
916   MOZ_ASSERT(cx);
917   RegExpStaticsObject* resObj = nullptr;
918   const Value& val = global->getSlot(REGEXP_STATICS);
919   if (!val.isObject()) {
920     MOZ_ASSERT(val.isUndefined());
921     resObj = RegExpStatics::create(cx);
922     if (!resObj) {
923       return nullptr;
924     }
925 
926     global->initSlot(REGEXP_STATICS, ObjectValue(*resObj));
927   } else {
928     resObj = &val.toObject().as<RegExpStaticsObject>();
929   }
930   return static_cast<RegExpStatics*>(resObj->getPrivate(/* nfixed = */ 1));
931 }
932 
933 /* static */
getIntrinsicsHolder(JSContext * cx,Handle<GlobalObject * > global)934 NativeObject* GlobalObject::getIntrinsicsHolder(JSContext* cx,
935                                                 Handle<GlobalObject*> global) {
936   Value slot = global->getReservedSlot(INTRINSICS);
937   MOZ_ASSERT(slot.isUndefined() || slot.isObject());
938 
939   if (slot.isObject()) {
940     return &slot.toObject().as<NativeObject>();
941   }
942 
943   Rooted<NativeObject*> intrinsicsHolder(cx);
944   bool isSelfHostingGlobal = cx->runtime()->isSelfHostingGlobal(global);
945   if (isSelfHostingGlobal) {
946     intrinsicsHolder = global;
947   } else {
948     intrinsicsHolder = NewTenuredObjectWithGivenProto<PlainObject>(cx, nullptr);
949     if (!intrinsicsHolder) {
950       return nullptr;
951     }
952   }
953 
954   // Define a top-level property 'undefined' with the undefined value.
955   if (!DefineDataProperty(cx, intrinsicsHolder, cx->names().undefined,
956                           UndefinedHandleValue,
957                           JSPROP_PERMANENT | JSPROP_READONLY)) {
958     return nullptr;
959   }
960 
961   // Install the intrinsics holder in the intrinsics.
962   global->setReservedSlot(INTRINSICS, ObjectValue(*intrinsicsHolder));
963   return intrinsicsHolder;
964 }
965 
966 /* static */
getSelfHostedFunction(JSContext * cx,Handle<GlobalObject * > global,HandlePropertyName selfHostedName,HandleAtom name,unsigned nargs,MutableHandleValue funVal)967 bool GlobalObject::getSelfHostedFunction(JSContext* cx,
968                                          Handle<GlobalObject*> global,
969                                          HandlePropertyName selfHostedName,
970                                          HandleAtom name, unsigned nargs,
971                                          MutableHandleValue funVal) {
972   bool exists = false;
973   if (!GlobalObject::maybeGetIntrinsicValue(cx, global, selfHostedName, funVal,
974                                             &exists)) {
975     return false;
976   }
977   if (exists) {
978     RootedFunction fun(cx, &funVal.toObject().as<JSFunction>());
979     if (fun->explicitName() == name) {
980       return true;
981     }
982 
983     if (fun->explicitName() == selfHostedName) {
984       // This function was initially cloned because it was called by
985       // other self-hosted code, so the clone kept its self-hosted name,
986       // instead of getting the name it's intended to have in content
987       // compartments. This can happen when a lazy builtin is initialized
988       // after self-hosted code for another builtin used the same
989       // function. In that case, we need to change the function's name,
990       // which is ok because it can't have been exposed to content
991       // before.
992       fun->initAtom(name);
993       return true;
994     }
995 
996     // The function might be installed multiple times on the same or
997     // different builtins, under different property names, so its name
998     // might be neither "selfHostedName" nor "name". In that case, its
999     // canonical name must've been set using the `_SetCanonicalName`
1000     // intrinsic.
1001     cx->runtime()->assertSelfHostedFunctionHasCanonicalName(cx, selfHostedName);
1002     return true;
1003   }
1004 
1005   RootedFunction fun(cx);
1006   if (!cx->runtime()->createLazySelfHostedFunctionClone(
1007           cx, selfHostedName, name, nargs, TenuredObject, &fun)) {
1008     return false;
1009   }
1010   funVal.setObject(*fun);
1011 
1012   return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
1013 }
1014 
1015 /* static */
getIntrinsicValueSlow(JSContext * cx,Handle<GlobalObject * > global,HandlePropertyName name,MutableHandleValue value)1016 bool GlobalObject::getIntrinsicValueSlow(JSContext* cx,
1017                                          Handle<GlobalObject*> global,
1018                                          HandlePropertyName name,
1019                                          MutableHandleValue value) {
1020   if (!cx->runtime()->cloneSelfHostedValue(cx, name, value)) {
1021     return false;
1022   }
1023 
1024   // It's possible in certain edge cases that cloning the value ended up
1025   // defining the intrinsic. For instance, cloning can call NewArray, which
1026   // resolves Array.prototype, which defines some self-hosted functions. If this
1027   // happens we use the value already defined on the intrinsics holder.
1028   bool exists = false;
1029   if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value, &exists)) {
1030     return false;
1031   }
1032   if (exists) {
1033     return true;
1034   }
1035 
1036   return GlobalObject::addIntrinsicValue(cx, global, name, value);
1037 }
1038 
1039 /* static */
addIntrinsicValue(JSContext * cx,Handle<GlobalObject * > global,HandlePropertyName name,HandleValue value)1040 bool GlobalObject::addIntrinsicValue(JSContext* cx,
1041                                      Handle<GlobalObject*> global,
1042                                      HandlePropertyName name,
1043                                      HandleValue value) {
1044   RootedNativeObject holder(cx, GlobalObject::getIntrinsicsHolder(cx, global));
1045   if (!holder) {
1046     return false;
1047   }
1048 
1049   RootedId id(cx, NameToId(name));
1050   MOZ_ASSERT(!holder->containsPure(id));
1051 
1052   constexpr PropertyFlags propFlags = {PropertyFlag::Configurable,
1053                                        PropertyFlag::Writable};
1054   uint32_t slot;
1055   if (!NativeObject::addProperty(cx, holder, id, propFlags, &slot)) {
1056     return false;
1057   }
1058   holder->initSlot(slot, value);
1059   return true;
1060 }
1061 
1062 /* static */
ensureModulePrototypesCreated(JSContext * cx,Handle<GlobalObject * > global,bool setUsedAsPrototype)1063 bool GlobalObject::ensureModulePrototypesCreated(JSContext* cx,
1064                                                  Handle<GlobalObject*> global,
1065                                                  bool setUsedAsPrototype) {
1066   // Note: if you arrived here because you're removing UseOffThreadParseGlobal,
1067   // please also remove the setUsedAsPrototype argument and the lambda below.
1068   MOZ_ASSERT_IF(!UseOffThreadParseGlobal(), !setUsedAsPrototype);
1069 
1070   auto maybeSetUsedAsPrototype = [cx, setUsedAsPrototype](HandleObject proto) {
1071     if (!setUsedAsPrototype) {
1072       return true;
1073     }
1074     return JSObject::setIsUsedAsPrototype(cx, proto);
1075   };
1076 
1077   RootedObject proto(cx);
1078   proto = getOrCreateModulePrototype(cx, global);
1079   if (!proto || !maybeSetUsedAsPrototype(proto)) {
1080     return false;
1081   }
1082 
1083   proto = getOrCreateImportEntryPrototype(cx, global);
1084   if (!proto || !maybeSetUsedAsPrototype(proto)) {
1085     return false;
1086   }
1087 
1088   proto = getOrCreateExportEntryPrototype(cx, global);
1089   if (!proto || !maybeSetUsedAsPrototype(proto)) {
1090     return false;
1091   }
1092 
1093   proto = getOrCreateRequestedModulePrototype(cx, global);
1094   if (!proto || !maybeSetUsedAsPrototype(proto)) {
1095     return false;
1096   }
1097 
1098   return true;
1099 }
1100 
1101 /* static */
createIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)1102 JSObject* GlobalObject::createIteratorPrototype(JSContext* cx,
1103                                                 Handle<GlobalObject*> global) {
1104   if (!cx->realm()->creationOptions().getIteratorHelpersEnabled()) {
1105     return getOrCreateObject(cx, global, ITERATOR_PROTO, initIteratorProto);
1106   }
1107 
1108   if (!ensureConstructor(cx, global, JSProto_Iterator)) {
1109     return nullptr;
1110   }
1111   JSObject* proto = &global->getPrototype(JSProto_Iterator).toObject();
1112   global->setReservedSlot(ITERATOR_PROTO, ObjectValue(*proto));
1113   return proto;
1114 }
1115 
1116 /* static */
createAsyncIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)1117 JSObject* GlobalObject::createAsyncIteratorPrototype(
1118     JSContext* cx, Handle<GlobalObject*> global) {
1119   if (!cx->realm()->creationOptions().getIteratorHelpersEnabled()) {
1120     return getOrCreateObject(cx, global, ASYNC_ITERATOR_PROTO,
1121                              initAsyncIteratorProto);
1122   }
1123 
1124   if (!ensureConstructor(cx, global, JSProto_AsyncIterator)) {
1125     return nullptr;
1126   }
1127   JSObject* proto = &global->getPrototype(JSProto_AsyncIterator).toObject();
1128   global->setReservedSlot(ASYNC_ITERATOR_PROTO, ObjectValue(*proto));
1129   return proto;
1130 }
1131