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