LCOV - code coverage report
Current view: top level - src/snapshot - embedded-file-writer.h (source / functions) Hit Total Coverage
Test: app.info Lines: 117 124 94.4 %
Date: 2019-04-17 Functions: 14 15 93.3 %

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

Generated by: LCOV version 1.10