• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "src/snapshot/embedded/embedded-file-writer.h"
6 
7 #include <algorithm>
8 #include <cinttypes>
9 
10 #include "src/codegen/source-position-table.h"
11 #include "src/flags/flags.h"  // For ENABLE_CONTROL_FLOW_INTEGRITY_BOOL
12 #include "src/objects/code-inl.h"
13 #include "src/snapshot/embedded/embedded-data-inl.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 namespace {
19 
WriteDirectiveOrSeparator(PlatformEmbeddedFileWriterBase * w,int current_line_length,DataDirective directive)20 int WriteDirectiveOrSeparator(PlatformEmbeddedFileWriterBase* w,
21                               int current_line_length,
22                               DataDirective directive) {
23   int printed_chars;
24   if (current_line_length == 0) {
25     printed_chars = w->IndentedDataDirective(directive);
26     DCHECK_LT(0, printed_chars);
27   } else {
28     printed_chars = fprintf(w->fp(), ",");
29     DCHECK_EQ(1, printed_chars);
30   }
31   return current_line_length + printed_chars;
32 }
33 
WriteLineEndIfNeeded(PlatformEmbeddedFileWriterBase * w,int current_line_length,int write_size)34 int WriteLineEndIfNeeded(PlatformEmbeddedFileWriterBase* w,
35                          int current_line_length, int write_size) {
36   static const int kTextWidth = 100;
37   // Check if adding ',0xFF...FF\n"' would force a line wrap. This doesn't use
38   // the actual size of the string to be written to determine this so it's
39   // more conservative than strictly needed.
40   if (current_line_length + strlen(",0x") + write_size * 2 > kTextWidth) {
41     fprintf(w->fp(), "\n");
42     return 0;
43   } else {
44     return current_line_length;
45   }
46 }
47 
48 }  // namespace
49 
WriteBuiltin(PlatformEmbeddedFileWriterBase * w,const i::EmbeddedData * blob,const Builtin builtin) const50 void EmbeddedFileWriter::WriteBuiltin(PlatformEmbeddedFileWriterBase* w,
51                                       const i::EmbeddedData* blob,
52                                       const Builtin builtin) const {
53   const bool is_default_variant =
54       std::strcmp(embedded_variant_, kDefaultEmbeddedVariant) == 0;
55 
56   base::EmbeddedVector<char, kTemporaryStringLength> builtin_symbol;
57   if (is_default_variant) {
58     // Create nicer symbol names for the default mode.
59     base::SNPrintF(builtin_symbol, "Builtins_%s", i::Builtins::name(builtin));
60   } else {
61     base::SNPrintF(builtin_symbol, "%s_Builtins_%s", embedded_variant_,
62                    i::Builtins::name(builtin));
63   }
64 
65   // Labels created here will show up in backtraces. We check in
66   // Isolate::SetEmbeddedBlob that the blob layout remains unchanged, i.e.
67   // that labels do not insert bytes into the middle of the blob byte
68   // stream.
69   w->DeclareFunctionBegin(builtin_symbol.begin(),
70                           blob->InstructionSizeOfBuiltin(builtin));
71   const int builtin_id = static_cast<int>(builtin);
72   const std::vector<byte>& current_positions = source_positions_[builtin_id];
73   // The code below interleaves bytes of assembly code for the builtin
74   // function with source positions at the appropriate offsets.
75   base::Vector<const byte> vpos(current_positions.data(),
76                                 current_positions.size());
77   v8::internal::SourcePositionTableIterator positions(
78       vpos, SourcePositionTableIterator::kExternalOnly);
79 
80 #ifndef DEBUG
81   CHECK(positions.done());  // Release builds must not contain debug infos.
82 #endif
83 
84   // Some builtins (JSConstructStubGeneric) have entry points located in the
85   // middle of them, we need to store their addresses since they are part of
86   // the list of allowed return addresses in the deoptimizer.
87   const std::vector<LabelInfo>& current_labels = label_info_[builtin_id];
88   auto label = current_labels.begin();
89 
90   const uint8_t* data = reinterpret_cast<const uint8_t*>(
91       blob->InstructionStartOfBuiltin(builtin));
92   uint32_t size = blob->PaddedInstructionSizeOfBuiltin(builtin);
93   uint32_t i = 0;
94   uint32_t next_source_pos_offset =
95       static_cast<uint32_t>(positions.done() ? size : positions.code_offset());
96   uint32_t next_label_offset = static_cast<uint32_t>(
97       (label == current_labels.end()) ? size : label->offset);
98   uint32_t next_offset = 0;
99   while (i < size) {
100     if (i == next_source_pos_offset) {
101       // Write source directive.
102       w->SourceInfo(positions.source_position().ExternalFileId(),
103                     GetExternallyCompiledFilename(
104                         positions.source_position().ExternalFileId()),
105                     positions.source_position().ExternalLine());
106       positions.Advance();
107       next_source_pos_offset = static_cast<uint32_t>(
108           positions.done() ? size : positions.code_offset());
109       CHECK_GE(next_source_pos_offset, i);
110     }
111     if (i == next_label_offset) {
112       WriteBuiltinLabels(w, label->name);
113       label++;
114       next_label_offset = static_cast<uint32_t>(
115           (label == current_labels.end()) ? size : label->offset);
116       CHECK_GE(next_label_offset, i);
117     }
118     next_offset = std::min(next_source_pos_offset, next_label_offset);
119     WriteBinaryContentsAsInlineAssembly(w, data + i, next_offset - i);
120     i = next_offset;
121   }
122 
123   w->DeclareFunctionEnd(builtin_symbol.begin());
124 }
125 
WriteBuiltinLabels(PlatformEmbeddedFileWriterBase * w,std::string name) const126 void EmbeddedFileWriter::WriteBuiltinLabels(PlatformEmbeddedFileWriterBase* w,
127                                             std::string name) const {
128   if (ENABLE_CONTROL_FLOW_INTEGRITY_BOOL) {
129     w->DeclareSymbolGlobal(name.c_str());
130   }
131 
132   w->DeclareLabel(name.c_str());
133 }
134 
WriteCodeSection(PlatformEmbeddedFileWriterBase * w,const i::EmbeddedData * blob) const135 void EmbeddedFileWriter::WriteCodeSection(PlatformEmbeddedFileWriterBase* w,
136                                           const i::EmbeddedData* blob) const {
137   w->Comment(
138       "The embedded blob code section starts here. It contains the builtin");
139   w->Comment("instruction streams.");
140   w->SectionText();
141 
142 #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64
143   // UMA needs an exposed function-type label at the start of the embedded
144   // code section.
145   static const char* kCodeStartForProfilerSymbolName =
146       "v8_code_start_for_profiler_";
147   static constexpr int kDummyFunctionLength = 1;
148   static constexpr int kDummyFunctionData = 0xcc;
149   w->DeclareFunctionBegin(kCodeStartForProfilerSymbolName,
150                           kDummyFunctionLength);
151   // The label must not be at the same address as the first builtin, insert
152   // padding bytes.
153   WriteDirectiveOrSeparator(w, 0, kByte);
154   w->HexLiteral(kDummyFunctionData);
155   w->Newline();
156   w->DeclareFunctionEnd(kCodeStartForProfilerSymbolName);
157 #endif
158 
159   w->AlignToCodeAlignment();
160   w->DeclareLabel(EmbeddedBlobCodeDataSymbol().c_str());
161 
162   STATIC_ASSERT(Builtins::kAllBuiltinsAreIsolateIndependent);
163   for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
164        ++builtin) {
165     WriteBuiltin(w, blob, builtin);
166   }
167   w->PaddingAfterCode();
168   w->Newline();
169 }
170 
WriteFileEpilogue(PlatformEmbeddedFileWriterBase * w,const i::EmbeddedData * blob) const171 void EmbeddedFileWriter::WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
172                                            const i::EmbeddedData* blob) const {
173   {
174     base::EmbeddedVector<char, kTemporaryStringLength>
175         embedded_blob_code_symbol;
176     base::SNPrintF(embedded_blob_code_symbol, "v8_%s_embedded_blob_code_",
177                    embedded_variant_);
178 
179     w->Comment("Pointer to the beginning of the embedded blob code.");
180     w->SectionData();
181     w->AlignToDataAlignment();
182     w->DeclarePointerToSymbol(embedded_blob_code_symbol.begin(),
183                               EmbeddedBlobCodeDataSymbol().c_str());
184     w->Newline();
185 
186     base::EmbeddedVector<char, kTemporaryStringLength>
187         embedded_blob_data_symbol;
188     base::SNPrintF(embedded_blob_data_symbol, "v8_%s_embedded_blob_data_",
189                    embedded_variant_);
190 
191     w->Comment("Pointer to the beginning of the embedded blob data section.");
192     w->AlignToDataAlignment();
193     w->DeclarePointerToSymbol(embedded_blob_data_symbol.begin(),
194                               EmbeddedBlobDataDataSymbol().c_str());
195     w->Newline();
196   }
197 
198   {
199     base::EmbeddedVector<char, kTemporaryStringLength>
200         embedded_blob_code_size_symbol;
201     base::SNPrintF(embedded_blob_code_size_symbol,
202                    "v8_%s_embedded_blob_code_size_", embedded_variant_);
203 
204     w->Comment("The size of the embedded blob code in bytes.");
205     w->SectionRoData();
206     w->AlignToDataAlignment();
207     w->DeclareUint32(embedded_blob_code_size_symbol.begin(), blob->code_size());
208     w->Newline();
209 
210     base::EmbeddedVector<char, kTemporaryStringLength>
211         embedded_blob_data_size_symbol;
212     base::SNPrintF(embedded_blob_data_size_symbol,
213                    "v8_%s_embedded_blob_data_size_", embedded_variant_);
214 
215     w->Comment("The size of the embedded blob data section in bytes.");
216     w->DeclareUint32(embedded_blob_data_size_symbol.begin(), blob->data_size());
217     w->Newline();
218   }
219 
220 #if defined(V8_OS_WIN64)
221   {
222     base::EmbeddedVector<char, kTemporaryStringLength> unwind_info_symbol;
223     base::SNPrintF(unwind_info_symbol, "%s_Builtins_UnwindInfo",
224                    embedded_variant_);
225 
226     w->MaybeEmitUnwindData(unwind_info_symbol.begin(),
227                            EmbeddedBlobCodeDataSymbol().c_str(), blob,
228                            reinterpret_cast<const void*>(&unwind_infos_[0]));
229   }
230 #endif  // V8_OS_WIN64
231 
232   w->FileEpilogue();
233 }
234 
235 // static
WriteBinaryContentsAsInlineAssembly(PlatformEmbeddedFileWriterBase * w,const uint8_t * data,uint32_t size)236 void EmbeddedFileWriter::WriteBinaryContentsAsInlineAssembly(
237     PlatformEmbeddedFileWriterBase* w, const uint8_t* data, uint32_t size) {
238   int current_line_length = 0;
239   uint32_t i = 0;
240 
241   // Begin by writing out byte chunks.
242   const DataDirective directive = w->ByteChunkDataDirective();
243   const int byte_chunk_size = DataDirectiveSize(directive);
244   for (; i + byte_chunk_size < size; i += byte_chunk_size) {
245     current_line_length =
246         WriteDirectiveOrSeparator(w, current_line_length, directive);
247     current_line_length += w->WriteByteChunk(data + i);
248     current_line_length =
249         WriteLineEndIfNeeded(w, current_line_length, byte_chunk_size);
250   }
251   if (current_line_length != 0) w->Newline();
252   current_line_length = 0;
253 
254   // Write any trailing bytes one-by-one.
255   for (; i < size; i++) {
256     current_line_length =
257         WriteDirectiveOrSeparator(w, current_line_length, kByte);
258     current_line_length += w->HexLiteral(data[i]);
259     current_line_length = WriteLineEndIfNeeded(w, current_line_length, 1);
260   }
261 
262   if (current_line_length != 0) w->Newline();
263 }
264 
LookupOrAddExternallyCompiledFilename(const char * filename)265 int EmbeddedFileWriter::LookupOrAddExternallyCompiledFilename(
266     const char* filename) {
267   auto result = external_filenames_.find(filename);
268   if (result != external_filenames_.end()) {
269     return result->second;
270   }
271   int new_id =
272       ExternalFilenameIndexToId(static_cast<int>(external_filenames_.size()));
273   external_filenames_.insert(std::make_pair(filename, new_id));
274   external_filenames_by_index_.push_back(filename);
275   DCHECK_EQ(external_filenames_by_index_.size(), external_filenames_.size());
276   return new_id;
277 }
278 
GetExternallyCompiledFilename(int fileid) const279 const char* EmbeddedFileWriter::GetExternallyCompiledFilename(
280     int fileid) const {
281   size_t index = static_cast<size_t>(ExternalFilenameIdToIndex(fileid));
282   DCHECK_GE(index, 0);
283   DCHECK_LT(index, external_filenames_by_index_.size());
284 
285   return external_filenames_by_index_[index];
286 }
287 
GetExternallyCompiledFilenameCount() const288 int EmbeddedFileWriter::GetExternallyCompiledFilenameCount() const {
289   return static_cast<int>(external_filenames_.size());
290 }
291 
PrepareBuiltinSourcePositionMap(Builtins * builtins)292 void EmbeddedFileWriter::PrepareBuiltinSourcePositionMap(Builtins* builtins) {
293   for (Builtin builtin = Builtins::kFirst; builtin <= Builtins::kLast;
294        ++builtin) {
295     // Retrieve the SourcePositionTable and copy it.
296     Code code = FromCodeT(builtins->code(builtin));
297     // Verify that the code object is still the "real code" and not a
298     // trampoline (which wouldn't have source positions).
299     DCHECK(!code.is_off_heap_trampoline());
300     ByteArray source_position_table = code.source_position_table();
301     std::vector<unsigned char> data(source_position_table.GetDataStartAddress(),
302                                     source_position_table.GetDataEndAddress());
303     source_positions_[static_cast<int>(builtin)] = data;
304   }
305 }
306 
PrepareBuiltinLabelInfoMap(int create_offset,int invoke_offset)307 void EmbeddedFileWriter::PrepareBuiltinLabelInfoMap(int create_offset,
308                                                     int invoke_offset) {
309   label_info_[static_cast<int>(Builtin::kJSConstructStubGeneric)].push_back(
310       {create_offset, "construct_stub_create_deopt_addr"});
311   label_info_[static_cast<int>(Builtin::kJSConstructStubGeneric)].push_back(
312       {invoke_offset, "construct_stub_invoke_deopt_addr"});
313 }
314 
315 }  // namespace internal
316 }  // namespace v8
317