LCOV - code coverage report
Current view: top level - src/snapshot - mksnapshot.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 64 142 45.1 %
Date: 2019-03-21 Functions: 9 15 60.0 %

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

Generated by: LCOV version 1.10