diff --git a/doc/api/n-api.md b/doc/api/n-api.md index e35196d7172e1d..96ed9a6b6a14ef 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -2769,6 +2769,10 @@ exceeds the size of the `ArrayBuffer`, a `RangeError` exception is raised. ```c @@ -2781,16 +2785,18 @@ napi_status napi_create_dataview(napi_env env, * `[in] env`: The environment that the API is invoked under. * `[in] length`: Number of elements in the `DataView`. -* `[in] arraybuffer`: `ArrayBuffer` underlying the `DataView`. +* `[in] arraybuffer`: `ArrayBuffer` or `SharedArrayBuffer` underlying the + `DataView`. * `[in] byte_offset`: The byte offset within the `ArrayBuffer` from which to start projecting the `DataView`. * `[out] result`: A `napi_value` representing a JavaScript `DataView`. Returns `napi_ok` if the API succeeded. -This API creates a JavaScript `DataView` object over an existing `ArrayBuffer`. -`DataView` objects provide an array-like view over an underlying data buffer, -but one which allows items of different size and type in the `ArrayBuffer`. +This API creates a JavaScript `DataView` object over an existing `ArrayBuffer` +or `SharedArrayBuffer`. `DataView` objects provide an array-like view over an +underlying data buffer, but one which allows items of different size and type in +the `ArrayBuffer` or `SharedArrayBuffer`. It is required that `byte_length + byte_offset` is less than or equal to the size in bytes of the array passed in. If not, a `RangeError` exception is diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index 153f49339f702e..b209bee8a29cca 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -3298,21 +3298,30 @@ napi_status NAPI_CDECL napi_create_dataview(napi_env env, CHECK_ARG(env, result); v8::Local value = v8impl::V8LocalValueFromJsValue(arraybuffer); - RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg); - v8::Local buffer = value.As(); - if (byte_length + byte_offset > buffer->ByteLength()) { - napi_throw_range_error(env, - "ERR_NAPI_INVALID_DATAVIEW_ARGS", - "byte_offset + byte_length should be less than or " - "equal to the size in bytes of the array passed in"); - return napi_set_last_error(env, napi_pending_exception); - } - v8::Local DataView = - v8::DataView::New(buffer, byte_offset, byte_length); + auto create_dataview = [&](auto buffer) -> napi_status { + if (byte_length + byte_offset > buffer->ByteLength()) { + napi_throw_range_error( + env, + "ERR_NAPI_INVALID_DATAVIEW_ARGS", + "byte_offset + byte_length should be less than or " + "equal to the size in bytes of the array passed in"); + return napi_set_last_error(env, napi_pending_exception); + } - *result = v8impl::JsValueFromV8LocalValue(DataView); - return GET_RETURN_STATUS(env); + v8::Local data_view = + v8::DataView::New(buffer, byte_offset, byte_length); + *result = v8impl::JsValueFromV8LocalValue(data_view); + return GET_RETURN_STATUS(env); + }; + + if (value->IsArrayBuffer()) { + return create_dataview(value.As()); + } else if (value->IsSharedArrayBuffer()) { + return create_dataview(value.As()); + } else { + return napi_set_last_error(env, napi_invalid_arg); + } } napi_status NAPI_CDECL napi_is_dataview(napi_env env, diff --git a/test/js-native-api/test_dataview/binding.gyp b/test/js-native-api/test_dataview/binding.gyp index 64235390812d79..c6d8a22c035c43 100644 --- a/test/js-native-api/test_dataview/binding.gyp +++ b/test/js-native-api/test_dataview/binding.gyp @@ -4,7 +4,10 @@ "target_name": "test_dataview", "sources": [ "test_dataview.c" - ] + ], + + # For node_api_is_sharedarraybuffer + 'defines': [ 'NAPI_EXPERIMENTAL', 'NODE_API_EXPERIMENTAL_NO_WARNING' ] } ] } diff --git a/test/js-native-api/test_dataview/test.js b/test/js-native-api/test_dataview/test.js index a6be58494069e5..218d9446a6b972 100644 --- a/test/js-native-api/test_dataview/test.js +++ b/test/js-native-api/test_dataview/test.js @@ -5,7 +5,7 @@ const assert = require('assert'); // Testing api calls for arrays const test_dataview = require(`./build/${common.buildType}/test_dataview`); -// Test for creating dataview +// Test for creating dataview with ArrayBuffer { const buffer = new ArrayBuffer(128); const template = Reflect.construct(DataView, [buffer]); @@ -15,10 +15,30 @@ const test_dataview = require(`./build/${common.buildType}/test_dataview`); `Expect ${theDataview} to be a DataView`); } -// Test for creating dataview with invalid range +// Test for creating dataview with SharedArrayBuffer +{ + const buffer = new SharedArrayBuffer(128); + const template = new DataView(buffer); + + const theDataview = test_dataview.CreateDataViewFromJSDataView(template); + assert.ok(theDataview instanceof DataView, + `Expect ${theDataview} to be a DataView`); + + assert.strictEqual(template.buffer, theDataview.buffer); +} + +// Test for creating dataview with ArrayBuffer and invalid range { const buffer = new ArrayBuffer(128); assert.throws(() => { test_dataview.CreateDataView(buffer, 10, 200); }, RangeError); } + +// Test for creating dataview with SharedArrayBuffer and invalid range +{ + const buffer = new SharedArrayBuffer(128); + assert.throws(() => { + test_dataview.CreateDataView(buffer, 10, 200); + }, RangeError); +} diff --git a/test/js-native-api/test_dataview/test_dataview.c b/test/js-native-api/test_dataview/test_dataview.c index 9f62b734c6a9ef..ec564e6e280014 100644 --- a/test/js-native-api/test_dataview/test_dataview.c +++ b/test/js-native-api/test_dataview/test_dataview.c @@ -20,9 +20,18 @@ static napi_value CreateDataView(napi_env env, napi_callback_info info) { bool is_arraybuffer; NODE_API_CALL(env, napi_is_arraybuffer(env, arraybuffer, &is_arraybuffer)); - NODE_API_ASSERT(env, is_arraybuffer, - "Wrong type of arguments. Expects a ArrayBuffer as the first " - "argument."); + + if (!is_arraybuffer) { + bool is_sharedarraybuffer; + NODE_API_CALL( + env, + node_api_is_sharedarraybuffer(env, arraybuffer, &is_sharedarraybuffer)); + NODE_API_ASSERT(env, + is_sharedarraybuffer, + "Wrong type of arguments. Expects a SharedArrayBuffer or " + "ArrayBuffer as the first " + "argument."); + } napi_valuetype valuetype1; NODE_API_CALL(env, napi_typeof(env, args[1], &valuetype1));