From c9563caa25bfb208f4dd8f0f0e55f0861bf057dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sun, 26 Jan 2020 00:30:38 -0400 Subject: [PATCH] src: add ArrayBuffer::Detach() and ::IsDetached() Refs: https://github.com/nodejs/node/pull/29768 Refs: https://github.com/nodejs/node/pull/30613 PR-URL: https://github.com/nodejs/node-addon-api/pull/659 Refs: https://github.com/nodejs/node/pull/29768 Refs: https://github.com/nodejs/node/pull/30613 Reviewed-By: Michael Dawson Reviewed-By: Gabriel Schulhof --- doc/array_buffer.md | 16 ++++++++++++++++ napi-inl.h | 14 ++++++++++++++ napi.h | 5 +++++ test/arraybuffer.cc | 38 +++++++++++++++++++++++++++++++------- test/arraybuffer.js | 5 +++++ 5 files changed, 71 insertions(+), 7 deletions(-) diff --git a/doc/array_buffer.md b/doc/array_buffer.md index 988a839a4..346fe6ace 100644 --- a/doc/array_buffer.md +++ b/doc/array_buffer.md @@ -130,4 +130,20 @@ void* Napi::ArrayBuffer::Data() const; Returns a pointer the wrapped data. +### Detach + +```cpp +void Napi::ArrayBuffer::Detach(); +``` + +Invokes the `ArrayBuffer` detach operation on a detachable `ArrayBuffer`. + +### IsDetached + +```cpp +bool Napi::ArrayBuffer::IsDetached() const; +``` + +Returns `true` if this `ArrayBuffer` has been detached. + [`Napi::Object`]: ./object.md diff --git a/napi-inl.h b/napi-inl.h index 5ecdd5046..5866fd89c 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -1530,6 +1530,20 @@ inline size_t ArrayBuffer::ByteLength() { return length; } +#if NAPI_VERSION >= 7 +inline bool ArrayBuffer::IsDetached() const { + bool detached; + napi_status status = napi_is_detached_arraybuffer(_env, _value, &detached); + NAPI_THROW_IF_FAILED(_env, status, false); + return detached; +} + +inline void ArrayBuffer::Detach() { + napi_status status = napi_detach_arraybuffer(_env, _value); + NAPI_THROW_IF_FAILED_VOID(_env, status); +} +#endif // NAPI_VERSION >= 7 + //////////////////////////////////////////////////////////////////////////////// // DataView class //////////////////////////////////////////////////////////////////////////////// diff --git a/napi.h b/napi.h index 76a62f659..945aac55e 100644 --- a/napi.h +++ b/napi.h @@ -822,6 +822,11 @@ namespace Napi { void* Data(); ///< Gets a pointer to the data buffer. size_t ByteLength(); ///< Gets the length of the array buffer in bytes. + +#if NAPI_VERSION >= 7 + bool IsDetached() const; + void Detach(); +#endif // NAPI_VERSION >= 7 }; /// A JavaScript typed-array value with unknown array type. diff --git a/test/arraybuffer.cc b/test/arraybuffer.cc index cc4f1f51c..4a1b2a34e 100644 --- a/test/arraybuffer.cc +++ b/test/arraybuffer.cc @@ -157,19 +157,43 @@ void CheckDetachUpdatesData(const CallbackInfo& info) { return; } - if (!info[1].IsFunction()) { - Error::New(info.Env(), "A function was expected.").ThrowAsJavaScriptException(); - return; - } - ArrayBuffer buffer = info[0].As(); - Function detach = info[1].As(); // This potentially causes the buffer to cache its data pointer and length. buffer.Data(); buffer.ByteLength(); - detach.Call({}); +#if NAPI_VERSION >= 7 + if (buffer.IsDetached()) { + Error::New(info.Env(), "Buffer should not be detached.").ThrowAsJavaScriptException(); + return; + } +#endif + + if (info.Length() == 2) { + // Detach externally (in JavaScript). + if (!info[1].IsFunction()) { + Error::New(info.Env(), "A function was expected.").ThrowAsJavaScriptException(); + return; + } + + Function detach = info[1].As(); + detach.Call({}); + } else { +#if NAPI_VERSION >= 7 + // Detach directly. + buffer.Detach(); +#else + return; +#endif + } + +#if NAPI_VERSION >= 7 + if (!buffer.IsDetached()) { + Error::New(info.Env(), "Buffer should be detached.").ThrowAsJavaScriptException(); + return; + } +#endif if (buffer.Data() != nullptr) { Error::New(info.Env(), "Incorrect data pointer.").ThrowAsJavaScriptException(); diff --git a/test/arraybuffer.js b/test/arraybuffer.js index 38d35d1e7..363de17d9 100644 --- a/test/arraybuffer.js +++ b/test/arraybuffer.js @@ -58,8 +58,13 @@ function test(binding) { 'ArrayBuffer updates data pointer and length when detached', () => { + // Detach the ArrayBuffer in JavaScript. const mem = new WebAssembly.Memory({ initial: 1 }); binding.arraybuffer.checkDetachUpdatesData(mem.buffer, () => mem.grow(1)); + + // Let C++ detach the ArrayBuffer. + const extBuffer = binding.arraybuffer.createExternalBuffer(); + binding.arraybuffer.checkDetachUpdatesData(extBuffer); }, ]); }