diff --git a/libdeno/api.cc b/libdeno/api.cc index e01f95e82a..5122527374 100644 --- a/libdeno/api.cc +++ b/libdeno/api.cc @@ -42,10 +42,39 @@ 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) { + auto* creator = new v8::SnapshotCreator(deno::external_references); + auto* isolate = creator->GetIsolate(); + auto* d = new deno::DenoIsolate(deno::empty_buf, cb); + d->snapshot_creator_ = creator; + d->AddIsolate(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, + source_map); + } + return reinterpret_cast(d); +} + deno::DenoIsolate* unwrap(Deno* d_) { return reinterpret_cast(d_); } +deno_buf deno_get_snapshot(Deno* d_) { + auto* d = unwrap(d_); + CHECK_NE(d->snapshot_creator_, nullptr); + auto blob = d->snapshot_creator_->CreateBlob( + v8::SnapshotCreator::FunctionCodeHandling::kClear); + return {nullptr, 0, reinterpret_cast(const_cast(blob.data)), + blob.raw_size}; +} + void deno_init() { // v8::V8::InitializeICUDefaultLocation(argv[0]); // v8::V8::InitializeExternalStartupData(argv[0]); diff --git a/libdeno/binding.cc b/libdeno/binding.cc index 9fca3814c7..686defffac 100644 --- a/libdeno/binding.cc +++ b/libdeno/binding.cc @@ -30,6 +30,19 @@ void DeserializeInternalFields(v8::Local holder, int index, deserialized_data.push_back(embedder_field); } +v8::StartupData SerializeInternalFields(v8::Local holder, int index, + void* data) { + DCHECK_EQ(data, nullptr); + InternalFieldData* embedder_field = static_cast( + holder->GetAlignedPointerFromInternalField(index)); + if (embedder_field == nullptr) return {nullptr, 0}; + int size = sizeof(*embedder_field); + char* payload = new char[size]; + // We simply use memcpy to serialize the content. + memcpy(payload, embedder_field, size); + return {payload, size}; +} + DenoIsolate* FromIsolate(v8::Isolate* isolate) { return static_cast(isolate->GetData(0)); } @@ -433,8 +446,10 @@ bool Execute(v8::Local context, const char* js_filename, } void InitializeContext(v8::Isolate* isolate, v8::Local context, - const char* js_filename, const std::string& js_source, - const std::string* source_map) { + const char* js_filename, const char* js_source, + const char* source_map) { + CHECK_NE(js_source, nullptr); + CHECK_NE(js_filename, nullptr); v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context); @@ -483,7 +498,7 @@ void InitializeContext(v8::Isolate* isolate, v8::Local context, .FromJust()); { - auto source = deno::v8_str(js_source.c_str()); + auto source = deno::v8_str(js_source); CHECK( deno_val->Set(context, deno::v8_str("mainSource"), source).FromJust()); @@ -491,10 +506,10 @@ void InitializeContext(v8::Isolate* isolate, v8::Local context, CHECK(r); if (source_map != nullptr) { - CHECK_GT(source_map->length(), 1u); v8::TryCatch try_catch(isolate); v8::ScriptOrigin origin(v8_str("set_source_map.js")); - std::string source_map_parens = "(" + *source_map + ")"; + std::string source_map_parens = + std::string("(") + std::string(source_map) + std::string(")"); auto source_map_v8_str = deno::v8_str(source_map_parens.c_str()); auto script = v8::Script::Compile(context, source_map_v8_str, &origin); if (script.IsEmpty()) { diff --git a/libdeno/deno.h b/libdeno/deno.h index f833bd5417..c29bfc0bbb 100644 --- a/libdeno/deno.h +++ b/libdeno/deno.h @@ -30,6 +30,11 @@ 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_snapshotter(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); // Returns false on error. diff --git a/libdeno/internal.h b/libdeno/internal.h index d71b36048e..6816debecf 100644 --- a/libdeno/internal.h +++ b/libdeno/internal.h @@ -16,6 +16,7 @@ class DenoIsolate { DenoIsolate(deno_buf snapshot, deno_recv_cb cb) : isolate_(nullptr), current_args_(nullptr), + snapshot_creator_(nullptr), global_import_buf_ptr_(nullptr), pending_promise_events_(0), cb_(cb), @@ -30,8 +31,8 @@ class DenoIsolate { void AddIsolate(v8::Isolate* isolate); v8::Isolate* isolate_; - // Put v8::Isolate::CreateParams here.. const v8::FunctionCallbackInfo* current_args_; + v8::SnapshotCreator* snapshot_creator_; void* global_import_buf_ptr_; int32_t pending_promise_events_; deno_recv_cb cb_; @@ -86,11 +87,13 @@ static intptr_t external_references[] = { reinterpret_cast(SetPromiseErrorExaminer), 0}; +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 std::string& js_source, - const std::string* source_map); + const char* js_filename, const char* js_source, + const char* source_map); void HandleException(v8::Local context, v8::Local exception); @@ -98,6 +101,9 @@ void HandleException(v8::Local context, void DeserializeInternalFields(v8::Local holder, int index, v8::StartupData payload, void* data); +v8::StartupData SerializeInternalFields(v8::Local holder, int index, + void* data); + v8::Local ImportBuf(DenoIsolate* d, deno_buf buf); void DeleteDataRef(DenoIsolate* d, int32_t req_id); diff --git a/libdeno/libdeno_test.cc b/libdeno/libdeno_test.cc index 4470124129..54285566fc 100644 --- a/libdeno/libdeno_test.cc +++ b/libdeno/libdeno_test.cc @@ -16,6 +16,17 @@ TEST(LibDenoTest, InitializesCorrectlyWithoutSnapshot) { deno_delete(d); } +TEST(LibDenoTest, Snapshotter) { + Deno* d1 = deno_new_snapshotter(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); + 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); EXPECT_TRUE(deno_execute(d, nullptr, "a.js", diff --git a/libdeno/snapshot_creator.cc b/libdeno/snapshot_creator.cc index 8038c9b13e..e2511461b3 100644 --- a/libdeno/snapshot_creator.cc +++ b/libdeno/snapshot_creator.cc @@ -7,42 +7,7 @@ #include "third_party/v8/include/v8.h" #include "third_party/v8/src/base/logging.h" -namespace deno { - -v8::StartupData SerializeInternalFields(v8::Local holder, int index, - void* data) { - DCHECK_EQ(data, nullptr); - InternalFieldData* embedder_field = static_cast( - holder->GetAlignedPointerFromInternalField(index)); - if (embedder_field == nullptr) return {nullptr, 0}; - int size = sizeof(*embedder_field); - char* payload = new char[size]; - // We simply use memcpy to serialize the content. - memcpy(payload, embedder_field, size); - return {payload, size}; -} - -v8::StartupData MakeSnapshot(const char* js_filename, - const std::string& js_source, - const std::string* source_map) { - auto* creator = new v8::SnapshotCreator(external_references); - auto* isolate = creator->GetIsolate(); - v8::Isolate::Scope isolate_scope(isolate); - { - v8::HandleScope handle_scope(isolate); - auto context = v8::Context::New(isolate); - InitializeContext(isolate, context, js_filename, js_source, source_map); - creator->SetDefaultContext(context, v8::SerializeInternalFieldsCallback( - SerializeInternalFields, nullptr)); - } - - auto snapshot_blob = - creator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear); - - return snapshot_blob; -} - -} // namespace deno +namespace deno {} // namespace deno int main(int argc, char** argv) { const char* snapshot_out_bin = argv[1]; @@ -64,9 +29,13 @@ int main(int argc, char** argv) { } deno_init(); - auto snapshot_blob = deno::MakeSnapshot( - js_fn, js_source, source_map_fn != nullptr ? &source_map : nullptr); - std::string snapshot_str(snapshot_blob.data, snapshot_blob.raw_size); + Deno* d = deno_new_snapshotter( + nullptr, js_fn, js_source.c_str(), + source_map_fn != nullptr ? source_map.c_str() : nullptr); + + auto snapshot = deno_get_snapshot(d); + std::string snapshot_str(reinterpret_cast(snapshot.data_ptr), + snapshot.data_len); std::ofstream file_(snapshot_out_bin, std::ios::binary); file_ << snapshot_str;