Skip to content

Commit be48760

Browse files
mertcanaltintargos
authored andcommitted
node-api: added SharedArrayBuffer api
PR-URL: #59071 Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent 97c4e1b commit be48760

File tree

6 files changed

+334
-13
lines changed

6 files changed

+334
-13
lines changed

doc/api/n-api.md

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3299,6 +3299,10 @@ Specification.
32993299
<!-- YAML
33003300
added: v8.0.0
33013301
napiVersion: 1
3302+
changes:
3303+
- version: REPLACEME
3304+
pr-url: https://github.com/nodejs/node/pull/59071
3305+
description: Added support for `SharedArrayBuffer`.
33023306
-->
33033307

33043308
```c
@@ -3309,21 +3313,20 @@ napi_status napi_get_arraybuffer_info(napi_env env,
33093313
```
33103314

33113315
* `[in] env`: The environment that the API is invoked under.
3312-
* `[in] arraybuffer`: `napi_value` representing the `ArrayBuffer` being queried.
3313-
* `[out] data`: The underlying data buffer of the `ArrayBuffer`. If byte\_length
3316+
* `[in] arraybuffer`: `napi_value` representing the `ArrayBuffer` or `SharedArrayBuffer` being queried.
3317+
* `[out] data`: The underlying data buffer of the `ArrayBuffer` or `SharedArrayBuffer`
33143318
is `0`, this may be `NULL` or any other pointer value.
33153319
* `[out] byte_length`: Length in bytes of the underlying data buffer.
33163320

33173321
Returns `napi_ok` if the API succeeded.
33183322

3319-
This API is used to retrieve the underlying data buffer of an `ArrayBuffer` and
3320-
its length.
3323+
This API is used to retrieve the underlying data buffer of an `ArrayBuffer` or `SharedArrayBuffer` and its length.
33213324

33223325
_WARNING_: Use caution while using this API. The lifetime of the underlying data
3323-
buffer is managed by the `ArrayBuffer` even after it's returned. A
3326+
buffer is managed by the `ArrayBuffer` or `SharedArrayBuffer` even after it's returned. A
33243327
possible safe way to use this API is in conjunction with
33253328
[`napi_create_reference`][], which can be used to guarantee control over the
3326-
lifetime of the `ArrayBuffer`. It's also safe to use the returned data buffer
3329+
lifetime of the `ArrayBuffer` or `SharedArrayBuffer`. It's also safe to use the returned data buffer
33273330
within the same callback as long as there are no calls to other APIs that might
33283331
trigger a GC.
33293332

@@ -4278,6 +4281,63 @@ This API represents the invocation of the `ArrayBuffer` `IsDetachedBuffer`
42784281
operation as defined in [Section isDetachedBuffer][] of the ECMAScript Language
42794282
Specification.
42804283

4284+
### `node_api_is_sharedarraybuffer`
4285+
4286+
<!-- YAML
4287+
added: REPLACEME
4288+
-->
4289+
4290+
> Stability: 1 - Experimental
4291+
4292+
```c
4293+
napi_status node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result)
4294+
```
4295+
4296+
* `[in] env`: The environment that the API is invoked under.
4297+
* `[in] value`: The JavaScript value to check.
4298+
* `[out] result`: Whether the given `napi_value` represents a `SharedArrayBuffer`.
4299+
4300+
Returns `napi_ok` if the API succeeded.
4301+
4302+
This API checks if the Object passed in is a `SharedArrayBuffer`.
4303+
4304+
### `node_api_create_sharedarraybuffer`
4305+
4306+
<!-- YAML
4307+
added: REPLACEME
4308+
-->
4309+
4310+
> Stability: 1 - Experimental
4311+
4312+
```c
4313+
napi_status node_api_create_sharedarraybuffer(napi_env env,
4314+
size_t byte_length,
4315+
void** data,
4316+
napi_value* result)
4317+
```
4318+
4319+
* `[in] env`: The environment that the API is invoked under.
4320+
* `[in] byte_length`: The length in bytes of the shared array buffer to create.
4321+
* `[out] data`: Pointer to the underlying byte buffer of the `SharedArrayBuffer`.
4322+
`data` can optionally be ignored by passing `NULL`.
4323+
* `[out] result`: A `napi_value` representing a JavaScript `SharedArrayBuffer`.
4324+
4325+
Returns `napi_ok` if the API succeeded.
4326+
4327+
This API returns a Node-API value corresponding to a JavaScript `SharedArrayBuffer`.
4328+
`SharedArrayBuffer`s are used to represent fixed-length binary data buffers that
4329+
can be shared across multiple workers.
4330+
4331+
The `SharedArrayBuffer` allocated will have an underlying byte buffer whose size is
4332+
determined by the `byte_length` parameter that's passed in.
4333+
The underlying buffer is optionally returned back to the caller in case the
4334+
caller wants to directly manipulate the buffer. This buffer can only be
4335+
written to directly from native code. To write to this buffer from JavaScript,
4336+
a typed array or `DataView` object would need to be created.
4337+
4338+
JavaScript `SharedArrayBuffer` objects are described in
4339+
[Section SharedArrayBuffer objects][] of the ECMAScript Language Specification.
4340+
42814341
## Working with JavaScript properties
42824342

