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_EMBEDDED_FILE_WRITER_H_ 6 #define V8_SNAPSHOT_EMBEDDED_EMBEDDED_FILE_WRITER_H_ 7 8 #include <cinttypes> 9 #include <cstdio> 10 #include <cstring> 11 #include <memory> 12 13 #include "src/common/globals.h" 14 #include "src/snapshot/embedded/embedded-data.h" 15 #include "src/snapshot/embedded/platform-embedded-file-writer-base.h" 16 17 #if defined(V8_OS_WIN64) 18 #include "src/diagnostics/unwinding-info-win64.h" 19 #endif // V8_OS_WIN64 20 21 namespace v8 { 22 namespace internal { 23 24 static constexpr char kDefaultEmbeddedVariant[] = "Default"; 25 26 struct LabelInfo { 27 int offset; 28 std::string name; 29 }; 30 31 // Detailed source-code information about builtins can only be obtained by 32 // registration on the isolate during compilation. 33 class EmbeddedFileWriterInterface { 34 public: 35 // We maintain a database of filenames to synthetic IDs. 36 virtual int LookupOrAddExternallyCompiledFilename(const char* filename) = 0; 37 virtual const char* GetExternallyCompiledFilename(int index) const = 0; 38 virtual int GetExternallyCompiledFilenameCount() const = 0; 39 40 // The isolate will call the method below just prior to replacing the 41 // compiled builtin Code objects with trampolines. 42 virtual void PrepareBuiltinSourcePositionMap(Builtins* builtins) = 0; 43 44 virtual void PrepareBuiltinLabelInfoMap(int create_offset, int invoke_offset, 45 int arguments_adaptor_offset) = 0; 46 47 #if defined(V8_OS_WIN64) 48 virtual void SetBuiltinUnwindData( 49 int builtin_index, 50 const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) = 0; 51 #endif // V8_OS_WIN64 52 }; 53 54 // Generates the embedded.S file which is later compiled into the final v8 55 // binary. Its contents are exported through two symbols: 56 // 57 // v8_<variant>_embedded_blob_ (intptr_t): 58 // a pointer to the start of the embedded blob. 59 // v8_<variant>_embedded_blob_size_ (uint32_t): 60 // size of the embedded blob in bytes. 61 // 62 // The variant is usually "Default" but can be modified in multisnapshot builds. 63 class EmbeddedFileWriter : public EmbeddedFileWriterInterface { 64 public: 65 int LookupOrAddExternallyCompiledFilename(const char* filename) override; 66 const char* GetExternallyCompiledFilename(int fileid) const override; 67 int GetExternallyCompiledFilenameCount() const override; 68 69 void PrepareBuiltinSourcePositionMap(Builtins* builtins) override; 70 71 void PrepareBuiltinLabelInfoMap(int create_offset, int invoke_create, 72 int arguments_adaptor_offset) override; 73 74 #if defined(V8_OS_WIN64) SetBuiltinUnwindData(int builtin_index,const win64_unwindinfo::BuiltinUnwindInfo & unwinding_info)75 void SetBuiltinUnwindData( 76 int builtin_index, 77 const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override { 78 DCHECK_LT(builtin_index, Builtins::builtin_count); 79 unwind_infos_[builtin_index] = unwinding_info; 80 } 81 #endif // V8_OS_WIN64 82 SetEmbeddedFile(const char * embedded_src_path)83 void SetEmbeddedFile(const char* embedded_src_path) { 84 embedded_src_path_ = embedded_src_path; 85 } 86 SetEmbeddedVariant(const char * embedded_variant)87 void SetEmbeddedVariant(const char* embedded_variant) { 88 if (embedded_variant == nullptr) return; 89 embedded_variant_ = embedded_variant; 90 } 91 SetTargetArch(const char * target_arch)92 void SetTargetArch(const char* target_arch) { target_arch_ = target_arch; } 93 SetTargetOs(const char * target_os)94 void SetTargetOs(const char* target_os) { target_os_ = target_os; } 95 WriteEmbedded(const i::EmbeddedData * blob)96 void WriteEmbedded(const i::EmbeddedData* blob) const { 97 MaybeWriteEmbeddedFile(blob); 98 } 99 100 private: MaybeWriteEmbeddedFile(const i::EmbeddedData * blob)101 void MaybeWriteEmbeddedFile(const i::EmbeddedData* blob) const { 102 if (embedded_src_path_ == nullptr) return; 103 104 FILE* fp = GetFileDescriptorOrDie(embedded_src_path_); 105 106 std::unique_ptr<PlatformEmbeddedFileWriterBase> writer = 107 NewPlatformEmbeddedFileWriter(target_arch_, target_os_); 108 writer->SetFile(fp); 109 110 WriteFilePrologue(writer.get()); 111 WriteExternalFilenames(writer.get()); 112 WriteDataSection(writer.get(), blob); 113 WriteCodeSection(writer.get(), blob); 114 WriteFileEpilogue(writer.get(), blob); 115 116 fclose(fp); 117 } 118 GetFileDescriptorOrDie(const char * filename)119 static FILE* GetFileDescriptorOrDie(const char* filename) { 120 FILE* fp = v8::base::OS::FOpen(filename, "wb"); 121 if (fp == nullptr) { 122 i::PrintF("Unable to open file \"%s\" for writing.\n", filename); 123 exit(1); 124 } 125 return fp; 126 } 127 WriteFilePrologue(PlatformEmbeddedFileWriterBase * w)128 void WriteFilePrologue(PlatformEmbeddedFileWriterBase* w) const { 129 w->Comment("Autogenerated file. Do not edit."); 130 w->Newline(); 131 w->FilePrologue(); 132 } 133 WriteExternalFilenames(PlatformEmbeddedFileWriterBase * w)134 void WriteExternalFilenames(PlatformEmbeddedFileWriterBase* w) const { 135 #ifndef DEBUG 136 // Release builds must not contain debug infos. 137 CHECK_EQ(external_filenames_by_index_.size(), 0); 138 #endif 139 140 w->Comment( 141 "Source positions in the embedded blob refer to filenames by id."); 142 w->Comment("Assembly directives here map the id to a filename."); 143 w->Newline(); 144 145 // Write external filenames. 146 int size = static_cast<int>(external_filenames_by_index_.size()); 147 for (int i = 0; i < size; i++) { 148 w->DeclareExternalFilename(ExternalFilenameIndexToId(i), 149 external_filenames_by_index_[i]); 150 } 151 } 152 153 // Fairly arbitrary but should fit all symbol names. 154 static constexpr int kTemporaryStringLength = 256; 155 EmbeddedBlobCodeDataSymbol()156 std::string EmbeddedBlobCodeDataSymbol() const { 157 i::EmbeddedVector<char, kTemporaryStringLength> 158 embedded_blob_code_data_symbol; 159 i::SNPrintF(embedded_blob_code_data_symbol, 160 "v8_%s_embedded_blob_code_data_", embedded_variant_); 161 return std::string{embedded_blob_code_data_symbol.begin()}; 162 } 163 EmbeddedBlobDataDataSymbol()164 std::string EmbeddedBlobDataDataSymbol() const { 165 i::EmbeddedVector<char, kTemporaryStringLength> 166 embedded_blob_data_data_symbol; 167 i::SNPrintF(embedded_blob_data_data_symbol, 168 "v8_%s_embedded_blob_data_data_", embedded_variant_); 169 return std::string{embedded_blob_data_data_symbol.begin()}; 170 } 171 WriteDataSection(PlatformEmbeddedFileWriterBase * w,const i::EmbeddedData * blob)172 void WriteDataSection(PlatformEmbeddedFileWriterBase* w, 173 const i::EmbeddedData* blob) const { 174 w->Comment("The embedded blob data section starts here."); 175 w->SectionRoData(); 176 w->AlignToDataAlignment(); 177 w->DeclareLabel(EmbeddedBlobDataDataSymbol().c_str()); 178 179 WriteBinaryContentsAsInlineAssembly(w, blob->data(), blob->data_size()); 180 } 181 182 void WriteBuiltin(PlatformEmbeddedFileWriterBase* w, 183 const i::EmbeddedData* blob, const int builtin_id) const; 184 185 void WriteBuiltinLabels(PlatformEmbeddedFileWriterBase* w, 186 std::string name) const; 187 188 void WriteCodeSection(PlatformEmbeddedFileWriterBase* w, 189 const i::EmbeddedData* blob) const; 190 191 void WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w, 192 const i::EmbeddedData* blob) const; 193 194 #if defined(V8_OS_WIN_X64) 195 void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterBase* w, 196 uint64_t rva_start, uint64_t rva_end) const; 197 #endif 198 199 static void WriteBinaryContentsAsInlineAssembly( 200 PlatformEmbeddedFileWriterBase* w, const uint8_t* data, uint32_t size); 201 202 // In assembly directives, filename ids need to begin with 1. 203 static constexpr int kFirstExternalFilenameId = 1; ExternalFilenameIndexToId(int index)204 static int ExternalFilenameIndexToId(int index) { 205 return kFirstExternalFilenameId + index; 206 } ExternalFilenameIdToIndex(int id)207 static int ExternalFilenameIdToIndex(int id) { 208 return id - kFirstExternalFilenameId; 209 } 210 211 private: 212 std::vector<byte> source_positions_[Builtins::builtin_count]; 213 std::vector<LabelInfo> label_info_[Builtins::builtin_count]; 214 215 #if defined(V8_OS_WIN64) 216 win64_unwindinfo::BuiltinUnwindInfo unwind_infos_[Builtins::builtin_count]; 217 #endif // V8_OS_WIN64 218 219 std::map<const char*, int> external_filenames_; 220 std::vector<const char*> external_filenames_by_index_; 221 222 // The file to generate or nullptr. 223 const char* embedded_src_path_ = nullptr; 224 225 // The variant is only used in multi-snapshot builds and otherwise set to 226 // "Default". 227 const char* embedded_variant_ = kDefaultEmbeddedVariant; 228 229 // {target_arch} and {target_os} control the generated assembly format. Note 230 // these may differ from both host- and target-platforms specified through 231 // e.g. V8_OS_* and V8_TARGET_ARCH_* defines. 232 const char* target_arch_ = nullptr; 233 const char* target_os_ = nullptr; 234 }; 235 236 } // namespace internal 237 } // namespace v8 238 239 #endif // V8_SNAPSHOT_EMBEDDED_EMBEDDED_FILE_WRITER_H_ 240