mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
node-api: added SharedArrayBuffer api
PR-URL: https://github.com/nodejs/node/pull/59071 Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
parent
7c2cb67141
commit
f1a8f447d7
|
|
@ -3299,6 +3299,10 @@ Specification.
|
|||
<!-- YAML
|
||||
added: v8.0.0
|
||||
napiVersion: 1
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/59071
|
||||
description: Added support for `SharedArrayBuffer`.
|
||||
-->
|
||||
|
||||
```c
|
||||
|
|
@ -3309,21 +3313,20 @@ napi_status napi_get_arraybuffer_info(napi_env env,
|
|||
```
|
||||
|
||||
* `[in] env`: The environment that the API is invoked under.
|
||||
* `[in] arraybuffer`: `napi_value` representing the `ArrayBuffer` being queried.
|
||||
* `[out] data`: The underlying data buffer of the `ArrayBuffer`. If byte\_length
|
||||
* `[in] arraybuffer`: `napi_value` representing the `ArrayBuffer` or `SharedArrayBuffer` being queried.
|
||||
* `[out] data`: The underlying data buffer of the `ArrayBuffer` or `SharedArrayBuffer`
|
||||
is `0`, this may be `NULL` or any other pointer value.
|
||||
* `[out] byte_length`: Length in bytes of the underlying data buffer.
|
||||
|
||||
Returns `napi_ok` if the API succeeded.
|
||||
|
||||
This API is used to retrieve the underlying data buffer of an `ArrayBuffer` and
|
||||
its length.
|
||||
This API is used to retrieve the underlying data buffer of an `ArrayBuffer` or `SharedArrayBuffer` and its length.
|
||||
|
||||
_WARNING_: Use caution while using this API. The lifetime of the underlying data
|
||||
buffer is managed by the `ArrayBuffer` even after it's returned. A
|
||||
buffer is managed by the `ArrayBuffer` or `SharedArrayBuffer` even after it's returned. A
|
||||
possible safe way to use this API is in conjunction with
|
||||
[`napi_create_reference`][], which can be used to guarantee control over the
|
||||
lifetime of the `ArrayBuffer`. It's also safe to use the returned data buffer
|
||||
lifetime of the `ArrayBuffer` or `SharedArrayBuffer`. It's also safe to use the returned data buffer
|
||||
within the same callback as long as there are no calls to other APIs that might
|
||||
trigger a GC.
|
||||
|
||||
|
|
@ -4278,6 +4281,63 @@ This API represents the invocation of the `ArrayBuffer` `IsDetachedBuffer`
|
|||
operation as defined in [Section isDetachedBuffer][] of the ECMAScript Language
|
||||
Specification.
|
||||
|
||||
### `node_api_is_sharedarraybuffer`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
```c
|
||||
napi_status node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result)
|
||||
```
|
||||
|
||||
* `[in] env`: The environment that the API is invoked under.
|
||||
* `[in] value`: The JavaScript value to check.
|
||||
* `[out] result`: Whether the given `napi_value` represents a `SharedArrayBuffer`.
|
||||
|
||||
Returns `napi_ok` if the API succeeded.
|
||||
|
||||
This API checks if the Object passed in is a `SharedArrayBuffer`.
|
||||
|
||||
### `node_api_create_sharedarraybuffer`
|
||||
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
|
||||
> Stability: 1 - Experimental
|
||||
|
||||
```c
|
||||
napi_status node_api_create_sharedarraybuffer(napi_env env,
|
||||
size_t byte_length,
|
||||
void** data,
|
||||
napi_value* result)
|
||||
```
|
||||
|
||||
* `[in] env`: The environment that the API is invoked under.
|
||||
* `[in] byte_length`: The length in bytes of the shared array buffer to create.
|
||||
* `[out] data`: Pointer to the underlying byte buffer of the `SharedArrayBuffer`.
|
||||
`data` can optionally be ignored by passing `NULL`.
|
||||
* `[out] result`: A `napi_value` representing a JavaScript `SharedArrayBuffer`.
|
||||
|
||||
Returns `napi_ok` if the API succeeded.
|
||||
|
||||
This API returns a Node-API value corresponding to a JavaScript `SharedArrayBuffer`.
|
||||
`SharedArrayBuffer`s are used to represent fixed-length binary data buffers that
|
||||
can be shared across multiple workers.
|
||||
|
||||
The `SharedArrayBuffer` allocated will have an underlying byte buffer whose size is
|
||||
determined by the `byte_length` parameter that's passed in.
|
||||
The underlying buffer is optionally returned back to the caller in case the
|
||||
caller wants to directly manipulate the buffer. This buffer can only be
|
||||
written to directly from native code. To write to this buffer from JavaScript,
|
||||
a typed array or `DataView` object would need to be created.
|
||||
|
||||
JavaScript `SharedArrayBuffer` objects are described in
|
||||
[Section SharedArrayBuffer objects][] of the ECMAScript Language Specification.
|
||||
|
||||
## Working with JavaScript properties
|
||||
|
||||
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.
|
|||
[Section IsArray]: https://tc39.es/ecma262/#sec-isarray
|
||||
[Section IsStrctEqual]: https://tc39.es/ecma262/#sec-strict-equality-comparison
|
||||
[Section Promise objects]: https://tc39.es/ecma262/#sec-promise-objects
|
||||
[Section SharedArrayBuffer objects]: https://tc39.es/ecma262/#sec-sharedarraybuffer-objects
|
||||
[Section ToBoolean]: https://tc39.es/ecma262/#sec-toboolean
|
||||
[Section ToNumber]: https://tc39.es/ecma262/#sec-tonumber
|
||||
[Section ToObject]: https://tc39.es/ecma262/#sec-toobject
|
||||
|
|
|
|||
|
|
@ -486,6 +486,14 @@ napi_get_dataview_info(napi_env env,
|
|||
napi_value* arraybuffer,
|
||||
size_t* byte_offset);
|
||||
|
||||
#ifdef NAPI_EXPERIMENTAL
|
||||
#define NODE_API_EXPERIMENTAL_HAS_SHAREDARRAYBUFFER
|
||||
NAPI_EXTERN napi_status NAPI_CDECL
|
||||
node_api_is_sharedarraybuffer(napi_env env, napi_value value, bool* result);
|
||||
NAPI_EXTERN napi_status NAPI_CDECL node_api_create_sharedarraybuffer(
|
||||
napi_env env, size_t byte_length, void** data, napi_value* result);
|
||||
#endif // NAPI_EXPERIMENTAL
|
||||
|
||||
// version management
|
||||
NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env,
|
||||
uint32_t* result);
|
||||
|
|
|
|||
|
|
@ -3077,21 +3077,68 @@ napi_status NAPI_CDECL napi_get_arraybuffer_info(napi_env env,
|
|||
CHECK_ARG(env, arraybuffer);
|
||||
|
||||
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
|
||||
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
|
||||
|
||||
v8::Local<v8::ArrayBuffer> ab = value.As<v8::ArrayBuffer>();
|
||||
if (value->IsArrayBuffer()) {
|
||||
v8::Local<v8::ArrayBuffer> ab = value.As<v8::ArrayBuffer>();
|
||||
|
||||
if (data != nullptr) {
|
||||
*data = ab->Data();
|
||||
}
|
||||
if (data != nullptr) {
|
||||
*data = ab->Data();
|
||||
}
|
||||
|
||||
if (byte_length != nullptr) {
|
||||
*byte_length = ab->ByteLength();
|
||||
if (byte_length != nullptr) {
|
||||
*byte_length = ab->ByteLength();
|
||||
}
|
||||
} else if (value->IsSharedArrayBuffer()) {
|
||||
v8::Local<v8::SharedArrayBuffer> sab = value.As<v8::SharedArrayBuffer>();
|
||||
|
||||
if (data != nullptr) {
|
||||
*data = sab->Data();
|
||||
}
|
||||
|
||||
if (byte_length != nullptr) {
|
||||
*byte_length = sab->ByteLength();
|
||||
}
|
||||
} else {
|
||||
return napi_set_last_error(env, napi_invalid_arg);
|
||||
}
|
||||
|
||||
return napi_clear_last_error(env);
|
||||
}
|
||||
|
||||
napi_status NAPI_CDECL node_api_is_sharedarraybuffer(napi_env env,
|
||||
napi_value value,
|
||||
bool* result) {
|
||||
CHECK_ENV_NOT_IN_GC(env);
|
||||
CHECK_ARG(env, value);
|
||||
CHECK_ARG(env, result);
|
||||
|
||||
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
|
||||
*result = val->IsSharedArrayBuffer();
|
||||
|
||||
return napi_clear_last_error(env);
|
||||
}
|
||||
|
||||
napi_status NAPI_CDECL node_api_create_sharedarraybuffer(napi_env env,
|
||||
size_t byte_length,
|
||||
void** data,
|
||||
napi_value* result) {
|
||||
NAPI_PREAMBLE(env);
|
||||
CHECK_ARG(env, result);
|
||||
|
||||
v8::Isolate* isolate = env->isolate;
|
||||
v8::Local<v8::SharedArrayBuffer> buffer =
|
||||
v8::SharedArrayBuffer::New(isolate, byte_length);
|
||||
|
||||
// Optionally return a pointer to the buffer's data, to avoid another call to
|
||||
// retrieve it.
|
||||
if (data != nullptr) {
|
||||
*data = buffer->Data();
|
||||
}
|
||||
|
||||
*result = v8impl::JsValueFromV8LocalValue(buffer);
|
||||
return GET_RETURN_STATUS(env);
|
||||
}
|
||||
|
||||
napi_status NAPI_CDECL napi_is_typedarray(napi_env env,
|
||||
napi_value value,
|
||||
bool* result) {
|
||||
|
|
|
|||
8
test/js-native-api/test_sharedarraybuffer/binding.gyp
Normal file
8
test/js-native-api/test_sharedarraybuffer/binding.gyp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "test_sharedarraybuffer",
|
||||
"sources": [ "test_sharedarraybuffer.c" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
67
test/js-native-api/test_sharedarraybuffer/test.js
Normal file
67
test/js-native-api/test_sharedarraybuffer/test.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../../common');
|
||||
const assert = require('assert');
|
||||
const test_sharedarraybuffer = require(`./build/${common.buildType}/test_sharedarraybuffer`);
|
||||
|
||||
{
|
||||
const sab = new SharedArrayBuffer(16);
|
||||
const ab = new ArrayBuffer(16);
|
||||
const obj = {};
|
||||
const arr = [];
|
||||
|
||||
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(sab), true);
|
||||
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(ab), false);
|
||||
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(obj), false);
|
||||
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(arr), false);
|
||||
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(null), false);
|
||||
assert.strictEqual(test_sharedarraybuffer.TestIsSharedArrayBuffer(undefined), false);
|
||||
}
|
||||
|
||||
// Test node_api_create_sharedarraybuffer
|
||||
{
|
||||
const sab = test_sharedarraybuffer.TestCreateSharedArrayBuffer(16);
|
||||
assert(sab instanceof SharedArrayBuffer);
|
||||
assert.strictEqual(sab.byteLength, 16);
|
||||
}
|
||||
|
||||
// Test node_api_create_get_sharedarraybuffer_info
|
||||
{
|
||||
const sab = new SharedArrayBuffer(32);
|
||||
const byteLength = test_sharedarraybuffer.TestGetSharedArrayBufferInfo(sab);
|
||||
assert.strictEqual(byteLength, 32);
|
||||
}
|
||||
|
||||
// Test data access
|
||||
{
|
||||
const sab = new SharedArrayBuffer(8);
|
||||
const result = test_sharedarraybuffer.TestSharedArrayBufferData(sab);
|
||||
assert.strictEqual(result, true);
|
||||
|
||||
// Check if data was written correctly
|
||||
const view = new Uint8Array(sab);
|
||||
for (let i = 0; i < 8; i++) {
|
||||
assert.strictEqual(view[i], i % 256);
|
||||
}
|
||||
}
|
||||
|
||||
// Test data pointer from existing SharedArrayBuffer
|
||||
{
|
||||
const sab = new SharedArrayBuffer(16);
|
||||
const result = test_sharedarraybuffer.TestSharedArrayBufferData(sab);
|
||||
assert.strictEqual(result, true);
|
||||
}
|
||||
|
||||
// Test zero-length SharedArrayBuffer
|
||||
{
|
||||
const sab = test_sharedarraybuffer.TestCreateSharedArrayBuffer(0);
|
||||
assert(sab instanceof SharedArrayBuffer);
|
||||
assert.strictEqual(sab.byteLength, 0);
|
||||
}
|
||||
|
||||
// Test invalid arguments
|
||||
{
|
||||
assert.throws(() => {
|
||||
test_sharedarraybuffer.TestGetSharedArrayBufferInfo({});
|
||||
}, { name: 'Error', message: 'Invalid argument' });
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
#define NAPI_EXPERIMENTAL
|
||||
#include <js_native_api.h>
|
||||
#include <string.h>
|
||||
#include "../common.h"
|
||||
#include "../entry_point.h"
|
||||
|
||||
static napi_value TestIsSharedArrayBuffer(napi_env env,
|
||||
napi_callback_info info) {
|
||||
size_t argc = 1;
|
||||
napi_value args[1];
|
||||
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
|
||||
|
||||
NODE_API_ASSERT(env, argc >= 1, "Wrong number of arguments");
|
||||
|
||||
bool is_sharedarraybuffer;
|
||||
NODE_API_CALL(
|
||||
env, node_api_is_sharedarraybuffer(env, args[0], &is_sharedarraybuffer));
|
||||
|
||||
napi_value ret;
|
||||
NODE_API_CALL(env, napi_get_boolean(env, is_sharedarraybuffer, &ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static napi_value TestCreateSharedArrayBuffer(napi_env env,
|
||||
napi_callback_info info) {
|
||||
size_t argc = 1;
|
||||
napi_value args[1];
|
||||
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
|
||||
|
||||
NODE_API_ASSERT(env, argc >= 1, "Wrong number of arguments");
|
||||
|
||||
napi_valuetype valuetype0;
|
||||
NODE_API_CALL(env, napi_typeof(env, args[0], &valuetype0));
|
||||
|
||||
NODE_API_ASSERT(
|
||||
env,
|
||||
valuetype0 == napi_number,
|
||||
"Wrong type of arguments. Expects a number as first argument.");
|
||||
|
||||
int32_t byte_length;
|
||||
NODE_API_CALL(env, napi_get_value_int32(env, args[0], &byte_length));
|
||||
|
||||
NODE_API_ASSERT(env,
|
||||
byte_length >= 0,
|
||||
"Invalid byte length. Expects a non-negative integer.");
|
||||
|
||||
napi_value ret;
|
||||
void* data;
|
||||
NODE_API_CALL(
|
||||
env, node_api_create_sharedarraybuffer(env, byte_length, &data, &ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static napi_value TestGetSharedArrayBufferInfo(napi_env env,
|
||||
napi_callback_info info) {
|
||||
size_t argc = 1;
|
||||
napi_value args[1];
|
||||
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
|
||||
|
||||
NODE_API_ASSERT(env, argc >= 1, "Wrong number of arguments");
|
||||
|
||||
void* data;
|
||||
size_t byte_length;
|
||||
NODE_API_CALL(env,
|
||||
napi_get_arraybuffer_info(env, args[0], &data, &byte_length));
|
||||
|
||||
napi_value ret;
|
||||
NODE_API_CALL(env, napi_create_uint32(env, byte_length, &ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void WriteTestDataToBuffer(void* data, size_t byte_length) {
|
||||
if (byte_length > 0 && data != NULL) {
|
||||
uint8_t* bytes = (uint8_t*)data;
|
||||
for (size_t i = 0; i < byte_length; i++) {
|
||||
bytes[i] = i % 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static napi_value TestSharedArrayBufferData(napi_env env,
|
||||
napi_callback_info info) {
|
||||
size_t argc = 1;
|
||||
napi_value args[1];
|
||||
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
|
||||
|
||||
NODE_API_ASSERT(env, argc >= 1, "Wrong number of arguments");
|
||||
|
||||
void* data;
|
||||
size_t byte_length;
|
||||
NODE_API_CALL(env,
|
||||
napi_get_arraybuffer_info(env, args[0], &data, &byte_length));
|
||||
|
||||
WriteTestDataToBuffer(data, byte_length);
|
||||
|
||||
// Return the same data pointer validity
|
||||
bool data_valid = (data != NULL) && (byte_length > 0);
|
||||
|
||||
napi_value ret;
|
||||
NODE_API_CALL(env, napi_get_boolean(env, data_valid, &ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXTERN_C_START
|
||||
napi_value Init(napi_env env, napi_value exports) {
|
||||
napi_property_descriptor descriptors[] = {
|
||||
DECLARE_NODE_API_PROPERTY("TestIsSharedArrayBuffer",
|
||||
TestIsSharedArrayBuffer),
|
||||
DECLARE_NODE_API_PROPERTY("TestCreateSharedArrayBuffer",
|
||||
TestCreateSharedArrayBuffer),
|
||||
DECLARE_NODE_API_PROPERTY("TestGetSharedArrayBufferInfo",
|
||||
TestGetSharedArrayBufferInfo),
|
||||
DECLARE_NODE_API_PROPERTY("TestSharedArrayBufferData",
|
||||
TestSharedArrayBufferData),
|
||||
};
|
||||
|
||||
NODE_API_CALL(
|
||||
env,
|
||||
napi_define_properties(env,
|
||||
exports,
|
||||
sizeof(descriptors) / sizeof(*descriptors),
|
||||
descriptors));
|
||||
|
||||
return exports;
|
||||
}
|
||||
EXTERN_C_END
|
||||
Loading…
Reference in New Issue
Block a user