/* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4
* -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "shell/ShellModuleObjectWrapper.h"
#include "mozilla/Maybe.h"
#include "mozilla/Span.h"
#include "jsapi.h" // JS_GetProperty, JS::Call, JS_NewPlainObject, JS_DefineProperty
#include "builtin/ModuleObject.h" // js::ModuleObject
#include "js/CallAndConstruct.h" // JS::Call
#include "js/CallArgs.h" // JS::CallArgs
#include "js/CallNonGenericMethod.h" // CallNonGenericMethod
#include "js/Class.h" // JSClass, JSCLASS_*
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
#include "js/ErrorReport.h" // JS_ReportErrorASCII
#include "js/PropertyAndElement.h" // JS_GetProperty
#include "js/PropertySpec.h" // JSPropertySpec, JS_PSG, JS_PS_END, JSFunctionSpec, JS_FN, JS_FN_END
#include "js/RootingAPI.h" // JS::Rooted, JS::Handle, JS::MutableHandle
#include "js/Value.h" // JS::Value
#include "vm/ArrayObject.h" // ArrayObject, NewDenseFullyAllocatedArray
#include "vm/GlobalObject.h" // DefinePropertiesAndFunctions
#include "vm/JSFunction.h" // JSFunction
#include "vm/JSObject.h" // JSObject
#include "vm/List.h" // ListObject
#include "vm/NativeObject.h" // NativeObject
#include "vm/Stack.h" // FixedInvokeArgs
#include "vm/NativeObject-inl.h" // NativeObject::ensureDenseInitializedLength
using namespace js;
using namespace js::shell;
using mozilla::Span;
#define DEFINE_CLASS_IMPL(
CLASS) \
CLASS* Shell
##CLASS##Wrapper::get() { \
return &getReservedSlot(TargetSlot).toObject().as<
CLASS>(); \
} \
/* static */ const JSClass Shell##CLASS##Wrapper::class_ = { \
"Shell" #CLASS "Wrapper", \
JSCLASS_HAS_RESERVED_SLOTS(Shell
##CLASS##Wrapper::SlotCount)}; \
MOZ_ALWAYS_INLINE
bool IsShell
##CLASS##Wrapper(JS::Handle<JS::Value> v) { \
return v.isObject() && v.toObject().is<Shell
##CLASS##Wrapper>(); \
}
#define DEFINE_CLASS(
CLASS) \
class Shell
##CLASS##Wrapper :
public js::NativeObject { \
public: \
using Target =
CLASS; \
enum ModuleSlot { TargetSlot = 0, SlotCount }; \
static const JSClass class_; \
static Shell
##CLASS##Wrapper* create(JSContext* cx, \
JS::Handle<
CLASS*> obj); \
CLASS* get(); \
}; \
DEFINE_CLASS_IMPL(
CLASS)
#define DEFINE_NATIVE_CLASS_IMPL(
CLASS) \
CLASS* Shell
##CLASS##Wrapper::get() { \
return static_cast<
CLASS*>(getReservedSlot(TargetSlot).toPrivate()); \
} \
/* static */ const JSClass Shell##CLASS##Wrapper::class_ = { \
"Shell" #CLASS "Wrapper", \
JSCLASS_HAS_RESERVED_SLOTS(Shell
##CLASS##Wrapper::SlotCount)}; \
MOZ_ALWAYS_INLINE
bool IsShell
##CLASS##Wrapper(JS::Handle<JS::Value> v) { \
return v.isObject() && v.toObject().is<Shell
##CLASS##Wrapper>(); \
}
#define DEFINE_NATIVE_CLASS(
CLASS) \
class Shell
##CLASS##Wrapper :
public js::NativeObject { \
public: \
using Target =
CLASS; \
enum ModuleSlot { OwnerSlot = 0, TargetSlot, SlotCount }; \
static const JSClass class_; \
static Shell
##CLASS##Wrapper* create(JSContext* cx, \
JS::Handle<JSObject*> owner, \
CLASS* obj); \
CLASS* get(); \
}; \
DEFINE_NATIVE_CLASS_IMPL(
CLASS)
DEFINE_CLASS(ModuleRequestObject)
DEFINE_NATIVE_CLASS(ImportEntry)
DEFINE_NATIVE_CLASS(ExportEntry)
DEFINE_NATIVE_CLASS(RequestedModule)
// NOTE: We don't need wrapper for IndirectBindingMap and ModuleNamespaceObject
DEFINE_CLASS_IMPL(ModuleObject)
#undef DEFINE_CLASS
#undef DEFINE_CLASS_IMPL
#undef DEFINE_NATIVE_CLASS
#undef DEFINE_NATIVE_CLASS_IMPL
bool IdentFilter(JSContext* cx, JS::Handle<JS::Value> from,
JS::MutableHandle<JS::Value> to) {
to.set(from);
return true;
}
bool GetModuleStatusName(JSContext* cx, JS::Handle<JS::Value> from,
JS::MutableHandle<JS::Value> to) {
if (!from.isInt32()) {
return false;
}
const char* statusStr = nullptr;
switch (
static_cast<ModuleStatus>(from.toInt32())) {
case ModuleStatus::Unlinked:
statusStr =
"Unlinked";
break;
case ModuleStatus::Linking:
statusStr =
"Linking";
break;
case ModuleStatus::Linked:
statusStr =
"Linked";
break;
case ModuleStatus::Evaluating:
statusStr =
"Evaluating";
break;
case ModuleStatus::EvaluatingAsync:
statusStr =
"EvaluatingAsync";
break;
case ModuleStatus::Evaluated:
statusStr =
"Evaluated";
break;
default:
MOZ_CRASH(
"Unknown ModuleStatus value");
}
JS::Rooted<JSString*> str(cx, JS_NewStringCopyZ(cx, statusStr));
if (!str) {
return false;
}
to.setString(str);
return true;
}
template <
class T>
bool SingleFilter(JSContext* cx, JS::Handle<JS::Value> from,
JS::MutableHandle<JS::Value> to) {
using TargetT =
typename T::Target;
if (!from.isObject() || !from.toObject().is<TargetT>()) {
to.set(from);
return true;
}
JS::Rooted<TargetT*> obj(cx, &from.toObject().as<TargetT>());
JS::Rooted<T*> filtered(cx, T::create(cx, obj));
if (!filtered) {
return false;
}
to.setObject(*filtered);
return true;
}
template <
class T>
bool ArrayFilter(JSContext* cx, JS::Handle<JS::Value> from,
JS::MutableHandle<JS::Value> to) {
using TargetT =
typename T::Target;
if (!from.isObject() || !from.toObject().is<ArrayObject>()) {
to.set(from);
return true;
}
JS::Rooted<ArrayObject*> fromArray(cx, &from.toObject().as<ArrayObject>());
uint32_t length = fromArray->length();
JS::Rooted<ArrayObject*> toArray(cx, NewDenseFullyAllocatedArray(cx, length));
if (!toArray) {
return false;
}
toArray->ensureDenseInitializedLength(0, length);
for (uint32_t i = 0; i < length; i++) {
JS::Rooted<JS::Value> item(cx, fromArray->getDenseElement(i));
JS::Rooted<TargetT*> req(cx, &item.toObject().as<TargetT>());
JS::Rooted<T*> filtered(cx, T::create(cx, req));
if (!filtered) {
return false;
}
toArray->initDenseElement(i, ObjectValue(*filtered));
}
to.setObject(*toArray);
return true;
}
template <
class T>
bool ListToArrayFilter(JSContext* cx, JS::Handle<JS::Value> from,
JS::MutableHandle<JS::Value> to) {
using TargetT =
typename T::Target;
if (!from.isObject() || !from.toObject().is<ListObject>()) {
to.set(from);
return true;
}
JS::Rooted<ListObject*> fromList(cx, &from.toObject().as<ListObject>());
uint32_t length = fromList->length();
JS::Rooted<ArrayObject*> toArray(cx, NewDenseFullyAllocatedArray(cx, length));
if (!toArray) {
return false;
}
toArray->ensureDenseInitializedLength(0, length);
for (uint32_t i = 0; i < length; i++) {
JS::Rooted<JS::Value> item(cx, fromList->get(i));
JS::Rooted<TargetT*> req(cx, &item.toObject().as<TargetT>());
JS::Rooted<T*> filtered(cx, T::create(cx, req));
if (!filtered) {
return false;
}
toArray->initDenseElement(i, ObjectValue(*filtered));
}
to.setObject(*toArray);
return true;
}
static Value StringOrNullValue(JSString* maybeString) {
if (!maybeString) {
return NullValue();
}
return StringValue(maybeString);
}
static Value Uint32Value(uint32_t x) {
MOZ_ASSERT(x <= INT32_MAX);
return Int32Value(x);
}
static Value Uint32OrUndefinedValue(mozilla::Maybe<uint32_t> x) {
if (x.isNothing()) {
return UndefinedValue();
}
return Uint32Value(x.value());
}
static Value ColumnNumberOneOriginValue(JS::ColumnNumberOneOrigin x) {
uint32_t column = x.oneOriginValue();
MOZ_ASSERT(column <= INT32_MAX);
return Int32Value(column);
}
static Value StatusValue(ModuleStatus status) {
return Int32Value(int32_t(status));
}
static Value ObjectOrUndefinedValue(JSObject* object) {
if (!object) {
return UndefinedValue();
}
return ObjectValue(*object);
}
template <
class T,
typename RawGetterT,
typename FilterT>
bool ShellModuleWrapperGetter(JSContext* cx,
const JS::CallArgs& args,
RawGetterT rawGetter, FilterT filter) {
JS::Rooted<T*> wrapper(cx, &args.thisv().toObject().as<T>());
if constexpr (std::is_same_v<T, ShellModuleObjectWrapper>) {
if (!wrapper->get()->hasCyclicModuleFields()) {
args.rval().set(UndefinedValue());
return true;
}
}
JS::Rooted<JS::Value> raw(cx, rawGetter(wrapper->get()));
JS::Rooted<JS::Value> filtered(cx);
if (!filter(cx, raw, &filtered)) {
return false;
}
args.rval().set(filtered);
return true;
}
#define DEFINE_GETTER_FUNCTIONS(
CLASS, PROP, TO_VALUE, FILTER) \
static Value Shell
##CLASS##Wrapper_
##PROP
##Getter_raw(
CLASS* obj) { \
return TO_VALUE(obj->PROP()); \
} \
static bool Shell
##CLASS##Wrapper_
##PROP
##Getter_impl( \
JSContext* cx,
const JS::CallArgs& args) { \
return ShellModuleWrapperGetter<Shell
##CLASS##Wrapper>( \
cx, args, Shell
##CLASS##Wrapper_
##PROP
##Getter_raw, FILTER); \
} \
static bool Shell
##CLASS##Wrapper_
##PROP
##Getter(JSContext* cx, \
unsigned argc, Value* vp) { \
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
return CallNonGenericMethod<IsShell
##CLASS##Wrapper, \
Shell
##CLASS##Wrapper_
##PROP
##Getter_impl>( \
cx, args); \
}
template <
class T>
bool SpanToArrayFilter(JSContext* cx, JS::Handle<JSObject*> owner,
Span<
const typename T::Target> from,
JS::MutableHandle<JS::Value> to) {
size_t length = from.Length();
JS::Rooted<ArrayObject*> toArray(cx, NewDenseFullyAllocatedArray(cx, length));
if (!toArray) {
return false;
}
toArray->ensureDenseInitializedLength(0, length);
for (uint32_t i = 0; i < length; i++) {
auto* element =
const_cast<
typename T::Target*>(&from[i]);
JS::Rooted<T*> filtered(cx, T::create(cx, owner, element));
if (!filtered) {
return false;
}
toArray->initDenseElement(i, ObjectValue(*filtered));
}
to.setObject(*toArray);
return true;
}
template <
class T,
typename RawGetterT,
typename FilterT>
bool ShellModuleNativeWrapperGetter(JSContext* cx,
const JS::CallArgs& args,
RawGetterT rawGetter, FilterT filter) {
JS::Rooted<T*> wrapper(cx, &args.thisv().toObject().as<T>());
if constexpr (std::is_same_v<T, ShellModuleObjectWrapper>) {
if (!wrapper->get()->hasCyclicModuleFields()) {
args.rval().set(UndefinedValue());
return true;
}
}
JS::Rooted<
typename T::Target*> owner(cx, wrapper->get());
JS::Rooted<JS::Value> filtered(cx);
if (!filter(cx, owner, rawGetter(owner), &filtered)) {
return false;
}
args.rval().set(filtered);
return true;
}
bool ModuleTypeToString(JSContext* cx, JS::Handle<JSObject*> owner,
JS::ModuleType moduleType,
JS::MutableHandle<JS::Value> to) {
switch (moduleType) {
case JS::ModuleType::Unknown:
to.setString(cx->names().unknown);
break;
case JS::ModuleType::JavaScript:
to.setString(cx->names().js);
break;
case JS::ModuleType::JSON:
to.setString(cx->names().json);
break;
}
MOZ_ASSERT(!to.isUndefined());
return true;
}
#define DEFINE_NATIVE_GETTER_FUNCTIONS(
CLASS, PROP, FILTER) \
static auto Shell
##CLASS##Wrapper_
##PROP
##Getter_raw(
CLASS* obj) { \
return obj->PROP(); \
} \
static bool Shell
##CLASS##Wrapper_
##PROP
##Getter_impl( \
JSContext* cx,
const JS::CallArgs& args) { \
return ShellModuleNativeWrapperGetter<Shell
##CLASS##Wrapper>( \
cx, args, Shell
##CLASS##Wrapper_
##PROP
##Getter_raw, FILTER); \
} \
static bool Shell
##CLASS##Wrapper_
##PROP
##Getter(JSContext* cx, \
unsigned argc, Value* vp) { \
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
return CallNonGenericMethod<IsShell
##CLASS##Wrapper, \
Shell
##CLASS##Wrapper_
##PROP
##Getter_impl>( \
cx, args); \
}
DEFINE_GETTER_FUNCTIONS(ModuleRequestObject, specifier, StringOrNullValue,
IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleRequestObject, getFirstUnsupportedAttributeKey,
StringOrNullValue, IdentFilter)
DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleRequestObject, moduleType,
ModuleTypeToString);
static const JSPropertySpec ShellModuleRequestObjectWrapper_accessors[] = {
JS_PSG(
"specifier", ShellModuleRequestObjectWrapper_specifierGetter, 0),
JS_PSG(
"moduleType", ShellModuleRequestObjectWrapper_moduleTypeGetter, 0),
JS_PSG(
"firstUnsupportedAttributeKey",
ShellModuleRequestObjectWrapper_getFirstUnsupportedAttributeKeyGetter,
0),
JS_PS_END,
};
DEFINE_GETTER_FUNCTIONS(ImportEntry, moduleRequest, ObjectOrNullValue,
SingleFilter<ShellModuleRequestObjectWrapper>)
DEFINE_GETTER_FUNCTIONS(ImportEntry, importName, StringOrNullValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ImportEntry, localName, StringValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ImportEntry, lineNumber, Uint32Value, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ImportEntry, columnNumber, ColumnNumberOneOriginValue,
IdentFilter)
static const JSPropertySpec ShellImportEntryWrapper_accessors[] = {
JS_PSG(
"moduleRequest", ShellImportEntryWrapper_moduleRequestGetter, 0),
JS_PSG(
"importName", ShellImportEntryWrapper_importNameGetter, 0),
JS_PSG(
"localName", ShellImportEntryWrapper_localNameGetter, 0),
JS_PSG(
"lineNumber", ShellImportEntryWrapper_lineNumberGetter, 0),
JS_PSG(
"columnNumber", ShellImportEntryWrapper_columnNumberGetter, 0),
JS_PS_END,
};
DEFINE_GETTER_FUNCTIONS(ExportEntry, exportName, StringOrNullValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ExportEntry, moduleRequest, ObjectOrNullValue,
SingleFilter<ShellModuleRequestObjectWrapper>)
DEFINE_GETTER_FUNCTIONS(ExportEntry, importName, StringOrNullValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ExportEntry, localName, StringOrNullValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ExportEntry, lineNumber, Uint32Value, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ExportEntry, columnNumber, ColumnNumberOneOriginValue,
IdentFilter)
static const JSPropertySpec ShellExportEntryWrapper_accessors[] = {
JS_PSG(
"exportName", ShellExportEntryWrapper_exportNameGetter, 0),
JS_PSG(
"moduleRequest", ShellExportEntryWrapper_moduleRequestGetter, 0),
JS_PSG(
"importName", ShellExportEntryWrapper_importNameGetter, 0),
JS_PSG(
"localName", ShellExportEntryWrapper_localNameGetter, 0),
JS_PSG(
"lineNumber", ShellExportEntryWrapper_lineNumberGetter, 0),
JS_PSG(
"columnNumber", ShellExportEntryWrapper_columnNumberGetter, 0),
JS_PS_END,
};
DEFINE_GETTER_FUNCTIONS(RequestedModule, moduleRequest, ObjectOrNullValue,
SingleFilter<ShellModuleRequestObjectWrapper>)
DEFINE_GETTER_FUNCTIONS(RequestedModule, lineNumber, Uint32Value, IdentFilter)
DEFINE_GETTER_FUNCTIONS(RequestedModule, columnNumber,
ColumnNumberOneOriginValue, IdentFilter)
static const JSPropertySpec ShellRequestedModuleWrapper_accessors[] = {
JS_PSG(
"moduleRequest", ShellRequestedModuleWrapper_moduleRequestGetter, 0),
JS_PSG(
"lineNumber", ShellRequestedModuleWrapper_lineNumberGetter, 0),
JS_PSG(
"columnNumber", ShellRequestedModuleWrapper_columnNumberGetter, 0),
JS_PS_END,
};
DEFINE_GETTER_FUNCTIONS(ModuleObject, namespace_, ObjectOrNullValue,
IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleObject, status, StatusValue, GetModuleStatusName)
DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeEvaluationError, Value, IdentFilter)
DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, requestedModules,
SpanToArrayFilter<ShellRequestedModuleWrapper>)
DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, importEntries,
SpanToArrayFilter<ShellImportEntryWrapper>)
DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, localExportEntries,
SpanToArrayFilter<ShellExportEntryWrapper>)
DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, indirectExportEntries,
SpanToArrayFilter<ShellExportEntryWrapper>)
DEFINE_NATIVE_GETTER_FUNCTIONS(ModuleObject, starExportEntries,
SpanToArrayFilter<ShellExportEntryWrapper>)
DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeDfsIndex, Uint32OrUndefinedValue,
IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeDfsAncestorIndex,
Uint32OrUndefinedValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleObject, hasTopLevelAwait, BooleanValue,
IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeTopLevelCapability,
ObjectOrUndefinedValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleObject, isAsyncEvaluating, BooleanValue,
IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleObject, maybeAsyncEvaluatingPostOrder,
Uint32OrUndefinedValue, IdentFilter)
DEFINE_GETTER_FUNCTIONS(ModuleObject, asyncParentModules, ObjectOrNullValue,
ListToArrayFilter<ShellModuleObjectWrapper>)
DEFINE_GETTER_FUNCTIONS(ModuleObject, maybePendingAsyncDependencies,
Uint32OrUndefinedValue, IdentFilter)
static const JSPropertySpec ShellModuleObjectWrapper_accessors[] = {
JS_PSG(
"namespace", ShellModuleObjectWrapper_namespace_Getter, 0),
JS_PSG(
"status", ShellModuleObjectWrapper_statusGetter, 0),
JS_PSG(
"evaluationError",
ShellModuleObjectWrapper_maybeEvaluationErrorGetter, 0),
JS_PSG(
"requestedModules", ShellModuleObjectWrapper_requestedModulesGetter,
0),
JS_PSG(
"importEntries", ShellModuleObjectWrapper_importEntriesGetter, 0),
JS_PSG(
"localExportEntries",
ShellModuleObjectWrapper_localExportEntriesGetter, 0),
JS_PSG(
"indirectExportEntries",
ShellModuleObjectWrapper_indirectExportEntriesGetter, 0),
JS_PSG(
"starExportEntries",
ShellModuleObjectWrapper_starExportEntriesGetter, 0),
JS_PSG(
"dfsIndex", ShellModuleObjectWrapper_maybeDfsIndexGetter, 0),
JS_PSG(
"dfsAncestorIndex",
ShellModuleObjectWrapper_maybeDfsAncestorIndexGetter, 0),
JS_PSG(
"hasTopLevelAwait", ShellModuleObjectWrapper_hasTopLevelAwaitGetter,
0),
JS_PSG(
"topLevelCapability",
ShellModuleObjectWrapper_maybeTopLevelCapabilityGetter, 0),
JS_PSG(
"isAsyncEvaluating",
ShellModuleObjectWrapper_isAsyncEvaluatingGetter, 0),
JS_PSG(
"asyncEvaluatingPostOrder",
ShellModuleObjectWrapper_maybeAsyncEvaluatingPostOrderGetter, 0),
JS_PSG(
"asyncParentModules",
ShellModuleObjectWrapper_asyncParentModulesGetter, 0),
JS_PSG(
"pendingAsyncDependencies",
ShellModuleObjectWrapper_maybePendingAsyncDependenciesGetter, 0),
JS_PS_END,
};
#undef DEFINE_GETTER_FUNCTIONS
#undef DEFINE_NATIVE_GETTER_FUNCTIONS
#define DEFINE_CREATE(
CLASS, ACCESSORS, FUNCTIONS) \
/* static */ \
Shell
##CLASS##Wrapper* Shell
##CLASS##Wrapper::create( \
JSContext* cx, JS::Handle<
CLASS*> target) { \
JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &class_)); \
if (!obj) { \
return nullptr; \
} \
if (!DefinePropertiesAndFunctions(cx, obj, ACCESSORS, FUNCTIONS)) { \
return nullptr; \
} \
auto* wrapper = &obj->as<Shell
##CLASS##Wrapper>(); \
wrapper->initReservedSlot(TargetSlot, ObjectValue(*target)); \
return wrapper; \
}
#define DEFINE_NATIVE_CREATE(
CLASS, ACCESSORS, FUNCTIONS) \
/* static */ \
Shell
##CLASS##Wrapper* Shell
##CLASS##Wrapper::create( \
JSContext* cx, JS::Handle<JSObject*> owner,
CLASS* target) { \
JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, &class_)); \
if (!obj) { \
return nullptr; \
} \
if (!DefinePropertiesAndFunctions(cx, obj, ACCESSORS, FUNCTIONS)) { \
return nullptr; \
} \
auto* wrapper = &obj->as<Shell
##CLASS##Wrapper>(); \
wrapper->initReservedSlot(OwnerSlot, ObjectValue(*owner)); \
wrapper->initReservedSlot(TargetSlot, PrivateValue(target)); \
return wrapper; \
}
DEFINE_CREATE(ModuleRequestObject, ShellModuleRequestObjectWrapper_accessors,
nullptr)
DEFINE_NATIVE_CREATE(ImportEntry, ShellImportEntryWrapper_accessors, nullptr)
DEFINE_NATIVE_CREATE(ExportEntry, ShellExportEntryWrapper_accessors, nullptr)
DEFINE_NATIVE_CREATE(RequestedModule, ShellRequestedModuleWrapper_accessors,
nullptr)
DEFINE_CREATE(ModuleObject, ShellModuleObjectWrapper_accessors, nullptr)
#undef DEFINE_CREATE
#undef DEFINE_NATIVE_CREATE