diff --git a/src/node.cc b/src/node.cc index 532f902aad..edb546052d 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) @@ -2051,8 +2053,16 @@ 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 { - assert(modpending == NULL); + // Once node::Init was called we can only register dynamic modules. + // See DLOpen. + CHECK_NE(modpending, NULL); modpending = mp; } } @@ -2069,6 +2079,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). @@ -2275,6 +2297,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) { @@ -2816,6 +2878,7 @@ void SetupProcessObject(Environment* env, NODE_SET_METHOD(process, "memoryUsage", MemoryUsage); NODE_SET_METHOD(process, "binding", Binding); + NODE_SET_METHOD(process, "_linkedBinding", LinkedBinding); NODE_SET_METHOD(process, "_setupAsyncListener", SetupAsyncListener); NODE_SET_METHOD(process, "_setupNextTick", SetupNextTick); @@ -3724,6 +3787,7 @@ int Start(int argc, char** argv) { int code; V8::Initialize(); + node_is_initialized = true; { Locker locker(node_isolate); Isolate::Scope isolate_scope(node_isolate); diff --git a/src/node.h b/src/node.h index 384b790c97..bb8a3de0e4 100644 --- a/src/node.h +++ b/src/node.h @@ -347,6 +347,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; @@ -361,6 +362,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);