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