LCOV - code coverage report
Current view: top level - src/snapshot - embedded-file-writer.h (source / functions) Hit Total Coverage
Test: app.info Lines: 108 118 91.5 %
Date: 2019-02-19 Functions: 14 16 87.5 %

          Line data    Source code
       1             : // Copyright 2018 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             : #ifndef V8_SNAPSHOT_EMBEDDED_FILE_WRITER_H_
       6             : #define V8_SNAPSHOT_EMBEDDED_FILE_WRITER_H_
       7             : 
       8             : #include <cstdio>
       9             : #include <cstring>
      10             : 
      11             : #include "src/globals.h"
      12             : #include "src/snapshot/snapshot.h"
      13             : #include "src/source-position-table.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18             : enum DataDirective {
      19             :   kByte,
      20             :   kLong,
      21             :   kQuad,
      22             :   kOcta,
      23             : };
      24             : 
      25             : static constexpr char kDefaultEmbeddedVariant[] = "Default";
      26             : 
      27             : // The platform-dependent logic for emitting assembly code for the generated
      28             : // embedded.S file.
      29             : class EmbeddedFileWriter;
      30             : class PlatformDependentEmbeddedFileWriter final {
      31             :  public:
      32           1 :   void SetFile(FILE* fp) { fp_ = fp; }
      33             : 
      34             :   void SectionText();
      35             :   void SectionData();
      36             :   void SectionRoData();
      37             : 
      38             :   void AlignToCodeAlignment();
      39             :   void AlignToDataAlignment();
      40             : 
      41             :   void DeclareUint32(const char* name, uint32_t value);
      42             :   void DeclarePointerToSymbol(const char* name, const char* target);
      43             : 
      44             :   void DeclareLabel(const char* name);
      45             : 
      46             :   void SourceInfo(int fileid, int line);
      47             :   void DeclareFunctionBegin(const char* name);
      48             :   void DeclareFunctionEnd(const char* name);
      49             : 
      50             :   // Returns the number of printed characters.
      51             :   int HexLiteral(uint64_t value);
      52             : 
      53             :   void Comment(const char* string);
      54        4266 :   void Newline() { fprintf(fp_, "\n"); }
      55             : 
      56             :   void FilePrologue();
      57             :   void DeclareExternalFilename(int fileid, const char* filename);
      58             :   void FileEpilogue();
      59             : 
      60             :   int IndentedDataDirective(DataDirective directive);
      61             : 
      62      172020 :   FILE* fp() const { return fp_; }
      63             : 
      64             :  private:
      65             :   void DeclareSymbolGlobal(const char* name);
      66             : 
      67             :  private:
      68             :   FILE* fp_ = nullptr;
      69             : };
      70             : 
      71             : // When writing out compiled builtins to a file, we
      72             : // Detailed source-code information about builtins can only be obtained by
      73             : // registration on the isolate during compilation.
      74           1 : class EmbeddedFileWriterInterface {
      75             :  public:
      76             :   // We maintain a database of filenames to synthetic IDs.
      77             :   virtual int LookupOrAddExternallyCompiledFilename(const char* filename) = 0;
      78             :   virtual const char* GetExternallyCompiledFilename(int index) const = 0;
      79             :   virtual int GetExternallyCompiledFilenameCount() const = 0;
      80             : 
      81             :   // The isolate will call the method below just prior to replacing the
      82             :   // compiled builtin Code objects with trampolines.
      83             :   virtual void PrepareBuiltinSourcePositionMap(Builtins* builtins) = 0;
      84             : };
      85             : 
      86             : // Generates the embedded.S file which is later compiled into the final v8
      87             : // binary. Its contents are exported through two symbols:
      88             : //
      89             : // v8_<variant>_embedded_blob_ (intptr_t):
      90             : //     a pointer to the start of the embedded blob.
      91             : // v8_<variant>_embedded_blob_size_ (uint32_t):
      92             : //     size of the embedded blob in bytes.
      93             : //
      94             : // The variant is usually "Default" but can be modified in multisnapshot builds.
      95        1511 : class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
      96             :  public:
      97       13592 :   int LookupOrAddExternallyCompiledFilename(const char* filename) override {
      98             :     auto result = external_filenames_.find(filename);
      99       13592 :     if (result != external_filenames_.end()) {
     100       13559 :       return result->second;
     101             :     }
     102             :     int new_id =
     103          33 :         ExternalFilenameIndexToId(static_cast<int>(external_filenames_.size()));
     104          66 :     external_filenames_.insert(std::make_pair(filename, new_id));
     105          33 :     external_filenames_by_index_.push_back(filename);
     106             :     DCHECK_EQ(external_filenames_by_index_.size(), external_filenames_.size());
     107          33 :     return new_id;
     108             :   }
     109             : 
     110           0 :   const char* GetExternallyCompiledFilename(int fileid) const override {
     111           0 :     size_t index = static_cast<size_t>(ExternalFilenameIdToIndex(fileid));
     112             :     DCHECK_GE(index, 0);
     113             :     DCHECK_LT(index, external_filenames_by_index_.size());
     114             : 
     115           0 :     return external_filenames_by_index_[index];
     116             :   }
     117             : 
     118           0 :   int GetExternallyCompiledFilenameCount() const override {
     119           0 :     return static_cast<int>(external_filenames_.size());
     120             :   }
     121             : 
     122             :   void PrepareBuiltinSourcePositionMap(Builtins* builtins) override;
     123             : 
     124             :   void SetEmbeddedFile(const char* embedded_src_path) {
     125           1 :     embedded_src_path_ = embedded_src_path;
     126             :   }
     127             : 
     128             :   void SetEmbeddedVariant(const char* embedded_variant) {
     129           1 :     embedded_variant_ = embedded_variant;
     130             :   }
     131             : 
     132             :   void WriteEmbedded(const i::EmbeddedData* blob) const {
     133           1 :     MaybeWriteEmbeddedFile(blob);
     134             :   }
     135             : 
     136             :  private:
     137           2 :   void MaybeWriteEmbeddedFile(const i::EmbeddedData* blob) const {
     138           1 :     if (embedded_src_path_ == nullptr) return;
     139             : 
     140           1 :     FILE* fp = GetFileDescriptorOrDie(embedded_src_path_);
     141             : 
     142           1 :     PlatformDependentEmbeddedFileWriter writer;
     143             :     writer.SetFile(fp);
     144             : 
     145           1 :     WriteFilePrologue(&writer);
     146           1 :     WriteExternalFilenames(&writer);
     147           1 :     WriteMetadataSection(&writer, blob);
     148           1 :     WriteInstructionStreams(&writer, blob);
     149           1 :     WriteFileEpilogue(&writer, blob);
     150             : 
     151           1 :     fclose(fp);
     152             :   }
     153             : 
     154           1 :   static FILE* GetFileDescriptorOrDie(const char* filename) {
     155           1 :     FILE* fp = v8::base::OS::FOpen(filename, "wb");
     156           1 :     if (fp == nullptr) {
     157           0 :       i::PrintF("Unable to open file \"%s\" for writing.\n", filename);
     158           0 :       exit(1);
     159             :     }
     160           1 :     return fp;
     161             :   }
     162             : 
     163           1 :   void WriteFilePrologue(PlatformDependentEmbeddedFileWriter* w) const {
     164           1 :     w->Comment("Autogenerated file. Do not edit.");
     165             :     w->Newline();
     166           1 :     w->FilePrologue();
     167           1 :   }
     168             : 
     169           1 :   void WriteExternalFilenames(PlatformDependentEmbeddedFileWriter* w) const {
     170             :     w->Comment(
     171           1 :         "Source positions in the embedded blob refer to filenames by id.");
     172           1 :     w->Comment("Assembly directives here map the id to a filename.");
     173             :     w->Newline();
     174             : 
     175             :     // Write external filenames.
     176          35 :     int size = static_cast<int>(external_filenames_by_index_.size());
     177          35 :     for (int i = 0; i < size; i++) {
     178             :       w->DeclareExternalFilename(ExternalFilenameIndexToId(i),
     179          99 :                                  external_filenames_by_index_[i]);
     180             :     }
     181           1 :   }
     182             : 
     183             :   // Fairly arbitrary but should fit all symbol names.
     184             :   static constexpr int kTemporaryStringLength = 256;
     185             : 
     186           1 :   void WriteMetadataSection(PlatformDependentEmbeddedFileWriter* w,
     187           1 :                             const i::EmbeddedData* blob) const {
     188             :     char embedded_blob_data_symbol[kTemporaryStringLength];
     189             :     i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol),
     190           2 :                 "v8_%s_embedded_blob_data_", embedded_variant_);
     191             : 
     192           1 :     w->Comment("The embedded blob starts here. Metadata comes first, followed");
     193           1 :     w->Comment("by builtin instruction streams.");
     194           1 :     w->SectionText();
     195           1 :     w->AlignToCodeAlignment();
     196           1 :     w->DeclareLabel(embedded_blob_data_symbol);
     197             : 
     198             :     WriteBinaryContentsAsInlineAssembly(w, blob->data(),
     199           1 :                                         i::EmbeddedData::RawDataOffset());
     200           1 :   }
     201             : 
     202        1505 :   void WriteBuiltin(PlatformDependentEmbeddedFileWriter* w,
     203             :                     const i::EmbeddedData* blob, const int builtin_id) const {
     204             :     const bool is_default_variant =
     205        1505 :         std::strcmp(embedded_variant_, kDefaultEmbeddedVariant) == 0;
     206             : 
     207             :     char builtin_symbol[kTemporaryStringLength];
     208        1505 :     if (is_default_variant) {
     209             :       // Create nicer symbol names for the default mode.
     210             :       i::SNPrintF(i::Vector<char>(builtin_symbol), "Builtins_%s",
     211        3010 :                   i::Builtins::name(builtin_id));
     212             :     } else {
     213             :       i::SNPrintF(i::Vector<char>(builtin_symbol), "%s_Builtins_%s",
     214           0 :                   embedded_variant_, i::Builtins::name(builtin_id));
     215             :     }
     216             : 
     217             :     // Labels created here will show up in backtraces. We check in
     218             :     // Isolate::SetEmbeddedBlob that the blob layout remains unchanged, i.e.
     219             :     // that labels do not insert bytes into the middle of the blob byte
     220             :     // stream.
     221        1505 :     w->DeclareFunctionBegin(builtin_symbol);
     222        1505 :     const std::vector<byte>& current_positions = source_positions_[builtin_id];
     223             : 
     224             :     // The code below interleaves bytes of assembly code for the builtin
     225             :     // function with source positions at the appropriate offsets.
     226             :     Vector<const byte> vpos(current_positions.data(), current_positions.size());
     227             :     v8::internal::SourcePositionTableIterator positions(
     228        1505 :         vpos, SourcePositionTableIterator::kExternalOnly);
     229             : 
     230             :     const uint8_t* data = reinterpret_cast<const uint8_t*>(
     231        1505 :         blob->InstructionStartOfBuiltin(builtin_id));
     232             :     uint32_t size = blob->PaddedInstructionSizeOfBuiltin(builtin_id);
     233             :     uint32_t i = 0;
     234             :     uint32_t next_offset = static_cast<uint32_t>(
     235        1505 :         positions.done() ? size : positions.code_offset());
     236        5455 :     while (i < size) {
     237        2445 :       if (i == next_offset) {
     238             :         // Write source directive.
     239             :         w->SourceInfo(positions.source_position().ExternalFileId(),
     240        1880 :                       positions.source_position().ExternalLine());
     241         940 :         positions.Advance();
     242             :         next_offset = static_cast<uint32_t>(
     243         940 :             positions.done() ? size : positions.code_offset());
     244             :       }
     245        2445 :       CHECK_GE(next_offset, i);
     246        2445 :       WriteBinaryContentsAsInlineAssembly(w, data + i, next_offset - i);
     247             :       i = next_offset;
     248             :     }
     249             : 
     250        1505 :     w->DeclareFunctionEnd(builtin_symbol);
     251        1505 :   }
     252             : 
     253           1 :   void WriteInstructionStreams(PlatformDependentEmbeddedFileWriter* w,
     254             :                                const i::EmbeddedData* blob) const {
     255        1506 :     for (int i = 0; i < i::Builtins::builtin_count; i++) {
     256        1505 :       if (!blob->ContainsBuiltin(i)) continue;
     257             : 
     258        1505 :       WriteBuiltin(w, blob, i);
     259             :     }
     260             :     w->Newline();
     261           1 :   }
     262             : 
     263           1 :   void WriteFileEpilogue(PlatformDependentEmbeddedFileWriter* w,
     264           1 :                          const i::EmbeddedData* blob) const {
     265             :     {
     266             :       char embedded_blob_data_symbol[kTemporaryStringLength];
     267             :       i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol),
     268           2 :                   "v8_%s_embedded_blob_data_", embedded_variant_);
     269             : 
     270             :       char embedded_blob_symbol[kTemporaryStringLength];
     271             :       i::SNPrintF(i::Vector<char>(embedded_blob_symbol), "v8_%s_embedded_blob_",
     272           2 :                   embedded_variant_);
     273             : 
     274           1 :       w->Comment("Pointer to the beginning of the embedded blob.");
     275           1 :       w->SectionData();
     276           1 :       w->AlignToDataAlignment();
     277             :       w->DeclarePointerToSymbol(embedded_blob_symbol,
     278           1 :                                 embedded_blob_data_symbol);
     279             :       w->Newline();
     280             :     }
     281             : 
     282             :     {
     283             :       char embedded_blob_size_symbol[kTemporaryStringLength];
     284             :       i::SNPrintF(i::Vector<char>(embedded_blob_size_symbol),
     285           2 :                   "v8_%s_embedded_blob_size_", embedded_variant_);
     286             : 
     287           1 :       w->Comment("The size of the embedded blob in bytes.");
     288           1 :       w->SectionRoData();
     289           1 :       w->AlignToDataAlignment();
     290           1 :       w->DeclareUint32(embedded_blob_size_symbol, blob->size());
     291             :       w->Newline();
     292             :     }
     293             : 
     294           1 :     w->FileEpilogue();
     295           1 :   }
     296             : 
     297             : #if defined(_MSC_VER) && !defined(__clang__)
     298             : #define V8_COMPILER_IS_MSVC
     299             : #endif
     300             : 
     301             : #if defined(V8_COMPILER_IS_MSVC) || defined(V8_OS_AIX)
     302             :   // Windows MASM doesn't have an .octa directive, use QWORDs instead.
     303             :   // Note: MASM *really* does not like large data streams. It takes over 5
     304             :   // minutes to assemble the ~350K lines of embedded.S produced when using
     305             :   // BYTE directives in a debug build. QWORD produces roughly 120KLOC and
     306             :   // reduces assembly time to ~40 seconds. Still terrible, but much better
     307             :   // than before. See also: https://crbug.com/v8/8475.
     308             : 
     309             :   // GCC MASM on Aix doesn't have an .octa directive, use .llong instead.
     310             : 
     311             :   static constexpr DataDirective kByteChunkDirective = kQuad;
     312             :   static constexpr int kByteChunkSize = 8;
     313             : 
     314             :   static int WriteByteChunk(PlatformDependentEmbeddedFileWriter* w,
     315             :                             int current_line_length, const uint8_t* data) {
     316             :     const uint64_t* quad_ptr = reinterpret_cast<const uint64_t*>(data);
     317             :     return current_line_length + w->HexLiteral(*quad_ptr);
     318             :   }
     319             : #else  // defined(V8_COMPILER_IS_MSVC) || defined(V8_OS_AIX)
     320             :   static constexpr DataDirective kByteChunkDirective = kOcta;
     321             :   static constexpr int kByteChunkSize = 16;
     322             : 
     323       72812 :   static int WriteByteChunk(PlatformDependentEmbeddedFileWriter* w,
     324             :                             int current_line_length, const uint8_t* data) {
     325             :     const size_t size = kInt64Size;
     326             : 
     327             :     uint64_t part1, part2;
     328             :     // Use memcpy for the reads since {data} is not guaranteed to be aligned.
     329             : #ifdef V8_TARGET_BIG_ENDIAN
     330             :     memcpy(&part1, data, size);
     331             :     memcpy(&part2, data + size, size);
     332             : #else
     333             :     memcpy(&part1, data + size, size);
     334             :     memcpy(&part2, data, size);
     335             : #endif  // V8_TARGET_BIG_ENDIAN
     336             : 
     337       72812 :     if (part1 != 0) {
     338             :       current_line_length +=
     339       72812 :           fprintf(w->fp(), "0x%" PRIx64 "%016" PRIx64, part1, part2);
     340             :     } else {
     341           0 :       current_line_length += fprintf(w->fp(), "0x%" PRIx64, part2);
     342             :     }
     343       72812 :     return current_line_length;
     344             :   }
     345             : #endif  // defined(V8_COMPILER_IS_MSVC) || defined(V8_OS_AIX)
     346             : #undef V8_COMPILER_IS_MSVC
     347             : 
     348      103468 :   static int WriteDirectiveOrSeparator(PlatformDependentEmbeddedFileWriter* w,
     349             :                                        int current_line_length,
     350             :                                        DataDirective directive) {
     351             :     int printed_chars;
     352      103468 :     if (current_line_length == 0) {
     353       39640 :       printed_chars = w->IndentedDataDirective(directive);
     354             :       DCHECK_LT(0, printed_chars);
     355             :     } else {
     356             :       printed_chars = fprintf(w->fp(), ",");
     357             :       DCHECK_EQ(1, printed_chars);
     358             :     }
     359      103468 :     return current_line_length + printed_chars;
     360             :   }
     361             : 
     362             :   static int WriteLineEndIfNeeded(PlatformDependentEmbeddedFileWriter* w,
     363             :                                   int current_line_length, int write_size) {
     364             :     static const int kTextWidth = 100;
     365             :     // Check if adding ',0xFF...FF\n"' would force a line wrap. This doesn't use
     366             :     // the actual size of the string to be written to determine this so it's
     367             :     // more conservative than strictly needed.
     368      103468 :     if (current_line_length + strlen(",0x") + write_size * 2 > kTextWidth) {
     369             :       fprintf(w->fp(), "\n");
     370             :       return 0;
     371             :     } else {
     372             :       return current_line_length;
     373             :     }
     374             :   }
     375             : 
     376        2446 :   static void WriteBinaryContentsAsInlineAssembly(
     377             :       PlatformDependentEmbeddedFileWriter* w, const uint8_t* data,
     378             :       uint32_t size) {
     379             :     int current_line_length = 0;
     380             :     uint32_t i = 0;
     381             : 
     382             :     // Begin by writing out byte chunks.
     383       77704 :     for (; i + kByteChunkSize < size; i += kByteChunkSize) {
     384             :       current_line_length = WriteDirectiveOrSeparator(w, current_line_length,
     385       72812 :                                                       kByteChunkDirective);
     386       72812 :       current_line_length = WriteByteChunk(w, current_line_length, data + i);
     387             :       current_line_length =
     388             :           WriteLineEndIfNeeded(w, current_line_length, kByteChunkSize);
     389             :     }
     390        2446 :     if (current_line_length != 0) w->Newline();
     391             :     current_line_length = 0;
     392             : 
     393             :     // Write any trailing bytes one-by-one.
     394       30656 :     for (; i < size; i++) {
     395             :       current_line_length =
     396       30656 :           WriteDirectiveOrSeparator(w, current_line_length, kByte);
     397       30656 :       current_line_length += w->HexLiteral(data[i]);
     398             :       current_line_length = WriteLineEndIfNeeded(w, current_line_length, 1);
     399             :     }
     400             : 
     401        2446 :     if (current_line_length != 0) w->Newline();
     402        2446 :   }
     403             : 
     404             :   static int ExternalFilenameIndexToId(int index) {
     405          66 :     return kFirstExternalFilenameId + index;
     406             :   }
     407             : 
     408             :   static int ExternalFilenameIdToIndex(int id) {
     409           0 :     return id - kFirstExternalFilenameId;
     410             :   }
     411             : 
     412             :   std::vector<byte> source_positions_[Builtins::builtin_count];
     413             : 
     414             :   // In assembly directives, filename ids need to begin with 1.
     415             :   static const int kFirstExternalFilenameId = 1;
     416             :   std::map<const char*, int> external_filenames_;
     417             :   std::vector<const char*> external_filenames_by_index_;
     418             : 
     419             :   const char* embedded_src_path_ = nullptr;
     420             :   const char* embedded_variant_ = kDefaultEmbeddedVariant;
     421             : };
     422             : 
     423             : }  // namespace internal
     424             : }  // namespace v8
     425             : 
     426             : #endif  // V8_SNAPSHOT_EMBEDDED_FILE_WRITER_H_

Generated by: LCOV version 1.10