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 01090f2

Browse filesBrowse files
bnoordhuisaduh95
authored andcommitted
node-api: add napi_create_external_sharedarraybuffer
Creates a SharedArrayBuffer from externally managed memory. Fixes: #62259 PR-URL: #62623 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Reviewed-By: Robert Nagy <ronagy@icloud.com>
1 parent 87443b4 commit 01090f2
Copy full SHA for 01090f2

7 files changed

+132-2Lines changed: 132 additions & 2 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/n-api.md‎

Copy file name to clipboardExpand all lines: doc/api/n-api.md
+35Lines changed: 35 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2573,6 +2573,41 @@ object just created has been garbage collected.
25732573
JavaScript `ArrayBuffer`s are described in
25742574
[Section ArrayBuffer objects][] of the ECMAScript Language Specification.
25752575

2576+
#### `node_api_create_external_sharedarraybuffer`
2577+
2578+
<!-- YAML
2579+
added: REPLACEME
2580+
-->
2581+
2582+
```c
2583+
napi_status
2584+
node_api_create_external_sharedarraybuffer(napi_env env,
2585+
void* external_data,
2586+
size_t byte_length,
2587+
node_api_noenv_finalize finalize_cb,
2588+
void* finalize_hint,
2589+
napi_value* result)
2590+
```
2591+
2592+
* `[in] env`: The environment that the API is invoked under.
2593+
* `[in] external_data`: Pointer to the underlying byte buffer of the
2594+
`SharedArrayBuffer`.
2595+
* `[in] byte_length`: The length in bytes of the underlying buffer.
2596+
* `[in] finalize_cb`: Optional callback to call when the `SharedArrayBuffer` is
2597+
being collected. Called on an arbitrary thread. Because a `SharedArrayBuffer`
2598+
can outlive the environment it's created in, the callback does not receive a
2599+
reference to `env`.
2600+
* `[in] finalize_hint`: Optional hint to pass to the finalize callback during
2601+
collection.
2602+
* `[out] result`: A `napi_value` representing a JavaScript `SharedArrayBuffer`.
2603+
2604+
Returns `napi_ok` if the API succeeded.
2605+
2606+
Create a `SharedArrayBuffer` with externally managed memory.
2607+
2608+
See the entry on [`napi_create_external_arraybuffer`][] for runtime
2609+
compatibility.
2610+
25762611
#### `napi_create_external_buffer`
25772612

25782613
<!-- YAML
Collapse file

‎src/js_native_api.h‎

Copy file name to clipboardExpand all lines: src/js_native_api.h
+10Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,16 @@ napi_create_external_arraybuffer(napi_env env,
437437
node_api_basic_finalize finalize_cb,
438438
void* finalize_hint,
439439
napi_value* result);
440+
#ifdef NAPI_EXPERIMENTAL
441+
#define NODE_API_EXPERIMENTAL_HAS_CREATE_EXTERNAL_SHAREDARRAYBUFFER
442+
NAPI_EXTERN napi_status NAPI_CDECL
443+
node_api_create_external_sharedarraybuffer(napi_env env,
444+
void* external_data,
445+
size_t byte_length,
446+
node_api_noenv_finalize finalize_cb,
447+
void* finalize_hint,
448+
napi_value* result);
449+
#endif // NAPI_EXPERIMENTAL
440450
#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED
441451
NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info(
442452
napi_env env, napi_value arraybuffer, void** data, size_t* byte_length);
Collapse file

‎src/js_native_api_types.h‎

