6
6
#include " json_parser.h"
7
7
#include " node_external_reference.h"
8
8
#include " node_internals.h"
9
+ #include " node_snapshot_builder.h"
9
10
#include " node_union_bytes.h"
11
+ #include " node_v8_platform-inl.h"
10
12
11
13
// The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
12
14
// the Node.js project that is present only once in the entire binary. It is
@@ -64,7 +66,7 @@ class SeaSerializer : public BlobSerializer<SeaSerializer> {
64
66
65
67
template <>
66
68
size_t SeaSerializer::Write (const SeaResource& sea) {
67
- sink.reserve (SeaResource::kHeaderSize + sea.code .size ());
69
+ sink.reserve (SeaResource::kHeaderSize + sea.main_code_or_snapshot .size ());
68
70
69
71
Debug (" Write SEA magic %x\n " , kMagic );
70
72
size_t written_total = WriteArithmetic<uint32_t >(kMagic );
@@ -75,9 +77,12 @@ size_t SeaSerializer::Write(const SeaResource& sea) {
75
77
DCHECK_EQ (written_total, SeaResource::kHeaderSize );
76
78
77
79
Debug (" Write SEA resource code %p, size=%zu\n " ,
78
- sea.code .data (),
79
- sea.code .size ());
80
- written_total += WriteStringView (sea.code , StringLogMode::kAddressAndContent );
80
+ sea.main_code_or_snapshot .data (),
81
+ sea.main_code_or_snapshot .size ());
82
+ written_total +=
83
+ WriteStringView (sea.main_code_or_snapshot ,
84
+ sea.use_snapshot () ? StringLogMode::kAddressOnly
85
+ : StringLogMode::kAddressAndContent );
81
86
return written_total;
82
87
}
83
88
@@ -103,7 +108,10 @@ SeaResource SeaDeserializer::Read() {
103
108
Debug (" Read SEA flags %x\n " , static_cast <uint32_t >(flags));
104
109
CHECK_EQ (read_total, SeaResource::kHeaderSize );
105
110
106
- std::string_view code = ReadStringView (StringLogMode::kAddressAndContent );
111
+ std::string_view code =
112
+ ReadStringView (static_cast <bool >(flags & SeaFlags::kuseSnapshot)
113
+ ? StringLogMode::kAddressOnly
114
+ : StringLogMode::kAddressAndContent );
107
115
Debug (" Read SEA resource code %p, size=%zu\n " , code.data (), code.size ());
108
116
return {flags, code};
109
117
}
@@ -133,6 +141,10 @@ std::string_view FindSingleExecutableBlob() {
133
141
134
142
} // anonymous namespace
135
143
144
+ bool SeaResource::use_snapshot () const {
145
+ return static_cast <bool >(flags & SeaFlags::kuseSnapshot);
146
+ }
147
+
136
148
SeaResource FindSingleExecutableResource () {
137
149
static const SeaResource sea_resource = []() -> SeaResource {
138
150
std::string_view blob = FindSingleExecutableBlob ();
@@ -235,10 +247,23 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
235
247
result.flags |= SeaFlags::kDisableExperimentalSeaWarning ;
236
248
}
237
249
250
+ std::optional<bool > use_snapshot = parser.GetTopLevelBoolField (" useSnapshot" );
251
+ if (!use_snapshot.has_value ()) {
252
+ FPrintF (
253
+ stderr, " \" useSnapshot\" field of %s is not a Boolean\n " , config_path);
254
+ return std::nullopt ;
255
+ }
256
+ if (use_snapshot.value ()) {
257
+ result.flags |= SeaFlags::kuseSnapshot;
258
+ }
259
+
238
260
return result;
239
261
}
240
262
241
- ExitCode GenerateSingleExecutableBlob (const SeaConfig& config) {
263
+ ExitCode GenerateSingleExecutableBlob (
264
+ const SeaConfig& config,
265
+ const std::vector<std::string> args,
266
+ const std::vector<std::string> exec_args) {
242
267
std::string main_script;
243
268
// TODO(joyeecheung): unify the file utils.
244
269
int r = ReadFileSync (&main_script, config.main_path .c_str ());
@@ -248,7 +273,40 @@ ExitCode GenerateSingleExecutableBlob(const SeaConfig& config) {
248
273
return ExitCode::kGenericUserError ;
249
274
}
250
275
251
- SeaResource sea{config.flags , main_script};
276
+ std::vector<char > snapshot_blob;
277
+ bool builds_snapshot_from_main =
278
+ static_cast <bool >(config.flags & SeaFlags::kuseSnapshot);
279
+ if (builds_snapshot_from_main) {
280
+ SnapshotData snapshot;
281
+ std::vector<std::string> patched_args = {args[0 ], GetAnonymousMainPath ()};
282
+ ExitCode exit_code = SnapshotBuilder::Generate (
283
+ &snapshot, patched_args, exec_args, main_script);
284
+ if (exit_code != ExitCode::kNoFailure ) {
285
+ return exit_code;
286
+ }
287
+ auto & persistents = snapshot.env_info .principal_realm .persistent_values ;
288
+ auto it = std::find_if (
289
+ persistents.begin (), persistents.end (), [](const PropInfo& prop) {
290
+ return prop.name == " snapshot_deserialize_main" ;
291
+ });
292
+ if (it == persistents.end ()) {
293
+ FPrintF (
294
+ stderr,
295
+ " %s does not invoke "
296
+ " v8.startupSnapshot.setDeserializeMainFunction(), which is required "
297
+ " for snapshot scripts used to build single executable applications."
298
+ " \n " ,
299
+ config.main_path );
300
+ return ExitCode::kGenericUserError ;
301
+ }
302
+ snapshot.ToBlob (&snapshot_blob);
303
+ }
304
+
305
+ SeaResource sea{
306
+ config.flags ,
307
+ builds_snapshot_from_main
308
+ ? std::string_view{snapshot_blob.data (), snapshot_blob.size ()}
309
+ : std::string_view{main_script.data (), main_script.size ()}};
252
310
253
311
SeaSerializer serializer;
254
312
serializer.Write (sea);
@@ -269,11 +327,14 @@ ExitCode GenerateSingleExecutableBlob(const SeaConfig& config) {
269
327
270
328
} // anonymous namespace
271
329
272
- ExitCode BuildSingleExecutableBlob (const std::string& config_path) {
330
+ ExitCode BuildSingleExecutableBlob (const std::string& config_path,
331
+ const std::vector<std::string>& args,
332
+ const std::vector<std::string>& exec_args) {
273
333
std::optional<SeaConfig> config_opt =
274
334
ParseSingleExecutableConfig (config_path);
275
335
if (config_opt.has_value ()) {
276
- ExitCode code = GenerateSingleExecutableBlob (config_opt.value ());
336
+ ExitCode code =
337
+ GenerateSingleExecutableBlob (config_opt.value (), args, exec_args);
277
338
return code;
278
339
}
279
340
0 commit comments