diff options
author | Gabriel Schulhof <gabriel.schulhof@intel.com> | 2019-07-15 03:21:13 +0300 |
---|---|---|
committer | Gabriel Schulhof <gabriel.schulhof@intel.com> | 2019-07-26 02:53:07 +0300 |
commit | 5030e81ce305cc6bc5a1e17dd0ef8a9c761f035b (patch) | |
tree | 5678055a6286b9e8a452b83b05398b5fad51ee5b /src/node_api.cc | |
parent | e9ea8eaf7a77cf9b6f164cef92283c5eb99688cc (diff) |
n-api: add APIs for per-instance state management
Adds `napi_set_instance_data()` and `napi_get_instance_data()`, which
allow native addons to store their data on and retrieve their data from
`napi_env`. `napi_set_instance_data()` accepts a finalizer which is
called when the `node::Environment()` is destroyed.
This entails rendering the `napi_env` local to each add-on.
Fixes: https://github.com/nodejs/abi-stable-node/issues/378
PR-URL: https://github.com/nodejs/node/pull/28682
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Diffstat (limited to 'src/node_api.cc')
-rw-r--r-- | src/node_api.cc | 74 |
1 files changed, 23 insertions, 51 deletions
diff --git a/src/node_api.cc b/src/node_api.cc index a9f26e551db..49472930634 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -46,9 +46,9 @@ class BufferFinalizer : private Finalizer { v8::HandleScope handle_scope(finalizer->_env->isolate); v8::Context::Scope context_scope(finalizer->_env->context()); - NapiCallIntoModuleThrow(finalizer->_env, [&]() { + finalizer->_env->CallIntoModuleThrow([&](napi_env env) { finalizer->_finalize_callback( - finalizer->_env, + env, finalizer->_finalize_data, finalizer->_finalize_hint); }); @@ -59,44 +59,22 @@ class BufferFinalizer : private Finalizer { } }; -static inline napi_env GetEnv(v8::Local<v8::Context> context) { +static inline napi_env NewEnv(v8::Local<v8::Context> context) { node_napi_env result; - auto isolate = context->GetIsolate(); - auto global = context->Global(); - - // In the case of the string for which we grab the private and the value of - // the private on the global object we can call .ToLocalChecked() directly - // because we need to stop hard if either of them is empty. - // - // Re https://github.com/nodejs/node/pull/14217#discussion_r128775149 - auto value = global->GetPrivate(context, NAPI_PRIVATE_KEY(context, env)) - .ToLocalChecked(); - - if (value->IsExternal()) { - result = static_cast<node_napi_env>(value.As<v8::External>()->Value()); - } else { - result = new node_napi_env__(context); - auto external = v8::External::New(isolate, result); - - // We must also stop hard if the result of assigning the env to the global - // is either nothing or false. - CHECK(global->SetPrivate(context, NAPI_PRIVATE_KEY(context, env), external) - .FromJust()); - - // TODO(addaleax): There was previously code that tried to delete the - // napi_env when its v8::Context was garbage collected; - // However, as long as N-API addons using this napi_env are in place, - // the Context needs to be accessible and alive. - // Ideally, we'd want an on-addon-unload hook that takes care of this - // once all N-API addons using this napi_env are unloaded. - // For now, a per-Environment cleanup hook is the best we can do. - result->node_env()->AddCleanupHook( - [](void* arg) { - static_cast<napi_env>(arg)->Unref(); - }, - static_cast<void*>(result)); - } + result = new node_napi_env__(context); + // TODO(addaleax): There was previously code that tried to delete the + // napi_env when its v8::Context was garbage collected; + // However, as long as N-API addons using this napi_env are in place, + // the Context needs to be accessible and alive. + // Ideally, we'd want an on-addon-unload hook that takes care of this + // once all N-API addons using this napi_env are unloaded. + // For now, a per-Environment cleanup hook is the best we can do. + result->node_env()->AddCleanupHook( + [](void* arg) { + static_cast<napi_env>(arg)->Unref(); + }, + static_cast<void*>(result)); return result; } @@ -325,7 +303,7 @@ class ThreadSafeFunction : public node::AsyncResource { v8::Local<v8::Function>::New(env->isolate, ref); js_callback = v8impl::JsValueFromV8LocalValue(js_cb); } - NapiCallIntoModuleThrow(env, [&]() { + env->CallIntoModuleThrow([&](napi_env env) { call_js_cb(env, js_callback, context, data); }); } @@ -346,7 +324,7 @@ class ThreadSafeFunction : public node::AsyncResource { v8::HandleScope scope(env->isolate); if (finalize_cb) { CallbackScope cb_scope(this); - NapiCallIntoModuleThrow(env, [&]() { + env->CallIntoModuleThrow([&](napi_env env) { finalize_cb(env, finalize_data, context); }); } @@ -481,10 +459,10 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports, // Create a new napi_env for this module or reference one if a pre-existing // one is found. - napi_env env = v8impl::GetEnv(context); + napi_env env = v8impl::NewEnv(context); napi_value _exports; - NapiCallIntoModuleThrow(env, [&]() { + env->CallIntoModuleThrow([&](napi_env env) { _exports = init(env, v8impl::JsValueFromV8LocalValue(exports)); }); @@ -889,15 +867,9 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork { CallbackScope callback_scope(this); - // We have to back up the env here because the `NAPI_CALL_INTO_MODULE` macro - // makes use of it after the call into the module completes, but the module - // may have deallocated **this**, and along with it the place where _env is - // stored. - napi_env env = _env; - - NapiCallIntoModule(env, [&]() { - _complete(_env, ConvertUVErrorCode(status), _data); - }, [env](v8::Local<v8::Value> local_err) { + _env->CallIntoModule([&](napi_env env) { + _complete(env, ConvertUVErrorCode(status), _data); + }, [](napi_env env, v8::Local<v8::Value> local_err) { // If there was an unhandled exception in the complete callback, // report it as a fatal exception. (There is no JavaScript on the // callstack that can possibly handle it.) |