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