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

[v8.x] n-api: add generic finalizer callback #28296

Conversation

gabrielschulhof
Copy link
Contributor

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: nodejs/abi-stable-node#313
PR-URL: #22244

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. node-api Issues and PRs related to the Node-API. v8.x labels Jun 19, 2019
@gabrielschulhof gabrielschulhof changed the title n-api: add generic finalizer callback [v8.x] n-api: add generic finalizer callback Jun 19, 2019
addaleax
addaleax previously approved these changes Jun 19, 2019
Copy link
Member

@addaleax addaleax left a comment

Choose a reason for hiding this comment

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

Idk … I would somehow prefer an API that would also automatically run the finalizer when the Node.js Environment exits, and while that’s totally doable, I feel like that the design of previous N-API funtions in this direction already messed that part up and so I’m not sure if it’s better to be consistent with that or better to be more easily usable here?

CHECK_ARG(env, js_object);

v8::Isolate* isolate = env->isolate;
v8::Local<v8::Context> context = isolate->GetCurrentContext();

This comment was marked as outdated.

### napi_add_finalizer
<!-- YAML
added: v8.0.0
napiVersion: 1

This comment was marked as outdated.

@addaleax addaleax dismissed their stale review June 19, 2019 21:56

sorry, only meant to comment, not approve

Copy link
Member

@addaleax addaleax left a comment

Choose a reason for hiding this comment

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

Sorry, I was confused and thought this was a PR against master – thanks for the backport!

That being said, my grudges with the API still kind of stand … 😄

@gabrielschulhof
Copy link
Contributor Author

@addaleax the finalizer does get automatically run when the environment exits, because everything is garbage-collected at that time, right?

@gabrielschulhof
Copy link
Contributor Author

@addaleax yikes! Looks like it's not finalizing at all on environment teardown! However, I get the impression that we can't simply bunch up all the finalizers, because there may be interdependence among them. Can we coax the garbage collector into one final pass that releases everything before the environment exits?

@addaleax
Copy link
Member

@addaleax the finalizer does get automatically run when the environment exits, because everything is garbage-collected at that time, right?

Can we coax the garbage collector into one final pass that releases everything before the environment exits?

No, for two reasons:

  • V8 doesn’t call those callbacks on teardown.
  • Environment teardown and V8 Isolate teardown do not happen at the same time; N-API is already unusable after the former, and even if V8 were to invoke finalizer callbacks on teardown, that would happen during the latter.

That means that the only way to actually handle Environment teardown from an addon is a cleanup hook, but since callbacks added with napi_add_finalizer are not removable during that phase, napi_add_finalizer is inherently unusable as a way of cleaning up resources.

@gabrielschulhof
Copy link
Contributor Author

@addaleax OK but the finalizer added with napi_add_finalizer() is no different from any other finalizer that's added (napi_wrap(), napi_create_external(), napi_create_external_arraybuffer(), and napi_create_external_buffer()). All are basically weak references. So, none of them are any good if the engine doesn't call them.

That means that the only way to actually handle Environment teardown from an addon is a cleanup hook, but since callbacks added with napi_add_finalizer are not removable during that phase, napi_add_finalizer is inherently unusable as a way of cleaning up resources.

They may not be removable, but since they'll never be called it doesn't really matter that they're attached. We could keep a list of them in the environment, removing an item from the list when the weak callback does get called, and calling all remaining ones at environment teardown, but again, the correct order in which to call them may not necessarily be the order in which they appear in the list – though it may be OK to call them in this order – I just dunno.

@gabrielschulhof
Copy link
Contributor Author

@addaleax I'm actually thinking that any interdependence between finalizers must already be handled by addons, because they may be called "out of order" even under normal circumstances. Like, when a database handle goes out of scope before the query handle does, or something like that. So, it may be worth bunching them up and calling any remaining ones from a cleanup hook.

@nodejs-github-bot
Copy link
Collaborator

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: nodejs/abi-stable-node#313
PR-URL: nodejs#22244
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
@gabrielschulhof
Copy link
Contributor Author

Rebased.

@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

BethGriggs pushed a commit that referenced this pull request Sep 19, 2019
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: nodejs/abi-stable-node#313
PR-URL: #22244
Backport-PR-URL: #28296
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
@BethGriggs
Copy link
Member

Landed on v8.x-staging

@BethGriggs BethGriggs closed this Sep 19, 2019
@BethGriggs
Copy link
Member

Backed out from v8.x-staging as after discussions with @gabrielschulhof and @mhdawson we determined this PR is semver-minor, and there are no plans to do another minor v8.x release.

@BethGriggs BethGriggs reopened this Sep 19, 2019
@BethGriggs BethGriggs added the semver-minor PRs that contain new features and should be released in the next minor version. label Sep 19, 2019
@gabrielschulhof
Copy link
Contributor Author

v8.x will receive no further updates.

@gabrielschulhof gabrielschulhof deleted the backport-22244-to-v8.x branch October 13, 2019 07:28
@gabrielschulhof gabrielschulhof restored the backport-22244-to-v8.x branch October 14, 2019 18:49
@gabrielschulhof gabrielschulhof deleted the backport-22244-to-v8.x branch March 13, 2020 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ Issues and PRs that require attention from people who are familiar with C++. node-api Issues and PRs related to the Node-API. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants