tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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, &regExpShapeWithDefaultProto, "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 }