summaryrefslogtreecommitdiff
path: root/src/node_api.cc
diff options
context:
space:
mode:
authorGabriel Schulhof <gabriel.schulhof@intel.com>2018-08-10 11:43:39 -0400
committerGabriel Schulhof <gabriel.schulhof@intel.com>2018-09-12 22:37:42 -0400
commitcf0e881b33c841d2f89a23be281e1aaf061a58a3 (patch)
treefd1ba7df5b6955559bd76eef9c1e276f891201e3 /src/node_api.cc
parent82b752a302f1bb1fb2e82baeabfb8627de0b159f (diff)
downloadandroid-node-v8-cf0e881b33c841d2f89a23be281e1aaf061a58a3.tar.gz
android-node-v8-cf0e881b33c841d2f89a23be281e1aaf061a58a3.tar.bz2
android-node-v8-cf0e881b33c841d2f89a23be281e1aaf061a58a3.zip
n-api: add generic finalizer callback
Add `napi_add_finalizer()`, which provides the ability to attach data to an arbitrary object and be notified when that object is garbage- collected so as to have an opportunity to delete the data previously attached. This differs from `napi_wrap()` in that it does not use up the private slot on the object, and is therefore neither removable, nor retrievable after the call to `napi_add_finalizer()`. It is assumed that the data is accessible by other means, yet it must be tied to the lifetime of the object. This is the case for data passed to a dynamically created function which is itself heap-allocated and must therefore be freed along with the function. Fixes: https://github.com/nodejs/abi-stable-node/issues/313 PR-URL: https://github.com/nodejs/node/pull/22244 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Diffstat (limited to 'src/node_api.cc')
-rw-r--r--src/node_api.cc112
1 files changed, 77 insertions, 35 deletions
diff --git a/src/node_api.cc b/src/node_api.cc
index ef4ec29708..690579f573 100644
--- a/src/node_api.cc
+++ b/src/node_api.cc
@@ -1157,6 +1157,63 @@ class ThreadSafeFunction : public node::AsyncResource {
bool handles_closing;
};
+enum WrapType {
+ retrievable,
+ anonymous
+};
+
+template <WrapType wrap_type> static inline
+napi_status Wrap(napi_env env,
+ napi_value js_object,
+ void* native_object,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_ref* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, js_object);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
+ RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
+ v8::Local<v8::Object> obj = value.As<v8::Object>();
+
+ if (wrap_type == retrievable) {
+ // If we've already wrapped this object, we error out.
+ RETURN_STATUS_IF_FALSE(env,
+ !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper))
+ .FromJust(),
+ napi_invalid_arg);
+ } else if (wrap_type == anonymous) {
+ // If no finalize callback is provided, we error out.
+ CHECK_ARG(env, finalize_cb);
+ }
+
+ v8impl::Reference* reference = nullptr;
+ if (result != nullptr) {
+ // The returned reference should be deleted via napi_delete_reference()
+ // ONLY in response to the finalize callback invocation. (If it is deleted
+ // before then, then the finalize callback will never be invoked.)
+ // Therefore a finalize callback is required when returning a reference.
+ CHECK_ARG(env, finalize_cb);
+ reference = v8impl::Reference::New(
+ env, obj, 0, false, finalize_cb, native_object, finalize_hint);
+ *result = reinterpret_cast<napi_ref>(reference);
+ } else {
+ // Create a self-deleting reference.
+ reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
+ native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
+ }
+
+ if (wrap_type == retrievable) {
+ CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
+ v8::External::New(isolate, reference)).FromJust());
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
} // end of namespace v8impl
// Intercepts the Node-V8 module registration callback. Converts parameters
@@ -2859,41 +2916,12 @@ napi_status napi_wrap(napi_env env,
napi_finalize finalize_cb,
void* finalize_hint,
napi_ref* result) {
- NAPI_PREAMBLE(env);
- CHECK_ARG(env, js_object);
-
- v8::Isolate* isolate = env->isolate;
- v8::Local<v8::Context> context = isolate->GetCurrentContext();
-
- v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
- RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
- v8::Local<v8::Object> obj = value.As<v8::Object>();
-
- // If we've already wrapped this object, we error out.
- RETURN_STATUS_IF_FALSE(env,
- !obj->HasPrivate(context, NAPI_PRIVATE_KEY(context, wrapper)).FromJust(),
- napi_invalid_arg);
-
- v8impl::Reference* reference = nullptr;
- if (result != nullptr) {
- // The returned reference should be deleted via napi_delete_reference()
- // ONLY in response to the finalize callback invocation. (If it is deleted
- // before then, then the finalize callback will never be invoked.)
- // Therefore a finalize callback is required when returning a reference.
- CHECK_ARG(env, finalize_cb);
- reference = v8impl::Reference::New(
- env, obj, 0, false, finalize_cb, native_object, finalize_hint);
- *result = reinterpret_cast<napi_ref>(reference);
- } else {
- // Create a self-deleting reference.
- reference = v8impl::Reference::New(env, obj, 0, true, finalize_cb,
- native_object, finalize_cb == nullptr ? nullptr : finalize_hint);
- }
-
- CHECK(obj->SetPrivate(context, NAPI_PRIVATE_KEY(context, wrapper),
- v8::External::New(isolate, reference)).FromJust());
-
- return GET_RETURN_STATUS(env);
+ return v8impl::Wrap<v8impl::retrievable>(env,
+ js_object,
+ native_object,
+ finalize_cb,
+ finalize_hint,
+ result);
}
napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
@@ -4138,3 +4166,17 @@ napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func) {
CHECK(func != nullptr);
return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref();
}
+
+napi_status napi_add_finalizer(napi_env env,
+ napi_value js_object,
+ void* native_object,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_ref* result) {
+ return v8impl::Wrap<v8impl::anonymous>(env,
+ js_object,
+ native_object,
+ finalize_cb,
+ finalize_hint,
+ result);
+}