Skip to content

Commit

Permalink
src: add ArrayBuffer::Detach() and ::IsDetached()
Browse files Browse the repository at this point in the history
Refs: nodejs/node#29768
Refs: nodejs/node#30613

PR-URL: nodejs/node-addon-api#659
Refs: nodejs/node#29768
Refs: nodejs/node#30613
Reviewed-By: Michael Dawson <midawson@redhat.com>
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
  • Loading branch information
kevindavies8 committed Nov 5, 2020
1 parent ffa38e4 commit ae16785
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 7 deletions.
16 changes: 16 additions & 0 deletions doc/array_buffer.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
14 changes: 14 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
////////////////////////////////////////////////////////////////////////////////
Expand Down
5 changes: 5 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
38 changes: 31 additions & 7 deletions test/arraybuffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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<ArrayBuffer>();
Function detach = info[1].As<Function>();

// 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<Function>();
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();
Expand Down
5 changes: 5 additions & 0 deletions test/arraybuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
]);
}

0 comments on commit ae16785

Please sign in to comment.