From d7016679509cd7f2d50612369509e8797d8157b0 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 18 Apr 2019 16:26:48 +0800 Subject: tools: implement node_mksnapshot Implements a node_mksnapshot target that generates a snapshot blob from a Node.js main instance's isolate, and serializes the data blob with other additional data into a C++ file that can be embedded into the Node.js binary. PR-URL: https://github.com/nodejs/node/pull/27321 Refs: https://github.com/nodejs/node/issues/17058 Reviewed-By: Anna Henningsen Reviewed-By: Refael Ackermann Reviewed-By: James M Snell Reviewed-By: Ben Noordhuis --- tools/snapshot/node_mksnapshot.cc | 51 ++++++++++++++++ tools/snapshot/snapshot_builder.cc | 122 +++++++++++++++++++++++++++++++++++++ tools/snapshot/snapshot_builder.h | 15 +++++ 3 files changed, 188 insertions(+) create mode 100644 tools/snapshot/node_mksnapshot.cc create mode 100644 tools/snapshot/snapshot_builder.cc create mode 100644 tools/snapshot/snapshot_builder.h (limited to 'tools/snapshot') diff --git a/tools/snapshot/node_mksnapshot.cc b/tools/snapshot/node_mksnapshot.cc new file mode 100644 index 0000000000..c273ba20b6 --- /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 0000000000..d1ec17e302 --- /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 0000000000..2e587d078b --- /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_ -- cgit v1.2.3