node-api: define version 10

Notable runtime changes to existing APIs:
- returning `node_api_cannot_run_js` instead of
  `napi_pending_exception`.
- allow creating references to objects, functions, and symbols.

PR-URL: https://github.com/nodejs/node/pull/55676
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Gabriel Schulhof 2024-12-31 08:29:50 -08:00 committed by GitHub
parent 19d58c5181
commit c5aa8b8ef1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 46 additions and 65 deletions

View File

@ -1748,7 +1748,7 @@ will not be freed. This can be avoided by calling
**Change History:** **Change History:**
* Experimental (`NAPI_EXPERIMENTAL` is defined): * Version 10 (`NAPI_VERSION` is defined as `10` or higher):
References can be created for all value types. The new supported value References can be created for all value types. The new supported value
types do not support weak reference semantic and the values of these types types do not support weak reference semantic and the values of these types
@ -2702,10 +2702,9 @@ JavaScript `TypedArray` objects are described in
added: added:
- v23.0.0 - v23.0.0
- v22.12.0 - v22.12.0
napiVersion: 10
--> -->
> Stability: 1 - Experimental
```c ```c
napi_status NAPI_CDECL node_api_create_buffer_from_arraybuffer(napi_env env, napi_status NAPI_CDECL node_api_create_buffer_from_arraybuffer(napi_env env,
napi_value arraybuffer, napi_value arraybuffer,
@ -2967,10 +2966,9 @@ The JavaScript `string` type is described in
added: added:
- v20.4.0 - v20.4.0
- v18.18.0 - v18.18.0
napiVersion: 10
--> -->
> Stability: 1 - Experimental
```c ```c
napi_status napi_status
node_api_create_external_string_latin1(napi_env env, node_api_create_external_string_latin1(napi_env env,
@ -3047,10 +3045,9 @@ The JavaScript `string` type is described in
added: added:
- v20.4.0 - v20.4.0
- v18.18.0 - v18.18.0
napiVersion: 10
--> -->
> Stability: 1 - Experimental
```c ```c
napi_status napi_status
node_api_create_external_string_utf16(napi_env env, node_api_create_external_string_utf16(napi_env env,
@ -3142,10 +3139,9 @@ creation methods.
added: added:
- v22.9.0 - v22.9.0
- v20.18.0 - v20.18.0
napiVersion: 10
--> -->
> Stability: 1 - Experimental
```c ```c
napi_status NAPI_CDECL node_api_create_property_key_latin1(napi_env env, napi_status NAPI_CDECL node_api_create_property_key_latin1(napi_env env,
const char* str, const char* str,
@ -3177,10 +3173,9 @@ The JavaScript `string` type is described in
added: added:
- v21.7.0 - v21.7.0
- v20.12.0 - v20.12.0
napiVersion: 10
--> -->
> Stability: 1 - Experimental
```c ```c
napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env, napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env,
const char16_t* str, const char16_t* str,
@ -3210,10 +3205,9 @@ The JavaScript `string` type is described in
added: added:
- v22.9.0 - v22.9.0
- v20.18.0 - v20.18.0
napiVersion: 10
--> -->
> Stability: 1 - Experimental
```c ```c
napi_status NAPI_CDECL node_api_create_property_key_utf8(napi_env env, napi_status NAPI_CDECL node_api_create_property_key_utf8(napi_env env,
const char* str, const char* str,
@ -6533,7 +6527,7 @@ napi_create_threadsafe_function(napi_env env,
**Change History:** **Change History:**
* Experimental (`NAPI_EXPERIMENTAL` is defined): * Version 10 (`NAPI_VERSION` is defined as `10` or higher):
Uncaught exceptions thrown in `call_js_cb` are handled with the Uncaught exceptions thrown in `call_js_cb` are handled with the
[`'uncaughtException'`][] event, instead of being ignored. [`'uncaughtException'`][] event, instead of being ignored.

View File

@ -85,7 +85,7 @@ with:
```bash ```bash
grep \ grep \
-E \ -nHE \
'N(ODE_)?API_EXPERIMENTAL' \ 'N(ODE_)?API_EXPERIMENTAL' \
src/js_native_api{_types,}.h \ src/js_native_api{_types,}.h \
src/node_api{_types,}.h src/node_api{_types,}.h
@ -95,13 +95,13 @@ and update the define version guards with the release version:
```diff ```diff
- #ifdef NAPI_EXPERIMENTAL - #ifdef NAPI_EXPERIMENTAL
+ #if NAPI_VERSION >= 10 + #if NAPI_VERSION >= 11
NAPI_EXTERN napi_status NAPI_CDECL NAPI_EXTERN napi_status NAPI_CDECL
node_api_function(napi_env env); node_api_function(napi_env env);
- #endif // NAPI_EXPERIMENTAL - #endif // NAPI_EXPERIMENTAL
+ #endif // NAPI_VERSION >= 10 + #endif // NAPI_VERSION >= 11
``` ```
Remove any feature flags of the form `NODE_API_EXPERIMENTAL_HAS_<FEATURE>`. Remove any feature flags of the form `NODE_API_EXPERIMENTAL_HAS_<FEATURE>`.
@ -121,11 +121,11 @@ Also, update the Node-API version value of the `napi_get_version` test in
#### Step 2. Update runtime version guards #### Step 2. Update runtime version guards
If this release includes runtime behavior version guards, the relevant commits If this release includes runtime behavior version guards, the relevant commits
should already include `NAPI_VERSION_EXPERIMENTAL` guard for the change. Check should already include the `NAPI_VERSION_EXPERIMENTAL` guard for the change.
for these guards with: Check for these guards with:
```bash ```bash
grep NAPI_VERSION_EXPERIMENTAL src/js_native_api_v8* src/node_api.cc grep -nH NAPI_VERSION_EXPERIMENTAL src/js_native_api_v8* src/node_api.cc
``` ```
and substitute this guard version with the release version `x`. and substitute this guard version with the release version `x`.
@ -138,7 +138,7 @@ Check for these definitions with:
```bash ```bash
grep \ grep \
-E \ -nHE \
'N(ODE_)?API_EXPERIMENTAL' \ 'N(ODE_)?API_EXPERIMENTAL' \
test/node-api/*/{*.{h,c},binding.gyp} \ test/node-api/*/{*.{h,c},binding.gyp} \
test/js-native-api/*/{*.{h,c},binding.gyp} test/js-native-api/*/{*.{h,c},binding.gyp}
@ -170,7 +170,7 @@ stability banner:
<!-- YAML <!-- YAML
added: added:
- v1.2.3 - v1.2.3
+ napiVersion: 10 + napiVersion: 11
--> -->
- > Stability: 1 - Experimental - > Stability: 1 - Experimental
@ -186,7 +186,7 @@ For all runtime version guards updated in Step 2, check for these definitions
with: with:
```bash ```bash
grep NAPI_EXPERIMENTAL doc/api/n-api.md grep -nH NAPI_EXPERIMENTAL doc/api/n-api.md
``` ```
In `doc/api/n-api.md`, update the `experimental` change history item to be the In `doc/api/n-api.md`, update the `experimental` change history item to be the

View File

@ -92,8 +92,7 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf16(napi_env env,
const char16_t* str, const char16_t* str,
size_t length, size_t length,
napi_value* result); napi_value* result);
#ifdef NAPI_EXPERIMENTAL #if NAPI_VERSION >= 10
#define NODE_API_EXPERIMENTAL_HAS_EXTERNAL_STRINGS
NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_latin1( NAPI_EXTERN napi_status NAPI_CDECL node_api_create_external_string_latin1(
napi_env env, napi_env env,
char* str, char* str,
@ -110,17 +109,14 @@ node_api_create_external_string_utf16(napi_env env,
void* finalize_hint, void* finalize_hint,
napi_value* result, napi_value* result,
bool* copied); bool* copied);
#endif // NAPI_EXPERIMENTAL
#ifdef NAPI_EXPERIMENTAL
#define NODE_API_EXPERIMENTAL_HAS_PROPERTY_KEYS
NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_latin1( NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_latin1(
napi_env env, const char* str, size_t length, napi_value* result); napi_env env, const char* str, size_t length, napi_value* result);
NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf8( NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf8(
napi_env env, const char* str, size_t length, napi_value* result); napi_env env, const char* str, size_t length, napi_value* result);
NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16( NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16(
napi_env env, const char16_t* str, size_t length, napi_value* result); napi_env env, const char16_t* str, size_t length, napi_value* result);
#endif // NAPI_EXPERIMENTAL #endif // NAPI_VERSION >= 10
NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env,
napi_value description, napi_value description,

View File

@ -2753,7 +2753,7 @@ napi_status NAPI_CDECL napi_create_reference(napi_env env,
CHECK_ARG(env, result); CHECK_ARG(env, result);
v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value); v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
if (env->module_api_version != NAPI_VERSION_EXPERIMENTAL) { if (env->module_api_version < 10) {
if (!(v8_value->IsObject() || v8_value->IsFunction() || if (!(v8_value->IsObject() || v8_value->IsFunction() ||
v8_value->IsSymbol())) { v8_value->IsSymbol())) {
return napi_set_last_error(env, napi_invalid_arg); return napi_set_last_error(env, napi_invalid_arg);

View File

@ -234,11 +234,11 @@ inline napi_status napi_set_last_error(node_api_basic_env basic_env,
CHECK_ENV_NOT_IN_GC((env)); \ CHECK_ENV_NOT_IN_GC((env)); \
RETURN_STATUS_IF_FALSE( \ RETURN_STATUS_IF_FALSE( \
(env), (env)->last_exception.IsEmpty(), napi_pending_exception); \ (env), (env)->last_exception.IsEmpty(), napi_pending_exception); \
RETURN_STATUS_IF_FALSE((env), \ RETURN_STATUS_IF_FALSE( \
(env)->can_call_into_js(), \ (env), \
(env->module_api_version == NAPI_VERSION_EXPERIMENTAL \ (env)->can_call_into_js(), \
? napi_cannot_run_js \ (env->module_api_version >= 10 ? napi_cannot_run_js \
: napi_pending_exception)); \ : napi_pending_exception)); \
napi_clear_last_error((env)); \ napi_clear_last_error((env)); \
v8impl::TryCatch try_catch((env)) v8impl::TryCatch try_catch((env))

View File

@ -93,11 +93,11 @@ void node_napi_env__::CallbackIntoModule(T&& call) {
return; return;
} }
node::Environment* node_env = env->node_env(); node::Environment* node_env = env->node_env();
// If the module api version is less than NAPI_VERSION_EXPERIMENTAL, // If the module api version is less than 10, and the option
// and the option --force-node-api-uncaught-exceptions-policy is not // --force-node-api-uncaught-exceptions-policy is not specified, emit a
// specified, emit a warning about the uncaught exception instead of // warning about the uncaught exception instead of triggering the uncaught
// triggering uncaught exception event. // exception event.
if (env->module_api_version < NAPI_VERSION_EXPERIMENTAL && if (env->module_api_version < 10 &&
!node_env->options()->force_node_api_uncaught_exceptions_policy && !node_env->options()->force_node_api_uncaught_exceptions_policy &&
!enforceUncaughtExceptionPolicy) { !enforceUncaughtExceptionPolicy) {
ProcessEmitDeprecationWarning( ProcessEmitDeprecationWarning(
@ -678,11 +678,13 @@ node::addon_context_register_func get_node_api_context_register_func(
const char* module_name, const char* module_name,
int32_t module_api_version) { int32_t module_api_version) {
static_assert( static_assert(
NODE_API_SUPPORTED_VERSION_MAX == 9, NODE_API_SUPPORTED_VERSION_MAX == 10,
"New version of Node-API requires adding another else-if statement below " "New version of Node-API requires adding another else-if statement below "
"for the new version and updating this assert condition."); "for the new version and updating this assert condition.");
if (module_api_version == 9) { if (module_api_version == 9) {
return node_api_context_register_func<9>; return node_api_context_register_func<9>;
} else if (module_api_version == 10) {
return node_api_context_register_func<10>;
} else if (module_api_version == NAPI_VERSION_EXPERIMENTAL) { } else if (module_api_version == NAPI_VERSION_EXPERIMENTAL) {
return node_api_context_register_func<NAPI_VERSION_EXPERIMENTAL>; return node_api_context_register_func<NAPI_VERSION_EXPERIMENTAL>;
} else if (module_api_version >= NODE_API_SUPPORTED_VERSION_MIN && } else if (module_api_version >= NODE_API_SUPPORTED_VERSION_MIN &&

View File

@ -133,8 +133,7 @@ napi_create_external_buffer(napi_env env,
napi_value* result); napi_value* result);
#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED #endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
#ifdef NAPI_EXPERIMENTAL #if NAPI_VERSION >= 10
#define NODE_API_EXPERIMENTAL_HAS_CREATE_BUFFER_FROM_ARRAYBUFFER
NAPI_EXTERN napi_status NAPI_CDECL NAPI_EXTERN napi_status NAPI_CDECL
node_api_create_buffer_from_arraybuffer(napi_env env, node_api_create_buffer_from_arraybuffer(napi_env env,
@ -142,7 +141,7 @@ node_api_create_buffer_from_arraybuffer(napi_env env,
size_t byte_offset, size_t byte_offset,
size_t byte_length, size_t byte_length,
napi_value* result); napi_value* result);
#endif // NAPI_EXPERIMENTAL #endif // NAPI_VERSION >= 10
NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env,
size_t length, size_t length,

View File

@ -100,7 +100,7 @@
// The NAPI_VERSION supported by the runtime. This is the inclusive range of // The NAPI_VERSION supported by the runtime. This is the inclusive range of
// versions which the Node.js binary being built supports. // versions which the Node.js binary being built supports.
#define NODE_API_SUPPORTED_VERSION_MAX 9 #define NODE_API_SUPPORTED_VERSION_MAX 10
#define NODE_API_SUPPORTED_VERSION_MIN 1 #define NODE_API_SUPPORTED_VERSION_MIN 1
// Node API modules use NAPI_VERSION 8 by default if it is not explicitly // Node API modules use NAPI_VERSION 8 by default if it is not explicitly

View File

@ -5,14 +5,14 @@
"sources": [ "sources": [
"test_cannot_run_js.c" "test_cannot_run_js.c"
], ],
"defines": [ "NAPI_EXPERIMENTAL" ], "defines": [ "NAPI_VERSION=10" ],
}, },
{ {
"target_name": "test_pending_exception", "target_name": "test_pending_exception",
"sources": [ "sources": [
"test_cannot_run_js.c" "test_cannot_run_js.c"
], ],
"defines": [ "NAPI_VERSION=8" ], "defines": [ "NAPI_VERSION=9" ],
} }
] ]
} }

View File

@ -22,7 +22,7 @@ static void Finalize(napi_env env, void* data, void* hint) {
// napi_pending_exception is returned). This is not deterministic from // napi_pending_exception is returned). This is not deterministic from
// the point of view of the addon. // the point of view of the addon.
#ifdef NAPI_EXPERIMENTAL #if NAPI_VERSION > 9
NODE_API_BASIC_ASSERT_RETURN_VOID( NODE_API_BASIC_ASSERT_RETURN_VOID(
result == napi_cannot_run_js || result == napi_ok, result == napi_cannot_run_js || result == napi_ok,
"getting named property from global in finalizer should succeed " "getting named property from global in finalizer should succeed "
@ -32,19 +32,10 @@ static void Finalize(napi_env env, void* data, void* hint) {
result == napi_pending_exception || result == napi_ok, result == napi_pending_exception || result == napi_ok,
"getting named property from global in finalizer should succeed " "getting named property from global in finalizer should succeed "
"or return napi_pending_exception"); "or return napi_pending_exception");
#endif // NAPI_EXPERIMENTAL #endif // NAPI_VERSION > 9
free(ref); free(ref);
} }
static void BasicFinalize(node_api_basic_env env, void* data, void* hint) {
#ifdef NAPI_EXPERIMENTAL
NODE_API_BASIC_CALL_RETURN_VOID(
env, node_api_post_finalizer(env, Finalize, data, hint));
#else
Finalize(env, data, hint);
#endif
}
static napi_value CreateRef(napi_env env, napi_callback_info info) { static napi_value CreateRef(napi_env env, napi_callback_info info) {
size_t argc = 1; size_t argc = 1;
napi_value cb; napi_value cb;
@ -55,8 +46,7 @@ static napi_value CreateRef(napi_env env, napi_callback_info info) {
NODE_API_CALL(env, napi_typeof(env, cb, &value_type)); NODE_API_CALL(env, napi_typeof(env, cb, &value_type));
NODE_API_ASSERT( NODE_API_ASSERT(
env, value_type == napi_function, "argument must be function"); env, value_type == napi_function, "argument must be function");
NODE_API_CALL(env, NODE_API_CALL(env, napi_add_finalizer(env, cb, ref, Finalize, NULL, ref));
napi_add_finalizer(env, cb, ref, BasicFinalize, NULL, ref));
return cb; return cb;
} }

View File

@ -34,7 +34,7 @@ assert.notStrictEqual(test_general.testGetPrototype(baseObject),
test_general.testGetPrototype(extendedObject)); test_general.testGetPrototype(extendedObject));
// Test version management functions // Test version management functions
assert.strictEqual(test_general.testGetVersion(), 9); assert.strictEqual(test_general.testGetVersion(), 10);
[ [
123, 123,

View File

@ -7,7 +7,7 @@
"test_null.c", "test_null.c",
], ],
"defines": [ "defines": [
"NAPI_EXPERIMENTAL", "NAPI_VERSION=10",
], ],
}, },
], ],

View File

@ -3,7 +3,7 @@
{ {
"target_name": "test_buffer", "target_name": "test_buffer",
"defines": [ "defines": [
'NAPI_EXPERIMENTAL' 'NAPI_VERSION=10'
], ],
"sources": [ "test_buffer.c" ] "sources": [ "test_buffer.c" ]
}, },

View File

@ -3,12 +3,12 @@
{ {
"target_name": "test_reference_all_types", "target_name": "test_reference_all_types",
"sources": [ "test_reference_by_node_api_version.c" ], "sources": [ "test_reference_by_node_api_version.c" ],
"defines": [ "NAPI_EXPERIMENTAL" ], "defines": [ "NAPI_VERSION=10" ],
}, },
{ {
"target_name": "test_reference_obj_only", "target_name": "test_reference_obj_only",
"sources": [ "test_reference_by_node_api_version.c" ], "sources": [ "test_reference_by_node_api_version.c" ],
"defines": [ "NAPI_VERSION=8" ], "defines": [ "NAPI_VERSION=9" ],
} }
] ]
} }