modules: adding load linked modules feature
authorThorsten Lorenz <thlorenz@gmx.de>
Mon, 15 Sep 2014 17:00:22 +0000 (12:00 -0500)
committerRod Vagg <rod@vagg.org>
Thu, 4 Dec 2014 10:20:28 +0000 (21:20 +1100)
- introduced NM_F_LINKED flag to identify linked modules
- setting node_is_initialized after calling V8::Initialize in order to
  make the right decision during initial module registration
- introduced modlist_linked in order to track modules that were
  pre-registered in order to complete it once node is initialized
- completing registration of linked module similarly to the way it's
  done inside DLOpen

PR-URL: https://github.com/iojs/io.js/pull/8
Reviewed-by: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
src/node.cc
src/node.h

index 66130de..57dd74f 100644 (file)
@@ -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<Object> exports);
 
 // DLOpen is process.dlopen(module, filename).
@@ -2262,6 +2284,46 @@ static void Binding(const FunctionCallbackInfo<Value>& args) {
   args.GetReturnValue().Set(exports);
 }
 
+static void LinkedBinding(const FunctionCallbackInfo<Value>& args) {
+  Environment* env = Environment::GetCurrent(args.GetIsolate());
+
+  Local<String> module = args[0]->ToString();
+
+  Local<Object> cache = env->binding_cache_object();
+  Local<Value> exports_v = cache->Get(module);
+
+  if (exports_v->IsObject())
+    return args.GetReturnValue().Set(exports_v.As<Object>());
+
+  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<Object> 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<String> property,
                                const PropertyCallbackInfo<Value>& 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.
index 8857751..afca6bf 100644 (file)
@@ -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);