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 #ifndef vm_GlobalObject_h
8 #define vm_GlobalObject_h
9 
10 #include "mozilla/Assertions.h"
11 
12 #include <stdint.h>
13 #include <type_traits>
14 
15 #include "jsapi.h"
16 #include "jsexn.h"
17 #include "jsfriendapi.h"
18 #include "jspubtd.h"
19 #include "jstypes.h"
20 #include "NamespaceImports.h"
21 
22 #include "gc/AllocKind.h"
23 #include "gc/Rooting.h"
24 #include "js/CallArgs.h"
25 #include "js/Class.h"
26 #include "js/ErrorReport.h"
27 #include "js/PropertyDescriptor.h"
28 #include "js/RootingAPI.h"
29 #include "js/ScalarType.h"  // js::Scalar::Type
30 #include "js/TypeDecls.h"
31 #include "js/Value.h"
32 #include "vm/JSContext.h"
33 #include "vm/JSFunction.h"
34 #include "vm/JSObject.h"
35 #include "vm/NativeObject.h"
36 #include "vm/Realm.h"
37 #include "vm/Runtime.h"
38 #include "vm/Shape.h"
39 #include "vm/StringType.h"
40 
41 struct JSFunctionSpec;
42 class JSJitInfo;
43 struct JSPrincipals;
44 struct JSPropertySpec;
45 
46 namespace JS {
47 class JS_PUBLIC_API RealmOptions;
48 };
49 
50 namespace js {
51 
52 class GlobalScope;
53 class GlobalLexicalEnvironmentObject;
54 class PlainObject;
55 class RegExpStatics;
56 
57 /*
58  * Global object slots are reserved as follows:
59  *
60  * [0, APPLICATION_SLOTS)
61  *   Pre-reserved slots in all global objects set aside for the embedding's
62  *   use. As with all reserved slots these start out as UndefinedValue() and
63  *   are traced for GC purposes. Apart from that the engine never touches
64  *   these slots, so the embedding can do whatever it wants with them.
65  * [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT)
66  *   Stores the original value of the constructor for the corresponding
67  *   JSProtoKey.
68  * [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT)
69  *   Stores the prototype, if any, for the constructor for the corresponding
70  *   JSProtoKey offset from JSProto_LIMIT.
71  * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, RESERVED_SLOTS)
72  *   Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics,
73  *   the original eval for this global object (implementing |var eval =
74  *   otherWindow.eval; eval(...)| as an indirect eval), a bit indicating
75  *   whether this object has been cleared (see JS_ClearScope), and a cache for
76  *   whether eval is allowed (per the global's Content Security Policy).
77  *
78  * The two JSProto_LIMIT-sized ranges are necessary to implement
79  * js::FindClassObject, and spec language speaking in terms of "the original
80  * Array prototype object", or "as if by the expression new Array()" referring
81  * to the original Array constructor. The actual (writable and even deletable)
82  * Object, Array, &c. properties are not stored in reserved slots.
83  */
84 class GlobalObject : public NativeObject {
85   /* Count of slots set aside for application use. */
86   static const unsigned APPLICATION_SLOTS = JSCLASS_GLOBAL_APPLICATION_SLOTS;
87 
88   /*
89    * Count of slots to store built-in prototypes and initial visible
90    * properties for the constructors.
91    */
92   static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 2;
93 
94   enum : unsigned {
95     /* Various function values needed by the engine. */
96     EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS,
97     THROWTYPEERROR,
98 
99     /* One-off properties stored after slots for built-ins. */
100     EMPTY_GLOBAL_SCOPE,
101     ITERATOR_PROTO,
102     ARRAY_ITERATOR_PROTO,
103     STRING_ITERATOR_PROTO,
104     REGEXP_STRING_ITERATOR_PROTO,
105     GENERATOR_OBJECT_PROTO,
106     ASYNC_ITERATOR_PROTO,
107     ASYNC_FROM_SYNC_ITERATOR_PROTO,
108     ASYNC_GENERATOR_PROTO,
109     MAP_ITERATOR_PROTO,
110     SET_ITERATOR_PROTO,
111     WRAP_FOR_VALID_ITERATOR_PROTO,
112     ITERATOR_HELPER_PROTO,
113     ASYNC_ITERATOR_HELPER_PROTO,
114     MODULE_PROTO,
115     IMPORT_ENTRY_PROTO,
116     EXPORT_ENTRY_PROTO,
117     REQUESTED_MODULE_PROTO,
118     MODULE_REQUEST_PROTO,
119     REGEXP_STATICS,
120     RUNTIME_CODEGEN_ENABLED,
121     INTRINSICS,
122     FOR_OF_PIC_CHAIN,
123     WINDOW_PROXY,
124     GLOBAL_THIS_RESOLVED,
125     SOURCE_URLS,
126     REALM_KEY_OBJECT,
127     ARRAY_SHAPE,
128 
129     /* Total reserved-slot count for global objects. */
130     RESERVED_SLOTS
131   };
132 
133   /*
134    * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and
135    * we won't expose GlobalObject, so just assert that the two values are
136    * synchronized.
137    */
138   static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS,
139                 "global object slot counts are inconsistent");
140 
constructorSlot(JSProtoKey key)141   static unsigned constructorSlot(JSProtoKey key) {
142     MOZ_ASSERT(key < JSProto_LIMIT);
143     return APPLICATION_SLOTS + key;
144   }
145 
prototypeSlot(JSProtoKey key)146   static unsigned prototypeSlot(JSProtoKey key) {
147     MOZ_ASSERT(key < JSProto_LIMIT);
148     return APPLICATION_SLOTS + JSProto_LIMIT + key;
149   }
150 
151  public:
152   GlobalLexicalEnvironmentObject& lexicalEnvironment() const;
153   GlobalScope& emptyGlobalScope() const;
154 
setOriginalEval(JSObject * evalobj)155   void setOriginalEval(JSObject* evalobj) {
156     MOZ_ASSERT(getSlotRef(EVAL).isUndefined());
157     setSlot(EVAL, ObjectValue(*evalobj));
158   }
159 
getConstructor(JSProtoKey key)160   Value getConstructor(JSProtoKey key) const {
161     return getSlot(constructorSlot(key));
162   }
163   static bool skipDeselectedConstructor(JSContext* cx, JSProtoKey key);
164   static bool initBuiltinConstructor(JSContext* cx,
165                                      Handle<GlobalObject*> global,
166                                      JSProtoKey key, HandleObject ctor,
167                                      HandleObject proto);
168 
169  private:
170   enum class IfClassIsDisabled { DoNothing, Throw };
171 
172   static bool resolveConstructor(JSContext* cx, Handle<GlobalObject*> global,
173                                  JSProtoKey key, IfClassIsDisabled mode);
174 
175  public:
ensureConstructor(JSContext * cx,Handle<GlobalObject * > global,JSProtoKey key)176   static bool ensureConstructor(JSContext* cx, Handle<GlobalObject*> global,
177                                 JSProtoKey key) {
178     if (global->isStandardClassResolved(key)) {
179       return true;
180     }
181     return resolveConstructor(cx, global, key, IfClassIsDisabled::Throw);
182   }
183 
getOrCreateConstructor(JSContext * cx,JSProtoKey key)184   static JSObject* getOrCreateConstructor(JSContext* cx, JSProtoKey key) {
185     MOZ_ASSERT(key != JSProto_Null);
186     Handle<GlobalObject*> global = cx->global();
187     if (!GlobalObject::ensureConstructor(cx, global, key)) {
188       return nullptr;
189     }
190     return &global->getConstructor(key).toObject();
191   }
192 
getOrCreatePrototype(JSContext * cx,JSProtoKey key)193   static JSObject* getOrCreatePrototype(JSContext* cx, JSProtoKey key) {
194     MOZ_ASSERT(key != JSProto_Null);
195     Handle<GlobalObject*> global = cx->global();
196     if (!GlobalObject::ensureConstructor(cx, global, key)) {
197       return nullptr;
198     }
199     return &global->getPrototype(key).toObject();
200   }
201 
maybeGetConstructor(JSProtoKey protoKey)202   JSObject* maybeGetConstructor(JSProtoKey protoKey) const {
203     MOZ_ASSERT(JSProto_Null < protoKey);
204     MOZ_ASSERT(protoKey < JSProto_LIMIT);
205     const Value& v = getConstructor(protoKey);
206     return v.isObject() ? &v.toObject() : nullptr;
207   }
208 
maybeGetPrototype(JSProtoKey protoKey)209   JSObject* maybeGetPrototype(JSProtoKey protoKey) const {
210     MOZ_ASSERT(JSProto_Null < protoKey);
211     MOZ_ASSERT(protoKey < JSProto_LIMIT);
212     const Value& v = getPrototype(protoKey);
213     return v.isObject() ? &v.toObject() : nullptr;
214   }
215 
216   static bool maybeResolveGlobalThis(JSContext* cx,
217                                      Handle<GlobalObject*> global,
218                                      bool* resolved);
219 
setConstructor(JSProtoKey key,const Value & v)220   void setConstructor(JSProtoKey key, const Value& v) {
221     setSlot(constructorSlot(key), v);
222   }
223 
getPrototype(JSProtoKey key)224   Value getPrototype(JSProtoKey key) const {
225     return getSlot(prototypeSlot(key));
226   }
227 
setPrototype(JSProtoKey key,const Value & value)228   void setPrototype(JSProtoKey key, const Value& value) {
229     setSlot(prototypeSlot(key), value);
230   }
231 
232   /*
233    * Lazy standard classes need a way to indicate they have been initialized.
234    * Otherwise, when we delete them, we might accidentally recreate them via
235    * a lazy initialization. We use the presence of an object in the
236    * getConstructor(key) reserved slot to indicate that they've been
237    * initialized.
238    *
239    * Note: A few builtin objects, like JSON and Math, are not constructors,
240    * so getConstructor is a bit of a misnomer.
241    */
isStandardClassResolved(JSProtoKey key)242   bool isStandardClassResolved(JSProtoKey key) const {
243     // If the constructor is undefined, then it hasn't been initialized.
244     Value value = getConstructor(key);
245     MOZ_ASSERT(value.isUndefined() || value.isObject() ||
246                value.isMagic(JS_OFF_THREAD_CONSTRUCTOR));
247     return !value.isUndefined();
248   }
249 
250  private:
classIsInitialized(JSProtoKey key)251   bool classIsInitialized(JSProtoKey key) const {
252     bool inited = !getConstructor(key).isUndefined();
253     MOZ_ASSERT(inited == !getPrototype(key).isUndefined());
254     return inited;
255   }
256 
functionObjectClassesInitialized()257   bool functionObjectClassesInitialized() const {
258     bool inited = classIsInitialized(JSProto_Function);
259     MOZ_ASSERT(inited == classIsInitialized(JSProto_Object));
260     return inited;
261   }
262 
263   // Disallow use of unqualified JSObject::create in GlobalObject.
264   static GlobalObject* create(...) = delete;
265 
266   friend struct ::JSRuntime;
267   static GlobalObject* createInternal(JSContext* cx, const JSClass* clasp);
268 
269  public:
270   static GlobalObject* new_(JSContext* cx, const JSClass* clasp,
271                             JSPrincipals* principals,
272                             JS::OnNewGlobalHookOption hookOption,
273                             const JS::RealmOptions& options);
274 
275   /*
276    * Create a constructor function with the specified name and length using
277    * ctor, a method which creates objects with the given class.
278    */
279   static JSFunction* createConstructor(
280       JSContext* cx, JSNative ctor, JSAtom* name, unsigned length,
281       gc::AllocKind kind = gc::AllocKind::FUNCTION,
282       const JSJitInfo* jitInfo = nullptr);
283 
284   /*
285    * Create an object to serve as [[Prototype]] for instances of the given
286    * class, using |Object.prototype| as its [[Prototype]].  Users creating
287    * prototype objects with particular internal structure (e.g. reserved
288    * slots guaranteed to contain values of particular types) must immediately
289    * complete the minimal initialization to make the returned object safe to
290    * touch.
291    */
292   static NativeObject* createBlankPrototype(JSContext* cx,
293                                             Handle<GlobalObject*> global,
294                                             const JSClass* clasp);
295 
296   /*
297    * Identical to createBlankPrototype, but uses proto as the [[Prototype]]
298    * of the returned blank prototype.
299    */
300   static NativeObject* createBlankPrototypeInheriting(JSContext* cx,
301                                                       const JSClass* clasp,
302                                                       HandleObject proto);
303 
304   template <typename T>
createBlankPrototypeInheriting(JSContext * cx,HandleObject proto)305   static T* createBlankPrototypeInheriting(JSContext* cx, HandleObject proto) {
306     NativeObject* res = createBlankPrototypeInheriting(cx, &T::class_, proto);
307     return res ? &res->template as<T>() : nullptr;
308   }
309 
310   template <typename T>
createBlankPrototype(JSContext * cx,Handle<GlobalObject * > global)311   static T* createBlankPrototype(JSContext* cx, Handle<GlobalObject*> global) {
312     NativeObject* res = createBlankPrototype(cx, global, &T::class_);
313     return res ? &res->template as<T>() : nullptr;
314   }
315 
getOrCreateObjectPrototype(JSContext * cx,Handle<GlobalObject * > global)316   static JSObject* getOrCreateObjectPrototype(JSContext* cx,
317                                               Handle<GlobalObject*> global) {
318     if (!global->functionObjectClassesInitialized()) {
319       if (!ensureConstructor(cx, global, JSProto_Object)) {
320         return nullptr;
321       }
322     }
323     return &global->getPrototype(JSProto_Object).toObject();
324   }
325 
getOrCreateFunctionConstructor(JSContext * cx,Handle<GlobalObject * > global)326   static JSObject* getOrCreateFunctionConstructor(
327       JSContext* cx, Handle<GlobalObject*> global) {
328     if (!global->functionObjectClassesInitialized()) {
329       if (!ensureConstructor(cx, global, JSProto_Object)) {
330         return nullptr;
331       }
332     }
333     return &global->getConstructor(JSProto_Function).toObject();
334   }
335 
getOrCreateFunctionPrototype(JSContext * cx,Handle<GlobalObject * > global)336   static JSObject* getOrCreateFunctionPrototype(JSContext* cx,
337                                                 Handle<GlobalObject*> global) {
338     if (!global->functionObjectClassesInitialized()) {
339       if (!ensureConstructor(cx, global, JSProto_Object)) {
340         return nullptr;
341       }
342     }
343     return &global->getPrototype(JSProto_Function).toObject();
344   }
345 
getOrCreateArrayPrototype(JSContext * cx,Handle<GlobalObject * > global)346   static NativeObject* getOrCreateArrayPrototype(JSContext* cx,
347                                                  Handle<GlobalObject*> global) {
348     if (!ensureConstructor(cx, global, JSProto_Array)) {
349       return nullptr;
350     }
351     return &global->getPrototype(JSProto_Array).toObject().as<NativeObject>();
352   }
353 
maybeGetArrayPrototype()354   NativeObject* maybeGetArrayPrototype() {
355     if (classIsInitialized(JSProto_Array)) {
356       return &getPrototype(JSProto_Array).toObject().as<NativeObject>();
357     }
358     return nullptr;
359   }
360 
getOrCreateBooleanPrototype(JSContext * cx,Handle<GlobalObject * > global)361   static JSObject* getOrCreateBooleanPrototype(JSContext* cx,
362                                                Handle<GlobalObject*> global) {
363     if (!ensureConstructor(cx, global, JSProto_Boolean)) {
364       return nullptr;
365     }
366     return &global->getPrototype(JSProto_Boolean).toObject();
367   }
368 
getOrCreateNumberPrototype(JSContext * cx,Handle<GlobalObject * > global)369   static JSObject* getOrCreateNumberPrototype(JSContext* cx,
370                                               Handle<GlobalObject*> global) {
371     if (!ensureConstructor(cx, global, JSProto_Number)) {
372       return nullptr;
373     }
374     return &global->getPrototype(JSProto_Number).toObject();
375   }
376 
getOrCreateStringPrototype(JSContext * cx,Handle<GlobalObject * > global)377   static JSObject* getOrCreateStringPrototype(JSContext* cx,
378                                               Handle<GlobalObject*> global) {
379     if (!ensureConstructor(cx, global, JSProto_String)) {
380       return nullptr;
381     }
382     return &global->getPrototype(JSProto_String).toObject();
383   }
384 
getOrCreateSymbolPrototype(JSContext * cx,Handle<GlobalObject * > global)385   static JSObject* getOrCreateSymbolPrototype(JSContext* cx,
386                                               Handle<GlobalObject*> global) {
387     if (!ensureConstructor(cx, global, JSProto_Symbol)) {
388       return nullptr;
389     }
390     return &global->getPrototype(JSProto_Symbol).toObject();
391   }
392 
getOrCreateBigIntPrototype(JSContext * cx,Handle<GlobalObject * > global)393   static JSObject* getOrCreateBigIntPrototype(JSContext* cx,
394                                               Handle<GlobalObject*> global) {
395     if (!ensureConstructor(cx, global, JSProto_BigInt)) {
396       return nullptr;
397     }
398     return &global->getPrototype(JSProto_BigInt).toObject();
399   }
400 
getOrCreatePromisePrototype(JSContext * cx,Handle<GlobalObject * > global)401   static JSObject* getOrCreatePromisePrototype(JSContext* cx,
402                                                Handle<GlobalObject*> global) {
403     if (!ensureConstructor(cx, global, JSProto_Promise)) {
404       return nullptr;
405     }
406     return &global->getPrototype(JSProto_Promise).toObject();
407   }
408 
getOrCreateRegExpPrototype(JSContext * cx,Handle<GlobalObject * > global)409   static JSObject* getOrCreateRegExpPrototype(JSContext* cx,
410                                               Handle<GlobalObject*> global) {
411     if (!ensureConstructor(cx, global, JSProto_RegExp)) {
412       return nullptr;
413     }
414     return &global->getPrototype(JSProto_RegExp).toObject();
415   }
416 
maybeGetRegExpPrototype()417   JSObject* maybeGetRegExpPrototype() {
418     if (classIsInitialized(JSProto_RegExp)) {
419       return &getPrototype(JSProto_RegExp).toObject();
420     }
421     return nullptr;
422   }
423 
getOrCreateSavedFramePrototype(JSContext * cx,Handle<GlobalObject * > global)424   static JSObject* getOrCreateSavedFramePrototype(
425       JSContext* cx, Handle<GlobalObject*> global) {
426     if (!ensureConstructor(cx, global, JSProto_SavedFrame)) {
427       return nullptr;
428     }
429     return &global->getPrototype(JSProto_SavedFrame).toObject();
430   }
431 
getOrCreateArrayBufferConstructor(JSContext * cx,Handle<GlobalObject * > global)432   static JSObject* getOrCreateArrayBufferConstructor(
433       JSContext* cx, Handle<GlobalObject*> global) {
434     if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) {
435       return nullptr;
436     }
437     return &global->getConstructor(JSProto_ArrayBuffer).toObject();
438   }
439 
getOrCreateArrayBufferPrototype(JSContext * cx,Handle<GlobalObject * > global)440   static JSObject* getOrCreateArrayBufferPrototype(
441       JSContext* cx, Handle<GlobalObject*> global) {
442     if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) {
443       return nullptr;
444     }
445     return &global->getPrototype(JSProto_ArrayBuffer).toObject();
446   }
447 
getOrCreateSharedArrayBufferPrototype(JSContext * cx,Handle<GlobalObject * > global)448   static JSObject* getOrCreateSharedArrayBufferPrototype(
449       JSContext* cx, Handle<GlobalObject*> global) {
450     if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) {
451       return nullptr;
452     }
453     return &global->getPrototype(JSProto_SharedArrayBuffer).toObject();
454   }
455 
getOrCreateCustomErrorPrototype(JSContext * cx,Handle<GlobalObject * > global,JSExnType exnType)456   static JSObject* getOrCreateCustomErrorPrototype(JSContext* cx,
457                                                    Handle<GlobalObject*> global,
458                                                    JSExnType exnType) {
459     JSProtoKey key = GetExceptionProtoKey(exnType);
460     if (!ensureConstructor(cx, global, key)) {
461       return nullptr;
462     }
463     return &global->getPrototype(key).toObject();
464   }
465 
getOrCreateErrorConstructor(JSContext * cx,Handle<GlobalObject * > global)466   static JSFunction* getOrCreateErrorConstructor(JSContext* cx,
467                                                  Handle<GlobalObject*> global) {
468     if (!ensureConstructor(cx, global, JSProto_Error)) {
469       return nullptr;
470     }
471     return &global->getConstructor(JSProto_Error).toObject().as<JSFunction>();
472   }
473 
getOrCreateErrorPrototype(JSContext * cx,Handle<GlobalObject * > global)474   static JSObject* getOrCreateErrorPrototype(JSContext* cx,
475                                              Handle<GlobalObject*> global) {
476     return getOrCreateCustomErrorPrototype(cx, global, JSEXN_ERR);
477   }
478 
getOrCreateSetPrototype(JSContext * cx,Handle<GlobalObject * > global)479   static NativeObject* getOrCreateSetPrototype(JSContext* cx,
480                                                Handle<GlobalObject*> global) {
481     if (!ensureConstructor(cx, global, JSProto_Set)) {
482       return nullptr;
483     }
484     return &global->getPrototype(JSProto_Set).toObject().as<NativeObject>();
485   }
486 
getOrCreateWeakSetPrototype(JSContext * cx,Handle<GlobalObject * > global)487   static NativeObject* getOrCreateWeakSetPrototype(
488       JSContext* cx, Handle<GlobalObject*> global) {
489     if (!ensureConstructor(cx, global, JSProto_WeakSet)) {
490       return nullptr;
491     }
492     return &global->getPrototype(JSProto_WeakSet).toObject().as<NativeObject>();
493   }
494 
495   static bool ensureModulePrototypesCreated(JSContext* cx,
496                                             Handle<GlobalObject*> global,
497                                             bool setUsedAsPrototype = false);
498 
getOrCreateModulePrototype(JSContext * cx,Handle<GlobalObject * > global)499   static JSObject* getOrCreateModulePrototype(JSContext* cx,
500                                               Handle<GlobalObject*> global) {
501     return getOrCreateObject(cx, global, MODULE_PROTO, initModuleProto);
502   }
503 
getOrCreateImportEntryPrototype(JSContext * cx,Handle<GlobalObject * > global)504   static JSObject* getOrCreateImportEntryPrototype(
505       JSContext* cx, Handle<GlobalObject*> global) {
506     return getOrCreateObject(cx, global, IMPORT_ENTRY_PROTO,
507                              initImportEntryProto);
508   }
509 
getOrCreateExportEntryPrototype(JSContext * cx,Handle<GlobalObject * > global)510   static JSObject* getOrCreateExportEntryPrototype(
511       JSContext* cx, Handle<GlobalObject*> global) {
512     return getOrCreateObject(cx, global, EXPORT_ENTRY_PROTO,
513                              initExportEntryProto);
514   }
515 
getOrCreateRequestedModulePrototype(JSContext * cx,Handle<GlobalObject * > global)516   static JSObject* getOrCreateRequestedModulePrototype(
517       JSContext* cx, Handle<GlobalObject*> global) {
518     return getOrCreateObject(cx, global, REQUESTED_MODULE_PROTO,
519                              initRequestedModuleProto);
520   }
521 
getOrCreateModuleRequestPrototype(JSContext * cx,Handle<GlobalObject * > global)522   static JSObject* getOrCreateModuleRequestPrototype(
523       JSContext* cx, Handle<GlobalObject*> global) {
524     return getOrCreateObject(cx, global, MODULE_REQUEST_PROTO,
525                              initModuleRequestProto);
526   }
527 
getOrCreateTypedArrayConstructor(JSContext * cx,Handle<GlobalObject * > global)528   static JSFunction* getOrCreateTypedArrayConstructor(
529       JSContext* cx, Handle<GlobalObject*> global) {
530     if (!ensureConstructor(cx, global, JSProto_TypedArray)) {
531       return nullptr;
532     }
533     return &global->getConstructor(JSProto_TypedArray)
534                 .toObject()
535                 .as<JSFunction>();
536   }
537 
getOrCreateTypedArrayPrototype(JSContext * cx,Handle<GlobalObject * > global)538   static JSObject* getOrCreateTypedArrayPrototype(
539       JSContext* cx, Handle<GlobalObject*> global) {
540     if (!ensureConstructor(cx, global, JSProto_TypedArray)) {
541       return nullptr;
542     }
543     return &global->getPrototype(JSProto_TypedArray).toObject();
544   }
545 
546  private:
547   using ObjectInitOp = bool (*)(JSContext*, Handle<GlobalObject*>);
548   using ObjectInitWithTagOp = bool (*)(JSContext*, Handle<GlobalObject*>,
549                                        HandleAtom);
550 
getOrCreateObject(JSContext * cx,Handle<GlobalObject * > global,unsigned slot,ObjectInitOp init)551   static JSObject* getOrCreateObject(JSContext* cx,
552                                      Handle<GlobalObject*> global,
553                                      unsigned slot, ObjectInitOp init) {
554     Value v = global->getSlotRef(slot);
555     if (v.isObject()) {
556       return &v.toObject();
557     }
558 
559     return createObject(cx, global, slot, init);
560   }
561 
getOrCreateObject(JSContext * cx,Handle<GlobalObject * > global,unsigned slot,HandleAtom tag,ObjectInitWithTagOp init)562   static JSObject* getOrCreateObject(JSContext* cx,
563                                      Handle<GlobalObject*> global,
564                                      unsigned slot, HandleAtom tag,
565                                      ObjectInitWithTagOp init) {
566     Value v = global->getSlotRef(slot);
567     if (v.isObject()) {
568       return &v.toObject();
569     }
570 
571     return createObject(cx, global, slot, tag, init);
572   }
573 
574   static JSObject* createObject(JSContext* cx, Handle<GlobalObject*> global,
575                                 unsigned slot, ObjectInitOp init);
576   static JSObject* createObject(JSContext* cx, Handle<GlobalObject*> global,
577                                 unsigned slot, HandleAtom tag,
578                                 ObjectInitWithTagOp init);
579 
580   static JSObject* createIteratorPrototype(JSContext* cx,
581                                            Handle<GlobalObject*> global);
582 
583  public:
getOrCreateIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)584   static JSObject* getOrCreateIteratorPrototype(JSContext* cx,
585                                                 Handle<GlobalObject*> global) {
586     if (global->getReservedSlot(ITERATOR_PROTO).isObject()) {
587       return &global->getReservedSlot(ITERATOR_PROTO).toObject();
588     }
589     return createIteratorPrototype(cx, global);
590   }
591 
592   static NativeObject* getOrCreateArrayIteratorPrototype(
593       JSContext* cx, Handle<GlobalObject*> global);
594 
maybeGetArrayIteratorPrototype()595   NativeObject* maybeGetArrayIteratorPrototype() {
596     Value v = getSlotRef(ARRAY_ITERATOR_PROTO);
597     if (v.isObject()) {
598       return &v.toObject().as<NativeObject>();
599     }
600     return nullptr;
601   }
602 
603   static JSObject* getOrCreateStringIteratorPrototype(
604       JSContext* cx, Handle<GlobalObject*> global);
605 
606   static JSObject* getOrCreateRegExpStringIteratorPrototype(
607       JSContext* cx, Handle<GlobalObject*> global);
608 
setGeneratorObjectPrototype(JSObject * obj)609   void setGeneratorObjectPrototype(JSObject* obj) {
610     setSlot(GENERATOR_OBJECT_PROTO, ObjectValue(*obj));
611   }
612 
getOrCreateGeneratorObjectPrototype(JSContext * cx,Handle<GlobalObject * > global)613   static JSObject* getOrCreateGeneratorObjectPrototype(
614       JSContext* cx, Handle<GlobalObject*> global) {
615     if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) {
616       return nullptr;
617     }
618     return &global->getSlot(GENERATOR_OBJECT_PROTO).toObject();
619   }
620 
getOrCreateGeneratorFunctionPrototype(JSContext * cx,Handle<GlobalObject * > global)621   static JSObject* getOrCreateGeneratorFunctionPrototype(
622       JSContext* cx, Handle<GlobalObject*> global) {
623     if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) {
624       return nullptr;
625     }
626     return &global->getPrototype(JSProto_GeneratorFunction).toObject();
627   }
628 
getOrCreateGeneratorFunction(JSContext * cx,Handle<GlobalObject * > global)629   static JSObject* getOrCreateGeneratorFunction(JSContext* cx,
630                                                 Handle<GlobalObject*> global) {
631     if (!ensureConstructor(cx, global, JSProto_GeneratorFunction)) {
632       return nullptr;
633     }
634     return &global->getConstructor(JSProto_GeneratorFunction).toObject();
635   }
636 
getOrCreateAsyncFunctionPrototype(JSContext * cx,Handle<GlobalObject * > global)637   static JSObject* getOrCreateAsyncFunctionPrototype(
638       JSContext* cx, Handle<GlobalObject*> global) {
639     if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) {
640       return nullptr;
641     }
642     return &global->getPrototype(JSProto_AsyncFunction).toObject();
643   }
644 
getOrCreateAsyncFunction(JSContext * cx,Handle<GlobalObject * > global)645   static JSObject* getOrCreateAsyncFunction(JSContext* cx,
646                                             Handle<GlobalObject*> global) {
647     if (!ensureConstructor(cx, global, JSProto_AsyncFunction)) {
648       return nullptr;
649     }
650     return &global->getConstructor(JSProto_AsyncFunction).toObject();
651   }
652 
653   static JSObject* createAsyncIteratorPrototype(JSContext* cx,
654                                                 Handle<GlobalObject*> global);
655 
getOrCreateAsyncIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)656   static JSObject* getOrCreateAsyncIteratorPrototype(
657       JSContext* cx, Handle<GlobalObject*> global) {
658     if (global->getReservedSlot(ASYNC_ITERATOR_PROTO).isObject()) {
659       return &global->getReservedSlot(ASYNC_ITERATOR_PROTO).toObject();
660     }
661     return createAsyncIteratorPrototype(cx, global);
662     // return getOrCreateObject(cx, global, ASYNC_ITERATOR_PROTO,
663     //                         initAsyncIteratorProto);
664   }
665 
getOrCreateAsyncFromSyncIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)666   static JSObject* getOrCreateAsyncFromSyncIteratorPrototype(
667       JSContext* cx, Handle<GlobalObject*> global) {
668     return getOrCreateObject(cx, global, ASYNC_FROM_SYNC_ITERATOR_PROTO,
669                              initAsyncFromSyncIteratorProto);
670   }
671 
getOrCreateAsyncGenerator(JSContext * cx,Handle<GlobalObject * > global)672   static JSObject* getOrCreateAsyncGenerator(JSContext* cx,
673                                              Handle<GlobalObject*> global) {
674     if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) {
675       return nullptr;
676     }
677     return &global->getPrototype(JSProto_AsyncGeneratorFunction).toObject();
678   }
679 
getOrCreateAsyncGeneratorFunction(JSContext * cx,Handle<GlobalObject * > global)680   static JSObject* getOrCreateAsyncGeneratorFunction(
681       JSContext* cx, Handle<GlobalObject*> global) {
682     if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) {
683       return nullptr;
684     }
685     return &global->getConstructor(JSProto_AsyncGeneratorFunction).toObject();
686   }
687 
setAsyncGeneratorPrototype(JSObject * obj)688   void setAsyncGeneratorPrototype(JSObject* obj) {
689     setSlot(ASYNC_GENERATOR_PROTO, ObjectValue(*obj));
690   }
691 
getOrCreateAsyncGeneratorPrototype(JSContext * cx,Handle<GlobalObject * > global)692   static JSObject* getOrCreateAsyncGeneratorPrototype(
693       JSContext* cx, Handle<GlobalObject*> global) {
694     if (!ensureConstructor(cx, global, JSProto_AsyncGeneratorFunction)) {
695       return nullptr;
696     }
697     return &global->getSlot(ASYNC_GENERATOR_PROTO).toObject();
698   }
699 
getOrCreateMapIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)700   static JSObject* getOrCreateMapIteratorPrototype(
701       JSContext* cx, Handle<GlobalObject*> global) {
702     return getOrCreateObject(cx, global, MAP_ITERATOR_PROTO,
703                              initMapIteratorProto);
704   }
705 
getOrCreateSetIteratorPrototype(JSContext * cx,Handle<GlobalObject * > global)706   static JSObject* getOrCreateSetIteratorPrototype(
707       JSContext* cx, Handle<GlobalObject*> global) {
708     return getOrCreateObject(cx, global, SET_ITERATOR_PROTO,
709                              initSetIteratorProto);
710   }
711 
getOrCreateDataViewPrototype(JSContext * cx,Handle<GlobalObject * > global)712   static JSObject* getOrCreateDataViewPrototype(JSContext* cx,
713                                                 Handle<GlobalObject*> global) {
714     if (!ensureConstructor(cx, global, JSProto_DataView)) {
715       return nullptr;
716     }
717     return &global->getPrototype(JSProto_DataView).toObject();
718   }
719 
getOrCreatePromiseConstructor(JSContext * cx,Handle<GlobalObject * > global)720   static JSObject* getOrCreatePromiseConstructor(JSContext* cx,
721                                                  Handle<GlobalObject*> global) {
722     if (!ensureConstructor(cx, global, JSProto_Promise)) {
723       return nullptr;
724     }
725     return &global->getConstructor(JSProto_Promise).toObject();
726   }
727 
728   static NativeObject* getOrCreateWrapForValidIteratorPrototype(
729       JSContext* cx, Handle<GlobalObject*> global);
730 
731   static NativeObject* getOrCreateIteratorHelperPrototype(
732       JSContext* cx, Handle<GlobalObject*> global);
733 
734   static NativeObject* getOrCreateAsyncIteratorHelperPrototype(
735       JSContext* cx, Handle<GlobalObject*> global);
736   static bool initAsyncIteratorHelperProto(JSContext* cx,
737                                            Handle<GlobalObject*> global);
738 
739   static NativeObject* getIntrinsicsHolder(JSContext* cx,
740                                            Handle<GlobalObject*> global);
741 
maybeExistingIntrinsicValue(PropertyName * name,Value * vp)742   bool maybeExistingIntrinsicValue(PropertyName* name, Value* vp) {
743     Value slot = getReservedSlot(INTRINSICS);
744     // If we're in the self-hosting compartment itself, the
745     // intrinsics-holder isn't initialized at this point.
746     if (slot.isUndefined()) {
747       *vp = UndefinedValue();
748       return false;
749     }
750 
751     NativeObject* holder = &slot.toObject().as<NativeObject>();
752     mozilla::Maybe<PropertyInfo> prop = holder->lookupPure(name);
753     if (prop.isNothing()) {
754       *vp = UndefinedValue();
755       return false;
756     }
757 
758     *vp = holder->getSlot(prop->slot());
759     return true;
760   }
761 
maybeGetIntrinsicValue(JSContext * cx,Handle<GlobalObject * > global,Handle<PropertyName * > name,MutableHandleValue vp,bool * exists)762   static bool maybeGetIntrinsicValue(JSContext* cx,
763                                      Handle<GlobalObject*> global,
764                                      Handle<PropertyName*> name,
765                                      MutableHandleValue vp, bool* exists) {
766     NativeObject* holder = getIntrinsicsHolder(cx, global);
767     if (!holder) {
768       return false;
769     }
770 
771     if (mozilla::Maybe<PropertyInfo> prop = holder->lookup(cx, name)) {
772       vp.set(holder->getSlot(prop->slot()));
773       *exists = true;
774     } else {
775       *exists = false;
776     }
777 
778     return true;
779   }
780 
getIntrinsicValue(JSContext * cx,Handle<GlobalObject * > global,HandlePropertyName name,MutableHandleValue value)781   static bool getIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
782                                 HandlePropertyName name,
783                                 MutableHandleValue value) {
784     bool exists = false;
785     if (!GlobalObject::maybeGetIntrinsicValue(cx, global, name, value,
786                                               &exists)) {
787       return false;
788     }
789     if (exists) {
790       return true;
791     }
792     return getIntrinsicValueSlow(cx, global, name, value);
793   }
794 
795   static bool getIntrinsicValueSlow(JSContext* cx, Handle<GlobalObject*> global,
796                                     HandlePropertyName name,
797                                     MutableHandleValue value);
798 
799   static bool addIntrinsicValue(JSContext* cx, Handle<GlobalObject*> global,
800                                 HandlePropertyName name, HandleValue value);
801 
802   static inline bool setIntrinsicValue(JSContext* cx,
803                                        Handle<GlobalObject*> global,
804                                        HandlePropertyName name,
805                                        HandleValue value);
806 
807   static bool getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
808                                     HandlePropertyName selfHostedName,
809                                     HandleAtom name, unsigned nargs,
810                                     MutableHandleValue funVal);
811 
812   static RegExpStatics* getRegExpStatics(JSContext* cx,
813                                          Handle<GlobalObject*> global);
814 
815   static JSObject* getOrCreateThrowTypeError(JSContext* cx,
816                                              Handle<GlobalObject*> global);
817 
818   static bool isRuntimeCodeGenEnabled(JSContext* cx, HandleString code,
819                                       Handle<GlobalObject*> global);
820 
821   static bool getOrCreateEval(JSContext* cx, Handle<GlobalObject*> global,
822                               MutableHandleObject eval);
823 
824   // Infallibly test whether the given value is the eval function for this
825   // global.
826   bool valueIsEval(const Value& val);
827 
828   // Implemented in vm/Iteration.cpp.
829   static bool initIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
830   template <unsigned Slot, const JSClass* ProtoClass,
831             const JSFunctionSpec* Methods>
832   static bool initObjectIteratorProto(JSContext* cx,
833                                       Handle<GlobalObject*> global,
834                                       HandleAtom tag);
835 
836   // Implemented in vm/AsyncIteration.cpp.
837   static bool initAsyncIteratorProto(JSContext* cx,
838                                      Handle<GlobalObject*> global);
839   static bool initAsyncFromSyncIteratorProto(JSContext* cx,
840                                              Handle<GlobalObject*> global);
841 
842   // Implemented in builtin/MapObject.cpp.
843   static bool initMapIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
844   static bool initSetIteratorProto(JSContext* cx, Handle<GlobalObject*> global);
845 
846   // Implemented in builtin/ModuleObject.cpp
847   static bool initModuleProto(JSContext* cx, Handle<GlobalObject*> global);
848   static bool initImportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
849   static bool initExportEntryProto(JSContext* cx, Handle<GlobalObject*> global);
850   static bool initRequestedModuleProto(JSContext* cx,
851                                        Handle<GlobalObject*> global);
852   static bool initModuleRequestProto(JSContext* cx,
853                                      Handle<GlobalObject*> global);
854 
855   static bool initStandardClasses(JSContext* cx, Handle<GlobalObject*> global);
856   static bool initSelfHostingBuiltins(JSContext* cx,
857                                       Handle<GlobalObject*> global,
858                                       const JSFunctionSpec* builtins);
859 
getDebuggers()860   Realm::DebuggerVector& getDebuggers() const {
861     return realm()->getDebuggers();
862   }
863 
getForOfPICObject()864   inline NativeObject* getForOfPICObject() {
865     Value forOfPIC = getReservedSlot(FOR_OF_PIC_CHAIN);
866     if (forOfPIC.isUndefined()) {
867       return nullptr;
868     }
869     return &forOfPIC.toObject().as<NativeObject>();
870   }
871   static NativeObject* getOrCreateForOfPICObject(JSContext* cx,
872                                                  Handle<GlobalObject*> global);
873 
windowProxy()874   JSObject* windowProxy() const {
875     return &getReservedSlot(WINDOW_PROXY).toObject();
876   }
maybeWindowProxy()877   JSObject* maybeWindowProxy() const {
878     Value v = getReservedSlot(WINDOW_PROXY);
879     MOZ_ASSERT(v.isObject() || v.isUndefined());
880     return v.isObject() ? &v.toObject() : nullptr;
881   }
setWindowProxy(JSObject * windowProxy)882   void setWindowProxy(JSObject* windowProxy) {
883     setReservedSlot(WINDOW_PROXY, ObjectValue(*windowProxy));
884   }
885 
getSourceURLsHolder()886   JSObject* getSourceURLsHolder() const {
887     Value v = getReservedSlot(SOURCE_URLS);
888     MOZ_ASSERT(v.isObject() || v.isUndefined());
889     return v.isObject() ? &v.toObject() : nullptr;
890   }
setSourceURLsHolder(JSObject * holder)891   void setSourceURLsHolder(JSObject* holder) {
892     setReservedSlot(SOURCE_URLS, ObjectValue(*holder));
893   }
clearSourceURLSHolder()894   void clearSourceURLSHolder() {
895     // This is called at the start of shrinking GCs, so avoids barriers.
896     getSlotRef(SOURCE_URLS).unbarrieredSet(UndefinedValue());
897   }
898 
setArrayShape(Shape * shape)899   void setArrayShape(Shape* shape) {
900     MOZ_ASSERT(getSlot(ARRAY_SHAPE).isUndefined());
901     initSlot(ARRAY_SHAPE, PrivateGCThingValue(shape));
902   }
maybeArrayShape()903   Shape* maybeArrayShape() const {
904     Value v = getSlot(ARRAY_SHAPE);
905     MOZ_ASSERT(v.isUndefined() || v.isPrivateGCThing());
906     return v.isPrivateGCThing() ? v.toGCThing()->as<Shape>() : nullptr;
907   }
908 
909   // Returns an object that represents the realm, used by embedder.
910   static JSObject* getOrCreateRealmKeyObject(JSContext* cx,
911                                              Handle<GlobalObject*> global);
912 
913   // A class used in place of a prototype during off-thread parsing.
914   struct OffThreadPlaceholderObject : public NativeObject {
915     static const int32_t SlotIndexSlot = 0;
916     static const JSClass class_;
917     static OffThreadPlaceholderObject* New(JSContext* cx, unsigned slot);
918     inline int32_t getSlotIndex() const;
919   };
920 
isOffThreadPrototypePlaceholder(JSObject * obj)921   static bool isOffThreadPrototypePlaceholder(JSObject* obj) {
922     return obj->is<OffThreadPlaceholderObject>();
923   }
924 
925   JSObject* getPrototypeForOffThreadPlaceholder(JSObject* placeholder);
926 
927  private:
928   static bool resolveOffThreadConstructor(JSContext* cx,
929                                           Handle<GlobalObject*> global,
930                                           JSProtoKey key);
931   static JSObject* createOffThreadObject(JSContext* cx,
932                                          Handle<GlobalObject*> global,
933                                          unsigned slot);
934 };
935 
936 /*
937  * Unless otherwise specified, define ctor.prototype = proto as non-enumerable,
938  * non-configurable, and non-writable; and define proto.constructor = ctor as
939  * non-enumerable but configurable and writable.
940  */
941 extern bool LinkConstructorAndPrototype(
942     JSContext* cx, JSObject* ctor, JSObject* proto,
943     unsigned prototypeAttrs = JSPROP_PERMANENT | JSPROP_READONLY,
944     unsigned constructorAttrs = 0);
945 
946 /*
947  * Define properties and/or functions on any object. Either ps or fs, or both,
948  * may be null.
949  */
950 extern bool DefinePropertiesAndFunctions(JSContext* cx, HandleObject obj,
951                                          const JSPropertySpec* ps,
952                                          const JSFunctionSpec* fs);
953 
954 extern bool DefineToStringTag(JSContext* cx, HandleObject obj, JSAtom* tag);
955 
956 /*
957  * Convenience templates to generic constructor and prototype creation functions
958  * for ClassSpecs.
959  */
960 
961 template <JSNative ctor, unsigned length, gc::AllocKind kind,
962           const JSJitInfo* jitInfo = nullptr>
GenericCreateConstructor(JSContext * cx,JSProtoKey key)963 JSObject* GenericCreateConstructor(JSContext* cx, JSProtoKey key) {
964   // Note - We duplicate the trick from ClassName() so that we don't need to
965   // include vm/JSAtom-inl.h here.
966   PropertyName* name = (&cx->names().Null)[key];
967   return GlobalObject::createConstructor(cx, ctor, name, length, kind, jitInfo);
968 }
969 
970 template <typename T>
GenericCreatePrototype(JSContext * cx,JSProtoKey key)971 JSObject* GenericCreatePrototype(JSContext* cx, JSProtoKey key) {
972   static_assert(
973       !std::is_same_v<T, PlainObject>,
974       "creating Object.prototype is very special and isn't handled here");
975   MOZ_ASSERT(&T::class_ == ProtoKeyToClass(key),
976              "type mismatch--probably too much copy/paste in your ClassSpec");
977   MOZ_ASSERT(
978       InheritanceProtoKeyForStandardClass(key) == JSProto_Object,
979       "subclasses (of anything but Object) can't use GenericCreatePrototype");
980   return GlobalObject::createBlankPrototype(cx, cx->global(), &T::protoClass_);
981 }
982 
StandardProtoKeyOrNull(const JSObject * obj)983 inline JSProtoKey StandardProtoKeyOrNull(const JSObject* obj) {
984   return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
985 }
986 
987 JSObject* NewTenuredObjectWithFunctionPrototype(JSContext* cx,
988                                                 Handle<GlobalObject*> global);
989 
990 }  // namespace js
991 
992 template <>
993 inline bool JSObject::is<js::GlobalObject>() const {
994   return !!(getClass()->flags & JSCLASS_IS_GLOBAL);
995 }
996 
997 #endif /* vm_GlobalObject_h */
998