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 15namespace v8 { 16namespace internal { 17 18namespace { 19 20int 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 34int 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 50void 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 126void 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 135void 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 171void 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 236void 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 265int 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 279const 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 288int EmbeddedFileWriter::GetExternallyCompiledFilenameCount() const { 289 return static_cast<int>(external_filenames_.size()); 290} 291 292void 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 307void 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