Skip to content

Commit

Permalink
n-api: add napi_detach_arraybuffer
Browse files Browse the repository at this point in the history
As ArrayBuffer#detach is an ecma spec operation
([Section 24.1.1.3](https://tc39.es/ecma262/#sec-detacharraybuffer)),
it might be good to have it in N-API.

Fixes #29674

PR-URL: #29768
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: David Carlier <devnexen@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
  • Loading branch information
legendecas authored and Trott committed Oct 14, 2019
1 parent f9caee9 commit 6afed1d
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 1 deletion.
27 changes: 27 additions & 0 deletions doc/api/n-api.md
Expand Up @@ -371,6 +371,8 @@ typedef enum {
napi_closing, napi_closing,
napi_bigint_expected, napi_bigint_expected,
napi_date_expected, napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
} napi_status; } napi_status;
``` ```


Expand Down Expand Up @@ -3148,6 +3150,30 @@ Returns `napi_ok` if the API succeeded.
This API represents the invocation of the Strict Equality algorithm as This API represents the invocation of the Strict Equality algorithm as
defined in [Section 7.2.14][] of the ECMAScript Language Specification. defined in [Section 7.2.14][] of the ECMAScript Language Specification.


### napi_detach_arraybuffer
<!-- YAML
added: REPLACEME
-->

```C
napi_status napi_detach_arraybuffer(napi_env env,
napi_value arraybuffer)
```
* `[in] env`: The environment that the API is invoked under.
* `[in] arraybuffer`: The JavaScript `ArrayBuffer` to be detached.
Returns `napi_ok` if the API succeeded. If a non-detachable `ArrayBuffer` is
passed in it returns `napi_detachable_arraybuffer_expected`.
Generally, an `ArrayBuffer` is non-detachable if it has been detached before.
The engine may impose additional conditions on whether an `ArrayBuffer` is
detachable. For example, V8 requires that the `ArrayBuffer` be external,
that is, created with [`napi_create_external_arraybuffer`][].
This API represents the invocation of the `ArrayBuffer` detach operation as
defined in [Section 24.1.1.3][] of the ECMAScript Language Specification.
## Working with JavaScript Properties ## Working with JavaScript Properties
N-API exposes a set of APIs to get and set properties on JavaScript N-API exposes a set of APIs to get and set properties on JavaScript
Expand Down Expand Up @@ -5144,6 +5170,7 @@ This API may only be called from the main thread.
[Section 22.1.4.1]: https://tc39.github.io/ecma262/#sec-properties-of-array-instances-length [Section 22.1.4.1]: https://tc39.github.io/ecma262/#sec-properties-of-array-instances-length
[Section 22.2]: https://tc39.github.io/ecma262/#sec-typedarray-objects [Section 22.2]: https://tc39.github.io/ecma262/#sec-typedarray-objects
[Section 24.1]: https://tc39.github.io/ecma262/#sec-arraybuffer-objects [Section 24.1]: https://tc39.github.io/ecma262/#sec-arraybuffer-objects
[Section 24.1.1.3]: https://tc39.es/ecma262/#sec-detacharraybuffer
[Section 24.3]: https://tc39.github.io/ecma262/#sec-dataview-objects [Section 24.3]: https://tc39.github.io/ecma262/#sec-dataview-objects
[Section 25.4]: https://tc39.github.io/ecma262/#sec-promise-objects [Section 25.4]: https://tc39.github.io/ecma262/#sec-promise-objects
[`Number.MIN_SAFE_INTEGER`]: https://tc39.github.io/ecma262/#sec-number.min_safe_integer [`Number.MIN_SAFE_INTEGER`]: https://tc39.github.io/ecma262/#sec-number.min_safe_integer
Expand Down
4 changes: 4 additions & 0 deletions src/js_native_api.h
Expand Up @@ -514,6 +514,10 @@ NAPI_EXTERN napi_status napi_set_instance_data(napi_env env,


NAPI_EXTERN napi_status napi_get_instance_data(napi_env env, NAPI_EXTERN napi_status napi_get_instance_data(napi_env env,
void** data); void** data);

// ArrayBuffer detaching
NAPI_EXTERN napi_status napi_detach_arraybuffer(napi_env env,
napi_value arraybuffer);
#endif // NAPI_EXPERIMENTAL #endif // NAPI_EXPERIMENTAL


EXTERN_C_END EXTERN_C_END
Expand Down
2 changes: 2 additions & 0 deletions src/js_native_api_types.h
Expand Up @@ -80,6 +80,8 @@ typedef enum {
napi_closing, napi_closing,
napi_bigint_expected, napi_bigint_expected,
napi_date_expected, napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
} napi_status; } napi_status;
// Note: when adding a new enum value to `napi_status`, please also update // Note: when adding a new enum value to `napi_status`, please also update
// `const int last_status` in `napi_get_last_error_info()' definition, // `const int last_status` in `napi_get_last_error_info()' definition,
Expand Down
23 changes: 22 additions & 1 deletion src/js_native_api_v8.cc
Expand Up @@ -671,6 +671,8 @@ const char* error_messages[] = {nullptr,
"Thread-safe function handle is closing", "Thread-safe function handle is closing",
"A bigint was expected", "A bigint was expected",
"A date was expected", "A date was expected",
"An arraybuffer was expected",
"A detachable arraybuffer was expected",
}; };


