Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node-api: allow napi_delete_reference in basic finalizers #55620

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/js_native_api_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2769,10 +2769,12 @@ napi_status NAPI_CDECL napi_create_reference(napi_env env,

// Deletes a reference. The referenced value is released, and may be GC'd unless
// there are other references to it.
// For a napi_reference returned from `napi_wrap`, this must be called in the
// finalizer.
napi_status NAPI_CDECL napi_delete_reference(napi_env env, napi_ref ref) {
// Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
// JS exceptions.
CHECK_ENV_NOT_IN_GC(env);
CHECK_ENV(env);
CHECK_ARG(env, ref);

delete reinterpret_cast<v8impl::Reference*>(ref);
Expand Down
7 changes: 4 additions & 3 deletions test/js-native-api/6_object_wrap/6_object_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ MyObject::MyObject(double value)

MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); }

void MyObject::Destructor(
napi_env env, void* nativeObject, void* /*finalize_hint*/) {
void MyObject::Destructor(node_api_basic_env env,
void* nativeObject,
void* /*finalize_hint*/) {
MyObject* obj = static_cast<MyObject*>(nativeObject);
delete obj;
}
Expand Down Expand Up @@ -154,7 +155,7 @@ napi_value MyObject::Multiply(napi_env env, napi_callback_info info) {
}

// This finalizer should never be invoked.
void ObjectWrapDanglingReferenceFinalizer(napi_env env,
void ObjectWrapDanglingReferenceFinalizer(node_api_basic_env env,
void* finalize_data,
void* finalize_hint) {
assert(0 && "unreachable");
Expand Down
7 changes: 7 additions & 0 deletions test/js-native-api/6_object_wrap/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
"sources": [
"6_object_wrap.cc"
]
},
{
"target_name": "6_object_wrap_basic_finalizer",
"defines": [ "NAPI_EXPERIMENTAL" ],
"sources": [
"6_object_wrap.cc"
]
}
]
}
4 changes: 3 additions & 1 deletion test/js-native-api/6_object_wrap/myobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
class MyObject {
public:
static void Init(napi_env env, napi_value exports);
static void Destructor(napi_env env, void* nativeObject, void* finalize_hint);
static void Destructor(node_api_basic_env env,
void* nativeObject,
void* finalize_hint);

private:
explicit MyObject(double value_ = 0);
Expand Down
20 changes: 20 additions & 0 deletions test/js-native-api/6_object_wrap/test-basic-finalizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Flags: --expose-gc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also test that the finalizer was called? Like, adding a heap-allocated int to the environment with napi_set_instance_data which is incremented from the finalizer, and an accessor to ensure that the value was incremented. We should try to make sure, if possible, that we check after gc but before the event loop has had a chance to run. That way we can distinguish between synchronous and asynchronous finalization.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated, thanks!


'use strict';
const common = require('../../common');
const addon = require(`./build/${common.buildType}/6_object_wrap_basic_finalizer`);
const { onGC } = require('../../common/gc');

/**
* This test verifies that an ObjectWrap can be correctly finalized with an NAPI_EXPERIMENTAL
* node_api_basic_finalizer.
*/

{
let obj = new addon.MyObject(9);
onGC(obj, {
ongc: common.mustCall(),
});
obj = null;
global.gc();
}
Loading