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