diff options
author | Joyee Cheung <joyeec9h3@gmail.com> | 2021-05-26 19:42:00 +0300 |
---|---|---|
committer | Michaƫl Zasso <targos@protonmail.com> | 2021-06-11 08:24:59 +0300 |
commit | 9bf9ddb49044762e75ab013f89830d9f65ed8d3f (patch) | |
tree | 593cf4fdf21117c420ad18f2660429cb5cd4e5cb /src | |
parent | 711916a271f63299bba9f6289ac79a23e0d8ce38 (diff) |
tools: refactor snapshot builder
This patch:
- Moves the snapshot building code to src/ so that we can reuse it
later when generating custom snapshots from an entry point accepted
by the node binary.
- Create a SnapshotData struct that incorporates all the data useful
for a snapshot blob, including both the V8 data and the Node.js
data.
PR-URL: https://github.com/nodejs/node/pull/38902
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/env.h | 7 | ||||
-rw-r--r-- | src/node.cc | 6 | ||||
-rw-r--r-- | src/node_main_instance.h | 2 | ||||
-rw-r--r-- | src/node_snapshot_stub.cc | 2 | ||||
-rw-r--r-- | src/node_snapshotable.cc | 165 | ||||
-rw-r--r-- | src/node_snapshotable.h | 10 |
6 files changed, 187 insertions, 5 deletions
diff --git a/src/env.h b/src/env.h index 4a50227ee8d..a3944eab90a 100644 --- a/src/env.h +++ b/src/env.h @@ -955,6 +955,13 @@ struct EnvSerializeInfo { friend std::ostream& operator<<(std::ostream& o, const EnvSerializeInfo& i); }; +struct SnapshotData { + SnapshotData() { blob.data = nullptr; } + v8::StartupData blob; + std::vector<size_t> isolate_data_indices; + EnvSerializeInfo env_info; +}; + class Environment : public MemoryRetainer { public: Environment(const Environment&) = delete; diff --git a/src/node.cc b/src/node.cc index 3ca2a05d8b8..75ad5689fca 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1130,7 +1130,7 @@ int Start(int argc, char** argv) { { Isolate::CreateParams params; - const std::vector<size_t>* indexes = nullptr; + const std::vector<size_t>* indices = nullptr; const EnvSerializeInfo* env_info = nullptr; bool force_no_snapshot = per_process::cli_options->per_isolate->no_node_snapshot; @@ -1138,7 +1138,7 @@ int Start(int argc, char** argv) { v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob(); if (blob != nullptr) { params.snapshot_blob = blob; - indexes = NodeMainInstance::GetIsolateDataIndexes(); + indices = NodeMainInstance::GetIsolateDataIndices(); env_info = NodeMainInstance::GetEnvSerializeInfo(); } } @@ -1149,7 +1149,7 @@ int Start(int argc, char** argv) { per_process::v8_platform.Platform(), result.args, result.exec_args, - indexes); + indices); result.exit_code = main_instance.Run(env_info); } diff --git a/src/node_main_instance.h b/src/node_main_instance.h index 6e38e95c266..75d4b7eac50 100644 --- a/src/node_main_instance.h +++ b/src/node_main_instance.h @@ -67,7 +67,7 @@ class NodeMainInstance { // If nullptr is returned, the binary is not built with embedded // snapshot. - static const std::vector<size_t>* GetIsolateDataIndexes(); + static const std::vector<size_t>* GetIsolateDataIndices(); static v8::StartupData* GetEmbeddedSnapshotBlob(); static const EnvSerializeInfo* GetEnvSerializeInfo(); static const std::vector<intptr_t>& CollectExternalReferences(); diff --git a/src/node_snapshot_stub.cc b/src/node_snapshot_stub.cc index 9d7b085994b..7c13d4e8c60 100644 --- a/src/node_snapshot_stub.cc +++ b/src/node_snapshot_stub.cc @@ -10,7 +10,7 @@ v8::StartupData* NodeMainInstance::GetEmbeddedSnapshotBlob() { return nullptr; } -const std::vector<size_t>* NodeMainInstance::GetIsolateDataIndexes() { +const std::vector<size_t>* NodeMainInstance::GetIsolateDataIndices() { return nullptr; } diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index 216a0a9a725..1871cef443f 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -1,16 +1,181 @@ #include "node_snapshotable.h" +#include <iostream> +#include <sstream> #include "base_object-inl.h" #include "debug_utils-inl.h" +#include "env-inl.h" +#include "node_errors.h" +#include "node_external_reference.h" #include "node_file.h" +#include "node_internals.h" +#include "node_main_instance.h" #include "node_v8.h" +#include "node_v8_platform-inl.h" namespace node { +using v8::Context; +using v8::HandleScope; +using v8::Isolate; using v8::Local; using v8::Object; using v8::SnapshotCreator; using v8::StartupData; +using v8::TryCatch; +using v8::Value; + +template <typename T> +void WriteVector(std::ostringstream* ss, const T* vec, size_t size) { + for (size_t i = 0; i < size; i++) { + *ss << std::to_string(vec[i]) << (i == size - 1 ? '\n' : ','); + } +} + +std::string FormatBlob(SnapshotData* data) { + std::ostringstream ss; + + ss << R"(#include <cstddef> +#include "env.h" +#include "node_main_instance.h" +#include "v8.h" + +// This file is generated by tools/snapshot. Do not edit. + +namespace node { + +static const char blob_data[] = { +)"; + WriteVector(&ss, data->blob.data, data->blob.raw_size); + ss << R"(}; + +static const int blob_size = )" + << data->blob.raw_size << R"(; +static v8::StartupData blob = { blob_data, blob_size }; +)"; + + ss << R"(v8::StartupData* NodeMainInstance::GetEmbeddedSnapshotBlob() { + return &blob; +} + +static const std::vector<size_t> isolate_data_indices { +)"; + WriteVector(&ss, + data->isolate_data_indices.data(), + data->isolate_data_indices.size()); + ss << R"(}; + +const std::vector<size_t>* NodeMainInstance::GetIsolateDataIndices() { + return &isolate_data_indices; +} + +static const EnvSerializeInfo env_info )" + << data->env_info << R"(; + +const EnvSerializeInfo* NodeMainInstance::GetEnvSerializeInfo() { + return &env_info; +} + +} // namespace node +)"; + + return ss.str(); +} + +void SnapshotBuilder::Generate(SnapshotData* out, + const std::vector<std::string> args, + const std::vector<std::string> exec_args) { + Isolate* isolate = Isolate::Allocate(); + isolate->SetCaptureStackTraceForUncaughtExceptions( + true, 10, v8::StackTrace::StackTraceOptions::kDetailed); + per_process::v8_platform.Platform()->RegisterIsolate(isolate, + uv_default_loop()); + std::unique_ptr<NodeMainInstance> main_instance; + std::string result; + + { + const std::vector<intptr_t>& external_references = + NodeMainInstance::CollectExternalReferences(); + SnapshotCreator creator(isolate, external_references.data()); + Environment* env; + { + main_instance = + NodeMainInstance::Create(isolate, + uv_default_loop(), + per_process::v8_platform.Platform(), + args, + exec_args); + + HandleScope scope(isolate); + creator.SetDefaultContext(Context::New(isolate)); + out->isolate_data_indices = + main_instance->isolate_data()->Serialize(&creator); + + // Run the per-context scripts + Local<Context> context; + { + TryCatch bootstrapCatch(isolate); + context = NewContext(isolate); + if (bootstrapCatch.HasCaught()) { + PrintCaughtException(isolate, context, bootstrapCatch); + abort(); + } + } + Context::Scope context_scope(context); + + // Create the environment + env = new Environment(main_instance->isolate_data(), + context, + args, + exec_args, + nullptr, + node::EnvironmentFlags::kDefaultFlags, + {}); + // Run scripts in lib/internal/bootstrap/ + { + TryCatch bootstrapCatch(isolate); + v8::MaybeLocal<Value> result = env->RunBootstrapping(); + if (bootstrapCatch.HasCaught()) { + PrintCaughtException(isolate, context, bootstrapCatch); + } + result.ToLocalChecked(); + } + + if (per_process::enabled_debug_list.enabled(DebugCategory::MKSNAPSHOT)) { + env->PrintAllBaseObjects(); + printf("Environment = %p\n", env); + } + + // Serialize the native states + out->env_info = env->Serialize(&creator); + // Serialize the context + size_t index = creator.AddContext( + context, {SerializeNodeContextInternalFields, env}); + CHECK_EQ(index, NodeMainInstance::kNodeContextIndex); + } + + // Must be out of HandleScope + out->blob = + creator.CreateBlob(SnapshotCreator::FunctionCodeHandling::kClear); + CHECK(out->blob.CanBeRehashed()); + // Must be done while the snapshot creator isolate is entered i.e. the + // creator is still alive. + FreeEnvironment(env); + main_instance->Dispose(); + } + + per_process::v8_platform.Platform()->UnregisterIsolate(isolate); +} + +std::string SnapshotBuilder::Generate( + const std::vector<std::string> args, + const std::vector<std::string> exec_args) { + SnapshotData data; + Generate(&data, args, exec_args); + std::string result = FormatBlob(&data); + delete[] data.blob.data; + return result; +} SnapshotableObject::SnapshotableObject(Environment* env, Local<Object> wrap, diff --git a/src/node_snapshotable.h b/src/node_snapshotable.h index c3b82c6edc7..38da68f6d28 100644 --- a/src/node_snapshotable.h +++ b/src/node_snapshotable.h @@ -11,6 +11,7 @@ namespace node { class Environment; struct EnvSerializeInfo; +struct SnapshotData; #define SERIALIZABLE_OBJECT_TYPES(V) \ V(fs_binding_data, fs::BindingData) \ @@ -119,6 +120,15 @@ void SerializeBindingData(Environment* env, EnvSerializeInfo* info); bool IsSnapshotableType(FastStringKey key); + +class SnapshotBuilder { + public: + static std::string Generate(const std::vector<std::string> args, + const std::vector<std::string> exec_args); + static void Generate(SnapshotData* out, + const std::vector<std::string> args, + const std::vector<std::string> exec_args); +}; } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |