diff --git a/README.md b/README.md index 1f1027e1b57ecf..70a130c5fa7d07 100644 --- a/README.md +++ b/README.md @@ -204,8 +204,6 @@ For information about the governance of the Node.js project, see **Michaël Zasso** <> (he/him) * [tniessen](https://github.com/tniessen) - **Tobias Nießen** <> (he/him) -* [Trott](https://github.com/Trott) - - **Rich Trott** <> (he/him) #### TSC regular members @@ -233,6 +231,8 @@ For information about the governance of the Node.js project, see **Rod Vagg** <> * [TimothyGu](https://github.com/TimothyGu) - **Tiancheng "Timothy" Gu** <> (he/him) +* [Trott](https://github.com/Trott) - + **Rich Trott** <> (he/him)
diff --git a/doc/api/n-api.md b/doc/api/n-api.md index dd1bc884e506a8..5de2c0cc48276a 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -3000,6 +3000,50 @@ The native string is copied. The JavaScript `string` type is described in [Section 6.1.4][] of the ECMAScript Language Specification. +#### `node_api_create_property_key_utf16` + + + +> Stability: 1 - Experimental + +```c +napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); +``` + +* `[in] env`: The environment that the API is invoked under. +* `[in] str`: Character buffer representing a UTF16-LE-encoded string. +* `[in] length`: The length of the string in two-byte code units, or + `NAPI_AUTO_LENGTH` if it is null-terminated. +* `[out] result`: A `napi_value` representing an optimized JavaScript `string` + to be used as a property key for objects. + +Returns `napi_ok` if the API succeeded. + +This API creates an optimized JavaScript `string` value from +a UTF16-LE-encoded C string to be used as a property key for objects. +The native string is copied. + +Many JavaScript engines including V8 use internalized strings as keys +to set and get property values. They typically use a hash table to create +and lookup such strings. While it adds some cost per key creation, it improves +the performance after that by enabling comparison of string pointers instead +of the whole strings. + +If a new JavaScript string is intended to be used as a property key, then for +some JavaScript engines it will be more efficient to use +the `node_api_create_property_key_utf16` function. +Otherwise, use the `napi_create_string_utf16` or +`node_api_create_external_string_utf16` functions as there may be additional +overhead in creating/storing strings with this method. + +The JavaScript `string` type is described in +[Section 6.1.4][] of the ECMAScript Language Specification. + ### Functions to convert from Node-API to C types #### `napi_get_array_length` diff --git a/src/js_native_api.h b/src/js_native_api.h index d665052b947552..5b8a26ed2331cf 100644 --- a/src/js_native_api.h +++ b/src/js_native_api.h @@ -110,6 +110,13 @@ node_api_create_external_string_utf16(napi_env env, napi_value* result, 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_utf16( + napi_env env, const char16_t* str, size_t length, napi_value* result); +#endif // NAPI_EXPERIMENTAL + NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, napi_value description, napi_value* result); diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index 044244eccfe9ea..78d6f24e8796ee 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -1651,6 +1651,18 @@ node_api_create_external_string_utf16(napi_env env, }); } +napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env, + const char16_t* str, + size_t length, + napi_value* result) { + return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) { + return v8::String::NewFromTwoByte(isolate, + reinterpret_cast(str), + v8::NewStringType::kInternalized, + static_cast(length)); + }); +} + napi_status NAPI_CDECL napi_create_double(napi_env env, double value, napi_value* result) { diff --git a/test/js-native-api/test_string/test.js b/test/js-native-api/test_string/test.js index 8926b9451175bd..ffcf0fab754e7c 100644 --- a/test/js-native-api/test_string/test.js +++ b/test/js-native-api/test_string/test.js @@ -16,6 +16,8 @@ assert.strictEqual(test_string.TestLatin1External(empty), empty); assert.strictEqual(test_string.TestUtf16External(empty), empty); assert.strictEqual(test_string.TestLatin1ExternalAutoLength(empty), empty); assert.strictEqual(test_string.TestUtf16ExternalAutoLength(empty), empty); +assert.strictEqual(test_string.TestPropertyKeyUtf16(empty), empty); +assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(empty), empty); assert.strictEqual(test_string.Utf16Length(empty), 0); assert.strictEqual(test_string.Utf8Length(empty), 0); @@ -33,6 +35,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str1), str1); assert.strictEqual(test_string.TestLatin1Insufficient(str1), str1.slice(0, 3)); assert.strictEqual(test_string.TestUtf8Insufficient(str1), str1.slice(0, 3)); assert.strictEqual(test_string.TestUtf16Insufficient(str1), str1.slice(0, 3)); +assert.strictEqual(test_string.TestPropertyKeyUtf16(str1), str1); +assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str1), str1); assert.strictEqual(test_string.Utf16Length(str1), 11); assert.strictEqual(test_string.Utf8Length(str1), 11); @@ -50,6 +54,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str2), str2); assert.strictEqual(test_string.TestLatin1Insufficient(str2), str2.slice(0, 3)); assert.strictEqual(test_string.TestUtf8Insufficient(str2), str2.slice(0, 3)); assert.strictEqual(test_string.TestUtf16Insufficient(str2), str2.slice(0, 3)); +assert.strictEqual(test_string.TestPropertyKeyUtf16(str2), str2); +assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str2), str2); assert.strictEqual(test_string.Utf16Length(str2), 62); assert.strictEqual(test_string.Utf8Length(str2), 62); @@ -67,6 +73,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str3), str3); assert.strictEqual(test_string.TestLatin1Insufficient(str3), str3.slice(0, 3)); assert.strictEqual(test_string.TestUtf8Insufficient(str3), str3.slice(0, 3)); assert.strictEqual(test_string.TestUtf16Insufficient(str3), str3.slice(0, 3)); +assert.strictEqual(test_string.TestPropertyKeyUtf16(str3), str3); +assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str3), str3); assert.strictEqual(test_string.Utf16Length(str3), 27); assert.strictEqual(test_string.Utf8Length(str3), 27); @@ -84,6 +92,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str4), str4); assert.strictEqual(test_string.TestLatin1Insufficient(str4), str4.slice(0, 3)); assert.strictEqual(test_string.TestUtf8Insufficient(str4), str4.slice(0, 1)); assert.strictEqual(test_string.TestUtf16Insufficient(str4), str4.slice(0, 3)); +assert.strictEqual(test_string.TestPropertyKeyUtf16(str4), str4); +assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str4), str4); assert.strictEqual(test_string.Utf16Length(str4), 31); assert.strictEqual(test_string.Utf8Length(str4), 62); @@ -101,6 +111,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str5), str5); assert.strictEqual(test_string.TestLatin1Insufficient(str5), str5.slice(0, 3)); assert.strictEqual(test_string.TestUtf8Insufficient(str5), str5.slice(0, 1)); assert.strictEqual(test_string.TestUtf16Insufficient(str5), str5.slice(0, 3)); +assert.strictEqual(test_string.TestPropertyKeyUtf16(str5), str5); +assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str5), str5); assert.strictEqual(test_string.Utf16Length(str5), 63); assert.strictEqual(test_string.Utf8Length(str5), 126); @@ -113,6 +125,8 @@ assert.strictEqual(test_string.TestUtf16External(str6), str6); assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str6), str6); assert.strictEqual(test_string.TestUtf8Insufficient(str6), str6.slice(0, 1)); assert.strictEqual(test_string.TestUtf16Insufficient(str6), str6.slice(0, 3)); +assert.strictEqual(test_string.TestPropertyKeyUtf16(str6), str6); +assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str6), str6); assert.strictEqual(test_string.Utf16Length(str6), 5); assert.strictEqual(test_string.Utf8Length(str6), 14); diff --git a/test/js-native-api/test_string/test_string.c b/test/js-native-api/test_string/test_string.c index b2046e3b873392..0095273bffec67 100644 --- a/test/js-native-api/test_string/test_string.c +++ b/test/js-native-api/test_string/test_string.c @@ -294,6 +294,23 @@ static napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) { return output; } +static napi_value TestPropertyKeyUtf16(napi_env env, napi_callback_info info) { + return TestTwoByteImpl(env, + info, + napi_get_value_string_utf16, + node_api_create_property_key_utf16, + actual_length); +} + +static napi_value TestPropertyKeyUtf16AutoLength(napi_env env, + napi_callback_info info) { + return TestTwoByteImpl(env, + info, + napi_get_value_string_utf16, + node_api_create_property_key_utf16, + auto_length); +} + static napi_value Utf16Length(napi_env env, napi_callback_info info) { napi_value args[1]; NODE_API_CALL(env, validate_and_retrieve_single_string_arg(env, info, args)); @@ -410,6 +427,9 @@ napi_value Init(napi_env env, napi_value exports) { DECLARE_NODE_API_PROPERTY("TestLargeLatin1", TestLargeLatin1), DECLARE_NODE_API_PROPERTY("TestLargeUtf16", TestLargeUtf16), DECLARE_NODE_API_PROPERTY("TestMemoryCorruption", TestMemoryCorruption), + DECLARE_NODE_API_PROPERTY("TestPropertyKeyUtf16", TestPropertyKeyUtf16), + DECLARE_NODE_API_PROPERTY("TestPropertyKeyUtf16AutoLength", + TestPropertyKeyUtf16AutoLength), }; init_test_null(env, exports); diff --git a/test/pummel/pummel.status b/test/pummel/pummel.status index 143450986e46c4..abd8b8957df0d4 100644 --- a/test/pummel/pummel.status +++ b/test/pummel/pummel.status @@ -9,6 +9,8 @@ prefix pummel [$system==win32] # https://github.com/nodejs/node/issues/40728 test-fs-watch-non-recursive: PASS,FLAKY +# https://github.com/nodejs/node/issues/50260 +test-structuredclone-jstransferable: PASS,FLAKY [$system==linux] # https://github.com/nodejs/node/issues/38226