diff --git a/libdeno/api.cc b/libdeno/api.cc index 388ab61460..4721818195 100644 --- a/libdeno/api.cc +++ b/libdeno/api.cc @@ -13,13 +13,40 @@ extern "C" { -Deno* deno_new(deno_buf snapshot, deno_config config) { - deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, config); +Deno* deno_new_snapshotter(deno_config config) { + CHECK(config.will_snapshot); + // TODO Support loading snapshots before snapshotting. + CHECK_NULL(config.load_snapshot.data_ptr); + auto* creator = new v8::SnapshotCreator(deno::external_references); + auto* isolate = creator->GetIsolate(); + auto* d = new deno::DenoIsolate(config); + d->snapshot_creator_ = creator; + d->AddIsolate(isolate); + { + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + auto context = v8::Context::New(isolate); + d->context_.Reset(isolate, context); + + creator->SetDefaultContext(context, + v8::SerializeInternalFieldsCallback( + deno::SerializeInternalFields, nullptr)); + deno::InitializeContext(isolate, context); + } + return reinterpret_cast(d); +} + +Deno* deno_new(deno_config config) { + if (config.will_snapshot) { + return deno_new_snapshotter(config); + } + deno::DenoIsolate* d = new deno::DenoIsolate(config); v8::Isolate::CreateParams params; params.array_buffer_allocator = d->array_buffer_allocator_; params.external_references = deno::external_references; - if (snapshot.data_ptr) { + if (config.load_snapshot.data_ptr) { params.snapshot_blob = &d->snapshot_; } @@ -35,10 +62,10 @@ Deno* deno_new(deno_buf snapshot, deno_config config) { v8::MaybeLocal(), v8::DeserializeInternalFieldsCallback( deno::DeserializeInternalFields, nullptr)); - if (!snapshot.data_ptr) { + if (!config.load_snapshot.data_ptr) { // If no snapshot is provided, we initialize the context with empty // main source code and source maps. - deno::InitializeContext(isolate, context, "", ""); + deno::InitializeContext(isolate, context); } d->context_.Reset(isolate, context); } @@ -46,26 +73,6 @@ Deno* deno_new(deno_buf snapshot, deno_config config) { return reinterpret_cast(d); } -Deno* deno_new_snapshotter(deno_config config, const char* js_filename, - const char* js_source) { - auto* creator = new v8::SnapshotCreator(deno::external_references); - auto* isolate = creator->GetIsolate(); - auto* d = new deno::DenoIsolate(deno::empty_buf, config); - d->snapshot_creator_ = creator; - d->AddIsolate(isolate); - { - v8::Locker locker(isolate); - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - auto context = v8::Context::New(isolate); - creator->SetDefaultContext(context, - v8::SerializeInternalFieldsCallback( - deno::SerializeInternalFields, nullptr)); - deno::InitializeContext(isolate, context, js_filename, js_source); - } - return reinterpret_cast(d); -} - deno::DenoIsolate* unwrap(Deno* d_) { return reinterpret_cast(d_); } @@ -73,6 +80,7 @@ deno::DenoIsolate* unwrap(Deno* d_) { deno_buf deno_get_snapshot(Deno* d_) { auto* d = unwrap(d_); CHECK_NE(d->snapshot_creator_, nullptr); + d->context_.Reset(); auto blob = d->snapshot_creator_->CreateBlob( v8::SnapshotCreator::FunctionCodeHandling::kClear); return {nullptr, 0, reinterpret_cast(const_cast(blob.data)), @@ -111,6 +119,7 @@ int deno_execute(Deno* d_, void* user_data, const char* js_filename, v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); auto context = d->context_.Get(d->isolate_); + CHECK(!context.IsEmpty()); return deno::Execute(context, js_filename, js_source) ? 1 : 0; } diff --git a/libdeno/binding.cc b/libdeno/binding.cc index 2a68d89aae..bb931ca1df 100644 --- a/libdeno/binding.cc +++ b/libdeno/binding.cc @@ -154,13 +154,8 @@ void HandleException(v8::Local context, v8::Isolate* isolate = context->GetIsolate(); DenoIsolate* d = FromIsolate(isolate); std::string json_str = EncodeExceptionAsJSON(context, exception); - if (d != nullptr) { - d->last_exception_ = json_str; - } else { - // This shouldn't happen in normal circumstances. Added for debugging. - std::cerr << "Pre-Deno Exception " << json_str << std::endl; - CHECK(false); - } + CHECK(d != nullptr); + d->last_exception_ = json_str; } void PromiseRejectCallback(v8::PromiseRejectMessage promise_reject_message) { @@ -396,10 +391,7 @@ bool Execute(v8::Local context, const char* js_filename, return ExecuteV8StringSource(context, js_filename, source); } -void InitializeContext(v8::Isolate* isolate, v8::Local context, - const char* js_filename, const char* js_source) { - CHECK_NE(js_source, nullptr); - CHECK_NE(js_filename, nullptr); +void InitializeContext(v8::Isolate* isolate, v8::Local context) { v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context); @@ -422,13 +414,6 @@ void InitializeContext(v8::Isolate* isolate, v8::Local context, CHECK(deno_val->SetAccessor(context, deno::v8_str("shared"), Shared) .FromJust()); - - { - auto source = deno::v8_str(js_source); - - bool r = deno::ExecuteV8StringSource(context, js_filename, source); - CHECK(r); - } } void DenoIsolate::AddIsolate(v8::Isolate* isolate) { diff --git a/libdeno/deno.h b/libdeno/deno.h index 48356bc86e..e0ba631531 100644 --- a/libdeno/deno.h +++ b/libdeno/deno.h @@ -30,14 +30,13 @@ const char* deno_v8_version(); void deno_set_v8_flags(int* argc, char** argv); typedef struct { - deno_buf shared; // Shared buffer to be mapped to libdeno.shared - deno_recv_cb recv_cb; // Maps to libdeno.send() calls. + int will_snapshot; // Default 0. If calling deno_get_snapshot 1. + deno_buf load_snapshot; // Optionally: A deno_buf from deno_get_snapshot. + deno_buf shared; // Shared buffer to be mapped to libdeno.shared + deno_recv_cb recv_cb; // Maps to libdeno.send() calls. } deno_config; -Deno* deno_new(deno_buf snapshot, deno_config config); - -Deno* deno_new_snapshotter(deno_config config, const char* js_filename, - const char* js_source); +Deno* deno_new(deno_config config); // Generate a snapshot. The resulting buf can be used with deno_new. // The caller must free the returned data by calling delete[] buf.data_ptr. diff --git a/libdeno/internal.h b/libdeno/internal.h index 3dc4d8d0e1..782108d988 100644 --- a/libdeno/internal.h +++ b/libdeno/internal.h @@ -13,7 +13,7 @@ namespace deno { // deno_s = Wrapped Isolate. class DenoIsolate { public: - DenoIsolate(deno_buf snapshot, deno_config config) + DenoIsolate(deno_config config) : isolate_(nullptr), shared_(config.shared), current_args_(nullptr), @@ -23,9 +23,10 @@ class DenoIsolate { next_req_id_(0), user_data_(nullptr) { array_buffer_allocator_ = v8::ArrayBuffer::Allocator::NewDefaultAllocator(); - if (snapshot.data_ptr) { - snapshot_.data = reinterpret_cast(snapshot.data_ptr); - snapshot_.raw_size = static_cast(snapshot.data_len); + if (config.load_snapshot.data_ptr) { + snapshot_.data = + reinterpret_cast(config.load_snapshot.data_ptr); + snapshot_.raw_size = static_cast(config.load_snapshot.data_len); } } @@ -98,8 +99,7 @@ static const deno_buf empty_buf = {nullptr, 0, nullptr, 0}; Deno* NewFromSnapshot(void* user_data, deno_recv_cb cb); -void InitializeContext(v8::Isolate* isolate, v8::Local context, - const char* js_filename, const char* js_source); +void InitializeContext(v8::Isolate* isolate, v8::Local context); void HandleException(v8::Local context, v8::Local exception); diff --git a/libdeno/libdeno_test.cc b/libdeno/libdeno_test.cc index 33a4702ae2..9627f4a8d0 100644 --- a/libdeno/libdeno_test.cc +++ b/libdeno/libdeno_test.cc @@ -3,30 +3,29 @@ TEST(LibDenoTest, InitializesCorrectly) { EXPECT_NE(snapshot.data_ptr, nullptr); - Deno* d = deno_new(snapshot, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2")); deno_delete(d); } TEST(LibDenoTest, InitializesCorrectlyWithoutSnapshot) { - Deno* d = deno_new(empty, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, empty, empty, nullptr}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "1 + 2")); deno_delete(d); } TEST(LibDenoTest, SnapshotterInitializesCorrectly) { - Deno* d = - deno_new_snapshotter(deno_config{empty, nullptr}, "a.js", "a = 1 + 2"); + Deno* d = deno_new(deno_config{1, empty, empty, nullptr}); deno_delete(d); } TEST(LibDenoTest, Snapshotter) { - Deno* d1 = - deno_new_snapshotter(deno_config{empty, nullptr}, "a.js", "a = 1 + 2"); + Deno* d1 = deno_new(deno_config{1, empty, empty, nullptr}); + EXPECT_TRUE(deno_execute(d1, nullptr, "a.js", "a = 1 + 2")); deno_buf test_snapshot = deno_get_snapshot(d1); deno_delete(d1); - Deno* d2 = deno_new(test_snapshot, deno_config{empty, nullptr}); + Deno* d2 = deno_new(deno_config{0, test_snapshot, empty, nullptr}); EXPECT_TRUE( deno_execute(d2, nullptr, "b.js", "if (a != 3) throw Error('x');")); deno_delete(d2); @@ -35,14 +34,14 @@ TEST(LibDenoTest, Snapshotter) { } TEST(LibDenoTest, CanCallFunction) { - Deno* d = deno_new(snapshot, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, 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, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr}); EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "throw Error()")); deno_delete(d); } @@ -87,7 +86,7 @@ TEST(LibDenoTest, RecvReturnEmpty) { EXPECT_EQ(buf.data_ptr[1], 'b'); EXPECT_EQ(buf.data_ptr[2], 'c'); }; - Deno* d = deno_new(snapshot, deno_config{empty, recv_cb}); + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "RecvReturnEmpty()")); EXPECT_EQ(count, 2); deno_delete(d); @@ -105,14 +104,14 @@ TEST(LibDenoTest, RecvReturnBar) { EXPECT_EQ(buf.data_ptr[2], 'c'); deno_respond(d, user_data, req_id, strbuf("bar")); }; - Deno* d = deno_new(snapshot, deno_config{empty, recv_cb}); + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb}); EXPECT_TRUE(deno_execute(d, d, "a.js", "RecvReturnBar()")); EXPECT_EQ(count, 1); deno_delete(d); } TEST(LibDenoTest, DoubleRecvFails) { - Deno* d = deno_new(snapshot, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr}); EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "DoubleRecvFails()")); deno_delete(d); } @@ -146,7 +145,7 @@ TEST(LibDenoTest, SendRecvSlice) { // Send back. deno_respond(d, user_data, req_id, buf2); }; - Deno* d = deno_new(snapshot, deno_config{empty, recv_cb}); + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb}); EXPECT_TRUE(deno_execute(d, d, "a.js", "SendRecvSlice()")); EXPECT_EQ(count, 5); deno_delete(d); @@ -163,26 +162,26 @@ TEST(LibDenoTest, JSSendArrayBufferViewTypes) { EXPECT_EQ(buf.alloc_len, 4321u); EXPECT_EQ(buf.data_ptr[0], count); }; - Deno* d = deno_new(snapshot, deno_config{empty, recv_cb}); + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "JSSendArrayBufferViewTypes()")); EXPECT_EQ(count, 3); deno_delete(d); } TEST(LibDenoTest, TypedArraySnapshots) { - Deno* d = deno_new(snapshot, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "TypedArraySnapshots()")); deno_delete(d); } TEST(LibDenoTest, SnapshotBug) { - Deno* d = deno_new(snapshot, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "SnapshotBug()")); deno_delete(d); } TEST(LibDenoTest, GlobalErrorHandling) { - Deno* d = deno_new(snapshot, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, snapshot, empty, nullptr}); EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "GlobalErrorHandling()")); // We only check that it starts with this string, so we don't have to check // the second frame, which contains line numbers in libdeno_test.js and may @@ -210,7 +209,7 @@ TEST(LibDenoTest, DataBuf) { EXPECT_EQ(buf.data_ptr[0], 1); EXPECT_EQ(buf.data_ptr[1], 2); }; - Deno* d = deno_new(snapshot, deno_config{empty, recv_cb}); + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "DataBuf()")); EXPECT_EQ(count, 1); // data_buf was subsequently changed in JS, let's check that our copy reflects @@ -223,7 +222,7 @@ TEST(LibDenoTest, DataBuf) { TEST(LibDenoTest, CheckPromiseErrors) { static int count = 0; auto recv_cb = [](auto _, int req_id, auto buf, auto data_buf) { count++; }; - Deno* d = deno_new(snapshot, deno_config{empty, recv_cb}); + Deno* d = deno_new(deno_config{0, snapshot, empty, recv_cb}); EXPECT_EQ(deno_last_exception(d), nullptr); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "CheckPromiseErrors()")); EXPECT_EQ(deno_last_exception(d), nullptr); @@ -236,7 +235,7 @@ TEST(LibDenoTest, CheckPromiseErrors) { } TEST(LibDenoTest, LastException) { - Deno* d = deno_new(empty, deno_config{empty, nullptr}); + Deno* d = deno_new(deno_config{0, empty, empty, nullptr}); EXPECT_EQ(deno_last_exception(d), nullptr); EXPECT_FALSE(deno_execute(d, nullptr, "a.js", "\n\nthrow Error('boo');\n\n")); EXPECT_STREQ(deno_last_exception(d), @@ -251,7 +250,7 @@ TEST(LibDenoTest, LastException) { TEST(LibDenoTest, Shared) { uint8_t s[] = {0, 1, 2}; deno_buf shared = {nullptr, 0, s, 3}; - Deno* d = deno_new(snapshot, deno_config{shared, nullptr}); + Deno* d = deno_new(deno_config{0, snapshot, shared, nullptr}); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", "Shared()")); EXPECT_EQ(s[0], 42); EXPECT_EQ(s[1], 43); diff --git a/libdeno/snapshot_creator.cc b/libdeno/snapshot_creator.cc index 7e29b61c84..ba926d3f35 100644 --- a/libdeno/snapshot_creator.cc +++ b/libdeno/snapshot_creator.cc @@ -1,6 +1,7 @@ // Copyright 2018 the Deno authors. All rights reserved. MIT license. // Hint: --trace_serializer is a useful debugging flag. #include +#include #include "deno.h" #include "file_util.h" #include "internal.h" @@ -22,8 +23,16 @@ int main(int argc, char** argv) { CHECK(deno::ReadFileToString(js_fn, &js_source)); deno_init(); - deno_config config = {deno::empty_buf, nullptr}; - Deno* d = deno_new_snapshotter(config, js_fn, js_source.c_str()); + deno_config config = {1, deno::empty_buf, deno::empty_buf, nullptr}; + Deno* d = deno_new(config); + + int r = deno_execute(d, nullptr, js_fn, js_source.c_str()); + if (!r) { + std::cerr << "Snapshot Exception " << std::endl; + std::cerr << deno_last_exception(d) << std::endl; + deno_delete(d); + return 1; + } auto snapshot = deno_get_snapshot(d); diff --git a/src/isolate.rs b/src/isolate.rs index 99e3670f24..2305a62a9d 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -144,10 +144,12 @@ impl Isolate { unsafe { libdeno::deno_init() }; }); let config = libdeno::deno_config { + will_snapshot: 0, + load_snapshot: snapshot, shared: libdeno::deno_buf::empty(), // TODO Use for message passing. recv_cb: pre_dispatch, }; - let libdeno_isolate = unsafe { libdeno::deno_new(snapshot, config) }; + let libdeno_isolate = unsafe { libdeno::deno_new(config) }; // 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 cbc074f1be..cce6c4e602 100644 --- a/src/libdeno.rs +++ b/src/libdeno.rs @@ -111,6 +111,8 @@ type DenoRecvCb = unsafe extern "C" fn( #[repr(C)] pub struct deno_config { + pub will_snapshot: c_int, + pub load_snapshot: deno_buf, pub shared: deno_buf, pub recv_cb: DenoRecvCb, } @@ -119,7 +121,7 @@ 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, config: deno_config) -> *const isolate; + pub fn deno_new(config: deno_config) -> *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);