summaryrefslogtreecommitdiff
path: root/src/node.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/node.cc')
-rw-r--r--src/node.cc409
1 files changed, 10 insertions, 399 deletions
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