| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Review requested:
|
Sorry, something went wrong.
|
This PR was discussed today in the Node-API meeting and the suggestion was to reuse the existing napi_ref instead of adding the new napi_persistent type. I am going to add new versions of functions related to napi_ref that will have a flag that will control behavior of napi_ref depending on whether it supports the weak ref semantic:
The new functions are going to have the same name as the current function, but to have prefix node_api_ instead of napi_, and to have a new flags parameter. |
Sorry, something went wrong.
|
Adding "blocked" label as #42557 (comment) said to prevent unexpected landing. Feel free to remove the label when it is not the case anymore. |
Sorry, something went wrong.
|
Hi @nodejs/node-api , can we get a new review after @vmoroz 's implementation changes that address the blocked issue re. #42557 (comment) ? Thanks |
Sorry, something went wrong.
There was a problem hiding this comment.
Doc should indicated as experimental as well.
Sorry, something went wrong.
|
We discussed in the 20 May Node-API meeting that @vmoroz would like to change the enum names for node_api_reftype_strong_or_weak and node_api_reftype_strong. If anyone has some suggestions, please feel free to comment on the PR. Thanks! |
Sorry, something went wrong.
|
@mhdawson, @legendecas, @NickNaso, per our discussion today at the Node-API meeting, I had updated the PR description and added a note to the doc that node_api_create_reference is targeting to replace the napi_create_reference. The PR is ready to be reviewed and merged. |
Sorry, something went wrong.
|
Some thoughts on naming. Maybe these would work?
Where we can explain the difference being that
In addition to the naming are we sure that all JavaScript engines will support making persistent references to all types or have what's needed for the node-api implementation for the engine to be able implement something that looks like a reference? |
Sorry, something went wrong.
|
AFAICT, the main blocker for supporting arbitrary values in napi_create_reference is the concern on various engine supports for the feature. I take a superficial dig into engines on the edge like JerryScript and found that they all support creating references on primitive values (with reference counting): https://jerryscript.net/api-reference/#jerry_acquire_value, and QuickJS JSValue https://bellard.org/quickjs/quickjs.html. However, node-api implementation of napi_create_reference in the iotjs, a Node.js implementation based on JerryScript, is not supporting weak references: https://github.com/jerryscript-project/iotjs/blob/master/src/napi/node_api_lifetime.c#L210 As the weak reference is not guaranteed to be consistent, as those values can be collected anytime, I believe the support of create strong references on primitive values can meet the criteria New API should be agnostic towards the underlying JavaScript VM and "A new API addition should be simultaneously implemented in at least one other VM implementation of Node.js". I believe it would be beneficial to strive to extend the maximum capability of existing APIs and try not to introduce new APIs for differences that are hard for end-users to choose between. |
Sorry, something went wrong.
@legendecas, do you think that instead of adding new API we should just change the implementation of the existing references to support all value types and just say in the docs that the weak references work only object-like values? |
Sorry, something went wrong.
@mhdawson, I have changed the names. |
Sorry, something went wrong.
Yes, we should try to extend the current API. For documentation, we should not distinguish types but instead say that the behavior of the weak reference is determined by the engine implementation, and is not guaranteed to be able to get the referenced value when the ref-count is reached 0. |
Sorry, something went wrong.
|
Hi @nodejs/node-api , This PR introduces two changes: (1) allowing references to all values and (2) the ability for modules to request certain feature sets at module registration. @vmoroz has requested some feedback on both of these points if possible. |
Sorry, something went wrong.
|
@mhdawson, @legendecas, I have updated the PR - please review. |
Sorry, something went wrong.
There was a problem hiding this comment.
This can be a good start for node-api to get started with backward-compatible feature additions!
As you mentioned in the node-api meetings, this bit flag (an enum is an int size) may only represent 32 features at most. I'm wondering if it would be more extensible to save the module's defined NAPI_VERSION as nm_napi_version here like nm_version instead. In this way, node can refuse to load a node-api addon when an addon requires NAPI_VERSION 10, but the node is compiled as NAPI_VERSION 9.
The drawback of the alternative is that people have to pick up all feature changes with the new NAPI_VERSION, not part of it. But this could also be a relief that we don't need to maintain a long list of features, but a version support list instead.
What do you think?
Sorry, something went wrong.
There was a problem hiding this comment.
I like the idea of passing Node-API version used for a module. This way we can enforce the version compatibility.
The only drawback could be that developers will not be able to choose functionality depending on the Node-API version at runtime. I am not sure if anyone does it though.
As for the 32-bit feature set limit, the proposal is to pass not the feature bits to the module, but rather the pointer to the feature set. This way we can use the first 31 bits normally. In case if we need more, then we can set the 32nd bit and it will mean that the feature set has the second 32bit number, and the feature set pointer becomes a pointer to the feature set array with two elements. We can extend this array to be as long as needed. Obviously, each new entry in this array will require its own enum type. In practice I doubt that we ever exceed the 31 bit limit, but if we do, then we can extend it using this approach.
Sorry, something went wrong.
There was a problem hiding this comment.
We never allowed creating a reference on primitive values (except Symbols). So I believe there is no need to check the feature bit here: reference on primitive values can not be a weak reference.
| _canBeWeak(!env->IsFeatureEnabled(napi_feature_reference_all_types) || | |
| _canBeWeak( |
Sorry, something went wrong.
There was a problem hiding this comment.
The intent here is to stop offering weak references for Symbols with the new flag and only do it for Objects and Functions to better match the JavaScript spec. But since currently we support weak references for Symbols and have unit tests in napi_references for them, I had to put the flag check here. This way the old code works without changes if the flag is not set.
Sorry, something went wrong.
There was a problem hiding this comment.
I removed the _canBeWeak field completely to let V8 engine to decide on the weak references' behavior.
The only true weak references, as it used to be before, are object, external objects, and functions.
All other types are strong references when the ref count is 0.
This behavior can be seen in the new tests.
The only difference between what we used to have before and now is that we allow all types instead of only four (object, external object, function, and symbol) to be ref counted.
It almost feels like that allowing use of napi_ref for all value types may not need a special feature, but we should rather just extend the existing behavior as we did previously for Symbols.
Sorry, something went wrong.
| node_api_default_experimental_features = node_api_feature_reference_all_types, | ||
|
|
||
| // version specific | ||
| node_api_default_features = node_api_default_experimental_features, |
There was a problem hiding this comment.
For compatiblity I'm wondering if we should tie the defaults to a Node-API version versus the vesion of Node.js Unless the module author choses to opt-in, they behaviour should not change unless they have moved up to a newer Node-API vesion?
Sorry, something went wrong.
There was a problem hiding this comment.
Looking more closely I think that is the approach that is described, but but nothing is guarded because its under experimental. Will make a comment in src/js_native_api_types.h
Sorry, something went wrong.
There was a problem hiding this comment.
My intent is to make it per Node-API version.
Sorry, something went wrong.
| // Not only objects, external objects, functions, and symbols as before. | ||
| node_api_feature_reference_all_types = 1 << 0, | ||
| // Each version of Node-API is going to have its own default set of features. | ||
| node_api_default_experimental_features = node_api_feature_reference_all_types, |
There was a problem hiding this comment.
I'm not sure if we should have this, I think we should guard the availabilty to be able to turn on experimental features with NAPI_EXPERIMENTAL, but I'm not sure if having a set different than the default for the Node-API version makes sense. Otherwise somebody who wants to use any experimental API is also forced into to new defaults.
Sorry, something went wrong.
There was a problem hiding this comment.
In case if someone does not want to use the new experimental default, they can always override it per module.
Sorry, something went wrong.
| ``` | ||
|
|
||
| * `[in] env`: The environment that the API is invoked under. | ||
| * `[in] feature`: The feature that we want to test. |
There was a problem hiding this comment.
| * `[in] feature`: The feature that we want to test. | |
| * `[in] feature`: The features that we want to test. |
Sorry, something went wrong.
There was a problem hiding this comment.
Changed. Though I am not sure why we need to use plural form, while the parameter is singular. Should I also rename the parameter?
Sorry, something went wrong.
| return napi_clear_last_error(env); | ||
| } | ||
|
|
||
| napi_status NAPI_CDECL node_api_is_feature_enabled(napi_env env, |
There was a problem hiding this comment.
I wonder if this should be in node_api.cc instead of this file. It is not tied to v8 right?
Sorry, something went wrong.
There was a problem hiding this comment.
It is not tied to V8. I was thinking that we want to have features available for different JS engines.
Sorry, something went wrong.
| #else // NODE_API_CUSTOM_FEATURES | ||
|
|
||
| #define NODE_API_DEFINE_DEFAULT_FEATURES \ | ||
| static node_api_features node_api_module_features = node_api_default_features; |
There was a problem hiding this comment.
Comments as before, I think this will end up setting to be specific to the Node.js version used to build versus the Node-API version selected. Should discuss this more.
Sorry, something went wrong.
There was a problem hiding this comment.
I am not sure how to address this. Let's discuss it in the Node-API meeting. The concern as I understand it is that if we add more experimental features, we may fail to propagate them to the previous versions of Node.JS, and thus it may cause differences in the behavior between Node.JS versions, while we have the same version of Node-API, right?
Sorry, something went wrong.
| #define NODE_API_FEATURES_PTR | ||
| #endif // NAPI_EXPERIMENTAL | ||
|
|
||
| #define NAPI_MODULE_X(modname, regfunc, priv, flags) \ |
There was a problem hiding this comment.
Should we just create a new NAPI_MODULE_X_FEATURES which takes the features parameter?
Sorry, something went wrong.
There was a problem hiding this comment.
It may be simpler - let me try.
Sorry, something went wrong.
|
Closing this PR because PR #45715 that was recently merged implements an alternative approach for changing existing behavior. It uses Node-API version instead of features. The PR #45715 also implements support for all value types supported by napi_ref. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
The issue
In the Node-API the napi_value exists only on the call stack. When the value needs to be persisted after the call stack is unwinded, we can use the napi_ref. Currently the napi_ref keeps napi_value only for napi_object, napi_function, napi_external, and napi_symbol types because napi_ref must support weak pointer semantic. Thus, there was a decision to not keep persistent values for other types such as napi_string or napi_number. Though, the napi_symbol cannot have the weak semantic, but we still can have a napi_ref for it.
Solution
In this PR we enable use of napi_ref for strong references to all napi_value types. Though, only references for napi_object, napi_external, and napi_function types could have the true weak reference semantic. These three types could be collected by GC when the ref count is 0, while other types cannot be collected because they are always string references. To keep the backward compatibility, this PR enables the new behavior under a special node_api_features bit flag node_api_feature_reference_all_types. The node_api_features are being introduced in this PR.
The new node_api_features allow changing internal behavior of existing Node-API functions.
We pass a node_api_features pointer to the napi_module struct in the NAPI_MODULE_X macro. This macro is used for the module registration. If the module is initialized without using this macro, then there will be no features selected and the module will use the node_api_feature_none.
Each Node-API version is going to define its own default set of features. For the current version it can be accessed using node_api_default_features. A module can override the set of its enabled features by adding NODE_API_CUSTOM_FEATURES definition to the .gyp file and then setting the value of the global node_api_module_features variable. To check enabled features, use the node_api_is_feature_enabled function.
For example, to disable node_api_feature_reference_all_types we can exclude its bit from the node_api_default_features:
Documentation
The n-api.md documentation is updated with the info about node_api_features enum and the node_api_is_feature_enabled function.
Testing
Added three new tests:
The test stores napi_value of different types and then retrieves them for the strong and weak napi_ref references.
The test_reference and test_init_reference_obj_only disable the node_api_feature_reference_all_types feature and make sure that the old napi_ref behavior continues to work.
The NAPI_EXPERIMENTAL is added to common.h and entry_point.c in test/js-native-api folder to make sure that the js-native-api tests always use the latest Node-API version features.