diff --git a/src/node.cc b/src/node.cc index 66130de0cb7f12..57dd74f6701c5d 100644 --- a/src/node.cc +++ b/src/node.cc @@ -131,8 +131,10 @@ static bool use_debug_agent = false; static bool debug_wait_connect = false; static int debug_port = 5858; static bool v8_is_profiling = false; +static bool node_is_initialized = false; static node_module* modpending; static node_module* modlist_builtin; +static node_module* modlist_linked; static node_module* modlist_addon; #if defined(NODE_HAVE_I18N_SUPPORT) @@ -2040,7 +2042,15 @@ extern "C" void node_module_register(void* m) { if (mp->nm_flags & NM_F_BUILTIN) { mp->nm_link = modlist_builtin; modlist_builtin = mp; + } else if (!node_is_initialized) { + // "Linked" modules are included as part of the node project. + // Like builtins they are registered *before* node::Init runs. + mp->nm_flags = NM_F_LINKED; + mp->nm_link = modlist_linked; + modlist_linked = mp; } else { + // Once node::Init was called we can only register dynamic modules. + // See DLOpen. CHECK_EQ(modpending, nullptr); modpending = mp; } @@ -2058,6 +2068,18 @@ struct node_module* get_builtin_module(const char* name) { return (mp); } +struct node_module* get_linked_module(const char* name) { + struct node_module* mp; + + for (mp = modlist_linked; mp != NULL; mp = mp->nm_link) { + if (strcmp(mp->nm_modname, name) == 0) + break; + } + + CHECK(mp == NULL || (mp->nm_flags & NM_F_LINKED) != 0); + return mp; +} + typedef void (UV_DYNAMIC* extInit)(Handle exports); // DLOpen is process.dlopen(module, filename). @@ -2262,6 +2284,46 @@ static void Binding(const FunctionCallbackInfo& args) { args.GetReturnValue().Set(exports); } +static void LinkedBinding(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args.GetIsolate()); + + Local module = args[0]->ToString(); + + Local cache = env->binding_cache_object(); + Local exports_v = cache->Get(module); + + if (exports_v->IsObject()) + return args.GetReturnValue().Set(exports_v.As()); + + node::Utf8Value module_v(module); + node_module* mod = get_linked_module(*module_v); + + if (mod == NULL) { + char errmsg[1024]; + snprintf(errmsg, + sizeof(errmsg), + "No such module was linked: %s", + *module_v); + return env->ThrowError(errmsg); + } + + Local exports = Object::New(env->isolate()); + + if (mod->nm_context_register_func != NULL) { + mod->nm_context_register_func(exports, + module, + env->context(), + mod->nm_priv); + } else if (mod->nm_register_func != NULL) { + mod->nm_register_func(exports, module, mod->nm_priv); + } else { + return env->ThrowError("Linked module has no declared entry point."); + } + + cache->Set(module, exports); + + args.GetReturnValue().Set(exports); +} static void ProcessTitleGetter(Local property, const PropertyCallbackInfo& info) { @@ -2801,6 +2863,7 @@ void SetupProcessObject(Environment* env, env->SetMethod(process, "memoryUsage", MemoryUsage); env->SetMethod(process, "binding", Binding); + env->SetMethod(process, "_linkedBinding", LinkedBinding); env->SetMethod(process, "_setupAsyncListener", SetupAsyncListener); env->SetMethod(process, "_setupNextTick", SetupNextTick); @@ -3700,6 +3763,7 @@ int Start(int argc, char** argv) { int code; V8::Initialize(); + node_is_initialized = true; // Fetch a reference to the main isolate, so we have a reference to it // even when we need it to access it from another (debugger) thread. diff --git a/src/node.h b/src/node.h index 8857751b509c8d..afca6bf0d332d0 100644 --- a/src/node.h +++ b/src/node.h @@ -339,6 +339,7 @@ typedef void (*addon_context_register_func)( void* priv); #define NM_F_BUILTIN 0x01 +#define NM_F_LINKED 0x02 struct node_module { int nm_version; @@ -353,6 +354,7 @@ struct node_module { }; node_module* get_builtin_module(const char *name); +node_module* get_linked_module(const char *name); extern "C" NODE_EXTERN void node_module_register(void* mod);