From 983f644a85ed80af6827243518a6e5561b4a88d8 Mon Sep 17 00:00:00 2001 From: umuoy1 Date: Mon, 13 Apr 2026 00:16:50 +0800 Subject: [PATCH 1/3] node-api: support SharedArrayBuffer in napi_create_typedarray Signed-off-by: umuoy1 --- doc/api/n-api.md | 22 ++-- src/js_native_api_v8.cc | 121 +++++++++--------- .../binding.gyp | 10 ++ .../test_typedarray_sharedarraybuffer/test.js | 110 ++++++++++++++++ .../test_typedarray_sharedarraybuffer.c | 76 +++++++++++ 5 files changed, 272 insertions(+), 67 deletions(-) create mode 100644 test/js-native-api/test_typedarray_sharedarraybuffer/binding.gyp create mode 100644 test/js-native-api/test_typedarray_sharedarraybuffer/test.js create mode 100644 test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 269492b480fd20..561ca80b473425 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -2762,21 +2762,22 @@ napi_status napi_create_typedarray(napi_env env, * `[in] env`: The environment that the API is invoked under. * `[in] type`: Scalar datatype of the elements within the `TypedArray`. * `[in] length`: Number of elements in the `TypedArray`. -* `[in] arraybuffer`: `ArrayBuffer` underlying the typed array. -* `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to - start projecting the `TypedArray`. +* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the + typed array. +* `[in] byte_offset`: The byte offset within the `ArrayBuffer` or + `SharedArrayBuffer` from which to start projecting the `TypedArray`. * `[out] result`: A `napi_value` representing a JavaScript `TypedArray`. Returns `napi_ok` if the API succeeded. This API creates a JavaScript `TypedArray` object over an existing -`ArrayBuffer`. `TypedArray` objects provide an array-like view over an -underlying data buffer where each element has the same underlying binary scalar -datatype. +`ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an +array-like view over an underlying data buffer where each element has the same +underlying binary scalar datatype. -It's required that `(length * size_of_element) + byte_offset` should -be <= the size in bytes of the array passed in. If not, a `RangeError` exception -is raised. +It is required that `(length * size_of_element) + byte_offset` is less than or +equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed +in. If not, a `RangeError` exception is raised. JavaScript `TypedArray` objects are described in [Section TypedArray objects][] of the ECMAScript Language Specification. @@ -3469,7 +3470,8 @@ napi_status napi_get_typedarray_info(napi_env env, the `byte_offset` value so that it points to the first element in the `TypedArray`. If the length of the array is `0`, this may be `NULL` or any other pointer value. -* `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`. +* `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the + `TypedArray`. * `[out] byte_offset`: The byte offset within the underlying native array at which the first element of the arrays is located. The value for the data parameter has already been adjusted so that data points to the first element diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index a944c18518471a..aff61a2e7bceb9 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -3228,66 +3228,73 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env, CHECK_ARG(env, result); v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); + auto create_typedarray = [&](auto buffer) -> napi_status { + v8::Local typedArray; + + switch (type) { + case napi_int8_array: + CREATE_TYPED_ARRAY( + env, Int8Array, 1, buffer, byte_offset, length, typedArray); + break; + case napi_uint8_array: + CREATE_TYPED_ARRAY( + env, Uint8Array, 1, buffer, byte_offset, length, typedArray); + break; + case napi_uint8_clamped_array: + CREATE_TYPED_ARRAY( + env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray); + break; + case napi_int16_array: + CREATE_TYPED_ARRAY( + env, Int16Array, 2, buffer, byte_offset, length, typedArray); + break; + case napi_uint16_array: + CREATE_TYPED_ARRAY( + env, Uint16Array, 2, buffer, byte_offset, length, typedArray); + break; + case napi_int32_array: + CREATE_TYPED_ARRAY( + env, Int32Array, 4, buffer, byte_offset, length, typedArray); + break; + case napi_uint32_array: + CREATE_TYPED_ARRAY( + env, Uint32Array, 4, buffer, byte_offset, length, typedArray); + break; + case napi_float32_array: + CREATE_TYPED_ARRAY( + env, Float32Array, 4, buffer, byte_offset, length, typedArray); + break; + case napi_float64_array: + CREATE_TYPED_ARRAY( + env, Float64Array, 8, buffer, byte_offset, length, typedArray); + break; + case napi_bigint64_array: + CREATE_TYPED_ARRAY( + env, BigInt64Array, 8, buffer, byte_offset, length, typedArray); + break; + case napi_biguint64_array: + CREATE_TYPED_ARRAY( + env, BigUint64Array, 8, buffer, byte_offset, length, typedArray); + break; + case napi_float16_array: + CREATE_TYPED_ARRAY( + env, Float16Array, 2, buffer, byte_offset, length, typedArray); + break; + default: + return napi_set_last_error(env, napi_invalid_arg); + } - v8::Local buffer = value.As(); - v8::Local typedArray; + *result = v8impl::JsValueFromV8LocalValue(typedArray); + return GET_RETURN_STATUS(env); + }; - switch (type) { - case napi_int8_array: - CREATE_TYPED_ARRAY( - env, Int8Array, 1, buffer, byte_offset, length, typedArray); - break; - case napi_uint8_array: - CREATE_TYPED_ARRAY( - env, Uint8Array, 1, buffer, byte_offset, length, typedArray); - break; - case napi_uint8_clamped_array: - CREATE_TYPED_ARRAY( - env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray); - break; - case napi_int16_array: - CREATE_TYPED_ARRAY( - env, Int16Array, 2, buffer, byte_offset, length, typedArray); - break; - case napi_uint16_array: - CREATE_TYPED_ARRAY( - env, Uint16Array, 2, buffer, byte_offset, length, typedArray); - break; - case napi_int32_array: - CREATE_TYPED_ARRAY( - env, Int32Array, 4, buffer, byte_offset, length, typedArray); - break; - case napi_uint32_array: - CREATE_TYPED_ARRAY( - env, Uint32Array, 4, buffer, byte_offset, length, typedArray); - break; - case napi_float32_array: - CREATE_TYPED_ARRAY( - env, Float32Array, 4, buffer, byte_offset, length, typedArray); - break; - case napi_float64_array: - CREATE_TYPED_ARRAY( - env, Float64Array, 8, buffer, byte_offset, length, typedArray); - break; - case napi_bigint64_array: - CREATE_TYPED_ARRAY( - env, BigInt64Array, 8, buffer, byte_offset, length, typedArray); - break; - case napi_biguint64_array: - CREATE_TYPED_ARRAY( - env, BigUint64Array, 8, buffer, byte_offset, length, typedArray); - break; - case napi_float16_array: - CREATE_TYPED_ARRAY( - env, Float16Array, 2, buffer, byte_offset, length, typedArray); - break; - default: - return napi_set_last_error(env, napi_invalid_arg); + if (value->IsArrayBuffer()) { + return create_typedarray(value.As()); + } else if (value->IsSharedArrayBuffer()) { + return create_typedarray(value.As()); + } else { + return napi_set_last_error(env, napi_invalid_arg); } - - *result = v8impl::JsValueFromV8LocalValue(typedArray); - return GET_RETURN_STATUS(env); } napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env, diff --git a/test/js-native-api/test_typedarray_sharedarraybuffer/binding.gyp b/test/js-native-api/test_typedarray_sharedarraybuffer/binding.gyp new file mode 100644 index 00000000000000..a25f52bbafaba5 --- /dev/null +++ b/test/js-native-api/test_typedarray_sharedarraybuffer/binding.gyp @@ -0,0 +1,10 @@ +{ + "targets": [ + { + "target_name": "test_typedarray_sharedarraybuffer", + "sources": [ + "test_typedarray_sharedarraybuffer.c" + ] + } + ] +} diff --git a/test/js-native-api/test_typedarray_sharedarraybuffer/test.js b/test/js-native-api/test_typedarray_sharedarraybuffer/test.js new file mode 100644 index 00000000000000..d3af5197be37ee --- /dev/null +++ b/test/js-native-api/test_typedarray_sharedarraybuffer/test.js @@ -0,0 +1,110 @@ +'use strict'; + +// Verify SharedArrayBuffer-backed typed arrays can be created through +// napi_create_typedarray() while preserving existing ArrayBuffer behavior. + +const common = require('../../common'); +const assert = require('assert'); + +const test_typedarray_sharedarraybuffer = + require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`); + +// Test for creating Uint8Array with ArrayBuffer +{ + const buffer = new ArrayBuffer(16); + const theArray = + test_typedarray_sharedarraybuffer.CreateUint8Array(buffer, 4, 6); + const theArrayBuffer = + test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray); + + assert.ok(theArray instanceof Uint8Array); + assert.strictEqual(theArray.buffer, buffer); + assert.ok(theArrayBuffer instanceof ArrayBuffer); + assert.strictEqual(theArrayBuffer, buffer); + assert.strictEqual(theArray.byteOffset, 4); + assert.strictEqual(theArray.length, 6); + + theArray.set([1, 2, 3, 4, 5, 6]); + assert.deepStrictEqual(Array.from(new Uint8Array(buffer, 4, 6)), + [1, 2, 3, 4, 5, 6]); +} + +// Test for creating Uint8Array with SharedArrayBuffer +{ + const buffer = new SharedArrayBuffer(16); + const theArray = + test_typedarray_sharedarraybuffer.CreateUint8Array(buffer, 4, 6); + const theArrayBuffer = + test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray); + + assert.ok(theArray instanceof Uint8Array); + assert.strictEqual(theArray.buffer, buffer); + assert.ok(theArrayBuffer instanceof SharedArrayBuffer); + assert.strictEqual(theArrayBuffer, buffer); + assert.strictEqual(theArray.byteOffset, 4); + assert.strictEqual(theArray.length, 6); + + theArray.set([6, 5, 4, 3, 2, 1]); + assert.deepStrictEqual(Array.from(new Uint8Array(buffer, 4, 6)), + [6, 5, 4, 3, 2, 1]); +} + +// Test for creating Uint16Array with SharedArrayBuffer +{ + const buffer = new SharedArrayBuffer(24); + const theArray = + test_typedarray_sharedarraybuffer.CreateUint16Array(buffer, 4, 4); + + assert.ok(theArray instanceof Uint16Array); + assert.strictEqual(theArray.buffer, buffer); + assert.strictEqual(theArray.byteOffset, 4); + assert.strictEqual(theArray.length, 4); + + theArray.set([1, 2, 3, 65535]); + assert.deepStrictEqual(Array.from(new Uint16Array(buffer, 4, 4)), + [1, 2, 3, 65535]); +} + +// Test for creating Int32Array with SharedArrayBuffer +{ + const buffer = new SharedArrayBuffer(32); + const theArray = + test_typedarray_sharedarraybuffer.CreateInt32Array(buffer, 8, 3); + + assert.ok(theArray instanceof Int32Array); + assert.strictEqual(theArray.buffer, buffer); + assert.strictEqual(theArray.byteOffset, 8); + assert.strictEqual(theArray.length, 3); + + theArray.set([-1, 0, 123456789]); + assert.deepStrictEqual(Array.from(new Int32Array(buffer, 8, 3)), + [-1, 0, 123456789]); +} + +// Test for creating TypedArrays with SharedArrayBuffer and invalid range +{ + const buffer = new SharedArrayBuffer(8); + + assert.throws(() => { + test_typedarray_sharedarraybuffer.CreateUint8Array(buffer, 9, 0); + }, RangeError); + + assert.throws(() => { + test_typedarray_sharedarraybuffer.CreateUint16Array(buffer, 0, 5); + }, RangeError); + + assert.throws(() => { + test_typedarray_sharedarraybuffer.CreateUint16Array(buffer, 1, 1); + }, RangeError); +} + +// Test invalid arguments +{ + assert.throws(() => { + test_typedarray_sharedarraybuffer.CreateUint8Array({}, 0, 1); + }, { name: 'Error', message: 'Invalid argument' }); + + assert.throws(() => { + test_typedarray_sharedarraybuffer.CreateUint8Array(1, 0, 1); + }, { name: 'Error', message: 'Invalid argument' }); +} diff --git a/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c b/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c new file mode 100644 index 00000000000000..c76be8dd24571e --- /dev/null +++ b/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c @@ -0,0 +1,76 @@ +// Verify napi_create_typedarray() accepts SharedArrayBuffer-backed views +// without changing its existing error handling. + +#include +#include "../common.h" +#include "../entry_point.h" + +static napi_value CreateTypedArray(napi_env env, + napi_callback_info info, + napi_typedarray_type type) { + size_t argc = 3; + napi_value args[3]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NODE_API_ASSERT(env, argc == 3, "Wrong number of arguments"); + + uint32_t byte_offset; + NODE_API_CALL(env, napi_get_value_uint32(env, args[1], &byte_offset)); + + uint32_t length; + NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &length)); + + napi_value typedarray; + NODE_API_CALL(env, + napi_create_typedarray(env, + type, + length, + args[0], + byte_offset, + &typedarray)); + + return typedarray; +} + +static napi_value CreateUint8Array(napi_env env, napi_callback_info info) { + return CreateTypedArray(env, info, napi_uint8_array); +} + +static napi_value CreateUint16Array(napi_env env, napi_callback_info info) { + return CreateTypedArray(env, info, napi_uint16_array); +} + +static napi_value CreateInt32Array(napi_env env, napi_callback_info info) { + return CreateTypedArray(env, info, napi_int32_array); +} + +static napi_value GetArrayBuffer(napi_env env, napi_callback_info info) { + size_t argc = 1; + napi_value args[1]; + NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); + + NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments"); + + napi_value arraybuffer; + NODE_API_CALL( + env, + napi_get_typedarray_info(env, args[0], NULL, NULL, NULL, &arraybuffer, NULL)); + + return arraybuffer; +} + +EXTERN_C_START +napi_value Init(napi_env env, napi_value exports) { + napi_property_descriptor descriptors[] = { + DECLARE_NODE_API_PROPERTY("CreateUint8Array", CreateUint8Array), + DECLARE_NODE_API_PROPERTY("CreateUint16Array", CreateUint16Array), + DECLARE_NODE_API_PROPERTY("CreateInt32Array", CreateInt32Array), + DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer), + }; + + NODE_API_CALL(env, napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors)); + + return exports; +} +EXTERN_C_END From 265fa6fbc6b24c285f02ed78b66b9c5b37e2e732 Mon Sep 17 00:00:00 2001 From: umuoy1 Date: Mon, 13 Apr 2026 00:51:30 +0800 Subject: [PATCH 2/3] test: format SharedArrayBuffer typedarray addon test Signed-off-by: umuoy1 --- .../test_typedarray_sharedarraybuffer.c | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c b/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c index c76be8dd24571e..e7565b0a403859 100644 --- a/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c +++ b/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c @@ -22,12 +22,8 @@ static napi_value CreateTypedArray(napi_env env, napi_value typedarray; NODE_API_CALL(env, - napi_create_typedarray(env, - type, - length, - args[0], - byte_offset, - &typedarray)); + napi_create_typedarray( + env, type, length, args[0], byte_offset, &typedarray)); return typedarray; } @@ -52,9 +48,9 @@ static napi_value GetArrayBuffer(napi_env env, napi_callback_info info) { NODE_API_ASSERT(env, argc == 1, "Wrong number of arguments"); napi_value arraybuffer; - NODE_API_CALL( - env, - napi_get_typedarray_info(env, args[0], NULL, NULL, NULL, &arraybuffer, NULL)); + NODE_API_CALL(env, + napi_get_typedarray_info( + env, args[0], NULL, NULL, NULL, &arraybuffer, NULL)); return arraybuffer; } @@ -62,14 +58,18 @@ static napi_value GetArrayBuffer(napi_env env, napi_callback_info info) { EXTERN_C_START napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { - DECLARE_NODE_API_PROPERTY("CreateUint8Array", CreateUint8Array), - DECLARE_NODE_API_PROPERTY("CreateUint16Array", CreateUint16Array), - DECLARE_NODE_API_PROPERTY("CreateInt32Array", CreateInt32Array), - DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer), + DECLARE_NODE_API_PROPERTY("CreateUint8Array", CreateUint8Array), + DECLARE_NODE_API_PROPERTY("CreateUint16Array", CreateUint16Array), + DECLARE_NODE_API_PROPERTY("CreateInt32Array", CreateInt32Array), + DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer), }; - NODE_API_CALL(env, napi_define_properties( - env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors)); + NODE_API_CALL( + env, + napi_define_properties(env, + exports, + sizeof(descriptors) / sizeof(*descriptors), + descriptors)); return exports; } From df6d255d82dfe67f65af93677ba419a03f5de904 Mon Sep 17 00:00:00 2001 From: umuoy1 Date: Mon, 13 Apr 2026 18:32:18 +0800 Subject: [PATCH 3/3] doc,test: improve SharedArrayBuffer typedarray test and docs Signed-off-by: umuoy1 --- doc/api/n-api.md | 7 + .../test_typedarray_sharedarraybuffer/test.js | 136 +++++++++--------- .../test_typedarray_sharedarraybuffer.c | 55 +++---- 3 files changed, 104 insertions(+), 94 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 561ca80b473425..a42b18a1c31bbd 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -2748,6 +2748,10 @@ Language Specification. ```c @@ -2779,6 +2783,9 @@ It is required that `(length * size_of_element) + byte_offset` is less than or equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed in. If not, a `RangeError` exception is raised. +For element sizes greater than 1, `byte_offset` is required to be a multiple +of the element size. If not, a `RangeError` exception is raised. + JavaScript `TypedArray` objects are described in [Section TypedArray objects][] of the ECMAScript Language Specification. diff --git a/test/js-native-api/test_typedarray_sharedarraybuffer/test.js b/test/js-native-api/test_typedarray_sharedarraybuffer/test.js index d3af5197be37ee..95a39c033231c7 100644 --- a/test/js-native-api/test_typedarray_sharedarraybuffer/test.js +++ b/test/js-native-api/test_typedarray_sharedarraybuffer/test.js @@ -9,102 +9,102 @@ const assert = require('assert'); const test_typedarray_sharedarraybuffer = require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`); -// Test for creating Uint8Array with ArrayBuffer -{ - const buffer = new ArrayBuffer(16); - const theArray = - test_typedarray_sharedarraybuffer.CreateUint8Array(buffer, 4, 6); - const theArrayBuffer = - test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray); - - assert.ok(theArray instanceof Uint8Array); - assert.strictEqual(theArray.buffer, buffer); - assert.ok(theArrayBuffer instanceof ArrayBuffer); - assert.strictEqual(theArrayBuffer, buffer); - assert.strictEqual(theArray.byteOffset, 4); - assert.strictEqual(theArray.length, 6); +const typedArrayCases = [ + { type: Int8Array, values: [-1, 0, 127] }, + { type: Uint8Array, values: [1, 2, 255] }, + { type: Uint8ClampedArray, values: [0, 128, 255] }, + { type: Int16Array, values: [-1, 0, 32767] }, + { type: Uint16Array, values: [1, 2, 65535] }, + { type: Int32Array, values: [-1, 0, 123456789] }, + { type: Uint32Array, values: [1, 2, 4294967295] }, + { type: Float16Array, values: [0.5, -1.5, 42.25] }, + { type: Float32Array, values: [0.5, -1.5, 42.25] }, + { type: Float64Array, values: [0.5, -1.5, 42.25] }, + { type: BigInt64Array, values: [1n, -2n, 123456789n] }, + { type: BigUint64Array, values: [1n, 2n, 123456789n] }, +]; + +function createBuffer(Type, BufferType, length) { + const byteOffset = Type.BYTES_PER_ELEMENT; + const byteLength = byteOffset + (length * Type.BYTES_PER_ELEMENT); + return { + buffer: new BufferType(byteLength), + byteOffset, + }; +} - theArray.set([1, 2, 3, 4, 5, 6]); - assert.deepStrictEqual(Array.from(new Uint8Array(buffer, 4, 6)), - [1, 2, 3, 4, 5, 6]); +function createTypedArray(Type, buffer, byteOffset, length) { + const template = new Type(buffer, byteOffset, length); + return test_typedarray_sharedarraybuffer.CreateTypedArray(template, buffer); } -// Test for creating Uint8Array with SharedArrayBuffer -{ - const buffer = new SharedArrayBuffer(16); - const theArray = - test_typedarray_sharedarraybuffer.CreateUint8Array(buffer, 4, 6); +function verifyTypedArray(Type, buffer, byteOffset, values) { + const theArray = createTypedArray(Type, buffer, byteOffset, values.length); const theArrayBuffer = test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray); - assert.ok(theArray instanceof Uint8Array); + assert.ok(theArray instanceof Type); assert.strictEqual(theArray.buffer, buffer); - assert.ok(theArrayBuffer instanceof SharedArrayBuffer); assert.strictEqual(theArrayBuffer, buffer); - assert.strictEqual(theArray.byteOffset, 4); - assert.strictEqual(theArray.length, 6); + assert.strictEqual(theArray.byteOffset, byteOffset); + assert.strictEqual(theArray.length, values.length); - theArray.set([6, 5, 4, 3, 2, 1]); - assert.deepStrictEqual(Array.from(new Uint8Array(buffer, 4, 6)), - [6, 5, 4, 3, 2, 1]); + theArray.set(values); + assert.deepStrictEqual(Array.from(new Type(buffer, byteOffset, values.length)), + values); } -// Test for creating Uint16Array with SharedArrayBuffer +// Keep the existing ArrayBuffer behavior covered while focusing this test +// on SharedArrayBuffer-backed TypedArray creation. { - const buffer = new SharedArrayBuffer(24); - const theArray = - test_typedarray_sharedarraybuffer.CreateUint16Array(buffer, 4, 4); - - assert.ok(theArray instanceof Uint16Array); - assert.strictEqual(theArray.buffer, buffer); - assert.strictEqual(theArray.byteOffset, 4); - assert.strictEqual(theArray.length, 4); - - theArray.set([1, 2, 3, 65535]); - assert.deepStrictEqual(Array.from(new Uint16Array(buffer, 4, 4)), - [1, 2, 3, 65535]); + const { buffer, byteOffset } = createBuffer(Uint8Array, ArrayBuffer, 3); + verifyTypedArray(Uint8Array, buffer, byteOffset, [1, 2, 3]); } -// Test for creating Int32Array with SharedArrayBuffer -{ - const buffer = new SharedArrayBuffer(32); - const theArray = - test_typedarray_sharedarraybuffer.CreateInt32Array(buffer, 8, 3); - - assert.ok(theArray instanceof Int32Array); - assert.strictEqual(theArray.buffer, buffer); - assert.strictEqual(theArray.byteOffset, 8); - assert.strictEqual(theArray.length, 3); +// Verify all TypedArray variants can be created from SharedArrayBuffer. +typedArrayCases.forEach(({ type, values }) => { + const { buffer, byteOffset } = createBuffer(type, SharedArrayBuffer, + values.length); + verifyTypedArray(type, buffer, byteOffset, values); +}); - theArray.set([-1, 0, 123456789]); - assert.deepStrictEqual(Array.from(new Int32Array(buffer, 8, 3)), - [-1, 0, 123456789]); -} - -// Test for creating TypedArrays with SharedArrayBuffer and invalid range -{ - const buffer = new SharedArrayBuffer(8); +// Test for creating TypedArrays with SharedArrayBuffer and invalid range. +for (const { type, values } of typedArrayCases) { + const { buffer, byteOffset } = createBuffer(type, SharedArrayBuffer, + values.length); + const template = new type(buffer, byteOffset, values.length); assert.throws(() => { - test_typedarray_sharedarraybuffer.CreateUint8Array(buffer, 9, 0); + test_typedarray_sharedarraybuffer.CreateTypedArray( + template, buffer, values.length + 1, byteOffset); }, RangeError); +} - assert.throws(() => { - test_typedarray_sharedarraybuffer.CreateUint16Array(buffer, 0, 5); - }, RangeError); +// Test for creating TypedArrays with SharedArrayBuffer and invalid alignment. +for (const { type, values } of typedArrayCases) { + if (type.BYTES_PER_ELEMENT <= 1) { + continue; + } + + const { buffer, byteOffset } = createBuffer(type, SharedArrayBuffer, + values.length); + const template = new type(buffer, byteOffset, values.length); assert.throws(() => { - test_typedarray_sharedarraybuffer.CreateUint16Array(buffer, 1, 1); + test_typedarray_sharedarraybuffer.CreateTypedArray( + template, buffer, 1, byteOffset + 1); }, RangeError); } -// Test invalid arguments +// Test invalid arguments. { + const template = new Uint8Array(1); + assert.throws(() => { - test_typedarray_sharedarraybuffer.CreateUint8Array({}, 0, 1); + test_typedarray_sharedarraybuffer.CreateTypedArray(template, {}); }, { name: 'Error', message: 'Invalid argument' }); assert.throws(() => { - test_typedarray_sharedarraybuffer.CreateUint8Array(1, 0, 1); + test_typedarray_sharedarraybuffer.CreateTypedArray(template, 1); }, { name: 'Error', message: 'Invalid argument' }); } diff --git a/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c b/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c index e7565b0a403859..f03ccfcdbca0f2 100644 --- a/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c +++ b/test/js-native-api/test_typedarray_sharedarraybuffer/test_typedarray_sharedarraybuffer.c @@ -5,41 +5,46 @@ #include "../common.h" #include "../entry_point.h" -static napi_value CreateTypedArray(napi_env env, - napi_callback_info info, - napi_typedarray_type type) { - size_t argc = 3; - napi_value args[3]; +static napi_value CreateTypedArray(napi_env env, napi_callback_info info) { + size_t argc = 4; + napi_value args[4]; NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); - NODE_API_ASSERT(env, argc == 3, "Wrong number of arguments"); + NODE_API_ASSERT(env, argc == 2 || argc == 4, "Wrong number of arguments"); - uint32_t byte_offset; - NODE_API_CALL(env, napi_get_value_uint32(env, args[1], &byte_offset)); + bool is_typedarray; + NODE_API_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray)); + NODE_API_ASSERT(env, + is_typedarray, + "Wrong type of arguments. Expects a typed array as first " + "argument."); - uint32_t length; - NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &length)); + napi_typedarray_type type; + size_t length; + size_t byte_offset; + NODE_API_CALL(env, + napi_get_typedarray_info( + env, args[0], &type, &length, NULL, NULL, &byte_offset)); + + if (argc == 4) { + uint32_t uint32_length; + NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length)); + length = uint32_length; + + uint32_t uint32_byte_offset; + NODE_API_CALL(env, + napi_get_value_uint32(env, args[3], &uint32_byte_offset)); + byte_offset = uint32_byte_offset; + } napi_value typedarray; NODE_API_CALL(env, napi_create_typedarray( - env, type, length, args[0], byte_offset, &typedarray)); + env, type, length, args[1], byte_offset, &typedarray)); return typedarray; } -static napi_value CreateUint8Array(napi_env env, napi_callback_info info) { - return CreateTypedArray(env, info, napi_uint8_array); -} - -static napi_value CreateUint16Array(napi_env env, napi_callback_info info) { - return CreateTypedArray(env, info, napi_uint16_array); -} - -static napi_value CreateInt32Array(napi_env env, napi_callback_info info) { - return CreateTypedArray(env, info, napi_int32_array); -} - static napi_value GetArrayBuffer(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; @@ -58,9 +63,7 @@ static napi_value GetArrayBuffer(napi_env env, napi_callback_info info) { EXTERN_C_START napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { - DECLARE_NODE_API_PROPERTY("CreateUint8Array", CreateUint8Array), - DECLARE_NODE_API_PROPERTY("CreateUint16Array", CreateUint16Array), - DECLARE_NODE_API_PROPERTY("CreateInt32Array", CreateInt32Array), + DECLARE_NODE_API_PROPERTY("CreateTypedArray", CreateTypedArray), DECLARE_NODE_API_PROPERTY("GetArrayBuffer", GetArrayBuffer), };