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:
Yavor Georgiev 2017-08-10 11:45:48 +02:00 committed by GitHub
parent bb3411f7f7
commit fb7f11263c
2 changed files with 12 additions and 30 deletions

View File

@ -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 {

View File

@ -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");
} }
} }