tor-browser

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

ShellModuleObjectWrapper.cpp (24798B)


      1 /* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4
      2 * -*- */
      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 "shell/ShellModuleObjectWrapper.h"
      8 
      9 #include "mozilla/Maybe.h"
     10 #include "mozilla/Span.h"
     11 
     12 #include "jsapi.h"  // JS_GetProperty, JS::Call, JS_NewPlainObject, JS_DefineProperty
     13 
     14 #include "builtin/ModuleObject.h"     // js::ModuleObject
     15 #include "js/CallAndConstruct.h"      // JS::Call
     16 #include "js/CallArgs.h"              // JS::CallArgs
     17 #include "js/CallNonGenericMethod.h"  // CallNonGenericMethod
     18 #include "js/Class.h"                 // JSClass, JSCLASS_*
     19 #include "js/ColumnNumber.h"          // JS::ColumnNumberOneOrigin
     20 #include "js/ErrorReport.h"           // JS_ReportErrorASCII
     21 #include "js/PropertyAndElement.h"    // JS_GetProperty
     22 #include "js/PropertySpec.h"  // JSPropertySpec, JS_PSG, JS_PS_END, JSFunctionSpec, JS_FN, JS_FN_END
     23 #include "js/RootingAPI.h"    // JS::Rooted, JS::Handle, JS::MutableHandle
     24 #include "js/Value.h"         // JS::Value
     25 #include "vm/ArrayObject.h"   // ArrayObject, NewDenseFullyAllocatedArray
     26 #include "vm/GlobalObject.h"  // DefinePropertiesAndFunctions
     27 #include "vm/JSFunction.h"    // JSFunction
     28 #include "vm/JSObject.h"      // JSObject
     29 #include "vm/List.h"          // ListObject
     30 #include "vm/NativeObject.h"  // NativeObject
     31 #include "vm/Stack.h"         // FixedInvokeArgs
     32 
     33 #include "vm/NativeObject-inl.h"  // NativeObject::ensureDenseInitializedLength
     34 
     35 using namespace js;
     36 using namespace js::shell;
     37 
     38 using mozilla::Span;
     39 
     40 #define DEFINE_CLASS_IMPL(CLASS)                                            \
     41  CLASS* Shell##CLASS##Wrapper::get() {                                     \
     42    return &getReservedSlot(TargetSlot).toObject().as<CLASS>();             \
     43  }                                                                         \
     44  /* static */ const JSClass Shell##CLASS##Wrapper::class_ = {              \
     45      "Shell" #CLASS "Wrapper",                                             \
     46      JSCLASS_HAS_RESERVED_SLOTS(Shell##CLASS##Wrapper::SlotCount)};        \
     47  MOZ_ALWAYS_INLINE bool IsShell##CLASS##Wrapper(JS::Handle<JS::Value> v) { \
     48    return v.isObject() && v.toObject().is<Shell##CLASS##Wrapper>();        \
     49  }
     50 
     51 #define DEFINE_CLASS(CLASS)                                       \
     52  class Shell##CLASS##Wrapper : public js::NativeObject {         \
     53   public:                                                        \
     54    using Target = CLASS;                                         \
     55    enum ModuleSlot { TargetSlot = 0, SlotCount };                \
     56    static const JSClass class_;                                  \
     57    static Shell##CLASS##Wrapper* create(JSContext* cx,           \
     58                                         JS::Handle<CLASS*> obj); \
     59    CLASS* get();                                                 \
     60  };                                                              \
     61  DEFINE_CLASS_IMPL(CLASS)
     62 
     63 #define DEFINE_NATIVE_CLASS_IMPL(CLASS)                                     \
     64  CLASS* Shell##CLASS##Wrapper::get() {                                     \
     65    return static_cast<CLASS*>(getReservedSlot(TargetSlot).toPrivate());    \
     66  }                                                                         \
     67  /* static */ const JSClass Shell##CLASS##Wrapper::class_ = {              \
     68      "Shell" #CLASS "Wrapper",                                             \
     69      JSCLASS_HAS_RESERVED_SLOTS(Shell##CLASS##Wrapper::SlotCount)};        \
     70  MOZ_ALWAYS_INLINE bool IsShell##CLASS##Wrapper(JS::Handle<JS::Value> v) { \
     71    return v.isObject() && v.toObject().is<Shell##CLASS##Wrapper>();        \
     72  }
     73 
     74 #define DEFINE_NATIVE_CLASS(CLASS)                                    \
     75  class Shell##CLASS##Wrapper : public js::NativeObject {             \
     76   public:                                                            \
     77    using Target = CLASS;                                             \
     78    enum ModuleSlot { OwnerSlot = 0, TargetSlot, SlotCount };         \
     79    static const JSClass class_;                                      \
     80    static Shell##CLASS##Wrapper* create(JSContext* cx,               \
     81                                         JS::Handle<JSObject*> owner, \
     82                                         CLASS* obj);                 \
     83    CLASS* get();                                                     \
     84  };                                                                  \
     85  DEFINE_NATIVE_CLASS_IMPL(CLASS)
     86 
     87 DEFINE_CLASS(ModuleRequestObject)
     88 DEFINE_NATIVE_CLASS(ImportEntry)
     89 DEFINE_NATIVE_CLASS(ExportEntry)
     90 DEFINE_NATIVE_CLASS(RequestedModule)
     91 // NOTE: We don't need wrapper for IndirectBindingMap and ModuleNamespaceObject
     92 DEFINE_CLASS_IMPL(ModuleObject)
     93 
     94 #undef DEFINE_CLASS
     95 #undef DEFINE_CLASS_IMPL
     96 #undef DEFINE_NATIVE_CLASS
     97 #undef DEFINE_NATIVE_CLASS_IMPL
     98 
     99 bool IdentFilter(JSContext* cx, JS::Handle<JS::Value> from,
    100                 JS::MutableHandle<JS::Value> to) {
    101  to.set(from);
    102  return true;
    103 }
    104 
    105 bool GetModuleStatusName(JSContext* cx, JS::Handle<JS::Value> from,
    106                         JS::MutableHandle<JS::Value> to) {
    107  if (!from.isInt32()) {
    108    return false;
    109  }
    110 
    111  const char* statusStr = nullptr;
    112  switch (static_cast<ModuleStatus>(from.toInt32())) {
    113    case ModuleStatus::New:
    114      statusStr = "New";
    115      break;
    116    case ModuleStatus::Unlinked:
    117      statusStr = "Unlinked";
    118      break;
    119    case ModuleStatus::Linking:
    120      statusStr = "Linking";
    121      break;
    122    case ModuleStatus::Linked:
    123      statusStr = "Linked";
    124      break;
    125    case ModuleStatus::Evaluating:
    126      statusStr = "Evaluating";
    127      break;
    128    case ModuleStatus::EvaluatingAsync:
    129      statusStr = "EvaluatingAsync";
    130      break;
    131    case ModuleStatus::Evaluated:
    132      statusStr = "Evaluated";
    133      break;
    134    default:
    135      MOZ_CRASH("Unknown ModuleStatus value");
    136  }
    137 
    138  JS::Rooted<JSString*> str(cx, JS_NewStringCopyZ(cx, statusStr));
    139  if (!str) {
    140    return false;
    141  }
    142 
    143  to.setString(str);
    144  return true;
    145 }
    146 
    147 template <class T>
    148 bool SingleFilter(JSContext* cx, JS::Handle<JS::Value> from,
    149                  JS::MutableHandle<JS::Value> to) {
    150  using TargetT = typename T::Target;
    151 
    152  if (!from.isObject() || !from.toObject().is<TargetT>()) {
    153    to.set(from);
    154    return true;
    155  }
    156 
    157  JS::Rooted<TargetT*> obj(cx, &from.toObject().as<TargetT>());
    158  JS::Rooted<T*> filtered(cx, T::create(cx, obj));
    159  if (!filtered) {
    160    return false;
    161  }
    162  to.setObject(*filtered);
    163  return true;
    164 }
    165 
    166 template <class T>
    167 bool ArrayFilter(JSContext* cx, JS::Handle<JS::Value> from,
    168                 JS::MutableHandle<JS::Value> to) {
    169  using TargetT = typename T::Target;
    170 
    171  if (!from.isObject() || !from.toObject().is<ArrayObject>()) {
    172    to.set(from);
    173    return true;
    174  }
    175 
    176  JS::Rooted<ArrayObject*> fromArray(cx, &from.toObject().as<ArrayObject>());
    177  uint32_t length = fromArray->length();
    178  JS::Rooted<ArrayObject*> toArray(cx, NewDenseFullyAllocatedArray(cx, length));
    179  if (!toArray) {
    180    return false;
    181  }
    182 
    183  toArray->ensureDenseInitializedLength(0, length);
    184 
    185  for (uint32_t i = 0; i < length; i++) {
    186    JS::Rooted<JS::Value> item(cx, fromArray->getDenseElement(i));
    187    JS::Rooted<TargetT*> req(cx, &item.toObject().as<TargetT>());
    188    JS::Rooted<T*> filtered(cx, T::create(cx, req));
    189    if (!filtered) {
    190      return false;
    191    }
    192    toArray->initDenseElement(i, ObjectValue(*filtered));
    193  }
    194  to.setObject(*toArray);
    195  return true;
    196 }
    197 
    198 template <class T>
    199 bool ListToArrayFilter(JSContext* cx, JS::Handle<JS::Value> from,
    200                       JS::MutableHandle<JS::Value> to) {
    201  using TargetT = typename T::Target;
    202 
    203  if (!from.isObject() || !from.toObject().is<ListObject>()) {
    204    to.set(from);
    205    return true;
    206  }
    207 
    208  JS::Rooted<ListObject*> fromList(cx, &from.toObject().as<ListObject>());
    209  uint32_t length = fromList->length();
    210  JS::Rooted<ArrayObject*> toArray(cx, NewDenseFullyAllocatedArray(cx, length));
    211  if (!toArray) {
    212    return false;
    213  }
    214 
    215  toArray->ensureDenseInitializedLength(0, length);
    216 
    217  for (uint32_t i = 0; i < length; i++) {
    218    JS::Rooted<JS::Value> item(cx, fromList->get(i));
    219    JS::Rooted<TargetT*> req(cx, &item.toObject().as<TargetT>());
    220    JS::Rooted<T*> filtered(cx, T::create(cx, req));
    221    if (!filtered) {
    222      return false;
    223    }
    224    toArray->initDenseElement(i, ObjectValue(*filtered));
    225  }
    226  to.setObject(*toArray);
    227  return true;
    228 }
    229 
    230 static Value StringOrNullValue(JSString* maybeString) {
    231  if (!maybeString) {
    232    return NullValue();
    233  }
    234 
    235  return StringValue(maybeString);
    236 }
    237 
    238 static Value Uint32Value(uint32_t x) {
    239  MOZ_ASSERT(x <= INT32_MAX);
    240  return Int32Value(x);
    241 }
    242 
    243 static Value Uint32OrUndefinedValue(mozilla::Maybe<uint32_t> x) {
    244  if (x.isNothing()) {
    245    return UndefinedValue();
    246  }
    247 
    248  return Uint32Value(x.value());
    249 }
    250 
    251 static Value AsyncEvaluationOrderInt32Value(AsyncEvaluationOrder x) {
    252  if (x.isUnset()) {
    253    return Int32Value(-1);
    254  }
    255  if (x.isDone()) {
    256    return Int32Value(-2);
    257  }
    258  return Uint32Value(x.get());
    259 }
    260 
    261 static Value ColumnNumberOneOriginValue(JS::ColumnNumberOneOrigin x) {
    262  uint32_t column = x.oneOriginValue();
    263  MOZ_ASSERT(column <= INT32_MAX);
    264  return Int32Value(column);
    265 }
    266 
    267 static Value StatusValue(ModuleStatus status) {
    268  return Int32Value(int32_t(status));
    269 }
    270 
    271 static Value ObjectOrUndefinedValue(JSObject* object) {
    272  if (!object) {
    273    return UndefinedValue();
    274  }
    275 
    276  return ObjectValue(*object);
    277 }
    278 
    279 template <class T, typename RawGetterT, typename FilterT>
    280 bool ShellModuleWrapperGetter(JSContext* cx, const JS::CallArgs& args,
    281                              RawGetterT rawGetter, FilterT filter) {
    282  JS::Rooted<T*> wrapper(cx, &args.thisv().toObject().as<T>());
    283  if constexpr (std::is_same_v<T, ShellModuleObjectWrapper>) {
    284    if (!wrapper->get()->hasCyclicModuleFields()) {
    285      args.rval().set(UndefinedValue());
    286      return true;
    287    }
    288  }
    289 
    290  JS::Rooted<JS::Value> raw(cx, rawGetter(wrapper->get()));
    291 
    292  JS::Rooted<JS::Value> filtered(cx);
    293  if (!filter(cx, raw, &filtered)) {
    294    return false;
    295  }
    296 
    297  args.rval().set(filtered);
    298  return true;
    299 }
    300 
    301 #define DEFINE_GETTER_FUNCTIONS(CLASS, PROP, TO_VALUE, FILTER)                 \
    302  static Value Shell##CLASS##Wrapper_##PROP##Getter_raw(CLASS* obj) {          \
    303    return TO_VALUE(obj->PROP());                                              \
    304  }                                                                            \
    305  static bool Shell##CLASS##Wrapper_##PROP##Getter_impl(                       \
    306      JSContext* cx, const JS::CallArgs& args) {                               \
    307    return ShellModuleWrapperGetter<Shell##CLASS##Wrapper>(                    \
    308        cx, args, Shell##CLASS##Wrapper_##PROP##Getter_raw, FILTER);           \
    309  }                                                                            \
    310  static bool Shell##CLASS##Wrapper_##PROP##Getter(JSContext* cx,              \
    311                                                   unsigned argc, Value* vp) { \
    312    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);                          \
    313    return CallNonGenericMethod<IsShell##CLASS##Wrapper,                       \
    314                                Shell##CLASS##Wrapper_##PROP##Getter_impl>(    \
    315        cx, args);                                                             \
    316  }
    317 
    318 template <class T>
    319 bool SpanToArrayFilter(JSContext* cx, JS::Handle<JSObject*> owner,
    320                       Span<const typename T::Target> from,
    321                       JS::MutableHandle<JS::Value> to) {
    322  size_t length = from.Length();
    323  JS::Rooted<ArrayObject*> toArray(cx, NewDenseFullyAllocatedArray(cx, length));
    324  if (!toArray) {
    325    return false;
    326  }
    327 
    328  toArray->ensureDenseInitializedLength(0, length);
    329 
    330  for (uint32_t i = 0; i < length; i++) {
    331    auto* element = const_cast<typename T::Target*>(&from[i]);
    332    JS::Rooted<T*> filtered(cx, T::create(cx, owner, element));
    333    if (!filtered) {
    334      return false;
    335    }
    336    toArray->initDenseElement(i, ObjectValue(*filtered));
    337  }
    338 
    339  to.setObject(*toArray);
    340  return true;
    341 }
    342 
    343 template <class T, typename RawGetterT, typename FilterT>
    344 bool ShellModuleNativeWrapperGetter(JSContext* cx, const JS::CallArgs& args,
    345                                    RawGetterT rawGetter, FilterT filter) {
    346  JS::Rooted<T*> wrapper(cx, &args.thisv().toObject().as<T>());
    347  if constexpr (std::is_same_v<T, ShellModuleObjectWrapper>) {
    348    if (!wrapper->get()->hasCyclicModuleFields()) {
    349      args.rval().set(UndefinedValue());
    350      return true;
    351    }
    352  }
    353 
    354  JS::Rooted<typename T::Target*> owner(cx, wrapper->get());
    355 
    356  JS::Rooted<JS::Value> filtered(cx);
    357  if (!filter(cx, owner, rawGetter(owner), &filtered)) {
    358    return false;
    359  }
    360 
    361  args.rval().set(filtered);
    362  return true;
    363 }
    364 
    365 bool ModuleTypeToString(JSContext* cx, JS::Handle<JSObject*> owner,
    366                        JS::ModuleType moduleType,
    367                        JS::MutableHandle<JS::Value> to) {
    368  switch (moduleType) {
    369    case JS::ModuleType::Unknown:
    370      to.setString(cx->names().unknown);
    371      break;
    372    case JS::ModuleType::JavaScript:
    373      to.setString(cx->names().js);
    374      break;
    375    case JS::ModuleType::JSON:
    376      to.setString(cx->names().json);
    377      break;
    378    case JS::ModuleType::CSS:
    379      MOZ_ASSERT_UNREACHABLE("CSS modules are not supported in the shell");
    380      break;
    381    case JS::ModuleType::Bytes:
    382      to.setString(cx->names().bytes);
    383      break;
    384  }
    385 
    386  MOZ_ASSERT(!to.isUndefined());
    387  return true;
    388 }
    389 
    390 #define DEFINE_NATIVE_GETTER_FUNCTIONS(CLASS, PROP, FILTER)                    \
    391  static auto Shell##CLASS##Wrapper_##PROP##Getter_raw(CLASS* obj) {           \
    392    return obj->PROP();                                                        \
    393  }                                                                            \
    394  static bool Shell##CLASS##Wrapper_##PROP##Getter_impl(                       \
    395      JSContext* cx, const JS::CallArgs& args) {                               \
    396    return ShellModuleNativeWrapperGetter<Shell##CLASS##Wrapper>(              \
    397        cx, args, Shell##CLASS##Wrapper_##PROP##Getter_raw, FILTER);           \
    398  }                                                                            \
    399  static bool Shell##CLASS##Wrapper_##PROP##Getter(JSContext* cx,              \
    400                                                   unsigned argc, Value* vp) { \
    401    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);                          \
    402    return CallNonGenericMethod<IsShell##CLASS##Wrapper,                       \
    403                                Shell##CLASS##Wrapper_##PROP##Getter_impl>(    \
    404        cx, args);                                                             \
    405  }
    406 
    407 DEFINE_GETTER_FUNCTIONS(ModuleRequestObject, specifier, StringOrNullValue,
    408                        IdentFilter)
    409 DEFINE_GETTER_FUNCTIONS(ModuleRequestObject, getFirstUnsupportedAttributeKey,
    410                        StringOrNullValue, IdentFilter)
    411 DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleRequestObject, moduleType,
    412                               ModuleTypeToString);
    413 
    414 static const JSPropertySpec ShellModuleRequestObjectWrapper_accessors[] = {
    415    JS_PSG("specifier", ShellModuleRequestObjectWrapper_specifierGetter, 0),
    416    JS_PSG("moduleType", ShellModuleRequestObjectWrapper_moduleTypeGetter, 0),
    417    JS_PSG(
    418        "firstUnsupportedAttributeKey",
    419        ShellModuleRequestObjectWrapper_getFirstUnsupportedAttributeKeyGetter,
    420        0),
    421    JS_PS_END,
    422 };
    423 
    424 DEFINE_GETTER_FUNCTIONS(ImportEntry, moduleRequest, ObjectOrNullValue,
    425                        SingleFilter<ShellModuleRequestObjectWrapper>)
    426 DEFINE_GETTER_FUNCTIONS(ImportEntry, importName, StringOrNullValue, IdentFilter)
    427 DEFINE_GETTER_FUNCTIONS(ImportEntry, localName, StringValue, IdentFilter)
    428 DEFINE_GETTER_FUNCTIONS(ImportEntry, lineNumber, Uint32Value, IdentFilter)
    429 DEFINE_GETTER_FUNCTIONS(ImportEntry, columnNumber, ColumnNumberOneOriginValue,
    430                        IdentFilter)
    431 
    432 static const JSPropertySpec ShellImportEntryWrapper_accessors[] = {
    433    JS_PSG("moduleRequest", ShellImportEntryWrapper_moduleRequestGetter, 0),
    434    JS_PSG("importName", ShellImportEntryWrapper_importNameGetter, 0),
    435    JS_PSG("localName", ShellImportEntryWrapper_localNameGetter, 0),
    436    JS_PSG("lineNumber", ShellImportEntryWrapper_lineNumberGetter, 0),
    437    JS_PSG("columnNumber", ShellImportEntryWrapper_columnNumberGetter, 0),
    438    JS_PS_END,
    439 };
    440 
    441 DEFINE_GETTER_FUNCTIONS(ExportEntry, exportName, StringOrNullValue, IdentFilter)
    442 DEFINE_GETTER_FUNCTIONS(ExportEntry, moduleRequest, ObjectOrNullValue,
    443                        SingleFilter<ShellModuleRequestObjectWrapper>)
    444 DEFINE_GETTER_FUNCTIONS(ExportEntry, importName, StringOrNullValue, IdentFilter)
    445 DEFINE_GETTER_FUNCTIONS(ExportEntry, localName, StringOrNullValue, IdentFilter)
    446 DEFINE_GETTER_FUNCTIONS(ExportEntry, lineNumber, Uint32Value, IdentFilter)
    447 DEFINE_GETTER_FUNCTIONS(ExportEntry, columnNumber, ColumnNumberOneOriginValue,
    448                        IdentFilter)
    449 
    450 static const JSPropertySpec ShellExportEntryWrapper_accessors[] = {
    451    JS_PSG("exportName", ShellExportEntryWrapper_exportNameGetter, 0),
    452    JS_PSG("moduleRequest", ShellExportEntryWrapper_moduleRequestGetter, 0),
    453    JS_PSG("importName", ShellExportEntryWrapper_importNameGetter, 0),
    454    JS_PSG("localName", ShellExportEntryWrapper_localNameGetter, 0),
    455    JS_PSG("lineNumber", ShellExportEntryWrapper_lineNumberGetter, 0),
    456    JS_PSG("columnNumber", ShellExportEntryWrapper_columnNumberGetter, 0),
    457    JS_PS_END,
    458 };
    459 
    460 DEFINE_GETTER_FUNCTIONS(RequestedModule, moduleRequest, ObjectOrNullValue,
    461                        SingleFilter<ShellModuleRequestObjectWrapper>)
    462 DEFINE_GETTER_FUNCTIONS(RequestedModule, lineNumber, Uint32Value, IdentFilter)
    463 DEFINE_GETTER_FUNCTIONS(RequestedModule, columnNumber,
    464                        ColumnNumberOneOriginValue, IdentFilter)
    465 
    466 static const JSPropertySpec ShellRequestedModuleWrapper_accessors[] = {
    467    JS_PSG("moduleRequest", ShellRequestedModuleWrapper_moduleRequestGetter, 0),
    468    JS_PSG("lineNumber", ShellRequestedModuleWrapper_lineNumberGetter, 0),
    469    JS_PSG("columnNumber", ShellRequestedModuleWrapper_columnNumberGetter, 0),
    470    JS_PS_END,
    471 };
    472 
    473 DEFINE_GETTER_FUNCTIONS(ModuleObject, namespace_, ObjectOrNullValue,
    474                        IdentFilter)
    475 DEFINE_GETTER_FUNCTIONS(ModuleObject, status, StatusValue, GetModuleStatusName)
    476 DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeEvaluationError, Value, IdentFilter)
    477 DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, requestedModules,
    478                               SpanToArrayFilter<ShellRequestedModuleWrapper>)
    479 DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, importEntries,
    480                               SpanToArrayFilter<ShellImportEntryWrapper>)
    481 DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, localExportEntries,
    482                               SpanToArrayFilter<ShellExportEntryWrapper>)
    483 DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries,
    484                               SpanToArrayFilter<ShellExportEntryWrapper>)
    485 DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, starExportEntries,
    486                               SpanToArrayFilter<ShellExportEntryWrapper>)
    487 DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeDfsAncestorIndex,
    488                        Uint32OrUndefinedValue, IdentFilter)
    489 DEFINE_GETTER_FUNCTIONS(ModuleObject, hasTopLevelAwait, BooleanValue,
    490                        IdentFilter)
    491 DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeTopLevelCapability,
    492                        ObjectOrUndefinedValue, IdentFilter)
    493 DEFINE_GETTER_FUNCTIONS(ModuleObject, asyncEvaluationOrder,
    494                        AsyncEvaluationOrderInt32Value, IdentFilter)
    495 DEFINE_GETTER_FUNCTIONS(ModuleObject, asyncParentModules, ObjectOrNullValue,
    496                        ListToArrayFilter<ShellModuleObjectWrapper>)
    497 DEFINE_GETTER_FUNCTIONS(ModuleObject, maybePendingAsyncDependencies,
    498                        Uint32OrUndefinedValue, IdentFilter)
    499 
    500 static const JSPropertySpec ShellModuleObjectWrapper_accessors[] = {
    501    JS_PSG("namespace", ShellModuleObjectWrapper_namespace_Getter, 0),
    502    JS_PSG("status", ShellModuleObjectWrapper_statusGetter, 0),
    503    JS_PSG("evaluationError",
    504           ShellModuleObjectWrapper_maybeEvaluationErrorGetter, 0),
    505    JS_PSG("requestedModules", ShellModuleObjectWrapper_requestedModulesGetter,
    506           0),
    507    JS_PSG("importEntries", ShellModuleObjectWrapper_importEntriesGetter, 0),
    508    JS_PSG("localExportEntries",
    509           ShellModuleObjectWrapper_localExportEntriesGetter, 0),
    510    JS_PSG("indirectExportEntries",
    511           ShellModuleObjectWrapper_indirectExportEntriesGetter, 0),
    512    JS_PSG("starExportEntries",
    513           ShellModuleObjectWrapper_starExportEntriesGetter, 0),
    514    JS_PSG("dfsAncestorIndex",
    515           ShellModuleObjectWrapper_maybeDfsAncestorIndexGetter, 0),
    516    JS_PSG("hasTopLevelAwait", ShellModuleObjectWrapper_hasTopLevelAwaitGetter,
    517           0),
    518    JS_PSG("topLevelCapability",
    519           ShellModuleObjectWrapper_maybeTopLevelCapabilityGetter, 0),
    520    JS_PSG("asyncEvaluationOrder",
    521           ShellModuleObjectWrapper_asyncEvaluationOrderGetter, 0),
    522    JS_PSG("asyncParentModules",
    523           ShellModuleObjectWrapper_asyncParentModulesGetter, 0),
    524    JS_PSG("pendingAsyncDependencies",
    525           ShellModuleObjectWrapper_maybePendingAsyncDependenciesGetter, 0),
    526    JS_PS_END,
    527 };
    528 
    529 #undef DEFINE_GETTER_FUNCTIONS
    530 #undef DEFINE_NATIVE_GETTER_FUNCTIONS
    531 
    532 #define DEFINE_CREATE(CLASS, ACCESSORS, FUNCTIONS)                      \
    533  /* static */                                                          \
    534  Shell##CLASS##Wrapper* Shell##CLASS##Wrapper::create(                 \
    535      JSContext* cx, JS::Handle<CLASS*> target) {                       \
    536    JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &class_));           \
    537    if (!obj) {                                                         \
    538      return nullptr;                                                   \
    539    }                                                                   \
    540    if (!DefinePropertiesAndFunctions(cx, obj, ACCESSORS, FUNCTIONS)) { \
    541      return nullptr;                                                   \
    542    }                                                                   \
    543    auto* wrapper = &obj->as<Shell##CLASS##Wrapper>();                  \
    544    wrapper->initReservedSlot(TargetSlot, ObjectValue(*target));        \
    545    return wrapper;                                                     \
    546  }
    547 
    548 #define DEFINE_NATIVE_CREATE(CLASS, ACCESSORS, FUNCTIONS)               \
    549  /* static */                                                          \
    550  Shell##CLASS##Wrapper* Shell##CLASS##Wrapper::create(                 \
    551      JSContext* cx, JS::Handle<JSObject*> owner, CLASS* target) {      \
    552    JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &class_));           \
    553    if (!obj) {                                                         \
    554      return nullptr;                                                   \
    555    }                                                                   \
    556    if (!DefinePropertiesAndFunctions(cx, obj, ACCESSORS, FUNCTIONS)) { \
    557      return nullptr;                                                   \
    558    }                                                                   \
    559    auto* wrapper = &obj->as<Shell##CLASS##Wrapper>();                  \
    560    wrapper->initReservedSlot(OwnerSlot, ObjectValue(*owner));          \
    561    wrapper->initReservedSlot(TargetSlot, PrivateValue(target));        \
    562    return wrapper;                                                     \
    563  }
    564 
    565 DEFINE_CREATE(ModuleRequestObject, ShellModuleRequestObjectWrapper_accessors,
    566              nullptr)
    567 
    568 DEFINE_NATIVE_CREATE(ImportEntry, ShellImportEntryWrapper_accessors, nullptr)
    569 DEFINE_NATIVE_CREATE(ExportEntry, ShellExportEntryWrapper_accessors, nullptr)
    570 DEFINE_NATIVE_CREATE(RequestedModule, ShellRequestedModuleWrapper_accessors,
    571                     nullptr)
    572 
    573 #undef DEFINE_CREATE
    574 #undef DEFINE_NATIVE_CREATE
    575 
    576 JS::ModuleType ShellModuleObjectWrapper::getModuleType() {
    577  return static_cast<JS::ModuleType>(getReservedSlot(ModuleTypeSlot).toInt32());
    578 }
    579 
    580 ShellModuleObjectWrapper* ShellModuleObjectWrapper::create(
    581    JSContext* cx, JS::Handle<ModuleObject*> target,
    582    JS::ModuleType moduleType) {
    583  JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &class_));
    584  if (!obj) {
    585    return nullptr;
    586  }
    587  if (!DefinePropertiesAndFunctions(cx, obj, ShellModuleObjectWrapper_accessors,
    588                                    nullptr)) {
    589    return nullptr;
    590  }
    591  auto* wrapper = &obj->as<ShellModuleObjectWrapper>();
    592  wrapper->initReservedSlot(TargetSlot, ObjectValue(*target));
    593  wrapper->initReservedSlot(ModuleTypeSlot,
    594                            Int32Value(static_cast<int32_t>(moduleType)));
    595  return wrapper;
    596 }