Skip to content

Commit 6cb0e58

Browse files
committed
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.
1 parent 2bb0c20 commit 6cb0e58

11 files changed

+189
-196
lines changed

node.gyp

-2
Original file line numberDiff line numberDiff line change
@@ -1554,8 +1554,6 @@
15541554
'src/node_snapshot_stub.cc',
15551555
'src/node_code_cache_stub.cc',
15561556
'tools/snapshot/node_mksnapshot.cc',
1557-
'tools/snapshot/snapshot_builder.cc',
1558-
'tools/snapshot/snapshot_builder.h',
15591557
],
15601558

15611559
'conditions': [

src/env.h

+7
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,13 @@ struct EnvSerializeInfo {
943943
friend std::ostream& operator<<(std::ostream& o, const EnvSerializeInfo& i);
944944
};
945945

946+
struct SnapshotData {
947+
SnapshotData() { blob.data = nullptr; }
948+
v8::StartupData blob;
949+
std::vector<size_t> isolate_data_indices;
950+
EnvSerializeInfo env_info;
951+
};
952+
946953
class Environment : public MemoryRetainer {
947954
public:
948955
Environment(const Environment&) = delete;

src/node.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -1102,15 +1102,15 @@ int Start(int argc, char** argv) {
11021102

11031103
{
11041104
Isolate::CreateParams params;
1105-
const std::vector<size_t>* indexes = nullptr;
1105+
const std::vector<size_t>* indices = nullptr;
11061106
const EnvSerializeInfo* env_info = nullptr;
11071107
bool force_no_snapshot =
11081108
per_process::cli_options->per_isolate->no_node_snapshot;
11091109
if (!force_no_snapshot) {
11101110
v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob();
11111111
if (blob != nullptr) {
11121112
params.snapshot_blob = blob;
1113-
indexes = NodeMainInstance::GetIsolateDataIndexes();
1113+
indices = NodeMainInstance::GetIsolateDataIndices();
11141114
env_info = NodeMainInstance::GetEnvSerializeInfo();
11151115
}
11161116
}
@@ -1121,7 +1121,7 @@ int Start(int argc, char** argv) {
11211121
per_process::v8_platform.Platform(),
11221122
result.args,
11231123
result.exec_args,
1124-
indexes);
1124+
indices);
11251125
result.exit_code = main_instance.Run(env_info);
11261126
}
11271127

src/node_main_instance.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class NodeMainInstance {
6767

6868
// If nullptr is returned, the binary is not built with embedded
6969
// snapshot.
70-
static const std::vector<size_t>* GetIsolateDataIndexes();
70+
static const std::vector<size_t>* GetIsolateDataIndices();
7171
static v8::StartupData* GetEmbeddedSnapshotBlob();
7272
static const EnvSerializeInfo* GetEnvSerializeInfo();
7373
static const std::vector<intptr_t>& CollectExternalReferences();

src/node_snapshot_stub.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ v8::StartupData* NodeMainInstance::GetEmbeddedSnapshotBlob() {
1010
return nullptr;
1111
}
1212

13-
const std::vector<size_t>* NodeMainInstance::GetIsolateDataIndexes() {
13+
const std::vector<size_t>* NodeMainInstance::GetIsolateDataIndices() {
1414
return nullptr;
1515
}
1616

src/node_snapshotable.cc

+165
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,181 @@
11

22
#include "node_snapshotable.h"
3+
#include <iostream>
4+
#include <sstream>
35
#include "base_object-inl.h"
46
#include "debug_utils-inl.h"
7+
#include "env-inl.h"
8+
#include "node_errors.h"
9+
#include "node_external_reference.h"
510
#include "node_file.h"
11+
#include "node_internals.h"
12+
#include "node_main_instance.h"
613
#include "node_v8.h"
14+
#include "node_v8_platform-inl.h"
715

816
namespace node {
917

18+
using v8::Context;
19+
using v8::HandleScope;
20+
using v8::Isolate;
1021
using v8::Local;
1122
using v8::Object;
1223
using v8::SnapshotCreator;
1324
using v8::StartupData;
25+
using v8::TryCatch;
26+
using v8::Value;
27+
28+
template <typename T>
29+
void WriteVector(std::ostringstream* ss, const T* vec, size_t size) {
30+
for (size_t i = 0; i < size; i++) {
31+
*ss << std::to_string(vec[i]) << (i == size - 1 ? '\n' : ',');
32+
}
33+
}
34+
35+
std::string FormatBlob(SnapshotData* data) {
36+
std::ostringstream ss;
37+
38+
ss << R"(#include <cstddef>
39+
#include "env.h"
40+
#include "node_main_instance.h"
41+
#include "v8.h"
42+
43+
// This file is generated by tools/snapshot. Do not edit.
44+
45+
namespace node {
46+
47+
static const char blob_data[] = {
48+
)";
49+
WriteVector(&ss, data->blob.data, data->blob.raw_size);
50+
ss << R"(};
51+
52+
static const int blob_size = )"
53+
<< data->blob.raw_size << R"(;
54+
static v8::StartupData blob = { blob_data, blob_size };
55+
)";
56+
57+
ss << R"(v8::StartupData* NodeMainInstance::GetEmbeddedSnapshotBlob() {
58+
return &blob;
59+
}
60+
61+
static const std::vector<size_t> isolate_data_indices {
62+
)";
63+
WriteVector(&ss,
64+
data->isolate_data_indices.data(),
65+
data->isolate_data_indices.size());
66+
ss << R"(};
67+
68+
const std::vector<size_t>* NodeMainInstance::GetIsolateDataIndices() {
69+
return &isolate_data_indices;
70+
}
71+
72+
static const EnvSerializeInfo env_info )"
73+
<< data->env_info << R"(;
74+
75+
const EnvSerializeInfo* NodeMainInstance::GetEnvSerializeInfo() {
76+
return &env_info;
77+
}
78+
79+
} // namespace node
80+
)";
81+
82+
return ss.str();
83+
}
84+
85+
void SnapshotBuilder::Generate(SnapshotData* out,
86+
const std::vector<std::string> args,
87+
const std::vector<std::string> exec_args) {
88+
Isolate* isolate = Isolate::Allocate();
89+
isolate->SetCaptureStackTraceForUncaughtExceptions(
90+
true, 10, v8::StackTrace::StackTraceOptions::kDetailed);
91+
per_process::v8_platform.Platform()->RegisterIsolate(isolate,
92+
uv_default_loop());
93+
std::unique_ptr<NodeMainInstance> main_instance;
94+
std::string result;
95+
96+
{
97+
const std::vector<intptr_t>& external_references =
98+
NodeMainInstance::CollectExternalReferences();
99+
SnapshotCreator creator(isolate, external_references.data());
100+
Environment* env;
101+
{
102+
main_instance =
103+
NodeMainInstance::Create(isolate,
104+
uv_default_loop(),
105+
per_process::v8_platform.Platform(),
106+
args,
107+
exec_args);
108+
109+
HandleScope scope(isolate);
110+
creator.SetDefaultContext(Context::New(isolate));
111+
out->isolate_data_indices =
112+
main_instance->isolate_data()->Serialize(&creator);
113+
114+
// Run the per-context scripts
115+
Local<Context> context;
116+
{
117+
TryCatch bootstrapCatch(isolate);
118+
context = NewContext(isolate);
119+
if (bootstrapCatch.HasCaught()) {
120+
PrintCaughtException(isolate, context, bootstrapCatch);
121+
abort();
122+
}
123+
}
124+
Context::Scope context_scope(context);
125+
126+
// Create the environment
127+
env = new Environment(main_instance->isolate_data(),
128+
context,
129+
args,
130+
exec_args,
131+
nullptr,
132+
node::EnvironmentFlags::kDefaultFlags,
133+
{});
134+
// Run scripts in lib/internal/bootstrap/
135+
{
136+
TryCatch bootstrapCatch(isolate);
137+
v8::MaybeLocal<Value> result = env->RunBootstrapping();
138+
if (bootstrapCatch.HasCaught()) {
139+
PrintCaughtException(isolate, context, bootstrapCatch);
140+
}
141+
result.ToLocalChecked();
142+
}
143+
144+
if (per_process::enabled_debug_list.enabled(DebugCategory::MKSNAPSHOT)) {
145+
env->PrintAllBaseObjects();
146+
printf("Environment = %p\n", env);
147+
}
148+
149+
// Serialize the native states
150+
out->env_info = env->Serialize(&creator);
151+
// Serialize the context
152+
size_t index = creator.AddContext(
153+
context, {SerializeNodeContextInternalFields, env});
154+
CHECK_EQ(index, NodeMainInstance::kNodeContextIndex);
155+
}
156+
157+
// Must be out of HandleScope
158+
out->blob =
159+
creator.CreateBlob(SnapshotCreator::FunctionCodeHandling::kClear);
160+
CHECK(out->blob.CanBeRehashed());
161+
// Must be done while the snapshot creator isolate is entered i.e. the
162+
// creator is still alive.
163+
FreeEnvironment(env);
164+
main_instance->Dispose();
165+
}
166+
167+
per_process::v8_platform.Platform()->UnregisterIsolate(isolate);
168+
}
169+
170+
std::string SnapshotBuilder::Generate(
171+
const std::vector<std::string> args,
172+
const std::vector<std::string> exec_args) {
173+
SnapshotData data;
174+
Generate(&data, args, exec_args);
175+
std::string result = FormatBlob(&data);
176+
delete[] data.blob.data;
177+
return result;
178+
}
14179

