Skip to content

Commit 242139f

Browse files
mertcanaltinrichardlau
authored andcommitted
node-api: optimize napi_set_property for perf
PR-URL: #50282 Reviewed-By: Vladimir Morozov <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]>
1 parent 42b4f0f commit 242139f

File tree

5 files changed

+97
-0
lines changed

5 files changed

+97
-0
lines changed

doc/api/n-api.md

+44
Original file line numberDiff line numberDiff line change
@@ -3081,6 +3081,50 @@ The native string is copied.
30813081
The JavaScript `string` type is described in
30823082
[Section 6.1.4][] of the ECMAScript Language Specification.
30833083

3084+
#### `node_api_create_property_key_utf16`
3085+
3086+
<!-- YAML
3087+
added: REPLACEME
3088+
-->
3089+
3090+
> Stability: 1 - Experimental
3091+
3092+
```c
3093+
napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env,
3094+
const char16_t* str,
3095+
size_t length,
3096+
napi_value* result);
3097+
```
3098+
3099+
* `[in] env`: The environment that the API is invoked under.
3100+
* `[in] str`: Character buffer representing a UTF16-LE-encoded string.
3101+
* `[in] length`: The length of the string in two-byte code units, or
3102+
`NAPI_AUTO_LENGTH` if it is null-terminated.
3103+
* `[out] result`: A `napi_value` representing an optimized JavaScript `string`
3104+
to be used as a property key for objects.
3105+
3106+
Returns `napi_ok` if the API succeeded.
3107+
3108+
This API creates an optimized JavaScript `string` value from
3109+
a UTF16-LE-encoded C string to be used as a property key for objects.
3110+
The native string is copied.
3111+
3112+
Many JavaScript engines including V8 use internalized strings as keys
3113+
to set and get property values. They typically use a hash table to create
3114+
and lookup such strings. While it adds some cost per key creation, it improves
3115+
the performance after that by enabling comparison of string pointers instead
3116+
of the whole strings.
3117+
3118+
If a new JavaScript string is intended to be used as a property key, then for
3119+
some JavaScript engines it will be more efficient to use
3120+
the `node_api_create_property_key_utf16` function.
3121+
Otherwise, use the `napi_create_string_utf16` or
3122+
`node_api_create_external_string_utf16` functions as there may be additional
3123+
overhead in creating/storing strings with this method.
3124+
3125+
The JavaScript `string` type is described in
3126+
[Section 6.1.4][] of the ECMAScript Language Specification.
3127+
30843128
### Functions to convert from Node-API to C types
30853129

30863130
#### `napi_get_array_length`

src/js_native_api.h

+7
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ node_api_create_external_string_utf16(napi_env env,
111111
napi_value* result,
112112
bool* copied);
113113
#endif // NAPI_EXPERIMENTAL
114+
115+
#ifdef NAPI_EXPERIMENTAL
116+
#define NODE_API_EXPERIMENTAL_HAS_PROPERTY_KEYS
117+
NAPI_EXTERN napi_status NAPI_CDECL node_api_create_property_key_utf16(
118+
napi_env env, const char16_t* str, size_t length, napi_value* result);
119+
#endif // NAPI_EXPERIMENTAL
120+
114121
NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env,
115122
napi_value description,
116123
napi_value* result);

src/js_native_api_v8.cc

+12
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,18 @@ napi_status NAPI_CDECL node_api_create_external_string_utf16(
17081708
});
17091709
}
17101710

1711+
napi_status NAPI_CDECL node_api_create_property_key_utf16(napi_env env,
1712+
const char16_t* str,
1713+
size_t length,
1714+
napi_value* result) {
1715+
return v8impl::NewString(env, str, length, result, [&](v8::Isolate* isolate) {
1716+
return v8::String::NewFromTwoByte(isolate,
1717+
reinterpret_cast<const uint16_t*>(str),
1718+
v8::NewStringType::kInternalized,
1719+
static_cast<int>(length));
1720+
});
1721+
}
1722+
17111723
napi_status NAPI_CDECL napi_create_double(napi_env env,
17121724
double value,
17131725
napi_value* result) {

test/js-native-api/test_string/test.js

+14
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ assert.strictEqual(test_string.TestLatin1External(empty), empty);
1616
assert.strictEqual(test_string.TestUtf16External(empty), empty);
1717
assert.strictEqual(test_string.TestLatin1ExternalAutoLength(empty), empty);
1818
assert.strictEqual(test_string.TestUtf16ExternalAutoLength(empty), empty);
19+
assert.strictEqual(test_string.TestPropertyKeyUtf16(empty), empty);
20+
assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(empty), empty);
1921
assert.strictEqual(test_string.Utf16Length(empty), 0);
2022
assert.strictEqual(test_string.Utf8Length(empty), 0);
2123

@@ -33,6 +35,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str1), str1);
3335
assert.strictEqual(test_string.TestLatin1Insufficient(str1), str1.slice(0, 3));
3436
assert.strictEqual(test_string.TestUtf8Insufficient(str1), str1.slice(0, 3));
3537
assert.strictEqual(test_string.TestUtf16Insufficient(str1), str1.slice(0, 3));
38+
assert.strictEqual(test_string.TestPropertyKeyUtf16(str1), str1);
39+
assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str1), str1);
3640
assert.strictEqual(test_string.Utf16Length(str1), 11);
3741
assert.strictEqual(test_string.Utf8Length(str1), 11);
3842

