Modernize V8 ArrayBuffer usage (#1198)
Instead of manually allocating a chunk of memory and asking V8 to create an ArrayBuffer around it, have V8 create an ArrayBuffer with its own allocator and copy the data in it. (fixes #1197) Remove an extra copy when reading data from ArrayBufferViews. Remove TODOs for Node.js versions older than 4.
This commit is contained in:
parent
bb3411f7f7
commit
fb7f11263c
|
@ -30,10 +30,6 @@
|
||||||
|
|
||||||
#include "js_types.hpp"
|
#include "js_types.hpp"
|
||||||
|
|
||||||
#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
|
|
||||||
#define REALM_V8_ARRAY_BUFFER_API 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define HANDLESCOPE Nan::HandleScope handle_scope;
|
#define HANDLESCOPE Nan::HandleScope handle_scope;
|
||||||
|
|
||||||
namespace realm {
|
namespace realm {
|
||||||
|
|
|
@ -30,20 +30,12 @@ inline bool node::Value::is_array(v8::Isolate* isolate, const v8::Local<v8::Valu
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline bool node::Value::is_array_buffer(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
inline bool node::Value::is_array_buffer(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
||||||
#if REALM_V8_ARRAY_BUFFER_API
|
|
||||||
return value->IsArrayBuffer();
|
return value->IsArrayBuffer();
|
||||||
#else
|
|
||||||
// TODO: Implement this!
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline bool node::Value::is_array_buffer_view(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
inline bool node::Value::is_array_buffer_view(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
||||||
#if REALM_V8_ARRAY_BUFFER_API
|
|
||||||
return value->IsArrayBufferView();
|
return value->IsArrayBufferView();
|
||||||
#else
|
|
||||||
// TODO: Implement this!
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -124,19 +116,14 @@ inline v8::Local<v8::Value> node::Value::from_string(v8::Isolate* isolate, const
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
inline v8::Local<v8::Value> node::Value::from_binary(v8::Isolate* isolate, BinaryData data) {
|
inline v8::Local<v8::Value> node::Value::from_binary(v8::Isolate* isolate, BinaryData data) {
|
||||||
#if REALM_V8_ARRAY_BUFFER_API
|
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, data.size());
|
||||||
size_t byte_count = data.size();
|
v8::ArrayBuffer::Contents contents = buffer->GetContents();
|
||||||
void* bytes = nullptr;
|
|
||||||
|
|
||||||
if (byte_count) {
|
if (data.size()) {
|
||||||
bytes = memcpy(malloc(byte_count), data.data(), byte_count);
|
memcpy(contents.Data(), data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// An "internalized" ArrayBuffer will free the malloc'd memory when garbage collected.
|
return buffer;
|
||||||
return v8::ArrayBuffer::New(isolate, bytes, byte_count, v8::ArrayBufferCreationMode::kInternalized);
|
|
||||||
#else
|
|
||||||
// TODO: Implement this for older V8
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -173,26 +160,25 @@ inline OwnedBinaryData node::Value::to_binary(v8::Isolate* isolate, v8::Local<v8
|
||||||
};
|
};
|
||||||
|
|
||||||
if (Value::is_array_buffer(isolate, value)) {
|
if (Value::is_array_buffer(isolate, value)) {
|
||||||
// TODO: This probably needs some abstraction for older V8.
|
|
||||||
#if REALM_V8_ARRAY_BUFFER_API
|
|
||||||
v8::Local<v8::ArrayBuffer> array_buffer = value.As<v8::ArrayBuffer>();
|
v8::Local<v8::ArrayBuffer> array_buffer = value.As<v8::ArrayBuffer>();
|
||||||
v8::ArrayBuffer::Contents contents = array_buffer->GetContents();
|
v8::ArrayBuffer::Contents contents = array_buffer->GetContents();
|
||||||
|
|
||||||
return make_owned_binary_data(static_cast<char*>(contents.Data()), contents.ByteLength());
|
return make_owned_binary_data(static_cast<char*>(contents.Data()), contents.ByteLength());
|
||||||
#else
|
|
||||||
// TODO: Implement this for older V8
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (Value::is_array_buffer_view(isolate, value)) {
|
else if (Value::is_array_buffer_view(isolate, value)) {
|
||||||
Nan::TypedArrayContents<char> contents(value);
|
v8::Local<v8::ArrayBufferView> array_buffer_view = value.As<v8::ArrayBufferView>();
|
||||||
|
std::unique_ptr<char[]> data(new char[array_buffer_view->ByteLength()]);
|
||||||
|
|
||||||
return make_owned_binary_data(*contents, contents.length());
|
size_t bytes = array_buffer_view->CopyContents(data.get(), array_buffer_view->ByteLength());
|
||||||
|
OwnedData owned_data(std::move(data), bytes);
|
||||||
|
|
||||||
|
return *reinterpret_cast<OwnedBinaryData*>(&owned_data);
|
||||||
}
|
}
|
||||||
else if (::node::Buffer::HasInstance(value)) {
|
else if (::node::Buffer::HasInstance(value)) {
|
||||||
return make_owned_binary_data(::node::Buffer::Data(value), ::node::Buffer::Length(value));
|
return make_owned_binary_data(::node::Buffer::Data(value), ::node::Buffer::Length(value));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw std::runtime_error("Can only convert Buffer, ArrayBuffer, and TypedArray objects to binary");
|
throw std::runtime_error("Can only convert Buffer, ArrayBuffer, and ArrayBufferView objects to binary");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue