Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various snapshot related clean ups #268

Merged
merged 3 commits into from
Jun 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deno2/.gclient
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
solutions = [{
'url': 'https://chromium.googlesource.com/v8/v8.git@2530a044126ae6a1d3dff0d8c61999762847d9f0',
'url': 'https://chromium.googlesource.com/v8/v8.git@6.8-lkgr',
'name': 'v8',
'deps_file': 'DEPS',
'custom_deps': {
Expand Down
11 changes: 4 additions & 7 deletions deno2/.gn
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,12 @@ default_args = {
v8_embedder_string = "-deno"
v8_enable_gdbjit = false
v8_enable_i18n_support = false
v8_enable_test_features = false
v8_experimental_extra_library_files = []
v8_extra_library_files = []
v8_imminent_deprecation_warnings = false
v8_monolithic = false
v8_untrusted_code_mitigations = false

# This tells V8 to write out/Default/gen/v8/snapshot.bin
# Which we can use to build our own snapshot.
v8_use_external_startup_data = true
v8_use_multi_snapshots = false
v8_use_external_startup_data = false
v8_use_snapshot = true
v8_experimental_extra_library_files = []
v8_extra_library_files = []
}
38 changes: 0 additions & 38 deletions deno2/deno.cc
Original file line number Diff line number Diff line change
Expand Up @@ -194,19 +194,6 @@ bool Execute(v8::Local<v8::Context> context, const char* js_filename,
return true;
}

v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
void* data) {
DCHECK_EQ(data, nullptr); // TODO(ry) pass Deno* object here.
InternalFieldData* embedder_field = static_cast<InternalFieldData*>(
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};
}

void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context,
const char* js_filename, const char* js_source) {
v8::HandleScope handle_scope(isolate);
Expand All @@ -233,31 +220,6 @@ void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context,
CHECK(r);
}

v8::StartupData MakeSnapshot(v8::StartupData* prev_natives_blob,
v8::StartupData* prev_snapshot_blob,
const char* js_filename, const char* js_source) {
v8::V8::SetNativesDataBlob(prev_natives_blob);
v8::V8::SetSnapshotDataBlob(prev_snapshot_blob);

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);
creator->SetDefaultContext(context, v8::SerializeInternalFieldsCallback(
SerializeInternalFields, nullptr));
}

// Note that using kKeep here will cause segfaults. This is demoed in the
// "SnapshotBug" test case.
auto snapshot_blob =
creator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);

return snapshot_blob;
}

