summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node.gyp2
-rw-r--r--src/node.cc409
-rw-r--r--src/node_api.cc3
-rw-r--r--src/node_binding.cc471
-rw-r--r--src/node_binding.h64
-rw-r--r--src/node_internals.h112
6 files changed, 552 insertions, 509 deletions
diff --git a/node.gyp b/node.gyp
index 3cbbe61e57..4ad5ef3a9f 100644
--- a/node.gyp
+++ b/node.gyp
@@ -343,6 +343,7 @@
'src/module_wrap.cc',
'src/node.cc',
'src/node_api.cc',
+ 'src/node_binding.cc',
'src/node_buffer.cc',
'src/node_config.cc',
'src/node_constants.cc',
@@ -414,6 +415,7 @@
'src/node.h',
'src/node_api.h',
'src/node_api_types.h',
+ 'src/node_binding.h',
'src/node_buffer.h',
'src/node_constants.h',
'src/node_context_data.h',
diff --git a/src/node.cc b/src/node.cc
index e01baf9726..01690a1e6c 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -19,6 +19,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
+#include "node_binding.h"
#include "node_buffer.h"
#include "node_constants.h"
#include "node_context_data.h"
@@ -113,20 +114,6 @@ typedef int mode_t;
#include <grp.h> // getgrnam()
#endif
-#if defined(__POSIX__)
-#include <dlfcn.h>
-#endif
-
-// This is used to load built-in modules. Instead of using
-// __attribute__((constructor)), we call the _register_<modname>
-// function for each built-in modules explicitly in
-// node::RegisterBuiltinModules(). This is only forward declaration.
-// The definitions are in each module's implementation when calling
-// the NODE_BUILTIN_MODULE_CONTEXT_AWARE.
-#define V(modname) void _register_##modname();
- NODE_BUILTIN_MODULES(V)
-#undef V
-
namespace node {
using native_module::NativeModuleLoader;
@@ -173,13 +160,6 @@ using v8::V8;
using v8::Value;
static bool v8_is_profiling = false;
-static bool node_is_initialized = false;
-static uv_once_t init_modpending_once = UV_ONCE_INIT;
-static uv_key_t thread_local_modpending;
-static node_module* modlist_builtin;
-static node_module* modlist_internal;
-static node_module* modlist_linked;
-static node_module* modlist_addon;
#ifdef NODE_EXPERIMENTAL_HTTP
static const char llhttp_version[] =
@@ -825,257 +805,6 @@ static void Exit(const FunctionCallbackInfo<Value>& args) {
env->Exit(code);
}
-extern "C" void node_module_register(void* m) {
- struct node_module* mp = reinterpret_cast<struct node_module*>(m);
-
- if (mp->nm_flags & NM_F_BUILTIN) {
- mp->nm_link = modlist_builtin;
- modlist_builtin = mp;
- } else if (mp->nm_flags & NM_F_INTERNAL) {
- mp->nm_link = modlist_internal;
- modlist_internal = 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 {
- uv_key_set(&thread_local_modpending, mp);
- }
-}
-
-inline struct node_module* FindModule(struct node_module* list,
- const char* name,
- int flag) {
- struct node_module* mp;
-
- for (mp = list; mp != nullptr; mp = mp->nm_link) {
- if (strcmp(mp->nm_modname, name) == 0)
- break;
- }
-
- CHECK(mp == nullptr || (mp->nm_flags & flag) != 0);
- return mp;
-}
-
-node_module* get_builtin_module(const char* name) {
- return FindModule(modlist_builtin, name, NM_F_BUILTIN);
-}
-node_module* get_internal_module(const char* name) {
- return FindModule(modlist_internal, name, NM_F_INTERNAL);
-}
-node_module* get_linked_module(const char* name) {
- return FindModule(modlist_linked, name, NM_F_LINKED);
-}
-
-class DLib {
- public:
-#ifdef __POSIX__
- static const int kDefaultFlags = RTLD_LAZY;
-#else
- static const int kDefaultFlags = 0;
-#endif
-
- inline DLib(const char* filename, int flags)
- : filename_(filename), flags_(flags), handle_(nullptr) {}
-
- inline bool Open();
- inline void Close();
- inline void* GetSymbolAddress(const char* name);
-
- const std::string filename_;
- const int flags_;
- std::string errmsg_;
- void* handle_;
-#ifndef __POSIX__
- uv_lib_t lib_;
-#endif
- private:
- DISALLOW_COPY_AND_ASSIGN(DLib);
-};
-
-
-#ifdef __POSIX__
-bool DLib::Open() {
- handle_ = dlopen(filename_.c_str(), flags_);
- if (handle_ != nullptr)
- return true;
- errmsg_ = dlerror();
- return false;
-}
-
-void DLib::Close() {
- if (handle_ == nullptr) return;
- dlclose(handle_);
- handle_ = nullptr;
-}
-
-void* DLib::GetSymbolAddress(const char* name) {
- return dlsym(handle_, name);
-}
-#else // !__POSIX__
-bool DLib::Open() {
- int ret = uv_dlopen(filename_.c_str(), &lib_);
- if (ret == 0) {
- handle_ = static_cast<void*>(lib_.handle);
- return true;
- }
- errmsg_ = uv_dlerror(&lib_);
- uv_dlclose(&lib_);
- return false;
-}
-
-void DLib::Close() {
- if (handle_ == nullptr) return;
- uv_dlclose(&lib_);
- handle_ = nullptr;
-}
-
-void* DLib::GetSymbolAddress(const char* name) {
- void* address;
- if (0 == uv_dlsym(&lib_, name, &address)) return address;
- return nullptr;
-}
-#endif // !__POSIX__
-
-using InitializerCallback = void (*)(Local<Object> exports,
- Local<Value> module,
- Local<Context> context);
-
-inline InitializerCallback GetInitializerCallback(DLib* dlib) {
- const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
- return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
-}
-
-inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
- const char* name =
- STRINGIFY(NAPI_MODULE_INITIALIZER_BASE) STRINGIFY(NAPI_MODULE_VERSION);
- return
- reinterpret_cast<napi_addon_register_func>(dlib->GetSymbolAddress(name));
-}
-
-void InitModpendingOnce() {
- CHECK_EQ(0, uv_key_create(&thread_local_modpending));
-}
-
-// DLOpen is process.dlopen(module, filename, flags).
-// Used to load 'module.node' dynamically shared objects.
-//
-// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
-// when two contexts try to load the same shared object. Maybe have a shadow
-// cache that's a plain C list or hash table that's shared across contexts?
-static void DLOpen(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
- auto context = env->context();
-
- uv_once(&init_modpending_once, InitModpendingOnce);
- CHECK_NULL(uv_key_get(&thread_local_modpending));
-
- if (args.Length() < 2) {
- env->ThrowError("process.dlopen needs at least 2 arguments.");
- return;
- }
-
- int32_t flags = DLib::kDefaultFlags;
- if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
- return env->ThrowTypeError("flag argument must be an integer.");
- }
-
- Local<Object> module;
- Local<Object> exports;
- Local<Value> exports_v;
- if (!args[0]->ToObject(context).ToLocal(&module) ||
- !module->Get(context, env->exports_string()).ToLocal(&exports_v) ||
- !exports_v->ToObject(context).ToLocal(&exports)) {
- return; // Exception pending.
- }
-
- node::Utf8Value filename(env->isolate(), args[1]); // Cast
- DLib dlib(*filename, flags);
- bool is_opened = dlib.Open();
-
- // Objects containing v14 or later modules will have registered themselves
- // on the pending list. Activate all of them now. At present, only one
- // module per object is supported.
- node_module* const mp = static_cast<node_module*>(
- uv_key_get(&thread_local_modpending));
- uv_key_set(&thread_local_modpending, nullptr);
-
- if (!is_opened) {
- Local<String> errmsg = OneByteString(env->isolate(), dlib.errmsg_.c_str());
- dlib.Close();
-#ifdef _WIN32
- // Windows needs to add the filename into the error message
- errmsg = String::Concat(
- env->isolate(), errmsg, args[1]->ToString(context).ToLocalChecked());
-#endif // _WIN32
- env->isolate()->ThrowException(Exception::Error(errmsg));
- return;
- }
-
- if (mp == nullptr) {
- if (auto callback = GetInitializerCallback(&dlib)) {
- callback(exports, module, context);
- } else if (auto napi_callback = GetNapiInitializerCallback(&dlib)) {
- napi_module_register_by_symbol(exports, module, context, napi_callback);
- } else {
- dlib.Close();
- env->ThrowError("Module did not self-register.");
- }
- return;
- }
-
- // -1 is used for N-API modules
- if ((mp->nm_version != -1) && (mp->nm_version != NODE_MODULE_VERSION)) {
- // Even if the module did self-register, it may have done so with the wrong
- // version. We must only give up after having checked to see if it has an
- // appropriate initializer callback.
- if (auto callback = GetInitializerCallback(&dlib)) {
- callback(exports, module, context);
- return;
- }
- char errmsg[1024];
- snprintf(errmsg,
- sizeof(errmsg),
- "The module '%s'"
- "\nwas compiled against a different Node.js version using"
- "\nNODE_MODULE_VERSION %d. This version of Node.js requires"
- "\nNODE_MODULE_VERSION %d. Please try re-compiling or "
- "re-installing\nthe module (for instance, using `npm rebuild` "
- "or `npm install`).",
- *filename, mp->nm_version, NODE_MODULE_VERSION);
-
- // NOTE: `mp` is allocated inside of the shared library's memory, calling
- // `dlclose` will deallocate it
- dlib.Close();
- env->ThrowError(errmsg);
- return;
- }
- if (mp->nm_flags & NM_F_BUILTIN) {
- dlib.Close();
- env->ThrowError("Built-in module self-registered.");
- return;
- }
-
- mp->nm_dso_handle = dlib.handle_;
- mp->nm_link = modlist_addon;
- modlist_addon = mp;
-
- if (mp->nm_context_register_func != nullptr) {
- mp->nm_context_register_func(exports, module, context, mp->nm_priv);
- } else if (mp->nm_register_func != nullptr) {
- mp->nm_register_func(exports, module, mp->nm_priv);
- } else {
- dlib.Close();
- env->ThrowError("Module has no declared entry point.");
- return;
- }
-
- // Tell coverity that 'handle' should not be freed when we return.
- // coverity[leaked_storage]
-}
-
static Maybe<bool> ProcessEmitWarningGeneric(Environment* env,
const char* warning,
const char* type = nullptr,
@@ -1179,118 +908,6 @@ static void OnMessage(Local<Message> message, Local<Value> error) {
}
}
-
-static Local<Object> InitModule(Environment* env,
- node_module* mod,
- Local<String> module) {
- Local<Object> exports = Object::New(env->isolate());
- // Internal bindings don't have a "module" object, only exports.
- CHECK_NULL(mod->nm_register_func);
- CHECK_NOT_NULL(mod->nm_context_register_func);
- Local<Value> unused = Undefined(env->isolate());
- mod->nm_context_register_func(exports,
- unused,
- env->context(),
- mod->nm_priv);
- return exports;
-}
-
-static void ThrowIfNoSuchModule(Environment* env, const char* module_v) {
- char errmsg[1024];
- snprintf(errmsg,
- sizeof(errmsg),
- "No such module: %s",
- module_v);
- env->ThrowError(errmsg);
-}
-
-static void GetBinding(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
-
- CHECK(args[0]->IsString());
-
- Local<String> module = args[0].As<String>();
- node::Utf8Value module_v(env->isolate(), module);
-
- node_module* mod = get_builtin_module(*module_v);
- Local<Object> exports;
- if (mod != nullptr) {
- exports = InitModule(env, mod, module);
- } else {
- return ThrowIfNoSuchModule(env, *module_v);
- }
-
- args.GetReturnValue().Set(exports);
-}
-
-static void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
-
- CHECK(args[0]->IsString());
-
- Local<String> module = args[0].As<String>();
- node::Utf8Value module_v(env->isolate(), module);
- Local<Object> exports;
-
- node_module* mod = get_internal_module(*module_v);
- if (mod != nullptr) {
- exports = InitModule(env, mod, module);
- } else if (!strcmp(*module_v, "constants")) {
- exports = Object::New(env->isolate());
- CHECK(exports->SetPrototype(env->context(),
- Null(env->isolate())).FromJust());
- DefineConstants(env->isolate(), exports);
- } else if (!strcmp(*module_v, "natives")) {
- exports = per_process_loader.GetSourceObject(env->context());
- } else {
- return ThrowIfNoSuchModule(env, *module_v);
- }
-
- args.GetReturnValue().Set(exports);
-}
-
-static void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
- Environment* env = Environment::GetCurrent(args);
-
- CHECK(args[0]->IsString());
-
- Local<String> module_name = args[0].As<String>();
-
- node::Utf8Value module_name_v(env->isolate(), module_name);
- node_module* mod = get_linked_module(*module_name_v);
-
- if (mod == nullptr) {
- char errmsg[1024];
- snprintf(errmsg,
- sizeof(errmsg),
- "No such module was linked: %s",
- *module_name_v);
- return env->ThrowError(errmsg);
- }
-
- Local<Object> module = Object::New(env->isolate());
- Local<Object> exports = Object::New(env->isolate());
- Local<String> exports_prop = String::NewFromUtf8(env->isolate(), "exports",
- NewStringType::kNormal).ToLocalChecked();
- module->Set(env->context(), exports_prop, exports).FromJust();
-
- if (mod->nm_context_register_func != nullptr) {
- mod->nm_context_register_func(exports,
- module,
- env->context(),
- mod->nm_priv);
- } else if (mod->nm_register_func != nullptr) {
- mod->nm_register_func(exports, module, mod->nm_priv);
- } else {
- return env->ThrowError("Linked module has no declared entry point.");
- }
-
- auto effective_exports = module->Get(env->context(),
- exports_prop).ToLocalChecked();
-
- args.GetReturnValue().Set(effective_exports);
-}
-
static Local<Object> GetFeatures(Environment* env) {
EscapableHandleScope scope(env->isolate());
@@ -1688,7 +1305,7 @@ void SetupProcessObject(Environment* env,
env->SetMethod(process, "_kill", Kill);
env->SetMethodNoSideEffect(process, "cwd", Cwd);
- env->SetMethod(process, "dlopen", DLOpen);
+ env->SetMethod(process, "dlopen", binding::DLOpen);
env->SetMethod(process, "reallyExit", Exit);
env->SetMethodNoSideEffect(process, "uptime", Uptime);
@@ -1825,16 +1442,18 @@ void LoadEnvironment(Environment* env) {
global).FromJust();
// Create binding loaders
- Local<Function> get_binding_fn =
- env->NewFunctionTemplate(GetBinding)->GetFunction(env->context())
- .ToLocalChecked();
+ Local<Function> get_binding_fn = env->NewFunctionTemplate(binding::GetBinding)
+ ->GetFunction(env->context())
+ .ToLocalChecked();
Local<Function> get_linked_binding_fn =
- env->NewFunctionTemplate(GetLinkedBinding)->GetFunction(env->context())
+ env->NewFunctionTemplate(binding::GetLinkedBinding)
+ ->GetFunction(env->context())
.ToLocalChecked();
Local<Function> get_internal_binding_fn =
- env->NewFunctionTemplate(GetInternalBinding)->GetFunction(env->context())
+ env->NewFunctionTemplate(binding::GetInternalBinding)
+ ->GetFunction(env->context())
.ToLocalChecked();
Local<Value> loaders_bootstrapper_args[] = {
@@ -2206,7 +1825,7 @@ void Init(std::vector<std::string>* argv,
prog_start_time = static_cast<double>(uv_now(uv_default_loop()));
// Register built-in modules
- RegisterBuiltinModules();
+ binding::RegisterBuiltinModules();
// Make inherited handles noninheritable.
uv_disable_stdio_inheritance();
@@ -2727,14 +2346,6 @@ int Start(int argc, char** argv) {
return exit_code;
}
-// Call built-in modules' _register_<module name> function to
-// do module registration explicitly.
-void RegisterBuiltinModules() {
-#define V(modname) _register_##modname();
- NODE_BUILTIN_MODULES(V)
-#undef V
-}
-
} // namespace node
#if !HAVE_INSPECTOR
diff --git a/src/node_api.cc b/src/node_api.cc
index 20428d40fa..7d843c08f5 100644
--- a/src/node_api.cc
+++ b/src/node_api.cc
@@ -1,10 +1,11 @@
#include <node_buffer.h>
#include "env.h"
#define NAPI_EXPERIMENTAL
+#include "js_native_api_v8.h"
#include "node_api.h"
+#include "node_binding.h"
#include "node_errors.h"
#include "node_internals.h"
-#include "js_native_api_v8.h"
struct node_napi_env__ : public napi_env__ {
explicit node_napi_env__(v8::Local<v8::Context> context):
diff --git a/src/node_binding.cc b/src/node_binding.cc
new file mode 100644
index 0000000000..a2e5134bfa
--- /dev/null
+++ b/src/node_binding.cc
@@ -0,0 +1,471 @@
+#include "node_binding.h"
+#include "node_internals.h"
+#include "node_native_module.h"
+
+#if defined(__POSIX__)
+#include <dlfcn.h>
+#endif
+
+#if HAVE_OPENSSL
+#define NODE_BUILTIN_OPENSSL_MODULES(V) V(crypto) V(tls_wrap)
+#else
+#define NODE_BUILTIN_OPENSSL_MODULES(V)
+#endif
+
+#if NODE_HAVE_I18N_SUPPORT
+#define NODE_BUILTIN_ICU_MODULES(V) V(icu)
+#else
+#define NODE_BUILTIN_ICU_MODULES(V)
+#endif
+
+// A list of built-in modules. In order to do module registration
+// in node::Init(), need to add built-in modules in the following list.
+// Then in binding::RegisterBuiltinModules(), it calls modules' registration
+// function. This helps the built-in modules are loaded properly when
+// node is built as static library. No need to depend on the
+// __attribute__((constructor)) like mechanism in GCC.
+#define NODE_BUILTIN_STANDARD_MODULES(V) \
+ V(async_wrap) \
+ V(buffer) \
+ V(cares_wrap) \
+ V(config) \
+ V(contextify) \
+ V(domain) \
+ V(fs) \
+ V(fs_event_wrap) \
+ V(heap_utils) \
+ V(http2) \
+ V(http_parser) \
+ V(inspector) \
+ V(js_stream) \
+ V(messaging) \
+ V(module_wrap) \
+ V(native_module) \
+ V(options) \
+ V(os) \
+ V(performance) \
+ V(pipe_wrap) \
+ V(process_wrap) \
+ V(serdes) \
+ V(signal_wrap) \
+ V(spawn_sync) \
+ V(stream_pipe) \
+ V(stream_wrap) \
+ V(string_decoder) \
+ V(symbols) \
+ V(tcp_wrap) \
+ V(timers) \
+ V(trace_events) \
+ V(tty_wrap) \
+ V(types) \
+ V(udp_wrap) \
+ V(url) \
+ V(util) \
+ V(uv) \
+ V(v8) \
+ V(worker) \
+ V(zlib)
+
+#define NODE_BUILTIN_MODULES(V) \
+ NODE_BUILTIN_STANDARD_MODULES(V) \
+ NODE_BUILTIN_OPENSSL_MODULES(V) \
+ NODE_BUILTIN_ICU_MODULES(V)
+
+// This is used to load built-in modules. Instead of using
+// __attribute__((constructor)), we call the _register_<modname>
+// function for each built-in modules explicitly in
+// binding::RegisterBuiltinModules(). This is only forward declaration.
+// The definitions are in each module's implementation when calling
+// the NODE_BUILTIN_MODULE_CONTEXT_AWARE.
+#define V(modname) void _register_##modname();
+NODE_BUILTIN_MODULES(V)
+#undef V
+
+namespace node {
+
+using v8::Context;
+using v8::Exception;
+using v8::FunctionCallbackInfo;
+using v8::Local;
+using v8::NewStringType;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+// Globals per process
+static node_module* modlist_builtin;
+static node_module* modlist_internal;
+static node_module* modlist_linked;
+static node_module* modlist_addon;
+static uv_once_t init_modpending_once = UV_ONCE_INIT;
+static uv_key_t thread_local_modpending;
+
+// This is set by node::Init() which is used by embedders
+bool node_is_initialized = false;
+
+extern "C" void node_module_register(void* m) {
+ struct node_module* mp = reinterpret_cast<struct node_module*>(m);
+
+ if (mp->nm_flags & NM_F_BUILTIN) {
+ mp->nm_link = modlist_builtin;
+ modlist_builtin = mp;
+ } else if (mp->nm_flags & NM_F_INTERNAL) {
+ mp->nm_link = modlist_internal;
+ modlist_internal = 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 {
+ uv_key_set(&thread_local_modpending, mp);
+ }
+}
+
+namespace binding {
+
+class DLib {
+ public:
+#ifdef __POSIX__
+ static const int kDefaultFlags = RTLD_LAZY;
+#else
+ static const int kDefaultFlags = 0;
+#endif
+
+ inline DLib(const char* filename, int flags)
+ : filename_(filename), flags_(flags), handle_(nullptr) {}
+
+ inline bool Open();
+ inline void Close();
+ inline void* GetSymbolAddress(const char* name);
+
+ const std::string filename_;
+ const int flags_;
+ std::string errmsg_;
+ void* handle_;
+#ifndef __POSIX__
+ uv_lib_t lib_;
+#endif
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DLib);
+};
+
+#ifdef __POSIX__
+bool DLib::Open() {
+ handle_ = dlopen(filename_.c_str(), flags_);
+ if (handle_ != nullptr) return true;
+ errmsg_ = dlerror();
+ return false;
+}
+
+void DLib::Close() {
+ if (handle_ == nullptr) return;
+ dlclose(handle_);
+ handle_ = nullptr;
+}
+
+void* DLib::GetSymbolAddress(const char* name) {
+ return dlsym(handle_, name);
+}
+#else // !__POSIX__
+bool DLib::Open() {
+ int ret = uv_dlopen(filename_.c_str(), &lib_);
+ if (ret == 0) {
+ handle_ = static_cast<void*>(lib_.handle);
+ return true;
+ }
+ errmsg_ = uv_dlerror(&lib_);
+ uv_dlclose(&lib_);
+ return false;
+}
+
+void DLib::Close() {
+ if (handle_ == nullptr) return;
+ uv_dlclose(&lib_);
+ handle_ = nullptr;
+}
+
+void* DLib::GetSymbolAddress(const char* name) {
+ void* address;
+ if (0 == uv_dlsym(&lib_, name, &address)) return address;
+ return nullptr;
+}
+#endif // !__POSIX__
+
+using InitializerCallback = void (*)(Local<Object> exports,
+ Local<Value> module,
+ Local<Context> context);
+
+inline InitializerCallback GetInitializerCallback(DLib* dlib) {
+ const char* name = "node_register_module_v" STRINGIFY(NODE_MODULE_VERSION);
+ return reinterpret_cast<InitializerCallback>(dlib->GetSymbolAddress(name));
+}
+
+inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) {
+ const char* name =
+ STRINGIFY(NAPI_MODULE_INITIALIZER_BASE) STRINGIFY(NAPI_MODULE_VERSION);
+ return reinterpret_cast<napi_addon_register_func>(
+ dlib->GetSymbolAddress(name));
+}
+
+void InitModpendingOnce() {
+ CHECK_EQ(0, uv_key_create(&thread_local_modpending));
+}
+
+// DLOpen is process.dlopen(module, filename, flags).
+// Used to load 'module.node' dynamically shared objects.
+//
+// FIXME(bnoordhuis) Not multi-context ready. TBD how to resolve the conflict
+// when two contexts try to load the same shared object. Maybe have a shadow
+// cache that's a plain C list or hash table that's shared across contexts?
+void DLOpen(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+ auto context = env->context();
+
+ uv_once(&init_modpending_once, InitModpendingOnce);
+ CHECK_NULL(uv_key_get(&thread_local_modpending));
+
+ if (args.Length() < 2) {
+ env->ThrowError("process.dlopen needs at least 2 arguments.");
+ return;
+ }
+
+ int32_t flags = DLib::kDefaultFlags;
+ if (args.Length() > 2 && !args[2]->Int32Value(context).To(&flags)) {
+ return env->ThrowTypeError("flag argument must be an integer.");
+ }
+
+ Local<Object> module;
+ Local<Object> exports;
+ Local<Value> exports_v;
+ if (!args[0]->ToObject(context).ToLocal(&module) ||
+ !module->Get(context, env->exports_string()).ToLocal(&exports_v) ||
+ !exports_v->ToObject(context).ToLocal(&exports)) {
+ return; // Exception pending.
+ }
+
+ node::Utf8Value filename(env->isolate(), args[1]); // Cast
+ DLib dlib(*filename, flags);
+ bool is_opened = dlib.Open();
+
+ // Objects containing v14 or later modules will have registered themselves
+ // on the pending list. Activate all of them now. At present, only one
+ // module per object is supported.
+ node_module* const mp =
+ static_cast<node_module*>(uv_key_get(&thread_local_modpending));
+ uv_key_set(&thread_local_modpending, nullptr);
+
+ if (!is_opened) {
+ Local<String> errmsg = OneByteString(env->isolate(), dlib.errmsg_.c_str());
+ dlib.Close();
+#ifdef _WIN32
+ // Windows needs to add the filename into the error message
+ errmsg = String::Concat(
+ env->isolate(), errmsg, args[1]->ToString(context).ToLocalChecked());
+#endif // _WIN32
+ env->isolate()->ThrowException(Exception::Error(errmsg));
+ return;
+ }
+
+ if (mp == nullptr) {
+ if (auto callback = GetInitializerCallback(&dlib)) {
+ callback(exports, module, context);
+ } else if (auto napi_callback = GetNapiInitializerCallback(&dlib)) {
+ napi_module_register_by_symbol(exports, module, context, napi_callback);
+ } else {
+ dlib.Close();
+ env->ThrowError("Module did not self-register.");
+ }
+ return;
+ }
+
+ // -1 is used for N-API modules
+ if ((mp->nm_version != -1) && (mp->nm_version != NODE_MODULE_VERSION)) {
+ // Even if the module did self-register, it may have done so with the wrong
+ // version. We must only give up after having checked to see if it has an
+ // appropriate initializer callback.
+ if (auto callback = GetInitializerCallback(&dlib)) {
+ callback(exports, module, context);
+ return;
+ }
+ char errmsg[1024];
+ snprintf(errmsg,
+ sizeof(errmsg),
+ "The module '%s'"
+ "\nwas compiled against a different Node.js version using"
+ "\nNODE_MODULE_VERSION %d. This version of Node.js requires"
+ "\nNODE_MODULE_VERSION %d. Please try re-compiling or "
+ "re-installing\nthe module (for instance, using `npm rebuild` "
+ "or `npm install`).",
+ *filename,
+ mp->nm_version,
+ NODE_MODULE_VERSION);
+
+ // NOTE: `mp` is allocated inside of the shared library's memory, calling
+ // `dlclose` will deallocate it
+ dlib.Close();
+ env->ThrowError(errmsg);
+ return;
+ }
+ if (mp->nm_flags & NM_F_BUILTIN) {
+ dlib.Close();
+ env->ThrowError("Built-in module self-registered.");
+ return;
+ }
+
+ mp->nm_dso_handle = dlib.handle_;
+ mp->nm_link = modlist_addon;
+ modlist_addon = mp;
+
+ if (mp->nm_context_register_func != nullptr) {
+ mp->nm_context_register_func(exports, module, context, mp->nm_priv);
+ } else if (mp->nm_register_func != nullptr) {
+ mp->nm_register_func(exports, module, mp->nm_priv);
+ } else {
+ dlib.Close();
+ env->ThrowError("Module has no declared entry point.");
+ return;
+ }
+
+ // Tell coverity that 'handle' should not be freed when we return.
+ // coverity[leaked_storage]
+}
+
+inline struct node_module* FindModule(struct node_module* list,
+ const char* name,
+ int flag) {
+ struct node_module* mp;
+
+ for (mp = list; mp != nullptr; mp = mp->nm_link) {
+ if (strcmp(mp->nm_modname, name) == 0) break;
+ }
+
+ CHECK(mp == nullptr || (mp->nm_flags & flag) != 0);
+ return mp;
+}
+
+node_module* get_builtin_module(const char* name) {
+ return FindModule(modlist_builtin, name, NM_F_BUILTIN);
+}
+node_module* get_internal_module(const char* name) {
+ return FindModule(modlist_internal, name, NM_F_INTERNAL);
+}
+node_module* get_linked_module(const char* name) {
+ return FindModule(modlist_linked, name, NM_F_LINKED);
+}
+
+static Local<Object> InitModule(Environment* env,
+ node_module* mod,
+ Local<String> module) {
+ Local<Object> exports = Object::New(env->isolate());
+ // Internal bindings don't have a "module" object, only exports.
+ CHECK_NULL(mod->nm_register_func);
+ CHECK_NOT_NULL(mod->nm_context_register_func);
+ Local<Value> unused = Undefined(env->isolate());
+ mod->nm_context_register_func(exports, unused, env->context(), mod->nm_priv);
+ return exports;
+}
+
+static void ThrowIfNoSuchModule(Environment* env, const char* module_v) {
+ char errmsg[1024];
+ snprintf(errmsg, sizeof(errmsg), "No such module: %s", module_v);
+ env->ThrowError(errmsg);
+}
+
+void GetBinding(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK(args[0]->IsString());
+
+ Local<String> module = args[0].As<String>();
+ node::Utf8Value module_v(env->isolate(), module);
+
+ node_module* mod = get_builtin_module(*module_v);
+ Local<Object> exports;
+ if (mod != nullptr) {
+ exports = InitModule(env, mod, module);
+ } else {
+ return ThrowIfNoSuchModule(env, *module_v);
+ }
+
+ args.GetReturnValue().Set(exports);
+}
+
+void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK(args[0]->IsString());
+
+ Local<String> module = args[0].As<String>();
+ node::Utf8Value module_v(env->isolate(), module);
+ Local<Object> exports;
+
+ node_module* mod = get_internal_module(*module_v);
+ if (mod != nullptr) {
+ exports = InitModule(env, mod, module);
+ } else if (!strcmp(*module_v, "constants")) {
+ exports = Object::New(env->isolate());
+ CHECK(
+ exports->SetPrototype(env->context(), Null(env->isolate())).FromJust());
+ DefineConstants(env->isolate(), exports);
+ } else if (!strcmp(*module_v, "natives")) {
+ exports = per_process_loader.GetSourceObject(env->context());
+ } else {
+ return ThrowIfNoSuchModule(env, *module_v);
+ }
+
+ args.GetReturnValue().Set(exports);
+}
+
+void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
+ Environment* env = Environment::GetCurrent(args);
+
+ CHECK(args[0]->IsString());
+
+ Local<String> module_name = args[0].As<String>();
+
+ node::Utf8Value module_name_v(env->isolate(), module_name);
+ node_module* mod = get_linked_module(*module_name_v);
+
+ if (mod == nullptr) {
+ char errmsg[1024];
+ snprintf(errmsg,
+ sizeof(errmsg),
+ "No such module was linked: %s",
+ *module_name_v);
+ return env->ThrowError(errmsg);
+ }
+
+ Local<Object> module = Object::New(env->isolate());
+ Local<Object> exports = Object::New(env->isolate());
+ Local<String> exports_prop =
+ String::NewFromUtf8(env->isolate(), "exports", NewStringType::kNormal)
+ .ToLocalChecked();
+ module->Set(env->context(), exports_prop, exports).FromJust();
+
+ if (mod->nm_context_register_func != nullptr) {
+ mod->nm_context_register_func(
+ exports, module, env->context(), mod->nm_priv);
+ } else if (mod->nm_register_func != nullptr) {
+ mod->nm_register_func(exports, module, mod->nm_priv);
+ } else {
+ return env->ThrowError("Linked module has no declared entry point.");
+ }
+
+ auto effective_exports =
+ module->Get(env->context(), exports_prop).ToLocalChecked();
+
+ args.GetReturnValue().Set(effective_exports);
+}
+
+// Call built-in modules' _register_<module name> function to
+// do module registration explicitly.
+void RegisterBuiltinModules() {
+#define V(modname) _register_##modname();
+ NODE_BUILTIN_MODULES(V)
+#undef V
+}
+
+} // namespace binding
+} // namespace node
diff --git a/src/node_binding.h b/src/node_binding.h
new file mode 100644
index 0000000000..743c82accd
--- /dev/null
+++ b/src/node_binding.h
@@ -0,0 +1,64 @@
+#ifndef SRC_NODE_BINDING_H_
+#define SRC_NODE_BINDING_H_
+
+#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+
+#include "node.h"
+#include "node_api.h"
+#include "uv.h"
+#include "v8.h"
+
+enum {
+ NM_F_BUILTIN = 1 << 0,
+ NM_F_LINKED = 1 << 1,
+ NM_F_INTERNAL = 1 << 2,
+};
+
+#define NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
+ static node::node_module _module = { \
+ NODE_MODULE_VERSION, \
+ flags, \
+ nullptr, \
+ __FILE__, \
+ nullptr, \
+ (node::addon_context_register_func)(regfunc), \
+ NODE_STRINGIFY(modname), \
+ priv, \
+ nullptr}; \
+ void _register_##modname() { node_module_register(&_module); }
+
+#define NODE_BUILTIN_MODULE_CONTEXT_AWARE(modname, regfunc) \
+ NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_BUILTIN)
+
+void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
+ v8::Local<v8::Value> module,
+ v8::Local<v8::Context> context,
+ napi_addon_register_func init);
+
+namespace node {
+
+#define NODE_MODULE_CONTEXT_AWARE_INTERNAL(modname, regfunc) \
+ NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_INTERNAL)
+
+// Globals per process
+// This is set by node::Init() which is used by embedders
+extern bool node_is_initialized;
+
+namespace binding {
+
+// Call _register<module_name> functions for all of
+// the built-in modules. Because built-in modules don't
+// use the __attribute__((constructor)). Need to
+// explicitly call the _register* functions.
+void RegisterBuiltinModules();
+void GetBinding(const v8::FunctionCallbackInfo<v8::Value>& args);
+void GetInternalBinding(const v8::FunctionCallbackInfo<v8::Value>& args);
+void GetLinkedBinding(const v8::FunctionCallbackInfo<v8::Value>& args);
+void DLOpen(const v8::FunctionCallbackInfo<v8::Value>& args);
+
+} // namespace binding
+
+} // namespace node
+
+#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+#endif // SRC_NODE_BINDING_H_
diff --git a/src/node_internals.h b/src/node_internals.h
index 68c0b1f753..6cb40c9070 100644
--- a/src/node_internals.h
+++ b/src/node_internals.h
@@ -24,15 +24,15 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
+#include "env-inl.h"
#include "node.h"
+#include "node_binding.h"
#include "node_mutex.h"
#include "node_persistent.h"
+#include "tracing/trace_event.h"
#include "util-inl.h"
-#include "env-inl.h"
#include "uv.h"
#include "v8.h"
-#include "tracing/trace_event.h"
-#include "node_api.h"
#include <stdint.h>
#include <stdlib.h>
@@ -57,12 +57,6 @@
#define Z_MAX_LEVEL 9
#define Z_DEFAULT_LEVEL Z_DEFAULT_COMPRESSION
-enum {
- NM_F_BUILTIN = 1 << 0,
- NM_F_LINKED = 1 << 1,
- NM_F_INTERNAL = 1 << 2,
-};
-
struct sockaddr;
// Variation on NODE_DEFINE_CONSTANT that sets a String value.
@@ -83,92 +77,6 @@ struct sockaddr;
constant_attributes).FromJust(); \
} while (0)
-
-#if HAVE_OPENSSL
-#define NODE_BUILTIN_OPENSSL_MODULES(V) V(crypto) V(tls_wrap)
-#else
-#define NODE_BUILTIN_OPENSSL_MODULES(V)
-#endif
-
-#if NODE_HAVE_I18N_SUPPORT
-#define NODE_BUILTIN_ICU_MODULES(V) V(icu)
-#else
-#define NODE_BUILTIN_ICU_MODULES(V)
-#endif
-
-// A list of built-in modules. In order to do module registration
-// in node::Init(), need to add built-in modules in the following list.
-// Then in node::RegisterBuiltinModules(), it calls modules' registration
-// function. This helps the built-in modules are loaded properly when
-// node is built as static library. No need to depend on the
-// __attribute__((constructor)) like mechanism in GCC.
-#define NODE_BUILTIN_STANDARD_MODULES(V) \
- V(async_wrap) \
- V(buffer) \
- V(cares_wrap) \
- V(config) \
- V(contextify) \
- V(domain) \
- V(fs) \
- V(fs_event_wrap) \
- V(heap_utils) \
- V(http2) \
- V(http_parser) \
- V(inspector) \
- V(js_stream) \
- V(messaging) \
- V(module_wrap) \
- V(native_module) \
- V(options) \
- V(os) \
- V(performance) \
- V(pipe_wrap) \
- V(process_wrap) \
- V(serdes) \
- V(signal_wrap) \
- V(spawn_sync) \
- V(stream_pipe) \
- V(stream_wrap) \
- V(string_decoder) \
- V(symbols) \
- V(tcp_wrap) \
- V(timers) \
- V(trace_events) \
- V(tty_wrap) \
- V(types) \
- V(udp_wrap) \
- V(url) \
- V(util) \
- V(uv) \
- V(v8) \
- V(worker) \
- V(zlib)
-
-#define NODE_BUILTIN_MODULES(V) \
- NODE_BUILTIN_STANDARD_MODULES(V) \
- NODE_BUILTIN_OPENSSL_MODULES(V) \
- NODE_BUILTIN_ICU_MODULES(V)
-
-#define NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \
- static node::node_module _module = { \
- NODE_MODULE_VERSION, \
- flags, \
- nullptr, \
- __FILE__, \
- nullptr, \
- (node::addon_context_register_func) (regfunc), \
- NODE_STRINGIFY(modname), \
- priv, \
- nullptr \
- }; \
- void _register_ ## modname() { \
- node_module_register(&_module); \
- }
-
-
-#define NODE_BUILTIN_MODULE_CONTEXT_AWARE(modname, regfunc) \
- NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_BUILTIN)
-
namespace node {
namespace native_module {
@@ -281,12 +189,6 @@ void SetupProcessObject(Environment* env,
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args);
-// Call _register<module_name> functions for all of
-// the built-in modules. Because built-in modules don't
-// use the __attribute__((constructor)). Need to
-// explicitly call the _register* functions.
-void RegisterBuiltinModules();
-
enum Endianness {
kLittleEndian, // _Not_ LITTLE_ENDIAN, clashes with endian.h.
kBigEndian
@@ -782,9 +684,6 @@ static inline const char* errno_string(int errorno) {
}
}
-#define NODE_MODULE_CONTEXT_AWARE_INTERNAL(modname, regfunc) \
- NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_INTERNAL)
-
#define TRACING_CATEGORY_NODE "node"
#define TRACING_CATEGORY_NODE1(one) \
TRACING_CATEGORY_NODE "," \
@@ -857,11 +756,6 @@ void DefineZlibConstants(v8::Local<v8::Object> target);
} // namespace node
-void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
- v8::Local<v8::Value> module,
- v8::Local<v8::Context> context,
- napi_addon_register_func init);
-
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_NODE_INTERNALS_H_