@@ -50,6 +54,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str2), str2);
5054
assert.strictEqual(test_string.TestLatin1Insufficient(str2), str2.slice(0, 3));
5155
assert.strictEqual(test_string.TestUtf8Insufficient(str2), str2.slice(0, 3));
5256
assert.strictEqual(test_string.TestUtf16Insufficient(str2), str2.slice(0, 3));
57+
assert.strictEqual(test_string.TestPropertyKeyUtf16(str2), str2);
58+
assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str2), str2);
5359
assert.strictEqual(test_string.Utf16Length(str2), 62);
5460
assert.strictEqual(test_string.Utf8Length(str2), 62);
5561

@@ -67,6 +73,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str3), str3);
6773
assert.strictEqual(test_string.TestLatin1Insufficient(str3), str3.slice(0, 3));
6874
assert.strictEqual(test_string.TestUtf8Insufficient(str3), str3.slice(0, 3));
6975
assert.strictEqual(test_string.TestUtf16Insufficient(str3), str3.slice(0, 3));
76+
assert.strictEqual(test_string.TestPropertyKeyUtf16(str3), str3);
77+
assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str3), str3);
7078
assert.strictEqual(test_string.Utf16Length(str3), 27);
7179
assert.strictEqual(test_string.Utf8Length(str3), 27);
7280

@@ -84,6 +92,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str4), str4);
8492
assert.strictEqual(test_string.TestLatin1Insufficient(str4), str4.slice(0, 3));
8593
assert.strictEqual(test_string.TestUtf8Insufficient(str4), str4.slice(0, 1));
8694
assert.strictEqual(test_string.TestUtf16Insufficient(str4), str4.slice(0, 3));
95+
assert.strictEqual(test_string.TestPropertyKeyUtf16(str4), str4);
96+
assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str4), str4);
8797
assert.strictEqual(test_string.Utf16Length(str4), 31);
8898
assert.strictEqual(test_string.Utf8Length(str4), 62);
8999

@@ -101,6 +111,8 @@ assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str5), str5);
101111
assert.strictEqual(test_string.TestLatin1Insufficient(str5), str5.slice(0, 3));
102112
assert.strictEqual(test_string.TestUtf8Insufficient(str5), str5.slice(0, 1));
103113
assert.strictEqual(test_string.TestUtf16Insufficient(str5), str5.slice(0, 3));
114+
assert.strictEqual(test_string.TestPropertyKeyUtf16(str5), str5);
115+
assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str5), str5);
104116
assert.strictEqual(test_string.Utf16Length(str5), 63);
105117
assert.strictEqual(test_string.Utf8Length(str5), 126);
106118

@@ -113,6 +125,8 @@ assert.strictEqual(test_string.TestUtf16External(str6), str6);
113125
assert.strictEqual(test_string.TestUtf16ExternalAutoLength(str6), str6);
114126
assert.strictEqual(test_string.TestUtf8Insufficient(str6), str6.slice(0, 1));
115127
assert.strictEqual(test_string.TestUtf16Insufficient(str6), str6.slice(0, 3));
128+
assert.strictEqual(test_string.TestPropertyKeyUtf16(str6), str6);
129+
assert.strictEqual(test_string.TestPropertyKeyUtf16AutoLength(str6), str6);
116130
assert.strictEqual(test_string.Utf16Length(str6), 5);
117131
assert.strictEqual(test_string.Utf8Length(str6), 14);
118132

test/js-native-api/test_string/test_string.c

+20
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,23 @@ static napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) {
294294
return output;
295295
}
296296

297+
static napi_value TestPropertyKeyUtf16(napi_env env, napi_callback_info info) {
298+
return TestTwoByteImpl(env,
299+
info,
300+
napi_get_value_string_utf16,
301+
node_api_create_property_key_utf16,
302+
actual_length);
303+
}
304+
305+
static napi_value TestPropertyKeyUtf16AutoLength(napi_env env,
306+
napi_callback_info info) {
307+
return TestTwoByteImpl(env,
308+
info,
309+
napi_get_value_string_utf16,
310+
node_api_create_property_key_utf16,
311+
auto_length);
312+
}
313+
297314
static napi_value Utf16Length(napi_env env, napi_callback_info info) {
298315
napi_value args[1];
299316
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) {
410427
DECLARE_NODE_API_PROPERTY("TestLargeLatin1", TestLargeLatin1),
411428
DECLARE_NODE_API_PROPERTY("TestLargeUtf16", TestLargeUtf16),
412429
DECLARE_NODE_API_PROPERTY("TestMemoryCorruption", TestMemoryCorruption),
430+
DECLARE_NODE_API_PROPERTY("TestPropertyKeyUtf16", TestPropertyKeyUtf16),
431+
DECLARE_NODE_API_PROPERTY("TestPropertyKeyUtf16AutoLength",
432+
TestPropertyKeyUtf16AutoLength),
413433
};
414434

415435
init_test_null(env, exports);

0 commit comments

Comments
 (0)