66#include  " json_parser.h" 
77#include  " node_external_reference.h" 
88#include  " node_internals.h" 
9+ #include  " node_snapshot_builder.h" 
910#include  " node_union_bytes.h" 
11+ #include  " node_v8_platform-inl.h" 
1012
1113//  The POSTJECT_SENTINEL_FUSE macro is a string of random characters selected by
1214//  the Node.js project that is present only once in the entire binary. It is
@@ -64,7 +66,7 @@ class SeaSerializer : public BlobSerializer<SeaSerializer> {
6466
6567template  <>
6668size_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 ());
6870
6971  Debug (" Write SEA magic %x\n " kMagic );
7072  size_t  written_total = WriteArithmetic<uint32_t >(kMagic );
@@ -75,9 +77,12 @@ size_t SeaSerializer::Write(const SeaResource& sea) {
7577  DCHECK_EQ (written_total, SeaResource::kHeaderSize );
7678
7779  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 );
8186  return  written_total;
8287}
8388
@@ -103,7 +108,10 @@ SeaResource SeaDeserializer::Read() {
103108  Debug (" Read SEA flags %x\n " static_cast <uint32_t >(flags));
104109  CHECK_EQ (read_total, SeaResource::kHeaderSize );
105110
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 );
107115  Debug (" Read SEA resource code %p, size=%zu\n " data (), code.size ());
108116  return  {flags, code};
109117}
@@ -133,6 +141,10 @@ std::string_view FindSingleExecutableBlob() {
133141
134142}  //  anonymous namespace
135143
144+ bool  SeaResource::use_snapshot () const  {
145+   return  static_cast <bool >(flags & SeaFlags::kuseSnapshot);
146+ }
147+ 
136148SeaResource FindSingleExecutableResource () {
137149  static  const  SeaResource sea_resource = []() -> SeaResource {
138150    std::string_view blob = FindSingleExecutableBlob ();
@@ -235,10 +247,23 @@ std::optional<SeaConfig> ParseSingleExecutableConfig(
235247    result.flags  |= SeaFlags::kDisableExperimentalSeaWarning ;
236248  }
237249
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 " 
254+     return  std::nullopt ;
255+   }
256+   if  (use_snapshot.value ()) {
257+     result.flags  |= SeaFlags::kuseSnapshot;
258+   }
259+ 
238260  return  result;
239261}
240262
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) {
242267  std::string main_script;
243268  //  TODO(joyeecheung): unify the file utils.
244269  int  r = ReadFileSync (&main_script, config.main_path .c_str ());
@@ -248,7 +273,40 @@ ExitCode GenerateSingleExecutableBlob(const SeaConfig& config) {
248273    return  ExitCode::kGenericUserError ;
249274  }
250275
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 ()}};
252310
253311  SeaSerializer serializer;
254312  serializer.Write (sea);
@@ -269,11 +327,14 @@ ExitCode GenerateSingleExecutableBlob(const SeaConfig& config) {
269327
270328}  //  anonymous namespace
271329
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) {
273333  std::optional<SeaConfig> config_opt =
274334      ParseSingleExecutableConfig (config_path);
275335  if  (config_opt.has_value ()) {
276-     ExitCode code = GenerateSingleExecutableBlob (config_opt.value ());
336+     ExitCode code =
337+         GenerateSingleExecutableBlob (config_opt.value (), args, exec_args);
277338    return  code;
278339  }
279340
0 commit comments