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 166c72e

Browse filesBrowse files
miguelmarcondesfaduh95
authored andcommitted
node-api: add napi_create_object_with_properties
PR-URL: #59953 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com>
1 parent 019af5b commit 166c72e
Copy full SHA for 166c72e

File tree

Expand file treeCollapse file tree

10 files changed

+343
-2
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

10 files changed

+343
-2
lines changed
Open diff view settings
Collapse file
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/
Collapse file
+116Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#include <assert.h>
2+
#include <node_api.h>
3+
#include <string>
4+
5+
struct BenchmarkParams {
6+
napi_value count_val;
7+
napi_value bench_obj;
8+
napi_value start_fn;
9+
napi_value end_fn;
10+
uint32_t count;
11+
};
12+
13+
static BenchmarkParams ParseBenchmarkArgs(napi_env env,
14+
const napi_callback_info info) {
15+
BenchmarkParams params;
16+
size_t argc = 4;
17+
napi_value args[4];
18+
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
19+
20+
params.count_val = args[0];
21+
params.bench_obj = args[1];
22+
params.start_fn = args[2];
23+
params.end_fn = args[3];
24+
25+
napi_get_value_uint32(env, params.count_val, &params.count);
26+
return params;
27+
}
28+
29+
static napi_value global_names[20];
30+
static napi_value global_values[20];
31+
static bool global_properties_initialized = false;
32+
33+
// Creating with many options because complains are when ~20 properties
34+
static void InitializeTestProperties(napi_env env) {
35+
if (global_properties_initialized) return;
36+
37+
for (int i = 0; i < 20; i++) {
38+
std::string name = "foo" + std::to_string(i);
39+
napi_create_string_utf8(
40+
env, name.c_str(), NAPI_AUTO_LENGTH, &global_names[i]);
41+
napi_create_string_utf8(
42+
env, name.c_str(), NAPI_AUTO_LENGTH, &global_values[i]);
43+
}
44+
global_properties_initialized = true;
45+
}
46+
47+
static napi_value CreateObjectWithPropertiesNew(napi_env env,
48+
napi_callback_info info) {
49+
BenchmarkParams params = ParseBenchmarkArgs(env, info);
50+
51+
InitializeTestProperties(env);
52+
53+
napi_value null_prototype;
54+
napi_get_null(env, &null_prototype);
55+
56+
napi_call_function(
57+
env, params.bench_obj, params.start_fn, 0, nullptr, nullptr);
58+
59+
for (uint32_t i = 0; i < params.count; i++) {
60+
napi_value obj;
61+
napi_create_object_with_properties(
62+
env, null_prototype, global_names, global_values, 20, &obj);
63+
}
64+
65+
napi_call_function(
66+
env, params.bench_obj, params.end_fn, 1, &params.count_val, nullptr);
67+
68+
return nullptr;
69+
}
70+
71+
static napi_value CreateObjectWithPropertiesOld(napi_env env,
72+
napi_callback_info info) {
73+
BenchmarkParams params = ParseBenchmarkArgs(env, info);
74+
75+
InitializeTestProperties(env);
76+
77+
napi_call_function(
78+
env, params.bench_obj, params.start_fn, 0, nullptr, nullptr);
79+
80+
for (uint32_t i = 0; i < params.count; i++) {
81+
napi_value obj;
82+
napi_create_object(env, &obj);
83+
for (int j = 0; j < 20; j++) {
84+
napi_set_property(env, obj, global_names[j], global_values[j]);
85+
}
86+
}
87+
88+
napi_call_function(
89+
env, params.bench_obj, params.end_fn, 1, &params.count_val, nullptr);
90+
91+
return nullptr;
92+
}
93+
94+
NAPI_MODULE_INIT() {
95+
napi_property_descriptor desc[] = {
96+
{"createObjectWithPropertiesNew",
97+
0,
98+
CreateObjectWithPropertiesNew,
99+
0,
100+
0,
101+
0,
102+
napi_default,
103+
0},
104+
{"createObjectWithPropertiesOld",
105+
0,
106+
CreateObjectWithPropertiesOld,
107+
0,
108+
0,
109+
0,
110+
napi_default,
111+
0},
112+
};
113+
114+
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
115+
return exports;
116+
}
Collapse file
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'sources': [ 'binding.cc' ],
6+
'defines': ['NAPI_EXPERIMENTAL']
7+
}
8+
]
9+
}
Collapse file
+24Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
3+
const common = require('../../common.js');
4+
5+
let binding;
6+
try {
7+
binding = require(`./build/${common.buildType}/binding`);
8+
} catch {
9+
console.error(`${__filename}: Binding failed to load`);
10+
process.exit(0);
11+
}
12+
13+
const bench = common.createBenchmark(main, {
14+
n: [1e2, 1e3, 1e4, 1e5, 1e6],
15+
method: ['new', 'old'],
16+
});
17+
18+
function main({ n, method }) {
19+
if (method === 'new') {
20+
binding.createObjectWithPropertiesNew(n, bench, bench.start, bench.end);
21+
} else {
22+
binding.createObjectWithPropertiesOld(n, bench, bench.start, bench.end);
23+
}
24+
}
Collapse file

