Skip to content

Commit

Permalink
added addModuleLoadHook, a module loader hook interface to node/v8
Browse files Browse the repository at this point in the history
this new hook will execute a js callback with the esm object
exported by a script, and the path used to load the script.
  • Loading branch information
Bryan Clement committed Feb 16, 2018
1 parent a16081c commit bf8a468
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 2 deletions.
7 changes: 7 additions & 0 deletions deps/v8/include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -6319,6 +6319,8 @@ enum class PromiseHookType { kInit, kResolve, kBefore, kAfter };
typedef void (*PromiseHook)(PromiseHookType type, Local<Promise> promise,
Local<Value> parent);

typedef void (*ModuleLoadHook)(Local<Context> context, Local<Value> exported_obj, Local<Module> module);

// --- Promise Reject Callback ---
enum PromiseRejectEvent {
kPromiseRejectWithNoHandler = 0,
Expand Down Expand Up @@ -7511,6 +7513,11 @@ class V8_EXPORT Isolate {
*/
void SetPromiseHook(PromiseHook hook);

/**
* Set the ModuleLoadHook callback for module loading events.
*/
void SetModuleLoadHook(ModuleLoadHook hook);

/**
* Set callback to notify about promise reject with no handler, or
* revocation of such a previous notification once the handler is added.
Expand Down
5 changes: 5 additions & 0 deletions deps/v8/src/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8887,6 +8887,11 @@ void Isolate::SetPromiseHook(PromiseHook hook) {
isolate->SetPromiseHook(hook);
}

void Isolate::SetModuleLoadHook(ModuleLoadHook hook) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->SetModuleLoadHook(hook);
}

void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
if (callback == nullptr) return;
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
Expand Down
11 changes: 11 additions & 0 deletions deps/v8/src/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,7 @@ Isolate::Isolate(bool enable_serializer)
rail_mode_(PERFORMANCE_ANIMATION),
promise_hook_or_debug_is_active_(false),
promise_hook_(nullptr),
module_load_hook_(nullptr),
load_start_time_ms_(0),
serializer_enabled_(enable_serializer),
has_fatal_error_(false),
Expand Down Expand Up @@ -3572,6 +3573,16 @@ void Isolate::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
v8::Utils::ToLocal(parent));
}

void Isolate::SetModuleLoadHook(ModuleLoadHook hook) {
module_load_hook_ = hook;
}

void Isolate::RunModuleLoadHook(Handle<Object> exported_module, Handle<Module> module) {
if (module_load_hook_ == nullptr) return;
v8::Local<v8::Context> api_context = v8::Utils::ToLocal(native_context());
module_load_hook_(api_context, v8::Utils::ToLocal(exported_module), v8::Utils::ToLocal(module));
}

void Isolate::SetPromiseRejectCallback(PromiseRejectCallback callback) {
promise_reject_callback_ = callback;
}
Expand Down
4 changes: 4 additions & 0 deletions deps/v8/src/isolate.h
Original file line number Diff line number Diff line change
Expand Up @@ -1239,6 +1239,9 @@ class Isolate {
void RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise,
Handle<Object> parent);

void SetModuleLoadHook(ModuleLoadHook hook);
void RunModuleLoadHook(Handle<Object> exported_obj, Handle<Module> module);

void AddDetachedContext(Handle<Context> context);
void CheckDetachedContextsAfterGC();

Expand Down Expand Up @@ -1530,6 +1533,7 @@ class Isolate {
base::AtomicValue<RAILMode> rail_mode_;
bool promise_hook_or_debug_is_active_;
PromiseHook promise_hook_;
ModuleLoadHook module_load_hook_;
HostImportModuleDynamicallyCallback host_import_module_dynamically_callback_;
HostInitializeImportMetaObjectCallback
host_initialize_import_meta_object_callback_;
Expand Down
6 changes: 5 additions & 1 deletion deps/v8/src/objects/module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -713,9 +713,13 @@ MaybeHandle<Object> Module::Evaluate(Handle<Module> module,
->BooleanValue());

MaybeTransitionComponent(module, stack, kEvaluated);
return handle(
MaybeHandle<Object> exported_obj = handle(
static_cast<JSIteratorResult*>(JSObject::cast(*result))->value(),
isolate);
if (!exported_obj.is_null()) {
isolate->RunModuleLoadHook(exported_obj.ToHandleChecked(), module);
}
return exported_obj;
}

namespace {
Expand Down
5 changes: 4 additions & 1 deletion lib/internal/loader/Loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const errors = require('internal/errors');
const ModuleMap = require('internal/loader/ModuleMap');
const { addModuleLoadHook } = internalBinding('module_wrap');
const ModuleJob = require('internal/loader/ModuleJob');
const defaultResolve = require('internal/loader/DefaultResolve');
const createDynamicModule = require('internal/loader/CreateDynamicModule');
Expand Down Expand Up @@ -70,12 +71,14 @@ class Loader {
return module.namespace();
}

hook({ resolve, dynamicInstantiate }) {
hook({ resolve, dynamicInstantiate, postLoad }) {
// Use .bind() to avoid giving access to the Loader instance when called.
if (resolve !== undefined)
this._resolve = FunctionBind(resolve, null);
if (dynamicInstantiate !== undefined)
this._dynamicInstantiate = FunctionBind(dynamicInstantiate, null);
if (postLoad !== undefined)
addModuleLoadHook(FunctionBind(postLoad, null));
}

async getModuleJob(specifier, parentURL) {
Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ struct PackageConfig {
V(fdclose_constructor_template, v8::ObjectTemplate) \
V(host_import_module_dynamically_callback, v8::Function) \
V(host_initialize_import_meta_object_callback, v8::Function) \
V(module_load_callback, v8::Function) \
V(http2ping_constructor_template, v8::ObjectTemplate) \
V(http2stream_constructor_template, v8::ObjectTemplate) \
V(http2settings_constructor_template, v8::ObjectTemplate) \
Expand Down
31 changes: 31 additions & 0 deletions src/module_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,36 @@ void ModuleWrap::SetInitializeImportMetaObjectCallback(
HostInitializeImportMetaObjectCallback);
}

void ModuleWrap::AddModuleLoadHook(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
if (!args[0]->IsFunction()) {
env->ThrowError("first argument is not a function");
return;
}

Local<Function> module_load_callback = args[0].As<Function>();
env->set_module_load_callback(module_load_callback);

isolate->SetModuleLoadHook(ModuleLoadHookCallback);

}

void ModuleWrap::ModuleLoadHookCallback(
Local<Context> context, Local<Value> exported_module, Local<Module> module) {
Isolate* isolate = context->GetIsolate();
Environment* env = Environment::GetCurrent(context);

Local<String> url =
env->module_map.find(module->GetIdentityHash())->second->url_.Get(isolate);
Local<Function> callback =
env->module_load_callback();
Local<Value> args[] = {exported_module, url};
callback->Call(context, Undefined(isolate), arraysize(args), args)
.ToLocalChecked();
}

void ModuleWrap::Initialize(Local<Object> target,
Local<Value> unused,
Local<Context> context) {
Expand All @@ -816,6 +846,7 @@ void ModuleWrap::Initialize(Local<Object> target,
GetStaticDependencySpecifiers);

target->Set(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"), tpl->GetFunction());
env->SetMethod(target, "addModuleLoadHook", ModuleWrap::AddModuleLoadHook);
env->SetMethod(target, "resolve", node::loader::ModuleWrap::Resolve);
env->SetMethod(target,
"setImportModuleDynamicallyCallback",
Expand Down
5 changes: 5 additions & 0 deletions src/module_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class ModuleWrap : public BaseObject {
v8::Local<v8::Context> context,
v8::Local<v8::Module> module,
v8::Local<v8::Object> meta);
static void ModuleLoadHookCallback(
v8::Local<v8::Context> context,
v8::Local<v8::Value> exported_module,
v8::Local<v8::Module> module);

private:
ModuleWrap(Environment* env,
Expand All @@ -47,6 +51,7 @@ class ModuleWrap : public BaseObject {
static void Namespace(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetStatus(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetError(const v8::FunctionCallbackInfo<v8::Value>& args);
static void AddModuleLoadHook(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetStaticDependencySpecifiers(
const v8::FunctionCallbackInfo<v8::Value>& args);

Expand Down

0 comments on commit bf8a468

Please sign in to comment.