napi_status napi_get_last_error_info(napi_env env, napi_status napi_get_last_error_info(napi_env env,
Expand All @@ -682,7 +684,7 @@ napi_status napi_get_last_error_info(napi_env env,
// message in the `napi_status` enum each time a new error message is added. // message in the `napi_status` enum each time a new error message is added.
// We don't have a napi_status_last as this would result in an ABI // We don't have a napi_status_last as this would result in an ABI
// change each time a message was added. // change each time a message was added.
const int last_status = napi_date_expected; const int last_status = napi_detachable_arraybuffer_expected;


static_assert( static_assert(
NAPI_ARRAYSIZE(error_messages) == last_status + 1, NAPI_ARRAYSIZE(error_messages) == last_status + 1,
Expand Down Expand Up @@ -3003,3 +3005,22 @@ napi_status napi_get_instance_data(napi_env env,


return napi_clear_last_error(env); return napi_clear_last_error(env);
} }

napi_status napi_detach_arraybuffer(napi_env env, napi_value arraybuffer) {
CHECK_ENV(env);
CHECK_ARG(env, arraybuffer);

v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
RETURN_STATUS_IF_FALSE(
env, value->IsArrayBuffer(), napi_arraybuffer_expected);

v8::Local<v8::ArrayBuffer> it = value.As<v8::ArrayBuffer>();
RETURN_STATUS_IF_FALSE(
env, it->IsExternal(), napi_detachable_arraybuffer_expected);
RETURN_STATUS_IF_FALSE(
env, it->IsDetachable(), napi_detachable_arraybuffer_expected);

it->Detach();

return napi_clear_last_error(env);
}
18 changes: 18 additions & 0 deletions test/js-native-api/test_typedarray/test.js
Expand Up @@ -74,3 +74,21 @@ nonByteArrayTypes.forEach((currentType) => {
console.log(`start of offset ${currentType}`); console.log(`start of offset ${currentType}`);
}, RangeError); }, RangeError);
}); });

// Test detaching
arrayTypes.forEach((currentType) => {
const buffer = Reflect.construct(currentType, [8]);
assert.throws(
() => test_typedarray.Detach(buffer),
/A detachable arraybuffer was expected/);
});
{
const buffer = test_typedarray.External();
assert.ok(externalResult instanceof Int8Array);
assert.strictEqual(externalResult.length, 3);
assert.strictEqual(externalResult.byteLength, 3);
test_typedarray.Detach(buffer);
assert.ok(externalResult instanceof Int8Array);
assert.strictEqual(buffer.length, 0);
assert.strictEqual(buffer.byteLength, 0);
}
19 changes: 19 additions & 0 deletions test/js-native-api/test_typedarray/test_typedarray.c
@@ -1,3 +1,4 @@
#define NAPI_EXPERIMENTAL
#include <js_native_api.h> #include <js_native_api.h>
#include <string.h> #include <string.h>
#include "../common.h" #include "../common.h"
Expand Down Expand Up @@ -165,12 +166,30 @@ static napi_value CreateTypedArray(napi_env env, napi_callback_info info) {
return output_array; return output_array;
} }


static napi_value Detach(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1];
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
NAPI_ASSERT(env, argc == 1, "Wrong number of arguments.");

bool is_typedarray;
NAPI_CALL(env, napi_is_typedarray(env, args[0], &is_typedarray));
NAPI_ASSERT(env, is_typedarray, "Wrong type of arguments. Expects a typedarray as first argument.");

napi_value arraybuffer;
NAPI_CALL(env, napi_get_typedarray_info(env, args[0], NULL, NULL, NULL, &arraybuffer, NULL));
NAPI_CALL(env, napi_detach_arraybuffer(env, arraybuffer));

return NULL;
}

EXTERN_C_START EXTERN_C_START
napi_value Init(napi_env env, napi_value exports) { napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor descriptors[] = { napi_property_descriptor descriptors[] = {
DECLARE_NAPI_PROPERTY("Multiply", Multiply), DECLARE_NAPI_PROPERTY("Multiply", Multiply),
DECLARE_NAPI_PROPERTY("External", External), DECLARE_NAPI_PROPERTY("External", External),
DECLARE_NAPI_PROPERTY("CreateTypedArray", CreateTypedArray), DECLARE_NAPI_PROPERTY("CreateTypedArray", CreateTypedArray),
DECLARE_NAPI_PROPERTY("Detach", Detach),
}; };


NAPI_CALL(env, napi_define_properties( NAPI_CALL(env, napi_define_properties(
Expand Down

0 comments on commit 6afed1d

Please sign in to comment.