summaryrefslogtreecommitdiff
path: root/src/binding.cc
diff options
context:
space:
mode:
authorBert Belder <bertbelder@gmail.com>2018-07-09 03:35:34 +0200
committerBert Belder <bertbelder@gmail.com>2018-07-12 21:26:38 +0200
commit24b0e91d8096f84a114f662e3eb42c83d0d3878d (patch)
treeacd9ae306618276020e75450c064ead463e64387 /src/binding.cc
parentbbcd4c8dd33121868d82123a3d36e3df282af45f (diff)
Move buffers between V8 and native
* send()/recv() now operate on TypedArrays rather than ArrayBuffers. * Remove a copy (through ArrayBuffer.slice()) from the send path. * Remove a copy (through v8::ArrayBuffer::New()) from the return path. * After moving a buffer from JS to native, the ArrayBuffer object and it's views are made inaccessible ('neutered'). * `struct deno_buf` now holds two [ptr, length] tuples, one for the actual memory allocation, and one for the logical data contained therein. This is necessary because flatbuffers fills it's buffer bottom-up, so the serialized blob doesn't start at beginning of the buffer, but somewhere in the middle.
Diffstat (limited to 'src/binding.cc')
-rw-r--r--src/binding.cc55
1 files changed, 39 insertions, 16 deletions
diff --git a/src/binding.cc b/src/binding.cc
index 50b029b90..2c4b6f722 100644
--- a/src/binding.cc
+++ b/src/binding.cc
@@ -139,6 +139,34 @@ void Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
fflush(stdout);
}
+static v8::Local<v8::Uint8Array> ImportBuf(v8::Isolate* isolate, deno_buf buf) {
+ auto ab = v8::ArrayBuffer::New(
+ isolate, reinterpret_cast<void*>(buf.alloc_ptr), buf.alloc_len,
+ v8::ArrayBufferCreationMode::kInternalized);
+ auto view =
+ v8::Uint8Array::New(ab, buf.data_ptr - buf.alloc_ptr, buf.data_len);
+ return view;
+}
+
+static deno_buf ExportBuf(v8::Isolate* isolate,
+ v8::Local<v8::ArrayBufferView> view) {
+ auto ab = view->Buffer();
+ auto contents = ab->Externalize();
+
+ deno_buf buf;
+ buf.alloc_ptr = reinterpret_cast<uint8_t*>(contents.Data());
+ buf.alloc_len = contents.ByteLength();
+ buf.data_ptr = buf.alloc_ptr + view->ByteOffset();
+ buf.data_len = view->ByteLength();
+
+ // Prevent JS from modifying buffer contents after exporting.
+ ab->Neuter();
+
+ return buf;
+}
+
+static void FreeBuf(deno_buf buf) { free(buf.alloc_ptr); }
+
// Sets the recv callback.
void Recv(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
@@ -169,20 +197,21 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK_EQ(args.Length(), 1);
v8::Local<v8::Value> ab_v = args[0];
- CHECK(ab_v->IsArrayBuffer());
- auto ab = v8::Local<v8::ArrayBuffer>::Cast(ab_v);
- auto contents = ab->GetContents();
-
- // data is only a valid pointer until the end of this call.
- const char* data =
- const_cast<const char*>(reinterpret_cast<char*>(contents.Data()));
- deno_buf buf{data, contents.ByteLength()};
+ CHECK(ab_v->IsArrayBufferView());
+ auto buf = ExportBuf(isolate, v8::Local<v8::ArrayBufferView>::Cast(ab_v));
DCHECK_EQ(d->currentArgs, nullptr);
d->currentArgs = &args;
d->cb(d, buf);
+ // Buffer is only valid until the end of the callback.
+ // TODO(piscisaureus):
+ // It's possible that data in the buffer is needed after the callback
+ // returns, e.g. when the handler offloads work to a thread pool, therefore
+ // make the callback responsible for releasing the buffer.
+ FreeBuf(buf);
+
d->currentArgs = nullptr;
}
@@ -303,12 +332,8 @@ int deno_send(Deno* d, deno_buf buf) {
return 0;
}
- // TODO(ry) support zero-copy.
- auto ab = v8::ArrayBuffer::New(d->isolate, buf.len);
- memcpy(ab->GetContents().Data(), buf.data, buf.len);
-
v8::Local<v8::Value> args[1];
- args[0] = ab;
+ args[0] = deno::ImportBuf(d->isolate, buf);
recv->Call(context->Global(), 1, args);
if (try_catch.HasCaught()) {
@@ -320,9 +345,7 @@ int deno_send(Deno* d, deno_buf buf) {
}
void deno_set_response(Deno* d, deno_buf buf) {
- // TODO(ry) Support zero-copy.
- auto ab = v8::ArrayBuffer::New(d->isolate, buf.len);
- memcpy(ab->GetContents().Data(), buf.data, buf.len);
+ auto ab = deno::ImportBuf(d->isolate, buf);
d->currentArgs->GetReturnValue().Set(ab);
}