| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 3acadae commit 45f3e3e
5 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2783,6 +2783,10 @@ Language Specification. | |||
| 2783 | 2783 | <!-- YAML | |
| 2784 | 2784 | added: v8.0.0 | |
| 2785 | 2785 | napiVersion: 1 | |
| 2786 | + changes: | ||
| 2787 | + - version: REPLACEME | ||
| 2788 | + pr-url: https://github.com/nodejs/node/pull/62710 | ||
| 2789 | + description: Added support for `SharedArrayBuffer`. | ||
| 2786 | 2790 | --> | |
| 2787 | 2791 | ||
| 2788 | 2792 | ```c | |
@@ -2797,21 +2801,25 @@ napi_status napi_create_typedarray(napi_env env, | |||
| 2797 | 2801 | * `[in] env`: The environment that the API is invoked under. | |
| 2798 | 2802 | * `[in] type`: Scalar datatype of the elements within the `TypedArray`. | |
| 2799 | 2803 | * `[in] length`: Number of elements in the `TypedArray`. | |
| 2800 | - * `[in] arraybuffer`: `ArrayBuffer` underlying the typed array. | ||
| 2801 | - * `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to | ||
| 2802 | - start projecting the `TypedArray`. | ||
| 2804 | + * `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the | ||
| 2805 | + typed array. | ||
| 2806 | + * `[in] byte_offset`: The byte offset within the `ArrayBuffer` or | ||
| 2807 | + `SharedArrayBuffer` from which to start projecting the `TypedArray`. | ||
| 2803 | 2808 | * `[out] result`: A `napi_value` representing a JavaScript `TypedArray`. | |
| 2804 | 2809 | ||
| 2805 | 2810 | Returns `napi_ok` if the API succeeded. | |
| 2806 | 2811 | ||
| 2807 | 2812 | This API creates a JavaScript `TypedArray` object over an existing | |
| 2808 | - `ArrayBuffer`. `TypedArray` objects provide an array-like view over an | ||
| 2809 | - underlying data buffer where each element has the same underlying binary scalar | ||
| 2810 | - datatype. | ||
| 2813 | + `ArrayBuffer` or `SharedArrayBuffer`. `TypedArray` objects provide an | ||
| 2814 | + array-like view over an underlying data buffer where each element has the same | ||
| 2815 | + underlying binary scalar datatype. | ||
| 2816 | + | ||
| 2817 | + It is required that `(length * size_of_element) + byte_offset` is less than or | ||
| 2818 | + equal to the size in bytes of the `ArrayBuffer` or `SharedArrayBuffer` passed | ||
| 2819 | + in. If not, a `RangeError` exception is raised. | ||
| 2811 | 2820 | ||
| 2812 | - It's required that `(length * size_of_element) + byte_offset` should | ||
| 2813 | - be <= the size in bytes of the array passed in. If not, a `RangeError` exception | ||
| 2814 | - is raised. | ||
| 2821 | + For element sizes greater than 1, `byte_offset` is required to be a multiple | ||
| 2822 | + of the element size. If not, a `RangeError` exception is raised. | ||
| 2815 | 2823 | ||
| 2816 | 2824 | JavaScript `TypedArray` objects are described in | |
| 2817 | 2825 | [Section TypedArray objects][] of the ECMAScript Language Specification. | |
@@ -3504,7 +3512,8 @@ napi_status napi_get_typedarray_info(napi_env env, | |||
| 3504 | 3512 | the `byte_offset` value so that it points to the first element in the | |
| 3505 | 3513 | `TypedArray`. If the length of the array is `0`, this may be `NULL` or | |
| 3506 | 3514 | any other pointer value. | |
| 3507 | - * `[out] arraybuffer`: The `ArrayBuffer` underlying the `TypedArray`. | ||
| 3515 | + * `[out] arraybuffer`: The `ArrayBuffer` or `SharedArrayBuffer` underlying the | ||
| 3516 | + `TypedArray`. | ||
| 3508 | 3517 | * `[out] byte_offset`: The byte offset within the underlying native array | |
| 3509 | 3518 | at which the first element of the arrays is located. The value for the data | |
| 3510 | 3519 | parameter has already been adjusted so that data points to the first element | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3276,66 +3276,73 @@ napi_status NAPI_CDECL napi_create_typedarray(napi_env env, | |||
| 3276 | 3276 | CHECK_ARG(env, result); | |
| 3277 | 3277 | ||
| 3278 | 3278 | v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer); | |
| 3279 | - RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); | ||
| 3279 | + auto create_typedarray = [&](auto buffer) -> napi_status { | ||
| 3280 | + v8::Local<v8::TypedArray> typedArray; | ||
| 3281 | + | ||
| 3282 | + switch (type) { | ||
| 3283 | + case napi_int8_array: | ||
| 3284 | + CREATE_TYPED_ARRAY( | ||
| 3285 | + env, Int8Array, 1, buffer, byte_offset, length, typedArray); | ||
| 3286 | + break; | ||
| 3287 | + case napi_uint8_array: | ||
| 3288 | + CREATE_TYPED_ARRAY( | ||
| 3289 | + env, Uint8Array, 1, buffer, byte_offset, length, typedArray); | ||
| 3290 | + break; | ||
| 3291 | + case napi_uint8_clamped_array: | ||
| 3292 | + CREATE_TYPED_ARRAY( | ||
| 3293 | + env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray); | ||
| 3294 | + break; | ||
| 3295 | + case napi_int16_array: | ||
| 3296 | + CREATE_TYPED_ARRAY( | ||
| 3297 | + env, Int16Array, 2, buffer, byte_offset, length, typedArray); | ||
| 3298 | + break; | ||
| 3299 | + case napi_uint16_array: | ||
| 3300 | + CREATE_TYPED_ARRAY( | ||
| 3301 | + env, Uint16Array, 2, buffer, byte_offset, length, typedArray); | ||
| 3302 | + break; | ||
| 3303 | + case napi_int32_array: | ||
| 3304 | + CREATE_TYPED_ARRAY( | ||
| 3305 | + env, Int32Array, 4, buffer, byte_offset, length, typedArray); | ||
| 3306 | + break; | ||
| 3307 | + case napi_uint32_array: | ||
| 3308 | + CREATE_TYPED_ARRAY( | ||
| 3309 | + env, Uint32Array, 4, buffer, byte_offset, length, typedArray); | ||
| 3310 | + break; | ||
| 3311 | + case napi_float32_array: | ||
| 3312 | + CREATE_TYPED_ARRAY( | ||
| 3313 | + env, Float32Array, 4, buffer, byte_offset, length, typedArray); | ||
| 3314 | + break; | ||
| 3315 | + case napi_float64_array: | ||
| 3316 | + CREATE_TYPED_ARRAY( | ||
| 3317 | + env, Float64Array, 8, buffer, byte_offset, length, typedArray); | ||
| 3318 | + break; | ||
| 3319 | + case napi_bigint64_array: | ||
| 3320 | + CREATE_TYPED_ARRAY( | ||
| 3321 | + env, BigInt64Array, 8, buffer, byte_offset, length, typedArray); | ||
| 3322 | + break; | ||
| 3323 | + case napi_biguint64_array: | ||
| 3324 | + CREATE_TYPED_ARRAY( | ||
| 3325 | + env, BigUint64Array, 8, buffer, byte_offset, length, typedArray); | ||
| 3326 | + break; | ||
| 3327 | + case napi_float16_array: | ||
| 3328 | + CREATE_TYPED_ARRAY( | ||
| 3329 | + env, Float16Array, 2, buffer, byte_offset, length, typedArray); | ||
| 3330 | + break; | ||
| 3331 | + default: | ||
| 3332 | + return napi_set_last_error(env, napi_invalid_arg); | ||
| 3333 | + } | ||
| 3280 | 3334 | ||
| 3281 | - v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>(); | ||
| 3282 | - v8::Local<v8::TypedArray> typedArray; | ||
| 3335 | + *result = v8impl::JsValueFromV8LocalValue(typedArray); | ||
| 3336 | + return GET_RETURN_STATUS(env); | ||
| 3337 | + }; | ||
| 3283 | 3338 | ||
| 3284 | - switch (type) { | ||
| 3285 | - case napi_int8_array: | ||
| 3286 | - CREATE_TYPED_ARRAY( | ||
| 3287 | - env, Int8Array, 1, buffer, byte_offset, length, typedArray); | ||
| 3288 | - break; | ||
| 3289 | - case napi_uint8_array: | ||
| 3290 | - CREATE_TYPED_ARRAY( | ||
| 3291 | - env, Uint8Array, 1, buffer, byte_offset, length, typedArray); | ||
| 3292 | - break; | ||
| 3293 | - case napi_uint8_clamped_array: | ||
| 3294 | - CREATE_TYPED_ARRAY( | ||
| 3295 | - env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray); | ||
| 3296 | - break; | ||
| 3297 | - case napi_int16_array: | ||
| 3298 | - CREATE_TYPED_ARRAY( | ||
| 3299 | - env, Int16Array, 2, buffer, byte_offset, length, typedArray); | ||
| 3300 | - break; | ||
| 3301 | - case napi_uint16_array: | ||
| 3302 | - CREATE_TYPED_ARRAY( | ||
| 3303 | - env, Uint16Array, 2, buffer, byte_offset, length, typedArray); | ||
| 3304 | - break; | ||
| 3305 | - case napi_int32_array: | ||
| 3306 | - CREATE_TYPED_ARRAY( | ||
| 3307 | - env, Int32Array, 4, buffer, byte_offset, length, typedArray); | ||
| 3308 | - break; | ||
| 3309 | - case napi_uint32_array: | ||
| 3310 | - CREATE_TYPED_ARRAY( | ||
| 3311 | - env, Uint32Array, 4, buffer, byte_offset, length, typedArray); | ||
| 3312 | - break; | ||
| 3313 | - case napi_float32_array: | ||
| 3314 | - CREATE_TYPED_ARRAY( | ||
| 3315 | - env, Float32Array, 4, buffer, byte_offset, length, typedArray); | ||
| 3316 | - break; | ||
| 3317 | - case napi_float64_array: | ||
| 3318 | - CREATE_TYPED_ARRAY( | ||
| 3319 | - env, Float64Array, 8, buffer, byte_offset, length, typedArray); | ||
| 3320 | - break; | ||
| 3321 | - case napi_bigint64_array: | ||
| 3322 | - CREATE_TYPED_ARRAY( | ||
| 3323 | - env, BigInt64Array, 8, buffer, byte_offset, length, typedArray); | ||
| 3324 | - break; | ||
| 3325 | - case napi_biguint64_array: | ||
| 3326 | - CREATE_TYPED_ARRAY( | ||
| 3327 | - env, BigUint64Array, 8, buffer, byte_offset, length, typedArray); | ||
| 3328 | - break; | ||
| 3329 | - case napi_float16_array: | ||
| 3330 | - CREATE_TYPED_ARRAY( | ||
| 3331 | - env, Float16Array, 2, buffer, byte_offset, length, typedArray); | ||
| 3332 | - break; | ||
| 3333 | - default: | ||
| 3334 | - return napi_set_last_error(env, napi_invalid_arg); | ||
| 3339 | + if (value->IsArrayBuffer()) { | ||
| 3340 | + return create_typedarray(value.As<v8::ArrayBuffer>()); | ||
| 3341 | + } else if (value->IsSharedArrayBuffer()) { | ||
| 3342 | + return create_typedarray(value.As<v8::SharedArrayBuffer>()); | ||
| 3343 | + } else { | ||
| 3344 | + return napi_set_last_error(env, napi_invalid_arg); | ||
| 3335 | 3345 | } | |
| 3336 | - | ||
| 3337 | - *result = v8impl::JsValueFromV8LocalValue(typedArray); | ||
| 3338 | - return GET_RETURN_STATUS(env); | ||
| 3339 | 3346 | } | |
| 3340 | 3347 | ||
| 3341 | 3348 | napi_status NAPI_CDECL napi_get_typedarray_info(napi_env env, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -5,6 +5,12 @@ | |||
| 5 | 5 | "sources": [ | |
| 6 | 6 | "test_typedarray.c" | |
| 7 | 7 | ] | |
| 8 | + }, | ||
| 9 | + { | ||
| 10 | + "target_name": "test_typedarray_sharedarraybuffer", | ||
| 11 | + "sources": [ | ||
| 12 | + "test_typedarray_sharedarraybuffer.c" | ||
| 13 | + ] | ||
| 8 | 14 | } | |
| 9 | 15 | ] | |
| 10 | 16 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,110 @@ | |||
| 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 | + const common = require('../../common'); | ||
| 7 | + const assert = require('assert'); | ||
| 8 | + | ||
| 9 | + const test_typedarray_sharedarraybuffer = | ||
| 10 | + require(`./build/${common.buildType}/test_typedarray_sharedarraybuffer`); | ||
| 11 | + | ||
| 12 | + const typedArrayCases = [ | ||
| 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: Float16Array, values: [0.5, -1.5, 42.25] }, | ||
| 21 | + { type: Float32Array, values: [0.5, -1.5, 42.25] }, | ||
| 22 | + { type: Float64Array, values: [0.5, -1.5, 42.25] }, | ||
| 23 | + { type: BigInt64Array, values: [1n, -2n, 123456789n] }, | ||
| 24 | + { type: BigUint64Array, values: [1n, 2n, 123456789n] }, | ||
| 25 | + ]; | ||
| 26 | + | ||
| 27 | + function createBuffer(Type, BufferType, length) { | ||
| 28 | + const byteOffset = Type.BYTES_PER_ELEMENT; | ||
| 29 | + const byteLength = byteOffset + (length * Type.BYTES_PER_ELEMENT); | ||
| 30 | + return { | ||
| 31 | + buffer: new BufferType(byteLength), | ||
| 32 | + byteOffset, | ||
| 33 | + }; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + function createTypedArray(Type, buffer, byteOffset, length) { | ||
| 37 | + const template = new Type(buffer, byteOffset, length); | ||
| 38 | + return test_typedarray_sharedarraybuffer.CreateTypedArray(template, buffer); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + function verifyTypedArray(Type, buffer, byteOffset, values) { | ||
| 42 | + const theArray = createTypedArray(Type, buffer, byteOffset, values.length); | ||
| 43 | + const theArrayBuffer = | ||
| 44 | + test_typedarray_sharedarraybuffer.GetArrayBuffer(theArray); | ||
| 45 | + | ||
| 46 | + assert.ok(theArray instanceof Type); | ||
| 47 | + assert.strictEqual(theArray.buffer, buffer); | ||
| 48 | + assert.strictEqual(theArrayBuffer, buffer); | ||
| 49 | + assert.strictEqual(theArray.byteOffset, byteOffset); | ||
| 50 | + assert.strictEqual(theArray.length, values.length); | ||
| 51 | + | ||
| 52 | + theArray.set(values); | ||
| 53 | + assert.deepStrictEqual(Array.from(new Type(buffer, byteOffset, values.length)), | ||
| 54 | + values); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + // Keep the existing ArrayBuffer behavior covered while focusing this test | ||
| 58 | + // on SharedArrayBuffer-backed TypedArray creation. | ||
| 59 | + { | ||
| 60 | + const { buffer, byteOffset } = createBuffer(Uint8Array, ArrayBuffer, 3); | ||
| 61 | + verifyTypedArray(Uint8Array, buffer, byteOffset, [1, 2, 3]); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + // Verify all TypedArray variants can be created from SharedArrayBuffer. | ||
| 65 | + typedArrayCases.forEach(({ type, values }) => { | ||
| 66 | + const { buffer, byteOffset } = createBuffer(type, SharedArrayBuffer, | ||
| 67 | + values.length); | ||
| 68 | + verifyTypedArray(type, buffer, byteOffset, values); | ||
| 69 | + }); | ||
| 70 | + | ||
| 71 | + // Test for creating TypedArrays with SharedArrayBuffer and invalid range. | ||
| 72 | + for (const { type, values } of typedArrayCases) { | ||
| 73 | + const { buffer, byteOffset } = createBuffer(type, SharedArrayBuffer, | ||
| 74 | + values.length); | ||
| 75 | + const template = new type(buffer, byteOffset, values.length); | ||
| 76 | + | ||
| 77 | + assert.throws(() => { | ||
| 78 | + test_typedarray_sharedarraybuffer.CreateTypedArray( | ||
| 79 | + template, buffer, values.length + 1, byteOffset); | ||
| 80 | + }, RangeError); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + // Test for creating TypedArrays with SharedArrayBuffer and invalid alignment. | ||
| 84 | + for (const { type, values } of typedArrayCases) { | ||
| 85 | + if (type.BYTES_PER_ELEMENT <= 1) { | ||
| 86 | + continue; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + const { buffer, byteOffset } = createBuffer(type, SharedArrayBuffer, | ||
| 90 | + values.length); | ||
| 91 | + const template = new type(buffer, byteOffset, values.length); | ||
| 92 | + | ||
| 93 | + assert.throws(() => { | ||
| 94 | + test_typedarray_sharedarraybuffer.CreateTypedArray( | ||
| 95 | + template, buffer, 1, byteOffset + 1); | ||
| 96 | + }, RangeError); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + // Test invalid arguments. | ||
| 100 | + { | ||
| 101 | + const template = new Uint8Array(1); | ||
| 102 | + | ||
| 103 | + assert.throws(() => { | ||
| 104 | + test_typedarray_sharedarraybuffer.CreateTypedArray(template, {}); | ||
| 105 | + }, { name: 'Error', message: 'Invalid argument' }); | ||
| 106 | + | ||
| 107 | + assert.throws(() => { | ||
| 108 | + test_typedarray_sharedarraybuffer.CreateTypedArray(template, 1); | ||
| 109 | + }, { name: 'Error', message: 'Invalid argument' }); | ||
| 110 | + } | ||
| Original file line number | Diff line number | Diff 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 | + static napi_value CreateTypedArray(napi_env env, napi_callback_info info) { | ||
| 9 | + size_t argc = 4; | ||
| 10 | + napi_value args[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 | + bool is_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_type type; | ||
| 23 | + size_t length; | ||
| 24 | + size_t byte_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_t uint32_length; | ||
| 31 | + NODE_API_CALL(env, napi_get_value_uint32(env, args[2], &uint32_length)); | ||
| 32 | + length = uint32_length; | ||
| 33 | + | ||
| 34 | + uint32_t uint32_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_value typedarray; | ||
| 41 | + NODE_API_CALL(env, | ||
| 42 | + napi_create_typedarray( | ||
| 43 | + env, type, length, args[1], byte_offset, &typedarray)); | ||
| 44 | + | ||
| 45 | + return typedarray; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + static napi_value GetArrayBuffer(napi_env env, napi_callback_info info) { | ||
| 49 | + size_t argc = 1; | ||
| 50 | + napi_value args[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_value arraybuffer; | ||
| 56 | + NODE_API_CALL(env, | ||
| 57 | + napi_get_typedarray_info( | ||
| 58 | + env, args[0], NULL, NULL, NULL, &arraybuffer, NULL)); | ||
| 59 | + | ||
| 60 | + return arraybuffer; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + EXTERN_C_START | ||
| 64 | + napi_value Init(napi_env env, napi_value exports) { | ||
| 65 | + napi_property_descriptor descriptors[] = { | ||
| 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 | + return exports; | ||
| 78 | + } | ||
| 79 | + EXTERN_C_END | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments