diff --git a/Makefile b/Makefile index d04aac3515a181..d41bf1601fb599 100644 --- a/Makefile +++ b/Makefile @@ -1226,6 +1226,8 @@ LINT_CPP_FILES = $(filter-out $(LINT_CPP_EXCLUDE), $(wildcard \ tools/icu/*.h \ tools/code_cache/*.cc \ tools/code_cache/*.h \ + tools/snapshot/*.cc \ + tools/snapshot/*.h \ )) # Code blocks don't have newline at the end, diff --git a/node.gyp b/node.gyp index 7f534d82080907..8019a16599a20f 100644 --- a/node.gyp +++ b/node.gyp @@ -1156,7 +1156,47 @@ }], ], }, # mkcodecache - ], # end targets + { + 'target_name': 'node_mksnapshot', + 'type': 'executable', + + 'dependencies': [ + '<(node_lib_target_name)', + 'deps/histogram/histogram.gyp:histogram', + ], + + 'includes': [ + 'node.gypi' + ], + + 'include_dirs': [ + 'src', + 'tools/msvs/genfiles', + 'deps/v8/include', + 'deps/cares/include', + 'deps/uv/include', + ], + + 'defines': [ 'NODE_WANT_INTERNALS=1' ], + + 'sources': [ + 'src/node_code_cache_stub.cc', + 'tools/snapshot/node_mksnapshot.cc', + 'tools/snapshot/snapshot_builder.cc', + 'tools/snapshot/snapshot_builder.h', + ], + + 'conditions': [ + [ 'node_report=="true"', { + 'conditions': [ + ['OS=="win"', { + 'libraries': [ 'Ws2_32' ], + }], + ], + }], + ], + }, # node_mksnapshot + ], # end targets 'conditions': [ ['OS=="aix" and node_shared=="true"', { diff --git a/tools/snapshot/node_mksnapshot.cc b/tools/snapshot/node_mksnapshot.cc new file mode 100644 index 00000000000000..c273ba20b610e1 --- /dev/null +++ b/tools/snapshot/node_mksnapshot.cc @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include + +#include "libplatform/libplatform.h" +#include "node_internals.h" +#include "snapshot_builder.h" +#include "v8.h" + +#ifdef _WIN32 +#include + +int wmain(int argc, wchar_t* argv[]) { +#else // UNIX +int main(int argc, char* argv[]) { +#endif // _WIN32 + + if (argc < 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + std::ofstream out; + out.open(argv[1], std::ios::out | std::ios::binary); + if (!out.is_open()) { + std::cerr << "Cannot open " << argv[1] << "\n"; + return 1; + } + + int node_argc = 1; + char argv0[] = "node"; + char* node_argv[] = {argv0, nullptr}; + + node::InitializationResult result = + node::InitializeOncePerProcess(node_argc, node_argv); + CHECK(!result.early_return); + CHECK_EQ(result.exit_code, 0); + + { + std::string snapshot = + node::SnapshotBuilder::Generate(result.args, result.exec_args); + out << snapshot; + out.close(); + } + + node::TearDownOncePerProcess(); + return 0; +} diff --git a/tools/snapshot/snapshot_builder.cc b/tools/snapshot/snapshot_builder.cc new file mode 100644 index 00000000000000..d1ec17e302ae97 --- /dev/null +++ b/tools/snapshot/snapshot_builder.cc @@ -0,0 +1,122 @@ +#include "snapshot_builder.h" +#include +#include +#include "env-inl.h" +#include "node_internals.h" +#include "node_main_instance.h" +#include "node_v8_platform-inl.h" + +namespace node { + +using v8::Context; +using v8::HandleScope; +using v8::Isolate; +using v8::Local; +using v8::Locker; +using v8::SnapshotCreator; +using v8::StartupData; + +std::string FormatBlob(v8::StartupData* blob, + const std::vector& isolate_data_indexes) { + std::stringstream ss; + size_t isolate_data_indexes_size = isolate_data_indexes.size(); + + ss << R"(#include +#include "node_main_instance.h" +#include "v8.h" + +// This file is generated by tools/snapshot. Do not edit. + +namespace node { + +static const uint8_t blob_data[] = { +)"; + + for (int i = 0; i < blob->raw_size; i++) { + uint8_t ch = blob->data[i]; + ss << std::to_string(ch) << ((i == blob->raw_size - 1) ? '\n' : ','); + } + + ss << R"(}; + +static const int blob_size = )" + << blob->raw_size << R"(; +static v8::StartupData blob = { + reinterpret_cast(blob_data), + blob_size +}; +)"; + + ss << R"(v8::StartupData* +NodeMainInstance::GetEmbeddedSnapshotBlob() { + return &blob; +} + +static const size_t isolate_data_indexes_raw[] = { +)"; + for (size_t i = 0; i < isolate_data_indexes_size; i++) { + ss << std::to_string(isolate_data_indexes[i]) + << ((i == isolate_data_indexes_size - 1) ? '\n' : ','); + } + ss << "};\n\n"; + + ss << "static const size_t isolate_data_indexes_size = " + << isolate_data_indexes_size << R"(; + +NodeMainInstance::IndexArray isolate_data_indexes { + isolate_data_indexes_raw, + isolate_data_indexes_size +}; + +const NodeMainInstance::IndexArray* +NodeMainInstance::GetIsolateDataIndexes() { + return &isolate_data_indexes; +} +} // namespace node +)"; + + return ss.str(); +} + +std::string SnapshotBuilder::Generate( + const std::vector args, + const std::vector exec_args) { + // TODO(joyeecheung): collect external references and set it in + // params.external_references. + std::vector external_references = { + reinterpret_cast(nullptr)}; + Isolate* isolate = Isolate::Allocate(); + per_process::v8_platform.Platform()->RegisterIsolate(isolate, + uv_default_loop()); + NodeMainInstance* main_instance = nullptr; + std::string result; + + { + std::vector isolate_data_indexes; + SnapshotCreator creator(isolate, external_references.data()); + { + main_instance = + NodeMainInstance::Create(isolate, + uv_default_loop(), + per_process::v8_platform.Platform(), + args, + exec_args); + HandleScope scope(isolate); + creator.SetDefaultContext(Context::New(isolate)); + isolate_data_indexes = main_instance->isolate_data()->Serialize(&creator); + } + + // Must be out of HandleScope + StartupData blob = + creator.CreateBlob(SnapshotCreator::FunctionCodeHandling::kClear); + // Must be done while the snapshot creator isolate is entered i.e. the + // creator is still alive. + main_instance->Dispose(); + result = FormatBlob(&blob, isolate_data_indexes); + delete blob.data; + } + + per_process::v8_platform.Platform()->UnregisterIsolate(isolate); + return result; +} +} // namespace node diff --git a/tools/snapshot/snapshot_builder.h b/tools/snapshot/snapshot_builder.h new file mode 100644 index 00000000000000..2e587d078b9bcd --- /dev/null +++ b/tools/snapshot/snapshot_builder.h @@ -0,0 +1,15 @@ +#ifndef TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_ +#define TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_ + +#include +#include + +namespace node { +class SnapshotBuilder { + public: + static std::string Generate(const std::vector args, + const std::vector exec_args); +}; +} // namespace node + +#endif // TOOLS_SNAPSHOT_SNAPSHOT_BUILDER_H_