15180
SnapshotableObject::SnapshotableObject(Environment* env,
16181
Local<Object> wrap,

src/node_snapshotable.h

+10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace node {
1111

1212
class Environment;
1313
struct EnvSerializeInfo;
14+
struct SnapshotData;
1415

1516
#define SERIALIZABLE_OBJECT_TYPES(V) \
1617
V(fs_binding_data, fs::BindingData) \
@@ -119,6 +120,15 @@ void SerializeBindingData(Environment* env,
119120
EnvSerializeInfo* info);
120121

121122
bool IsSnapshotableType(FastStringKey key);
123+
124+
class SnapshotBuilder {
125+
public:
126+
static std::string Generate(const std::vector<std::string> args,
127+
const std::vector<std::string> exec_args);
128+
static void Generate(SnapshotData* out,
129+
const std::vector<std::string> args,
130+
const std::vector<std::string> exec_args);
131+
};
122132
} // namespace node
123133

124134
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

tools/snapshot/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ into the Node.js executable, `libnode` is first built with these unresolved
2323
symbols:
2424

2525
- `node::NodeMainInstance::GetEmbeddedSnapshotBlob`
26-
- `node::NodeMainInstance::GetIsolateDataIndexes`
26+
- `node::NodeMainInstance::GetIsolateDataIndices`
2727

2828
Then the `node_mksnapshot` executable is built with C++ files in this
2929
directory, as well as `src/node_snapshot_stub.cc` which defines the unresolved

tools/snapshot/node_mksnapshot.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
#include "libplatform/libplatform.h"
99
#include "node_internals.h"
10-
#include "snapshot_builder.h"
10+
#include "node_snapshotable.h"
1111
#include "util-inl.h"
1212
#include "v8.h"
1313

0 commit comments

Comments
 (0)