Skip to content

Commit

Permalink
Bug 1487346 - Replace shell module loader property with a hook functi…
Browse files Browse the repository at this point in the history
…on r=anba
  • Loading branch information
jonco3 committed Aug 31, 2018
1 parent 905a4c8 commit fefc9ff
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 41 deletions.
3 changes: 2 additions & 1 deletion js/src/shell/ModuleLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,11 @@ const ReflectLoader = new class {
}
};

setModuleLoadHook((path) => ReflectLoader.importRoot(path));

setModuleResolveHook((module, requestName) => {
let path = ReflectLoader.resolve(requestName, module);
return ReflectLoader.loadAndParse(path);
});

Reflect.Loader = ReflectLoader;
}
85 changes: 45 additions & 40 deletions js/src/shell/js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ enum JSShellExitCode {
// Define use of application-specific slots on the shell's global object.
enum GlobalAppSlot
{
GlobalAppSlotModuleResolveHook,
GlobalAppSlotModuleLoadHook, // Shell-specific; load a module graph
GlobalAppSlotModuleResolveHook, // HostResolveImportedModule
GlobalAppSlotCount
};
static_assert(GlobalAppSlotCount <= JSCLASS_GLOBAL_APPLICATION_SLOTS,
Expand Down Expand Up @@ -648,58 +649,33 @@ InitModuleLoader(JSContext* cx)
}

static bool
GetLoaderObject(JSContext* cx, MutableHandleObject resultOut)
GetModuleImportHook(JSContext* cx, MutableHandleFunction resultOut)
{
// Look up the |Reflect.Loader| object that has been defined by the module
// loader.

RootedObject object(cx, cx->global());
RootedValue value(cx);
if (!JS_GetProperty(cx, object, "Reflect", &value) || !value.isObject())
return false;

object = &value.toObject();
if (!JS_GetProperty(cx, object, "Loader", &value) || !value.isObject())
return false;

resultOut.set(&value.toObject());
return true;
}

static bool
GetImportRootMethod(JSContext* cx, HandleObject loader, MutableHandleFunction resultOut)
{
// Look up the module loader's |importRoot| method.

RootedValue value(cx);
if (!JS_GetProperty(cx, loader, "importRoot", &value) || !value.isObject())
Handle<GlobalObject*> global = cx->global();
RootedValue hookValue(cx, global->getReservedSlot(GlobalAppSlotModuleLoadHook));
if (hookValue.isUndefined()) {
JS_ReportErrorASCII(cx, "Module load hook not set");
return false;
}

RootedObject object(cx, &value.toObject());
if (!object->is<JSFunction>())
if (!hookValue.isObject() || !hookValue.toObject().is<JSFunction>()) {
JS_ReportErrorASCII(cx, "Module load hook is not a function");
return false;
}

resultOut.set(&object->as<JSFunction>());
resultOut.set(&hookValue.toObject().as<JSFunction>());
return true;
}

static MOZ_MUST_USE bool
RunModule(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
{
// Execute a module by calling Reflect.Loader.importRoot on the resolved
// filename.

RootedObject loaderObj(cx);
if (!GetLoaderObject(cx, &loaderObj)) {
JS_ReportErrorASCII(cx, "Failed to get Reflect.Loader");
return false;
}
// Execute a module by calling the module loader's import hook on the
// resolved filename.

RootedFunction importFun(cx);
if (!GetImportRootMethod(cx, loaderObj, &importFun)) {
JS_ReportErrorASCII(cx, "Failed to get Reflect.Loader.importRoot method");
if (!GetModuleImportHook(cx, &importFun))
return false;
}

RootedString path(cx, JS_NewStringCopyZ(cx, filename));
if (!path)
Expand All @@ -713,7 +689,7 @@ RunModule(JSContext* cx, const char* filename, FILE* file, bool compileOnly)
args[0].setString(path);

RootedValue value(cx);
return JS_CallFunction(cx, loaderObj, importFun, args, &value);
return JS_CallFunction(cx, nullptr, importFun, args, &value);
}

static bool
Expand Down Expand Up @@ -3895,6 +3871,29 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp)
return true;
}

static bool
SetModuleLoadHook(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() != 1) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
"setModuleLoadHook", "0", "s");
return false;
}

if (!args[0].isObject() || !args[0].toObject().is<JSFunction>()) {
const char* typeName = InformalValueTypeName(args[0]);
JS_ReportErrorASCII(cx, "expected hook function, got %s", typeName);
return false;
}

Handle<GlobalObject*> global = cx->global();
global->setReservedSlot(GlobalAppSlotModuleLoadHook, args[0]);

args.rval().setUndefined();
return true;
}

static bool
SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
{
Expand Down Expand Up @@ -6098,6 +6097,12 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
"parseModule(code)",
" Parses source text as a module and returns a Module object."),

JS_FN_HELP("setModuleLoadHook", SetModuleLoadHook, 1, 0,
"setModuleLoadHook(function(path))",
" Set the shell specific module load hook to |function|.\n"
" This hook is used to load a module graph. It should be implemented by the\n"
" module loader."),

JS_FN_HELP("setModuleResolveHook", SetModuleResolveHook, 1, 0,
"setModuleResolveHook(function(module, specifier) {})",
" Set the HostResolveImportedModule hook to |function|.\n"
Expand Down

0 comments on commit fefc9ff

Please sign in to comment.