void AddIsolate(Deno* d, v8::Isolate* isolate) {
d->isolate = isolate;
// Leaving this code here because it will probably be useful later on, but
Expand Down
7 changes: 0 additions & 7 deletions deno2/deno.gni
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,16 @@ template("create_snapshot") {
data = []
exe = rebase_path(get_label_info(":snapshot_creator", "root_out_dir") +
"/snapshot_creator")
natives_in_bin = "$root_out_dir/natives_blob.bin"
snapshot_in_bin = "$root_out_dir/snapshot_blob.bin"
natives_out_cc = "$target_gen_dir/natives${suffix}.cc"
snapshot_out_cc = "$target_gen_dir/snapshot${suffix}.cc"
sources = [
invoker.js,
]
outputs = [
natives_out_cc,
snapshot_out_cc,
]
args = [
exe,
rebase_path(invoker.js, root_build_dir),
rebase_path(natives_in_bin, root_build_dir),
rebase_path(snapshot_in_bin, root_build_dir),
rebase_path(natives_out_cc, root_build_dir),
rebase_path(snapshot_out_cc, root_build_dir),
]

Expand Down
4 changes: 0 additions & 4 deletions deno2/deno_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ Deno* NewFromSnapshot(void* data, deno_sub_cb cb);
void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> context,
const char* js_filename, const char* js_source);

v8::StartupData MakeSnapshot(v8::StartupData* prev_natives_blob,
v8::StartupData* prev_snapshot_blob,
const char* js_filename, const char* js_source);

void AddIsolate(Deno* d, v8::Isolate* isolate);

} // namespace deno
Expand Down
8 changes: 5 additions & 3 deletions deno2/file_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,18 @@ class StartupDataCppWriter {
void WritePrefix() {
file_ << "// Autogenerated snapshot file. Do not edit.\n\n";
file_ << "#include \"v8/include/v8.h\"\n\n";
file_ << "namespace deno { \n\n";
}

void WriteSuffix() {
char buffer[500];
snprintf(buffer, sizeof(buffer),
"const v8::StartupData* StartupBlob_%s() {\n", name_);
snprintf(buffer, sizeof(buffer), "v8::StartupData* StartupBlob_%s() {\n",
name_);
file_ << buffer;
snprintf(buffer, sizeof(buffer), " return &%s_blob;\n", name_);
file_ << buffer;
file_ << "}\n\n";
file_ << "} // namespace deno\n\n";
}

void WriteBinaryContentsAsCArray() {
Expand All @@ -78,7 +80,7 @@ class StartupDataCppWriter {
snprintf(buffer, sizeof(buffer), "static const int %s_blob_size = %llu;\n",
name_, static_cast<unsigned long long>(data_.size()));
file_ << buffer;
snprintf(buffer, sizeof(buffer), "static const v8::StartupData %s_blob =\n",
snprintf(buffer, sizeof(buffer), "static v8::StartupData %s_blob =\n",
name_);
file_ << buffer;
snprintf(buffer, sizeof(buffer),
Expand Down
18 changes: 5 additions & 13 deletions deno2/from_snapshot.cc
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
// Copyright 2018 Ryan Dahl <[email protected]>
// All rights reserved. MIT License.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>

#include "v8/include/v8.h"
#include "v8/src/base/logging.h"

#include "./deno_internal.h"
#include "include/deno.h"

namespace deno {

#ifdef DENO_MOCK_RUNTIME
#include "natives_mock_runtime.cc"
#include "snapshot_mock_runtime.cc"
#else
#include "natives_deno.cc"
#include "snapshot_deno.cc"
#endif

namespace deno {

std::vector<InternalFieldData*> deserialized_data;

void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
v8::StartupData payload, void* data) {
assert(data == nullptr); // TODO(ry) pass Deno* object here.
DCHECK_EQ(data, nullptr);
if (payload.raw_size == 0) {
holder->SetAlignedPointerInInternalField(index, nullptr);
return;
Expand All @@ -37,13 +35,6 @@ void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
}

Deno* NewFromSnapshot(void* data, deno_sub_cb cb) {
auto natives_blob = *StartupBlob_natives();
auto snapshot_blob = *StartupBlob_snapshot();

v8::V8::SetNativesDataBlob(&natives_blob);
v8::V8::SetSnapshotDataBlob(&snapshot_blob);
v8::DeserializeInternalFieldsCallback(DeserializeInternalFields, nullptr);

Deno* d = new Deno;
d->currentArgs = nullptr;
d->cb = cb;
Expand All @@ -52,6 +43,7 @@ Deno* NewFromSnapshot(void* data, deno_sub_cb cb) {
params.array_buffer_allocator =
v8::ArrayBuffer::Allocator::NewDefaultAllocator();
params.external_references = external_references;
params.snapshot_blob = StartupBlob_snapshot();
v8::Isolate* isolate = v8::Isolate::New(params);
AddIsolate(d, isolate);

Expand Down
2 changes: 0 additions & 2 deletions deno2/js/mock_runtime.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// A simple runtime that doesn't involve typescript or protobufs to test
// libdeno. Invoked by mock_runtime_test.cc
const window = eval("this");

function assert(cond) {
if (!cond) throw Error("mock_runtime.js assert failed");
Expand Down Expand Up @@ -68,7 +67,6 @@ function DoubleSubFails() {
deno.sub((channel, msg) => assert(false));
}


// The following join has caused SnapshotBug to segfault when using kKeep.
[].join("");

Expand Down
1 change: 1 addition & 0 deletions deno2/mock_runtime_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,6 @@ TEST(MockRuntimeTest, SnapshotBug) {
int main(int argc, char** argv) {
testing::InitGoogleTest(&argc, argv);
deno_init();
deno_set_flags(&argc, argv);
return RUN_ALL_TESTS();
}
77 changes: 56 additions & 21 deletions deno2/snapshot_creator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,76 @@
#include "v8/include/v8.h"
#include "v8/src/base/logging.h"

v8::StartupData StringToStartupData(const std::string& s) {
return v8::StartupData{s.c_str(), s.size()};
namespace deno {

v8::StartupData SerializeInternalFields(v8::Local<v8::Object> holder, int index,
void* data) {
DCHECK_EQ(data, nullptr);
InternalFieldData* embedder_field = static_cast<InternalFieldData*>(
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 char* js_source) {
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);
creator->SetDefaultContext(context, v8::SerializeInternalFieldsCallback(
SerializeInternalFields, nullptr));
}

// Note that using kKeep here will cause segfaults. This is demoed in the
// "SnapshotBug" test case.
auto snapshot_blob =
creator->CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);

return snapshot_blob;
}

} // namespace deno

int main(int argc, char** argv) {
const char* js_fn = argv[1];
const char* natives_in_bin = argv[2];
const char* snapshot_in_bin = argv[3];
const char* natives_out_cc = argv[4];
const char* snapshot_out_cc = argv[5];
const char* snapshot_out_cc = argv[2];

v8::V8::SetFlagsFromCommandLine(&argc, argv, true);

CHECK_EQ(argc, 3);
CHECK_NE(js_fn, nullptr);
CHECK_NE(natives_in_bin, nullptr);
CHECK_NE(snapshot_in_bin, nullptr);
CHECK_NE(natives_out_cc, nullptr);
CHECK_NE(snapshot_out_cc, nullptr);

v8::V8::SetFlagsFromCommandLine(&argc, argv, true);

std::string js_source;
CHECK(deno::ReadFileToString(js_fn, &js_source));

std::string natives_str;
CHECK(deno::ReadFileToString(natives_in_bin, &natives_str));
auto natives_blob = StringToStartupData(natives_str);

std::string snapshot_in_str;
CHECK(deno::ReadFileToString(snapshot_in_bin, &snapshot_in_str));
auto snapshot_in_blob = StringToStartupData(snapshot_in_str);
// Wrap the js_source in an IIFE to work around a bug in the V8 snapshot
// serializer. Without it, CreateBlob() triggers the following assert:
// Debug check failed : outer_scope_info()->IsScopeInfo() || is_toplevel().
// ==== C stack trace ====
// v8::internal::SharedFunctionInfo::FlushCompiled
// v8::SnapshotCreator::CreateBlob
// deno::MakeSnapshot
// Avoid misaligning the source map, and ensure that the sourceMappingUrl
// comment remains at the last line.
auto smu_offset = js_source.rfind("//#");
CHECK(smu_offset != std::string::npos);
auto wrapped_js_source = "(function() {" + js_source.substr(0, smu_offset) +
"\n})();\n" + js_source.substr(smu_offset);
// Double check that the source mapping url comment is at the last line.
auto last_line = wrapped_js_source.substr(wrapped_js_source.rfind('\n'));
CHECK(last_line.find("sourceMappingURL") != std::string::npos);

deno_init();
auto snapshot_blob = deno::MakeSnapshot(&natives_blob, &snapshot_in_blob,
js_fn, js_source.c_str());
auto snapshot_blob = deno::MakeSnapshot(js_fn, wrapped_js_source.c_str());
std::string snapshot_str(snapshot_blob.data, snapshot_blob.raw_size);

CHECK(deno::WriteDataAsCpp("natives", natives_out_cc, natives_str));
CHECK(deno::WriteDataAsCpp("snapshot", snapshot_out_cc, snapshot_str));
}