42834343
Node-API exposes a set of APIs to get and set properties on JavaScript
@@ -6791,6 +6851,7 @@ the add-on's file name during loading.
67916851
[Section IsArray]: https://tc39.es/ecma262/#sec-isarray
67926852
[Section IsStrctEqual]: https://tc39.es/ecma262/#sec-strict-equality-comparison
67936853
[Section Promise objects]: https://tc39.es/ecma262/#sec-promise-objects
6854+
[Section SharedArrayBuffer objects]: https://tc39.es/ecma262/#sec-sharedarraybuffer-objects
67946855
[Section ToBoolean]: https://tc39.es/ecma262/#sec-toboolean
67956856
[Section ToNumber]: https://tc39.es/ecma262/#sec-tonumber
67966857
[Section ToObject]: https://tc39.es/ecma262/#sec-toobject

src/js_native_api.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,14 @@ napi_get_dataview_info(napi_env env,
474474
napi_value* arraybuffer,
475475
size_t* byte_offset);
476476

477+
#ifdef NAPI_EXPERIMENTAL
478+
#define NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
479+
NAPI_EXTERN napi_status NAPI_CDECL
480+
node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result);
481+
NAPI_EXTERN napi_status NAPI_CDECL node_api_create_sharedarraybuffer(
482+
napi_env env, size_t byte_length, void** data, napi_value* result);
483+
#endif // NAPI_EXPERIMENTAL
484+
477485
// version management
478486
NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env,
479487
uint32_t* result);

src/js_native_api_v8.cc

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3077,21 +3077,68 @@ napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env,
30773077
CHECK_ARG(env, arraybuffer);
30783078

30793079
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3080-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
30813080

3082-
v8::Local<v8::ArrayBuffer> ab = value.As<v8::ArrayBuffer>();
3081+
if (value->IsArrayBuffer()) {
3082+
v8::Local<v8::ArrayBuffer> ab = value.As<v8::ArrayBuffer>();
30833083

3084-
if (data != nullptr) {
3085-
*data = ab->Data();
3086-
}
3084+
if (data != nullptr) {
3085+
*data = ab->Data();
3086+
}
30873087

3088-
if (byte_length != nullptr) {
3089-
*byte_length = ab->ByteLength();
3088+
if (byte_length != nullptr) {
3089+
*byte_length = ab->ByteLength();
3090+
}
3091+
} else if (value->IsSharedArrayBuffer()) {
3092+
v8::Local<v8::SharedArrayBuffer> sab = value.As<v8::SharedArrayBuffer>();
3093+
3094+
if (data != nullptr) {
3095+
*data = sab->Data();
3096+
}
3097+
3098+
if (byte_length != nullptr) {
3099+
*byte_length = sab->ByteLength();
3100+
}
3101+
} else {
3102+
return napi_set_last_error(env, napi_invalid_arg);
30903103
}
30913104

30923105
return napi_clear_last_error(env);
30933106
}
30943107

3108+
napi_status NAPI_CDECL node_api_is_sharedarraybuffer(napi_env env,
3109+
napi_value value,
3110+
bool* result) {
3111+
CHECK_ENV_NOT_IN_GC(env);
3112+
CHECK_ARG(env, value);
3113+
CHECK_ARG(env, result);
3114+
3115+
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
3116+
*result = val->IsSharedArrayBuffer();
3117+
3118+
return napi_clear_last_error(env);
3119+
}
3120+
3121+
napi_status NAPI_CDECL node_api_create_sharedarraybuffer(napi_env env,
3122+
size_t byte_length,
3123+
void** data,
3124+
napi_value* result) {
3125+
NAPI_PREAMBLE(env);
3126+
CHECK_ARG(env, result);
3127+
3128+
v8::Isolate* isolate = env->isolate;
3129+
v8::Local<v8::SharedArrayBuffer> buffer =
3130+
v8::SharedArrayBuffer::New(isolate, byte_length);
3131+
3132+
// Optionally return a pointer to the buffer's data, to avoid another call to
3133+
// retrieve it.
3134+
if (data != nullptr) {
3135+
*data = buffer->Data();
3136+
}
3137+
3138+
*result = v8impl::JsValueFromV8LocalValue(buffer);
3139+
return GET_RETURN_STATUS(env);
3140+
}
3141+
30953142
napi_status NAPI_CDECL napi_is_typedarray(napi_env env,
30963143
napi_value value,
30973144
bool* result) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "test_sharedarraybuffer",
5+
"sources": [ "test_sharedarraybuffer.c" ]
6+
}
7+
]
8+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const assert = require('assert');
5+
const test_sharedarraybuffer = require(`./build/${common.buildType}/test_sharedarraybuffer`);
6+
7+
{
8+
const sab = new SharedArrayBuffer(16);
9+
const ab = new ArrayBuffer(16);
10+
const obj = {};
11+
const arr = [];
12+
13+
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(sab), true);
14+
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(ab), false);
15+
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(obj), false);
16+
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(arr), false);
17+
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(null), false);
18+
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(undefined), false);
19+
}
20+
21+
// Test node_api_create_sharedarraybuffer
22+
{
23+
const sab = test_sharedarraybuffer.TestCreateSharedArrayBuffer(16);
24+
assert(sab instanceof SharedArrayBuffer);
25+
assert.strictEqual(sab.byteLength, 16);
26+
}
27+
28+
// Test node_api_create_get_sharedarraybuffer_info
29+
{
30+
const sab = new SharedArrayBuffer(32);
31+
const byteLength = test_sharedarraybuffer.TestGetSharedArrayBufferInfo(sab);
32+
assert.strictEqual(byteLength, 32);
33+
}
34+
35+
// Test data access
36+
{
37+
const sab = new SharedArrayBuffer(8);
38+
const result = test_sharedarraybuffer.TestSharedArrayBufferData(sab);
39+
assert.strictEqual(result, true);
40+
41+
// Check if data was written correctly
42+
const view = new Uint8Array(sab);
43+
for (let i = 0; i < 8; i++) {
44+
assert.strictEqual(view[i], i % 256);
45+
}
46+
}
47+
48+
// Test data pointer from existing SharedArrayBuffer
49+
{
50+
const sab = new SharedArrayBuffer(16);
51+
const result = test_sharedarraybuffer.TestSharedArrayBufferData(sab);
52+
assert.strictEqual(result, true);
53+
}
54+
55+
// Test zero-length SharedArrayBuffer
56+
{
57+
const sab = test_sharedarraybuffer.TestCreateSharedArrayBuffer(0);
58+
assert(sab instanceof SharedArrayBuffer);
59+
assert.strictEqual(sab.byteLength, 0);
60+
}
61+
62+
// Test invalid arguments
63+
{
64+
assert.throws(() => {
65+
test_sharedarraybuffer.TestGetSharedArrayBufferInfo({});
66+
}, { name: 'Error', message: 'Invalid argument' });
67+
}

0 commit comments

Comments
 (0)