n-api: Re-use napi_env between modules#14217
n-api: Re-use napi_env between modules#14217gabrielschulhof wants to merge 1 commit intonodejs:masterfrom
Conversation
src/node_api.cc
Outdated
There was a problem hiding this comment.
node::Mutex (and use node::Mutex::ScopedLock below), then you won't need a uv_once_t either.
src/node_api.cc
Outdated
There was a problem hiding this comment.
Are napi_env instances immortal? If not, there should be code somewhere to remove it from the map again.
There was a problem hiding this comment.
I guess we need a refcount then, because we need to know, for each isolate, how many modules are using the napi_env.
There was a problem hiding this comment.
We shall also need a v8impl::release_env() to dereference/delete. However, these only makes sense when we have a module unload strategy.
There was a problem hiding this comment.
I have changed the comment about v8impl::get_env() to remind of this.
There was a problem hiding this comment.
Style nit: can you line up the arguments in this file and others?
src/node_api.cc
Outdated
There was a problem hiding this comment.
The comment should probably change now as we'd no longer delete the env when a module is unloaded.
|
Can you change the title for the commit comment so that Re-use is lower case -> re-use |
|
I think this isn't going to work when modules static-link |
|
@jasongin perhaps then we need a public API for per-isolate data that is better than what V8 offers. |
248260d to
6a58919
Compare
|
@bnoordhuis @mhdawson I have now addressed your review comments. I'm not sure I should be implementing the As for the interoperability with statically linked node-addon-api versions mentioned by @jasongin, I think we've already broken that with the stricter wrapping, because we perform the type check based on the value of the string pointer, not its contents. |
I think that is not actually a problem, because there should never be a need for a module to unwrap an instance that was wrapped by a different module. |
|
@TimothyGu's idea about using TBH, if we could attach such hidden properties to the global object we'd essentially have the per- In terms of implementation, from https://github.com/nodejs/nan/blob/master/nan_private.h it looks like |
|
@jasongin I wouldn't dismiss the idea of cross-module wrapping/unwrapping so easily. I can imagine a scenario where we have two different packages depending on the same N-API module and the application passing objects originating from one to the other and vice versa. |
6a58919 to
f7174d0
Compare
|
@mhdawson @bnoordhuis @jasongin I re-wrote this patch using @TimothyGu's idea regarding |
|
Oh, and it takes care of the eventuality of module unloading, and the eventuality of a module having to be loaded multiple times for multiple contexts as foretold by @bnoordhuis. |
src/node_api.cc
Outdated
There was a problem hiding this comment.
You should try to cache the key somehow to avoid having to create a new string and getting it from the V8 internal hash map on every run. GC is a non-concern as v8::Privates created through ForApi will never be GC'd.
There was a problem hiding this comment.
That's a bit of a chicken-and-egg problem. I mean, I could create a std::map keyed on the isolate and store these v8::Privates but then I might as well go with the previous approach of storing the napi_env in the map's value.
This code runs once as part of DLopen() for a given module and then never again for that module. Given this, is it worth caching this value?
There was a problem hiding this comment.
Actually, storing the napi_env instead of the v8::Private means I lose the ability to pass a napi_env created internally to node-addon-api, so I wouldn't revert to the previous approach. Still, I would only introduce a mutex if caching it really is worth it for the load-module use case.
There was a problem hiding this comment.
If module loading performance isn't a concern, I wouldn't worry about it. FWIW it's also not necessary to use a mutex as ForApi is idempotent.
There was a problem hiding this comment.
I thought the point of caching the v8::Private was to avoid calling ForApi more than once per new isolate. Or did you mean that I should cache the result of v8::String::NewFromOneByte?
If I use a std::map I must protect it with a mutex because another thread might be in the process of depositing a new value or it might be in the process of erasing an unused value.
I suppose you mean the kind of caching that I see in node.cc, like env->exports_string(). I guess maybe I should start looking into using node::Environment.
src/node_api.cc
Outdated
There was a problem hiding this comment.
NewFromOneByte would suffice.
src/node_api.cc
Outdated
There was a problem hiding this comment.
These two checks can be combined as CHECK(maybe_set.FromJust(false)).
There was a problem hiding this comment.
AFAICT FromJust() doesn't take any parameters. I tried to combine, but I get
In file included from ../src/node_internals.h:28:0,
from ../src/node.h:173,
from ../src/node_buffer.h:25,
from ../src/node_api.cc:11:
../src/node_api.cc: In function ‘napi_env__* {anonymous}::v8impl::get_env(v8::Local<v8::Context>)’:
../src/node_api.cc:735:35: error: no matching function for call to ‘v8::Maybe<bool>::FromJust(bool)’
CHECK(maybe_set.FromJust(false));
^
../src/util.h:107:44: note: in definition of macro ‘UNLIKELY’
#define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
^~~~
../src/node_api.cc:735:5: note: in expansion of macro ‘CHECK’
CHECK(maybe_set.FromJust(false));
^~~~~
In file included from ../src/node.h:63:0,
from ../src/node_buffer.h:25,
from ../src/node_api.cc:11:
../deps/v8/include/v8.h:8014:15: note: candidate: T v8::Maybe<T>::FromJust() const [with T = bool]
V8_INLINE T FromJust() const {
^~~~~~~~
../deps/v8/include/v8.h:8014:15: note: candidate expects 0 arguments, 1 provided
There was a problem hiding this comment.
Oops I meant FromMaybe(false)
c775e90 to
9ff9cf7
Compare
TimothyGu
left a comment
There was a problem hiding this comment.
LGTM. Don't worry about the Private thing, not sure what I was thinking.
src/node_api.cc
Outdated
There was a problem hiding this comment.
All other functions in the v8impl namespace uses CamelCase. Might be good to do that here etc.
src/node_api.cc
Outdated
src/node_api.cc
Outdated
There was a problem hiding this comment.
Just an observation but .ToLocalChecked() also does the equivalent of CHECK(!maybe_value.IsEmpty()).
src/node_api.cc
Outdated
There was a problem hiding this comment.
This works because ~Persistent() currently doesn't call .Reset() but v8.h indicates that may change in the future. Not sure what to do about that but I figured you should know.
9ff9cf7 to
d057bfc
Compare
|
@TimothyGu I have updated to camelCase. @bnoordhuis I have removed the |
Store the `napi_env` on the global object at a private key. This gives us one `napi_env` per context. Re: nodejs#13872 (comment)
d057bfc to
cdb7f13
Compare
|
I changed the commit message subject to contain no uppercase letters. |
|
If this is good to go, may I have a CI run please? |
|
Seems like the CI is having some issues, though. |
|
I think the CI is fixed now. Could somebody please submit this PR? |
|
Oh, NM. Thanks! |
|
https://ci.nodejs.org/job/node-test-pull-request/9351/ completed successfully a while ago. It shouldn't still show as pending in this PR. |
|
@gabrielschulhof CI status reporting is broken, don’t worry about it (not sure whether somebody’s looking into it or not). |
|
@addaleax NP. I'm just eager to get this landed, that's all :) |
|
I’m going to sleep soon but if it’s not landed tomorrow I can do that. Also, just nominated you for push & CI access, that should be a bit more practical if you like :) |
|
Wow! I'm honoured! Thanks! |
|
Landed in 9926dfe. I also amended the commit message to reference #14367 rather than #13872 (comment), as the approach we ended up taking was documented in #14367. |
|
And also, I'd second Anna's nomination :) |
Store the `napi_env` on the global object at a private key. This gives us one `napi_env` per context. Refs: nodejs#14367 PR-URL: nodejs#14217 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Create a std::map keyed on the isolate pointer and storing one napi_env
per isolate and protect it with a mutex.
Re: #13872 (comment)
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passesAffected core subsystem(s)
n-api
@bnoordhuis @mhdawson this is what sharing the
napi_envwould look like with a global static and a mutex.