summaryrefslogtreecommitdiff
path: root/libdeno
diff options
context:
space:
mode:
Diffstat (limited to 'libdeno')
-rw-r--r--libdeno/api.cc47
-rw-r--r--libdeno/binding.cc61
-rw-r--r--libdeno/deno.h18
-rw-r--r--libdeno/internal.h31
-rw-r--r--libdeno/libdeno_test.cc63
-rw-r--r--libdeno/libdeno_test.js6
-rw-r--r--libdeno/modules_test.cc4
-rw-r--r--libdeno/test.cc2
-rw-r--r--libdeno/test.h2
9 files changed, 149 insertions, 85 deletions
diff --git a/libdeno/api.cc b/libdeno/api.cc
index 2601862a2..4cb7b846b 100644
--- a/libdeno/api.cc
+++ b/libdeno/api.cc
@@ -78,6 +78,19 @@ deno::DenoIsolate* unwrap(Deno* d_) {
return reinterpret_cast<deno::DenoIsolate*>(d_);
}
+void deno_lock(Deno* d_) {
+ auto* d = unwrap(d_);
+ CHECK_NULL(d->locker_);
+ d->locker_ = new v8::Locker(d->isolate_);
+}
+
+void deno_unlock(Deno* d_) {
+ auto* d = unwrap(d_);
+ CHECK_NOT_NULL(d->locker_);
+ delete d->locker_;
+ d->locker_ = nullptr;
+}
+
deno_buf deno_get_snapshot(Deno* d_) {
auto* d = unwrap(d_);
CHECK_NOT_NULL(d->snapshot_creator_);
@@ -87,7 +100,7 @@ deno_buf deno_get_snapshot(Deno* d_) {
auto blob = d->snapshot_creator_->CreateBlob(
v8::SnapshotCreator::FunctionCodeHandling::kKeep);
return {nullptr, 0, reinterpret_cast<uint8_t*>(const_cast<char*>(blob.data)),
- blob.raw_size};
+ blob.raw_size, 0};
}
static std::unique_ptr<v8::Platform> platform;
@@ -127,12 +140,23 @@ void deno_execute(Deno* d_, void* user_data, const char* js_filename,
deno::Execute(context, js_filename, js_source);
}
-void deno_respond(Deno* d_, void* user_data, int32_t req_id, deno_buf buf) {
+void deno_zero_copy_release(Deno* d_, size_t zero_copy_id) {
+ auto* d = unwrap(d_);
+ v8::Isolate::Scope isolate_scope(d->isolate_);
+ v8::Locker locker(d->isolate_);
+ v8::HandleScope handle_scope(d->isolate_);
+ d->DeleteZeroCopyRef(zero_copy_id);
+}
+
+void deno_respond(Deno* d_, void* user_data, deno_buf buf) {
auto* d = unwrap(d_);
if (d->current_args_ != nullptr) {
// Synchronous response.
- auto ab = deno::ImportBuf(d, buf);
- d->current_args_->GetReturnValue().Set(ab);
+ if (buf.data_ptr != nullptr) {
+ DCHECK_EQ(buf.zero_copy_id, 0);
+ auto ab = deno::ImportBuf(d, buf);
+ d->current_args_->GetReturnValue().Set(ab);
+ }
d->current_args_ = nullptr;
return;
}
@@ -148,8 +172,6 @@ void deno_respond(Deno* d_, void* user_data, int32_t req_id, deno_buf buf) {
v8::TryCatch try_catch(d->isolate_);
- deno::DeleteDataRef(d, req_id);
-
auto recv_ = d->recv_.Get(d->isolate_);
if (recv_.IsEmpty()) {
d->last_exception_ = "libdeno.recv_ has not been called.";
@@ -157,8 +179,17 @@ void deno_respond(Deno* d_, void* user_data, int32_t req_id, deno_buf buf) {
}
v8::Local<v8::Value> args[1];
- args[0] = deno::ImportBuf(d, buf);
- auto v = recv_->Call(context, context->Global(), 1, args);
+ int argc = 0;
+
+ // You cannot use zero_copy_buf with deno_respond(). Use
+ // deno_zero_copy_release() instead.
+ DCHECK_EQ(buf.zero_copy_id, 0);
+ if (buf.data_ptr != nullptr) {
+ args[0] = deno::ImportBuf(d, buf);
+ argc = 1;
+ }
+
+ auto v = recv_->Call(context, context->Global(), argc, args);
if (try_catch.HasCaught()) {
CHECK(v.IsEmpty());
diff --git a/libdeno/binding.cc b/libdeno/binding.cc
index f640fe83c..d4849db7b 100644
--- a/libdeno/binding.cc
+++ b/libdeno/binding.cc
@@ -44,20 +44,6 @@ v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
return {payload, size};
}
-void AddDataRef(DenoIsolate* d, int32_t req_id, v8::Local<v8::Value> data_v) {
- d->async_data_map_.emplace(std::piecewise_construct, std::make_tuple(req_id),
- std::make_tuple(d->isolate_, data_v));
-}
-
-void DeleteDataRef(DenoIsolate* d, int32_t req_id) {
- // Delete persistent reference to data ArrayBuffer.
- auto it = d->async_data_map_.find(req_id);
- if (it != d->async_data_map_.end()) {
- it->second.Reset();
- d->async_data_map_.erase(it);
- }
-}
-
// Extracts a C string from a v8::V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<string conversion failed>";
@@ -131,6 +117,13 @@ void ErrorToJSON(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
v8::Local<v8::Uint8Array> ImportBuf(DenoIsolate* d, deno_buf buf) {
+ // Do not use ImportBuf with zero_copy buffers.
+ DCHECK_EQ(buf.zero_copy_id, 0);
+
+ if (buf.data_ptr == nullptr) {
+ return v8::Local<v8::Uint8Array>();
+ }
+
if (buf.alloc_ptr == nullptr) {
// If alloc_ptr isn't set, we memcpy.
// This is currently used for flatbuffers created in Rust.
@@ -209,42 +202,44 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
DenoIsolate* d = DenoIsolate::FromIsolate(isolate);
DCHECK_EQ(d->isolate_, isolate);
- v8::Locker locker(d->isolate_);
+ deno_buf control = {nullptr, 0u, nullptr, 0u, 0u};
+ deno_buf zero_copy = {nullptr, 0u, nullptr, 0u, 0u};
+
v8::HandleScope handle_scope(isolate);
- CHECK_NULL(d->current_args_); // libdeno.send re-entry forbidden.
- int32_t req_id = d->next_req_id_++;
+ if (args.Length() > 0) {
+ v8::Local<v8::Value> control_v = args[0];
+ if (control_v->IsArrayBufferView()) {
+ control =
+ GetContents(isolate, v8::Local<v8::ArrayBufferView>::Cast(control_v));
+ }
+ }
- v8::Local<v8::Value> control_v = args[0];
- CHECK(control_v->IsArrayBufferView());
- deno_buf control =
- GetContents(isolate, v8::Local<v8::ArrayBufferView>::Cast(control_v));
- deno_buf data = {nullptr, 0u, nullptr, 0u};
- v8::Local<v8::Value> data_v;
+ v8::Local<v8::Value> zero_copy_v;
if (args.Length() == 2) {
if (args[1]->IsArrayBufferView()) {
- data_v = args[1];
- data = GetContents(isolate, v8::Local<v8::ArrayBufferView>::Cast(data_v));
+ zero_copy_v = args[1];
+ zero_copy = GetContents(
+ isolate, v8::Local<v8::ArrayBufferView>::Cast(zero_copy_v));
+ size_t zero_copy_id = d->next_zero_copy_id_++;
+ DCHECK_GT(zero_copy_id, 0);
+ zero_copy.zero_copy_id = zero_copy_id;
+ // If the zero_copy ArrayBuffer was given, we must maintain a strong
+ // reference to it until deno_zero_copy_release is called.
+ d->AddZeroCopyRef(zero_copy_id, zero_copy_v);
}
- } else {
- CHECK_EQ(args.Length(), 1);
}
DCHECK_NULL(d->current_args_);
d->current_args_ = &args;
- d->recv_cb_(d->user_data_, req_id, control, data);
+ d->recv_cb_(d->user_data_, control, zero_copy);
if (d->current_args_ == nullptr) {
// This indicates that deno_repond() was called already.
} else {
// Asynchronous.
d->current_args_ = nullptr;
- // If the data ArrayBuffer was given, we must maintain a strong reference
- // to it until deno_respond is called.
- if (!data_v.IsEmpty()) {
- AddDataRef(d, req_id, data_v);
- }
}
}
diff --git a/libdeno/deno.h b/libdeno/deno.h
index 6be0b5625..f3902985e 100644
--- a/libdeno/deno.h
+++ b/libdeno/deno.h
@@ -15,6 +15,7 @@ typedef struct {
size_t alloc_len; // Length of the memory allocation.
uint8_t* data_ptr; // Start of logical contents (within the allocation).
size_t data_len; // Length of logical contents.
+ size_t zero_copy_id; // 0 = normal, 1 = must call deno_zero_copy_release.
} deno_buf;
typedef struct deno_s Deno;
@@ -22,8 +23,8 @@ typedef struct deno_s Deno;
// A callback to receive a message from a libdeno.send() javascript call.
// control_buf is valid for only for the lifetime of this callback.
// data_buf is valid until deno_respond() is called.
-typedef void (*deno_recv_cb)(void* user_data, int32_t req_id,
- deno_buf control_buf, deno_buf data_buf);
+typedef void (*deno_recv_cb)(void* user_data, deno_buf control_buf,
+ deno_buf zerop_copy_buf);
void deno_init();
const char* deno_v8_version();
@@ -47,6 +48,9 @@ deno_buf deno_get_snapshot(Deno* d);
void deno_delete(Deno* d);
+void deno_lock(Deno* d);
+void deno_unlock(Deno* d);
+
// Compile and execute a traditional JavaScript script that does not use
// module import statements.
// If it succeeded deno_last_exception() will return NULL.
@@ -66,11 +70,13 @@ void deno_execute(Deno* d, void* user_data, const char* js_filename,
// longer owns `buf` and must not use it; deno_respond() is responsible for
// releasing its memory.)
//
-// Calling this function more than once with the same req_id will result in
-// an error.
-//
// If a JS exception was encountered, deno_last_exception() will be non-NULL.
-void deno_respond(Deno* d, void* user_data, int32_t req_id, deno_buf buf);
+void deno_respond(Deno* d, void* user_data, deno_buf buf);
+
+// consumes zero_copy
+// Calling this function more than once with the same zero_copy_id will result
+// in an error.
+void deno_zero_copy_release(Deno* d, size_t zero_copy_id);
void deno_check_promise_errors(Deno* d);
diff --git a/libdeno/internal.h b/libdeno/internal.h
index 720966407..563043085 100644
--- a/libdeno/internal.h
+++ b/libdeno/internal.h
@@ -30,12 +30,13 @@ class DenoIsolate {
public:
explicit DenoIsolate(deno_config config)
: isolate_(nullptr),
+ locker_(nullptr),
shared_(config.shared),
current_args_(nullptr),
snapshot_creator_(nullptr),
global_import_buf_ptr_(nullptr),
recv_cb_(config.recv_cb),
- next_req_id_(0),
+ next_zero_copy_id_(1), // zero_copy_id must not be zero.
user_data_(nullptr),
resolve_cb_(nullptr) {
array_buffer_allocator_ = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
@@ -48,6 +49,9 @@ class DenoIsolate {
~DenoIsolate() {
shared_ab_.Reset();
+ if (locker_) {
+ delete locker_;
+ }
if (snapshot_creator_) {
delete snapshot_creator_;
} else {
@@ -78,14 +82,31 @@ class DenoIsolate {
}
}
+ void DeleteZeroCopyRef(size_t zero_copy_id) {
+ DCHECK_NE(zero_copy_id, 0);
+ // Delete persistent reference to data ArrayBuffer.
+ auto it = zero_copy_map_.find(zero_copy_id);
+ if (it != zero_copy_map_.end()) {
+ it->second.Reset();
+ zero_copy_map_.erase(it);
+ }
+ }
+
+ void AddZeroCopyRef(size_t zero_copy_id, v8::Local<v8::Value> zero_copy_v) {
+ zero_copy_map_.emplace(std::piecewise_construct,
+ std::make_tuple(zero_copy_id),
+ std::make_tuple(isolate_, zero_copy_v));
+ }
+
v8::Isolate* isolate_;
+ v8::Locker* locker_;
v8::ArrayBuffer::Allocator* array_buffer_allocator_;
deno_buf shared_;
const v8::FunctionCallbackInfo<v8::Value>* current_args_;
v8::SnapshotCreator* snapshot_creator_;
void* global_import_buf_ptr_;
deno_recv_cb recv_cb_;
- int32_t next_req_id_;
+ size_t next_zero_copy_id_;
void* user_data_;
v8::Persistent<v8::Object> builtin_modules_;
@@ -94,7 +115,7 @@ class DenoIsolate {
deno_resolve_cb resolve_cb_;
v8::Persistent<v8::Context> context_;
- std::map<int32_t, v8::Persistent<v8::Value>> async_data_map_;
+ std::map<size_t, v8::Persistent<v8::Value>> zero_copy_map_;
std::map<int, v8::Persistent<v8::Value>> pending_promise_map_;
std::string last_exception_;
v8::Persistent<v8::Function> recv_;
@@ -152,7 +173,7 @@ static intptr_t external_references[] = {
reinterpret_cast<intptr_t>(MessageCallback),
0};
-static const deno_buf empty_buf = {nullptr, 0, nullptr, 0};
+static const deno_buf empty_buf = {nullptr, 0, nullptr, 0, 0};
Deno* NewFromSnapshot(void* user_data, deno_recv_cb cb);
@@ -166,8 +187,6 @@ v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
v8::Local<v8::Uint8Array> ImportBuf(DenoIsolate* d, deno_buf buf);
-void DeleteDataRef(DenoIsolate* d, int32_t req_id);
-
bool Execute(v8::Local<v8::Context> context, const char* js_filename,
const char* js_source);
bool ExecuteMod(v8::Local<v8::Context> context, const char* js_filename,
diff --git a/libdeno/libdeno_test.cc b/libdeno/libdeno_test.cc
index 3193e7677..90fceef73 100644
--- a/libdeno/libdeno_test.cc
+++ b/libdeno/libdeno_test.cc
@@ -26,9 +26,11 @@ TEST(LibDenoTest, Snapshotter) {
TEST(LibDenoTest, CanCallFunction) {
Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr});
+ deno_lock(d);
deno_execute(d, nullptr, "a.js",
"if (CanCallFunction() != 'foo') throw Error();");
EXPECT_EQ(nullptr, deno_last_exception(d));
+ deno_unlock(d);
deno_delete(d);
}
@@ -47,6 +49,7 @@ deno_buf strbuf(const char* str) {
buf.alloc_len = len + 1;
buf.data_ptr = buf.alloc_ptr;
buf.data_len = len;
+ buf.zero_copy_id = 0;
return buf;
}
@@ -71,8 +74,8 @@ void assert_null(deno_buf b) {
TEST(LibDenoTest, RecvReturnEmpty) {
static int count = 0;
- auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) {
- assert_null(data_buf);
+ auto recv_cb = [](auto _, auto buf, auto zero_copy_buf) {
+ assert_null(zero_copy_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
@@ -88,15 +91,17 @@ TEST(LibDenoTest, RecvReturnEmpty) {
TEST(LibDenoTest, RecvReturnBar) {
static int count = 0;
- auto recv_cb = [](auto user_data, int req_id, auto buf, auto data_buf) {
+ auto recv_cb = [](auto user_data, auto buf, auto zero_copy_buf) {
auto d = reinterpret_cast<Deno*>(user_data);
- assert_null(data_buf);
+ assert_null(zero_copy_buf);
count++;
EXPECT_EQ(static_cast<size_t>(3), buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 'a');
EXPECT_EQ(buf.data_ptr[1], 'b');
EXPECT_EQ(buf.data_ptr[2], 'c');
- deno_respond(d, user_data, req_id, strbuf("bar"));
+ EXPECT_EQ(zero_copy_buf.zero_copy_id, 0u);
+ EXPECT_EQ(zero_copy_buf.data_ptr, nullptr);
+ deno_respond(d, user_data, strbuf("bar"));
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
deno_execute(d, d, "a.js", "RecvReturnBar()");
@@ -114,9 +119,9 @@ TEST(LibDenoTest, DoubleRecvFails) {
TEST(LibDenoTest, SendRecvSlice) {
static int count = 0;
- auto recv_cb = [](auto user_data, int req_id, auto buf, auto data_buf) {
+ auto recv_cb = [](auto user_data, auto buf, auto zero_copy_buf) {
auto d = reinterpret_cast<Deno*>(user_data);
- assert_null(data_buf);
+ assert_null(zero_copy_buf);
static const size_t alloc_len = 1024;
size_t i = count++;
// Check the size and offset of the slice.
@@ -134,12 +139,12 @@ TEST(LibDenoTest, SendRecvSlice) {
memcpy(alloc_ptr, buf.alloc_ptr, alloc_len);
// Make a slice that is a bit shorter than the original.
deno_buf buf2{alloc_ptr, alloc_len, alloc_ptr + data_offset,
- buf.data_len - 19};
+ buf.data_len - 19, 0};
// Place some values into the buffer for the JS side to verify.
buf2.data_ptr[0] = 200 + i;
buf2.data_ptr[buf2.data_len - 1] = 200 - i;
// Send back.
- deno_respond(d, user_data, req_id, buf2);
+ deno_respond(d, user_data, buf2);
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
deno_execute(d, d, "a.js", "SendRecvSlice()");
@@ -150,8 +155,8 @@ TEST(LibDenoTest, SendRecvSlice) {
TEST(LibDenoTest, JSSendArrayBufferViewTypes) {
static int count = 0;
- auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) {
- assert_null(data_buf);
+ auto recv_cb = [](auto _, auto buf, auto zero_copy_buf) {
+ assert_null(zero_copy_buf);
count++;
size_t data_offset = buf.data_ptr - buf.alloc_ptr;
EXPECT_EQ(data_offset, 2468u);
@@ -197,33 +202,39 @@ TEST(LibDenoTest, GlobalErrorHandling) {
deno_delete(d);
}
-TEST(LibDenoTest, DataBuf) {
+TEST(LibDenoTest, ZeroCopyBuf) {
static int count = 0;
- static deno_buf data_buf_copy;
- auto recv_cb = [](auto _, int req_id, deno_buf buf, deno_buf data_buf) {
+ static deno_buf zero_copy_buf2;
+ auto recv_cb = [](auto user_data, deno_buf buf, deno_buf zero_copy_buf) {
count++;
- data_buf.data_ptr[0] = 4;
- data_buf.data_ptr[1] = 2;
- data_buf_copy = data_buf;
+ EXPECT_GT(zero_copy_buf.zero_copy_id, 0u);
+ zero_copy_buf.data_ptr[0] = 4;
+ zero_copy_buf.data_ptr[1] = 2;
+ zero_copy_buf2 = zero_copy_buf;
EXPECT_EQ(2u, buf.data_len);
- EXPECT_EQ(2u, data_buf.data_len);
+ EXPECT_EQ(2u, zero_copy_buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 1);
EXPECT_EQ(buf.data_ptr[1], 2);
+ // Note zero_copy_buf won't actually be freed here because in
+ // libdeno_test.js zeroCopyBuf is a rooted global. We just want to exercise
+ // the API here.
+ auto d = reinterpret_cast<Deno*>(user_data);
+ deno_zero_copy_release(d, zero_copy_buf.zero_copy_id);
};
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
- deno_execute(d, nullptr, "a.js", "DataBuf()");
+ deno_execute(d, d, "a.js", "ZeroCopyBuf()");
EXPECT_EQ(nullptr, deno_last_exception(d));
EXPECT_EQ(count, 1);
- // data_buf was subsequently changed in JS, let's check that our copy reflects
- // that.
- EXPECT_EQ(data_buf_copy.data_ptr[0], 9);
- EXPECT_EQ(data_buf_copy.data_ptr[1], 8);
+ // zero_copy_buf was subsequently changed in JS, let's check that our copy
+ // reflects that.
+ EXPECT_EQ(zero_copy_buf2.data_ptr[0], 9);
+ EXPECT_EQ(zero_copy_buf2.data_ptr[1], 8);
deno_delete(d);
}
TEST(LibDenoTest, CheckPromiseErrors) {
static int count = 0;
- auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) { count++; };
+ auto recv_cb = [](auto _, auto buf, auto zero_copy_buf) { count++; };
Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb});
EXPECT_EQ(deno_last_exception(d), nullptr);
deno_execute(d, nullptr, "a.js", "CheckPromiseErrors()");
@@ -271,7 +282,7 @@ TEST(LibDenoTest, EncodeErrorBug) {
TEST(LibDenoTest, Shared) {
uint8_t s[] = {0, 1, 2};
- deno_buf shared = {nullptr, 0, s, 3};
+ deno_buf shared = {nullptr, 0, s, 3, 0};
Deno* d = deno_new(deno_config{0, snapshot, shared, nullptr});
deno_execute(d, nullptr, "a.js", "Shared()");
EXPECT_EQ(nullptr, deno_last_exception(d));
@@ -306,7 +317,7 @@ TEST(LibDenoTest, LibDenoEvalContextError) {
TEST(LibDenoTest, SharedAtomics) {
int32_t s[] = {0, 1, 2};
- deno_buf shared = {nullptr, 0, reinterpret_cast<uint8_t*>(s), sizeof s};
+ deno_buf shared = {nullptr, 0, reinterpret_cast<uint8_t*>(s), sizeof s, 0};
Deno* d = deno_new(deno_config{0, empty, shared, nullptr});
deno_execute(d, nullptr, "a.js",
"Atomics.add(new Int32Array(libdeno.shared), 0, 1)");
diff --git a/libdeno/libdeno_test.js b/libdeno/libdeno_test.js
index d6ea5f983..8b1ad2e04 100644
--- a/libdeno/libdeno_test.js
+++ b/libdeno/libdeno_test.js
@@ -103,11 +103,11 @@ global.GlobalErrorHandling = () => {
};
// Allocate this buf at the top level to avoid GC.
-const dataBuf = new Uint8Array([3, 4]);
+const zeroCopyBuf = new Uint8Array([3, 4]);
-global.DataBuf = () => {
+global.ZeroCopyBuf = () => {
const a = new Uint8Array([1, 2]);
- const b = dataBuf;
+ const b = zeroCopyBuf;
// The second parameter of send should modified by the
// privileged side.
const r = libdeno.send(a, b);
diff --git a/libdeno/modules_test.cc b/libdeno/modules_test.cc
index d41c38b8e..cb800e89a 100644
--- a/libdeno/modules_test.cc
+++ b/libdeno/modules_test.cc
@@ -2,10 +2,12 @@
#include "test.h"
static int exec_count = 0;
-void recv_cb(void* user_data, int req_id, deno_buf buf, deno_buf data_buf) {
+void recv_cb(void* user_data, deno_buf buf, deno_buf zero_copy_buf) {
// We use this to check that scripts have executed.
EXPECT_EQ(1u, buf.data_len);
EXPECT_EQ(buf.data_ptr[0], 4);
+ EXPECT_EQ(zero_copy_buf.zero_copy_id, 0u);
+ EXPECT_EQ(zero_copy_buf.data_ptr, nullptr);
exec_count++;
}
diff --git a/libdeno/test.cc b/libdeno/test.cc
index a8fcbc63b..1340fe8c3 100644
--- a/libdeno/test.cc
+++ b/libdeno/test.cc
@@ -3,7 +3,7 @@
#include <string>
#include "file_util.h"
-deno_buf snapshot = {nullptr, 0, nullptr, 0};
+deno_buf snapshot = {nullptr, 0, nullptr, 0, 0};
int main(int argc, char** argv) {
// Locate the snapshot.
diff --git a/libdeno/test.h b/libdeno/test.h
index 25ca93988..2f7c32384 100644
--- a/libdeno/test.h
+++ b/libdeno/test.h
@@ -6,6 +6,6 @@
#include "testing/gtest/include/gtest/gtest.h"
extern deno_buf snapshot; // Loaded in libdeno/test.cc
-const deno_buf empty = {nullptr, 0, nullptr, 0};
+const deno_buf empty = {nullptr, 0, nullptr, 0, 0};
#endif // TEST_H_