Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit dbf9e9f

Browse filesBrowse files
gabrielschulhofRafaelGSS
authored andcommitted
node-api: provide napi_define_properties fast path
Implement defining properties via V8's `v8::Object::CreateDataProperty()`, which is faster for data-valued, writable, configurable, and enumerable properties. Re: #45905 Signed-off-by: Gabriel Schulhof <gabrielschulhof@gmail.com> PR-URL: #48440 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 38bf290 commit dbf9e9f
Copy full SHA for dbf9e9f

File tree

Expand file treeCollapse file tree

6 files changed

+149
-9
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

6 files changed

+149
-9
lines changed
Open diff view settings
Collapse file

‎Makefile‎

Copy file name to clipboardExpand all lines: Makefile
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,7 @@ FORMAT_CPP_FILES ?=
14221422
FORMAT_CPP_FILES += $(LINT_CPP_FILES)
14231423
# C source codes.
14241424
FORMAT_CPP_FILES += $(wildcard \
1425+
benchmark/napi/*/*.c \
14251426
test/js-native-api/*/*.c \
14261427
test/js-native-api/*/*.h \
14271428
test/node-api/*/*.c \
Collapse file
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/
Collapse file
+104Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <node_api.h>
2+
#include <stdio.h>
3+
#include <stdlib.h>
4+
5+
#define NODE_API_CALL(call) \
6+
do { \
7+
napi_status status = call; \
8+
if (status != napi_ok) { \
9+
fprintf(stderr, #call " failed: %d\n", status); \
10+
abort(); \
11+
} \
12+
} while (0)
13+
14+
#define ABORT_IF_FALSE(condition) \
15+
if (!(condition)) { \
16+
fprintf(stderr, #condition " failed\n"); \
17+
abort(); \
18+
}
19+
20+
static napi_value Runner(napi_env env,
21+
napi_callback_info info,
22+
napi_property_attributes attr) {
23+
napi_value argv[2], undefined, js_array_length, start, end;
24+
size_t argc = 2;
25+
napi_valuetype val_type = napi_undefined;
26+
bool is_array = false;
27+
uint32_t array_length = 0;
28+
napi_value* native_array;
29+
30+
// Validate params and retrieve start and end function.
31+
NODE_API_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
32+
ABORT_IF_FALSE(argc == 2);
33+
NODE_API_CALL(napi_typeof(env, argv[0], &val_type));
34+
ABORT_IF_FALSE(val_type == napi_object);
35+
NODE_API_CALL(napi_is_array(env, argv[1], &is_array));
36+
ABORT_IF_FALSE(is_array);
37+
NODE_API_CALL(napi_get_array_length(env, argv[1], &array_length));
38+
NODE_API_CALL(napi_get_named_property(env, argv[0], "start", &start));
39+
NODE_API_CALL(napi_typeof(env, start, &val_type));
40+
ABORT_IF_FALSE(val_type == napi_function);
41+
NODE_API_CALL(napi_get_named_property(env, argv[0], "end", &end));
42+
NODE_API_CALL(napi_typeof(env, end, &val_type));
43+
ABORT_IF_FALSE(val_type == napi_function);
44+
45+
NODE_API_CALL(napi_get_undefined(env, &undefined));
46+
NODE_API_CALL(napi_create_uint32(env, array_length, &js_array_length));
47+
48+
// Copy objects into a native array.
49+
native_array = malloc(array_length * sizeof(*native_array));
50+
for (uint32_t idx = 0; idx < array_length; idx++) {
51+
NODE_API_CALL(napi_get_element(env, argv[1], idx, &native_array[idx]));
52+
}
53+
54+
const napi_property_descriptor desc = {
55+
"prop", NULL, NULL, NULL, NULL, js_array_length, attr, NULL};
56+
57+
// Start the benchmark.
58+
napi_call_function(env, argv[0], start, 0, NULL, NULL);
59+
60+
for (uint32_t idx = 0; idx < array_length; idx++) {
61+
NODE_API_CALL(napi_define_properties(env, native_array[idx], 1, &desc));
62+
}
63+
64+
// Conclude the benchmark.
65+
NODE_API_CALL(
66+
napi_call_function(env, argv[0], end, 1, &js_array_length, NULL));
67+
68+
free(native_array);
69+
70+
return undefined;
71+
}
72+
73+
static napi_value RunFastPath(napi_env env, napi_callback_info info) {
74+
return Runner(env, info, napi_writable | napi_enumerable | napi_configurable);
75+
}
76+
77+
static napi_value RunSlowPath(napi_env env, napi_callback_info info) {
78+
return Runner(env, info, napi_writable | napi_enumerable);
79+
}
80+
81+
NAPI_MODULE_INIT() {
82+
napi_property_descriptor props[] = {
83+
{"runFastPath",
84+
NULL,
85+
RunFastPath,
86+
NULL,
87+
NULL,
88+
NULL,
89+
napi_writable | napi_configurable | napi_enumerable,
90+
NULL},
91+
{"runSlowPath",
92+
NULL,
93+
RunSlowPath,
94+
NULL,
95+
NULL,
96+
NULL,
97+
napi_writable | napi_configurable | napi_enumerable,
98+
NULL},
99+
};
100+
101+
NODE_API_CALL(napi_define_properties(
102+
env, exports, sizeof(props) / sizeof(*props), props));
103+
return exports;
104+
}
Collapse file
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'sources': [ 'binding.c' ]
6+
}
7+
]
8+
}
Collapse file
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
const common = require('../../common.js');
4+
5+
const binding = require(`./build/${common.buildType}/binding`);
6+
7+
const bench = common.createBenchmark(main, {
8+
n: [5e6],
9+
implem: ['runFastPath', 'runSlowPath'],
10+
});
11+
12+
function main({ n, implem }) {
13+
const objs = Array(n).fill(null).map((item) => new Object());
14+
binding[implem](bench, objs);
15+
}
Collapse file

‎src/js_native_api_v8.cc‎

Copy file name to clipboardExpand all lines: src/js_native_api_v8.cc
+20-9Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,16 +1369,27 @@ napi_define_properties(napi_env env,
13691369
}
13701370
} else {
13711371
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
1372+
bool defined_successfully = false;
1373+
1374+
if ((p->attributes & napi_enumerable) &&
1375+
(p->attributes & napi_writable) &&
1376+
(p->attributes & napi_configurable)) {
1377+
// Use a fast path for this type of data property.
1378+
auto define_maybe =
1379+
obj->CreateDataProperty(context, property_name, value);
1380+
defined_successfully = define_maybe.FromMaybe(false);
1381+
} else {
1382+
v8::PropertyDescriptor descriptor(value,
1383+
(p->attributes & napi_writable) != 0);
1384+
descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1385+
descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1386+
1387+
auto define_maybe =
1388+
obj->DefineProperty(context, property_name, descriptor);
1389+
defined_successfully = define_maybe.FromMaybe(false);
1390+
}
13721391

1373-
v8::PropertyDescriptor descriptor(value,
1374-
(p->attributes & napi_writable) != 0);
1375-
descriptor.set_enumerable((p->attributes & napi_enumerable) != 0);
1376-
descriptor.set_configurable((p->attributes & napi_configurable) != 0);
1377-
1378-
auto define_maybe =
1379-
obj->DefineProperty(context, property_name, descriptor);
1380-
1381-
if (!define_maybe.FromMaybe(false)) {
1392+
if (!defined_successfully) {
13821393
return napi_set_last_error(env, napi_invalid_arg);
13831394
}
13841395
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.