tor-browser

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

ModuleObject.cpp (80659B)


      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 "builtin/ModuleObject.h"
      8 
      9 #include "mozilla/DebugOnly.h"
     10 #include "mozilla/ScopeExit.h"
     11 
     12 #include "builtin/Promise.h"
     13 #include "builtin/SelfHostingDefines.h"
     14 #include "frontend/ParseNode.h"
     15 #include "frontend/ParserAtom.h"  // TaggedParserAtomIndex, ParserAtomsTable, ParserAtom
     16 #include "frontend/SharedContext.h"
     17 #include "frontend/Stencil.h"
     18 #include "gc/GCContext.h"
     19 #include "gc/Tracer.h"
     20 #include "js/ColumnNumber.h"  // JS::ColumnNumberOneOrigin, JS::LimitedColumnNumberOneOrigin
     21 #include "js/friend/ErrorMessages.h"  // JSMSG_*
     22 #include "js/Modules.h"  // JS::GetModulePrivate, JS::ModuleDynamicImportHook, JS::ModuleType
     23 #include "vm/EqualityOperations.h"  // js::SameValue
     24 #include "vm/Interpreter.h"    // Execute, Lambda, ReportRuntimeLexicalError
     25 #include "vm/ModuleBuilder.h"  // js::ModuleBuilder
     26 #include "vm/Modules.h"
     27 #include "vm/PlainObject.h"    // js::PlainObject
     28 #include "vm/PromiseObject.h"  // js::PromiseObject
     29 #include "vm/SharedStencil.h"  // js::GCThingIndex
     30 
     31 #include "gc/GCContext-inl.h"
     32 #include "vm/EnvironmentObject-inl.h"  // EnvironmentObject::setAliasedBinding
     33 #include "vm/JSObject-inl.h"
     34 #include "vm/JSScript-inl.h"
     35 #include "vm/List-inl.h"
     36 #include "vm/NativeObject-inl.h"
     37 
     38 using namespace js;
     39 
     40 using mozilla::Maybe;
     41 using mozilla::Nothing;
     42 using mozilla::Some;
     43 using mozilla::Span;
     44 
     45 static_assert(ModuleStatus::New < ModuleStatus::Unlinked &&
     46                  ModuleStatus::Unlinked < ModuleStatus::Linking &&
     47                  ModuleStatus::Linking < ModuleStatus::Linked &&
     48                  ModuleStatus::Linked < ModuleStatus::Evaluating &&
     49                  ModuleStatus::Evaluating < ModuleStatus::EvaluatingAsync &&
     50                  ModuleStatus::EvaluatingAsync < ModuleStatus::Evaluated &&
     51                  ModuleStatus::Evaluated < ModuleStatus::Evaluated_Error,
     52              "Module statuses are ordered incorrectly");
     53 
     54 static Value StringOrNullValue(JSString* maybeString) {
     55  return maybeString ? StringValue(maybeString) : NullValue();
     56 }
     57 
     58 static Value ModuleTypeToValue(JS::ModuleType moduleType) {
     59  static_assert(size_t(JS::ModuleType::Limit) <= INT32_MAX);
     60  return Int32Value(int32_t(moduleType));
     61 }
     62 
     63 static JS::ModuleType ValueToModuleType(const Value& value) {
     64  int32_t i = value.toInt32();
     65  MOZ_ASSERT(i >= 0 && i <= int32_t(JS::ModuleType::Limit));
     66  return static_cast<JS::ModuleType>(i);
     67 }
     68 
     69 static Value ImportPhaseToValue(ImportPhase phase) {
     70  static_assert(size_t(ImportPhase::Limit) <= INT32_MAX);
     71  return Int32Value(int32_t(phase));
     72 }
     73 
     74 static ImportPhase ValueToImportPhase(const Value& value) {
     75  int32_t i = value.toInt32();
     76  MOZ_ASSERT(i >= 0 && i <= int32_t(ImportPhase::Limit));
     77  return static_cast<ImportPhase>(i);
     78 }
     79 
     80 #define DEFINE_ATOM_ACCESSOR_METHOD(cls, name, slot) \
     81  JSAtom* cls::name() const {                        \
     82    Value value = getReservedSlot(slot);             \
     83    return &value.toString()->asAtom();              \
     84  }
     85 
     86 #define DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(cls, name, slot) \
     87  JSAtom* cls::name() const {                                \
     88    Value value = getReservedSlot(slot);                     \
     89    if (value.isNull()) {                                    \
     90      return nullptr;                                        \
     91    }                                                        \
     92    return &value.toString()->asAtom();                      \
     93  }
     94 
     95 #define DEFINE_UINT32_ACCESSOR_METHOD(cls, name, slot) \
     96  uint32_t cls::name() const {                         \
     97    Value value = getReservedSlot(slot);               \
     98    MOZ_ASSERT(value.toNumber() >= 0);                 \
     99    if (value.isInt32()) {                             \
    100      return value.toInt32();                          \
    101    }                                                  \
    102    return JS::ToUint32(value.toDouble());             \
    103  }
    104 
    105 ///////////////////////////////////////////////////////////////////////////
    106 // ImportEntry
    107 
    108 ImportEntry::ImportEntry(Handle<ModuleRequestObject*> moduleRequest,
    109                         Handle<JSAtom*> maybeImportName,
    110                         Handle<JSAtom*> localName, uint32_t lineNumber,
    111                         JS::ColumnNumberOneOrigin columnNumber)
    112    : moduleRequest_(moduleRequest),
    113      importName_(maybeImportName),
    114      localName_(localName),
    115      lineNumber_(lineNumber),
    116      columnNumber_(columnNumber) {}
    117 
    118 void ImportEntry::trace(JSTracer* trc) {
    119  TraceEdge(trc, &moduleRequest_, "ImportEntry::moduleRequest_");
    120  TraceNullableEdge(trc, &importName_, "ImportEntry::importName_");
    121  TraceNullableEdge(trc, &localName_, "ImportEntry::localName_");
    122 }
    123 
    124 ///////////////////////////////////////////////////////////////////////////
    125 // ExportEntry
    126 
    127 ExportEntry::ExportEntry(Handle<JSAtom*> maybeExportName,
    128                         Handle<ModuleRequestObject*> moduleRequest,
    129                         Handle<JSAtom*> maybeImportName,
    130                         Handle<JSAtom*> maybeLocalName, uint32_t lineNumber,
    131                         JS::ColumnNumberOneOrigin columnNumber)
    132    : exportName_(maybeExportName),
    133      moduleRequest_(moduleRequest),
    134      importName_(maybeImportName),
    135      localName_(maybeLocalName),
    136      lineNumber_(lineNumber),
    137      columnNumber_(columnNumber) {
    138  // Line and column numbers are optional for export entries since direct
    139  // entries are checked at parse time.
    140 }
    141 
    142 void ExportEntry::trace(JSTracer* trc) {
    143  TraceNullableEdge(trc, &exportName_, "ExportEntry::exportName_");
    144  TraceNullableEdge(trc, &moduleRequest_, "ExportEntry::moduleRequest_");
    145  TraceNullableEdge(trc, &importName_, "ExportEntry::importName_");
    146  TraceNullableEdge(trc, &localName_, "ExportEntry::localName_");
    147 }
    148 
    149 ///////////////////////////////////////////////////////////////////////////
    150 // RequestedModule
    151 
    152 /* static */
    153 RequestedModule::RequestedModule(Handle<ModuleRequestObject*> moduleRequest,
    154                                 uint32_t lineNumber,
    155                                 JS::ColumnNumberOneOrigin columnNumber)
    156    : moduleRequest_(moduleRequest),
    157      lineNumber_(lineNumber),
    158      columnNumber_(columnNumber) {}
    159 
    160 void RequestedModule::trace(JSTracer* trc) {
    161  TraceEdge(trc, &moduleRequest_, "ExportEntry::moduleRequest_");
    162 }
    163 
    164 ///////////////////////////////////////////////////////////////////////////
    165 // ResolvedBindingObject
    166 
    167 /* static */ const JSClass ResolvedBindingObject::class_ = {
    168    "ResolvedBinding",
    169    JSCLASS_HAS_RESERVED_SLOTS(ResolvedBindingObject::SlotCount),
    170 };
    171 
    172 ModuleObject* ResolvedBindingObject::module() const {
    173  Value value = getReservedSlot(ModuleSlot);
    174  return &value.toObject().as<ModuleObject>();
    175 }
    176 
    177 JSAtom* ResolvedBindingObject::bindingName() const {
    178  Value value = getReservedSlot(BindingNameSlot);
    179  return &value.toString()->asAtom();
    180 }
    181 
    182 /* static */
    183 bool ResolvedBindingObject::isInstance(HandleValue value) {
    184  return value.isObject() && value.toObject().is<ResolvedBindingObject>();
    185 }
    186 
    187 /* static */
    188 ResolvedBindingObject* ResolvedBindingObject::create(
    189    JSContext* cx, Handle<ModuleObject*> module, Handle<JSAtom*> bindingName) {
    190  ResolvedBindingObject* self =
    191      NewObjectWithGivenProto<ResolvedBindingObject>(cx, nullptr);
    192  if (!self) {
    193    return nullptr;
    194  }
    195 
    196  self->initReservedSlot(ModuleSlot, ObjectValue(*module));
    197  self->initReservedSlot(BindingNameSlot, StringValue(bindingName));
    198  return self;
    199 }
    200 
    201 ///////////////////////////////////////////////////////////////////////////
    202 // ImportAttribute
    203 
    204 ImportAttribute::ImportAttribute(Handle<JSAtom*> key, Handle<JSString*> value)
    205    : key_(key), value_(value) {}
    206 
    207 void ImportAttribute::trace(JSTracer* trc) {
    208  TraceNullableEdge(trc, &key_, "ImportAttribute::key_");
    209  TraceNullableEdge(trc, &value_, "ImportAttribute::value_");
    210 }
    211 
    212 ///////////////////////////////////////////////////////////////////////////
    213 // ModuleRequestObject
    214 /* static */ const JSClass ModuleRequestObject::class_ = {
    215    "ModuleRequest",
    216    JSCLASS_HAS_RESERVED_SLOTS(ModuleRequestObject::SlotCount),
    217 };
    218 
    219 DEFINE_ATOM_OR_NULL_ACCESSOR_METHOD(ModuleRequestObject, specifier,
    220                                    SpecifierSlot)
    221 
    222 JS::ModuleType ModuleRequestObject::moduleType() const {
    223  return ValueToModuleType(getReservedSlot(ModuleTypeSlot));
    224 }
    225 
    226 ImportPhase ModuleRequestObject::phase() const {
    227  return ValueToImportPhase(getReservedSlot(PhaseSlot));
    228 }
    229 
    230 static bool GetModuleType(JSContext* cx,
    231                          Handle<ImportAttributeVector> maybeAttributes,
    232                          JS::ModuleType& moduleType) {
    233  for (const ImportAttribute& importAttribute : maybeAttributes) {
    234    if (importAttribute.key() == cx->names().type) {
    235      Rooted<JSLinearString*> typeStr(
    236          cx, importAttribute.value()->ensureLinear(cx));
    237      if (!typeStr) {
    238        return false;
    239      }
    240 
    241      if (js::EqualStrings(typeStr, cx->names().json)) {
    242        moduleType = JS::ModuleType::JSON;
    243      } else if (js::EqualStrings(typeStr, cx->names().css)) {
    244        moduleType = JS::ModuleType::CSS;
    245      } else if (js::EqualStrings(typeStr, cx->names().bytes)) {
    246        moduleType = JS::ModuleType::Bytes;
    247      } else {
    248        moduleType = JS::ModuleType::Unknown;
    249      }
    250 
    251      return true;
    252    }
    253  }
    254 
    255  moduleType = JS::ModuleType::JavaScript;
    256  return true;
    257 }
    258 
    259 /* static */
    260 bool ModuleRequestObject::isInstance(HandleValue value) {
    261  return value.isObject() && value.toObject().is<ModuleRequestObject>();
    262 }
    263 
    264 /* static */
    265 ModuleRequestObject* ModuleRequestObject::create(
    266    JSContext* cx, Handle<JSAtom*> specifier,
    267    Handle<ImportAttributeVector> maybeAttributes, ImportPhase phase) {
    268  JS::ModuleType moduleType = JS::ModuleType::JavaScript;
    269  if (!GetModuleType(cx, maybeAttributes, moduleType)) {
    270    return nullptr;
    271  }
    272 
    273  return create(cx, specifier, moduleType, phase);
    274 }
    275 
    276 /* static */
    277 ModuleRequestObject* ModuleRequestObject::create(JSContext* cx,
    278                                                 Handle<JSAtom*> specifier,
    279                                                 JS::ModuleType moduleType,
    280                                                 ImportPhase phase) {
    281  ModuleRequestObject* self =
    282      NewObjectWithGivenProto<ModuleRequestObject>(cx, nullptr);
    283  if (!self) {
    284    return nullptr;
    285  }
    286 
    287  self->initReservedSlot(SpecifierSlot, StringOrNullValue(specifier));
    288  self->initReservedSlot(ModuleTypeSlot, ModuleTypeToValue(moduleType));
    289  self->initReservedSlot(PhaseSlot, ImportPhaseToValue(phase));
    290 
    291  return self;
    292 }
    293 
    294 void ModuleRequestObject::setFirstUnsupportedAttributeKey(Handle<JSAtom*> key) {
    295  initReservedSlot(FirstUnsupportedAttributeKeySlot, StringOrNullValue(key));
    296 }
    297 
    298 bool ModuleRequestObject::hasFirstUnsupportedAttributeKey() const {
    299  return !getReservedSlot(FirstUnsupportedAttributeKeySlot).isNullOrUndefined();
    300 }
    301 
    302 JSAtom* ModuleRequestObject::getFirstUnsupportedAttributeKey() const {
    303  if (!hasFirstUnsupportedAttributeKey()) {
    304    return nullptr;
    305  }
    306  return &getReservedSlot(FirstUnsupportedAttributeKeySlot)
    307              .toString()
    308              ->asAtom();
    309 }
    310 
    311 ///////////////////////////////////////////////////////////////////////////
    312 // IndirectBindingMap
    313 
    314 IndirectBindingMap::Binding::Binding(ModuleEnvironmentObject* environment,
    315                                     jsid targetName, PropertyInfo prop)
    316    : environment(environment),
    317 #ifdef DEBUG
    318      targetName(targetName),
    319 #endif
    320      prop(prop) {
    321 }
    322 
    323 void IndirectBindingMap::trace(JSTracer* trc) {
    324  if (!map_) {
    325    return;
    326  }
    327 
    328  for (Map::Enum e(*map_); !e.empty(); e.popFront()) {
    329    Binding& b = e.front().value();
    330    TraceEdge(trc, &b.environment, "module bindings environment");
    331 #ifdef DEBUG
    332    TraceEdge(trc, &b.targetName, "module bindings target name");
    333 #endif
    334    mozilla::DebugOnly<jsid> prev(e.front().key());
    335    TraceEdge(trc, &e.front().mutableKey(), "module bindings binding name");
    336    MOZ_ASSERT(e.front().key() == prev);
    337  }
    338 }
    339 
    340 bool IndirectBindingMap::put(JSContext* cx, HandleId name,
    341                             Handle<ModuleEnvironmentObject*> environment,
    342                             HandleId targetName) {
    343  if (!map_) {
    344    map_.emplace(cx->zone());
    345  }
    346 
    347  mozilla::Maybe<PropertyInfo> prop = environment->lookup(cx, targetName);
    348  MOZ_ASSERT(prop.isSome());
    349  if (!map_->put(name, Binding(environment, targetName, *prop))) {
    350    ReportOutOfMemory(cx);
    351    return false;
    352  }
    353 
    354  return true;
    355 }
    356 
    357 bool IndirectBindingMap::lookup(jsid name, ModuleEnvironmentObject** envOut,
    358                                mozilla::Maybe<PropertyInfo>* propOut) const {
    359  if (!map_) {
    360    return false;
    361  }
    362 
    363  auto ptr = map_->lookup(name);
    364  if (!ptr) {
    365    return false;
    366  }
    367 
    368  const Binding& binding = ptr->value();
    369  MOZ_ASSERT(binding.environment);
    370  MOZ_ASSERT(
    371      binding.environment->containsPure(binding.targetName, binding.prop));
    372  *envOut = binding.environment;
    373  *propOut = Some(binding.prop);
    374  return true;
    375 }
    376 
    377 ///////////////////////////////////////////////////////////////////////////
    378 // ModuleNamespaceObject
    379 
    380 /* static */
    381 constexpr ModuleNamespaceObject::ProxyHandler
    382    ModuleNamespaceObject::proxyHandler;
    383 
    384 /* static */
    385 bool ModuleNamespaceObject::isInstance(HandleValue value) {
    386  return value.isObject() && value.toObject().is<ModuleNamespaceObject>();
    387 }
    388 
    389 /* static */
    390 ModuleNamespaceObject* ModuleNamespaceObject::create(
    391    JSContext* cx, Handle<ModuleObject*> module,
    392    MutableHandle<UniquePtr<ExportNameVector>> exports,
    393    MutableHandle<UniquePtr<IndirectBindingMap>> bindings) {
    394  RootedValue priv(cx, ObjectValue(*module));
    395  ProxyOptions options;
    396  options.setLazyProto(true);
    397 
    398  RootedObject object(
    399      cx, NewProxyObject(cx, &proxyHandler, priv, nullptr, options));
    400  if (!object) {
    401    return nullptr;
    402  }
    403 
    404  SetProxyReservedSlot(object, ExportsSlot,
    405                       PrivateValue(exports.get().release()));
    406  AddCellMemory(object, sizeof(ExportNameVector), MemoryUse::ModuleExports);
    407 
    408  SetProxyReservedSlot(object, BindingsSlot,
    409                       PrivateValue(bindings.get().release()));
    410  AddCellMemory(object, sizeof(IndirectBindingMap),
    411                MemoryUse::ModuleBindingMap);
    412 
    413  return &object->as<ModuleNamespaceObject>();
    414 }
    415 
    416 ModuleObject& ModuleNamespaceObject::module() {
    417  return GetProxyPrivate(this).toObject().as<ModuleObject>();
    418 }
    419 
    420 const ExportNameVector& ModuleNamespaceObject::exports() const {
    421  Value value = GetProxyReservedSlot(this, ExportsSlot);
    422  auto* exports = static_cast<ExportNameVector*>(value.toPrivate());
    423  MOZ_ASSERT(exports);
    424  return *exports;
    425 }
    426 
    427 ExportNameVector& ModuleNamespaceObject::mutableExports() {
    428  // Get a non-const reference for tracing/destruction. Do not actually mutate
    429  // this vector!  This would be incorrect without adding barriers.
    430  return const_cast<ExportNameVector&>(exports());
    431 }
    432 
    433 IndirectBindingMap& ModuleNamespaceObject::bindings() {
    434  Value value = GetProxyReservedSlot(this, BindingsSlot);
    435  auto* bindings = static_cast<IndirectBindingMap*>(value.toPrivate());
    436  MOZ_ASSERT(bindings);
    437  return *bindings;
    438 }
    439 
    440 bool ModuleNamespaceObject::hasExports() const {
    441  // Exports may not be present if we hit OOM in initialization.
    442  return !GetProxyReservedSlot(this, ExportsSlot).isUndefined();
    443 }
    444 
    445 bool ModuleNamespaceObject::hasBindings() const {
    446  // Import bindings may not be present if we hit OOM in initialization.
    447  return !GetProxyReservedSlot(this, BindingsSlot).isUndefined();
    448 }
    449 
    450 bool ModuleNamespaceObject::addBinding(JSContext* cx,
    451                                       Handle<JSAtom*> exportedName,
    452                                       Handle<ModuleObject*> targetModule,
    453                                       Handle<JSAtom*> targetName) {
    454  Rooted<ModuleEnvironmentObject*> environment(
    455      cx, &targetModule->initialEnvironment());
    456  RootedId exportedNameId(cx, AtomToId(exportedName));
    457  RootedId targetNameId(cx, AtomToId(targetName));
    458  return bindings().put(cx, exportedNameId, environment, targetNameId);
    459 }
    460 
    461 constexpr char ModuleNamespaceObject::ProxyHandler::family = 0;
    462 
    463 bool ModuleNamespaceObject::ProxyHandler::getPrototype(
    464    JSContext* cx, HandleObject proxy, MutableHandleObject protop) const {
    465  protop.set(nullptr);
    466  return true;
    467 }
    468 
    469 bool ModuleNamespaceObject::ProxyHandler::setPrototype(
    470    JSContext* cx, HandleObject proxy, HandleObject proto,
    471    ObjectOpResult& result) const {
    472  if (!proto) {
    473    return result.succeed();
    474  }
    475  return result.failCantSetProto();
    476 }
    477 
    478 bool ModuleNamespaceObject::ProxyHandler::getPrototypeIfOrdinary(
    479    JSContext* cx, HandleObject proxy, bool* isOrdinary,
    480    MutableHandleObject protop) const {
    481  *isOrdinary = false;
    482  return true;
    483 }
    484 
    485 bool ModuleNamespaceObject::ProxyHandler::setImmutablePrototype(
    486    JSContext* cx, HandleObject proxy, bool* succeeded) const {
    487  *succeeded = true;
    488  return true;
    489 }
    490 
    491 bool ModuleNamespaceObject::ProxyHandler::isExtensible(JSContext* cx,
    492                                                       HandleObject proxy,
    493                                                       bool* extensible) const {
    494  *extensible = false;
    495  return true;
    496 }
    497 
    498 bool ModuleNamespaceObject::ProxyHandler::preventExtensions(
    499    JSContext* cx, HandleObject proxy, ObjectOpResult& result) const {
    500  result.succeed();
    501  return true;
    502 }
    503 
    504 bool ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(
    505    JSContext* cx, HandleObject proxy, HandleId id,
    506    MutableHandle<mozilla::Maybe<PropertyDescriptor>> desc) const {
    507  Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
    508  if (id.isSymbol()) {
    509    if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
    510      desc.set(Some(PropertyDescriptor::Data(StringValue(cx->names().Module))));
    511      return true;
    512    }
    513 
    514    desc.reset();
    515    return true;
    516  }
    517 
    518  const IndirectBindingMap& bindings = ns->bindings();
    519  ModuleEnvironmentObject* env;
    520  mozilla::Maybe<PropertyInfo> prop;
    521  if (!bindings.lookup(id, &env, &prop)) {
    522    // Not found.
    523    desc.reset();
    524    return true;
    525  }
    526 
    527  RootedValue value(cx, env->getSlot(prop->slot()));
    528  if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) {
    529    ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id);
    530    return false;
    531  }
    532 
    533  desc.set(
    534      Some(PropertyDescriptor::Data(value, {JS::PropertyAttribute::Enumerable,
    535                                            JS::PropertyAttribute::Writable})));
    536  return true;
    537 }
    538 
    539 static bool ValidatePropertyDescriptor(
    540    JSContext* cx, Handle<PropertyDescriptor> desc, bool expectedWritable,
    541    bool expectedEnumerable, bool expectedConfigurable,
    542    HandleValue expectedValue, ObjectOpResult& result) {
    543  if (desc.isAccessorDescriptor()) {
    544    return result.fail(JSMSG_CANT_REDEFINE_PROP);
    545  }
    546 
    547  if (desc.hasWritable() && desc.writable() != expectedWritable) {
    548    return result.fail(JSMSG_CANT_REDEFINE_PROP);
    549  }
    550 
    551  if (desc.hasEnumerable() && desc.enumerable() != expectedEnumerable) {
    552    return result.fail(JSMSG_CANT_REDEFINE_PROP);
    553  }
    554 
    555  if (desc.hasConfigurable() && desc.configurable() != expectedConfigurable) {
    556    return result.fail(JSMSG_CANT_REDEFINE_PROP);
    557  }
    558 
    559  if (desc.hasValue()) {
    560    bool same;
    561    if (!SameValue(cx, desc.value(), expectedValue, &same)) {
    562      return false;
    563    }
    564    if (!same) {
    565      return result.fail(JSMSG_CANT_REDEFINE_PROP);
    566    }
    567  }
    568 
    569  return result.succeed();
    570 }
    571 
    572 bool ModuleNamespaceObject::ProxyHandler::defineProperty(
    573    JSContext* cx, HandleObject proxy, HandleId id,
    574    Handle<PropertyDescriptor> desc, ObjectOpResult& result) const {
    575  if (id.isSymbol()) {
    576    if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
    577      RootedValue value(cx, StringValue(cx->names().Module));
    578      return ValidatePropertyDescriptor(cx, desc, false, false, false, value,
    579                                        result);
    580    }
    581    return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
    582  }
    583 
    584  const IndirectBindingMap& bindings =
    585      proxy->as<ModuleNamespaceObject>().bindings();
    586  ModuleEnvironmentObject* env;
    587  mozilla::Maybe<PropertyInfo> prop;
    588  if (!bindings.lookup(id, &env, &prop)) {
    589    return result.fail(JSMSG_CANT_DEFINE_PROP_OBJECT_NOT_EXTENSIBLE);
    590  }
    591 
    592  RootedValue value(cx, env->getSlot(prop->slot()));
    593  if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) {
    594    ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id);
    595    return false;
    596  }
    597 
    598  return ValidatePropertyDescriptor(cx, desc, true, true, false, value, result);
    599 }
    600 
    601 bool ModuleNamespaceObject::ProxyHandler::has(JSContext* cx, HandleObject proxy,
    602                                              HandleId id, bool* bp) const {
    603  Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
    604  if (id.isSymbol()) {
    605    *bp = id.isWellKnownSymbol(JS::SymbolCode::toStringTag);
    606    return true;
    607  }
    608 
    609  *bp = ns->bindings().has(id);
    610  return true;
    611 }
    612 
    613 bool ModuleNamespaceObject::ProxyHandler::get(JSContext* cx, HandleObject proxy,
    614                                              HandleValue receiver, HandleId id,
    615                                              MutableHandleValue vp) const {
    616  Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
    617  if (id.isSymbol()) {
    618    if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
    619      vp.setString(cx->names().Module);
    620      return true;
    621    }
    622 
    623    vp.setUndefined();
    624    return true;
    625  }
    626 
    627  ModuleEnvironmentObject* env;
    628  mozilla::Maybe<PropertyInfo> prop;
    629  if (!ns->bindings().lookup(id, &env, &prop)) {
    630    vp.setUndefined();
    631    return true;
    632  }
    633 
    634  RootedValue value(cx, env->getSlot(prop->slot()));
    635  if (value.isMagic(JS_UNINITIALIZED_LEXICAL)) {
    636    ReportRuntimeLexicalError(cx, JSMSG_UNINITIALIZED_LEXICAL, id);
    637    return false;
    638  }
    639 
    640  vp.set(value);
    641  return true;
    642 }
    643 
    644 bool ModuleNamespaceObject::ProxyHandler::set(JSContext* cx, HandleObject proxy,
    645                                              HandleId id, HandleValue v,
    646                                              HandleValue receiver,
    647                                              ObjectOpResult& result) const {
    648  return result.failReadOnly();
    649 }
    650 
    651 bool ModuleNamespaceObject::ProxyHandler::delete_(
    652    JSContext* cx, HandleObject proxy, HandleId id,
    653    ObjectOpResult& result) const {
    654  Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
    655  if (id.isSymbol()) {
    656    if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
    657      return result.failCantDelete();
    658    }
    659 
    660    return result.succeed();
    661  }
    662 
    663  if (ns->bindings().has(id)) {
    664    return result.failCantDelete();
    665  }
    666 
    667  return result.succeed();
    668 }
    669 
    670 bool ModuleNamespaceObject::ProxyHandler::ownPropertyKeys(
    671    JSContext* cx, HandleObject proxy, MutableHandleIdVector props) const {
    672  Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
    673  uint32_t count = ns->exports().length();
    674  if (!props.reserve(props.length() + count + 1)) {
    675    return false;
    676  }
    677 
    678  for (JSAtom* atom : ns->exports()) {
    679    props.infallibleAppend(AtomToId(atom));
    680  }
    681  props.infallibleAppend(
    682      PropertyKey::Symbol(cx->wellKnownSymbols().toStringTag));
    683 
    684  return true;
    685 }
    686 
    687 void ModuleNamespaceObject::ProxyHandler::trace(JSTracer* trc,
    688                                                JSObject* proxy) const {
    689  auto& self = proxy->as<ModuleNamespaceObject>();
    690 
    691  if (self.hasExports()) {
    692    self.mutableExports().trace(trc);
    693  }
    694 
    695  if (self.hasBindings()) {
    696    self.bindings().trace(trc);
    697  }
    698 }
    699 
    700 void ModuleNamespaceObject::ProxyHandler::finalize(JS::GCContext* gcx,
    701                                                   JSObject* proxy) const {
    702  auto& self = proxy->as<ModuleNamespaceObject>();
    703 
    704  if (self.hasExports()) {
    705    gcx->delete_(proxy, &self.mutableExports(), MemoryUse::ModuleExports);
    706  }
    707 
    708  if (self.hasBindings()) {
    709    gcx->delete_(proxy, &self.bindings(), MemoryUse::ModuleBindingMap);
    710  }
    711 }
    712 
    713 // https://tc39.es/ecma262/#sec-IncrementModuleAsyncEvaluationCount
    714 // 9.6.3 IncrementModuleAsyncEvaluationCount()
    715 static uint32_t IncrementModuleAsyncEvaluationCount(JSRuntime* rt) {
    716  if (rt->pendingAsyncModuleEvaluations == 0) {
    717    // From the spec NOTE:
    718    //   An implementation may unobservably reset [[ModuleAsyncEvaluationCount]]
    719    //   to 0 whenever there are no pending modules.
    720    rt->moduleAsyncEvaluatingPostOrder = 0;
    721  }
    722 
    723  uint32_t ordinal = rt->moduleAsyncEvaluatingPostOrder;
    724  MOZ_ASSERT(ordinal != ASYNC_EVALUATING_POST_ORDER_DONE);
    725  MOZ_ASSERT(ordinal != ASYNC_EVALUATING_POST_ORDER_UNSET);
    726  MOZ_ASSERT(ordinal < ASYNC_EVALUATING_POST_ORDER_MAX_VALUE);
    727  rt->moduleAsyncEvaluatingPostOrder++;
    728 
    729  MOZ_ASSERT(rt->pendingAsyncModuleEvaluations < MAX_UINT32);
    730  rt->pendingAsyncModuleEvaluations++;
    731 
    732  return ordinal;
    733 }
    734 
    735 bool AsyncEvaluationOrder::isUnset() const {
    736  return value == ASYNC_EVALUATING_POST_ORDER_UNSET;
    737 }
    738 
    739 bool AsyncEvaluationOrder::isDone() const {
    740  return value == ASYNC_EVALUATING_POST_ORDER_DONE;
    741 }
    742 
    743 bool AsyncEvaluationOrder::isInteger() const {
    744  return value <= ASYNC_EVALUATING_POST_ORDER_MAX_VALUE;
    745 }
    746 
    747 uint32_t AsyncEvaluationOrder::get() const {
    748  MOZ_ASSERT(isInteger());
    749  return value;
    750 }
    751 
    752 void AsyncEvaluationOrder::set(JSRuntime* rt) {
    753  MOZ_ASSERT(isUnset());
    754  value = IncrementModuleAsyncEvaluationCount(rt);
    755 }
    756 
    757 void AsyncEvaluationOrder::setDone(JSRuntime* rt) {
    758  MOZ_ASSERT(isInteger());
    759  MOZ_ASSERT(rt->pendingAsyncModuleEvaluations > 0);
    760  rt->pendingAsyncModuleEvaluations--;
    761  value = ASYNC_EVALUATING_POST_ORDER_DONE;
    762 }
    763 
    764 ///////////////////////////////////////////////////////////////////////////
    765 // SyntheticModuleFields
    766 
    767 // The fields of a synthetic module record, as described in:
    768 // https://tc39.es/proposal-json-modules/#sec-synthetic-module-records
    769 class js::SyntheticModuleFields {
    770 public:
    771  ExportNameVector exportNames;
    772 
    773 public:
    774  void trace(JSTracer* trc);
    775 };
    776 
    777 void SyntheticModuleFields::trace(JSTracer* trc) { exportNames.trace(trc); }
    778 
    779 ///////////////////////////////////////////////////////////////////////////
    780 // CyclicModuleFields
    781 
    782 // The fields of a cyclic module record, as described in:
    783 // https://tc39.es/ecma262/#sec-cyclic-module-records
    784 class js::CyclicModuleFields {
    785 public:
    786  ModuleStatus status = ModuleStatus::New;
    787 
    788  bool hasTopLevelAwait : 1;
    789 
    790 private:
    791  // Flag bits that determine whether other fields are present.
    792  bool hasDfsAncestorIndex : 1;
    793  bool hasPendingAsyncDependencies : 1;
    794 
    795  // Fields whose presence is conditional on the flag bits above.
    796  uint32_t dfsAncestorIndex = 0;
    797  uint32_t pendingAsyncDependencies = 0;
    798 
    799  // Fields describing the layout of exportEntries.
    800  uint32_t indirectExportEntriesStart = 0;
    801  uint32_t starExportEntriesStart = 0;
    802 
    803 public:
    804  HeapPtr<Value> evaluationError;
    805  HeapPtr<JSObject*> metaObject;
    806  HeapPtr<ScriptSourceObject*> scriptSourceObject;
    807  RequestedModuleVector requestedModules;
    808  LoadedModuleMap loadedModules;
    809  ImportEntryVector importEntries;
    810  ExportEntryVector exportEntries;
    811  IndirectBindingMap importBindings;
    812  UniquePtr<FunctionDeclarationVector> functionDeclarations;
    813  AsyncEvaluationOrder asyncEvaluationOrder;
    814  HeapPtr<PromiseObject*> topLevelCapability;
    815  HeapPtr<ListObject*> asyncParentModules;
    816  HeapPtr<ModuleObject*> cycleRoot;
    817 
    818 public:
    819  CyclicModuleFields();
    820 
    821  void trace(JSTracer* trc);
    822 
    823  void initExportEntries(MutableHandle<ExportEntryVector> allEntries,
    824                         uint32_t localExportCount,
    825                         uint32_t indirectExportCount,
    826                         uint32_t starExportCount);
    827  Span<const ExportEntry> localExportEntries() const;
    828  Span<const ExportEntry> indirectExportEntries() const;
    829  Span<const ExportEntry> starExportEntries() const;
    830 
    831  void setDfsAncestorIndex(uint32_t index);
    832  Maybe<uint32_t> maybeDfsAncestorIndex() const;
    833  void clearDfsAncestorIndex();
    834 
    835  void setPendingAsyncDependencies(uint32_t newValue);
    836  Maybe<uint32_t> maybePendingAsyncDependencies() const;
    837 };
    838 
    839 CyclicModuleFields::CyclicModuleFields()
    840    : hasTopLevelAwait(false),
    841      hasDfsAncestorIndex(false),
    842      hasPendingAsyncDependencies(false) {}
    843 
    844 void CyclicModuleFields::trace(JSTracer* trc) {
    845  TraceEdge(trc, &evaluationError, "CyclicModuleFields::evaluationError");
    846  TraceNullableEdge(trc, &metaObject, "CyclicModuleFields::metaObject");
    847  TraceNullableEdge(trc, &scriptSourceObject,
    848                    "CyclicModuleFields::scriptSourceObject");
    849  requestedModules.trace(trc);
    850  loadedModules.trace(trc);
    851  importEntries.trace(trc);
    852  exportEntries.trace(trc);
    853  importBindings.trace(trc);
    854  TraceNullableEdge(trc, &topLevelCapability,
    855                    "CyclicModuleFields::topLevelCapability");
    856  TraceNullableEdge(trc, &asyncParentModules,
    857                    "CyclicModuleFields::asyncParentModules");
    858  TraceNullableEdge(trc, &cycleRoot, "CyclicModuleFields::cycleRoot");
    859 }
    860 
    861 void CyclicModuleFields::initExportEntries(
    862    MutableHandle<ExportEntryVector> allEntries, uint32_t localExportCount,
    863    uint32_t indirectExportCount, uint32_t starExportCount) {
    864  MOZ_ASSERT(allEntries.length() ==
    865             localExportCount + indirectExportCount + starExportCount);
    866 
    867  exportEntries = std::move(allEntries.get());
    868  indirectExportEntriesStart = localExportCount;
    869  starExportEntriesStart = indirectExportEntriesStart + indirectExportCount;
    870 }
    871 
    872 Span<const ExportEntry> CyclicModuleFields::localExportEntries() const {
    873  MOZ_ASSERT(indirectExportEntriesStart <= exportEntries.length());
    874  return Span(exportEntries.begin(),
    875              exportEntries.begin() + indirectExportEntriesStart);
    876 }
    877 
    878 Span<const ExportEntry> CyclicModuleFields::indirectExportEntries() const {
    879  MOZ_ASSERT(indirectExportEntriesStart <= starExportEntriesStart);
    880  MOZ_ASSERT(starExportEntriesStart <= exportEntries.length());
    881  return Span(exportEntries.begin() + indirectExportEntriesStart,
    882              exportEntries.begin() + starExportEntriesStart);
    883 }
    884 
    885 Span<const ExportEntry> CyclicModuleFields::starExportEntries() const {
    886  MOZ_ASSERT(starExportEntriesStart <= exportEntries.length());
    887  return Span(exportEntries.begin() + starExportEntriesStart,
    888              exportEntries.end());
    889 }
    890 
    891 void CyclicModuleFields::setDfsAncestorIndex(uint32_t index) {
    892  dfsAncestorIndex = index;
    893  hasDfsAncestorIndex = true;
    894 }
    895 
    896 Maybe<uint32_t> CyclicModuleFields::maybeDfsAncestorIndex() const {
    897  return hasDfsAncestorIndex ? Some(dfsAncestorIndex) : Nothing();
    898 }
    899 
    900 void CyclicModuleFields::clearDfsAncestorIndex() {
    901  dfsAncestorIndex = 0;
    902  hasDfsAncestorIndex = false;
    903 }
    904 
    905 void CyclicModuleFields::setPendingAsyncDependencies(uint32_t newValue) {
    906  pendingAsyncDependencies = newValue;
    907  hasPendingAsyncDependencies = true;
    908 }
    909 
    910 Maybe<uint32_t> CyclicModuleFields::maybePendingAsyncDependencies() const {
    911  return hasPendingAsyncDependencies ? Some(pendingAsyncDependencies)
    912                                     : Nothing();
    913 }
    914 
    915 ///////////////////////////////////////////////////////////////////////////
    916 // ModuleObject
    917 
    918 /* static */ const JSClassOps ModuleObject::classOps_ = {
    919    nullptr,                 // addProperty
    920    nullptr,                 // delProperty
    921    nullptr,                 // enumerate
    922    nullptr,                 // newEnumerate
    923    nullptr,                 // resolve
    924    nullptr,                 // mayResolve
    925    ModuleObject::finalize,  // finalize
    926    nullptr,                 // call
    927    nullptr,                 // construct
    928    ModuleObject::trace,     // trace
    929 };
    930 
    931 /* static */ const JSClass ModuleObject::class_ = {
    932    "Module",
    933    JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) |
    934        JSCLASS_BACKGROUND_FINALIZE,
    935    &ModuleObject::classOps_,
    936 };
    937 
    938 /* static */
    939 bool ModuleObject::isInstance(HandleValue value) {
    940  return value.isObject() && value.toObject().is<ModuleObject>();
    941 }
    942 
    943 bool ModuleObject::hasCyclicModuleFields() const {
    944  // This currently only returns false if we GC during initialization.
    945  return !getReservedSlot(CyclicModuleFieldsSlot).isUndefined();
    946 }
    947 
    948 CyclicModuleFields* ModuleObject::cyclicModuleFields() {
    949  MOZ_ASSERT(hasCyclicModuleFields());
    950  void* ptr = getReservedSlot(CyclicModuleFieldsSlot).toPrivate();
    951  MOZ_ASSERT(ptr);
    952  return static_cast<CyclicModuleFields*>(ptr);
    953 }
    954 const CyclicModuleFields* ModuleObject::cyclicModuleFields() const {
    955  return const_cast<ModuleObject*>(this)->cyclicModuleFields();
    956 }
    957 
    958 Span<const RequestedModule> ModuleObject::requestedModules() const {
    959  return cyclicModuleFields()->requestedModules;
    960 }
    961 
    962 Span<const ImportEntry> ModuleObject::importEntries() const {
    963  return cyclicModuleFields()->importEntries;
    964 }
    965 
    966 Span<const ExportEntry> ModuleObject::localExportEntries() const {
    967  return cyclicModuleFields()->localExportEntries();
    968 }
    969 
    970 Span<const ExportEntry> ModuleObject::indirectExportEntries() const {
    971  return cyclicModuleFields()->indirectExportEntries();
    972 }
    973 
    974 Span<const ExportEntry> ModuleObject::starExportEntries() const {
    975  return cyclicModuleFields()->starExportEntries();
    976 }
    977 
    978 const ExportNameVector& ModuleObject::syntheticExportNames() const {
    979  return syntheticModuleFields()->exportNames;
    980 }
    981 
    982 void ModuleObject::initFunctionDeclarations(
    983    UniquePtr<FunctionDeclarationVector> decls) {
    984  cyclicModuleFields()->functionDeclarations = std::move(decls);
    985 }
    986 
    987 /* static */
    988 ModuleObject* ModuleObject::create(JSContext* cx) {
    989  Rooted<UniquePtr<CyclicModuleFields>> fields(cx);
    990  fields = cx->make_unique<CyclicModuleFields>();
    991  if (!fields) {
    992    return nullptr;
    993  }
    994 
    995  ModuleObject* self = NewObjectWithGivenProto<ModuleObject>(cx, nullptr);
    996  if (!self) {
    997    return nullptr;
    998  }
    999 
   1000  InitReservedSlot(self, CyclicModuleFieldsSlot, fields.release(),
   1001                   MemoryUse::ModuleCyclicFields);
   1002 
   1003  return self;
   1004 }
   1005 
   1006 /* static */
   1007 ModuleObject* ModuleObject::createSynthetic(
   1008    JSContext* cx, MutableHandle<ExportNameVector> exportNames) {
   1009  Rooted<UniquePtr<SyntheticModuleFields>> syntheticFields(cx);
   1010  syntheticFields = cx->make_unique<SyntheticModuleFields>();
   1011  if (!syntheticFields) {
   1012    return nullptr;
   1013  }
   1014 
   1015  ModuleObject* self = NewObjectWithGivenProto<ModuleObject>(cx, nullptr);
   1016  if (!self) {
   1017    return nullptr;
   1018  }
   1019 
   1020  InitReservedSlot(self, SyntheticModuleFieldsSlot, syntheticFields.release(),
   1021                   MemoryUse::ModuleSyntheticFields);
   1022 
   1023  self->syntheticModuleFields()->exportNames = std::move(exportNames.get());
   1024 
   1025  return self;
   1026 }
   1027 
   1028 /* static */
   1029 void ModuleObject::finalize(JS::GCContext* gcx, JSObject* obj) {
   1030  ModuleObject* self = &obj->as<ModuleObject>();
   1031  if (self->hasCyclicModuleFields()) {
   1032    gcx->delete_(obj, self->cyclicModuleFields(),
   1033                 MemoryUse::ModuleCyclicFields);
   1034  }
   1035  if (self->hasSyntheticModuleFields()) {
   1036    gcx->delete_(obj, self->syntheticModuleFields(),
   1037                 MemoryUse::ModuleSyntheticFields);
   1038  }
   1039 }
   1040 
   1041 ModuleEnvironmentObject& ModuleObject::initialEnvironment() const {
   1042  Value value = getReservedSlot(EnvironmentSlot);
   1043  return value.toObject().as<ModuleEnvironmentObject>();
   1044 }
   1045 
   1046 ModuleEnvironmentObject* ModuleObject::environment() const {
   1047  // Note that this it's valid to call this even if there was an error
   1048  // evaluating the module.
   1049 
   1050  // According to the spec the environment record is created during linking, but
   1051  // we create it earlier than that.
   1052  if (status() < ModuleStatus::Linked) {
   1053    return nullptr;
   1054  }
   1055 
   1056  return &initialEnvironment();
   1057 }
   1058 
   1059 IndirectBindingMap& ModuleObject::importBindings() {
   1060  return cyclicModuleFields()->importBindings;
   1061 }
   1062 
   1063 ModuleNamespaceObject* ModuleObject::namespace_() {
   1064  Value value = getReservedSlot(NamespaceSlot);
   1065  if (value.isUndefined()) {
   1066    return nullptr;
   1067  }
   1068  return &value.toObject().as<ModuleNamespaceObject>();
   1069 }
   1070 
   1071 ScriptSourceObject* ModuleObject::scriptSourceObject() const {
   1072  return cyclicModuleFields()->scriptSourceObject;
   1073 }
   1074 
   1075 void ModuleObject::initAsyncSlots(JSContext* cx, bool hasTopLevelAwait,
   1076                                  Handle<ListObject*> asyncParentModules) {
   1077  cyclicModuleFields()->hasTopLevelAwait = hasTopLevelAwait;
   1078  cyclicModuleFields()->asyncParentModules = asyncParentModules;
   1079 }
   1080 
   1081 void ModuleObject::initScriptSlots(HandleScript script) {
   1082  MOZ_ASSERT(script);
   1083  MOZ_ASSERT(script->sourceObject());
   1084  MOZ_ASSERT(script->filename());
   1085  initReservedSlot(ScriptSlot, PrivateGCThingValue(script));
   1086  cyclicModuleFields()->scriptSourceObject = script->sourceObject();
   1087 }
   1088 
   1089 void ModuleObject::setInitialEnvironment(
   1090    Handle<ModuleEnvironmentObject*> initialEnvironment) {
   1091  initReservedSlot(EnvironmentSlot, ObjectValue(*initialEnvironment));
   1092 }
   1093 
   1094 void ModuleObject::initImportExportData(
   1095    MutableHandle<RequestedModuleVector> requestedModules,
   1096    MutableHandle<ImportEntryVector> importEntries,
   1097    MutableHandle<ExportEntryVector> exportEntries, uint32_t localExportCount,
   1098    uint32_t indirectExportCount, uint32_t starExportCount) {
   1099  cyclicModuleFields()->requestedModules = std::move(requestedModules.get());
   1100  cyclicModuleFields()->importEntries = std::move(importEntries.get());
   1101  cyclicModuleFields()->initExportEntries(exportEntries, localExportCount,
   1102                                          indirectExportCount, starExportCount);
   1103 }
   1104 
   1105 /* static */
   1106 bool ModuleObject::Freeze(JSContext* cx, Handle<ModuleObject*> self) {
   1107  return FreezeObject(cx, self);
   1108 }
   1109 
   1110 #ifdef DEBUG
   1111 /* static */ inline bool ModuleObject::AssertFrozen(
   1112    JSContext* cx, Handle<ModuleObject*> self) {
   1113  bool frozen = false;
   1114  if (!TestIntegrityLevel(cx, self, IntegrityLevel::Frozen, &frozen)) {
   1115    return false;
   1116  }
   1117  MOZ_ASSERT(frozen);
   1118 
   1119  return true;
   1120 }
   1121 #endif
   1122 
   1123 JSScript* ModuleObject::maybeScript() const {
   1124  Value value = getReservedSlot(ScriptSlot);
   1125  if (value.isUndefined()) {
   1126    return nullptr;
   1127  }
   1128  BaseScript* script = value.toGCThing()->as<BaseScript>();
   1129  MOZ_ASSERT(script->hasBytecode(),
   1130             "Module scripts should always have bytecode");
   1131  return script->asJSScript();
   1132 }
   1133 
   1134 JSScript* ModuleObject::script() const {
   1135  JSScript* ptr = maybeScript();
   1136  MOZ_RELEASE_ASSERT(ptr);
   1137  return ptr;
   1138 }
   1139 
   1140 const char* ModuleObject::filename() const {
   1141  // The ScriptSlot will be cleared once the module is evaluated, so we try to
   1142  // get the filename from cyclicModuleFields().
   1143 
   1144  // TODO: Bug 1885483: Provide filename for JSON modules
   1145  if (!hasCyclicModuleFields()) {
   1146    return "(JSON module)";
   1147  }
   1148  return cyclicModuleFields()->scriptSourceObject->source()->filename();
   1149 }
   1150 
   1151 static inline void AssertValidModuleStatus(ModuleStatus status) {
   1152  MOZ_ASSERT(status >= ModuleStatus::New &&
   1153             status <= ModuleStatus::Evaluated_Error);
   1154 }
   1155 
   1156 ModuleStatus ModuleObject::status() const {
   1157  // Always return `ModuleStatus::Evaluated` so we can assert a module's status
   1158  // without checking which kind it is, even though synthetic modules don't have
   1159  // this field according to the spec.
   1160  if (hasSyntheticModuleFields()) {
   1161    return ModuleStatus::Evaluated;
   1162  }
   1163 
   1164  ModuleStatus status = cyclicModuleFields()->status;
   1165  AssertValidModuleStatus(status);
   1166 
   1167  if (status == ModuleStatus::Evaluated_Error) {
   1168    return ModuleStatus::Evaluated;
   1169  }
   1170 
   1171  return status;
   1172 }
   1173 
   1174 void ModuleObject::setStatus(ModuleStatus newStatus) {
   1175  AssertValidModuleStatus(newStatus);
   1176 
   1177  // Note that under OOM conditions we can fail the module linking process even
   1178  // after modules have been marked as linked.
   1179  MOZ_ASSERT((status() <= ModuleStatus::Linked &&
   1180              newStatus == ModuleStatus::Unlinked) ||
   1181                 newStatus > status(),
   1182             "New module status inconsistent with current status");
   1183 
   1184  cyclicModuleFields()->status = newStatus;
   1185 }
   1186 
   1187 bool ModuleObject::hasTopLevelAwait() const {
   1188  return cyclicModuleFields()->hasTopLevelAwait;
   1189 }
   1190 
   1191 AsyncEvaluationOrder& ModuleObject::asyncEvaluationOrder() {
   1192  return cyclicModuleFields()->asyncEvaluationOrder;
   1193 }
   1194 
   1195 AsyncEvaluationOrder const& ModuleObject::asyncEvaluationOrder() const {
   1196  return cyclicModuleFields()->asyncEvaluationOrder;
   1197 }
   1198 
   1199 Maybe<uint32_t> ModuleObject::maybeDfsAncestorIndex() const {
   1200  return cyclicModuleFields()->maybeDfsAncestorIndex();
   1201 }
   1202 
   1203 uint32_t ModuleObject::dfsAncestorIndex() const {
   1204  return maybeDfsAncestorIndex().value();
   1205 }
   1206 
   1207 void ModuleObject::setDfsAncestorIndex(uint32_t index) {
   1208  cyclicModuleFields()->setDfsAncestorIndex(index);
   1209 }
   1210 
   1211 void ModuleObject::clearDfsAncestorIndex() {
   1212  cyclicModuleFields()->clearDfsAncestorIndex();
   1213 }
   1214 
   1215 PromiseObject* ModuleObject::maybeTopLevelCapability() const {
   1216  return cyclicModuleFields()->topLevelCapability;
   1217 }
   1218 
   1219 PromiseObject* ModuleObject::topLevelCapability() const {
   1220  PromiseObject* capability = maybeTopLevelCapability();
   1221  MOZ_RELEASE_ASSERT(capability);
   1222  return capability;
   1223 }
   1224 
   1225 // static
   1226 PromiseObject* ModuleObject::createTopLevelCapability(
   1227    JSContext* cx, Handle<ModuleObject*> module) {
   1228  MOZ_ASSERT(!module->maybeTopLevelCapability());
   1229 
   1230  Rooted<PromiseObject*> resultPromise(cx, CreatePromiseObjectForAsync(cx));
   1231  if (!resultPromise) {
   1232    return nullptr;
   1233  }
   1234 
   1235  module->setInitialTopLevelCapability(resultPromise);
   1236  return resultPromise;
   1237 }
   1238 
   1239 void ModuleObject::setInitialTopLevelCapability(
   1240    Handle<PromiseObject*> capability) {
   1241  cyclicModuleFields()->topLevelCapability = capability;
   1242 }
   1243 
   1244 ListObject* ModuleObject::asyncParentModules() const {
   1245  return cyclicModuleFields()->asyncParentModules;
   1246 }
   1247 
   1248 bool ModuleObject::appendAsyncParentModule(JSContext* cx,
   1249                                           Handle<ModuleObject*> self,
   1250                                           Handle<ModuleObject*> parent) {
   1251  Rooted<Value> parentValue(cx, ObjectValue(*parent));
   1252  return self->asyncParentModules()->append(cx, parentValue);
   1253 }
   1254 
   1255 Maybe<uint32_t> ModuleObject::maybePendingAsyncDependencies() const {
   1256  return cyclicModuleFields()->maybePendingAsyncDependencies();
   1257 }
   1258 
   1259 uint32_t ModuleObject::pendingAsyncDependencies() const {
   1260  return maybePendingAsyncDependencies().value();
   1261 }
   1262 
   1263 void ModuleObject::setPendingAsyncDependencies(uint32_t newValue) {
   1264  cyclicModuleFields()->setPendingAsyncDependencies(newValue);
   1265 }
   1266 
   1267 void ModuleObject::setCycleRoot(ModuleObject* cycleRoot) {
   1268  cyclicModuleFields()->cycleRoot = cycleRoot;
   1269 }
   1270 
   1271 ModuleObject* ModuleObject::getCycleRoot() const {
   1272  MOZ_RELEASE_ASSERT(cyclicModuleFields()->cycleRoot);
   1273  return cyclicModuleFields()->cycleRoot;
   1274 }
   1275 
   1276 LoadedModuleMap& ModuleObject::loadedModules() {
   1277  return cyclicModuleFields()->loadedModules;
   1278 }
   1279 
   1280 const LoadedModuleMap& ModuleObject::loadedModules() const {
   1281  return cyclicModuleFields()->loadedModules;
   1282 }
   1283 
   1284 bool ModuleObject::hasSyntheticModuleFields() const {
   1285  bool result = !getReservedSlot(SyntheticModuleFieldsSlot).isUndefined();
   1286  MOZ_ASSERT_IF(result, !hasCyclicModuleFields());
   1287  return result;
   1288 }
   1289 
   1290 SyntheticModuleFields* ModuleObject::syntheticModuleFields() {
   1291  MOZ_ASSERT(!hasCyclicModuleFields());
   1292  void* ptr = getReservedSlot(SyntheticModuleFieldsSlot).toPrivate();
   1293  MOZ_ASSERT(ptr);
   1294  return static_cast<SyntheticModuleFields*>(ptr);
   1295 }
   1296 const SyntheticModuleFields* ModuleObject::syntheticModuleFields() const {
   1297  return const_cast<ModuleObject*>(this)->syntheticModuleFields();
   1298 }
   1299 
   1300 bool ModuleObject::hasTopLevelCapability() const {
   1301  return cyclicModuleFields()->topLevelCapability;
   1302 }
   1303 
   1304 bool ModuleObject::hadEvaluationError() const {
   1305  if (hasSyntheticModuleFields()) {
   1306    return false;
   1307  }
   1308 
   1309  ModuleStatus fullStatus = cyclicModuleFields()->status;
   1310  return fullStatus == ModuleStatus::Evaluated_Error;
   1311 }
   1312 
   1313 void ModuleObject::setEvaluationError(HandleValue newValue) {
   1314  MOZ_ASSERT(status() != ModuleStatus::Unlinked &&
   1315             status() != ModuleStatus::New);
   1316  MOZ_ASSERT(!hadEvaluationError());
   1317 
   1318  cyclicModuleFields()->status = ModuleStatus::Evaluated_Error;
   1319  cyclicModuleFields()->evaluationError = newValue;
   1320 
   1321  MOZ_ASSERT(status() == ModuleStatus::Evaluated);
   1322  MOZ_ASSERT(hadEvaluationError());
   1323 }
   1324 
   1325 Value ModuleObject::maybeEvaluationError() const {
   1326  return cyclicModuleFields()->evaluationError;
   1327 }
   1328 
   1329 Value ModuleObject::evaluationError() const {
   1330  MOZ_ASSERT(hadEvaluationError());
   1331  return maybeEvaluationError();
   1332 }
   1333 
   1334 JSObject* ModuleObject::metaObject() const {
   1335  return cyclicModuleFields()->metaObject;
   1336 }
   1337 
   1338 void ModuleObject::setMetaObject(JSObject* obj) {
   1339  MOZ_ASSERT(obj);
   1340  MOZ_ASSERT(!metaObject());
   1341  cyclicModuleFields()->metaObject = obj;
   1342 }
   1343 
   1344 /* static */
   1345 void ModuleObject::trace(JSTracer* trc, JSObject* obj) {
   1346  ModuleObject& module = obj->as<ModuleObject>();
   1347  if (module.hasCyclicModuleFields()) {
   1348    module.cyclicModuleFields()->trace(trc);
   1349  }
   1350  if (module.hasSyntheticModuleFields()) {
   1351    module.syntheticModuleFields()->trace(trc);
   1352  }
   1353 }
   1354 
   1355 /* static */
   1356 bool ModuleObject::instantiateFunctionDeclarations(JSContext* cx,
   1357                                                   Handle<ModuleObject*> self) {
   1358 #ifdef DEBUG
   1359  MOZ_ASSERT(self->status() == ModuleStatus::Linking);
   1360  if (!AssertFrozen(cx, self)) {
   1361    return false;
   1362  }
   1363 #endif
   1364  // |self| initially manages this vector.
   1365  UniquePtr<FunctionDeclarationVector>& funDecls =
   1366      self->cyclicModuleFields()->functionDeclarations;
   1367  if (!funDecls) {
   1368    JS_ReportErrorASCII(
   1369        cx, "Module function declarations have already been instantiated");
   1370    return false;
   1371  }
   1372 
   1373  Rooted<ModuleEnvironmentObject*> env(cx, &self->initialEnvironment());
   1374  RootedObject obj(cx);
   1375  RootedValue value(cx);
   1376  RootedFunction fun(cx);
   1377  Rooted<PropertyName*> name(cx);
   1378 
   1379  for (GCThingIndex funIndex : *funDecls) {
   1380    fun.set(self->script()->getFunction(funIndex));
   1381    obj = Lambda(cx, fun, env);
   1382    if (!obj) {
   1383      return false;
   1384    }
   1385 
   1386    name = fun->fullExplicitName()->asPropertyName();
   1387    value = ObjectValue(*obj);
   1388    if (!SetProperty(cx, env, name, value)) {
   1389      return false;
   1390    }
   1391  }
   1392 
   1393  // Free the vector, now its contents are no longer needed.
   1394  funDecls.reset();
   1395 
   1396  return true;
   1397 }
   1398 
   1399 /* static */
   1400 bool ModuleObject::execute(JSContext* cx, Handle<ModuleObject*> self) {
   1401 #ifdef DEBUG
   1402  MOZ_ASSERT(self->status() == ModuleStatus::Evaluating ||
   1403             self->status() == ModuleStatus::EvaluatingAsync ||
   1404             self->status() == ModuleStatus::Evaluated);
   1405  MOZ_ASSERT(!self->hadEvaluationError());
   1406  if (!AssertFrozen(cx, self)) {
   1407    return false;
   1408  }
   1409 #endif
   1410 
   1411  RootedScript script(cx, self->script());
   1412 
   1413  auto guardA = mozilla::MakeScopeExit([&] {
   1414    if (self->hasTopLevelAwait()) {
   1415      // Handled in AsyncModuleExecutionFulfilled and
   1416      // AsyncModuleExecutionRejected.
   1417      return;
   1418    }
   1419    ModuleObject::onTopLevelEvaluationFinished(self);
   1420  });
   1421 
   1422  Rooted<ModuleEnvironmentObject*> env(cx, self->environment());
   1423  if (!env) {
   1424    JS_ReportErrorASCII(cx,
   1425                        "Module declarations have not yet been instantiated");
   1426    return false;
   1427  }
   1428 
   1429  Rooted<Value> ignored(cx);
   1430  return Execute(cx, script, env, &ignored);
   1431 }
   1432 
   1433 /* static */
   1434 void ModuleObject::onTopLevelEvaluationFinished(ModuleObject* module) {
   1435  // ScriptSlot is used by debugger to access environments during evaluating
   1436  // the top-level script.
   1437  // Clear the reference at exit to prevent us keeping this alive unnecessarily.
   1438  module->setReservedSlot(ScriptSlot, UndefinedValue());
   1439 }
   1440 
   1441 /* static */
   1442 ModuleNamespaceObject* ModuleObject::createNamespace(
   1443    JSContext* cx, Handle<ModuleObject*> self,
   1444    MutableHandle<UniquePtr<ExportNameVector>> exports) {
   1445  MOZ_ASSERT(!self->namespace_());
   1446 
   1447  Rooted<UniquePtr<IndirectBindingMap>> bindings(cx);
   1448  bindings = cx->make_unique<IndirectBindingMap>();
   1449  if (!bindings) {
   1450    return nullptr;
   1451  }
   1452 
   1453  auto* ns = ModuleNamespaceObject::create(cx, self, exports, &bindings);
   1454  if (!ns) {
   1455    return nullptr;
   1456  }
   1457 
   1458  self->initReservedSlot(NamespaceSlot, ObjectValue(*ns));
   1459  return ns;
   1460 }
   1461 
   1462 /* static */
   1463 bool ModuleObject::createEnvironment(JSContext* cx,
   1464                                     Handle<ModuleObject*> self) {
   1465  Rooted<ModuleEnvironmentObject*> env(
   1466      cx, ModuleEnvironmentObject::create(cx, self));
   1467  if (!env) {
   1468    return false;
   1469  }
   1470 
   1471  self->setInitialEnvironment(env);
   1472  return true;
   1473 }
   1474 
   1475 /*static*/
   1476 bool ModuleObject::createSyntheticEnvironment(JSContext* cx,
   1477                                              Handle<ModuleObject*> self,
   1478                                              JS::HandleVector<Value> values) {
   1479  Rooted<ModuleEnvironmentObject*> env(
   1480      cx, ModuleEnvironmentObject::createSynthetic(cx, self));
   1481  if (!env) {
   1482    return false;
   1483  }
   1484 
   1485  MOZ_ASSERT(env->shape()->propMapLength() == values.length());
   1486 
   1487  for (uint32_t i = 0; i < values.length(); i++) {
   1488    env->setAliasedBinding(env->firstSyntheticValueSlot() + i, values[i]);
   1489  }
   1490 
   1491  self->setInitialEnvironment(env);
   1492 
   1493  return true;
   1494 }
   1495 
   1496 ///////////////////////////////////////////////////////////////////////////
   1497 // GraphLoadingStateRecordObject
   1498 
   1499 GraphLoadingStateRecord::GraphLoadingStateRecord(
   1500    JS::LoadModuleResolvedCallback resolved,
   1501    JS::LoadModuleRejectedCallback rejected)
   1502    : resolved(resolved), rejected(rejected) {}
   1503 
   1504 void GraphLoadingStateRecord::trace(JSTracer* trc) { visited.trace(trc); }
   1505 
   1506 /* static */
   1507 const JSClass GraphLoadingStateRecordObject::class_ = {
   1508    "GraphLoadingStateRecordObject",
   1509    JSCLASS_HAS_RESERVED_SLOTS(GraphLoadingStateRecordObject::SlotCount) |
   1510        JSCLASS_BACKGROUND_FINALIZE,
   1511    &GraphLoadingStateRecordObject::classOps_,
   1512 };
   1513 static_assert(GraphLoadingStateRecordObject::StateSlot == 0);
   1514 
   1515 /* static */
   1516 const JSClassOps GraphLoadingStateRecordObject::classOps_ = {
   1517    nullptr,                                  // addProperty
   1518    nullptr,                                  // delProperty
   1519    nullptr,                                  // enumerate
   1520    nullptr,                                  // newEnumerate
   1521    nullptr,                                  // resolve
   1522    nullptr,                                  // mayResolve
   1523    GraphLoadingStateRecordObject::finalize,  // finalize
   1524    nullptr,                                  // call
   1525    nullptr,                                  // construct
   1526    GraphLoadingStateRecordObject::trace,     // trace
   1527 };
   1528 
   1529 /* static */
   1530 GraphLoadingStateRecordObject* GraphLoadingStateRecordObject::create(
   1531    JSContext* cx, bool isLoading, uint32_t pendingModulesCount,
   1532    JS::LoadModuleResolvedCallback resolved,
   1533    JS::LoadModuleRejectedCallback rejected, Handle<Value> hostDefined) {
   1534  Rooted<GraphLoadingStateRecordObject*> self(
   1535      cx, NewObjectWithGivenProto<GraphLoadingStateRecordObject>(cx, nullptr));
   1536  if (!self) {
   1537    return nullptr;
   1538  }
   1539 
   1540  auto* state = cx->new_<GraphLoadingStateRecord>(resolved, rejected);
   1541  if (!state) {
   1542    ReportOutOfMemory(cx);
   1543    return nullptr;
   1544  }
   1545 
   1546  InitReservedSlot(self, StateSlot, state, MemoryUse::GraphLoadingStateRecord);
   1547  self->initReservedSlot(IsLoadingSlot, Int32Value(isLoading));
   1548  self->initReservedSlot(PendingModulesCountSlot,
   1549                         Int32Value(pendingModulesCount));
   1550  self->initReservedSlot(HostDefinedSlot, hostDefined);
   1551  return self;
   1552 }
   1553 
   1554 /* static */
   1555 GraphLoadingStateRecordObject* GraphLoadingStateRecordObject::create(
   1556    JSContext* cx, bool isLoading, uint32_t pendingModulesCount,
   1557    Handle<PromiseObject*> promise, Handle<Value> hostDefined) {
   1558  Rooted<GraphLoadingStateRecordObject*> self(
   1559      cx, NewObjectWithGivenProto<GraphLoadingStateRecordObject>(cx, nullptr));
   1560  if (!self) {
   1561    return nullptr;
   1562  }
   1563 
   1564  auto* state = cx->new_<GraphLoadingStateRecord>();
   1565  if (!state) {
   1566    ReportOutOfMemory(cx);
   1567    return nullptr;
   1568  }
   1569 
   1570  InitReservedSlot(self, StateSlot, state, MemoryUse::GraphLoadingStateRecord);
   1571  self->initReservedSlot(PromiseSlot, ObjectValue(*promise));
   1572  self->initReservedSlot(IsLoadingSlot, Int32Value(isLoading));
   1573  self->initReservedSlot(PendingModulesCountSlot,
   1574                         Int32Value(pendingModulesCount));
   1575  self->initReservedSlot(HostDefinedSlot, hostDefined);
   1576  return self;
   1577 }
   1578 
   1579 VisitedModuleSet& GraphLoadingStateRecordObject::visited() {
   1580  GraphLoadingStateRecord* state = static_cast<GraphLoadingStateRecord*>(
   1581      getReservedSlot(StateSlot).toPrivate());
   1582  MOZ_ASSERT(state);
   1583  return state->visited;
   1584 }
   1585 
   1586 PromiseObject* GraphLoadingStateRecordObject::promise() {
   1587  if (getReservedSlot(PromiseSlot).isUndefined()) {
   1588    return nullptr;
   1589  }
   1590  return &getReservedSlot(PromiseSlot).toObject().as<PromiseObject>();
   1591 }
   1592 
   1593 bool GraphLoadingStateRecordObject::isLoading() {
   1594  return getReservedSlot(IsLoadingSlot).toInt32();
   1595 }
   1596 
   1597 void GraphLoadingStateRecordObject::setIsLoading(bool isLoading) {
   1598  setReservedSlot(IsLoadingSlot, Int32Value(isLoading));
   1599 }
   1600 
   1601 uint32_t GraphLoadingStateRecordObject::pendingModulesCount() {
   1602  return getReservedSlot(PendingModulesCountSlot).toInt32();
   1603 }
   1604 
   1605 void GraphLoadingStateRecordObject::setPendingModulesCount(uint32_t count) {
   1606  setReservedSlot(PendingModulesCountSlot, Int32Value(count));
   1607 }
   1608 
   1609 Value GraphLoadingStateRecordObject::hostDefined() {
   1610  return getReservedSlot(HostDefinedSlot);
   1611 }
   1612 
   1613 bool GraphLoadingStateRecordObject::resolved(
   1614    JSContext* cx, JS::Handle<JS::Value> hostDefined) {
   1615  if (promise()) {
   1616    Rooted<PromiseObject*> promiseObj(cx, promise());
   1617    return AsyncFunctionReturned(cx, promiseObj, UndefinedHandleValue);
   1618  }
   1619 
   1620  GraphLoadingStateRecord* state = static_cast<GraphLoadingStateRecord*>(
   1621      getReservedSlot(StateSlot).toPrivate());
   1622  MOZ_ASSERT(state);
   1623  MOZ_ASSERT(state->resolved);
   1624  return state->resolved(cx, hostDefined);
   1625 }
   1626 
   1627 bool GraphLoadingStateRecordObject::rejected(JSContext* cx,
   1628                                             JS::Handle<JS::Value> hostDefined,
   1629                                             Handle<JS::Value> error) {
   1630  if (promise()) {
   1631    Rooted<PromiseObject*> promiseObj(cx, promise());
   1632    return AsyncFunctionThrown(cx, promiseObj, error);
   1633  }
   1634 
   1635  GraphLoadingStateRecord* state = static_cast<GraphLoadingStateRecord*>(
   1636      getReservedSlot(StateSlot).toPrivate());
   1637  MOZ_ASSERT(state);
   1638  MOZ_ASSERT(state->rejected);
   1639  return state->rejected(cx, hostDefined, error);
   1640 }
   1641 
   1642 /* static */
   1643 void GraphLoadingStateRecordObject::finalize(JS::GCContext* gcx,
   1644                                             JSObject* obj) {
   1645  auto* self = &obj->as<GraphLoadingStateRecordObject>();
   1646  Value stateValue = self->getReservedSlot(StateSlot);
   1647  if (!stateValue.isUndefined()) {
   1648    auto* state = static_cast<GraphLoadingStateRecord*>(stateValue.toPrivate());
   1649    gcx->delete_(obj, state, MemoryUse::GraphLoadingStateRecord);
   1650  }
   1651 }
   1652 
   1653 /* static */
   1654 void GraphLoadingStateRecordObject::trace(JSTracer* trc, JSObject* obj) {
   1655  GraphLoadingStateRecordObject* self =
   1656      &obj->as<GraphLoadingStateRecordObject>();
   1657  Value stateValue = self->getReservedSlot(StateSlot);
   1658  if (!stateValue.isUndefined()) {
   1659    GraphLoadingStateRecord* state =
   1660        static_cast<GraphLoadingStateRecord*>(stateValue.toPrivate());
   1661    state->trace(trc);
   1662  }
   1663 }
   1664 
   1665 ///////////////////////////////////////////////////////////////////////////
   1666 // ModuleBuilder
   1667 
   1668 ModuleBuilder::ModuleBuilder(FrontendContext* fc,
   1669                             const frontend::EitherParser& eitherParser)
   1670    : fc_(fc),
   1671      eitherParser_(eitherParser),
   1672      requestedModuleIndexes_(fc),
   1673      importEntries_(fc),
   1674      exportEntries_(fc),
   1675      exportNames_(fc) {}
   1676 
   1677 bool ModuleBuilder::noteFunctionDeclaration(FrontendContext* fc,
   1678                                            uint32_t funIndex) {
   1679  if (!functionDecls_.emplaceBack(funIndex)) {
   1680    js::ReportOutOfMemory(fc);
   1681    return false;
   1682  }
   1683  return true;
   1684 }
   1685 
   1686 void ModuleBuilder::noteAsync(frontend::StencilModuleMetadata& metadata) {
   1687  metadata.isAsync = true;
   1688 }
   1689 
   1690 bool ModuleBuilder::buildTables(frontend::StencilModuleMetadata& metadata) {
   1691  // https://tc39.es/ecma262/#sec-parsemodule
   1692  // 15.2.1.17.1 ParseModule, Steps 4-11.
   1693 
   1694  // Step 4.
   1695  metadata.moduleRequests = std::move(moduleRequests_);
   1696  metadata.requestedModules = std::move(requestedModules_);
   1697 
   1698  // Step 5.
   1699  if (!metadata.importEntries.reserve(importEntries_.count())) {
   1700    js::ReportOutOfMemory(fc_);
   1701    return false;
   1702  }
   1703  for (auto r = importEntries_.all(); !r.empty(); r.popFront()) {
   1704    frontend::StencilModuleEntry& entry = r.front().value();
   1705    metadata.importEntries.infallibleAppend(entry);
   1706  }
   1707 
   1708  // Steps 6-11.
   1709  for (const frontend::StencilModuleEntry& exp : exportEntries_) {
   1710    if (!exp.moduleRequest) {
   1711      frontend::StencilModuleEntry* importEntry = importEntryFor(exp.localName);
   1712      if (!importEntry) {
   1713        if (!metadata.localExportEntries.append(exp)) {
   1714          js::ReportOutOfMemory(fc_);
   1715          return false;
   1716        }
   1717      } else {
   1718        // All names should have already been marked as used-by-stencil.
   1719        if (!importEntry->importName) {
   1720          // This is a re-export of an imported module namespace object.
   1721          auto entry = frontend::StencilModuleEntry::exportNamespaceFromEntry(
   1722              importEntry->moduleRequest, exp.exportName, exp.lineno,
   1723              exp.column);
   1724          if (!metadata.indirectExportEntries.append(entry)) {
   1725            js::ReportOutOfMemory(fc_);
   1726            return false;
   1727          }
   1728        } else {
   1729          auto entry = frontend::StencilModuleEntry::exportFromEntry(
   1730              importEntry->moduleRequest, importEntry->importName,
   1731              exp.exportName, exp.lineno, exp.column);
   1732          if (!metadata.indirectExportEntries.append(entry)) {
   1733            js::ReportOutOfMemory(fc_);
   1734            return false;
   1735          }
   1736        }
   1737      }
   1738    } else if (!exp.importName && !exp.exportName) {
   1739      if (!metadata.starExportEntries.append(exp)) {
   1740        js::ReportOutOfMemory(fc_);
   1741        return false;
   1742      }
   1743    } else {
   1744      if (!metadata.indirectExportEntries.append(exp)) {
   1745        js::ReportOutOfMemory(fc_);
   1746        return false;
   1747      }
   1748    }
   1749  }
   1750 
   1751  return true;
   1752 }
   1753 
   1754 void ModuleBuilder::finishFunctionDecls(
   1755    frontend::StencilModuleMetadata& metadata) {
   1756  metadata.functionDecls = std::move(functionDecls_);
   1757 }
   1758 
   1759 bool frontend::StencilModuleMetadata::createModuleRequestObjects(
   1760    JSContext* cx, CompilationAtomCache& atomCache,
   1761    MutableHandle<ModuleRequestVector> output) const {
   1762  if (!output.reserve(moduleRequests.length())) {
   1763    ReportOutOfMemory(cx);
   1764    return false;
   1765  }
   1766 
   1767  Rooted<ModuleRequestObject*> object(cx);
   1768  for (const StencilModuleRequest& request : moduleRequests) {
   1769    object = createModuleRequestObject(cx, atomCache, request);
   1770    if (!object) {
   1771      return false;
   1772    }
   1773 
   1774    output.infallibleEmplaceBack(object);
   1775  }
   1776 
   1777  return true;
   1778 }
   1779 
   1780 ModuleRequestObject* frontend::StencilModuleMetadata::createModuleRequestObject(
   1781    JSContext* cx, CompilationAtomCache& atomCache,
   1782    const StencilModuleRequest& request) const {
   1783  uint32_t numberOfAttributes = request.attributes.length();
   1784 
   1785  Rooted<ImportAttributeVector> attributes(cx);
   1786  if (numberOfAttributes > 0) {
   1787    if (!attributes.reserve(numberOfAttributes)) {
   1788      ReportOutOfMemory(cx);
   1789      return nullptr;
   1790    }
   1791 
   1792    Rooted<JSAtom*> attributeKey(cx);
   1793    Rooted<JSAtom*> attributeValue(cx);
   1794    for (uint32_t j = 0; j < numberOfAttributes; ++j) {
   1795      attributeKey = atomCache.getExistingAtomAt(cx, request.attributes[j].key);
   1796      attributeValue =
   1797          atomCache.getExistingAtomAt(cx, request.attributes[j].value);
   1798 
   1799      attributes.infallibleEmplaceBack(attributeKey, attributeValue);
   1800    }
   1801  }
   1802 
   1803  Rooted<JSAtom*> specifier(cx,
   1804                            atomCache.getExistingAtomAt(cx, request.specifier));
   1805  MOZ_ASSERT(specifier);
   1806 
   1807  Rooted<ModuleRequestObject*> moduleRequestObject(
   1808      cx, ModuleRequestObject::create(cx, specifier, attributes));
   1809  if (!moduleRequestObject) {
   1810    return nullptr;
   1811  }
   1812 
   1813  if (request.firstUnsupportedAttributeKey) {
   1814    Rooted<JSAtom*> unsupportedAttributeKey(
   1815        cx,
   1816        atomCache.getExistingAtomAt(cx, request.firstUnsupportedAttributeKey));
   1817    moduleRequestObject->setFirstUnsupportedAttributeKey(
   1818        unsupportedAttributeKey);
   1819  }
   1820 
   1821  return moduleRequestObject;
   1822 }
   1823 
   1824 bool frontend::StencilModuleMetadata::createImportEntries(
   1825    JSContext* cx, CompilationAtomCache& atomCache,
   1826    Handle<ModuleRequestVector> moduleRequests,
   1827    MutableHandle<ImportEntryVector> output) const {
   1828  if (!output.reserve(importEntries.length())) {
   1829    ReportOutOfMemory(cx);
   1830    return false;
   1831  }
   1832 
   1833  for (const StencilModuleEntry& entry : importEntries) {
   1834    Rooted<ModuleRequestObject*> moduleRequest(cx);
   1835    moduleRequest = moduleRequests[entry.moduleRequest.value()].get();
   1836    MOZ_ASSERT(moduleRequest);
   1837 
   1838    Rooted<JSAtom*> localName(cx);
   1839    if (entry.localName) {
   1840      localName = atomCache.getExistingAtomAt(cx, entry.localName);
   1841      MOZ_ASSERT(localName);
   1842    }
   1843 
   1844    Rooted<JSAtom*> importName(cx);
   1845    if (entry.importName) {
   1846      importName = atomCache.getExistingAtomAt(cx, entry.importName);
   1847      MOZ_ASSERT(importName);
   1848    }
   1849 
   1850    MOZ_ASSERT(!entry.exportName);
   1851 
   1852    output.infallibleEmplaceBack(moduleRequest, importName, localName,
   1853                                 entry.lineno, entry.column);
   1854  }
   1855 
   1856  return true;
   1857 }
   1858 
   1859 bool frontend::StencilModuleMetadata::createExportEntries(
   1860    JSContext* cx, frontend::CompilationAtomCache& atomCache,
   1861    Handle<ModuleRequestVector> moduleRequests,
   1862    const frontend::StencilModuleMetadata::EntryVector& input,
   1863    MutableHandle<ExportEntryVector> output) const {
   1864  if (!output.reserve(output.length() + input.length())) {
   1865    ReportOutOfMemory(cx);
   1866    return false;
   1867  }
   1868 
   1869  for (const frontend::StencilModuleEntry& entry : input) {
   1870    Rooted<JSAtom*> exportName(cx);
   1871    if (entry.exportName) {
   1872      exportName = atomCache.getExistingAtomAt(cx, entry.exportName);
   1873      MOZ_ASSERT(exportName);
   1874    }
   1875 
   1876    Rooted<ModuleRequestObject*> moduleRequestObject(cx);
   1877    if (entry.moduleRequest) {
   1878      moduleRequestObject = moduleRequests[entry.moduleRequest.value()].get();
   1879      MOZ_ASSERT(moduleRequestObject);
   1880    }
   1881 
   1882    Rooted<JSAtom*> localName(cx);
   1883    if (entry.localName) {
   1884      localName = atomCache.getExistingAtomAt(cx, entry.localName);
   1885      MOZ_ASSERT(localName);
   1886    }
   1887 
   1888    Rooted<JSAtom*> importName(cx);
   1889    if (entry.importName) {
   1890      importName = atomCache.getExistingAtomAt(cx, entry.importName);
   1891      MOZ_ASSERT(importName);
   1892    }
   1893 
   1894    output.infallibleEmplaceBack(exportName, moduleRequestObject, importName,
   1895                                 localName, entry.lineno, entry.column);
   1896  }
   1897 
   1898  return true;
   1899 }
   1900 
   1901 bool frontend::StencilModuleMetadata::createRequestedModules(
   1902    JSContext* cx, CompilationAtomCache& atomCache,
   1903    Handle<ModuleRequestVector> moduleRequests,
   1904    MutableHandle<RequestedModuleVector> output) const {
   1905  if (!output.reserve(requestedModules.length())) {
   1906    ReportOutOfMemory(cx);
   1907    return false;
   1908  }
   1909 
   1910  for (const frontend::StencilModuleEntry& entry : requestedModules) {
   1911    Rooted<ModuleRequestObject*> moduleRequest(cx);
   1912    moduleRequest = moduleRequests[entry.moduleRequest.value()].get();
   1913    MOZ_ASSERT(moduleRequest);
   1914 
   1915    MOZ_ASSERT(!entry.localName);
   1916    MOZ_ASSERT(!entry.importName);
   1917    MOZ_ASSERT(!entry.exportName);
   1918 
   1919    output.infallibleEmplaceBack(moduleRequest, entry.lineno, entry.column);
   1920  }
   1921 
   1922  return true;
   1923 }
   1924 
   1925 // Use StencilModuleMetadata data to fill in ModuleObject
   1926 bool frontend::StencilModuleMetadata::initModule(
   1927    JSContext* cx, FrontendContext* fc,
   1928    frontend::CompilationAtomCache& atomCache,
   1929    JS::Handle<ModuleObject*> module) const {
   1930  Rooted<ModuleRequestVector> moduleRequestsVector(cx);
   1931  if (!createModuleRequestObjects(cx, atomCache, &moduleRequestsVector)) {
   1932    return false;
   1933  }
   1934 
   1935  Rooted<RequestedModuleVector> requestedModulesVector(cx);
   1936  if (!createRequestedModules(cx, atomCache, moduleRequestsVector,
   1937                              &requestedModulesVector)) {
   1938    return false;
   1939  }
   1940 
   1941  Rooted<ImportEntryVector> importEntriesVector(cx);
   1942  if (!createImportEntries(cx, atomCache, moduleRequestsVector,
   1943                           &importEntriesVector)) {
   1944    return false;
   1945  }
   1946 
   1947  Rooted<ExportEntryVector> exportEntriesVector(cx);
   1948  if (!createExportEntries(cx, atomCache, moduleRequestsVector,
   1949                           localExportEntries, &exportEntriesVector)) {
   1950    return false;
   1951  }
   1952 
   1953  Rooted<ExportEntryVector> indirectExportEntriesVector(cx);
   1954  if (!createExportEntries(cx, atomCache, moduleRequestsVector,
   1955                           indirectExportEntries, &exportEntriesVector)) {
   1956    return false;
   1957  }
   1958 
   1959  Rooted<ExportEntryVector> starExportEntriesVector(cx);
   1960  if (!createExportEntries(cx, atomCache, moduleRequestsVector,
   1961                           starExportEntries, &exportEntriesVector)) {
   1962    return false;
   1963  }
   1964 
   1965  // Copy the vector of declarations to the ModuleObject.
   1966  auto functionDeclsCopy = MakeUnique<FunctionDeclarationVector>();
   1967  if (!functionDeclsCopy || !functionDeclsCopy->appendAll(functionDecls)) {
   1968    js::ReportOutOfMemory(fc);
   1969    return false;
   1970  }
   1971  module->initFunctionDeclarations(std::move(functionDeclsCopy));
   1972 
   1973  Rooted<ListObject*> asyncParentModulesList(cx, ListObject::create(cx));
   1974  if (!asyncParentModulesList) {
   1975    return false;
   1976  }
   1977 
   1978  module->initAsyncSlots(cx, isAsync, asyncParentModulesList);
   1979 
   1980  module->initImportExportData(
   1981      &requestedModulesVector, &importEntriesVector, &exportEntriesVector,
   1982      localExportEntries.length(), indirectExportEntries.length(),
   1983      starExportEntries.length());
   1984 
   1985  return true;
   1986 }
   1987 
   1988 bool ModuleBuilder::processAttributes(frontend::StencilModuleRequest& request,
   1989                                      frontend::ListNode* attributeList) {
   1990  using namespace js::frontend;
   1991 
   1992  for (ParseNode* attributeItem : attributeList->contents()) {
   1993    BinaryNode* attribute = &attributeItem->as<BinaryNode>();
   1994    MOZ_ASSERT(attribute->isKind(ParseNodeKind::ImportAttribute));
   1995 
   1996    auto key = attribute->left()->as<NameNode>().atom();
   1997    markUsedByStencil(key);
   1998 
   1999    // Note: This should be driven by a host hook
   2000    // (HostGetSupportedImportAttributes), however the infrastructure of said
   2001    // host hook is deeply unclear, and so right now embedders will not have
   2002    // the ability to alter or extend the set of supported attributes.
   2003    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1840723.
   2004    if (key == TaggedParserAtomIndex::WellKnown::type()) {
   2005      auto value = attribute->right()->as<NameNode>().atom();
   2006      markUsedByStencil(value);
   2007 
   2008      StencilModuleImportAttribute attributeStencil(key, value);
   2009      if (!request.attributes.append(attributeStencil)) {
   2010        js::ReportOutOfMemory(fc_);
   2011        return false;
   2012      }
   2013    } else {
   2014      if (!request.firstUnsupportedAttributeKey) {
   2015        request.firstUnsupportedAttributeKey = key;
   2016      }
   2017    }
   2018  }
   2019 
   2020  return true;
   2021 }
   2022 
   2023 bool ModuleBuilder::processImport(frontend::BinaryNode* importNode) {
   2024  using namespace js::frontend;
   2025 
   2026  MOZ_ASSERT(importNode->isKind(ParseNodeKind::ImportDecl));
   2027 
   2028  auto* specList = &importNode->left()->as<ListNode>();
   2029  MOZ_ASSERT(specList->isKind(ParseNodeKind::ImportSpecList));
   2030 
   2031  auto* moduleRequest = &importNode->right()->as<BinaryNode>();
   2032  MOZ_ASSERT(moduleRequest->isKind(ParseNodeKind::ImportModuleRequest));
   2033 
   2034  auto* moduleSpec = &moduleRequest->left()->as<NameNode>();
   2035  MOZ_ASSERT(moduleSpec->isKind(ParseNodeKind::StringExpr));
   2036 
   2037  auto* attributeList = &moduleRequest->right()->as<ListNode>();
   2038  MOZ_ASSERT(attributeList->isKind(ParseNodeKind::ImportAttributeList));
   2039 
   2040  auto specifier = moduleSpec->atom();
   2041  MaybeModuleRequestIndex moduleRequestIndex =
   2042      appendModuleRequest(specifier, attributeList);
   2043  if (!moduleRequestIndex.isSome()) {
   2044    return false;
   2045  }
   2046 
   2047  if (!maybeAppendRequestedModule(moduleRequestIndex, moduleSpec)) {
   2048    return false;
   2049  }
   2050 
   2051  for (ParseNode* item : specList->contents()) {
   2052    uint32_t line;
   2053    JS::LimitedColumnNumberOneOrigin column;
   2054    eitherParser_.computeLineAndColumn(item->pn_pos.begin, &line, &column);
   2055 
   2056    StencilModuleEntry entry;
   2057    TaggedParserAtomIndex localName;
   2058    if (item->isKind(ParseNodeKind::ImportSpec)) {
   2059      auto* spec = &item->as<BinaryNode>();
   2060 
   2061      auto* importNameNode = &spec->left()->as<NameNode>();
   2062      auto* localNameNode = &spec->right()->as<NameNode>();
   2063 
   2064      auto importName = importNameNode->atom();
   2065      localName = localNameNode->atom();
   2066 
   2067      markUsedByStencil(localName);
   2068      markUsedByStencil(importName);
   2069      entry = StencilModuleEntry::importEntry(
   2070          moduleRequestIndex, localName, importName, line,
   2071          JS::ColumnNumberOneOrigin(column));
   2072    } else {
   2073      MOZ_ASSERT(item->isKind(ParseNodeKind::ImportNamespaceSpec));
   2074      auto* spec = &item->as<UnaryNode>();
   2075 
   2076      auto* localNameNode = &spec->kid()->as<NameNode>();
   2077 
   2078      localName = localNameNode->atom();
   2079 
   2080      markUsedByStencil(localName);
   2081      entry = StencilModuleEntry::importNamespaceEntry(
   2082          moduleRequestIndex, localName, line,
   2083          JS::ColumnNumberOneOrigin(column));
   2084    }
   2085 
   2086    if (!importEntries_.put(localName, entry)) {
   2087      return false;
   2088    }
   2089  }
   2090 
   2091  return true;
   2092 }
   2093 
   2094 bool ModuleBuilder::processExport(frontend::ParseNode* exportNode) {
   2095  using namespace js::frontend;
   2096 
   2097  MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportStmt) ||
   2098             exportNode->isKind(ParseNodeKind::ExportDefaultStmt));
   2099 
   2100  bool isDefault = exportNode->isKind(ParseNodeKind::ExportDefaultStmt);
   2101  ParseNode* kid = isDefault ? exportNode->as<BinaryNode>().left()
   2102                             : exportNode->as<UnaryNode>().kid();
   2103 
   2104  if (isDefault && exportNode->as<BinaryNode>().right()) {
   2105    // This is an export default containing an expression.
   2106    auto localName = TaggedParserAtomIndex::WellKnown::default_();
   2107    auto exportName = TaggedParserAtomIndex::WellKnown::default_();
   2108    return appendExportEntry(exportName, localName);
   2109  }
   2110 
   2111  switch (kid->getKind()) {
   2112    case ParseNodeKind::ExportSpecList: {
   2113      MOZ_ASSERT(!isDefault);
   2114      for (ParseNode* item : kid->as<ListNode>().contents()) {
   2115        BinaryNode* spec = &item->as<BinaryNode>();
   2116        MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportSpec));
   2117 
   2118        NameNode* localNameNode = &spec->left()->as<NameNode>();
   2119        NameNode* exportNameNode = &spec->right()->as<NameNode>();
   2120 
   2121        auto localName = localNameNode->atom();
   2122        auto exportName = exportNameNode->atom();
   2123 
   2124        if (!appendExportEntry(exportName, localName, spec)) {
   2125          return false;
   2126        }
   2127      }
   2128      break;
   2129    }
   2130 
   2131    case ParseNodeKind::ClassDecl: {
   2132      const ClassNode& cls = kid->as<ClassNode>();
   2133      MOZ_ASSERT(cls.names());
   2134      auto localName = cls.names()->innerBinding()->atom();
   2135      auto exportName =
   2136          isDefault ? TaggedParserAtomIndex::WellKnown::default_() : localName;
   2137      if (!appendExportEntry(exportName, localName)) {
   2138        return false;
   2139      }
   2140      break;
   2141    }
   2142 
   2143    case ParseNodeKind::VarStmt:
   2144    case ParseNodeKind::ConstDecl:
   2145    case ParseNodeKind::LetDecl: {
   2146      for (ParseNode* binding : kid->as<ListNode>().contents()) {
   2147        if (binding->isKind(ParseNodeKind::AssignExpr)) {
   2148          binding = binding->as<AssignmentNode>().left();
   2149        } else {
   2150          MOZ_ASSERT(binding->isKind(ParseNodeKind::Name));
   2151        }
   2152 
   2153        if (binding->isKind(ParseNodeKind::Name)) {
   2154          auto localName = binding->as<NameNode>().atom();
   2155          auto exportName = isDefault
   2156                                ? TaggedParserAtomIndex::WellKnown::default_()
   2157                                : localName;
   2158          if (!appendExportEntry(exportName, localName)) {
   2159            return false;
   2160          }
   2161        } else if (binding->isKind(ParseNodeKind::ArrayExpr)) {
   2162          if (!processExportArrayBinding(&binding->as<ListNode>())) {
   2163            return false;
   2164          }
   2165        } else {
   2166          MOZ_ASSERT(binding->isKind(ParseNodeKind::ObjectExpr));
   2167          if (!processExportObjectBinding(&binding->as<ListNode>())) {
   2168            return false;
   2169          }
   2170        }
   2171      }
   2172      break;
   2173    }
   2174 
   2175    case ParseNodeKind::Function: {
   2176      FunctionBox* box = kid->as<FunctionNode>().funbox();
   2177      MOZ_ASSERT(!box->isArrow());
   2178      auto localName = box->explicitName();
   2179      auto exportName =
   2180          isDefault ? TaggedParserAtomIndex::WellKnown::default_() : localName;
   2181      if (!appendExportEntry(exportName, localName)) {
   2182        return false;
   2183      }
   2184      break;
   2185    }
   2186 
   2187    default:
   2188      MOZ_CRASH("Unexpected parse node");
   2189  }
   2190 
   2191  return true;
   2192 }
   2193 
   2194 bool ModuleBuilder::processExportBinding(frontend::ParseNode* binding) {
   2195  using namespace js::frontend;
   2196 
   2197  if (binding->isKind(ParseNodeKind::Name)) {
   2198    auto name = binding->as<NameNode>().atom();
   2199    return appendExportEntry(name, name);
   2200  }
   2201 
   2202  if (binding->isKind(ParseNodeKind::ArrayExpr)) {
   2203    return processExportArrayBinding(&binding->as<ListNode>());
   2204  }
   2205 
   2206  MOZ_ASSERT(binding->isKind(ParseNodeKind::ObjectExpr));
   2207  return processExportObjectBinding(&binding->as<ListNode>());
   2208 }
   2209 
   2210 bool ModuleBuilder::processExportArrayBinding(frontend::ListNode* array) {
   2211  using namespace js::frontend;
   2212 
   2213  MOZ_ASSERT(array->isKind(ParseNodeKind::ArrayExpr));
   2214 
   2215  for (ParseNode* node : array->contents()) {
   2216    if (node->isKind(ParseNodeKind::Elision)) {
   2217      continue;
   2218    }
   2219 
   2220    if (node->isKind(ParseNodeKind::Spread)) {
   2221      node = node->as<UnaryNode>().kid();
   2222    } else if (node->isKind(ParseNodeKind::AssignExpr)) {
   2223      node = node->as<AssignmentNode>().left();
   2224    }
   2225 
   2226    if (!processExportBinding(node)) {
   2227      return false;
   2228    }
   2229  }
   2230 
   2231  return true;
   2232 }
   2233 
   2234 bool ModuleBuilder::processExportObjectBinding(frontend::ListNode* obj) {
   2235  using namespace js::frontend;
   2236 
   2237  MOZ_ASSERT(obj->isKind(ParseNodeKind::ObjectExpr));
   2238 
   2239  for (ParseNode* node : obj->contents()) {
   2240    MOZ_ASSERT(node->isKind(ParseNodeKind::MutateProto) ||
   2241               node->isKind(ParseNodeKind::PropertyDefinition) ||
   2242               node->isKind(ParseNodeKind::Shorthand) ||
   2243               node->isKind(ParseNodeKind::Spread));
   2244 
   2245    ParseNode* target;
   2246    if (node->isKind(ParseNodeKind::Spread)) {
   2247      target = node->as<UnaryNode>().kid();
   2248    } else {
   2249      if (node->isKind(ParseNodeKind::MutateProto)) {
   2250        target = node->as<UnaryNode>().kid();
   2251      } else {
   2252        target = node->as<BinaryNode>().right();
   2253      }
   2254 
   2255      if (target->isKind(ParseNodeKind::AssignExpr)) {
   2256        target = target->as<AssignmentNode>().left();
   2257      }
   2258    }
   2259 
   2260    if (!processExportBinding(target)) {
   2261      return false;
   2262    }
   2263  }
   2264 
   2265  return true;
   2266 }
   2267 
   2268 bool ModuleBuilder::processExportFrom(frontend::BinaryNode* exportNode) {
   2269  using namespace js::frontend;
   2270 
   2271  MOZ_ASSERT(exportNode->isKind(ParseNodeKind::ExportFromStmt));
   2272 
   2273  auto* specList = &exportNode->left()->as<ListNode>();
   2274  MOZ_ASSERT(specList->isKind(ParseNodeKind::ExportSpecList));
   2275 
   2276  auto* moduleRequest = &exportNode->right()->as<BinaryNode>();
   2277  MOZ_ASSERT(moduleRequest->isKind(ParseNodeKind::ImportModuleRequest));
   2278 
   2279  auto* moduleSpec = &moduleRequest->left()->as<NameNode>();
   2280  MOZ_ASSERT(moduleSpec->isKind(ParseNodeKind::StringExpr));
   2281 
   2282  auto* attributeList = &moduleRequest->right()->as<ListNode>();
   2283  MOZ_ASSERT(attributeList->isKind(ParseNodeKind::ImportAttributeList));
   2284 
   2285  auto specifier = moduleSpec->atom();
   2286  MaybeModuleRequestIndex moduleRequestIndex =
   2287      appendModuleRequest(specifier, attributeList);
   2288  if (!moduleRequestIndex.isSome()) {
   2289    return false;
   2290  }
   2291 
   2292  if (!maybeAppendRequestedModule(moduleRequestIndex, moduleSpec)) {
   2293    return false;
   2294  }
   2295 
   2296  for (ParseNode* spec : specList->contents()) {
   2297    uint32_t line;
   2298    JS::LimitedColumnNumberOneOrigin column;
   2299    eitherParser_.computeLineAndColumn(spec->pn_pos.begin, &line, &column);
   2300 
   2301    StencilModuleEntry entry;
   2302    if (spec->isKind(ParseNodeKind::ExportSpec)) {
   2303      auto* importNameNode = &spec->as<BinaryNode>().left()->as<NameNode>();
   2304      auto* exportNameNode = &spec->as<BinaryNode>().right()->as<NameNode>();
   2305 
   2306      auto importName = importNameNode->atom();
   2307      auto exportName = exportNameNode->atom();
   2308      MOZ_ASSERT(exportNames_.has(exportName));
   2309 
   2310      markUsedByStencil(importName);
   2311      markUsedByStencil(exportName);
   2312      entry = StencilModuleEntry::exportFromEntry(
   2313          moduleRequestIndex, importName, exportName, line,
   2314          JS::ColumnNumberOneOrigin(column));
   2315    } else if (spec->isKind(ParseNodeKind::ExportNamespaceSpec)) {
   2316      auto* exportNameNode = &spec->as<UnaryNode>().kid()->as<NameNode>();
   2317 
   2318      auto exportName = exportNameNode->atom();
   2319      MOZ_ASSERT(exportNames_.has(exportName));
   2320 
   2321      markUsedByStencil(exportName);
   2322      entry = StencilModuleEntry::exportNamespaceFromEntry(
   2323          moduleRequestIndex, exportName, line,
   2324          JS::ColumnNumberOneOrigin(column));
   2325    } else {
   2326      MOZ_ASSERT(spec->isKind(ParseNodeKind::ExportBatchSpecStmt));
   2327 
   2328      entry = StencilModuleEntry::exportBatchFromEntry(
   2329          moduleRequestIndex, line, JS::ColumnNumberOneOrigin(column));
   2330    }
   2331 
   2332    if (!exportEntries_.append(entry)) {
   2333      return false;
   2334    }
   2335  }
   2336 
   2337  return true;
   2338 }
   2339 
   2340 frontend::StencilModuleEntry* ModuleBuilder::importEntryFor(
   2341    frontend::TaggedParserAtomIndex localName) const {
   2342  MOZ_ASSERT(localName);
   2343  auto ptr = importEntries_.lookup(localName);
   2344  if (!ptr) {
   2345    return nullptr;
   2346  }
   2347 
   2348  return &ptr->value();
   2349 }
   2350 
   2351 ModuleBuilder::NoteExportedNameResult ModuleBuilder::noteExportedName(
   2352    frontend::TaggedParserAtomIndex name) {
   2353  MOZ_ASSERT(name);
   2354  auto addPtr = exportNames_.lookupForAdd(name);
   2355  if (addPtr) {
   2356    return NoteExportedNameResult::AlreadyDeclared;
   2357  }
   2358  if (!exportNames_.add(addPtr, name)) {
   2359    return NoteExportedNameResult::OutOfMemory;
   2360  }
   2361  return NoteExportedNameResult::Success;
   2362 }
   2363 
   2364 bool ModuleBuilder::appendExportEntry(
   2365    frontend::TaggedParserAtomIndex exportName,
   2366    frontend::TaggedParserAtomIndex localName, frontend::ParseNode* node) {
   2367  MOZ_ASSERT(exportNames_.has(exportName));
   2368 
   2369  uint32_t line = 0;
   2370  JS::LimitedColumnNumberOneOrigin column;
   2371  if (node) {
   2372    eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
   2373  }
   2374 
   2375  markUsedByStencil(localName);
   2376  markUsedByStencil(exportName);
   2377  auto entry = frontend::StencilModuleEntry::exportAsEntry(
   2378      localName, exportName, line, JS::ColumnNumberOneOrigin(column));
   2379  return exportEntries_.append(entry);
   2380 }
   2381 
   2382 frontend::MaybeModuleRequestIndex ModuleBuilder::appendModuleRequest(
   2383    frontend::TaggedParserAtomIndex specifier,
   2384    frontend::ListNode* attributeList) {
   2385  markUsedByStencil(specifier);
   2386  auto request = frontend::StencilModuleRequest(specifier);
   2387 
   2388  if (!processAttributes(request, attributeList)) {
   2389    return MaybeModuleRequestIndex();
   2390  }
   2391 
   2392  if (auto ptr = moduleRequestIndexes_.lookup(request)) {
   2393    return MaybeModuleRequestIndex(ptr->value());
   2394  }
   2395 
   2396  uint32_t index = moduleRequests_.length();
   2397  if (!moduleRequests_.append(request) ||
   2398      !moduleRequestIndexes_.put(request, index)) {
   2399    js::ReportOutOfMemory(fc_);
   2400    return MaybeModuleRequestIndex();
   2401  }
   2402 
   2403  return MaybeModuleRequestIndex(index);
   2404 }
   2405 
   2406 bool ModuleBuilder::maybeAppendRequestedModule(
   2407    MaybeModuleRequestIndex moduleRequest, frontend::ParseNode* node) {
   2408  uint32_t index = moduleRequest.value();
   2409  if (requestedModuleIndexes_.has(index)) {
   2410    return true;
   2411  }
   2412 
   2413  uint32_t line;
   2414  JS::LimitedColumnNumberOneOrigin column;
   2415  eitherParser_.computeLineAndColumn(node->pn_pos.begin, &line, &column);
   2416 
   2417  auto entry = frontend::StencilModuleEntry::requestedModule(
   2418      moduleRequest, line, JS::ColumnNumberOneOrigin(column));
   2419 
   2420  if (!requestedModules_.append(entry)) {
   2421    js::ReportOutOfMemory(fc_);
   2422    return false;
   2423  }
   2424 
   2425  return requestedModuleIndexes_.put(index);
   2426 }
   2427 
   2428 void ModuleBuilder::markUsedByStencil(frontend::TaggedParserAtomIndex name) {
   2429  // Imported/exported identifiers must be atomized.
   2430  eitherParser_.parserAtoms().markUsedByStencil(
   2431      name, frontend::ParserAtom::Atomize::Yes);
   2432 }
   2433 
   2434 JSObject* js::GetOrCreateModuleMetaObject(JSContext* cx,
   2435                                          HandleObject moduleArg) {
   2436  Handle<ModuleObject*> module = moduleArg.as<ModuleObject>();
   2437  if (JSObject* obj = module->metaObject()) {
   2438    return obj;
   2439  }
   2440 
   2441  RootedObject metaObject(cx, NewPlainObjectWithProto(cx, nullptr));
   2442  if (!metaObject) {
   2443    return nullptr;
   2444  }
   2445 
   2446  JS::ModuleMetadataHook func = cx->runtime()->moduleMetadataHook;
   2447  if (!func) {
   2448    JS_ReportErrorASCII(cx, "Module metadata hook not set");
   2449    return nullptr;
   2450  }
   2451 
   2452  RootedValue modulePrivate(cx, JS::GetModulePrivate(module));
   2453  if (!func(cx, modulePrivate, metaObject)) {
   2454    return nullptr;
   2455  }
   2456 
   2457  module->setMetaObject(metaObject);
   2458 
   2459  return metaObject;
   2460 }
   2461 
   2462 bool ModuleObject::topLevelCapabilityResolve(JSContext* cx,
   2463                                             Handle<ModuleObject*> module) {
   2464  RootedValue rval(cx);
   2465  Rooted<PromiseObject*> promise(
   2466      cx, &module->topLevelCapability()->as<PromiseObject>());
   2467  return AsyncFunctionReturned(cx, promise, rval);
   2468 }
   2469 
   2470 bool ModuleObject::topLevelCapabilityReject(JSContext* cx,
   2471                                            Handle<ModuleObject*> module,
   2472                                            HandleValue error) {
   2473  Rooted<PromiseObject*> promise(
   2474      cx, &module->topLevelCapability()->as<PromiseObject>());
   2475  return AsyncFunctionThrown(cx, promise, error);
   2476 }