LCOV - code coverage report
Current view: top level - src/snapshot - mksnapshot.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 64 143 44.8 %
Date: 2019-01-20 Functions: 10 16 62.5 %

          Line data    Source code
       1             : // Copyright 2006-2008 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <errno.h>
       6             : #include <signal.h>
       7             : #include <stdio.h>
       8             : 
       9             : #include "include/libplatform/libplatform.h"
      10             : #include "src/assembler-arch.h"
      11             : #include "src/base/platform/platform.h"
      12             : #include "src/flags.h"
      13             : #include "src/msan.h"
      14             : #include "src/snapshot/embedded-file-writer.h"
      15             : #include "src/snapshot/natives.h"
      16             : #include "src/snapshot/partial-serializer.h"
      17             : #include "src/snapshot/snapshot.h"
      18             : #include "src/snapshot/startup-serializer.h"
      19             : 
      20             : namespace {
      21             : 
      22             : class SnapshotFileWriter {
      23             :  public:
      24             :   void SetSnapshotFile(const char* snapshot_cpp_file) {
      25           1 :     snapshot_cpp_path_ = snapshot_cpp_file;
      26             :   }
      27             : 
      28             :   void SetStartupBlobFile(const char* snapshot_blob_file) {
      29           1 :     snapshot_blob_path_ = snapshot_blob_file;
      30             :   }
      31             : 
      32           2 :   void WriteSnapshot(v8::StartupData blob) const {
      33             :     // TODO(crbug/633159): if we crash before the files have been fully created,
      34             :     // we end up with a corrupted snapshot file. The build step would succeed,
      35             :     // but the build target is unusable. Ideally we would write out temporary
      36             :     // files and only move them to the final destination as last step.
      37             :     i::Vector<const i::byte> blob_vector(
      38           1 :         reinterpret_cast<const i::byte*>(blob.data), blob.raw_size);
      39           1 :     MaybeWriteSnapshotFile(blob_vector);
      40           1 :     MaybeWriteStartupBlob(blob_vector);
      41           1 :   }
      42             : 
      43             :  private:
      44           4 :   void MaybeWriteStartupBlob(const i::Vector<const i::byte>& blob) const {
      45           2 :     if (!snapshot_blob_path_) return;
      46             : 
      47           1 :     FILE* fp = GetFileDescriptorOrDie(snapshot_blob_path_);
      48           2 :     size_t written = fwrite(blob.begin(), 1, blob.length(), fp);
      49           1 :     fclose(fp);
      50           1 :     if (written != static_cast<size_t>(blob.length())) {
      51           0 :       i::PrintF("Writing snapshot file failed.. Aborting.\n");
      52           0 :       remove(snapshot_blob_path_);
      53           0 :       exit(1);
      54             :     }
      55             :   }
      56             : 
      57           1 :   void MaybeWriteSnapshotFile(const i::Vector<const i::byte>& blob) const {
      58           2 :     if (!snapshot_cpp_path_) return;
      59             : 
      60           0 :     FILE* fp = GetFileDescriptorOrDie(snapshot_cpp_path_);
      61             : 
      62           0 :     WriteSnapshotFilePrefix(fp);
      63           0 :     WriteSnapshotFileData(fp, blob);
      64           0 :     WriteSnapshotFileSuffix(fp);
      65             : 
      66           0 :     fclose(fp);
      67             :   }
      68             : 
      69           0 :   static void WriteSnapshotFilePrefix(FILE* fp) {
      70             :     fprintf(fp, "// Autogenerated snapshot file. Do not edit.\n\n");
      71             :     fprintf(fp, "#include \"src/v8.h\"\n");
      72             :     fprintf(fp, "#include \"src/base/platform/platform.h\"\n\n");
      73             :     fprintf(fp, "#include \"src/snapshot/snapshot.h\"\n\n");
      74             :     fprintf(fp, "namespace v8 {\n");
      75             :     fprintf(fp, "namespace internal {\n\n");
      76           0 :   }
      77             : 
      78           0 :   static void WriteSnapshotFileSuffix(FILE* fp) {
      79             :     fprintf(fp, "const v8::StartupData* Snapshot::DefaultSnapshotBlob() {\n");
      80             :     fprintf(fp, "  return &blob;\n");
      81             :     fprintf(fp, "}\n\n");
      82             :     fprintf(fp, "}  // namespace internal\n");
      83             :     fprintf(fp, "}  // namespace v8\n");
      84           0 :   }
      85             : 
      86           0 :   static void WriteSnapshotFileData(FILE* fp,
      87           0 :                                     const i::Vector<const i::byte>& blob) {
      88             :     fprintf(fp, "static const byte blob_data[] = {\n");
      89           0 :     WriteBinaryContentsAsCArray(fp, blob);
      90             :     fprintf(fp, "};\n");
      91             :     fprintf(fp, "static const int blob_size = %d;\n", blob.length());
      92             :     fprintf(fp, "static const v8::StartupData blob =\n");
      93             :     fprintf(fp, "{ (const char*) blob_data, blob_size };\n");
      94           0 :   }
      95             : 
      96           0 :   static void WriteBinaryContentsAsCArray(
      97           0 :       FILE* fp, const i::Vector<const i::byte>& blob) {
      98           0 :     for (int i = 0; i < blob.length(); i++) {
      99           0 :       if ((i & 0x1F) == 0x1F) fprintf(fp, "\n");
     100           0 :       if (i > 0) fprintf(fp, ",");
     101           0 :       fprintf(fp, "%u", static_cast<unsigned char>(blob.at(i)));
     102             :     }
     103             :     fprintf(fp, "\n");
     104           0 :   }
     105             : 
     106           1 :   static FILE* GetFileDescriptorOrDie(const char* filename) {
     107           1 :     FILE* fp = v8::base::OS::FOpen(filename, "wb");
     108           1 :     if (fp == nullptr) {
     109           0 :       i::PrintF("Unable to open file \"%s\" for writing.\n", filename);
     110           0 :       exit(1);
     111             :     }
     112           1 :     return fp;
     113             :   }
     114             : 
     115             :   const char* snapshot_cpp_path_ = nullptr;
     116             :   const char* snapshot_blob_path_ = nullptr;
     117             : };
     118             : 
     119           2 : char* GetExtraCode(char* filename, const char* description) {
     120           2 :   if (filename == nullptr || strlen(filename) == 0) return nullptr;
     121             :   ::printf("Loading script for %s: %s\n", description, filename);
     122           0 :   FILE* file = v8::base::OS::FOpen(filename, "rb");
     123           0 :   if (file == nullptr) {
     124           0 :     fprintf(stderr, "Failed to open '%s': errno %d\n", filename, errno);
     125           0 :     exit(1);
     126             :   }
     127           0 :   fseek(file, 0, SEEK_END);
     128           0 :   size_t size = ftell(file);
     129           0 :   rewind(file);
     130           0 :   char* chars = new char[size + 1];
     131           0 :   chars[size] = '\0';
     132           0 :   for (size_t i = 0; i < size;) {
     133           0 :     size_t read = fread(&chars[i], 1, size - i, file);
     134           0 :     if (ferror(file)) {
     135           0 :       fprintf(stderr, "Failed to read '%s': errno %d\n", filename, errno);
     136           0 :       exit(1);
     137             :     }
     138           0 :     i += read;
     139             :   }
     140           0 :   fclose(file);
     141           0 :   return chars;
     142             : }
     143             : 
     144           0 : bool RunExtraCode(v8::Isolate* isolate, v8::Local<v8::Context> context,
     145             :                   const char* utf8_source, const char* name) {
     146             :   v8::base::ElapsedTimer timer;
     147             :   timer.Start();
     148             :   v8::Context::Scope context_scope(context);
     149           0 :   v8::TryCatch try_catch(isolate);
     150             :   v8::Local<v8::String> source_string;
     151           0 :   if (!v8::String::NewFromUtf8(isolate, utf8_source, v8::NewStringType::kNormal)
     152           0 :            .ToLocal(&source_string)) {
     153             :     return false;
     154             :   }
     155             :   v8::Local<v8::String> resource_name =
     156             :       v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal)
     157           0 :           .ToLocalChecked();
     158             :   v8::ScriptOrigin origin(resource_name);
     159             :   v8::ScriptCompiler::Source source(source_string, origin);
     160             :   v8::Local<v8::Script> script;
     161           0 :   if (!v8::ScriptCompiler::Compile(context, &source).ToLocal(&script))
     162             :     return false;
     163           0 :   if (script->Run(context).IsEmpty()) return false;
     164           0 :   if (i::FLAG_profile_deserialization) {
     165             :     i::PrintF("Executing custom snapshot script %s took %0.3f ms\n", name,
     166           0 :               timer.Elapsed().InMillisecondsF());
     167             :   }
     168             :   timer.Stop();
     169           0 :   CHECK(!try_catch.HasCaught());
     170             :   return true;
     171             : }
     172             : 
     173           1 : v8::StartupData CreateSnapshotDataBlob(v8::SnapshotCreator* snapshot_creator,
     174             :                                        const char* script_source = nullptr) {
     175             :   // Create a new isolate and a new context from scratch, optionally run
     176             :   // a script to embed, and serialize to create a snapshot blob.
     177             :   v8::StartupData result = {nullptr, 0};
     178             :   v8::base::ElapsedTimer timer;
     179             :   timer.Start();
     180             :   {
     181           1 :     v8::Isolate* isolate = snapshot_creator->GetIsolate();
     182             :     {
     183           1 :       v8::HandleScope scope(isolate);
     184           1 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
     185           1 :       if (script_source != nullptr &&
     186           0 :           !RunExtraCode(isolate, context, script_source, "<embedded>")) {
     187           0 :         return result;
     188             :       }
     189           1 :       snapshot_creator->SetDefaultContext(context);
     190             :     }
     191             :     result = snapshot_creator->CreateBlob(
     192           1 :         v8::SnapshotCreator::FunctionCodeHandling::kClear);
     193             :   }
     194             : 
     195           1 :   if (i::FLAG_profile_deserialization) {
     196             :     i::PrintF("Creating snapshot took %0.3f ms\n",
     197           0 :               timer.Elapsed().InMillisecondsF());
     198             :   }
     199             :   timer.Stop();
     200           1 :   return result;
     201             : }
     202             : 
     203           0 : v8::StartupData WarmUpSnapshotDataBlob(v8::SnapshotCreator* snapshot_creator,
     204             :                                        const char* warmup_source) {
     205           0 :   CHECK_NOT_NULL(warmup_source);
     206             :   // Use following steps to create a warmed up snapshot blob from a cold one:
     207             :   //  - Create a new isolate from the cold snapshot.
     208             :   //  - Create a new context to run the warmup script. This will trigger
     209             :   //    compilation of executed functions.
     210             :   //  - Create a new context. This context will be unpolluted.
     211             :   //  - Serialize the isolate and the second context into a new snapshot blob.
     212             :   v8::StartupData result = {nullptr, 0};
     213             :   v8::base::ElapsedTimer timer;
     214             :   timer.Start();
     215             :   {
     216           0 :     v8::Isolate* isolate = snapshot_creator->GetIsolate();
     217             :     {
     218           0 :       v8::HandleScope scope(isolate);
     219           0 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
     220           0 :       if (!RunExtraCode(isolate, context, warmup_source, "<warm-up>")) {
     221           0 :         return result;
     222           0 :       }
     223             :     }
     224             :     {
     225           0 :       v8::HandleScope handle_scope(isolate);
     226           0 :       isolate->ContextDisposedNotification(false);
     227           0 :       v8::Local<v8::Context> context = v8::Context::New(isolate);
     228           0 :       snapshot_creator->SetDefaultContext(context);
     229             :     }
     230             :     result = snapshot_creator->CreateBlob(
     231           0 :         v8::SnapshotCreator::FunctionCodeHandling::kKeep);
     232             :   }
     233             : 
     234           0 :   if (i::FLAG_profile_deserialization) {
     235             :     i::PrintF("Warming up snapshot took %0.3f ms\n",
     236           0 :               timer.Elapsed().InMillisecondsF());
     237             :   }
     238             :   timer.Stop();
     239           0 :   return result;
     240             : }
     241             : 
     242           1 : void WriteEmbeddedFile(i::EmbeddedFileWriter* writer) {
     243           1 :   i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob();
     244             :   writer->WriteEmbedded(&embedded_blob);
     245           1 : }
     246             : }  // namespace
     247             : 
     248           1 : int main(int argc, char** argv) {
     249             :   v8::base::EnsureConsoleOutput();
     250             : 
     251             :   // Make mksnapshot runs predictable to create reproducible snapshots.
     252           1 :   i::FLAG_predictable = true;
     253             : 
     254             :   // Print the usage if an error occurs when parsing the command line
     255             :   // flags or if the help flag is set.
     256           1 :   int result = i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
     257           1 :   if (result > 0 || (argc > 3) || i::FLAG_help) {
     258             :     ::printf("Usage: %s --startup_src=... --startup_blob=... [extras]\n",
     259           0 :              argv[0]);
     260           0 :     i::FlagList::PrintHelp();
     261           0 :     return !i::FLAG_help;
     262             :   }
     263             : 
     264             :   i::CpuFeatures::Probe(true);
     265           1 :   v8::V8::InitializeICUDefaultLocation(argv[0]);
     266           2 :   std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
     267           1 :   v8::V8::InitializePlatform(platform.get());
     268           1 :   v8::V8::Initialize();
     269             : 
     270             :   {
     271           1 :     SnapshotFileWriter snapshot_writer;
     272           1 :     snapshot_writer.SetSnapshotFile(i::FLAG_startup_src);
     273           1 :     snapshot_writer.SetStartupBlobFile(i::FLAG_startup_blob);
     274             : 
     275           1 :     i::EmbeddedFileWriter embedded_writer;
     276           1 :     embedded_writer.SetEmbeddedFile(i::FLAG_embedded_src);
     277           1 :     embedded_writer.SetEmbeddedVariant(i::FLAG_embedded_variant);
     278             : 
     279             :     std::unique_ptr<char> embed_script(
     280           1 :         GetExtraCode(argc >= 2 ? argv[1] : nullptr, "embedding"));
     281             :     std::unique_ptr<char> warmup_script(
     282           1 :         GetExtraCode(argc >= 3 ? argv[2] : nullptr, "warm up"));
     283             : 
     284           1 :     i::DisableEmbeddedBlobRefcounting();
     285             :     v8::StartupData blob;
     286             :     {
     287           1 :       v8::Isolate* isolate = v8::Isolate::Allocate();
     288             :       if (i::FLAG_embedded_builtins) {
     289             :         // Set code range such that relative jumps for builtins to
     290             :         // builtin calls in the snapshot are possible.
     291             :         i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
     292             :         size_t code_range_size =
     293             :             i::kMaximalCodeRangeSize == 0
     294             :                 ? i::kMaxPCRelativeCodeRangeInMB
     295             :                 : std::min(i::kMaximalCodeRangeSize / i::MB,
     296           1 :                            i::kMaxPCRelativeCodeRangeInMB);
     297           1 :         i_isolate->heap()->ConfigureHeap(0, 0, code_range_size);
     298             :       }
     299           1 :       v8::SnapshotCreator snapshot_creator(isolate);
     300           1 :       if (i::FLAG_embedded_builtins) WriteEmbeddedFile(&embedded_writer);
     301           1 :       blob = CreateSnapshotDataBlob(&snapshot_creator, embed_script.get());
     302             :     }
     303             : 
     304           1 :     if (warmup_script) {
     305           0 :       CHECK(blob.raw_size > 0 && blob.data != nullptr);
     306           0 :       v8::StartupData cold = blob;
     307           0 :       v8::SnapshotCreator snapshot_creator(nullptr, &cold);
     308           0 :       blob = WarmUpSnapshotDataBlob(&snapshot_creator, warmup_script.get());
     309           0 :       delete[] cold.data;
     310             :     }
     311             : 
     312           1 :     CHECK(blob.data);
     313           1 :     snapshot_writer.WriteSnapshot(blob);
     314           1 :     delete[] blob.data;
     315             :   }
     316           1 :   i::FreeCurrentEmbeddedBlob();
     317             : 
     318           1 :   v8::V8::Dispose();
     319           1 :   v8::V8::ShutdownPlatform();
     320             :   return 0;
     321           3 : }

Generated by: LCOV version 1.10