LCOV - code coverage report
Current view: top level - src/snapshot - mksnapshot.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 69 154 44.8 %
Date: 2019-04-17 Functions: 10 18 55.6 %

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

Generated by: LCOV version 1.10