GeezerVison is showing github.com — node-api: provide napi_define_properties fast path · nodejs/node@dbf9e9f
File treeExpand file treeCollapse file tree Open diff view settings benchmark/napi/define_properties
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: Makefile +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1422,6 +1422,7 @@ FORMAT_CPP_FILES ?= | 1422 | 1422 | FORMAT_CPP_FILES += $(LINT_CPP_FILES) | 1423 | 1423 | # C source codes. | 1424 | 1424 | FORMAT_CPP_FILES += $(wildcard \ | | 1425 | + benchmark/napi/*/*.c \ | 1425 | 1426 | test/js-native-api/*/*.c \ | 1426 | 1427 | test/js-native-api/*/*.h \ | 1427 | 1428 | test/node-api/*/*.c \ | |
Collapse file Copy file name to clipboard +1Lines changed: 1 addition & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +build/ |
Collapse file Copy file name to clipboard +104Lines changed: 104 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 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 Copy file name to clipboard +8Lines changed: 8 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +{ | | 2 | + 'targets': [ | | 3 | + { | | 4 | + 'target_name': 'binding', | | 5 | + 'sources': [ 'binding.c' ] | | 6 | + } | | 7 | + ] | | 8 | +} |
Collapse file Copy file name to clipboard +15Lines changed: 15 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 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 Copy file name to clipboardExpand all lines: src/js_native_api_v8.cc +20-9Lines changed: 20 additions & 9 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1369,16 +1369,27 @@ napi_define_properties(napi_env env, | 1369 | 1369 | } | 1370 | 1370 | } else { | 1371 | 1371 | 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 | + } | 1372 | 1391 |
| 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) { | 1382 | 1393 | return napi_set_last_error(env, napi_invalid_arg); | 1383 | 1394 | } | 1384 | 1395 | } | |
|