Copy file name to clipboardExpand all lines: src/js_native_api_types.h
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,10 @@ typedef void(NAPI_CDECL* node_api_nogc_finalize)(node_api_nogc_env env,
176176
#endif
177177
typedef node_api_nogc_finalize node_api_basic_finalize;
178178

179+
// A finalizer that can be called from any thread and at any time.
180+
typedef void(NAPI_CDECL* node_api_noenv_finalize)(void* finalize_data,
181+
void* finalize_hint);
182+
179183
typedef struct {
180184
// One of utf8name or name should be NULL.
181185
const char* utf8name;
Collapse file

‎src/js_native_api_v8.cc‎

Copy file name to clipboardExpand all lines: src/js_native_api_v8.cc
+42Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3134,6 +3134,48 @@ napi_create_external_arraybuffer(napi_env env,
31343134
env, buffer, nullptr, nullptr, nullptr, result, nullptr);
31353135
}
31363136

3137+
napi_status NAPI_CDECL
3138+
node_api_create_external_sharedarraybuffer(napi_env env,
3139+
void* external_data,
3140+
size_t byte_length,
3141+
node_api_noenv_finalize finalize_cb,
3142+
void* finalize_hint,
3143+
napi_value* result) {
3144+
NAPI_PREAMBLE(env);
3145+
CHECK_ARG(env, result);
3146+
#ifdef V8_ENABLE_SANDBOX
3147+
return napi_set_last_error(env, napi_no_external_buffers_allowed);
3148+
#else
3149+
struct FinalizerData {
3150+
void (*cb)(void* external_data, void* finalize_hint);
3151+
void* hint;
3152+
};
3153+
auto deleter = [](void* external_data, size_t length, void* deleter_data) {
3154+
if (auto fd = static_cast<FinalizerData*>(deleter_data)) {
3155+
fd->cb(external_data, fd->hint);
3156+
delete fd;
3157+
}
3158+
};
3159+
FinalizerData* deleter_data = nullptr;
3160+
if (finalize_cb != nullptr) {
3161+
deleter_data = new FinalizerData{finalize_cb, finalize_hint};
3162+
}
3163+
auto unique_backing_store = v8::SharedArrayBuffer::NewBackingStore(
3164+
external_data,
3165+
byte_length,
3166+
deleter,
3167+
reinterpret_cast<void*>(deleter_data));
3168+
CHECK(!!unique_backing_store); // Cannot fail.
3169+
auto shared_backing_store =
3170+
std::shared_ptr<v8::BackingStore>(std::move(unique_backing_store));
3171+
auto shared_array_buffer =
3172+
v8::SharedArrayBuffer::New(env->isolate, std::move(shared_backing_store));
3173+
CHECK_MAYBE_EMPTY(env, shared_array_buffer, napi_generic_failure);
3174+
*result = v8impl::JsValueFromV8LocalValue(shared_array_buffer);
3175+
return napi_clear_last_error(env);
3176+
#endif // V8_ENABLE_SANDBOX
3177+
}
3178+
31373179
napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env,
31383180
napi_value arraybuffer,
31393181
void** data,
Collapse file

‎test/node-api/test_buffer/binding.gyp‎

Copy file name to clipboardExpand all lines: test/node-api/test_buffer/binding.gyp
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
{
44
"target_name": "test_buffer",
55
"defines": [
6-
'NAPI_VERSION=10'
6+
"NAPI_EXPERIMENTAL",
7+
"NODE_API_EXPERIMENTAL_NO_WARNING"
78
],
89
"sources": [ "test_buffer.c" ]
910
},
Collapse file

‎test/node-api/test_buffer/test.js‎

Copy file name to clipboardExpand all lines: test/node-api/test_buffer/test.js
+13-1Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
const common = require('../../common');
55
const binding = require(`./build/${common.buildType}/test_buffer`);
66
const assert = require('assert');
7-
const tick = require('util').promisify(require('../../common/tick'));
7+
const util = require('util');
8+
const tick = util.promisify(require('../../common/tick'));
89

910
(async function() {
1011
assert.strictEqual(binding.newBuffer().toString(), binding.theText);
@@ -26,6 +27,17 @@ const tick = require('util').promisify(require('../../common/tick'));
2627
console.log('gc2');
2728
assert.strictEqual(binding.getDeleterCallCount(), 2);
2829

30+
// Caveat emptor: it's indeterminate when the SharedArrayBuffer's backing
31+
// store is reclaimed; at least some of the time it happens even before
32+
// calling gc().
33+
let sab = binding.newExternalSharedArrayBuffer();
34+
assert(util.types.isSharedArrayBuffer(sab));
35+
sab = null;
36+
global.gc();
37+
await tick(10);
38+
console.log('gc3');
39+
assert.strictEqual(binding.getDeleterCallCount(), 3);
40+
2941
// To test this doesn't crash
3042
binding.invalidObjectAsBuffer({});
3143

Collapse file

‎test/node-api/test_buffer/test_buffer.c‎

Copy file name to clipboardExpand all lines: test/node-api/test_buffer/test_buffer.c
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,30 @@ static napi_value newExternalBuffer(napi_env env, napi_callback_info info) {
5858
return theBuffer;
5959
}
6060

61+
static char externalSharedArrayBufferData[1];
62+
63+
static void freeExternalSharedArrayBuffer(void* data, void* hint) {
64+
(void)hint;
65+
NODE_API_BASIC_ASSERT_RETURN_VOID(
66+
data == (void*)externalSharedArrayBufferData,
67+
"SharedArrayBuffer points to wrong data");
68+
deleterCallCount++;
69+
}
70+
71+
static napi_value newExternalSharedArrayBuffer(napi_env env,
72+
napi_callback_info info) {
73+
napi_value sab;
74+
NODE_API_CALL(
75+
env,
76+
node_api_create_external_sharedarraybuffer(env,
77+
externalSharedArrayBufferData,
78+
1,
79+
freeExternalSharedArrayBuffer,
80+
NULL,
81+
&sab));
82+
return sab;
83+
}
84+
6185
static napi_value getDeleterCallCount(napi_env env, napi_callback_info info) {
6286
napi_value callCount;
6387
NODE_API_CALL(env, napi_create_int32(env, deleterCallCount, &callCount));
@@ -171,6 +195,8 @@ static napi_value Init(napi_env env, napi_value exports) {
171195
napi_property_descriptor methods[] = {
172196
DECLARE_NODE_API_PROPERTY("newBuffer", newBuffer),
173197
DECLARE_NODE_API_PROPERTY("newExternalBuffer", newExternalBuffer),
198+
DECLARE_NODE_API_PROPERTY("newExternalSharedArrayBuffer",
199+
newExternalSharedArrayBuffer),
174200
DECLARE_NODE_API_PROPERTY("getDeleterCallCount", getDeleterCallCount),
175201
DECLARE_NODE_API_PROPERTY("copyBuffer", copyBuffer),
176202
DECLARE_NODE_API_PROPERTY("bufferHasInstance", bufferHasInstance),

0 commit comments

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