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 e7486d4

Browse filesBrowse files
Gabriel Schulhofaddaleax
andcommitted
n-api: support type-tagging objects
`napi_instanceof()` is insufficient for reliably establishing the data type to which a pointer stored with `napi_wrap()` or `napi_create_external()` inside a JavaScript object points. Thus, we need a way to "mark" an object with a value that, when later retrieved, can unambiguously tell us whether it is safe to cast the pointer stored inside it to a certain structure. Such a check must survive loading/unloading/multiple instances of an addon, so we use UUIDs chosen *a priori*. Fixes: #28164 Co-authored-by: Anna Henningsen <github@addaleax.net> PR-URL: #28237 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Signed-off-by: Gabriel Schulhof <gabriel.schulhof@intel.com>
1 parent 18e8687 commit e7486d4
Copy full SHA for e7486d4

File tree

Expand file treeCollapse file tree

14 files changed

+545
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

14 files changed

+545
-0
lines changed
Open diff view settings
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': [ '../type-tag/binding.c' ]
6+
}
7+
]
8+
}
Collapse file
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
const common = require('../../common.js');
3+
4+
let binding;
5+
try {
6+
binding = require(`./build/${common.buildType}/binding`);
7+
} catch {
8+
console.error(`${__filename}: Binding failed to load`);
9+
process.exit(0);
10+
}
11+
12+
const bench = common.createBenchmark(main, {
13+
n: [1e5, 1e6, 1e7],
14+
});
15+
16+
function main({ n }) {
17+
binding.checkObjectTag(n, bench, bench.start, bench.end);
18+
}
Collapse file

‎benchmark/napi/type-tag/binding.c‎

Copy file name to clipboard
+84Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#include <assert.h>
2+
#define NAPI_EXPERIMENTAL
3+
#include <node_api.h>
4+
5+
#define NAPI_CALL(call) \
6+
do { \
7+
napi_status status = call; \
8+
assert(status == napi_ok && #call " failed"); \
9+
} while (0);
10+
11+
#define EXPORT_FUNC(env, exports, name, func) \
12+
do { \
13+
napi_value js_func; \
14+
NAPI_CALL(napi_create_function((env), \
15+
(name), \
16+
NAPI_AUTO_LENGTH, \
17+
(func), \
18+
NULL, \
19+
&js_func)); \
20+
NAPI_CALL(napi_set_named_property((env), \
21+
(exports), \
22+
(name), \
23+
js_func)); \
24+
} while (0);
25+
26+
static const napi_type_tag tag = {
27+
0xe7ecbcd5954842f6, 0x9e75161c9bf27282
28+
};
29+
30+
static napi_value TagObject(napi_env env, napi_callback_info info) {
31+
size_t argc = 4;
32+
napi_value argv[4];
33+
uint32_t n;
34+
uint32_t index;
35+
napi_handle_scope scope;
36+
37+
NAPI_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
38+
NAPI_CALL(napi_get_value_uint32(env, argv[0], &n));
39+
NAPI_CALL(napi_open_handle_scope(env, &scope));
40+
napi_value objects[n];
41+
for (index = 0; index < n; index++) {
42+
NAPI_CALL(napi_create_object(env, &objects[index]));
43+
}
44+
45+
// Time the object tag creation.
46+
NAPI_CALL(napi_call_function(env, argv[1], argv[2], 0, NULL, NULL));
47+
for (index = 0; index < n; index++) {
48+
NAPI_CALL(napi_type_tag_object(env, objects[index], &tag));
49+
}
50+
NAPI_CALL(napi_call_function(env, argv[1], argv[3], 1, &argv[0], NULL));
51+
52+
NAPI_CALL(napi_close_handle_scope(env, scope));
53+
return NULL;
54+
}
55+
56+
static napi_value CheckObjectTag(napi_env env, napi_callback_info info) {
57+
size_t argc = 4;
58+
napi_value argv[4];
59+
uint32_t n;
60+
uint32_t index;
61+
bool is_of_type;
62+
63+
NAPI_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
64+
NAPI_CALL(napi_get_value_uint32(env, argv[0], &n));
65+
napi_value object;
66+
NAPI_CALL(napi_create_object(env, &object));
67+
NAPI_CALL(napi_type_tag_object(env, object, &tag));
68+
69+
// Time the object tag checking.
70+
NAPI_CALL(napi_call_function(env, argv[1], argv[2], 0, NULL, NULL));
71+
for (index = 0; index < n; index++) {
72+
NAPI_CALL(napi_check_object_type_tag(env, object, &tag, &is_of_type));
73+
assert(is_of_type && " type mismatch");
74+
}
75+
NAPI_CALL(napi_call_function(env, argv[1], argv[3], 1, &argv[0], NULL));
76+
77+
return NULL;
78+
}
79+
80+
NAPI_MODULE_INIT() {
81+
EXPORT_FUNC(env, exports, "tagObject", TagObject);
82+
EXPORT_FUNC(env, exports, "checkObjectTag", CheckObjectTag);
83+
return exports;
84+
}
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
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
const common = require('../../common.js');
3+
4+
let binding;
5+
try {
6+
binding = require(`./build/${common.buildType}/binding`);
7+
} catch {
8+
console.error(`${__filename}: Binding failed to load`);
9+
process.exit(0);
10+
}
11+
12+
const bench = common.createBenchmark(main, {
13+
n: [1e5, 1e6, 1e7],
14+
});
15+
16+
function main({ n }) {
17+
binding.checkObjectTag(n, bench, bench.start, bench.end);
18+
}
Collapse file

‎benchmark/napi/type-tag/index.js‎

Copy file name to clipboard
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
const common = require('../../common.js');
3+
4+
let binding;
5+
try {
6+
binding = require(`./build/${common.buildType}/binding`);
7+
} catch {
8+
console.error(`${__filename}: Binding failed to load`);
9+
process.exit(0);
10+
}
11+
12+
const bench = common.createBenchmark(main, {
13+
n: [1e3, 1e4, 1e5],
14+
});
15+
16+
function main({ n }) {
17+
binding.tagObject(n, bench, bench.start, bench.end);
18+
}

0 commit comments

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