diff --git a/js/libdeno.ts b/js/libdeno.ts index 623bfeea28..9745365b0f 100644 --- a/js/libdeno.ts +++ b/js/libdeno.ts @@ -17,6 +17,8 @@ interface Libdeno { print(x: string, isErr?: boolean): void; + shared: ArrayBuffer; + setGlobalErrorHandler: ( handler: ( message: string, diff --git a/libdeno/api.cc b/libdeno/api.cc index 5122527374..6ee2c934f4 100644 --- a/libdeno/api.cc +++ b/libdeno/api.cc @@ -13,8 +13,8 @@ extern "C" { -Deno* deno_new(deno_buf snapshot, deno_recv_cb cb) { - deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, cb); +Deno* deno_new(deno_buf snapshot, deno_buf shared, deno_recv_cb cb) { + deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, cb, shared); v8::Isolate::CreateParams params; params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); @@ -42,11 +42,12 @@ Deno* deno_new(deno_buf snapshot, deno_recv_cb cb) { return reinterpret_cast(d); } -Deno* deno_new_snapshotter(deno_recv_cb cb, const char* js_filename, - const char* js_source, const char* source_map) { +Deno* deno_new_snapshotter(deno_buf shared, deno_recv_cb cb, + const char* js_filename, const char* js_source, + const char* source_map) { auto* creator = new v8::SnapshotCreator(deno::external_references); auto* isolate = creator->GetIsolate(); - auto* d = new deno::DenoIsolate(deno::empty_buf, cb); + auto* d = new deno::DenoIsolate(deno::empty_buf, cb, shared); d->snapshot_creator_ = creator; d->AddIsolate(isolate); v8::Isolate::Scope isolate_scope(isolate); diff --git a/libdeno/binding.cc b/libdeno/binding.cc index 686defffac..6cf0a7a21c 100644 --- a/libdeno/binding.cc +++ b/libdeno/binding.cc @@ -339,6 +339,26 @@ void Send(const v8::FunctionCallbackInfo& args) { } } +void Shared(v8::Local property, + const v8::PropertyCallbackInfo& info) { + v8::Isolate* isolate = info.GetIsolate(); + DenoIsolate* d = FromIsolate(isolate); + DCHECK_EQ(d->isolate_, isolate); + v8::Locker locker(d->isolate_); + v8::EscapableHandleScope handle_scope(isolate); + if (d->shared_.data_ptr == nullptr) { + return; + } + v8::Local ab; + if (d->shared_ab_.IsEmpty()) { + // Lazily initialize the persistent external ArrayBuffer. + ab = v8::ArrayBuffer::New(isolate, d->shared_.data_ptr, d->shared_.data_len, + v8::ArrayBufferCreationMode::kExternalized); + d->shared_ab_.Reset(isolate, ab); + } + info.GetReturnValue().Set(ab); +} + // Sets the global error handler. void SetGlobalErrorHandler(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); @@ -470,6 +490,9 @@ void InitializeContext(v8::Isolate* isolate, v8::Local context, auto send_val = send_tmpl->GetFunction(context).ToLocalChecked(); CHECK(deno_val->Set(context, deno::v8_str("send"), send_val).FromJust()); + CHECK(deno_val->SetAccessor(context, deno::v8_str("shared"), Shared) + .FromJust()); + auto set_global_error_handler_tmpl = v8::FunctionTemplate::New(isolate, SetGlobalErrorHandler); auto set_global_error_handler_val = diff --git a/libdeno/deno.h b/libdeno/deno.h index c29bfc0bbb..96d1298c14 100644 --- a/libdeno/deno.h +++ b/libdeno/deno.h @@ -29,10 +29,11 @@ void deno_init(); const char* deno_v8_version(); void deno_set_v8_flags(int* argc, char** argv); -Deno* deno_new(deno_buf snapshot, deno_recv_cb cb); +Deno* deno_new(deno_buf snapshot, deno_buf shared, deno_recv_cb cb); -Deno* deno_new_snapshotter(deno_recv_cb cb, const char* js_filename, - const char* js_source, const char* source_map); +Deno* deno_new_snapshotter(deno_buf shared, deno_recv_cb cb, + const char* js_filename, const char* js_source, + const char* source_map); deno_buf deno_get_snapshot(Deno* d); void deno_delete(Deno* d); diff --git a/libdeno/internal.h b/libdeno/internal.h index 6816debecf..a996a00086 100644 --- a/libdeno/internal.h +++ b/libdeno/internal.h @@ -13,8 +13,9 @@ namespace deno { // deno_s = Wrapped Isolate. class DenoIsolate { public: - DenoIsolate(deno_buf snapshot, deno_recv_cb cb) + DenoIsolate(deno_buf snapshot, deno_recv_cb cb, deno_buf shared) : isolate_(nullptr), + shared_(shared), current_args_(nullptr), snapshot_creator_(nullptr), global_import_buf_ptr_(nullptr), @@ -31,6 +32,7 @@ class DenoIsolate { void AddIsolate(v8::Isolate* isolate); v8::Isolate* isolate_; + deno_buf shared_; const v8::FunctionCallbackInfo* current_args_; v8::SnapshotCreator* snapshot_creator_; void* global_import_buf_ptr_; @@ -48,6 +50,7 @@ class DenoIsolate { v8::Persistent promise_error_examiner_; v8::StartupData snapshot_; v8::Persistent global_import_buf_; + v8::Persistent shared_ab_; }; class UserDataScope { @@ -75,6 +78,8 @@ struct InternalFieldData { void Print(const v8::FunctionCallbackInfo& args); void Recv(const v8::FunctionCallbackInfo& args); void Send(const v8::FunctionCallbackInfo& args); +void Shared(v8::Local property, + const v8::PropertyCallbackInfo& info); void SetGlobalErrorHandler(const v8::FunctionCallbackInfo& args); void SetPromiseRejectHandler(const v8::FunctionCallbackInfo& args); void SetPromiseErrorExaminer(const v8::FunctionCallbackInfo& args); @@ -82,6 +87,7 @@ static intptr_t external_references[] = { reinterpret_cast(Print), reinterpret_cast(Recv), reinterpret_cast(Send), + reinterpret_cast(Shared), reinterpret_cast(SetGlobalErrorHandler), reinterpret_cast(SetPromiseRejectHandler), reinterpret_cast(SetPromiseErrorExaminer), diff --git a/libdeno/libdeno_test.cc b/libdeno/libdeno_test.cc index 54285566fc..7e7cd966c3 100644 --- a/libdeno/libdeno_test.cc +++ b/libdeno/libdeno_test.cc @@ -2,40 +2,38 @@ #include "test.h" TEST(LibDenoTest, InitializesCorrectly) { - printf("snapshot.data_ptr %p\n", snapshot.data_ptr); EXPECT_NE(snapshot.data_ptr, nullptr); - Deno* d = deno_new(empty, nullptr); + Deno* d = deno_new(snapshot, empty, nullptr); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2")); deno_delete(d); } TEST(LibDenoTest, InitializesCorrectlyWithoutSnapshot) { - deno_buf empty = {nullptr, 0, nullptr, 0}; - Deno* d = deno_new(empty, nullptr); + Deno* d = deno_new(empty, empty, nullptr); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2")); deno_delete(d); } TEST(LibDenoTest, Snapshotter) { - Deno* d1 = deno_new_snapshotter(nullptr, "a.js", "a = 1 + 2", nullptr); + Deno* d1 = deno_new_snapshotter(empty, nullptr, "a.js", "a = 1 + 2", nullptr); deno_buf test_snapshot = deno_get_snapshot(d1); // TODO(ry) deno_delete(d1); - Deno* d2 = deno_new(test_snapshot, nullptr); + Deno* d2 = deno_new(test_snapshot, empty, nullptr); EXPECT_TRUE( deno_execute(d2, nullptr, "b.js", "if (a != 3) throw Error('x');")); deno_delete(d2); } TEST(LibDenoTest, CanCallFunction) { - Deno* d = deno_new(snapshot, nullptr); + Deno* d = deno_new(snapshot, empty, nullptr); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "if (CanCallFunction() != 'foo') throw Error();")); deno_delete(d); } TEST(LibDenoTest, ErrorsCorrectly) { - Deno* d = deno_new(snapshot, nullptr); + Deno* d = deno_new(snapshot, empty, nullptr); EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "throw Error()")); deno_delete(d); } @@ -72,14 +70,15 @@ void assert_null(deno_buf b) { TEST(LibDenoTest, RecvReturnEmpty) { static int count = 0; - Deno* d = deno_new(snapshot, [](auto _, int req_id, auto buf, auto data_buf) { - assert_null(data_buf); - count++; - EXPECT_EQ(static_cast(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* d = deno_new(snapshot, empty, + [](auto _, int req_id, auto buf, auto data_buf) { + assert_null(data_buf); + count++; + EXPECT_EQ(static_cast(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'); + }); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "RecvReturnEmpty()")); EXPECT_EQ(count, 2); deno_delete(d); @@ -87,7 +86,7 @@ TEST(LibDenoTest, RecvReturnEmpty) { TEST(LibDenoTest, RecvReturnBar) { static int count = 0; - Deno* d = deno_new(snapshot, + Deno* d = deno_new(snapshot, empty, [](auto user_data, int req_id, auto buf, auto data_buf) { auto d = reinterpret_cast(user_data); assert_null(data_buf); @@ -104,7 +103,7 @@ TEST(LibDenoTest, RecvReturnBar) { } TEST(LibDenoTest, DoubleRecvFails) { - Deno* d = deno_new(snapshot, nullptr); + Deno* d = deno_new(snapshot, empty, nullptr); EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "DoubleRecvFails()")); deno_delete(d); } @@ -112,7 +111,7 @@ TEST(LibDenoTest, DoubleRecvFails) { TEST(LibDenoTest, SendRecvSlice) { static int count = 0; Deno* d = deno_new( - snapshot, [](auto user_data, int req_id, auto buf, auto data_buf) { + snapshot, empty, [](auto user_data, int req_id, auto buf, auto data_buf) { auto d = reinterpret_cast(user_data); assert_null(data_buf); static const size_t alloc_len = 1024; @@ -146,47 +145,49 @@ TEST(LibDenoTest, SendRecvSlice) { TEST(LibDenoTest, JSSendArrayBufferViewTypes) { static int count = 0; - Deno* d = deno_new(snapshot, [](auto _, int req_id, auto buf, auto data_buf) { - assert_null(data_buf); - count++; - size_t data_offset = buf.data_ptr - buf.alloc_ptr; - EXPECT_EQ(data_offset, 2468u); - EXPECT_EQ(buf.data_len, 1000u); - EXPECT_EQ(buf.alloc_len, 4321u); - EXPECT_EQ(buf.data_ptr[0], count); - }); + Deno* d = deno_new(snapshot, empty, + [](auto _, int req_id, auto buf, auto data_buf) { + assert_null(data_buf); + count++; + size_t data_offset = buf.data_ptr - buf.alloc_ptr; + EXPECT_EQ(data_offset, 2468u); + EXPECT_EQ(buf.data_len, 1000u); + EXPECT_EQ(buf.alloc_len, 4321u); + EXPECT_EQ(buf.data_ptr[0], count); + }); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "JSSendArrayBufferViewTypes()")); EXPECT_EQ(count, 3); deno_delete(d); } TEST(LibDenoTest, TypedArraySnapshots) { - Deno* d = deno_new(snapshot, nullptr); + Deno* d = deno_new(snapshot, empty, nullptr); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "TypedArraySnapshots()")); deno_delete(d); } TEST(LibDenoTest, SnapshotBug) { - Deno* d = deno_new(snapshot, nullptr); + Deno* d = deno_new(snapshot, empty, nullptr); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "SnapshotBug()")); deno_delete(d); } TEST(LibDenoTest, GlobalErrorHandling) { static int count = 0; - Deno* d = deno_new(snapshot, [](auto _, int req_id, auto buf, auto data_buf) { - assert_null(data_buf); - count++; - EXPECT_EQ(static_cast(1), buf.data_len); - EXPECT_EQ(buf.data_ptr[0], 42); - }); + Deno* d = deno_new(snapshot, empty, + [](auto _, int req_id, auto buf, auto data_buf) { + assert_null(data_buf); + count++; + EXPECT_EQ(static_cast(1), buf.data_len); + EXPECT_EQ(buf.data_ptr[0], 42); + }); EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "GlobalErrorHandling()")); EXPECT_EQ(count, 1); deno_delete(d); } TEST(LibDenoTest, DoubleGlobalErrorHandlingFails) { - Deno* d = deno_new(snapshot, nullptr); + Deno* d = deno_new(snapshot, empty, nullptr); EXPECT_FALSE( deno_execute(d, nullptr, "a.js", "DoubleGlobalErrorHandlingFails()")); deno_delete(d); @@ -195,7 +196,7 @@ TEST(LibDenoTest, DoubleGlobalErrorHandlingFails) { TEST(LibDenoTest, DataBuf) { static int count = 0; static deno_buf data_buf_copy; - Deno* d = deno_new(snapshot, + Deno* d = deno_new(snapshot, empty, [](auto _, int req_id, deno_buf buf, deno_buf data_buf) { count++; data_buf.data_ptr[0] = 4; @@ -217,12 +218,25 @@ TEST(LibDenoTest, DataBuf) { TEST(LibDenoTest, PromiseRejectCatchHandling) { static int count = 0; - Deno* d = deno_new(snapshot, [](auto _, int req_id, auto buf, auto data_buf) { - // If no error, nothing should be sent, and count should not increment - count++; - }); + Deno* d = deno_new(snapshot, empty, + [](auto _, int req_id, auto buf, auto data_buf) { + // If no error, nothing should be sent, and count should + // not increment + count++; + }); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "PromiseRejectCatchHandling()")); EXPECT_EQ(count, 0); deno_delete(d); } + +TEST(LibDenoTest, Shared) { + uint8_t s[] = {0, 1, 2}; + deno_buf shared = {nullptr, 0, s, 3}; + Deno* d = deno_new(snapshot, shared, nullptr); + EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "Shared()")); + EXPECT_EQ(s[0], 42); + EXPECT_EQ(s[1], 43); + EXPECT_EQ(s[2], 44); + deno_delete(d); +} diff --git a/libdeno/libdeno_test.js b/libdeno/libdeno_test.js index 1aa09a7752..c9eaaa0cac 100644 --- a/libdeno/libdeno_test.js +++ b/libdeno/libdeno_test.js @@ -173,3 +173,16 @@ global.PromiseRejectCatchHandling = () => { } })(); } + +global.Shared = () => { + const ab = libdeno.shared; + assert(ab instanceof ArrayBuffer); + assert(ab.byteLength === 3); + const ui8 = new Uint8Array(ab); + assert(ui8[0] === 0); + assert(ui8[1] === 1); + assert(ui8[2] === 2); + ui8[0] = 42; + ui8[1] = 43; + ui8[2] = 44; +} diff --git a/libdeno/snapshot_creator.cc b/libdeno/snapshot_creator.cc index e2511461b3..adad025dbc 100644 --- a/libdeno/snapshot_creator.cc +++ b/libdeno/snapshot_creator.cc @@ -30,7 +30,7 @@ int main(int argc, char** argv) { deno_init(); Deno* d = deno_new_snapshotter( - nullptr, js_fn, js_source.c_str(), + deno::empty_buf, nullptr, js_fn, js_source.c_str(), source_map_fn != nullptr ? source_map.c_str() : nullptr); auto snapshot = deno_get_snapshot(d); diff --git a/src/isolate.rs b/src/isolate.rs index df13fca966..e222d280fa 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -100,6 +100,15 @@ pub struct Metrics { static DENO_INIT: std::sync::Once = std::sync::ONCE_INIT; +fn empty() -> libdeno::deno_buf { + libdeno::deno_buf { + alloc_ptr: std::ptr::null_mut(), + alloc_len: 0, + data_ptr: std::ptr::null_mut(), + data_len: 0, + } +} + impl Isolate { pub fn new( flags: flags::DenoFlags, @@ -109,9 +118,9 @@ impl Isolate { DENO_INIT.call_once(|| { unsafe { libdeno::deno_init() }; }); - + let shared = empty(); // TODO Use shared for message passing. let libdeno_isolate = unsafe { - libdeno::deno_new(snapshot::deno_snapshot.clone(), pre_dispatch) + libdeno::deno_new(snapshot::deno_snapshot.clone(), shared, pre_dispatch) }; // This channel handles sending async messages back to the runtime. let (tx, rx) = mpsc::channel::<(i32, Buf)>(); diff --git a/src/libdeno.rs b/src/libdeno.rs index 812cd4620c..bb0509e011 100644 --- a/src/libdeno.rs +++ b/src/libdeno.rs @@ -28,7 +28,11 @@ extern "C" { pub fn deno_init(); pub fn deno_v8_version() -> *const c_char; pub fn deno_set_v8_flags(argc: *mut c_int, argv: *mut *mut c_char); - pub fn deno_new(snapshot: deno_buf, cb: DenoRecvCb) -> *const isolate; + pub fn deno_new( + snapshot: deno_buf, + shared: deno_buf, + cb: DenoRecvCb, + ) -> *const isolate; pub fn deno_delete(i: *const isolate); pub fn deno_last_exception(i: *const isolate) -> *const c_char; pub fn deno_check_promise_errors(i: *const isolate);