‎doc/api/n-api.md‎

Copy file name to clipboardExpand all lines: doc/api/n-api.md
+37Lines changed: 37 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2637,6 +2637,43 @@ It is the equivalent of doing `new Object()` in JavaScript.
26372637
The JavaScript `Object` type is described in [Section object type][] of the
26382638
ECMAScript Language Specification.
26392639

2640+
#### `napi_create_object_with_properties`
2641+
2642+
<!-- YAML
2643+
added: REPLACEME
2644+
-->
2645+
2646+
> Stability: 1 - Experimental
2647+
2648+
```cpp
2649+
napi_status napi_create_object_with_properties(napi_env env,
2650+
napi_value prototype_or_null,
2651+
const napi_value* property_names,
2652+
const napi_value* property_values,
2653+
size_t property_count,
2654+
napi_value* result)
2655+
```
2656+
2657+
* `[in] env`: The environment that the API is invoked under.
2658+
* `[in] prototype_or_null`: The prototype object for the new object. Can be a
2659+
`napi_value` representing a JavaScript object to use as the prototype, a
2660+
`napi_value` representing JavaScript `null`, or a `nullptr` that will be converted to `null`.
2661+
* `[in] property_names`: Array of `napi_value` representing the property names.
2662+
* `[in] property_values`: Array of `napi_value` representing the property values.
2663+
* `[in] property_count`: Number of properties in the arrays.
2664+
* `[out] result`: A `napi_value` representing a JavaScript `Object`.
2665+
2666+
Returns `napi_ok` if the API succeeded.
2667+
2668+
This API creates a JavaScript `Object` with the specified prototype and
2669+
properties. This is more efficient than calling `napi_create_object` followed
2670+
by multiple `napi_set_property` calls, as it can create the object with all
2671+
properties atomically, avoiding potential V8 map transitions.
2672+
2673+
The arrays `property_names` and `property_values` must have the same length
2674+
specified by `property_count`. The properties are added to the object in the
2675+
order they appear in the arrays.
2676+
26402677
#### `napi_create_symbol`
26412678

26422679
<!-- YAML
Collapse file

‎src/js_native_api.h‎

Copy file name to clipboardExpand all lines: src/js_native_api.h
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env,
7878
// Methods to create Primitive types/Objects
7979
NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env,
8080
napi_value* result);
81+
#ifdef NAPI_EXPERIMENTAL
82+
#define NODE_API_EXPERIMENTAL_HAS_CREATE_OBJECT_WITH_PROPERTIES
83+
NAPI_EXTERN napi_status NAPI_CDECL
84+
napi_create_object_with_properties(napi_env env,
85+
napi_value prototype_or_null,
86+
napi_value* property_names,
87+
napi_value* property_values,
88+
size_t property_count,
89+
napi_value* result);
90+
#endif // NAPI_EXPERIMENTAL
91+
8192
NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env,
8293
napi_value* result);
8394
NAPI_EXTERN napi_status NAPI_CDECL
Collapse file

‎src/js_native_api_v8.cc‎

Copy file name to clipboardExpand all lines: src/js_native_api_v8.cc
+44Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,6 +1593,50 @@ napi_status NAPI_CDECL napi_create_object(napi_env env, napi_value* result) {
15931593
return napi_clear_last_error(env);
15941594
}
15951595

1596+
napi_status NAPI_CDECL
1597+
napi_create_object_with_properties(napi_env env,
1598+
napi_value prototype_or_null,
1599+
napi_value* property_names,
1600+
napi_value* property_values,
1601+
size_t property_count,
1602+
napi_value* result) {
1603+
CHECK_ENV_NOT_IN_GC(env);
1604+
CHECK_ARG(env, result);
1605+
1606+
if (property_count > 0) {
1607+
CHECK_ARG(env, property_names);
1608+
CHECK_ARG(env, property_values);
1609+
}
1610+
1611+
v8::Local<v8::Value> v8_prototype_or_null;
1612+
if (prototype_or_null == nullptr) {
1613+
v8_prototype_or_null = v8::Null(env->isolate);
1614+
} else {
1615+
v8_prototype_or_null = v8impl::V8LocalValueFromJsValue(prototype_or_null);
1616+
}
1617+
1618+
v8::LocalVector<v8::Name> v8_names(env->isolate, property_count);
1619+
v8::LocalVector<v8::Value> v8_values(env->isolate, property_count);
1620+
1621+
for (size_t i = 0; i < property_count; i++) {
1622+
v8::Local<v8::Value> name_value =
1623+
v8impl::V8LocalValueFromJsValue(property_names[i]);
1624+
RETURN_STATUS_IF_FALSE(env, name_value->IsName(), napi_name_expected);
1625+
v8_names[i] = name_value.As<v8::Name>();
1626+
v8_values[i] = v8impl::V8LocalValueFromJsValue(property_values[i]);
1627+
}
1628+
1629+
v8::Local<v8::Object> obj = v8::Object::New(env->isolate,
1630+
v8_prototype_or_null,
1631+
v8_names.data(),
1632+
v8_values.data(),
1633+
property_count);
1634+
1635+
RETURN_STATUS_IF_FALSE(env, !obj.IsEmpty(), napi_generic_failure);
1636+
*result = v8impl::JsValueFromV8LocalValue(obj);
1637+
return napi_clear_last_error(env);
1638+
}
1639+
15961640
napi_status NAPI_CDECL napi_create_array(napi_env env, napi_value* result) {
15971641
CHECK_ENV_NOT_IN_GC(env);
15981642
CHECK_ARG(env, result);
Collapse file

‎test/js-native-api/test_object/binding.gyp‎

Copy file name to clipboardExpand all lines: test/js-native-api/test_object/binding.gyp
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
"sources": [
66
"test_null.c",
77
"test_object.c"
8-
]
8+
],
9+
"defines": [
10+
"NAPI_EXPERIMENTAL"
11+
],
912
},
1013
{
1114
"target_name": "test_exceptions",
Collapse file

‎test/js-native-api/test_object/test.js‎

Copy file name to clipboardExpand all lines: test/js-native-api/test_object/test.js
+18-1Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const assert = require('assert');
55
// Testing api calls for objects
66
const test_object = require(`./build/${common.buildType}/test_object`);
77

8-
98
const object = {
109
hello: 'world',
1110
array: [
@@ -391,3 +390,21 @@ assert.deepStrictEqual(test_object.TestGetProperty(), {
391390
delete obj.x;
392391
}, /Cannot delete property 'x' of #<Object>/);
393392
}
393+
394+
{
395+
const objectWithProperties = test_object.TestCreateObjectWithProperties();
396+
assert.strictEqual(typeof objectWithProperties, 'object');
397+
assert.strictEqual(objectWithProperties.name, 'Foo');
398+
assert.strictEqual(objectWithProperties.age, 42);
399+
assert.strictEqual(objectWithProperties.active, true);
400+
401+
const emptyObject = test_object.TestCreateObjectWithPropertiesEmpty();
402+
assert.strictEqual(typeof emptyObject, 'object');
403+
assert.strictEqual(Object.keys(emptyObject).length, 0);
404+
405+
const objectWithCustomPrototype = test_object.TestCreateObjectWithCustomPrototype();
406+
assert.strictEqual(typeof objectWithCustomPrototype, 'object');
407+
assert.deepStrictEqual(Object.getOwnPropertyNames(objectWithCustomPrototype), ['value']);
408+
assert.strictEqual(objectWithCustomPrototype.value, 42);
409+
assert.strictEqual(typeof objectWithCustomPrototype.test, 'function');
410+
}

0 commit comments

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