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"
#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;
namespace realm {

View File

@ -30,20 +30,12 @@ inline bool node::Value::is_array(v8::Isolate* isolate, const v8::Local<v8::Valu
template<>
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();
#else
// TODO: Implement this!
#endif
}
template<>
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();
#else
// TODO: Implement this!
#endif
}
template<>
@ -124,19 +116,14 @@ inline v8::Local<v8::Value> node::Value::from_string(v8::Isolate* isolate, const
template<>
inline v8::Local<v8::Value> node::Value::from_binary(v8::Isolate* isolate, BinaryData data) {
#if REALM_V8_ARRAY_BUFFER_API
size_t byte_count = data.size();
void* bytes = nullptr;
v8::Local<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, data.size());
v8::ArrayBuffer::Contents contents = buffer->GetContents();
if (byte_count) {
bytes = memcpy(malloc(byte_count), data.data(), byte_count);
if (data.size()) {
memcpy(contents.Data(), data.data(), data.size());
}
// An "internalized" ArrayBuffer will free the malloc'd memory when garbage collected.
return v8::ArrayBuffer::New(isolate, bytes, byte_count, v8::ArrayBufferCreationMode::kInternalized);
#else
// TODO: Implement this for older V8
#endif
return buffer;
}
template<>
@ -173,26 +160,25 @@ inline OwnedBinaryData node::Value::to_binary(v8::Isolate* isolate, v8::Local<v8
};
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::ArrayBuffer::Contents contents = array_buffer->GetContents();
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)) {
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)) {
return make_owned_binary_data(::node::Buffer::Data(value), ::node::Buffer::Length(value));
}
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");
}
}