Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Commit 3909ff2

Browse files
umuoy1juanarbol
authored andcommitted
node-api: support SharedArrayBuffer in napi_create_typedarray
Signed-off-by: umuoy1 <burningdian@gmail.com> PR-URL: #62710 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: Vladimir Morozov <vmorozov@microsoft.com> Signed-off-by: Juan JosΓ© Arboleda <soyjuanarbol@gmail.com>
1 parent fdc65e4 commit 3909ff2

5 files changed

Lines changed: 273 additions & 63 deletions

File tree

β€Ždoc/api/n-api.mdβ€Ž

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ Language Specification.
27342734
<!-- YAML
27352735
added: v8.0.0
27362736
napiVersion: 1
2737+
changes:
2738+
- version: REPLACEME
2739+
pr-url: https://github.com/nodejs/node/pull/62710
2740+
description: Added support for `SharedArrayBuffer`.
27372741
-->
27382742

27392743
```c
@@ -2748,21 +2752,25 @@ napi_status napi_create_typedarray(napi_env env,
27482752
* `[in] env`: The environment that the API is invoked under.
27492753
* `[in] type`: Scalar datatype of the elements within the `TypedArray`.
27502754
* `[in] length`: Number of elements in the `TypedArray`.
2751-
* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array.
2752-
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to
2753-
start projecting the `TypedArray`.
2755+
* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the
2756+
typed array.
2757+
* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or
2758+
`SharedArrayBuffer` from which to start projecting the `TypedArray`.
27542759
* `[out] result`: A `napi_value` representing a JavaScript `TypedArray`.
27552760

27562761
Returns `napi_ok` if the API succeeded.
27572762

27582763
This API creates a JavaScript `TypedArray` object over an existing
2759-
`ArrayBuffer`. `TypedArray` objects provide an array-like view over an
2760-
underlying data buffer where each element has the same underlying binary scalar
2761-
datatype.
2764+
`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an
2765+
array-like view over an underlying data buffer where each element has the same
2766+
underlying binary scalar datatype.
2767+
2768+
It is required that `(length * size_of_element) + byte_offset` is less than or
2769+
equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed
2770+
in. If not, a `RangeError` exception is raised.
27622771

2763-
It's required that `(length * size_of_element) + byte_offset` should
2764-
be <= the size in bytes of the array passed in. If not, a `RangeError` exception
2765-
is raised.
2772+
For element sizes greater than 1, `byte_offset` is required to be a multiple
2773+
of the element size. If not, a `RangeError` exception is raised.
27662774

27672775
JavaScript `TypedArray` objects are described in
27682776
[Section TypedArray objects][] of the ECMAScript Language Specification.
@@ -3439,7 +3447,8 @@ napi_status napi_get_typedarray_info(napi_env env,
34393447
the `byte_offset` value so that it points to the first element in the
34403448
`TypedArray`. If the length of the array is `0`, this may be `NULL` or
34413449
any other pointer value.
3442-
* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`.
3450+
* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the
3451+
`TypedArray`.
34433452
* `[out] byte_offset`: The byte offset within the underlying native array
34443453
at which the first element of the arrays is located. The value for the data
34453454
parameter has already been adjusted so that data points to the first element

β€Žsrc/js_native_api_v8.ccβ€Ž

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,62 +3204,69 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env,
32043204
CHECK_ARG(env, result);
32053205

32063206
v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
3207-
RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
3207+
auto create_typedarray = [&](auto buffer) -> napi_status {
3208+
v8::Local<v8::TypedArray> typedArray;
3209+
3210+
switch (type) {
3211+
case napi_int8_array:
3212+
CREATE_TYPED_ARRAY(
3213+
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3214+
break;
3215+
case napi_uint8_array:
3216+
CREATE_TYPED_ARRAY(
3217+
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3218+
break;
3219+
case napi_uint8_clamped_array:
3220+
CREATE_TYPED_ARRAY(
3221+
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3222+
break;
3223+
case napi_int16_array:
3224+
CREATE_TYPED_ARRAY(
3225+
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3226+
break;
3227+
case napi_uint16_array:
3228+
CREATE_TYPED_ARRAY(
3229+
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3230+
break;
3231+
case napi_int32_array:
3232+
CREATE_TYPED_ARRAY(
3233+
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3234+
break;
3235+
case napi_uint32_array:
3236+
CREATE_TYPED_ARRAY(
3237+
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3238+
break;
3239+
case napi_float32_array:
3240+
CREATE_TYPED_ARRAY(
3241+
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3242+
break;
3243+
case napi_float64_array:
3244+
CREATE_TYPED_ARRAY(
3245+
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3246+
break;
3247+
case napi_bigint64_array:
3248+
CREATE_TYPED_ARRAY(
3249+
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3250+
break;
3251+
case napi_biguint64_array:
3252+
CREATE_TYPED_ARRAY(
3253+
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3254+
break;
3255+
default:
3256+
returnnapi_set_last_error(env, napi_invalid_arg);
3257+
}
32083258

3209-
v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
3210-
v8::Local<v8::TypedArray> typedArray;
3259+
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3260+
returnGET_RETURN_STATUS(env);
3261+
};
32113262

3212-
switch (type) {
3213-
case napi_int8_array:
3214-
CREATE_TYPED_ARRAY(
3215-
env, Int8Array, 1, buffer, byte_offset, length, typedArray);
3216-
break;
3217-
case napi_uint8_array:
3218-
CREATE_TYPED_ARRAY(
3219-
env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
3220-
break;
3221-
case napi_uint8_clamped_array:
3222-
CREATE_TYPED_ARRAY(
3223-
env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
3224-
break;
3225-
case napi_int16_array:
3226-
CREATE_TYPED_ARRAY(
3227-
env, Int16Array, 2, buffer, byte_offset, length, typedArray);
3228-
break;
3229-
case napi_uint16_array:
3230-
CREATE_TYPED_ARRAY(
3231-
env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
3232-
break;
3233-
case napi_int32_array:
3234-
CREATE_TYPED_ARRAY(
3235-
env, Int32Array, 4, buffer, byte_offset, length, typedArray);
3236-
break;
3237-
case napi_uint32_array:
3238-
CREATE_TYPED_ARRAY(
3239-
env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
3240-
break;
3241-
case napi_float32_array:
3242-
CREATE_TYPED_ARRAY(
3243-
env, Float32Array, 4, buffer, byte_offset, length, typedArray);
3244-
break;
3245-
case napi_float64_array:
3246-
CREATE_TYPED_ARRAY(
3247-
env, Float64Array, 8, buffer, byte_offset, length, typedArray);
3248-
break;
3249-
case napi_bigint64_array:
3250-
CREATE_TYPED_ARRAY(
3251-
env, BigInt64Array, 8, buffer, byte_offset, length, typedArray);
3252-
break;
3253-
case napi_biguint64_array:
3254-
CREATE_TYPED_ARRAY(
3255-
env, BigUint64Array, 8, buffer, byte_offset, length, typedArray);
3256-
break;
3257-
default:
3258-
returnnapi_set_last_error(env, napi_invalid_arg);
3263+
if (value->IsArrayBuffer()) {
3264+
returncreate_typedarray(value.As<v8::ArrayBuffer>());
3265+
} elseif (value->IsSharedArrayBuffer()) {
3266+
returncreate_typedarray(value.As<v8::SharedArrayBuffer>());
3267+
} else {
3268+
returnnapi_set_last_error(env, napi_invalid_arg);
32593269
}
3260-
3261-
*result = v8impl::JsValueFromV8LocalValue(typedArray);
3262-
returnGET_RETURN_STATUS(env);
32633270
}
32643271

32653272
napi_status NAPI_CDECLnapi_get_typedarray_info(napi_env env,

β€Žtest/js-native-api/test_typedarray/binding.gypβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
"sources": [
66
"test_typedarray.c"
77
]
8+
},
9+
{
10+
"target_name": "test_typedarray_sharedarraybuffer",
11+
"sources": [
12+
"test_typedarray_sharedarraybuffer.c"
13+
]
814
}
915
]
1016
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
'use strict';
2+
3+
// Verify SharedArrayBuffer-backed typed arrays can be created through
4+
// napi_create_typedarray() while preserving existing ArrayBuffer behavior.
5+
6+
constcommon=require('../../common');
7+
constassert=require('assert');
8+
9+
consttest_typedarray_sharedarraybuffer=
10+
require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`);
11+
12+
consttypedArrayCases=[
13+
{type: Int8Array,values: [-1,0,127]},
14+
{type: Uint8Array,values: [1,2,255]},
15+
{type: Uint8ClampedArray,values: [0,128,255]},
16+
{type: Int16Array,values: [-1,0,32767]},
17+
{type: Uint16Array,values: [1,2,65535]},
18+
{type: Int32Array,values: [-1,0,123456789]},
19+
{type: Uint32Array,values: [1,2,4294967295]},
20+
{type: Float32Array,values: [0.5,-1.5,42.25]},
21+
{type: Float64Array,values: [0.5,-1.5,42.25]},
22+
{type: BigInt64Array,values: [1n,-2n,123456789n]},
23+
{type: BigUint64Array,values: [1n,2n,123456789n]},
24+
];
25+
26+
functioncreateBuffer(Type,BufferType,length){
27+
constbyteOffset=Type.BYTES_PER_ELEMENT;
28+
constbyteLength=byteOffset+(length*Type.BYTES_PER_ELEMENT);
29+
return{
30+
buffer: newBufferType(byteLength),
31+
byteOffset,
32+
};
33+
}
34+
35+
functioncreateTypedArray(Type,buffer,byteOffset,length){
36+
consttemplate=newType(buffer,byteOffset,length);
37+
returntest_typedarray_sharedarraybuffer.CreateTypedArray(template,buffer);
38+
}
39+
40+
functionverifyTypedArray(Type,buffer,byteOffset,values){
41+
consttheArray=createTypedArray(Type,buffer,byteOffset,values.length);
42+
consttheArrayBuffer=
43+
test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray);
44+
45+
assert.ok(theArrayinstanceofType);
46+
assert.strictEqual(theArray.buffer,buffer);
47+
assert.strictEqual(theArrayBuffer,buffer);
48+
assert.strictEqual(theArray.byteOffset,byteOffset);
49+
assert.strictEqual(theArray.length,values.length);
50+
51+
theArray.set(values);
52+
assert.deepStrictEqual(Array.from(newType(buffer,byteOffset,values.length)),
53+
values);
54+
}
55+
56+
// Keep the existing ArrayBuffer behavior covered while focusing this test
57+
// on SharedArrayBuffer-backed TypedArray creation.
58+
{
59+
const{ buffer, byteOffset }=createBuffer(Uint8Array,ArrayBuffer,3);
60+
verifyTypedArray(Uint8Array,buffer,byteOffset,[1,2,3]);
61+
}
62+
63+
// Verify all TypedArray variants can be created from SharedArrayBuffer.
64+
typedArrayCases.forEach(({ type, values })=>{
65+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
66+
values.length);
67+
verifyTypedArray(type,buffer,byteOffset,values);
68+
});
69+
70+
// Test for creating TypedArrays with SharedArrayBuffer and invalid range.
71+
for(const{ type, values }oftypedArrayCases){
72+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
73+
values.length);
74+
consttemplate=newtype(buffer,byteOffset,values.length);
75+
76+
assert.throws(()=>{
77+
test_typedarray_sharedarraybuffer.CreateTypedArray(
78+
template,buffer,values.length+1,byteOffset);
79+
},RangeError);
80+
}
81+
82+
// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment.
83+
for(const{ type, values }oftypedArrayCases){
84+
if(type.BYTES_PER_ELEMENT<=1){
85+
continue;
86+
}
87+
88+
const{ buffer, byteOffset }=createBuffer(type,SharedArrayBuffer,
89+
values.length);
90+
consttemplate=newtype(buffer,byteOffset,values.length);
91+
92+
assert.throws(()=>{
93+
test_typedarray_sharedarraybuffer.CreateTypedArray(
94+
template,buffer,1,byteOffset+1);
95+
},RangeError);
96+
}
97+
98+
// Test invalid arguments.
99+
{
100+
consttemplate=newUint8Array(1);
101+
102+
assert.throws(()=>{
103+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,{});
104+
},{name: 'Error',message: 'Invalid argument'});
105+
106+
assert.throws(()=>{
107+
test_typedarray_sharedarraybuffer.CreateTypedArray(template,1);
108+
},{name: 'Error',message: 'Invalid argument'});
109+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views
2+
// without changing its existing error handling.
3+
4+
#include<js_native_api.h>
5+
#include"../common.h"
6+
#include"../entry_point.h"
7+
8+
staticnapi_valueCreateTypedArray(napi_envenv, napi_callback_infoinfo) {
9+
size_targc=4;
10+
napi_valueargs[4];
11+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
12+
13+
NODE_API_ASSERT(env, argc==2||argc==4, "Wrong number of arguments");
14+
15+
boolis_typedarray;
16+
NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
17+
NODE_API_ASSERT(env,
18+
is_typedarray,
19+
"Wrong type of arguments. Expects a typed array as first "
20+
"argument.");
21+
22+
napi_typedarray_typetype;
23+
size_tlength;
24+
size_tbyte_offset;
25+
NODE_API_CALL(env,
26+
napi_get_typedarray_info(
27+
env, args[0], &type, &length, NULL, NULL, &byte_offset));
28+
29+
if (argc==4) {
30+
uint32_tuint32_length;
31+
NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length));
32+
length=uint32_length;
33+
34+
uint32_tuint32_byte_offset;
35+
NODE_API_CALL(env,
36+
napi_get_value_uint32(env, args[3], &uint32_byte_offset));
37+
byte_offset=uint32_byte_offset;
38+
}
39+
40+
napi_valuetypedarray;
41+
NODE_API_CALL(env,
42+
napi_create_typedarray(
43+
env, type, length, args[1], byte_offset, &typedarray));
44+
45+
returntypedarray;
46+
}
47+
48+
staticnapi_valueGetArrayBuffer(napi_envenv, napi_callback_infoinfo) {
49+
size_targc=1;
50+
napi_valueargs[1];
51+
NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
52+
53+
NODE_API_ASSERT(env, argc==1, "Wrong number of arguments");
54+
55+
napi_valuearraybuffer;
56+
NODE_API_CALL(env,
57+
napi_get_typedarray_info(
58+
env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
59+
60+
returnarraybuffer;
61+
}
62+
63+
EXTERN_C_START
64+
napi_valueInit(napi_envenv, napi_valueexports) {
65+
napi_property_descriptordescriptors[] = {
66+
DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray),
67+
DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer),
68+
};
69+
70+
NODE_API_CALL(
71+
env,
72+
napi_define_properties(env,
73+
exports,
74+
sizeof(descriptors) / sizeof(*descriptors),
75+
descriptors));
76+
77+
returnexports;
78+
}
79+
EXTERN_C_END

0 commit comments

Comments
Β (0)