LCOV - code coverage report
Current view: top level - src/snapshot - embedded-file-writer.h (source / functions) Hit Total Coverage
Test: app.info Lines: 76 83 91.6 %
Date: 2019-01-20 Functions: 9 9 100.0 %

          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             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : enum DataDirective {
      18             :   kByte,
      19             :   kLong,
      20             :   kQuad,
      21             :   kOcta,
      22             : };
      23             : 
      24             : static constexpr char kDefaultEmbeddedVariant[] = "Default";
      25             : 
      26             : // The platform-dependent logic for emitting assembly code for the generated
      27             : // embedded.S file.
      28             : class PlatformDependentEmbeddedFileWriter final {
      29             :  public:
      30           1 :   void SetFile(FILE* fp) { fp_ = fp; }
      31             : 
      32             :   void SectionText();
      33             :   void SectionData();
      34             :   void SectionRoData();
      35             : 
      36             :   void AlignToCodeAlignment();
      37             :   void AlignToDataAlignment();
      38             : 
      39             :   void DeclareUint32(const char* name, uint32_t value);
      40             :   void DeclarePointerToSymbol(const char* name, const char* target);
      41             : 
      42             :   void DeclareLabel(const char* name);
      43             : 
      44             :   void DeclareFunctionBegin(const char* name);
      45             :   void DeclareFunctionEnd(const char* name);
      46             : 
      47             :   // Returns the number of printed characters.
      48             :   int HexLiteral(uint64_t value);
      49             : 
      50             :   void Comment(const char* string);
      51         117 :   void Newline() { fprintf(fp_, "\n"); }
      52             : 
      53             :   void FilePrologue();
      54             :   void FileEpilogue();
      55             : 
      56             :   int IndentedDataDirective(DataDirective directive);
      57             : 
      58      146608 :   FILE* fp() const { return fp_; }
      59             : 
      60             :  private:
      61             :   void DeclareSymbolGlobal(const char* name);
      62             : 
      63             :  private:
      64             :   FILE* fp_ = nullptr;
      65             : };
      66             : 
      67             : // Generates the embedded.S file which is later compiled into the final v8
      68             : // binary. Its contents are exported through two symbols:
      69             : //
      70             : // v8_<variant>_embedded_blob_ (intptr_t):
      71             : //     a pointer to the start of the embedded blob.
      72             : // v8_<variant>_embedded_blob_size_ (uint32_t):
      73             : //     size of the embedded blob in bytes.
      74             : //
      75             : // The variant is usually "Default" but can be modified in multisnapshot builds.
      76             : class EmbeddedFileWriter {
      77             :  public:
      78             :   void SetEmbeddedFile(const char* embedded_src_path) {
      79           1 :     embedded_src_path_ = embedded_src_path;
      80             :   }
      81             : 
      82             :   void SetEmbeddedVariant(const char* embedded_variant) {
      83           1 :     embedded_variant_ = embedded_variant;
      84             :   }
      85             : 
      86             :   void WriteEmbedded(const i::EmbeddedData* blob) const {
      87           1 :     MaybeWriteEmbeddedFile(blob);
      88             :   }
      89             : 
      90             :  private:
      91           2 :   void MaybeWriteEmbeddedFile(const i::EmbeddedData* blob) const {
      92           1 :     if (embedded_src_path_ == nullptr) return;
      93             : 
      94           1 :     FILE* fp = GetFileDescriptorOrDie(embedded_src_path_);
      95             : 
      96           1 :     PlatformDependentEmbeddedFileWriter writer;
      97             :     writer.SetFile(fp);
      98             : 
      99           1 :     WriteFilePrologue(&writer);
     100           1 :     WriteMetadataSection(&writer, blob);
     101           1 :     WriteInstructionStreams(&writer, blob);
     102           1 :     WriteFileEpilogue(&writer, blob);
     103             : 
     104           1 :     fclose(fp);
     105             :   }
     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           1 :   static void WriteFilePrologue(PlatformDependentEmbeddedFileWriter* w) {
     117           1 :     w->Comment("Autogenerated file. Do not edit.");
     118             :     w->Newline();
     119           1 :     w->FilePrologue();
     120           1 :   }
     121             : 
     122             :   // Fairly arbitrary but should fit all symbol names.
     123             :   static constexpr int kTemporaryStringLength = 256;
     124             : 
     125           1 :   void WriteMetadataSection(PlatformDependentEmbeddedFileWriter* w,
     126           1 :                             const i::EmbeddedData* blob) const {
     127             :     char embedded_blob_data_symbol[kTemporaryStringLength];
     128             :     i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol),
     129           2 :                 "v8_%s_embedded_blob_data_", embedded_variant_);
     130             : 
     131           1 :     w->Comment("The embedded blob starts here. Metadata comes first, followed");
     132           1 :     w->Comment("by builtin instruction streams.");
     133           1 :     w->SectionText();
     134           1 :     w->AlignToCodeAlignment();
     135           1 :     w->DeclareLabel(embedded_blob_data_symbol);
     136             : 
     137             :     WriteBinaryContentsAsInlineAssembly(w, blob->data(),
     138           1 :                                         i::EmbeddedData::RawDataOffset());
     139           1 :   }
     140             : 
     141           1 :   void WriteInstructionStreams(PlatformDependentEmbeddedFileWriter* w,
     142             :                                const i::EmbeddedData* blob) const {
     143             :     const bool is_default_variant =
     144           1 :         std::strcmp(embedded_variant_, kDefaultEmbeddedVariant) == 0;
     145             : 
     146        1512 :     for (int i = 0; i < i::Builtins::builtin_count; i++) {
     147        1511 :       if (!blob->ContainsBuiltin(i)) continue;
     148             : 
     149             :       char builtin_symbol[kTemporaryStringLength];
     150        1511 :       if (is_default_variant) {
     151             :         // Create nicer symbol names for the default mode.
     152             :         i::SNPrintF(i::Vector<char>(builtin_symbol), "Builtins_%s",
     153        3022 :                     i::Builtins::name(i));
     154             :       } else {
     155             :         i::SNPrintF(i::Vector<char>(builtin_symbol), "%s_Builtins_%s",
     156           0 :                     embedded_variant_, i::Builtins::name(i));
     157             :       }
     158             : 
     159             :       // Labels created here will show up in backtraces. We check in
     160             :       // Isolate::SetEmbeddedBlob that the blob layout remains unchanged, i.e.
     161             :       // that labels do not insert bytes into the middle of the blob byte
     162             :       // stream.
     163        1511 :       w->DeclareFunctionBegin(builtin_symbol);
     164             :       WriteBinaryContentsAsInlineAssembly(
     165             :           w,
     166        1511 :           reinterpret_cast<const uint8_t*>(blob->InstructionStartOfBuiltin(i)),
     167        1511 :           blob->PaddedInstructionSizeOfBuiltin(i));
     168        1511 :       w->DeclareFunctionEnd(builtin_symbol);
     169             :     }
     170             :     w->Newline();
     171           1 :   }
     172             : 
     173           1 :   void WriteFileEpilogue(PlatformDependentEmbeddedFileWriter* w,
     174           1 :                          const i::EmbeddedData* blob) const {
     175             :     {
     176             :       char embedded_blob_data_symbol[kTemporaryStringLength];
     177             :       i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol),
     178           2 :                   "v8_%s_embedded_blob_data_", embedded_variant_);
     179             : 
     180             :       char embedded_blob_symbol[kTemporaryStringLength];
     181             :       i::SNPrintF(i::Vector<char>(embedded_blob_symbol), "v8_%s_embedded_blob_",
     182           2 :                   embedded_variant_);
     183             : 
     184           1 :       w->Comment("Pointer to the beginning of the embedded blob.");
     185           1 :       w->SectionData();
     186           1 :       w->AlignToDataAlignment();
     187             :       w->DeclarePointerToSymbol(embedded_blob_symbol,
     188           1 :                                 embedded_blob_data_symbol);
     189             :       w->Newline();
     190             :     }
     191             : 
     192             :     {
     193             :       char embedded_blob_size_symbol[kTemporaryStringLength];
     194             :       i::SNPrintF(i::Vector<char>(embedded_blob_size_symbol),
     195           2 :                   "v8_%s_embedded_blob_size_", embedded_variant_);
     196             : 
     197           1 :       w->Comment("The size of the embedded blob in bytes.");
     198           1 :       w->SectionRoData();
     199           1 :       w->DeclareUint32(embedded_blob_size_symbol, blob->size());
     200             :       w->Newline();
     201             :     }
     202             : 
     203           1 :     w->FileEpilogue();
     204           1 :   }
     205             : 
     206             : #if defined(_MSC_VER) && !defined(__clang__)
     207             : #define V8_COMPILER_IS_MSVC
     208             : #endif
     209             : 
     210             : #if defined(V8_COMPILER_IS_MSVC) || defined(V8_OS_AIX)
     211             :   // Windows MASM doesn't have an .octa directive, use QWORDs instead.
     212             :   // Note: MASM *really* does not like large data streams. It takes over 5
     213             :   // minutes to assemble the ~350K lines of embedded.S produced when using
     214             :   // BYTE directives in a debug build. QWORD produces roughly 120KLOC and
     215             :   // reduces assembly time to ~40 seconds. Still terrible, but much better
     216             :   // than before. See also: https://crbug.com/v8/8475.
     217             : 
     218             :   // GCC MASM on Aix doesn't have an .octa directive, use .llong instead.
     219             : 
     220             :   static constexpr DataDirective kByteChunkDirective = kQuad;
     221             :   static constexpr int kByteChunkSize = 8;
     222             : 
     223             :   static int WriteByteChunk(PlatformDependentEmbeddedFileWriter* w,
     224             :                             int current_line_length, const uint8_t* data) {
     225             :     const uint64_t* quad_ptr = reinterpret_cast<const uint64_t*>(data);
     226             :     return current_line_length + w->HexLiteral(*quad_ptr);
     227             :   }
     228             : #else  // defined(V8_COMPILER_IS_MSVC) || defined(V8_OS_AIX)
     229             :   static constexpr DataDirective kByteChunkDirective = kOcta;
     230             :   static constexpr int kByteChunkSize = 16;
     231             : 
     232       73360 :   static int WriteByteChunk(PlatformDependentEmbeddedFileWriter* w,
     233             :                             int current_line_length, const uint8_t* data) {
     234             :     const uint64_t* quad_ptr1 = reinterpret_cast<const uint64_t*>(data);
     235             :     const uint64_t* quad_ptr2 = reinterpret_cast<const uint64_t*>(data + 8);
     236             : 
     237             : #ifdef V8_TARGET_BIG_ENDIAN
     238             :     uint64_t part1 = *quad_ptr1;
     239             :     uint64_t part2 = *quad_ptr2;
     240             : #else
     241       73360 :     uint64_t part1 = *quad_ptr2;
     242       73360 :     uint64_t part2 = *quad_ptr1;
     243             : #endif  // V8_TARGET_BIG_ENDIAN
     244             : 
     245       73360 :     if (part1 != 0) {
     246             :       current_line_length +=
     247       73360 :           fprintf(w->fp(), "0x%" PRIx64 "%016" PRIx64, part1, part2);
     248             :     } else {
     249           0 :       current_line_length += fprintf(w->fp(), "0x%" PRIx64, part2);
     250             :     }
     251       73360 :     return current_line_length;
     252             :   }
     253             : #endif  // defined(V8_COMPILER_IS_MSVC) || defined(V8_OS_AIX)
     254             : #undef V8_COMPILER_IS_MSVC
     255             : 
     256       73360 :   static int WriteDirectiveOrSeparator(PlatformDependentEmbeddedFileWriter* w,
     257             :                                        int current_line_length,
     258             :                                        DataDirective directive) {
     259             :     int printed_chars;
     260       73360 :     if (current_line_length == 0) {
     261       36615 :       printed_chars = w->IndentedDataDirective(directive);
     262             :       DCHECK_LT(0, printed_chars);
     263             :     } else {
     264             :       printed_chars = fprintf(w->fp(), ",");
     265             :       DCHECK_EQ(1, printed_chars);
     266             :     }
     267       73360 :     return current_line_length + printed_chars;
     268             :   }
     269             : 
     270             :   static int WriteLineEndIfNeeded(PlatformDependentEmbeddedFileWriter* w,
     271             :                                   int current_line_length, int write_size) {
     272             :     static const int kTextWidth = 100;
     273             :     // Check if adding ',0xFF...FF\n"' would force a line wrap. This doesn't use
     274             :     // the actual size of the string to be written to determine this so it's
     275             :     // more conservative than strictly needed.
     276       73360 :     if (current_line_length + strlen(",0x") + write_size * 2 > kTextWidth) {
     277             :       fprintf(w->fp(), "\n");
     278             :       return 0;
     279             :     } else {
     280             :       return current_line_length;
     281             :     }
     282             :   }
     283             : 
     284        1512 :   static void WriteBinaryContentsAsInlineAssembly(
     285             :       PlatformDependentEmbeddedFileWriter* w, const uint8_t* data,
     286             :       uint32_t size) {
     287             :     int current_line_length = 0;
     288             : 
     289             :     uint32_t i = 0;
     290             : 
     291             :     // Begin by writing out byte chunks.
     292       74872 :     for (; i <= size - kByteChunkSize; i += kByteChunkSize) {
     293             :       current_line_length = WriteDirectiveOrSeparator(w, current_line_length,
     294       73360 :                                                       kByteChunkDirective);
     295       73360 :       current_line_length = WriteByteChunk(w, current_line_length, data + i);
     296             :       current_line_length =
     297             :           WriteLineEndIfNeeded(w, current_line_length, kByteChunkSize);
     298             :     }
     299        1512 :     if (current_line_length != 0) w->Newline();
     300             :     current_line_length = 0;
     301             : 
     302             :     // Write any trailing bytes one-by-one.
     303           0 :     for (; i < size; i++) {
     304             :       current_line_length =
     305           0 :           WriteDirectiveOrSeparator(w, current_line_length, kByte);
     306           0 :       current_line_length += w->HexLiteral(data[i]);
     307             :       current_line_length = WriteLineEndIfNeeded(w, current_line_length, 1);
     308             :     }
     309        1512 :     if (current_line_length != 0) w->Newline();
     310        1512 :   }
     311             : 
     312             :   const char* embedded_src_path_ = nullptr;
     313             :   const char* embedded_variant_ = kDefaultEmbeddedVariant;
     314             : };
     315             : 
     316             : }  // namespace internal
     317             : }  // namespace v8
     318             : 
     319             : #endif  // V8_SNAPSHOT_EMBEDDED_FILE_WRITER_H_

Generated by: LCOV version 1.10