1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "oat_writer.h" 18 19 #include <algorithm> 20 #include <unistd.h> 21 #include <zlib.h> 22 23 #include "arch/arm64/instruction_set_features_arm64.h" 24 #include "art_method-inl.h" 25 #include "base/allocator.h" 26 #include "base/bit_vector-inl.h" 27 #include "base/enums.h" 28 #include "base/file_magic.h" 29 #include "base/logging.h" // For VLOG 30 #include "base/os.h" 31 #include "base/safe_map.h" 32 #include "base/stl_util.h" 33 #include "base/unix_file/fd_file.h" 34 #include "class_linker.h" 35 #include "class_table-inl.h" 36 #include "compiled_method-inl.h" 37 #include "debug/method_debug_info.h" 38 #include "dex/art_dex_file_loader.h" 39 #include "dex/dex_file-inl.h" 40 #include "dex/dex_file_loader.h" 41 #include "dex/dex_file_types.h" 42 #include "dex/standard_dex_file.h" 43 #include "dex/verification_results.h" 44 #include "dex_container.h" 45 #include "dexlayout.h" 46 #include "driver/compiler_driver-inl.h" 47 #include "driver/compiler_options.h" 48 #include "gc/space/image_space.h" 49 #include "gc/space/space.h" 50 #include "handle_scope-inl.h" 51 #include "image_writer.h" 52 #include "jit/profile_compilation_info.h" 53 #include "linker/buffered_output_stream.h" 54 #include "linker/file_output_stream.h" 55 #include "linker/index_bss_mapping_encoder.h" 56 #include "linker/linker_patch.h" 57 #include "linker/multi_oat_relative_patcher.h" 58 #include "linker/output_stream.h" 59 #include "mirror/array.h" 60 #include "mirror/class_loader.h" 61 #include "mirror/dex_cache-inl.h" 62 #include "mirror/object-inl.h" 63 #include "oat_quick_method_header.h" 64 #include "quicken_info.h" 65 #include "scoped_thread_state_change-inl.h" 66 #include "type_lookup_table.h" 67 #include "utils/dex_cache_arrays_layout-inl.h" 68 #include "vdex_file.h" 69 #include "verifier/verifier_deps.h" 70 #include "zip_archive.h" 71 72 namespace art { 73 namespace linker { 74 75 namespace { // anonymous namespace 76 77 // If we write dex layout info in the oat file. 78 static constexpr bool kWriteDexLayoutInfo = true; 79 80 // Force the OAT method layout to be sorted-by-name instead of 81 // the default (class_def_idx, method_idx). 82 // 83 // Otherwise if profiles are used, that will act as 84 // the primary sort order. 85 // 86 // A bit easier to use for development since oatdump can easily 87 // show that things are being re-ordered when two methods aren't adjacent. 88 static constexpr bool kOatWriterForceOatCodeLayout = false; 89 90 static constexpr bool kOatWriterDebugOatCodeLayout = false; 91 92 typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader; 93 94 const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) { 95 return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data); 96 } 97 98 class ChecksumUpdatingOutputStream : public OutputStream { 99 public: 100 ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header) 101 : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { } 102 103 bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE { 104 oat_header_->UpdateChecksum(buffer, byte_count); 105 return out_->WriteFully(buffer, byte_count); 106 } 107 108 off_t Seek(off_t offset, Whence whence) OVERRIDE { 109 return out_->Seek(offset, whence); 110 } 111 112 bool Flush() OVERRIDE { 113 return out_->Flush(); 114 } 115 116 private: 117 OutputStream* const out_; 118 OatHeader* const oat_header_; 119 }; 120 121 inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) { 122 // We want to align the code rather than the preheader. 123 uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader); 124 uint32_t aligned_code_offset = compiled_method.AlignCode(unaligned_code_offset); 125 return aligned_code_offset - unaligned_code_offset; 126 } 127 128 } // anonymous namespace 129 130 // Defines the location of the raw dex file to write. 131 class OatWriter::DexFileSource { 132 public: 133 enum Type { 134 kNone, 135 kZipEntry, 136 kRawFile, 137 kRawData, 138 }; 139 140 explicit DexFileSource(ZipEntry* zip_entry) 141 : type_(kZipEntry), source_(zip_entry) { 142 DCHECK(source_ != nullptr); 143 } 144 145 explicit DexFileSource(File* raw_file) 146 : type_(kRawFile), source_(raw_file) { 147 DCHECK(source_ != nullptr); 148 } 149 150 explicit DexFileSource(const uint8_t* dex_file) 151 : type_(kRawData), source_(dex_file) { 152 DCHECK(source_ != nullptr); 153 } 154 155 Type GetType() const { return type_; } 156 bool IsZipEntry() const { return type_ == kZipEntry; } 157 bool IsRawFile() const { return type_ == kRawFile; } 158 bool IsRawData() const { return type_ == kRawData; } 159 160 ZipEntry* GetZipEntry() const { 161 DCHECK(IsZipEntry()); 162 DCHECK(source_ != nullptr); 163 return static_cast<ZipEntry*>(const_cast<void*>(source_)); 164 } 165 166 File* GetRawFile() const { 167 DCHECK(IsRawFile()); 168 DCHECK(source_ != nullptr); 169 return static_cast<File*>(const_cast<void*>(source_)); 170 } 171 172 const uint8_t* GetRawData() const { 173 DCHECK(IsRawData()); 174 DCHECK(source_ != nullptr); 175 return static_cast<const uint8_t*>(source_); 176 } 177 178 void Clear() { 179 type_ = kNone; 180 source_ = nullptr; 181 } 182 183 private: 184 Type type_; 185 const void* source_; 186 }; 187 188 // OatClassHeader is the header only part of the oat class that is required even when compilation 189 // is not enabled. 190 class OatWriter::OatClassHeader { 191 public: 192 OatClassHeader(uint32_t offset, 193 uint32_t num_non_null_compiled_methods, 194 uint32_t num_methods, 195 ClassStatus status) 196 : status_(enum_cast<uint16_t>(status)), 197 offset_(offset) { 198 // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use 199 // kOatClassAllCompiled unless there is at least one compiled method. This means in an 200 // interpreter only system, we can assert that all classes are kOatClassNoneCompiled. 201 if (num_non_null_compiled_methods == 0) { 202 type_ = kOatClassNoneCompiled; 203 } else if (num_non_null_compiled_methods == num_methods) { 204 type_ = kOatClassAllCompiled; 205 } else { 206 type_ = kOatClassSomeCompiled; 207 } 208 } 209 210 bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const; 211 212 static size_t SizeOf() { 213 return sizeof(status_) + sizeof(type_); 214 } 215 216 // Data to write. 217 static_assert(enum_cast<>(ClassStatus::kLast) < (1 << 16), "class status won't fit in 16bits"); 218 uint16_t status_; 219 220 static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits"); 221 uint16_t type_; 222 223 // Offset of start of OatClass from beginning of OatHeader. It is 224 // used to validate file position when writing. 225 uint32_t offset_; 226 }; 227 228 // The actual oat class body contains the information about compiled methods. It is only required 229 // for compiler filters that have any compilation. 230 class OatWriter::OatClass { 231 public: 232 OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods, 233 uint32_t compiled_methods_with_code, 234 uint16_t oat_class_type); 235 OatClass(OatClass&& src) = default; 236 size_t SizeOf() const; 237 bool Write(OatWriter* oat_writer, OutputStream* out) const; 238 239 CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const { 240 return compiled_methods_[class_def_method_index]; 241 } 242 243 // CompiledMethods for each class_def_method_index, or null if no method is available. 244 dchecked_vector<CompiledMethod*> compiled_methods_; 245 246 // Offset from OatClass::offset_ to the OatMethodOffsets for the 247 // class_def_method_index. If 0, it means the corresponding 248 // CompiledMethod entry in OatClass::compiled_methods_ should be 249 // null and that the OatClass::type_ should be kOatClassBitmap. 250 dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_; 251 252 // Data to write. 253 uint32_t method_bitmap_size_; 254 255 // bit vector indexed by ClassDef method index. When 256 // OatClassType::type_ is kOatClassBitmap, a set bit indicates the 257 // method has an OatMethodOffsets in methods_offsets_, otherwise 258 // the entry was ommited to save space. If OatClassType::type_ is 259 // not is kOatClassBitmap, the bitmap will be null. 260 std::unique_ptr<BitVector> method_bitmap_; 261 262 // OatMethodOffsets and OatMethodHeaders for each CompiledMethod 263 // present in the OatClass. Note that some may be missing if 264 // OatClass::compiled_methods_ contains null values (and 265 // oat_method_offsets_offsets_from_oat_class_ should contain 0 266 // values in this case). 267 dchecked_vector<OatMethodOffsets> method_offsets_; 268 dchecked_vector<OatQuickMethodHeader> method_headers_; 269 270 private: 271 size_t GetMethodOffsetsRawSize() const { 272 return method_offsets_.size() * sizeof(method_offsets_[0]); 273 } 274 275 DISALLOW_COPY_AND_ASSIGN(OatClass); 276 }; 277 278 class OatWriter::OatDexFile { 279 public: 280 OatDexFile(const char* dex_file_location, 281 DexFileSource source, 282 CreateTypeLookupTable create_type_lookup_table, 283 uint32_t dex_file_location_checksun, 284 size_t dex_file_size); 285 OatDexFile(OatDexFile&& src) = default; 286 287 const char* GetLocation() const { 288 return dex_file_location_data_; 289 } 290 291 size_t SizeOf() const; 292 bool Write(OatWriter* oat_writer, OutputStream* out) const; 293 bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out); 294 295 size_t GetClassOffsetsRawSize() const { 296 return class_offsets_.size() * sizeof(class_offsets_[0]); 297 } 298 299 // The source of the dex file. 300 DexFileSource source_; 301 302 // Whether to create the type lookup table. 303 CreateTypeLookupTable create_type_lookup_table_; 304 305 // Dex file size. Passed in the constructor, but could be 306 // overwritten by LayoutAndWriteDexFile. 307 size_t dex_file_size_; 308 309 // Offset of start of OatDexFile from beginning of OatHeader. It is 310 // used to validate file position when writing. 311 size_t offset_; 312 313 ///// Start of data to write to vdex/oat file. 314 315 const uint32_t dex_file_location_size_; 316 const char* const dex_file_location_data_; 317 318 // The checksum of the dex file. 319 const uint32_t dex_file_location_checksum_; 320 321 // Offset of the dex file in the vdex file. Set when writing dex files in 322 // SeekToDexFile. 323 uint32_t dex_file_offset_; 324 325 // The lookup table offset in the oat file. Set in WriteTypeLookupTables. 326 uint32_t lookup_table_offset_; 327 328 // Class and BSS offsets set in PrepareLayout. 329 uint32_t class_offsets_offset_; 330 uint32_t method_bss_mapping_offset_; 331 uint32_t type_bss_mapping_offset_; 332 uint32_t string_bss_mapping_offset_; 333 334 // Offset of dex sections that will have different runtime madvise states. 335 // Set in WriteDexLayoutSections. 336 uint32_t dex_sections_layout_offset_; 337 338 // Data to write to a separate section. We set the length 339 // of the vector in OpenDexFiles. 340 dchecked_vector<uint32_t> class_offsets_; 341 342 // Dex section layout info to serialize. 343 DexLayoutSections dex_sections_layout_; 344 345 ///// End of data to write to vdex/oat file. 346 private: 347 DISALLOW_COPY_AND_ASSIGN(OatDexFile); 348 }; 349 350 #define DCHECK_OFFSET() \ 351 DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \ 352 << "file_offset=" << file_offset << " relative_offset=" << relative_offset 353 354 #define DCHECK_OFFSET_() \ 355 DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \ 356 << "file_offset=" << file_offset << " offset_=" << offset_ 357 358 OatWriter::OatWriter(bool compiling_boot_image, 359 TimingLogger* timings, 360 ProfileCompilationInfo* info, 361 CompactDexLevel compact_dex_level) 362 : write_state_(WriteState::kAddingDexFileSources), 363 timings_(timings), 364 raw_dex_files_(), 365 zip_archives_(), 366 zipped_dex_files_(), 367 zipped_dex_file_locations_(), 368 compiler_driver_(nullptr), 369 image_writer_(nullptr), 370 compiling_boot_image_(compiling_boot_image), 371 extract_dex_files_into_vdex_(true), 372 dex_files_(nullptr), 373 vdex_size_(0u), 374 vdex_dex_files_offset_(0u), 375 vdex_dex_shared_data_offset_(0u), 376 vdex_verifier_deps_offset_(0u), 377 vdex_quickening_info_offset_(0u), 378 oat_size_(0u), 379 bss_start_(0u), 380 bss_size_(0u), 381 bss_methods_offset_(0u), 382 bss_roots_offset_(0u), 383 bss_method_entry_references_(), 384 bss_method_entries_(), 385 bss_type_entries_(), 386 bss_string_entries_(), 387 map_boot_image_tables_to_bss_(false), 388 oat_data_offset_(0u), 389 oat_header_(nullptr), 390 size_vdex_header_(0), 391 size_vdex_checksums_(0), 392 size_dex_file_alignment_(0), 393 size_executable_offset_alignment_(0), 394 size_oat_header_(0), 395 size_oat_header_key_value_store_(0), 396 size_dex_file_(0), 397 size_verifier_deps_(0), 398 size_verifier_deps_alignment_(0), 399 size_quickening_info_(0), 400 size_quickening_info_alignment_(0), 401 size_interpreter_to_interpreter_bridge_(0), 402 size_interpreter_to_compiled_code_bridge_(0), 403 size_jni_dlsym_lookup_(0), 404 size_quick_generic_jni_trampoline_(0), 405 size_quick_imt_conflict_trampoline_(0), 406 size_quick_resolution_trampoline_(0), 407 size_quick_to_interpreter_bridge_(0), 408 size_trampoline_alignment_(0), 409 size_method_header_(0), 410 size_code_(0), 411 size_code_alignment_(0), 412 size_relative_call_thunks_(0), 413 size_misc_thunks_(0), 414 size_vmap_table_(0), 415 size_method_info_(0), 416 size_oat_dex_file_location_size_(0), 417 size_oat_dex_file_location_data_(0), 418 size_oat_dex_file_location_checksum_(0), 419 size_oat_dex_file_offset_(0), 420 size_oat_dex_file_class_offsets_offset_(0), 421 size_oat_dex_file_lookup_table_offset_(0), 422 size_oat_dex_file_dex_layout_sections_offset_(0), 423 size_oat_dex_file_dex_layout_sections_(0), 424 size_oat_dex_file_dex_layout_sections_alignment_(0), 425 size_oat_dex_file_method_bss_mapping_offset_(0), 426 size_oat_dex_file_type_bss_mapping_offset_(0), 427 size_oat_dex_file_string_bss_mapping_offset_(0), 428 size_oat_lookup_table_alignment_(0), 429 size_oat_lookup_table_(0), 430 size_oat_class_offsets_alignment_(0), 431 size_oat_class_offsets_(0), 432 size_oat_class_type_(0), 433 size_oat_class_status_(0), 434 size_oat_class_method_bitmaps_(0), 435 size_oat_class_method_offsets_(0), 436 size_method_bss_mappings_(0u), 437 size_type_bss_mappings_(0u), 438 size_string_bss_mappings_(0u), 439 relative_patcher_(nullptr), 440 absolute_patch_locations_(), 441 profile_compilation_info_(info), 442 compact_dex_level_(compact_dex_level) { 443 // If we have a profile, always use at least the default compact dex level. The reason behind 444 // this is that CompactDex conversion is not more expensive than normal dexlayout. 445 if (info != nullptr && compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone) { 446 compact_dex_level_ = kDefaultCompactDexLevel; 447 } 448 } 449 450 static bool ValidateDexFileHeader(const uint8_t* raw_header, const char* location) { 451 const bool valid_standard_dex_magic = DexFileLoader::IsMagicValid(raw_header); 452 if (!valid_standard_dex_magic) { 453 LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location; 454 return false; 455 } 456 if (!DexFileLoader::IsVersionAndMagicValid(raw_header)) { 457 LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location; 458 return false; 459 } 460 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header); 461 if (header->file_size_ < sizeof(DexFile::Header)) { 462 LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header." 463 << " File: " << location; 464 return false; 465 } 466 return true; 467 } 468 469 static const UnalignedDexFileHeader* GetDexFileHeader(File* file, 470 uint8_t* raw_header, 471 const char* location) { 472 // Read the dex file header and perform minimal verification. 473 if (!file->ReadFully(raw_header, sizeof(DexFile::Header))) { 474 PLOG(ERROR) << "Failed to read dex file header. Actual: " 475 << " File: " << location << " Output: " << file->GetPath(); 476 return nullptr; 477 } 478 if (!ValidateDexFileHeader(raw_header, location)) { 479 return nullptr; 480 } 481 482 return AsUnalignedDexFileHeader(raw_header); 483 } 484 485 bool OatWriter::AddDexFileSource(const char* filename, 486 const char* location, 487 CreateTypeLookupTable create_type_lookup_table) { 488 DCHECK(write_state_ == WriteState::kAddingDexFileSources); 489 uint32_t magic; 490 std::string error_msg; 491 File fd = OpenAndReadMagic(filename, &magic, &error_msg); 492 if (fd.Fd() == -1) { 493 PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'"; 494 return false; 495 } else if (DexFileLoader::IsMagicValid(magic)) { 496 uint8_t raw_header[sizeof(DexFile::Header)]; 497 const UnalignedDexFileHeader* header = GetDexFileHeader(&fd, raw_header, location); 498 if (header == nullptr) { 499 return false; 500 } 501 // The file is open for reading, not writing, so it's OK to let the File destructor 502 // close it without checking for explicit Close(), so pass checkUsage = false. 503 raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false)); 504 oat_dex_files_.emplace_back(/* OatDexFile */ 505 location, 506 DexFileSource(raw_dex_files_.back().get()), 507 create_type_lookup_table, 508 header->checksum_, 509 header->file_size_); 510 } else if (IsZipMagic(magic)) { 511 if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) { 512 return false; 513 } 514 } else { 515 LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'"; 516 return false; 517 } 518 return true; 519 } 520 521 // Add dex file source(s) from a zip file specified by a file handle. 522 bool OatWriter::AddZippedDexFilesSource(File&& zip_fd, 523 const char* location, 524 CreateTypeLookupTable create_type_lookup_table) { 525 DCHECK(write_state_ == WriteState::kAddingDexFileSources); 526 std::string error_msg; 527 zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg)); 528 ZipArchive* zip_archive = zip_archives_.back().get(); 529 if (zip_archive == nullptr) { 530 LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': " 531 << error_msg; 532 return false; 533 } 534 for (size_t i = 0; ; ++i) { 535 std::string entry_name = DexFileLoader::GetMultiDexClassesDexName(i); 536 std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg)); 537 if (entry == nullptr) { 538 break; 539 } 540 zipped_dex_files_.push_back(std::move(entry)); 541 zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location)); 542 const char* full_location = zipped_dex_file_locations_.back().c_str(); 543 // We override the checksum from header with the CRC from ZIP entry. 544 oat_dex_files_.emplace_back(/* OatDexFile */ 545 full_location, 546 DexFileSource(zipped_dex_files_.back().get()), 547 create_type_lookup_table, 548 zipped_dex_files_.back()->GetCrc32(), 549 zipped_dex_files_.back()->GetUncompressedLength()); 550 } 551 if (zipped_dex_file_locations_.empty()) { 552 LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg; 553 return false; 554 } 555 return true; 556 } 557 558 // Add dex file source(s) from a vdex file specified by a file handle. 559 bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file, 560 const char* location, 561 CreateTypeLookupTable create_type_lookup_table) { 562 DCHECK(write_state_ == WriteState::kAddingDexFileSources); 563 DCHECK(vdex_file.HasDexSection()); 564 const uint8_t* current_dex_data = nullptr; 565 for (size_t i = 0; i < vdex_file.GetVerifierDepsHeader().GetNumberOfDexFiles(); ++i) { 566 current_dex_data = vdex_file.GetNextDexFileData(current_dex_data); 567 if (current_dex_data == nullptr) { 568 LOG(ERROR) << "Unexpected number of dex files in vdex " << location; 569 return false; 570 } 571 572 if (!DexFileLoader::IsMagicValid(current_dex_data)) { 573 LOG(ERROR) << "Invalid magic in vdex file created from " << location; 574 return false; 575 } 576 // We used `zipped_dex_file_locations_` to keep the strings in memory. 577 zipped_dex_file_locations_.push_back(DexFileLoader::GetMultiDexLocation(i, location)); 578 const char* full_location = zipped_dex_file_locations_.back().c_str(); 579 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(current_dex_data); 580 oat_dex_files_.emplace_back(/* OatDexFile */ 581 full_location, 582 DexFileSource(current_dex_data), 583 create_type_lookup_table, 584 vdex_file.GetLocationChecksum(i), 585 header->file_size_); 586 } 587 588 if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) { 589 LOG(ERROR) << "Unexpected number of dex files in vdex " << location; 590 return false; 591 } 592 593 if (oat_dex_files_.empty()) { 594 LOG(ERROR) << "No dex files in vdex file created from " << location; 595 return false; 596 } 597 return true; 598 } 599 600 // Add dex file source from raw memory. 601 bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data, 602 const char* location, 603 uint32_t location_checksum, 604 CreateTypeLookupTable create_type_lookup_table) { 605 DCHECK(write_state_ == WriteState::kAddingDexFileSources); 606 if (data.size() < sizeof(DexFile::Header)) { 607 LOG(ERROR) << "Provided data is shorter than dex file header. size: " 608 << data.size() << " File: " << location; 609 return false; 610 } 611 if (!ValidateDexFileHeader(data.data(), location)) { 612 return false; 613 } 614 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data()); 615 if (data.size() < header->file_size_) { 616 LOG(ERROR) << "Truncated dex file data. Data size: " << data.size() 617 << " file size from header: " << header->file_size_ << " File: " << location; 618 return false; 619 } 620 621 oat_dex_files_.emplace_back(/* OatDexFile */ 622 location, 623 DexFileSource(data.data()), 624 create_type_lookup_table, 625 location_checksum, 626 header->file_size_); 627 return true; 628 } 629 630 dchecked_vector<std::string> OatWriter::GetSourceLocations() const { 631 dchecked_vector<std::string> locations; 632 locations.reserve(oat_dex_files_.size()); 633 for (const OatDexFile& oat_dex_file : oat_dex_files_) { 634 locations.push_back(oat_dex_file.GetLocation()); 635 } 636 return locations; 637 } 638 639 bool OatWriter::MayHaveCompiledMethods() const { 640 return CompilerFilter::IsAnyCompilationEnabled( 641 GetCompilerDriver()->GetCompilerOptions().GetCompilerFilter()); 642 } 643 644 bool OatWriter::WriteAndOpenDexFiles( 645 File* vdex_file, 646 OutputStream* oat_rodata, 647 InstructionSet instruction_set, 648 const InstructionSetFeatures* instruction_set_features, 649 SafeMap<std::string, std::string>* key_value_store, 650 bool verify, 651 bool update_input_vdex, 652 CopyOption copy_dex_files, 653 /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, 654 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) { 655 CHECK(write_state_ == WriteState::kAddingDexFileSources); 656 657 // Record the ELF rodata section offset, i.e. the beginning of the OAT data. 658 if (!RecordOatDataOffset(oat_rodata)) { 659 return false; 660 } 661 662 std::vector<std::unique_ptr<MemMap>> dex_files_map; 663 std::vector<std::unique_ptr<const DexFile>> dex_files; 664 665 // Initialize VDEX and OAT headers. 666 667 // Reserve space for Vdex header and checksums. 668 vdex_size_ = sizeof(VdexFile::VerifierDepsHeader) + 669 oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); 670 oat_size_ = InitOatHeader(instruction_set, 671 instruction_set_features, 672 dchecked_integral_cast<uint32_t>(oat_dex_files_.size()), 673 key_value_store); 674 675 ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get()); 676 677 std::unique_ptr<BufferedOutputStream> vdex_out = 678 std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file)); 679 // Write DEX files into VDEX, mmap and open them. 680 if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex, copy_dex_files) || 681 !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) { 682 return false; 683 } 684 685 // Write type lookup tables into the oat file. 686 if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) { 687 return false; 688 } 689 690 // Write dex layout sections into the oat file. 691 if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) { 692 return false; 693 } 694 695 *opened_dex_files_map = std::move(dex_files_map); 696 *opened_dex_files = std::move(dex_files); 697 write_state_ = WriteState::kPrepareLayout; 698 return true; 699 } 700 701 void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) { 702 CHECK(write_state_ == WriteState::kPrepareLayout); 703 704 relative_patcher_ = relative_patcher; 705 SetMultiOatRelativePatcherAdjustment(); 706 707 if (compiling_boot_image_) { 708 CHECK(image_writer_ != nullptr); 709 } 710 InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); 711 CHECK_EQ(instruction_set, oat_header_->GetInstructionSet()); 712 713 { 714 TimingLogger::ScopedTiming split("InitBssLayout", timings_); 715 InitBssLayout(instruction_set); 716 } 717 718 uint32_t offset = oat_size_; 719 { 720 TimingLogger::ScopedTiming split("InitClassOffsets", timings_); 721 offset = InitClassOffsets(offset); 722 } 723 { 724 TimingLogger::ScopedTiming split("InitOatClasses", timings_); 725 offset = InitOatClasses(offset); 726 } 727 { 728 TimingLogger::ScopedTiming split("InitIndexBssMappings", timings_); 729 offset = InitIndexBssMappings(offset); 730 } 731 { 732 TimingLogger::ScopedTiming split("InitOatMaps", timings_); 733 offset = InitOatMaps(offset); 734 } 735 { 736 TimingLogger::ScopedTiming split("InitOatDexFiles", timings_); 737 oat_header_->SetOatDexFilesOffset(offset); 738 offset = InitOatDexFiles(offset); 739 } 740 { 741 TimingLogger::ScopedTiming split("InitOatCode", timings_); 742 offset = InitOatCode(offset); 743 } 744 { 745 TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_); 746 offset = InitOatCodeDexFiles(offset); 747 } 748 oat_size_ = offset; 749 bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u; 750 751 CHECK_EQ(dex_files_->size(), oat_dex_files_.size()); 752 if (compiling_boot_image_) { 753 CHECK_EQ(image_writer_ != nullptr, 754 oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr); 755 } 756 757 write_state_ = WriteState::kWriteRoData; 758 } 759 760 OatWriter::~OatWriter() { 761 } 762 763 class OatWriter::DexMethodVisitor { 764 public: 765 DexMethodVisitor(OatWriter* writer, size_t offset) 766 : writer_(writer), 767 offset_(offset), 768 dex_file_(nullptr), 769 class_def_index_(dex::kDexNoIndex) {} 770 771 virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) { 772 DCHECK(dex_file_ == nullptr); 773 DCHECK_EQ(class_def_index_, dex::kDexNoIndex); 774 dex_file_ = dex_file; 775 class_def_index_ = class_def_index; 776 return true; 777 } 778 779 virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0; 780 781 virtual bool EndClass() { 782 if (kIsDebugBuild) { 783 dex_file_ = nullptr; 784 class_def_index_ = dex::kDexNoIndex; 785 } 786 return true; 787 } 788 789 size_t GetOffset() const { 790 return offset_; 791 } 792 793 protected: 794 virtual ~DexMethodVisitor() { } 795 796 OatWriter* const writer_; 797 798 // The offset is usually advanced for each visited method by the derived class. 799 size_t offset_; 800 801 // The dex file and class def index are set in StartClass(). 802 const DexFile* dex_file_; 803 size_t class_def_index_; 804 }; 805 806 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor { 807 public: 808 OatDexMethodVisitor(OatWriter* writer, size_t offset) 809 : DexMethodVisitor(writer, offset), 810 oat_class_index_(0u), 811 method_offsets_index_(0u) {} 812 813 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE { 814 DexMethodVisitor::StartClass(dex_file, class_def_index); 815 if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) { 816 // There are no oat classes if there aren't any compiled methods. 817 CHECK_LT(oat_class_index_, writer_->oat_classes_.size()); 818 } 819 method_offsets_index_ = 0u; 820 return true; 821 } 822 823 bool EndClass() OVERRIDE { 824 ++oat_class_index_; 825 return DexMethodVisitor::EndClass(); 826 } 827 828 protected: 829 size_t oat_class_index_; 830 size_t method_offsets_index_; 831 }; 832 833 static bool HasCompiledCode(const CompiledMethod* method) { 834 return method != nullptr && !method->GetQuickCode().empty(); 835 } 836 837 static bool HasQuickeningInfo(const CompiledMethod* method) { 838 // The dextodexcompiler puts the quickening info table into the CompiledMethod 839 // for simplicity. 840 return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty(); 841 } 842 843 class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor { 844 public: 845 explicit InitBssLayoutMethodVisitor(OatWriter* writer) 846 : DexMethodVisitor(writer, /* offset */ 0u) {} 847 848 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, 849 const ClassDataItemIterator& it) OVERRIDE { 850 // Look for patches with .bss references and prepare maps with placeholders for their offsets. 851 CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod( 852 MethodReference(dex_file_, it.GetMemberIndex())); 853 if (HasCompiledCode(compiled_method)) { 854 for (const LinkerPatch& patch : compiled_method->GetPatches()) { 855 if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) { 856 MethodReference target_method = patch.TargetMethod(); 857 AddBssReference(target_method, 858 target_method.dex_file->NumMethodIds(), 859 &writer_->bss_method_entry_references_); 860 writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u); 861 } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) { 862 TypeReference target_type(patch.TargetTypeDexFile(), patch.TargetTypeIndex()); 863 AddBssReference(target_type, 864 target_type.dex_file->NumTypeIds(), 865 &writer_->bss_type_entry_references_); 866 writer_->bss_type_entries_.Overwrite(target_type, /* placeholder */ 0u); 867 } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) { 868 StringReference target_string(patch.TargetStringDexFile(), patch.TargetStringIndex()); 869 AddBssReference(target_string, 870 target_string.dex_file->NumStringIds(), 871 &writer_->bss_string_entry_references_); 872 writer_->bss_string_entries_.Overwrite(target_string, /* placeholder */ 0u); 873 } else if (patch.GetType() == LinkerPatch::Type::kStringInternTable || 874 patch.GetType() == LinkerPatch::Type::kTypeClassTable) { 875 writer_->map_boot_image_tables_to_bss_ = true; 876 } 877 } 878 } else { 879 DCHECK(compiled_method == nullptr || compiled_method->GetPatches().empty()); 880 } 881 return true; 882 } 883 884 private: 885 void AddBssReference(const DexFileReference& ref, 886 size_t number_of_indexes, 887 /*inout*/ SafeMap<const DexFile*, BitVector>* references) { 888 // We currently support inlining of throwing instructions only when they originate in the 889 // same dex file as the outer method. All .bss references are used by throwing instructions. 890 DCHECK_EQ(dex_file_, ref.dex_file); 891 892 auto refs_it = references->find(ref.dex_file); 893 if (refs_it == references->end()) { 894 refs_it = references->Put( 895 ref.dex_file, 896 BitVector(number_of_indexes, /* expandable */ false, Allocator::GetMallocAllocator())); 897 refs_it->second.ClearAllBits(); 898 } 899 refs_it->second.SetBit(ref.index); 900 } 901 }; 902 903 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { 904 public: 905 InitOatClassesMethodVisitor(OatWriter* writer, size_t offset) 906 : DexMethodVisitor(writer, offset), 907 compiled_methods_(), 908 compiled_methods_with_code_(0u) { 909 size_t num_classes = 0u; 910 for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) { 911 num_classes += oat_dex_file.class_offsets_.size(); 912 } 913 // If we aren't compiling only reserve headers. 914 writer_->oat_class_headers_.reserve(num_classes); 915 if (writer->MayHaveCompiledMethods()) { 916 writer->oat_classes_.reserve(num_classes); 917 } 918 compiled_methods_.reserve(256u); 919 // If there are any classes, the class offsets allocation aligns the offset. 920 DCHECK(num_classes == 0u || IsAligned<4u>(offset)); 921 } 922 923 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE { 924 DexMethodVisitor::StartClass(dex_file, class_def_index); 925 compiled_methods_.clear(); 926 compiled_methods_with_code_ = 0u; 927 return true; 928 } 929 930 bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, 931 const ClassDataItemIterator& it) OVERRIDE { 932 // Fill in the compiled_methods_ array for methods that have a 933 // CompiledMethod. We track the number of non-null entries in 934 // compiled_methods_with_code_ since we only want to allocate 935 // OatMethodOffsets for the compiled methods. 936 uint32_t method_idx = it.GetMemberIndex(); 937 CompiledMethod* compiled_method = 938 writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx)); 939 compiled_methods_.push_back(compiled_method); 940 if (HasCompiledCode(compiled_method)) { 941 ++compiled_methods_with_code_; 942 } 943 return true; 944 } 945 946 bool EndClass() OVERRIDE { 947 ClassReference class_ref(dex_file_, class_def_index_); 948 ClassStatus status; 949 bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status); 950 if (!found) { 951 VerificationResults* results = writer_->compiler_driver_->GetVerificationResults(); 952 if (results != nullptr && results->IsClassRejected(class_ref)) { 953 // The oat class status is used only for verification of resolved classes, 954 // so use ClassStatus::kErrorResolved whether the class was resolved or unresolved 955 // during compile-time verification. 956 status = ClassStatus::kErrorResolved; 957 } else { 958 status = ClassStatus::kNotReady; 959 } 960 } 961 962 writer_->oat_class_headers_.emplace_back(offset_, 963 compiled_methods_with_code_, 964 compiled_methods_.size(), 965 status); 966 OatClassHeader& header = writer_->oat_class_headers_.back(); 967 offset_ += header.SizeOf(); 968 if (writer_->MayHaveCompiledMethods()) { 969 writer_->oat_classes_.emplace_back(compiled_methods_, 970 compiled_methods_with_code_, 971 header.type_); 972 offset_ += writer_->oat_classes_.back().SizeOf(); 973 } 974 return DexMethodVisitor::EndClass(); 975 } 976 977 private: 978 dchecked_vector<CompiledMethod*> compiled_methods_; 979 size_t compiled_methods_with_code_; 980 }; 981 982 // CompiledMethod + metadata required to do ordered method layout. 983 // 984 // See also OrderedMethodVisitor. 985 struct OatWriter::OrderedMethodData { 986 ProfileCompilationInfo::MethodHotness method_hotness; 987 OatClass* oat_class; 988 CompiledMethod* compiled_method; 989 MethodReference method_reference; 990 size_t method_offsets_index; 991 992 size_t class_def_index; 993 uint32_t access_flags; 994 const DexFile::CodeItem* code_item; 995 996 // A value of -1 denotes missing debug info 997 static constexpr size_t kDebugInfoIdxInvalid = static_cast<size_t>(-1); 998 // Index into writer_->method_info_ 999 size_t debug_info_idx; 1000 1001 bool HasDebugInfo() const { 1002 return debug_info_idx != kDebugInfoIdxInvalid; 1003 } 1004 1005 // Bin each method according to the profile flags. 1006 // 1007 // Groups by e.g. 1008 // -- not hot at all 1009 // -- hot 1010 // -- hot and startup 1011 // -- hot and post-startup 1012 // -- hot and startup and poststartup 1013 // -- startup 1014 // -- startup and post-startup 1015 // -- post-startup 1016 // 1017 // (See MethodHotness enum definition for up-to-date binning order.) 1018 bool operator<(const OrderedMethodData& other) const { 1019 if (kOatWriterForceOatCodeLayout) { 1020 // Development flag: Override default behavior by sorting by name. 1021 1022 std::string name = method_reference.PrettyMethod(); 1023 std::string other_name = other.method_reference.PrettyMethod(); 1024 return name < other_name; 1025 } 1026 1027 // Use the profile's method hotness to determine sort order. 1028 if (GetMethodHotnessOrder() < other.GetMethodHotnessOrder()) { 1029 return true; 1030 } 1031 1032 // Default: retain the original order. 1033 return false; 1034 } 1035 1036 private: 1037 // Used to determine relative order for OAT code layout when determining 1038 // binning. 1039 size_t GetMethodHotnessOrder() const { 1040 bool hotness[] = { 1041 method_hotness.IsHot(), 1042 method_hotness.IsStartup(), 1043 method_hotness.IsPostStartup() 1044 }; 1045 1046 1047 // Note: Bin-to-bin order does not matter. If the kernel does or does not read-ahead 1048 // any memory, it only goes into the buffer cache and does not grow the PSS until the first 1049 // time that memory is referenced in the process. 1050 1051 size_t hotness_bits = 0; 1052 for (size_t i = 0; i < arraysize(hotness); ++i) { 1053 if (hotness[i]) { 1054 hotness_bits |= (1 << i); 1055 } 1056 } 1057 1058 if (kIsDebugBuild) { 1059 // Check for bins that are always-empty given a real profile. 1060 if (method_hotness.IsHot() && 1061 !method_hotness.IsStartup() && !method_hotness.IsPostStartup()) { 1062 std::string name = method_reference.PrettyMethod(); 1063 LOG(FATAL) << "Method " << name << " had a Hot method that wasn't marked " 1064 << "either start-up or post-startup. Possible corrupted profile?"; 1065 // This is not fatal, so only warn. 1066 } 1067 } 1068 1069 return hotness_bits; 1070 } 1071 }; 1072 1073 // Given a queue of CompiledMethod in some total order, 1074 // visit each one in that order. 1075 class OatWriter::OrderedMethodVisitor { 1076 public: 1077 explicit OrderedMethodVisitor(OrderedMethodList ordered_methods) 1078 : ordered_methods_(std::move(ordered_methods)) { 1079 } 1080 1081 virtual ~OrderedMethodVisitor() {} 1082 1083 // Invoke VisitMethod in the order of `ordered_methods`, then invoke VisitComplete. 1084 bool Visit() REQUIRES_SHARED(Locks::mutator_lock_) { 1085 if (!VisitStart()) { 1086 return false; 1087 } 1088 1089 for (const OrderedMethodData& method_data : ordered_methods_) { 1090 if (!VisitMethod(method_data)) { 1091 return false; 1092 } 1093 } 1094 1095 return VisitComplete(); 1096 } 1097 1098 // Invoked once at the beginning, prior to visiting anything else. 1099 // 1100 // Return false to abort further visiting. 1101 virtual bool VisitStart() { return true; } 1102 1103 // Invoked repeatedly in the order specified by `ordered_methods`. 1104 // 1105 // Return false to short-circuit and to stop visiting further methods. 1106 virtual bool VisitMethod(const OrderedMethodData& method_data) 1107 REQUIRES_SHARED(Locks::mutator_lock_) = 0; 1108 1109 // Invoked once at the end, after every other method has been successfully visited. 1110 // 1111 // Return false to indicate the overall `Visit` has failed. 1112 virtual bool VisitComplete() = 0; 1113 1114 OrderedMethodList ReleaseOrderedMethods() { 1115 return std::move(ordered_methods_); 1116 } 1117 1118 private: 1119 // List of compiled methods, sorted by the order defined in OrderedMethodData. 1120 // Methods can be inserted more than once in case of duplicated methods. 1121 OrderedMethodList ordered_methods_; 1122 }; 1123 1124 // Visit every compiled method in order to determine its order within the OAT file. 1125 // Methods from the same class do not need to be adjacent in the OAT code. 1126 class OatWriter::LayoutCodeMethodVisitor : public OatDexMethodVisitor { 1127 public: 1128 LayoutCodeMethodVisitor(OatWriter* writer, size_t offset) 1129 : OatDexMethodVisitor(writer, offset) { 1130 } 1131 1132 bool EndClass() OVERRIDE { 1133 OatDexMethodVisitor::EndClass(); 1134 return true; 1135 } 1136 1137 bool VisitMethod(size_t class_def_method_index, 1138 const ClassDataItemIterator& it) 1139 OVERRIDE 1140 REQUIRES_SHARED(Locks::mutator_lock_) { 1141 Locks::mutator_lock_->AssertSharedHeld(Thread::Current()); 1142 1143 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; 1144 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); 1145 1146 if (HasCompiledCode(compiled_method)) { 1147 size_t debug_info_idx = OrderedMethodData::kDebugInfoIdxInvalid; 1148 1149 { 1150 const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions(); 1151 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode(); 1152 uint32_t code_size = quick_code.size() * sizeof(uint8_t); 1153 1154 // Debug method info must be pushed in the original order 1155 // (i.e. all methods from the same class must be adjacent in the debug info sections) 1156 // ElfCompilationUnitWriter::Write requires this. 1157 if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) { 1158 debug::MethodDebugInfo info = debug::MethodDebugInfo(); 1159 writer_->method_info_.push_back(info); 1160 1161 // The debug info is filled in LayoutReserveOffsetCodeMethodVisitor 1162 // once we know the offsets. 1163 // 1164 // Store the index into writer_->method_info_ since future push-backs 1165 // could reallocate and change the underlying data address. 1166 debug_info_idx = writer_->method_info_.size() - 1; 1167 } 1168 } 1169 1170 MethodReference method_ref(dex_file_, it.GetMemberIndex()); 1171 1172 // Lookup method hotness from profile, if available. 1173 // Otherwise assume a default of none-hotness. 1174 ProfileCompilationInfo::MethodHotness method_hotness = 1175 writer_->profile_compilation_info_ != nullptr 1176 ? writer_->profile_compilation_info_->GetMethodHotness(method_ref) 1177 : ProfileCompilationInfo::MethodHotness(); 1178 1179 // Handle duplicate methods by pushing them repeatedly. 1180 OrderedMethodData method_data = { 1181 method_hotness, 1182 oat_class, 1183 compiled_method, 1184 method_ref, 1185 method_offsets_index_, 1186 class_def_index_, 1187 it.GetMethodAccessFlags(), 1188 it.GetMethodCodeItem(), 1189 debug_info_idx 1190 }; 1191 ordered_methods_.push_back(method_data); 1192 1193 method_offsets_index_++; 1194 } 1195 1196 return true; 1197 } 1198 1199 OrderedMethodList ReleaseOrderedMethods() { 1200 if (kOatWriterForceOatCodeLayout || writer_->profile_compilation_info_ != nullptr) { 1201 // Sort by the method ordering criteria (in OrderedMethodData). 1202 // Since most methods will have the same ordering criteria, 1203 // we preserve the original insertion order within the same sort order. 1204 std::stable_sort(ordered_methods_.begin(), ordered_methods_.end()); 1205 } else { 1206 // The profile-less behavior is as if every method had 0 hotness 1207 // associated with it. 1208 // 1209 // Since sorting all methods with hotness=0 should give back the same 1210 // order as before, don't do anything. 1211 DCHECK(std::is_sorted(ordered_methods_.begin(), ordered_methods_.end())); 1212 } 1213 1214 return std::move(ordered_methods_); 1215 } 1216 1217 private: 1218 // List of compiled methods, later to be sorted by order defined in OrderedMethodData. 1219 // Methods can be inserted more than once in case of duplicated methods. 1220 OrderedMethodList ordered_methods_; 1221 }; 1222 1223 // Given a method order, reserve the offsets for each CompiledMethod in the OAT file. 1224 class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisitor { 1225 public: 1226 LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer, 1227 size_t offset, 1228 OrderedMethodList ordered_methods) 1229 : LayoutReserveOffsetCodeMethodVisitor(writer, 1230 offset, 1231 writer->GetCompilerDriver()->GetCompilerOptions(), 1232 std::move(ordered_methods)) { 1233 } 1234 1235 virtual bool VisitComplete() OVERRIDE { 1236 offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_); 1237 if (generate_debug_info_) { 1238 std::vector<debug::MethodDebugInfo> thunk_infos = 1239 relative_patcher_->GenerateThunkDebugInfo(executable_offset_); 1240 writer_->method_info_.insert(writer_->method_info_.end(), 1241 std::make_move_iterator(thunk_infos.begin()), 1242 std::make_move_iterator(thunk_infos.end())); 1243 } 1244 return true; 1245 } 1246 1247 virtual bool VisitMethod(const OrderedMethodData& method_data) 1248 OVERRIDE 1249 REQUIRES_SHARED(Locks::mutator_lock_) { 1250 OatClass* oat_class = method_data.oat_class; 1251 CompiledMethod* compiled_method = method_data.compiled_method; 1252 const MethodReference& method_ref = method_data.method_reference; 1253 uint16_t method_offsets_index_ = method_data.method_offsets_index; 1254 size_t class_def_index = method_data.class_def_index; 1255 uint32_t access_flags = method_data.access_flags; 1256 bool has_debug_info = method_data.HasDebugInfo(); 1257 size_t debug_info_idx = method_data.debug_info_idx; 1258 1259 DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod(); 1260 1261 // Derived from CompiledMethod. 1262 uint32_t quick_code_offset = 0; 1263 1264 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode(); 1265 uint32_t code_size = quick_code.size() * sizeof(uint8_t); 1266 uint32_t thumb_offset = compiled_method->CodeDelta(); 1267 1268 // Deduplicate code arrays if we are not producing debuggable code. 1269 bool deduped = true; 1270 if (debuggable_) { 1271 quick_code_offset = relative_patcher_->GetOffset(method_ref); 1272 if (quick_code_offset != 0u) { 1273 // Duplicate methods, we want the same code for both of them so that the oat writer puts 1274 // the same code in both ArtMethods so that we do not get different oat code at runtime. 1275 } else { 1276 quick_code_offset = NewQuickCodeOffset(compiled_method, method_ref, thumb_offset); 1277 deduped = false; 1278 } 1279 } else { 1280 quick_code_offset = dedupe_map_.GetOrCreate( 1281 compiled_method, 1282 [this, &deduped, compiled_method, &method_ref, thumb_offset]() { 1283 deduped = false; 1284 return NewQuickCodeOffset(compiled_method, method_ref, thumb_offset); 1285 }); 1286 } 1287 1288 if (code_size != 0) { 1289 if (relative_patcher_->GetOffset(method_ref) != 0u) { 1290 // TODO: Should this be a hard failure? 1291 LOG(WARNING) << "Multiple definitions of " 1292 << method_ref.dex_file->PrettyMethod(method_ref.index) 1293 << " offsets " << relative_patcher_->GetOffset(method_ref) 1294 << " " << quick_code_offset; 1295 } else { 1296 relative_patcher_->SetOffset(method_ref, quick_code_offset); 1297 } 1298 } 1299 1300 // Update quick method header. 1301 DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size()); 1302 OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_]; 1303 uint32_t vmap_table_offset = method_header->GetVmapTableOffset(); 1304 uint32_t method_info_offset = method_header->GetMethodInfoOffset(); 1305 // The code offset was 0 when the mapping/vmap table offset was set, so it's set 1306 // to 0-offset and we need to adjust it by code_offset. 1307 uint32_t code_offset = quick_code_offset - thumb_offset; 1308 CHECK(!compiled_method->GetQuickCode().empty()); 1309 // If the code is compiled, we write the offset of the stack map relative 1310 // to the code. 1311 if (vmap_table_offset != 0u) { 1312 vmap_table_offset += code_offset; 1313 DCHECK_LT(vmap_table_offset, code_offset); 1314 } 1315 if (method_info_offset != 0u) { 1316 method_info_offset += code_offset; 1317 DCHECK_LT(method_info_offset, code_offset); 1318 } 1319 uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); 1320 uint32_t core_spill_mask = compiled_method->GetCoreSpillMask(); 1321 uint32_t fp_spill_mask = compiled_method->GetFpSpillMask(); 1322 *method_header = OatQuickMethodHeader(vmap_table_offset, 1323 method_info_offset, 1324 frame_size_in_bytes, 1325 core_spill_mask, 1326 fp_spill_mask, 1327 code_size); 1328 1329 if (!deduped) { 1330 // Update offsets. (Checksum is updated when writing.) 1331 offset_ += sizeof(*method_header); // Method header is prepended before code. 1332 offset_ += code_size; 1333 // Record absolute patch locations. 1334 if (!compiled_method->GetPatches().empty()) { 1335 uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset(); 1336 for (const LinkerPatch& patch : compiled_method->GetPatches()) { 1337 if (!patch.IsPcRelative()) { 1338 writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset()); 1339 } 1340 } 1341 } 1342 } 1343 1344 // Exclude quickened dex methods (code_size == 0) since they have no native code. 1345 if (generate_debug_info_ && code_size != 0) { 1346 DCHECK(has_debug_info); 1347 1348 bool has_code_info = method_header->IsOptimized(); 1349 // Record debug information for this function if we are doing that. 1350 debug::MethodDebugInfo& info = writer_->method_info_[debug_info_idx]; 1351 DCHECK(info.custom_name.empty()); 1352 info.dex_file = method_ref.dex_file; 1353 info.class_def_index = class_def_index; 1354 info.dex_method_index = method_ref.index; 1355 info.access_flags = access_flags; 1356 // For intrinsics emitted by codegen, the code has no relation to the original code item. 1357 info.code_item = compiled_method->IsIntrinsic() ? nullptr : method_data.code_item; 1358 info.isa = compiled_method->GetInstructionSet(); 1359 info.deduped = deduped; 1360 info.is_native_debuggable = native_debuggable_; 1361 info.is_optimized = method_header->IsOptimized(); 1362 info.is_code_address_text_relative = true; 1363 info.code_address = code_offset - executable_offset_; 1364 info.code_size = code_size; 1365 info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); 1366 info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr; 1367 info.cfi = compiled_method->GetCFIInfo(); 1368 } else { 1369 DCHECK(!has_debug_info); 1370 } 1371 1372 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); 1373 OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_]; 1374 offsets->code_offset_ = quick_code_offset; 1375 1376 return true; 1377 } 1378 1379 size_t GetOffset() const { 1380 return offset_; 1381 } 1382 1383 private: 1384 LayoutReserveOffsetCodeMethodVisitor(OatWriter* writer, 1385 size_t offset, 1386 const CompilerOptions& compiler_options, 1387 OrderedMethodList ordered_methods) 1388 : OrderedMethodVisitor(std::move(ordered_methods)), 1389 writer_(writer), 1390 offset_(offset), 1391 relative_patcher_(writer->relative_patcher_), 1392 executable_offset_(writer->oat_header_->GetExecutableOffset()), 1393 debuggable_(compiler_options.GetDebuggable()), 1394 native_debuggable_(compiler_options.GetNativeDebuggable()), 1395 generate_debug_info_(compiler_options.GenerateAnyDebugInfo()) { 1396 writer->absolute_patch_locations_.reserve( 1397 writer->GetCompilerDriver()->GetNonRelativeLinkerPatchCount()); 1398 } 1399 1400 struct CodeOffsetsKeyComparator { 1401 bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const { 1402 // Code is deduplicated by CompilerDriver, compare only data pointers. 1403 if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) { 1404 return lhs->GetQuickCode().data() < rhs->GetQuickCode().data(); 1405 } 1406 // If the code is the same, all other fields are likely to be the same as well. 1407 if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) { 1408 return lhs->GetVmapTable().data() < rhs->GetVmapTable().data(); 1409 } 1410 if (UNLIKELY(lhs->GetMethodInfo().data() != rhs->GetMethodInfo().data())) { 1411 return lhs->GetMethodInfo().data() < rhs->GetMethodInfo().data(); 1412 } 1413 if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) { 1414 return lhs->GetPatches().data() < rhs->GetPatches().data(); 1415 } 1416 if (UNLIKELY(lhs->IsIntrinsic() != rhs->IsIntrinsic())) { 1417 return rhs->IsIntrinsic(); 1418 } 1419 return false; 1420 } 1421 }; 1422 1423 uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method, 1424 const MethodReference& method_ref, 1425 uint32_t thumb_offset) { 1426 offset_ = relative_patcher_->ReserveSpace(offset_, compiled_method, method_ref); 1427 offset_ += CodeAlignmentSize(offset_, *compiled_method); 1428 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader), 1429 GetInstructionSetAlignment(compiled_method->GetInstructionSet())); 1430 return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset; 1431 } 1432 1433 OatWriter* writer_; 1434 1435 // Offset of the code of the compiled methods. 1436 size_t offset_; 1437 1438 // Deduplication is already done on a pointer basis by the compiler driver, 1439 // so we can simply compare the pointers to find out if things are duplicated. 1440 SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_; 1441 1442 // Cache writer_'s members and compiler options. 1443 MultiOatRelativePatcher* relative_patcher_; 1444 uint32_t executable_offset_; 1445 const bool debuggable_; 1446 const bool native_debuggable_; 1447 const bool generate_debug_info_; 1448 }; 1449 1450 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { 1451 public: 1452 InitMapMethodVisitor(OatWriter* writer, size_t offset) 1453 : OatDexMethodVisitor(writer, offset) {} 1454 1455 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED) 1456 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 1457 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; 1458 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); 1459 1460 if (HasCompiledCode(compiled_method)) { 1461 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); 1462 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u); 1463 1464 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable(); 1465 uint32_t map_size = map.size() * sizeof(map[0]); 1466 if (map_size != 0u) { 1467 size_t offset = dedupe_map_.GetOrCreate( 1468 map.data(), 1469 [this, map_size]() { 1470 uint32_t new_offset = offset_; 1471 offset_ += map_size; 1472 return new_offset; 1473 }); 1474 // Code offset is not initialized yet, so set the map offset to 0u-offset. 1475 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u); 1476 oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset); 1477 } 1478 ++method_offsets_index_; 1479 } 1480 1481 return true; 1482 } 1483 1484 private: 1485 // Deduplication is already done on a pointer basis by the compiler driver, 1486 // so we can simply compare the pointers to find out if things are duplicated. 1487 SafeMap<const uint8_t*, uint32_t> dedupe_map_; 1488 }; 1489 1490 class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor { 1491 public: 1492 InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {} 1493 1494 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED) 1495 OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { 1496 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; 1497 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); 1498 1499 if (HasCompiledCode(compiled_method)) { 1500 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); 1501 DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(), 0u); 1502 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo(); 1503 const uint32_t map_size = map.size() * sizeof(map[0]); 1504 if (map_size != 0u) { 1505 size_t offset = dedupe_map_.GetOrCreate( 1506 map.data(), 1507 [this, map_size]() { 1508 uint32_t new_offset = offset_; 1509 offset_ += map_size; 1510 return new_offset; 1511 }); 1512 // Code offset is not initialized yet, so set the map offset to 0u-offset. 1513 DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u); 1514 oat_class->method_headers_[method_offsets_index_].SetMethodInfoOffset(0u - offset); 1515 } 1516 ++method_offsets_index_; 1517 } 1518 1519 return true; 1520 } 1521 1522 private: 1523 // Deduplication is already done on a pointer basis by the compiler driver, 1524 // so we can simply compare the pointers to find out if things are duplicated. 1525 SafeMap<const uint8_t*, uint32_t> dedupe_map_; 1526 }; 1527 1528 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { 1529 public: 1530 InitImageMethodVisitor(OatWriter* writer, 1531 size_t offset, 1532 const std::vector<const DexFile*>* dex_files) 1533 : OatDexMethodVisitor(writer, offset), 1534 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())), 1535 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr), 1536 dex_files_(dex_files), 1537 class_linker_(Runtime::Current()->GetClassLinker()) {} 1538 1539 // Handle copied methods here. Copy pointer to quick code from 1540 // an origin method to a copied method only if they are 1541 // in the same oat file. If the origin and the copied methods are 1542 // in different oat files don't touch the copied method. 1543 // References to other oat files are not supported yet. 1544 bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE 1545 REQUIRES_SHARED(Locks::mutator_lock_) { 1546 OatDexMethodVisitor::StartClass(dex_file, class_def_index); 1547 // Skip classes that are not in the image. 1548 if (!IsImageClass()) { 1549 return true; 1550 } 1551 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), *dex_file); 1552 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 1553 mirror::Class* klass = dex_cache->GetResolvedType(class_def.class_idx_); 1554 if (klass != nullptr) { 1555 for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) { 1556 // Find origin method. Declaring class and dex_method_idx 1557 // in the copied method should be the same as in the origin 1558 // method. 1559 mirror::Class* declaring_class = method.GetDeclaringClass(); 1560 ArtMethod* origin = declaring_class->FindClassMethod( 1561 declaring_class->GetDexCache(), 1562 method.GetDexMethodIndex(), 1563 pointer_size_); 1564 CHECK(origin != nullptr); 1565 CHECK(!origin->IsDirect()); 1566 CHECK(origin->GetDeclaringClass() == declaring_class); 1567 if (IsInOatFile(&declaring_class->GetDexFile())) { 1568 const void* code_ptr = 1569 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_); 1570 if (code_ptr == nullptr) { 1571 methods_to_process_.push_back(std::make_pair(&method, origin)); 1572 } else { 1573 method.SetEntryPointFromQuickCompiledCodePtrSize( 1574 code_ptr, pointer_size_); 1575 } 1576 } 1577 } 1578 } 1579 return true; 1580 } 1581 1582 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE 1583 REQUIRES_SHARED(Locks::mutator_lock_) { 1584 // Skip methods that are not in the image. 1585 if (!IsImageClass()) { 1586 return true; 1587 } 1588 1589 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; 1590 CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); 1591 1592 OatMethodOffsets offsets(0u); 1593 if (HasCompiledCode(compiled_method)) { 1594 DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); 1595 offsets = oat_class->method_offsets_[method_offsets_index_]; 1596 ++method_offsets_index_; 1597 } 1598 1599 Thread* self = Thread::Current(); 1600 ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_); 1601 ArtMethod* method; 1602 if (writer_->HasBootImage()) { 1603 const InvokeType invoke_type = it.GetMethodInvokeType( 1604 dex_file_->GetClassDef(class_def_index_)); 1605 // Unchecked as we hold mutator_lock_ on entry. 1606 ScopedObjectAccessUnchecked soa(self); 1607 StackHandleScope<1> hs(self); 1608 method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>( 1609 it.GetMemberIndex(), 1610 hs.NewHandle(dex_cache), 1611 ScopedNullHandle<mirror::ClassLoader>(), 1612 /* referrer */ nullptr, 1613 invoke_type); 1614 if (method == nullptr) { 1615 LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: " 1616 << dex_file_->PrettyMethod(it.GetMemberIndex(), true); 1617 self->AssertPendingException(); 1618 mirror::Throwable* exc = self->GetException(); 1619 std::string dump = exc->Dump(); 1620 LOG(FATAL) << dump; 1621 UNREACHABLE(); 1622 } 1623 } else { 1624 // Should already have been resolved by the compiler. 1625 // It may not be resolved if the class failed to verify, in this case, don't set the 1626 // entrypoint. This is not fatal since we shall use a resolution method. 1627 method = class_linker_->LookupResolvedMethod(it.GetMemberIndex(), dex_cache, class_loader_); 1628 } 1629 if (method != nullptr && 1630 compiled_method != nullptr && 1631 compiled_method->GetQuickCode().size() != 0) { 1632 method->SetEntryPointFromQuickCompiledCodePtrSize( 1633 reinterpret_cast<void*>(offsets.code_offset_), pointer_size_); 1634 } 1635 1636 return true; 1637 } 1638 1639 // Check whether current class is image class 1640 bool IsImageClass() { 1641 const DexFile::TypeId& type_id = 1642 dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_); 1643 const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id); 1644 return writer_->GetCompilerDriver()->IsImageClass(class_descriptor); 1645 } 1646 1647 // Check whether specified dex file is in the compiled oat file. 1648 bool IsInOatFile(const DexFile* dex_file) { 1649 return ContainsElement(*dex_files_, dex_file); 1650 } 1651 1652 // Assign a pointer to quick code for copied methods 1653 // not handled in the method StartClass 1654 void Postprocess() { 1655 for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) { 1656 ArtMethod* method = p.first; 1657 ArtMethod* origin = p.second; 1658 const void* code_ptr = 1659 origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_); 1660 if (code_ptr != nullptr) { 1661 method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_); 1662 } 1663 } 1664 } 1665 1666 private: 1667 const PointerSize pointer_size_; 1668 ObjPtr<mirror::ClassLoader> class_loader_; 1669 const std::vector<const DexFile*>* dex_files_; 1670 ClassLinker* const class_linker_; 1671 std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_; 1672 }; 1673 1674 class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { 1675 public: 1676 WriteCodeMethodVisitor(OatWriter* writer, 1677 OutputStream* out, 1678 const size_t file_offset, 1679 size_t relative_offset, 1680 OrderedMethodList ordered_methods) 1681 : OrderedMethodVisitor(std::move(ordered_methods)), 1682 writer_(writer), 1683 offset_(relative_offset), 1684 dex_file_(nullptr), 1685 pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())), 1686 class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr), 1687 out_(out), 1688 file_offset_(file_offset), 1689 class_linker_(Runtime::Current()->GetClassLinker()), 1690 dex_cache_(nullptr), 1691 no_thread_suspension_("OatWriter patching") { 1692 patched_code_.reserve(16 * KB); 1693 if (writer_->HasBootImage()) { 1694 // If we're creating the image, the address space must be ready so that we can apply patches. 1695 CHECK(writer_->image_writer_->IsImageAddressSpaceReady()); 1696 } 1697 } 1698 1699 virtual bool VisitStart() OVERRIDE { 1700 return true; 1701 } 1702 1703 void UpdateDexFileAndDexCache(const DexFile* dex_file) 1704 REQUIRES_SHARED(Locks::mutator_lock_) { 1705 dex_file_ = dex_file; 1706 1707 // Ordered method visiting is only for compiled methods. 1708 DCHECK(writer_->MayHaveCompiledMethods()); 1709 1710 if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) { 1711 // Only need to set the dex cache if we have compilation. Other modes might have unloaded it. 1712 if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) { 1713 dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file); 1714 DCHECK(dex_cache_ != nullptr); 1715 } 1716 } 1717 } 1718 1719 virtual bool VisitComplete() { 1720 offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_); 1721 if (UNLIKELY(offset_ == 0u)) { 1722 PLOG(ERROR) << "Failed to write final relative call thunks"; 1723 return false; 1724 } 1725 return true; 1726 } 1727 1728 virtual bool VisitMethod(const OrderedMethodData& method_data) OVERRIDE 1729 REQUIRES_SHARED(Locks::mutator_lock_) { 1730 const MethodReference& method_ref = method_data.method_reference; 1731 UpdateDexFileAndDexCache(method_ref.dex_file); 1732 1733 OatClass* oat_class = method_data.oat_class; 1734 CompiledMethod* compiled_method = method_data.compiled_method; 1735 uint16_t method_offsets_index = method_data.method_offsets_index; 1736 1737 // No thread suspension since dex_cache_ that may get invalidated if that occurs. 1738 ScopedAssertNoThreadSuspension tsc(__FUNCTION__); 1739 DCHECK(HasCompiledCode(compiled_method)) << method_ref.PrettyMethod(); 1740 1741 // TODO: cleanup DCHECK_OFFSET_ to accept file_offset as parameter. 1742 size_t file_offset = file_offset_; // Used by DCHECK_OFFSET_ macro. 1743 OutputStream* out = out_; 1744 1745 ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode(); 1746 uint32_t code_size = quick_code.size() * sizeof(uint8_t); 1747 1748 // Deduplicate code arrays. 1749 const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index]; 1750 if (method_offsets.code_offset_ > offset_) { 1751 offset_ = writer_->relative_patcher_->WriteThunks(out, offset_); 1752 if (offset_ == 0u) { 1753 ReportWriteFailure("relative call thunk", method_ref); 1754 return false; 1755 } 1756 uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method); 1757 if (alignment_size != 0) { 1758 if (!writer_->WriteCodeAlignment(out, alignment_size)) { 1759 ReportWriteFailure("code alignment padding", method_ref); 1760 return false; 1761 } 1762 offset_ += alignment_size; 1763 DCHECK_OFFSET_(); 1764 } 1765 DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader), 1766 GetInstructionSetAlignment(compiled_method->GetInstructionSet())); 1767 DCHECK_EQ(method_offsets.code_offset_, 1768 offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta()) 1769 << dex_file_->PrettyMethod(method_ref.index); 1770 const OatQuickMethodHeader& method_header = 1771 oat_class->method_headers_[method_offsets_index]; 1772 if (!out->WriteFully(&method_header, sizeof(method_header))) { 1773 ReportWriteFailure("method header", method_ref); 1774 return false; 1775 } 1776 writer_->size_method_header_ += sizeof(method_header); 1777 offset_ += sizeof(method_header); 1778 DCHECK_OFFSET_(); 1779 1780 if (!compiled_method->GetPatches().empty()) { 1781 patched_code_.assign(quick_code.begin(), quick_code.end()); 1782 quick_code = ArrayRef<const uint8_t>(patched_code_); 1783 for (const LinkerPatch& patch : compiled_method->GetPatches()) { 1784 uint32_t literal_offset = patch.LiteralOffset(); 1785 switch (patch.GetType()) { 1786 case LinkerPatch::Type::kMethodBssEntry: { 1787 uint32_t target_offset = 1788 writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod()); 1789 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1790 patch, 1791 offset_ + literal_offset, 1792 target_offset); 1793 break; 1794 } 1795 case LinkerPatch::Type::kCallRelative: { 1796 // NOTE: Relative calls across oat files are not supported. 1797 uint32_t target_offset = GetTargetOffset(patch); 1798 writer_->relative_patcher_->PatchCall(&patched_code_, 1799 literal_offset, 1800 offset_ + literal_offset, 1801 target_offset); 1802 break; 1803 } 1804 case LinkerPatch::Type::kStringRelative: { 1805 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch)); 1806 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1807 patch, 1808 offset_ + literal_offset, 1809 target_offset); 1810 break; 1811 } 1812 case LinkerPatch::Type::kStringInternTable: { 1813 uint32_t target_offset = GetInternTableEntryOffset(patch); 1814 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1815 patch, 1816 offset_ + literal_offset, 1817 target_offset); 1818 break; 1819 } 1820 case LinkerPatch::Type::kStringBssEntry: { 1821 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex()); 1822 uint32_t target_offset = 1823 writer_->bss_start_ + writer_->bss_string_entries_.Get(ref); 1824 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1825 patch, 1826 offset_ + literal_offset, 1827 target_offset); 1828 break; 1829 } 1830 case LinkerPatch::Type::kTypeRelative: { 1831 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch)); 1832 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1833 patch, 1834 offset_ + literal_offset, 1835 target_offset); 1836 break; 1837 } 1838 case LinkerPatch::Type::kTypeClassTable: { 1839 uint32_t target_offset = GetClassTableEntryOffset(patch); 1840 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1841 patch, 1842 offset_ + literal_offset, 1843 target_offset); 1844 break; 1845 } 1846 case LinkerPatch::Type::kTypeBssEntry: { 1847 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex()); 1848 uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref); 1849 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1850 patch, 1851 offset_ + literal_offset, 1852 target_offset); 1853 break; 1854 } 1855 case LinkerPatch::Type::kCall: { 1856 uint32_t target_offset = GetTargetOffset(patch); 1857 PatchCodeAddress(&patched_code_, literal_offset, target_offset); 1858 break; 1859 } 1860 case LinkerPatch::Type::kMethodRelative: { 1861 uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch)); 1862 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, 1863 patch, 1864 offset_ + literal_offset, 1865 target_offset); 1866 break; 1867 } 1868 case LinkerPatch::Type::kBakerReadBarrierBranch: { 1869 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_, 1870 patch, 1871 offset_ + literal_offset); 1872 break; 1873 } 1874 default: { 1875 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType(); 1876 break; 1877 } 1878 } 1879 } 1880 } 1881 1882 if (!out->WriteFully(quick_code.data(), code_size)) { 1883 ReportWriteFailure("method code", method_ref); 1884 return false; 1885 } 1886 writer_->size_code_ += code_size; 1887 offset_ += code_size; 1888 } 1889 DCHECK_OFFSET_(); 1890 1891 return true; 1892 } 1893 1894 size_t GetOffset() const { 1895 return offset_; 1896 } 1897 1898 private: 1899 OatWriter* const writer_; 1900 1901 // Updated in VisitMethod as methods are written out. 1902 size_t offset_; 1903 1904 // Potentially varies with every different VisitMethod. 1905 // Used to determine which DexCache to use when finding ArtMethods. 1906 const DexFile* dex_file_; 1907 1908 // Pointer size we are compiling to. 1909 const PointerSize pointer_size_; 1910 // The image writer's classloader, if there is one, else null. 1911 ObjPtr<mirror::ClassLoader> class_loader_; 1912 // Stream to output file, where the OAT code will be written to. 1913 OutputStream* const out_; 1914 const size_t file_offset_; 1915 ClassLinker* const class_linker_; 1916 ObjPtr<mirror::DexCache> dex_cache_; 1917 std::vector<uint8_t> patched_code_; 1918 const ScopedAssertNoThreadSuspension no_thread_suspension_; 1919 1920 void ReportWriteFailure(const char* what, const MethodReference& method_ref) { 1921 PLOG(ERROR) << "Failed to write " << what << " for " 1922 << method_ref.PrettyMethod() << " to " << out_->GetLocation(); 1923 } 1924 1925 ArtMethod* GetTargetMethod(const LinkerPatch& patch) 1926 REQUIRES_SHARED(Locks::mutator_lock_) { 1927 MethodReference ref = patch.TargetMethod(); 1928 ObjPtr<mirror::DexCache> dex_cache = 1929 (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache( 1930 Thread::Current(), *ref.dex_file); 1931 ArtMethod* method = 1932 class_linker_->LookupResolvedMethod(ref.index, dex_cache, class_loader_); 1933 CHECK(method != nullptr); 1934 return method; 1935 } 1936 1937 uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { 1938 uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod()); 1939 // If there's no new compiled code, either we're compiling an app and the target method 1940 // is in the boot image, or we need to point to the correct trampoline. 1941 if (UNLIKELY(target_offset == 0)) { 1942 ArtMethod* target = GetTargetMethod(patch); 1943 DCHECK(target != nullptr); 1944 const void* oat_code_offset = 1945 target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_); 1946 if (oat_code_offset != 0) { 1947 DCHECK(!writer_->HasBootImage()); 1948 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset)); 1949 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset)); 1950 DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset)); 1951 target_offset = PointerToLowMemUInt32(oat_code_offset); 1952 } else { 1953 target_offset = target->IsNative() 1954 ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset() 1955 : writer_->oat_header_->GetQuickToInterpreterBridgeOffset(); 1956 } 1957 } 1958 return target_offset; 1959 } 1960 1961 ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file) 1962 REQUIRES_SHARED(Locks::mutator_lock_) { 1963 return (target_dex_file == dex_file_) 1964 ? dex_cache_ 1965 : class_linker_->FindDexCache(Thread::Current(), *target_dex_file); 1966 } 1967 1968 ObjPtr<mirror::Class> GetTargetType(const LinkerPatch& patch) 1969 REQUIRES_SHARED(Locks::mutator_lock_) { 1970 DCHECK(writer_->HasImage()); 1971 ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile()); 1972 ObjPtr<mirror::Class> type = 1973 class_linker_->LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_); 1974 CHECK(type != nullptr); 1975 return type; 1976 } 1977 1978 ObjPtr<mirror::String> GetTargetString(const LinkerPatch& patch) 1979 REQUIRES_SHARED(Locks::mutator_lock_) { 1980 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 1981 ObjPtr<mirror::String> string = 1982 linker->LookupString(patch.TargetStringIndex(), GetDexCache(patch.TargetStringDexFile())); 1983 DCHECK(string != nullptr); 1984 DCHECK(writer_->HasBootImage() || 1985 Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string)); 1986 return string; 1987 } 1988 1989 uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { 1990 DCHECK(writer_->HasBootImage()); 1991 method = writer_->image_writer_->GetImageMethodAddress(method); 1992 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_); 1993 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index); 1994 // TODO: Clean up offset types. The target offset must be treated as signed. 1995 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin); 1996 } 1997 1998 uint32_t GetTargetObjectOffset(ObjPtr<mirror::Object> object) 1999 REQUIRES_SHARED(Locks::mutator_lock_) { 2000 DCHECK(writer_->HasBootImage()); 2001 object = writer_->image_writer_->GetImageAddress(object.Ptr()); 2002 size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_); 2003 uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index); 2004 // TODO: Clean up offset types. The target offset must be treated as signed. 2005 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object.Ptr()) - oat_data_begin); 2006 } 2007 2008 void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object) 2009 REQUIRES_SHARED(Locks::mutator_lock_) { 2010 if (writer_->HasBootImage()) { 2011 object = writer_->image_writer_->GetImageAddress(object); 2012 } else { 2013 // NOTE: We're using linker patches for app->boot references when the image can 2014 // be relocated and therefore we need to emit .oat_patches. We're not using this 2015 // for app->app references, so check that the object is in the image space. 2016 DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace()); 2017 } 2018 // Note: We only patch targeting Objects in image which is in the low 4gb. 2019 uint32_t address = PointerToLowMemUInt32(object); 2020 DCHECK_LE(offset + 4, code->size()); 2021 uint8_t* data = &(*code)[offset]; 2022 data[0] = address & 0xffu; 2023 data[1] = (address >> 8) & 0xffu; 2024 data[2] = (address >> 16) & 0xffu; 2025 data[3] = (address >> 24) & 0xffu; 2026 } 2027 2028 void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset) 2029 REQUIRES_SHARED(Locks::mutator_lock_) { 2030 uint32_t address = target_offset; 2031 if (writer_->HasBootImage()) { 2032 size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_); 2033 // TODO: Clean up offset types. 2034 // The target_offset must be treated as signed for cross-oat patching. 2035 const void* target = reinterpret_cast<const void*>( 2036 writer_->image_writer_->GetOatDataBegin(oat_index) + 2037 static_cast<int32_t>(target_offset)); 2038 address = PointerToLowMemUInt32(target); 2039 } 2040 DCHECK_LE(offset + 4, code->size()); 2041 uint8_t* data = &(*code)[offset]; 2042 data[0] = address & 0xffu; 2043 data[1] = (address >> 8) & 0xffu; 2044 data[2] = (address >> 16) & 0xffu; 2045 data[3] = (address >> 24) & 0xffu; 2046 } 2047 2048 // Calculate the offset of the InternTable slot (GcRoot<String>) when mmapped to the .bss. 2049 uint32_t GetInternTableEntryOffset(const LinkerPatch& patch) 2050 REQUIRES_SHARED(Locks::mutator_lock_) { 2051 DCHECK(!writer_->HasBootImage()); 2052 const uint8_t* string_root = writer_->LookupBootImageInternTableSlot( 2053 *patch.TargetStringDexFile(), patch.TargetStringIndex()); 2054 DCHECK(string_root != nullptr); 2055 return GetBootImageTableEntryOffset(string_root); 2056 } 2057 2058 // Calculate the offset of the ClassTable::TableSlot when mmapped to the .bss. 2059 uint32_t GetClassTableEntryOffset(const LinkerPatch& patch) 2060 REQUIRES_SHARED(Locks::mutator_lock_) { 2061 DCHECK(!writer_->HasBootImage()); 2062 const uint8_t* table_slot = 2063 writer_->LookupBootImageClassTableSlot(*patch.TargetTypeDexFile(), patch.TargetTypeIndex()); 2064 DCHECK(table_slot != nullptr); 2065 return GetBootImageTableEntryOffset(table_slot); 2066 } 2067 2068 uint32_t GetBootImageTableEntryOffset(const uint8_t* raw_root) { 2069 uint32_t base_offset = writer_->bss_start_; 2070 for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) { 2071 const uint8_t* const_tables_begin = 2072 space->Begin() + space->GetImageHeader().GetBootImageConstantTablesOffset(); 2073 size_t offset = static_cast<size_t>(raw_root - const_tables_begin); 2074 if (offset < space->GetImageHeader().GetBootImageConstantTablesSize()) { 2075 DCHECK_LE(base_offset + offset, writer_->bss_start_ + writer_->bss_methods_offset_); 2076 return base_offset + offset; 2077 } 2078 base_offset += space->GetImageHeader().GetBootImageConstantTablesSize(); 2079 } 2080 LOG(FATAL) << "Didn't find boot image string in boot image intern tables!"; 2081 UNREACHABLE(); 2082 } 2083 }; 2084 2085 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { 2086 public: 2087 WriteMapMethodVisitor(OatWriter* writer, 2088 OutputStream* out, 2089 const size_t file_offset, 2090 size_t relative_offset) 2091 : OatDexMethodVisitor(writer, relative_offset), 2092 out_(out), 2093 file_offset_(file_offset) {} 2094 2095 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE { 2096 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; 2097 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); 2098 2099 if (HasCompiledCode(compiled_method)) { 2100 size_t file_offset = file_offset_; 2101 OutputStream* out = out_; 2102 2103 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(); 2104 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_; 2105 ++method_offsets_index_; 2106 2107 DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) || 2108 (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u)) 2109 << compiled_method->GetVmapTable().size() << " " << map_offset << " " 2110 << dex_file_->PrettyMethod(it.GetMemberIndex()); 2111 2112 // If vdex is enabled, only emit the map for compiled code. The quickening info 2113 // is emitted in the vdex already. 2114 if (map_offset != 0u) { 2115 // Transform map_offset to actual oat data offset. 2116 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset; 2117 DCHECK_NE(map_offset, 0u); 2118 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex()); 2119 2120 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable(); 2121 size_t map_size = map.size() * sizeof(map[0]); 2122 if (map_offset == offset_) { 2123 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex). 2124 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) { 2125 ReportWriteFailure(it); 2126 return false; 2127 } 2128 offset_ += map_size; 2129 } 2130 } 2131 DCHECK_OFFSET_(); 2132 } 2133 2134 return true; 2135 } 2136 2137 private: 2138 OutputStream* const out_; 2139 size_t const file_offset_; 2140 2141 void ReportWriteFailure(const ClassDataItemIterator& it) { 2142 PLOG(ERROR) << "Failed to write map for " 2143 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation(); 2144 } 2145 }; 2146 2147 class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor { 2148 public: 2149 WriteMethodInfoVisitor(OatWriter* writer, 2150 OutputStream* out, 2151 const size_t file_offset, 2152 size_t relative_offset) 2153 : OatDexMethodVisitor(writer, relative_offset), 2154 out_(out), 2155 file_offset_(file_offset) {} 2156 2157 bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE { 2158 OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; 2159 const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); 2160 2161 if (HasCompiledCode(compiled_method)) { 2162 size_t file_offset = file_offset_; 2163 OutputStream* out = out_; 2164 uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(); 2165 uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_; 2166 ++method_offsets_index_; 2167 DCHECK((compiled_method->GetMethodInfo().size() == 0u && map_offset == 0u) || 2168 (compiled_method->GetMethodInfo().size() != 0u && map_offset != 0u)) 2169 << compiled_method->GetMethodInfo().size() << " " << map_offset << " " 2170 << dex_file_->PrettyMethod(it.GetMemberIndex()); 2171 if (map_offset != 0u) { 2172 // Transform map_offset to actual oat data offset. 2173 map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset; 2174 DCHECK_NE(map_offset, 0u); 2175 DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex()); 2176 2177 ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo(); 2178 size_t map_size = map.size() * sizeof(map[0]); 2179 if (map_offset == offset_) { 2180 // Write deduplicated map (code info for Optimizing or transformation info for dex2dex). 2181 if (UNLIKELY(!out->WriteFully(map.data(), map_size))) { 2182 ReportWriteFailure(it); 2183 return false; 2184 } 2185 offset_ += map_size; 2186 } 2187 } 2188 DCHECK_OFFSET_(); 2189 } 2190 2191 return true; 2192 } 2193 2194 private: 2195 OutputStream* const out_; 2196 size_t const file_offset_; 2197 2198 void ReportWriteFailure(const ClassDataItemIterator& it) { 2199 PLOG(ERROR) << "Failed to write map for " 2200 << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation(); 2201 } 2202 }; 2203 2204 // Visit all methods from all classes in all dex files with the specified visitor. 2205 bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) { 2206 for (const DexFile* dex_file : *dex_files_) { 2207 const size_t class_def_count = dex_file->NumClassDefs(); 2208 for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) { 2209 if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) { 2210 return false; 2211 } 2212 if (MayHaveCompiledMethods()) { 2213 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 2214 const uint8_t* class_data = dex_file->GetClassData(class_def); 2215 if (class_data != nullptr) { // ie not an empty class, such as a marker interface 2216 ClassDataItemIterator it(*dex_file, class_data); 2217 it.SkipAllFields(); 2218 size_t class_def_method_index = 0u; 2219 while (it.HasNextMethod()) { 2220 if (!visitor->VisitMethod(class_def_method_index, it)) { 2221 return false; 2222 } 2223 ++class_def_method_index; 2224 it.Next(); 2225 } 2226 DCHECK(!it.HasNext()); 2227 } 2228 } 2229 if (UNLIKELY(!visitor->EndClass())) { 2230 return false; 2231 } 2232 } 2233 } 2234 return true; 2235 } 2236 2237 size_t OatWriter::InitOatHeader(InstructionSet instruction_set, 2238 const InstructionSetFeatures* instruction_set_features, 2239 uint32_t num_dex_files, 2240 SafeMap<std::string, std::string>* key_value_store) { 2241 TimingLogger::ScopedTiming split("InitOatHeader", timings_); 2242 oat_header_.reset(OatHeader::Create(instruction_set, 2243 instruction_set_features, 2244 num_dex_files, 2245 key_value_store)); 2246 size_oat_header_ += sizeof(OatHeader); 2247 size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader); 2248 return oat_header_->GetHeaderSize(); 2249 } 2250 2251 size_t OatWriter::InitClassOffsets(size_t offset) { 2252 // Reserve space for class offsets in OAT and update class_offsets_offset_. 2253 for (OatDexFile& oat_dex_file : oat_dex_files_) { 2254 DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u); 2255 if (!oat_dex_file.class_offsets_.empty()) { 2256 // Class offsets are required to be 4 byte aligned. 2257 offset = RoundUp(offset, 4u); 2258 oat_dex_file.class_offsets_offset_ = offset; 2259 offset += oat_dex_file.GetClassOffsetsRawSize(); 2260 DCHECK_ALIGNED(offset, 4u); 2261 } 2262 } 2263 return offset; 2264 } 2265 2266 size_t OatWriter::InitOatClasses(size_t offset) { 2267 // calculate the offsets within OatDexFiles to OatClasses 2268 InitOatClassesMethodVisitor visitor(this, offset); 2269 bool success = VisitDexMethods(&visitor); 2270 CHECK(success); 2271 offset = visitor.GetOffset(); 2272 2273 // Update oat_dex_files_. 2274 auto oat_class_it = oat_class_headers_.begin(); 2275 for (OatDexFile& oat_dex_file : oat_dex_files_) { 2276 for (uint32_t& class_offset : oat_dex_file.class_offsets_) { 2277 DCHECK(oat_class_it != oat_class_headers_.end()); 2278 class_offset = oat_class_it->offset_; 2279 ++oat_class_it; 2280 } 2281 } 2282 CHECK(oat_class_it == oat_class_headers_.end()); 2283 2284 return offset; 2285 } 2286 2287 size_t OatWriter::InitOatMaps(size_t offset) { 2288 if (!MayHaveCompiledMethods()) { 2289 return offset; 2290 } 2291 { 2292 InitMapMethodVisitor visitor(this, offset); 2293 bool success = VisitDexMethods(&visitor); 2294 DCHECK(success); 2295 offset = visitor.GetOffset(); 2296 } 2297 { 2298 InitMethodInfoVisitor visitor(this, offset); 2299 bool success = VisitDexMethods(&visitor); 2300 DCHECK(success); 2301 offset = visitor.GetOffset(); 2302 } 2303 return offset; 2304 } 2305 2306 template <typename GetBssOffset> 2307 static size_t CalculateNumberOfIndexBssMappingEntries(size_t number_of_indexes, 2308 size_t slot_size, 2309 const BitVector& indexes, 2310 GetBssOffset get_bss_offset) { 2311 IndexBssMappingEncoder encoder(number_of_indexes, slot_size); 2312 size_t number_of_entries = 0u; 2313 bool first_index = true; 2314 for (uint32_t index : indexes.Indexes()) { 2315 uint32_t bss_offset = get_bss_offset(index); 2316 if (first_index || !encoder.TryMerge(index, bss_offset)) { 2317 encoder.Reset(index, bss_offset); 2318 ++number_of_entries; 2319 first_index = false; 2320 } 2321 } 2322 DCHECK_NE(number_of_entries, 0u); 2323 return number_of_entries; 2324 } 2325 2326 template <typename GetBssOffset> 2327 static size_t CalculateIndexBssMappingSize(size_t number_of_indexes, 2328 size_t slot_size, 2329 const BitVector& indexes, 2330 GetBssOffset get_bss_offset) { 2331 size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries(number_of_indexes, 2332 slot_size, 2333 indexes, 2334 get_bss_offset); 2335 return IndexBssMapping::ComputeSize(number_of_entries); 2336 } 2337 2338 size_t OatWriter::InitIndexBssMappings(size_t offset) { 2339 if (bss_method_entry_references_.empty() && 2340 bss_type_entry_references_.empty() && 2341 bss_string_entry_references_.empty()) { 2342 return offset; 2343 } 2344 // If there are any classes, the class offsets allocation aligns the offset 2345 // and we cannot have any index bss mappings without class offsets. 2346 static_assert(alignof(IndexBssMapping) == 4u, "IndexBssMapping alignment check."); 2347 DCHECK_ALIGNED(offset, 4u); 2348 2349 size_t number_of_method_dex_files = 0u; 2350 size_t number_of_type_dex_files = 0u; 2351 size_t number_of_string_dex_files = 0u; 2352 PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet()); 2353 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) { 2354 const DexFile* dex_file = (*dex_files_)[i]; 2355 auto method_it = bss_method_entry_references_.find(dex_file); 2356 if (method_it != bss_method_entry_references_.end()) { 2357 const BitVector& method_indexes = method_it->second; 2358 ++number_of_method_dex_files; 2359 oat_dex_files_[i].method_bss_mapping_offset_ = offset; 2360 offset += CalculateIndexBssMappingSize( 2361 dex_file->NumMethodIds(), 2362 static_cast<size_t>(pointer_size), 2363 method_indexes, 2364 [=](uint32_t index) { 2365 return bss_method_entries_.Get({dex_file, index}); 2366 }); 2367 } 2368 2369 auto type_it = bss_type_entry_references_.find(dex_file); 2370 if (type_it != bss_type_entry_references_.end()) { 2371 const BitVector& type_indexes = type_it->second; 2372 ++number_of_type_dex_files; 2373 oat_dex_files_[i].type_bss_mapping_offset_ = offset; 2374 offset += CalculateIndexBssMappingSize( 2375 dex_file->NumTypeIds(), 2376 sizeof(GcRoot<mirror::Class>), 2377 type_indexes, 2378 [=](uint32_t index) { 2379 return bss_type_entries_.Get({dex_file, dex::TypeIndex(index)}); 2380 }); 2381 } 2382 2383 auto string_it = bss_string_entry_references_.find(dex_file); 2384 if (string_it != bss_string_entry_references_.end()) { 2385 const BitVector& string_indexes = string_it->second; 2386 ++number_of_string_dex_files; 2387 oat_dex_files_[i].string_bss_mapping_offset_ = offset; 2388 offset += CalculateIndexBssMappingSize( 2389 dex_file->NumStringIds(), 2390 sizeof(GcRoot<mirror::String>), 2391 string_indexes, 2392 [=](uint32_t index) { 2393 return bss_string_entries_.Get({dex_file, dex::StringIndex(index)}); 2394 }); 2395 } 2396 } 2397 // Check that all dex files targeted by bss entries are in `*dex_files_`. 2398 CHECK_EQ(number_of_method_dex_files, bss_method_entry_references_.size()); 2399 CHECK_EQ(number_of_type_dex_files, bss_type_entry_references_.size()); 2400 CHECK_EQ(number_of_string_dex_files, bss_string_entry_references_.size()); 2401 return offset; 2402 } 2403 2404 size_t OatWriter::InitOatDexFiles(size_t offset) { 2405 // Initialize offsets of oat dex files. 2406 for (OatDexFile& oat_dex_file : oat_dex_files_) { 2407 oat_dex_file.offset_ = offset; 2408 offset += oat_dex_file.SizeOf(); 2409 } 2410 return offset; 2411 } 2412 2413 size_t OatWriter::InitOatCode(size_t offset) { 2414 // calculate the offsets within OatHeader to executable code 2415 size_t old_offset = offset; 2416 // required to be on a new page boundary 2417 offset = RoundUp(offset, kPageSize); 2418 oat_header_->SetExecutableOffset(offset); 2419 size_executable_offset_alignment_ = offset - old_offset; 2420 // TODO: Remove unused trampoline offsets from the OatHeader (requires oat version change). 2421 oat_header_->SetInterpreterToInterpreterBridgeOffset(0); 2422 oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0); 2423 if (compiler_driver_->GetCompilerOptions().IsBootImage()) { 2424 InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); 2425 const bool generate_debug_info = compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo(); 2426 size_t adjusted_offset = offset; 2427 2428 #define DO_TRAMPOLINE(field, fn_name) \ 2429 offset = CompiledCode::AlignCode(offset, instruction_set); \ 2430 adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \ 2431 oat_header_->Set ## fn_name ## Offset(adjusted_offset); \ 2432 (field) = compiler_driver_->Create ## fn_name(); \ 2433 if (generate_debug_info) { \ 2434 debug::MethodDebugInfo info = {}; \ 2435 info.custom_name = #fn_name; \ 2436 info.isa = instruction_set; \ 2437 info.is_code_address_text_relative = true; \ 2438 /* Use the code offset rather than the `adjusted_offset`. */ \ 2439 info.code_address = offset - oat_header_->GetExecutableOffset(); \ 2440 info.code_size = (field)->size(); \ 2441 method_info_.push_back(std::move(info)); \ 2442 } \ 2443 offset += (field)->size(); 2444 2445 DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup); 2446 DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline); 2447 DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline); 2448 DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline); 2449 DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge); 2450 2451 #undef DO_TRAMPOLINE 2452 } else { 2453 oat_header_->SetJniDlsymLookupOffset(0); 2454 oat_header_->SetQuickGenericJniTrampolineOffset(0); 2455 oat_header_->SetQuickImtConflictTrampolineOffset(0); 2456 oat_header_->SetQuickResolutionTrampolineOffset(0); 2457 oat_header_->SetQuickToInterpreterBridgeOffset(0); 2458 } 2459 return offset; 2460 } 2461 2462 size_t OatWriter::InitOatCodeDexFiles(size_t offset) { 2463 if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) { 2464 if (kOatWriterDebugOatCodeLayout) { 2465 LOG(INFO) << "InitOatCodeDexFiles: OatWriter(" 2466 << this << "), " 2467 << "compilation is disabled"; 2468 } 2469 2470 return offset; 2471 } 2472 bool success = false; 2473 2474 { 2475 ScopedObjectAccess soa(Thread::Current()); 2476 2477 LayoutCodeMethodVisitor layout_code_visitor(this, offset); 2478 success = VisitDexMethods(&layout_code_visitor); 2479 DCHECK(success); 2480 2481 LayoutReserveOffsetCodeMethodVisitor layout_reserve_code_visitor( 2482 this, 2483 offset, 2484 layout_code_visitor.ReleaseOrderedMethods()); 2485 success = layout_reserve_code_visitor.Visit(); 2486 DCHECK(success); 2487 offset = layout_reserve_code_visitor.GetOffset(); 2488 2489 // Save the method order because the WriteCodeMethodVisitor will need this 2490 // order again. 2491 DCHECK(ordered_methods_ == nullptr); 2492 ordered_methods_.reset( 2493 new OrderedMethodList( 2494 layout_reserve_code_visitor.ReleaseOrderedMethods())); 2495 2496 if (kOatWriterDebugOatCodeLayout) { 2497 LOG(INFO) << "IniatOatCodeDexFiles: method order: "; 2498 for (const OrderedMethodData& ordered_method : *ordered_methods_) { 2499 std::string pretty_name = ordered_method.method_reference.PrettyMethod(); 2500 LOG(INFO) << pretty_name 2501 << "@ offset " 2502 << relative_patcher_->GetOffset(ordered_method.method_reference) 2503 << " X hotness " 2504 << reinterpret_cast<void*>(ordered_method.method_hotness.GetFlags()); 2505 } 2506 } 2507 } 2508 2509 if (HasImage()) { 2510 InitImageMethodVisitor image_visitor(this, offset, dex_files_); 2511 success = VisitDexMethods(&image_visitor); 2512 image_visitor.Postprocess(); 2513 DCHECK(success); 2514 offset = image_visitor.GetOffset(); 2515 } 2516 2517 return offset; 2518 } 2519 2520 void OatWriter::InitBssLayout(InstructionSet instruction_set) { 2521 { 2522 InitBssLayoutMethodVisitor visitor(this); 2523 bool success = VisitDexMethods(&visitor); 2524 DCHECK(success); 2525 } 2526 2527 DCHECK_EQ(bss_size_, 0u); 2528 if (HasBootImage()) { 2529 DCHECK(!map_boot_image_tables_to_bss_); 2530 DCHECK(bss_string_entries_.empty()); 2531 } 2532 if (!map_boot_image_tables_to_bss_ && 2533 bss_method_entries_.empty() && 2534 bss_type_entries_.empty() && 2535 bss_string_entries_.empty()) { 2536 // Nothing to put to the .bss section. 2537 return; 2538 } 2539 2540 // Allocate space for boot image tables in the .bss section. 2541 PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set); 2542 if (map_boot_image_tables_to_bss_) { 2543 for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) { 2544 bss_size_ += space->GetImageHeader().GetBootImageConstantTablesSize(); 2545 } 2546 } 2547 2548 bss_methods_offset_ = bss_size_; 2549 2550 // Prepare offsets for .bss ArtMethod entries. 2551 for (auto& entry : bss_method_entries_) { 2552 DCHECK_EQ(entry.second, 0u); 2553 entry.second = bss_size_; 2554 bss_size_ += static_cast<size_t>(pointer_size); 2555 } 2556 2557 bss_roots_offset_ = bss_size_; 2558 2559 // Prepare offsets for .bss Class entries. 2560 for (auto& entry : bss_type_entries_) { 2561 DCHECK_EQ(entry.second, 0u); 2562 entry.second = bss_size_; 2563 bss_size_ += sizeof(GcRoot<mirror::Class>); 2564 } 2565 // Prepare offsets for .bss String entries. 2566 for (auto& entry : bss_string_entries_) { 2567 DCHECK_EQ(entry.second, 0u); 2568 entry.second = bss_size_; 2569 bss_size_ += sizeof(GcRoot<mirror::String>); 2570 } 2571 } 2572 2573 bool OatWriter::WriteRodata(OutputStream* out) { 2574 CHECK(write_state_ == WriteState::kWriteRoData); 2575 2576 size_t file_offset = oat_data_offset_; 2577 off_t current_offset = out->Seek(0, kSeekCurrent); 2578 if (current_offset == static_cast<off_t>(-1)) { 2579 PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation(); 2580 } 2581 DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize()); 2582 size_t relative_offset = current_offset - file_offset; 2583 2584 // Wrap out to update checksum with each write. 2585 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get()); 2586 out = &checksum_updating_out; 2587 2588 relative_offset = WriteClassOffsets(out, file_offset, relative_offset); 2589 if (relative_offset == 0) { 2590 PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation(); 2591 return false; 2592 } 2593 2594 relative_offset = WriteClasses(out, file_offset, relative_offset); 2595 if (relative_offset == 0) { 2596 PLOG(ERROR) << "Failed to write classes to " << out->GetLocation(); 2597 return false; 2598 } 2599 2600 relative_offset = WriteIndexBssMappings(out, file_offset, relative_offset); 2601 if (relative_offset == 0) { 2602 PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation(); 2603 return false; 2604 } 2605 2606 relative_offset = WriteMaps(out, file_offset, relative_offset); 2607 if (relative_offset == 0) { 2608 PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation(); 2609 return false; 2610 } 2611 2612 relative_offset = WriteOatDexFiles(out, file_offset, relative_offset); 2613 if (relative_offset == 0) { 2614 PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation(); 2615 return false; 2616 } 2617 2618 // Write padding. 2619 off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent); 2620 relative_offset += size_executable_offset_alignment_; 2621 DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset()); 2622 size_t expected_file_offset = file_offset + relative_offset; 2623 if (static_cast<uint32_t>(new_offset) != expected_file_offset) { 2624 PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset 2625 << " Expected: " << expected_file_offset << " File: " << out->GetLocation(); 2626 return 0; 2627 } 2628 DCHECK_OFFSET(); 2629 2630 write_state_ = WriteState::kWriteText; 2631 return true; 2632 } 2633 2634 class OatWriter::WriteQuickeningInfoMethodVisitor { 2635 public: 2636 WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out) 2637 : writer_(writer), 2638 out_(out) {} 2639 2640 bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) { 2641 // Map of offsets for quicken info related to method indices. 2642 SafeMap<const uint8_t*, uint32_t> offset_map; 2643 // Use method index order to minimize the encoded size of the offset table. 2644 for (const DexFile* dex_file : dex_files) { 2645 std::vector<uint32_t>* const offsets = 2646 &quicken_info_offset_indices_.Put(dex_file, std::vector<uint32_t>())->second; 2647 for (uint32_t method_idx = 0; method_idx < dex_file->NumMethodIds(); ++method_idx) { 2648 uint32_t offset = 0u; 2649 MethodReference method_ref(dex_file, method_idx); 2650 CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(method_ref); 2651 if (compiled_method != nullptr && HasQuickeningInfo(compiled_method)) { 2652 ArrayRef<const uint8_t> map = compiled_method->GetVmapTable(); 2653 2654 // Record each index if required. written_bytes_ is the offset from the start of the 2655 // quicken info data. 2656 // May be already inserted for deduplicate items. 2657 // Add offset of one to make sure 0 represents unused. 2658 auto pair = offset_map.emplace(map.data(), written_bytes_ + 1); 2659 offset = pair.first->second; 2660 // Write out the map if it's not already written. 2661 if (pair.second) { 2662 const uint32_t length = map.size() * sizeof(map.front()); 2663 if (!out_->WriteFully(map.data(), length)) { 2664 PLOG(ERROR) << "Failed to write quickening info for " << method_ref.PrettyMethod() 2665 << " to " << out_->GetLocation(); 2666 return false; 2667 } 2668 written_bytes_ += length; 2669 } 2670 } 2671 offsets->push_back(offset); 2672 } 2673 } 2674 return true; 2675 } 2676 2677 size_t GetNumberOfWrittenBytes() const { 2678 return written_bytes_; 2679 } 2680 2681 SafeMap<const DexFile*, std::vector<uint32_t>>& GetQuickenInfoOffsetIndicies() { 2682 return quicken_info_offset_indices_; 2683 } 2684 2685 private: 2686 OatWriter* const writer_; 2687 OutputStream* const out_; 2688 size_t written_bytes_ = 0u; 2689 SafeMap<const DexFile*, std::vector<uint32_t>> quicken_info_offset_indices_; 2690 }; 2691 2692 class OatWriter::WriteQuickeningInfoOffsetsMethodVisitor { 2693 public: 2694 WriteQuickeningInfoOffsetsMethodVisitor( 2695 OutputStream* out, 2696 uint32_t start_offset, 2697 SafeMap<const DexFile*, std::vector<uint32_t>>* quicken_info_offset_indices, 2698 std::vector<uint32_t>* out_table_offsets) 2699 : out_(out), 2700 start_offset_(start_offset), 2701 quicken_info_offset_indices_(quicken_info_offset_indices), 2702 out_table_offsets_(out_table_offsets) {} 2703 2704 bool VisitDexMethods(const std::vector<const DexFile*>& dex_files) { 2705 for (const DexFile* dex_file : dex_files) { 2706 auto it = quicken_info_offset_indices_->find(dex_file); 2707 DCHECK(it != quicken_info_offset_indices_->end()) << "Failed to find dex file " 2708 << dex_file->GetLocation(); 2709 const std::vector<uint32_t>* const offsets = &it->second; 2710 2711 const uint32_t current_offset = start_offset_ + written_bytes_; 2712 CHECK_ALIGNED_PARAM(current_offset, CompactOffsetTable::kAlignment); 2713 2714 // Generate and write the data. 2715 std::vector<uint8_t> table_data; 2716 CompactOffsetTable::Build(*offsets, &table_data); 2717 2718 // Store the offset since we need to put those after the dex file. Table offsets are relative 2719 // to the start of the quicken info section. 2720 out_table_offsets_->push_back(current_offset); 2721 2722 const uint32_t length = table_data.size() * sizeof(table_data.front()); 2723 if (!out_->WriteFully(table_data.data(), length)) { 2724 PLOG(ERROR) << "Failed to write quickening offset table for " << dex_file->GetLocation() 2725 << " to " << out_->GetLocation(); 2726 return false; 2727 } 2728 written_bytes_ += length; 2729 } 2730 return true; 2731 } 2732 2733 size_t GetNumberOfWrittenBytes() const { 2734 return written_bytes_; 2735 } 2736 2737 private: 2738 OutputStream* const out_; 2739 const uint32_t start_offset_; 2740 size_t written_bytes_ = 0u; 2741 // Maps containing the offsets for the tables. 2742 SafeMap<const DexFile*, std::vector<uint32_t>>* const quicken_info_offset_indices_; 2743 std::vector<uint32_t>* const out_table_offsets_; 2744 }; 2745 2746 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) { 2747 if (!extract_dex_files_into_vdex_) { 2748 // Nothing to write. Leave `vdex_size_` untouched and unaligned. 2749 vdex_quickening_info_offset_ = vdex_size_; 2750 size_quickening_info_alignment_ = 0; 2751 return true; 2752 } 2753 size_t initial_offset = vdex_size_; 2754 // Make sure the table is properly aligned. 2755 size_t start_offset = RoundUp(initial_offset, 4u); 2756 2757 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet); 2758 if (actual_offset != static_cast<off_t>(start_offset)) { 2759 PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset 2760 << " Expected: " << start_offset 2761 << " Output: " << vdex_out->GetLocation(); 2762 return false; 2763 } 2764 2765 size_t current_offset = start_offset; 2766 if (compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) { 2767 std::vector<uint32_t> dex_files_indices; 2768 WriteQuickeningInfoMethodVisitor write_quicken_info_visitor(this, vdex_out); 2769 if (!write_quicken_info_visitor.VisitDexMethods(*dex_files_)) { 2770 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation(); 2771 return false; 2772 } 2773 2774 uint32_t quicken_info_offset = write_quicken_info_visitor.GetNumberOfWrittenBytes(); 2775 current_offset = current_offset + quicken_info_offset; 2776 uint32_t before_offset = current_offset; 2777 current_offset = RoundUp(current_offset, CompactOffsetTable::kAlignment); 2778 const size_t extra_bytes = current_offset - before_offset; 2779 quicken_info_offset += extra_bytes; 2780 actual_offset = vdex_out->Seek(current_offset, kSeekSet); 2781 if (actual_offset != static_cast<off_t>(current_offset)) { 2782 PLOG(ERROR) << "Failed to seek to quickening offset table section. Actual: " << actual_offset 2783 << " Expected: " << current_offset 2784 << " Output: " << vdex_out->GetLocation(); 2785 return false; 2786 } 2787 2788 std::vector<uint32_t> table_offsets; 2789 WriteQuickeningInfoOffsetsMethodVisitor table_visitor( 2790 vdex_out, 2791 quicken_info_offset, 2792 &write_quicken_info_visitor.GetQuickenInfoOffsetIndicies(), 2793 /*out*/ &table_offsets); 2794 if (!table_visitor.VisitDexMethods(*dex_files_)) { 2795 PLOG(ERROR) << "Failed to write the vdex quickening info. File: " 2796 << vdex_out->GetLocation(); 2797 return false; 2798 } 2799 2800 CHECK_EQ(table_offsets.size(), dex_files_->size()); 2801 2802 current_offset += table_visitor.GetNumberOfWrittenBytes(); 2803 2804 // Store the offset table offset as a preheader for each dex. 2805 size_t index = 0; 2806 for (const OatDexFile& oat_dex_file : oat_dex_files_) { 2807 const off_t desired_offset = oat_dex_file.dex_file_offset_ - 2808 sizeof(VdexFile::QuickeningTableOffsetType); 2809 actual_offset = vdex_out->Seek(desired_offset, kSeekSet); 2810 if (actual_offset != desired_offset) { 2811 PLOG(ERROR) << "Failed to seek to before dex file for writing offset table offset: " 2812 << actual_offset << " Expected: " << desired_offset 2813 << " Output: " << vdex_out->GetLocation(); 2814 return false; 2815 } 2816 uint32_t offset = table_offsets[index]; 2817 if (!vdex_out->WriteFully(reinterpret_cast<const uint8_t*>(&offset), sizeof(offset))) { 2818 PLOG(ERROR) << "Failed to write verifier deps." 2819 << " File: " << vdex_out->GetLocation(); 2820 return false; 2821 } 2822 ++index; 2823 } 2824 if (!vdex_out->Flush()) { 2825 PLOG(ERROR) << "Failed to flush stream after writing quickening info." 2826 << " File: " << vdex_out->GetLocation(); 2827 return false; 2828 } 2829 size_quickening_info_ = current_offset - start_offset; 2830 } else { 2831 // We know we did not quicken. 2832 size_quickening_info_ = 0; 2833 } 2834 2835 if (size_quickening_info_ == 0) { 2836 // Nothing was written. Leave `vdex_size_` untouched and unaligned. 2837 vdex_quickening_info_offset_ = initial_offset; 2838 size_quickening_info_alignment_ = 0; 2839 } else { 2840 vdex_size_ = start_offset + size_quickening_info_; 2841 vdex_quickening_info_offset_ = start_offset; 2842 size_quickening_info_alignment_ = start_offset - initial_offset; 2843 } 2844 2845 return true; 2846 } 2847 2848 bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) { 2849 if (verifier_deps == nullptr) { 2850 // Nothing to write. Record the offset, but no need 2851 // for alignment. 2852 vdex_verifier_deps_offset_ = vdex_size_; 2853 return true; 2854 } 2855 2856 size_t initial_offset = vdex_size_; 2857 size_t start_offset = RoundUp(initial_offset, 4u); 2858 2859 vdex_size_ = start_offset; 2860 vdex_verifier_deps_offset_ = vdex_size_; 2861 size_verifier_deps_alignment_ = start_offset - initial_offset; 2862 2863 off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet); 2864 if (actual_offset != static_cast<off_t>(start_offset)) { 2865 PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset 2866 << " Expected: " << start_offset 2867 << " Output: " << vdex_out->GetLocation(); 2868 return false; 2869 } 2870 2871 std::vector<uint8_t> buffer; 2872 verifier_deps->Encode(*dex_files_, &buffer); 2873 2874 if (!vdex_out->WriteFully(buffer.data(), buffer.size())) { 2875 PLOG(ERROR) << "Failed to write verifier deps." 2876 << " File: " << vdex_out->GetLocation(); 2877 return false; 2878 } 2879 if (!vdex_out->Flush()) { 2880 PLOG(ERROR) << "Failed to flush stream after writing verifier deps." 2881 << " File: " << vdex_out->GetLocation(); 2882 return false; 2883 } 2884 2885 size_verifier_deps_ = buffer.size(); 2886 vdex_size_ += size_verifier_deps_; 2887 return true; 2888 } 2889 2890 bool OatWriter::WriteCode(OutputStream* out) { 2891 CHECK(write_state_ == WriteState::kWriteText); 2892 2893 // Wrap out to update checksum with each write. 2894 ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get()); 2895 out = &checksum_updating_out; 2896 2897 SetMultiOatRelativePatcherAdjustment(); 2898 2899 const size_t file_offset = oat_data_offset_; 2900 size_t relative_offset = oat_header_->GetExecutableOffset(); 2901 DCHECK_OFFSET(); 2902 2903 relative_offset = WriteCode(out, file_offset, relative_offset); 2904 if (relative_offset == 0) { 2905 LOG(ERROR) << "Failed to write oat code to " << out->GetLocation(); 2906 return false; 2907 } 2908 2909 relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset); 2910 if (relative_offset == 0) { 2911 LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation(); 2912 return false; 2913 } 2914 2915 const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent); 2916 if (oat_end_file_offset == static_cast<off_t>(-1)) { 2917 LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation(); 2918 return false; 2919 } 2920 2921 if (kIsDebugBuild) { 2922 uint32_t size_total = 0; 2923 #define DO_STAT(x) \ 2924 VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \ 2925 size_total += (x); 2926 2927 DO_STAT(size_vdex_header_); 2928 DO_STAT(size_vdex_checksums_); 2929 DO_STAT(size_dex_file_alignment_); 2930 DO_STAT(size_executable_offset_alignment_); 2931 DO_STAT(size_oat_header_); 2932 DO_STAT(size_oat_header_key_value_store_); 2933 DO_STAT(size_dex_file_); 2934 DO_STAT(size_verifier_deps_); 2935 DO_STAT(size_verifier_deps_alignment_); 2936 DO_STAT(size_quickening_info_); 2937 DO_STAT(size_quickening_info_alignment_); 2938 DO_STAT(size_interpreter_to_interpreter_bridge_); 2939 DO_STAT(size_interpreter_to_compiled_code_bridge_); 2940 DO_STAT(size_jni_dlsym_lookup_); 2941 DO_STAT(size_quick_generic_jni_trampoline_); 2942 DO_STAT(size_quick_imt_conflict_trampoline_); 2943 DO_STAT(size_quick_resolution_trampoline_); 2944 DO_STAT(size_quick_to_interpreter_bridge_); 2945 DO_STAT(size_trampoline_alignment_); 2946 DO_STAT(size_method_header_); 2947 DO_STAT(size_code_); 2948 DO_STAT(size_code_alignment_); 2949 DO_STAT(size_relative_call_thunks_); 2950 DO_STAT(size_misc_thunks_); 2951 DO_STAT(size_vmap_table_); 2952 DO_STAT(size_method_info_); 2953 DO_STAT(size_oat_dex_file_location_size_); 2954 DO_STAT(size_oat_dex_file_location_data_); 2955 DO_STAT(size_oat_dex_file_location_checksum_); 2956 DO_STAT(size_oat_dex_file_offset_); 2957 DO_STAT(size_oat_dex_file_class_offsets_offset_); 2958 DO_STAT(size_oat_dex_file_lookup_table_offset_); 2959 DO_STAT(size_oat_dex_file_dex_layout_sections_offset_); 2960 DO_STAT(size_oat_dex_file_dex_layout_sections_); 2961 DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_); 2962 DO_STAT(size_oat_dex_file_method_bss_mapping_offset_); 2963 DO_STAT(size_oat_dex_file_type_bss_mapping_offset_); 2964 DO_STAT(size_oat_dex_file_string_bss_mapping_offset_); 2965 DO_STAT(size_oat_lookup_table_alignment_); 2966 DO_STAT(size_oat_lookup_table_); 2967 DO_STAT(size_oat_class_offsets_alignment_); 2968 DO_STAT(size_oat_class_offsets_); 2969 DO_STAT(size_oat_class_type_); 2970 DO_STAT(size_oat_class_status_); 2971 DO_STAT(size_oat_class_method_bitmaps_); 2972 DO_STAT(size_oat_class_method_offsets_); 2973 DO_STAT(size_method_bss_mappings_); 2974 DO_STAT(size_type_bss_mappings_); 2975 DO_STAT(size_string_bss_mappings_); 2976 #undef DO_STAT 2977 2978 VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; 2979 2980 CHECK_EQ(vdex_size_ + oat_size_, size_total); 2981 CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset)); 2982 } 2983 2984 CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset)); 2985 CHECK_EQ(oat_size_, relative_offset); 2986 2987 write_state_ = WriteState::kWriteHeader; 2988 return true; 2989 } 2990 2991 bool OatWriter::WriteHeader(OutputStream* out, 2992 uint32_t image_file_location_oat_checksum, 2993 uintptr_t image_file_location_oat_begin, 2994 int32_t image_patch_delta) { 2995 CHECK(write_state_ == WriteState::kWriteHeader); 2996 2997 oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum); 2998 oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin); 2999 if (compiler_driver_->GetCompilerOptions().IsBootImage()) { 3000 CHECK_EQ(image_patch_delta, 0); 3001 CHECK_EQ(oat_header_->GetImagePatchDelta(), 0); 3002 } else { 3003 CHECK_ALIGNED(image_patch_delta, kPageSize); 3004 oat_header_->SetImagePatchDelta(image_patch_delta); 3005 } 3006 oat_header_->UpdateChecksumWithHeaderData(); 3007 3008 const size_t file_offset = oat_data_offset_; 3009 3010 off_t current_offset = out->Seek(0, kSeekCurrent); 3011 if (current_offset == static_cast<off_t>(-1)) { 3012 PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation(); 3013 return false; 3014 } 3015 if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) { 3016 PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation(); 3017 return false; 3018 } 3019 DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent))); 3020 3021 // Flush all other data before writing the header. 3022 if (!out->Flush()) { 3023 PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation(); 3024 return false; 3025 } 3026 // Write the header. 3027 size_t header_size = oat_header_->GetHeaderSize(); 3028 if (!out->WriteFully(oat_header_.get(), header_size)) { 3029 PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation(); 3030 return false; 3031 } 3032 // Flush the header data. 3033 if (!out->Flush()) { 3034 PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation(); 3035 return false; 3036 } 3037 3038 if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) { 3039 PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation(); 3040 return false; 3041 } 3042 DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent)); 3043 3044 write_state_ = WriteState::kDone; 3045 return true; 3046 } 3047 3048 size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) { 3049 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3050 if (oat_dex_file.class_offsets_offset_ != 0u) { 3051 // Class offsets are required to be 4 byte aligned. 3052 if (UNLIKELY(!IsAligned<4u>(relative_offset))) { 3053 size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset; 3054 if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) { 3055 return 0u; 3056 } 3057 relative_offset += padding_size; 3058 } 3059 DCHECK_OFFSET(); 3060 if (!oat_dex_file.WriteClassOffsets(this, out)) { 3061 return 0u; 3062 } 3063 relative_offset += oat_dex_file.GetClassOffsetsRawSize(); 3064 } 3065 } 3066 return relative_offset; 3067 } 3068 3069 size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) { 3070 const bool may_have_compiled = MayHaveCompiledMethods(); 3071 if (may_have_compiled) { 3072 CHECK_EQ(oat_class_headers_.size(), oat_classes_.size()); 3073 } 3074 for (size_t i = 0; i < oat_class_headers_.size(); ++i) { 3075 // If there are any classes, the class offsets allocation aligns the offset. 3076 DCHECK_ALIGNED(relative_offset, 4u); 3077 DCHECK_OFFSET(); 3078 if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) { 3079 return 0u; 3080 } 3081 relative_offset += oat_class_headers_[i].SizeOf(); 3082 if (may_have_compiled) { 3083 if (!oat_classes_[i].Write(this, out)) { 3084 return 0u; 3085 } 3086 relative_offset += oat_classes_[i].SizeOf(); 3087 } 3088 } 3089 return relative_offset; 3090 } 3091 3092 size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) { 3093 { 3094 size_t vmap_tables_offset = relative_offset; 3095 WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset); 3096 if (UNLIKELY(!VisitDexMethods(&visitor))) { 3097 return 0; 3098 } 3099 relative_offset = visitor.GetOffset(); 3100 size_vmap_table_ = relative_offset - vmap_tables_offset; 3101 } 3102 { 3103 size_t method_infos_offset = relative_offset; 3104 WriteMethodInfoVisitor visitor(this, out, file_offset, relative_offset); 3105 if (UNLIKELY(!VisitDexMethods(&visitor))) { 3106 return 0; 3107 } 3108 relative_offset = visitor.GetOffset(); 3109 size_method_info_ = relative_offset - method_infos_offset; 3110 } 3111 3112 return relative_offset; 3113 } 3114 3115 3116 template <typename GetBssOffset> 3117 size_t WriteIndexBssMapping(OutputStream* out, 3118 size_t number_of_indexes, 3119 size_t slot_size, 3120 const BitVector& indexes, 3121 GetBssOffset get_bss_offset) { 3122 // Allocate the IndexBssMapping. 3123 size_t number_of_entries = CalculateNumberOfIndexBssMappingEntries( 3124 number_of_indexes, slot_size, indexes, get_bss_offset); 3125 size_t mappings_size = IndexBssMapping::ComputeSize(number_of_entries); 3126 DCHECK_ALIGNED(mappings_size, sizeof(uint32_t)); 3127 std::unique_ptr<uint32_t[]> storage(new uint32_t[mappings_size / sizeof(uint32_t)]); 3128 IndexBssMapping* mappings = new(storage.get()) IndexBssMapping(number_of_entries); 3129 mappings->ClearPadding(); 3130 // Encode the IndexBssMapping. 3131 IndexBssMappingEncoder encoder(number_of_indexes, slot_size); 3132 auto init_it = mappings->begin(); 3133 bool first_index = true; 3134 for (uint32_t index : indexes.Indexes()) { 3135 size_t bss_offset = get_bss_offset(index); 3136 if (first_index) { 3137 first_index = false; 3138 encoder.Reset(index, bss_offset); 3139 } else if (!encoder.TryMerge(index, bss_offset)) { 3140 *init_it = encoder.GetEntry(); 3141 ++init_it; 3142 encoder.Reset(index, bss_offset); 3143 } 3144 } 3145 // Store the last entry. 3146 *init_it = encoder.GetEntry(); 3147 ++init_it; 3148 DCHECK(init_it == mappings->end()); 3149 3150 if (!out->WriteFully(storage.get(), mappings_size)) { 3151 return 0u; 3152 } 3153 return mappings_size; 3154 } 3155 3156 size_t OatWriter::WriteIndexBssMappings(OutputStream* out, 3157 size_t file_offset, 3158 size_t relative_offset) { 3159 TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_); 3160 if (bss_method_entry_references_.empty() && 3161 bss_type_entry_references_.empty() && 3162 bss_string_entry_references_.empty()) { 3163 return relative_offset; 3164 } 3165 // If there are any classes, the class offsets allocation aligns the offset 3166 // and we cannot have method bss mappings without class offsets. 3167 static_assert(alignof(IndexBssMapping) == sizeof(uint32_t), 3168 "IndexBssMapping alignment check."); 3169 DCHECK_ALIGNED(relative_offset, sizeof(uint32_t)); 3170 3171 PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet()); 3172 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) { 3173 const DexFile* dex_file = (*dex_files_)[i]; 3174 OatDexFile* oat_dex_file = &oat_dex_files_[i]; 3175 auto method_it = bss_method_entry_references_.find(dex_file); 3176 if (method_it != bss_method_entry_references_.end()) { 3177 const BitVector& method_indexes = method_it->second; 3178 DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_); 3179 DCHECK_OFFSET(); 3180 size_t method_mappings_size = WriteIndexBssMapping( 3181 out, 3182 dex_file->NumMethodIds(), 3183 static_cast<size_t>(pointer_size), 3184 method_indexes, 3185 [=](uint32_t index) { 3186 return bss_method_entries_.Get({dex_file, index}); 3187 }); 3188 if (method_mappings_size == 0u) { 3189 return 0u; 3190 } 3191 size_method_bss_mappings_ += method_mappings_size; 3192 relative_offset += method_mappings_size; 3193 } else { 3194 DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_); 3195 } 3196 3197 auto type_it = bss_type_entry_references_.find(dex_file); 3198 if (type_it != bss_type_entry_references_.end()) { 3199 const BitVector& type_indexes = type_it->second; 3200 DCHECK_EQ(relative_offset, oat_dex_file->type_bss_mapping_offset_); 3201 DCHECK_OFFSET(); 3202 size_t type_mappings_size = WriteIndexBssMapping( 3203 out, 3204 dex_file->NumTypeIds(), 3205 sizeof(GcRoot<mirror::Class>), 3206 type_indexes, 3207 [=](uint32_t index) { 3208 return bss_type_entries_.Get({dex_file, dex::TypeIndex(index)}); 3209 }); 3210 if (type_mappings_size == 0u) { 3211 return 0u; 3212 } 3213 size_type_bss_mappings_ += type_mappings_size; 3214 relative_offset += type_mappings_size; 3215 } else { 3216 DCHECK_EQ(0u, oat_dex_file->type_bss_mapping_offset_); 3217 } 3218 3219 auto string_it = bss_string_entry_references_.find(dex_file); 3220 if (string_it != bss_string_entry_references_.end()) { 3221 const BitVector& string_indexes = string_it->second; 3222 DCHECK_EQ(relative_offset, oat_dex_file->string_bss_mapping_offset_); 3223 DCHECK_OFFSET(); 3224 size_t string_mappings_size = WriteIndexBssMapping( 3225 out, 3226 dex_file->NumStringIds(), 3227 sizeof(GcRoot<mirror::String>), 3228 string_indexes, 3229 [=](uint32_t index) { 3230 return bss_string_entries_.Get({dex_file, dex::StringIndex(index)}); 3231 }); 3232 if (string_mappings_size == 0u) { 3233 return 0u; 3234 } 3235 size_string_bss_mappings_ += string_mappings_size; 3236 relative_offset += string_mappings_size; 3237 } else { 3238 DCHECK_EQ(0u, oat_dex_file->string_bss_mapping_offset_); 3239 } 3240 } 3241 return relative_offset; 3242 } 3243 3244 size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) { 3245 TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_); 3246 3247 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) { 3248 OatDexFile* oat_dex_file = &oat_dex_files_[i]; 3249 DCHECK_EQ(relative_offset, oat_dex_file->offset_); 3250 DCHECK_OFFSET(); 3251 3252 // Write OatDexFile. 3253 if (!oat_dex_file->Write(this, out)) { 3254 return 0u; 3255 } 3256 relative_offset += oat_dex_file->SizeOf(); 3257 } 3258 3259 return relative_offset; 3260 } 3261 3262 size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) { 3263 if (compiler_driver_->GetCompilerOptions().IsBootImage()) { 3264 InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); 3265 3266 #define DO_TRAMPOLINE(field) \ 3267 do { \ 3268 uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \ 3269 uint32_t alignment_padding = aligned_offset - relative_offset; \ 3270 out->Seek(alignment_padding, kSeekCurrent); \ 3271 size_trampoline_alignment_ += alignment_padding; \ 3272 if (!out->WriteFully((field)->data(), (field)->size())) { \ 3273 PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \ 3274 return false; \ 3275 } \ 3276 size_ ## field += (field)->size(); \ 3277 relative_offset += alignment_padding + (field)->size(); \ 3278 DCHECK_OFFSET(); \ 3279 } while (false) 3280 3281 DO_TRAMPOLINE(jni_dlsym_lookup_); 3282 DO_TRAMPOLINE(quick_generic_jni_trampoline_); 3283 DO_TRAMPOLINE(quick_imt_conflict_trampoline_); 3284 DO_TRAMPOLINE(quick_resolution_trampoline_); 3285 DO_TRAMPOLINE(quick_to_interpreter_bridge_); 3286 #undef DO_TRAMPOLINE 3287 } 3288 return relative_offset; 3289 } 3290 3291 size_t OatWriter::WriteCodeDexFiles(OutputStream* out, 3292 size_t file_offset, 3293 size_t relative_offset) { 3294 if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) { 3295 // As with InitOatCodeDexFiles, also skip the writer if 3296 // compilation was disabled. 3297 if (kOatWriterDebugOatCodeLayout) { 3298 LOG(INFO) << "WriteCodeDexFiles: OatWriter(" 3299 << this << "), " 3300 << "compilation is disabled"; 3301 } 3302 3303 return relative_offset; 3304 } 3305 ScopedObjectAccess soa(Thread::Current()); 3306 DCHECK(ordered_methods_ != nullptr); 3307 std::unique_ptr<OrderedMethodList> ordered_methods_ptr = 3308 std::move(ordered_methods_); 3309 WriteCodeMethodVisitor visitor(this, 3310 out, 3311 file_offset, 3312 relative_offset, 3313 std::move(*ordered_methods_ptr)); 3314 if (UNLIKELY(!visitor.Visit())) { 3315 return 0; 3316 } 3317 relative_offset = visitor.GetOffset(); 3318 3319 size_code_alignment_ += relative_patcher_->CodeAlignmentSize(); 3320 size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize(); 3321 size_misc_thunks_ += relative_patcher_->MiscThunksSize(); 3322 3323 return relative_offset; 3324 } 3325 3326 bool OatWriter::RecordOatDataOffset(OutputStream* out) { 3327 // Get the elf file offset of the oat file. 3328 const off_t raw_file_offset = out->Seek(0, kSeekCurrent); 3329 if (raw_file_offset == static_cast<off_t>(-1)) { 3330 LOG(ERROR) << "Failed to get file offset in " << out->GetLocation(); 3331 return false; 3332 } 3333 oat_data_offset_ = static_cast<size_t>(raw_file_offset); 3334 return true; 3335 } 3336 3337 bool OatWriter::WriteDexFiles(OutputStream* out, 3338 File* file, 3339 bool update_input_vdex, 3340 CopyOption copy_dex_files) { 3341 TimingLogger::ScopedTiming split("Write Dex files", timings_); 3342 3343 // If extraction is enabled, only do it if not all the dex files are aligned and uncompressed. 3344 if (copy_dex_files == CopyOption::kOnlyIfCompressed) { 3345 extract_dex_files_into_vdex_ = false; 3346 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3347 if (!oat_dex_file.source_.IsZipEntry()) { 3348 extract_dex_files_into_vdex_ = true; 3349 break; 3350 } 3351 ZipEntry* entry = oat_dex_file.source_.GetZipEntry(); 3352 if (!entry->IsUncompressed() || !entry->IsAlignedToDexHeader()) { 3353 extract_dex_files_into_vdex_ = true; 3354 break; 3355 } 3356 } 3357 } else if (copy_dex_files == CopyOption::kAlways) { 3358 extract_dex_files_into_vdex_ = true; 3359 } else { 3360 DCHECK(copy_dex_files == CopyOption::kNever); 3361 extract_dex_files_into_vdex_ = false; 3362 } 3363 3364 if (extract_dex_files_into_vdex_) { 3365 // Add the dex section header. 3366 vdex_size_ += sizeof(VdexFile::DexSectionHeader); 3367 vdex_dex_files_offset_ = vdex_size_; 3368 // Write dex files. 3369 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3370 if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) { 3371 return false; 3372 } 3373 } 3374 3375 // Write shared dex file data section and fix up the dex file headers. 3376 vdex_dex_shared_data_offset_ = vdex_size_; 3377 uint32_t shared_data_size = 0u; 3378 3379 if (dex_container_ != nullptr) { 3380 CHECK(!update_input_vdex) << "Update input vdex should have empty dex container"; 3381 DexContainer::Section* const section = dex_container_->GetDataSection(); 3382 if (section->Size() > 0) { 3383 CHECK(compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone); 3384 const off_t existing_offset = out->Seek(0, kSeekCurrent); 3385 if (static_cast<uint32_t>(existing_offset) != vdex_dex_shared_data_offset_) { 3386 PLOG(ERROR) << "Expected offset " << vdex_dex_shared_data_offset_ << " but got " 3387 << existing_offset; 3388 return false; 3389 } 3390 shared_data_size = section->Size(); 3391 if (!out->WriteFully(section->Begin(), shared_data_size)) { 3392 PLOG(ERROR) << "Failed to write shared data!"; 3393 return false; 3394 } 3395 if (!out->Flush()) { 3396 PLOG(ERROR) << "Failed to flush after writing shared dex section."; 3397 return false; 3398 } 3399 // Fix up the dex headers to have correct offsets to the data section. 3400 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3401 // Overwrite the header by reading it, updating the offset, and writing it back out. 3402 DexFile::Header header; 3403 if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) { 3404 PLOG(ERROR) << "Failed to read dex header for updating"; 3405 return false; 3406 } 3407 if (!CompactDexFile::IsMagicValid(header.magic_)) { 3408 // Non-compact dex file, probably failed to convert due to duplicate methods. 3409 continue; 3410 } 3411 CHECK_GT(vdex_dex_shared_data_offset_, oat_dex_file.dex_file_offset_); 3412 // Offset is from the dex file base. 3413 header.data_off_ = vdex_dex_shared_data_offset_ - oat_dex_file.dex_file_offset_; 3414 // The size should already be what part of the data buffer may be used by the dex. 3415 CHECK_LE(header.data_size_, shared_data_size); 3416 if (!file->PwriteFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) { 3417 PLOG(ERROR) << "Failed to write dex header for updating"; 3418 return false; 3419 } 3420 } 3421 section->Clear(); 3422 } 3423 dex_container_.reset(); 3424 } else { 3425 const uint8_t* data_begin = nullptr; 3426 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3427 DexFile::Header header; 3428 if (!file->PreadFully(&header, sizeof(header), oat_dex_file.dex_file_offset_)) { 3429 PLOG(ERROR) << "Failed to read dex header"; 3430 return false; 3431 } 3432 if (!CompactDexFile::IsMagicValid(header.magic_)) { 3433 // Non compact dex does not have shared data section. 3434 continue; 3435 } 3436 const uint32_t expected_data_off = vdex_dex_shared_data_offset_ - 3437 oat_dex_file.dex_file_offset_; 3438 if (header.data_off_ != expected_data_off) { 3439 PLOG(ERROR) << "Shared data section offset " << header.data_off_ 3440 << " does not match expected value " << expected_data_off; 3441 return false; 3442 } 3443 if (oat_dex_file.source_.IsRawData()) { 3444 // Figure out the start of the shared data section so we can copy it below. 3445 const uint8_t* cur_data_begin = oat_dex_file.source_.GetRawData() + header.data_off_; 3446 if (data_begin != nullptr) { 3447 CHECK_EQ(data_begin, cur_data_begin); 3448 } 3449 data_begin = cur_data_begin; 3450 } 3451 // The different dex files currently can have different data sizes since 3452 // the dex writer writes them one at a time into the shared section.:w 3453 shared_data_size = std::max(shared_data_size, header.data_size_); 3454 } 3455 // If we are not updating the input vdex, write out the shared data section. 3456 if (!update_input_vdex) { 3457 const off_t existing_offset = out->Seek(0, kSeekCurrent); 3458 if (static_cast<uint32_t>(existing_offset) != vdex_dex_shared_data_offset_) { 3459 PLOG(ERROR) << "Expected offset " << vdex_dex_shared_data_offset_ << " but got " 3460 << existing_offset; 3461 return false; 3462 } 3463 if (!out->WriteFully(data_begin, shared_data_size)) { 3464 PLOG(ERROR) << "Failed to write shared data!"; 3465 return false; 3466 } 3467 if (!out->Flush()) { 3468 PLOG(ERROR) << "Failed to flush after writing shared dex section."; 3469 return false; 3470 } 3471 } 3472 } 3473 vdex_size_ += shared_data_size; 3474 size_dex_file_ += shared_data_size; 3475 } else { 3476 vdex_dex_shared_data_offset_ = vdex_size_; 3477 } 3478 3479 return true; 3480 } 3481 3482 void OatWriter::CloseSources() { 3483 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3484 oat_dex_file.source_.Clear(); // Get rid of the reference, it's about to be invalidated. 3485 } 3486 zipped_dex_files_.clear(); 3487 zip_archives_.clear(); 3488 raw_dex_files_.clear(); 3489 } 3490 3491 bool OatWriter::WriteDexFile(OutputStream* out, 3492 File* file, 3493 OatDexFile* oat_dex_file, 3494 bool update_input_vdex) { 3495 if (!SeekToDexFile(out, file, oat_dex_file)) { 3496 return false; 3497 } 3498 // update_input_vdex disables compact dex and layout. 3499 if (profile_compilation_info_ != nullptr || 3500 compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) { 3501 CHECK(!update_input_vdex) 3502 << "We should never update the input vdex when doing dexlayout or compact dex"; 3503 if (!LayoutAndWriteDexFile(out, oat_dex_file)) { 3504 return false; 3505 } 3506 } else if (oat_dex_file->source_.IsZipEntry()) { 3507 DCHECK(!update_input_vdex); 3508 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) { 3509 return false; 3510 } 3511 } else if (oat_dex_file->source_.IsRawFile()) { 3512 DCHECK(!update_input_vdex); 3513 if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) { 3514 return false; 3515 } 3516 } else { 3517 DCHECK(oat_dex_file->source_.IsRawData()); 3518 if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) { 3519 return false; 3520 } 3521 } 3522 3523 // Update current size and account for the written data. 3524 DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_); 3525 vdex_size_ += oat_dex_file->dex_file_size_; 3526 size_dex_file_ += oat_dex_file->dex_file_size_; 3527 return true; 3528 } 3529 3530 bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) { 3531 // Dex files are required to be 4 byte aligned. 3532 size_t initial_offset = vdex_size_; 3533 size_t start_offset = RoundUp(initial_offset, 4); 3534 size_dex_file_alignment_ += start_offset - initial_offset; 3535 3536 // Leave extra room for the quicken offset table offset. 3537 start_offset += sizeof(VdexFile::QuickeningTableOffsetType); 3538 // TODO: Not count the offset as part of alignment. 3539 size_dex_file_alignment_ += sizeof(VdexFile::QuickeningTableOffsetType); 3540 3541 size_t file_offset = start_offset; 3542 3543 // Seek to the start of the dex file and flush any pending operations in the stream. 3544 // Verify that, after flushing the stream, the file is at the same offset as the stream. 3545 off_t actual_offset = out->Seek(file_offset, kSeekSet); 3546 if (actual_offset != static_cast<off_t>(file_offset)) { 3547 PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset 3548 << " Expected: " << file_offset 3549 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3550 return false; 3551 } 3552 if (!out->Flush()) { 3553 PLOG(ERROR) << "Failed to flush before writing dex file." 3554 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3555 return false; 3556 } 3557 actual_offset = lseek(file->Fd(), 0, SEEK_CUR); 3558 if (actual_offset != static_cast<off_t>(file_offset)) { 3559 PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset 3560 << " Expected: " << file_offset 3561 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3562 return false; 3563 } 3564 3565 vdex_size_ = start_offset; 3566 oat_dex_file->dex_file_offset_ = start_offset; 3567 return true; 3568 } 3569 3570 bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) { 3571 // Open dex files and write them into `out`. 3572 // Note that we only verify dex files which do not belong to the boot class path. 3573 // This is because those have been processed by `hiddenapi` and would not pass 3574 // some of the checks. No guarantees are lost, however, as `hiddenapi` verifies 3575 // the dex files prior to processing. 3576 TimingLogger::ScopedTiming split("Dex Layout", timings_); 3577 std::string error_msg; 3578 std::string location(oat_dex_file->GetLocation()); 3579 std::unique_ptr<const DexFile> dex_file; 3580 const ArtDexFileLoader dex_file_loader; 3581 if (oat_dex_file->source_.IsZipEntry()) { 3582 ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry(); 3583 std::unique_ptr<MemMap> mem_map( 3584 zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg)); 3585 if (mem_map == nullptr) { 3586 LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg; 3587 return false; 3588 } 3589 dex_file = dex_file_loader.Open(location, 3590 zip_entry->GetCrc32(), 3591 std::move(mem_map), 3592 /* verify */ !compiling_boot_image_, 3593 /* verify_checksum */ true, 3594 &error_msg); 3595 } else if (oat_dex_file->source_.IsRawFile()) { 3596 File* raw_file = oat_dex_file->source_.GetRawFile(); 3597 int dup_fd = dup(raw_file->Fd()); 3598 if (dup_fd < 0) { 3599 PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location; 3600 return false; 3601 } 3602 dex_file = dex_file_loader.OpenDex(dup_fd, location, 3603 /* verify */ !compiling_boot_image_, 3604 /* verify_checksum */ true, 3605 /* mmap_shared */ false, 3606 &error_msg); 3607 } else { 3608 // The source data is a vdex file. 3609 CHECK(oat_dex_file->source_.IsRawData()) 3610 << static_cast<size_t>(oat_dex_file->source_.GetType()); 3611 const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData(); 3612 // Note: The raw data has already been checked to contain the header 3613 // and all the data that the header specifies as the file size. 3614 DCHECK(raw_dex_file != nullptr); 3615 DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation())); 3616 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file); 3617 // Since the source may have had its layout changed, or may be quickened, don't verify it. 3618 dex_file = dex_file_loader.Open(raw_dex_file, 3619 header->file_size_, 3620 location, 3621 oat_dex_file->dex_file_location_checksum_, 3622 nullptr, 3623 /* verify */ false, 3624 /* verify_checksum */ false, 3625 &error_msg); 3626 } 3627 if (dex_file == nullptr) { 3628 LOG(ERROR) << "Failed to open dex file for layout: " << error_msg; 3629 return false; 3630 } 3631 Options options; 3632 options.compact_dex_level_ = compact_dex_level_; 3633 options.update_checksum_ = true; 3634 DexLayout dex_layout(options, profile_compilation_info_, /*file*/ nullptr, /*header*/ nullptr); 3635 const uint8_t* dex_src = nullptr; 3636 if (dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0, &dex_container_, &error_msg)) { 3637 oat_dex_file->dex_sections_layout_ = dex_layout.GetSections(); 3638 // Dex layout can affect the size of the dex file, so we update here what we have set 3639 // when adding the dex file as a source. 3640 const UnalignedDexFileHeader* header = 3641 AsUnalignedDexFileHeader(dex_container_->GetMainSection()->Begin()); 3642 oat_dex_file->dex_file_size_ = header->file_size_; 3643 dex_src = dex_container_->GetMainSection()->Begin(); 3644 } else { 3645 LOG(WARNING) << "Failed to run dex layout, reason:" << error_msg; 3646 // Since we failed to convert the dex, just copy the input dex. 3647 dex_src = dex_file->Begin(); 3648 } 3649 if (!WriteDexFile(out, oat_dex_file, dex_src, /* update_input_vdex */ false)) { 3650 return false; 3651 } 3652 if (dex_container_ != nullptr) { 3653 // Clear the main section in case we write more data into the container. 3654 dex_container_->GetMainSection()->Clear(); 3655 } 3656 CHECK_EQ(oat_dex_file->dex_file_location_checksum_, dex_file->GetLocationChecksum()); 3657 return true; 3658 } 3659 3660 bool OatWriter::WriteDexFile(OutputStream* out, 3661 File* file, 3662 OatDexFile* oat_dex_file, 3663 ZipEntry* dex_file) { 3664 size_t start_offset = vdex_size_; 3665 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent)); 3666 3667 // Extract the dex file and get the extracted size. 3668 std::string error_msg; 3669 if (!dex_file->ExtractToFile(*file, &error_msg)) { 3670 LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg 3671 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3672 return false; 3673 } 3674 if (file->Flush() != 0) { 3675 PLOG(ERROR) << "Failed to flush dex file from ZIP entry." 3676 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3677 return false; 3678 } 3679 off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR); 3680 if (extracted_end == static_cast<off_t>(-1)) { 3681 PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry." 3682 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3683 return false; 3684 } 3685 if (extracted_end < static_cast<off_t>(start_offset)) { 3686 LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end 3687 << " Start: " << start_offset 3688 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3689 return false; 3690 } 3691 uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset); 3692 if (extracted_size < sizeof(DexFile::Header)) { 3693 LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: " 3694 << extracted_size << " File: " << oat_dex_file->GetLocation(); 3695 return false; 3696 } 3697 3698 // Read the dex file header and extract required data to OatDexFile. 3699 off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET); 3700 if (actual_offset != static_cast<off_t>(start_offset)) { 3701 PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset 3702 << " Expected: " << start_offset 3703 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3704 return false; 3705 } 3706 if (extracted_size < oat_dex_file->dex_file_size_) { 3707 LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size 3708 << " file size from header: " << oat_dex_file->dex_file_size_ 3709 << " File: " << oat_dex_file->GetLocation(); 3710 return false; 3711 } 3712 3713 // Seek both file and stream to the end offset. 3714 size_t end_offset = start_offset + oat_dex_file->dex_file_size_; 3715 actual_offset = lseek(file->Fd(), end_offset, SEEK_SET); 3716 if (actual_offset != static_cast<off_t>(end_offset)) { 3717 PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset 3718 << " Expected: " << end_offset 3719 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3720 return false; 3721 } 3722 actual_offset = out->Seek(end_offset, kSeekSet); 3723 if (actual_offset != static_cast<off_t>(end_offset)) { 3724 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset 3725 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation(); 3726 return false; 3727 } 3728 if (!out->Flush()) { 3729 PLOG(ERROR) << "Failed to flush stream after seeking over dex file." 3730 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3731 return false; 3732 } 3733 3734 // If we extracted more than the size specified in the header, truncate the file. 3735 if (extracted_size > oat_dex_file->dex_file_size_) { 3736 if (file->SetLength(end_offset) != 0) { 3737 PLOG(ERROR) << "Failed to truncate excessive dex file length." 3738 << " File: " << oat_dex_file->GetLocation() 3739 << " Output: " << file->GetPath(); 3740 return false; 3741 } 3742 } 3743 3744 return true; 3745 } 3746 3747 bool OatWriter::WriteDexFile(OutputStream* out, 3748 File* file, 3749 OatDexFile* oat_dex_file, 3750 File* dex_file) { 3751 size_t start_offset = vdex_size_; 3752 DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent)); 3753 3754 off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET); 3755 if (input_offset != static_cast<off_t>(0)) { 3756 PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset 3757 << " Expected: 0" 3758 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3759 return false; 3760 } 3761 3762 // Copy the input dex file using sendfile(). 3763 if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) { 3764 PLOG(ERROR) << "Failed to copy dex file to oat file." 3765 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3766 return false; 3767 } 3768 if (file->Flush() != 0) { 3769 PLOG(ERROR) << "Failed to flush dex file." 3770 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3771 return false; 3772 } 3773 3774 // Check file position and seek the stream to the end offset. 3775 size_t end_offset = start_offset + oat_dex_file->dex_file_size_; 3776 off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR); 3777 if (actual_offset != static_cast<off_t>(end_offset)) { 3778 PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset 3779 << " Expected: " << end_offset 3780 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3781 return false; 3782 } 3783 actual_offset = out->Seek(end_offset, kSeekSet); 3784 if (actual_offset != static_cast<off_t>(end_offset)) { 3785 PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset 3786 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation(); 3787 return false; 3788 } 3789 if (!out->Flush()) { 3790 PLOG(ERROR) << "Failed to flush stream after seeking over dex file." 3791 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath(); 3792 return false; 3793 } 3794 3795 return true; 3796 } 3797 3798 bool OatWriter::WriteDexFile(OutputStream* out, 3799 OatDexFile* oat_dex_file, 3800 const uint8_t* dex_file, 3801 bool update_input_vdex) { 3802 // Note: The raw data has already been checked to contain the header 3803 // and all the data that the header specifies as the file size. 3804 DCHECK(dex_file != nullptr); 3805 DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation())); 3806 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file); 3807 3808 if (update_input_vdex) { 3809 // The vdex already contains the dex code, no need to write it again. 3810 } else { 3811 if (!out->WriteFully(dex_file, header->file_size_)) { 3812 PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation() 3813 << " to " << out->GetLocation(); 3814 return false; 3815 } 3816 if (!out->Flush()) { 3817 PLOG(ERROR) << "Failed to flush stream after writing dex file." 3818 << " File: " << oat_dex_file->GetLocation(); 3819 return false; 3820 } 3821 } 3822 return true; 3823 } 3824 3825 bool OatWriter::OpenDexFiles( 3826 File* file, 3827 bool verify, 3828 /*out*/ std::vector<std::unique_ptr<MemMap>>* opened_dex_files_map, 3829 /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) { 3830 TimingLogger::ScopedTiming split("OpenDexFiles", timings_); 3831 3832 if (oat_dex_files_.empty()) { 3833 // Nothing to do. 3834 return true; 3835 } 3836 3837 if (!extract_dex_files_into_vdex_) { 3838 std::vector<std::unique_ptr<const DexFile>> dex_files; 3839 std::vector<std::unique_ptr<MemMap>> maps; 3840 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3841 std::string error_msg; 3842 MemMap* map = oat_dex_file.source_.GetZipEntry()->MapDirectlyOrExtract( 3843 oat_dex_file.dex_file_location_data_, "zipped dex", &error_msg); 3844 if (map == nullptr) { 3845 LOG(ERROR) << error_msg; 3846 return false; 3847 } 3848 maps.emplace_back(map); 3849 // Now, open the dex file. 3850 const ArtDexFileLoader dex_file_loader; 3851 dex_files.emplace_back(dex_file_loader.Open(map->Begin(), 3852 map->Size(), 3853 oat_dex_file.GetLocation(), 3854 oat_dex_file.dex_file_location_checksum_, 3855 /* oat_dex_file */ nullptr, 3856 verify, 3857 verify, 3858 &error_msg)); 3859 if (dex_files.back() == nullptr) { 3860 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation() 3861 << " Error: " << error_msg; 3862 return false; 3863 } 3864 oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_); 3865 } 3866 *opened_dex_files_map = std::move(maps); 3867 *opened_dex_files = std::move(dex_files); 3868 CloseSources(); 3869 return true; 3870 } 3871 // We could have closed the sources at the point of writing the dex files, but to 3872 // make it consistent with the case we're not writing the dex files, we close them now. 3873 CloseSources(); 3874 3875 size_t map_offset = oat_dex_files_[0].dex_file_offset_; 3876 size_t length = vdex_size_ - map_offset; 3877 3878 std::string error_msg; 3879 std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile( 3880 length, 3881 PROT_READ | PROT_WRITE, 3882 MAP_SHARED, 3883 file->Fd(), 3884 map_offset, 3885 /* low_4gb */ false, 3886 file->GetPath().c_str(), 3887 &error_msg)); 3888 if (dex_files_map == nullptr) { 3889 LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath() 3890 << " error: " << error_msg; 3891 return false; 3892 } 3893 const ArtDexFileLoader dex_file_loader; 3894 std::vector<std::unique_ptr<const DexFile>> dex_files; 3895 for (OatDexFile& oat_dex_file : oat_dex_files_) { 3896 const uint8_t* raw_dex_file = 3897 dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset; 3898 3899 if (kIsDebugBuild) { 3900 // Sanity check our input files. 3901 // Note that ValidateDexFileHeader() logs error messages. 3902 CHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) 3903 << "Failed to verify written dex file header!" 3904 << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset 3905 << " ~ " << static_cast<const void*>(raw_dex_file); 3906 3907 const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file); 3908 CHECK_EQ(header->file_size_, oat_dex_file.dex_file_size_) 3909 << "File size mismatch in written dex file header! Expected: " 3910 << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_ 3911 << " Output: " << file->GetPath(); 3912 } 3913 3914 // Now, open the dex file. 3915 dex_files.emplace_back(dex_file_loader.Open(raw_dex_file, 3916 oat_dex_file.dex_file_size_, 3917 oat_dex_file.GetLocation(), 3918 oat_dex_file.dex_file_location_checksum_, 3919 /* oat_dex_file */ nullptr, 3920 verify, 3921 verify, 3922 &error_msg)); 3923 if (dex_files.back() == nullptr) { 3924 LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation() 3925 << " Error: " << error_msg; 3926 return false; 3927 } 3928 3929 // Set the class_offsets size now that we have easy access to the DexFile and 3930 // it has been verified in dex_file_loader.Open. 3931 oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_); 3932 } 3933 3934 opened_dex_files_map->push_back(std::move(dex_files_map)); 3935 *opened_dex_files = std::move(dex_files); 3936 return true; 3937 } 3938 3939 bool OatWriter::WriteTypeLookupTables( 3940 OutputStream* oat_rodata, 3941 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) { 3942 TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_); 3943 3944 uint32_t expected_offset = oat_data_offset_ + oat_size_; 3945 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet); 3946 if (static_cast<uint32_t>(actual_offset) != expected_offset) { 3947 PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset 3948 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation(); 3949 return false; 3950 } 3951 3952 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size()); 3953 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) { 3954 OatDexFile* oat_dex_file = &oat_dex_files_[i]; 3955 DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u); 3956 3957 if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate || 3958 oat_dex_file->class_offsets_.empty()) { 3959 continue; 3960 } 3961 3962 size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size()); 3963 if (table_size == 0u) { 3964 continue; 3965 } 3966 3967 // Create the lookup table. When `nullptr` is given as the storage buffer, 3968 // TypeLookupTable allocates its own and OatDexFile takes ownership. 3969 const DexFile& dex_file = *opened_dex_files[i]; 3970 { 3971 std::unique_ptr<TypeLookupTable> type_lookup_table = 3972 TypeLookupTable::Create(dex_file, /* storage */ nullptr); 3973 type_lookup_table_oat_dex_files_.push_back( 3974 std::make_unique<art::OatDexFile>(std::move(type_lookup_table))); 3975 dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get()); 3976 } 3977 TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable(); 3978 3979 // Type tables are required to be 4 byte aligned. 3980 size_t initial_offset = oat_size_; 3981 size_t rodata_offset = RoundUp(initial_offset, 4); 3982 size_t padding_size = rodata_offset - initial_offset; 3983 3984 if (padding_size != 0u) { 3985 std::vector<uint8_t> buffer(padding_size, 0u); 3986 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) { 3987 PLOG(ERROR) << "Failed to write lookup table alignment padding." 3988 << " File: " << oat_dex_file->GetLocation() 3989 << " Output: " << oat_rodata->GetLocation(); 3990 return false; 3991 } 3992 } 3993 3994 DCHECK_EQ(oat_data_offset_ + rodata_offset, 3995 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent))); 3996 DCHECK_EQ(table_size, table->RawDataLength()); 3997 3998 if (!oat_rodata->WriteFully(table->RawData(), table_size)) { 3999 PLOG(ERROR) << "Failed to write lookup table." 4000 << " File: " << oat_dex_file->GetLocation() 4001 << " Output: " << oat_rodata->GetLocation(); 4002 return false; 4003 } 4004 4005 oat_dex_file->lookup_table_offset_ = rodata_offset; 4006 4007 oat_size_ += padding_size + table_size; 4008 size_oat_lookup_table_ += table_size; 4009 size_oat_lookup_table_alignment_ += padding_size; 4010 } 4011 4012 if (!oat_rodata->Flush()) { 4013 PLOG(ERROR) << "Failed to flush stream after writing type lookup tables." 4014 << " File: " << oat_rodata->GetLocation(); 4015 return false; 4016 } 4017 4018 return true; 4019 } 4020 4021 bool OatWriter::WriteDexLayoutSections( 4022 OutputStream* oat_rodata, 4023 const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) { 4024 TimingLogger::ScopedTiming split(__FUNCTION__, timings_); 4025 4026 if (!kWriteDexLayoutInfo) { 4027 return true;; 4028 } 4029 4030 uint32_t expected_offset = oat_data_offset_ + oat_size_; 4031 off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet); 4032 if (static_cast<uint32_t>(actual_offset) != expected_offset) { 4033 PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset 4034 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation(); 4035 return false; 4036 } 4037 4038 DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size()); 4039 size_t rodata_offset = oat_size_; 4040 for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) { 4041 OatDexFile* oat_dex_file = &oat_dex_files_[i]; 4042 DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u); 4043 4044 // Write dex layout section alignment bytes. 4045 const size_t padding_size = 4046 RoundUp(rodata_offset, alignof(DexLayoutSections)) - rodata_offset; 4047 if (padding_size != 0u) { 4048 std::vector<uint8_t> buffer(padding_size, 0u); 4049 if (!oat_rodata->WriteFully(buffer.data(), padding_size)) { 4050 PLOG(ERROR) << "Failed to write lookup table alignment padding." 4051 << " File: " << oat_dex_file->GetLocation() 4052 << " Output: " << oat_rodata->GetLocation(); 4053 return false; 4054 } 4055 size_oat_dex_file_dex_layout_sections_alignment_ += padding_size; 4056 rodata_offset += padding_size; 4057 } 4058 4059 DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections)); 4060 DCHECK_EQ(oat_data_offset_ + rodata_offset, 4061 static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent))); 4062 DCHECK(oat_dex_file != nullptr); 4063 if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_, 4064 sizeof(oat_dex_file->dex_sections_layout_))) { 4065 PLOG(ERROR) << "Failed to write dex layout sections." 4066 << " File: " << oat_dex_file->GetLocation() 4067 << " Output: " << oat_rodata->GetLocation(); 4068 return false; 4069 } 4070 oat_dex_file->dex_sections_layout_offset_ = rodata_offset; 4071 size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_); 4072 rodata_offset += sizeof(oat_dex_file->dex_sections_layout_); 4073 } 4074 oat_size_ = rodata_offset; 4075 4076 if (!oat_rodata->Flush()) { 4077 PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections." 4078 << " File: " << oat_rodata->GetLocation(); 4079 return false; 4080 } 4081 4082 return true; 4083 } 4084 4085 bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) { 4086 // Write checksums 4087 off_t checksums_offset = sizeof(VdexFile::VerifierDepsHeader); 4088 off_t actual_offset = vdex_out->Seek(checksums_offset, kSeekSet); 4089 if (actual_offset != checksums_offset) { 4090 PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset 4091 << " File: " << vdex_out->GetLocation(); 4092 return false; 4093 } 4094 4095 for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) { 4096 OatDexFile* oat_dex_file = &oat_dex_files_[i]; 4097 if (!vdex_out->WriteFully( 4098 &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) { 4099 PLOG(ERROR) << "Failed to write dex file location checksum. File: " 4100 << vdex_out->GetLocation(); 4101 return false; 4102 } 4103 size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum); 4104 } 4105 4106 // Maybe write dex section header. 4107 DCHECK_NE(vdex_verifier_deps_offset_, 0u); 4108 DCHECK_NE(vdex_quickening_info_offset_, 0u); 4109 4110 bool has_dex_section = extract_dex_files_into_vdex_; 4111 if (has_dex_section) { 4112 DCHECK_NE(vdex_dex_files_offset_, 0u); 4113 size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_; 4114 size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_; 4115 size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_; 4116 4117 VdexFile::DexSectionHeader dex_section_header(dex_section_size, 4118 dex_shared_data_size, 4119 quickening_info_section_size); 4120 if (!vdex_out->WriteFully(&dex_section_header, sizeof(VdexFile::DexSectionHeader))) { 4121 PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation(); 4122 return false; 4123 } 4124 size_vdex_header_ += sizeof(VdexFile::DexSectionHeader); 4125 } 4126 4127 // Write header. 4128 actual_offset = vdex_out->Seek(0, kSeekSet); 4129 if (actual_offset != 0) { 4130 PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset 4131 << " File: " << vdex_out->GetLocation(); 4132 return false; 4133 } 4134 4135 size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_; 4136 4137 VdexFile::VerifierDepsHeader deps_header( 4138 oat_dex_files_.size(), verifier_deps_section_size, has_dex_section); 4139 if (!vdex_out->WriteFully(&deps_header, sizeof(VdexFile::VerifierDepsHeader))) { 4140 PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation(); 4141 return false; 4142 } 4143 size_vdex_header_ += sizeof(VdexFile::VerifierDepsHeader); 4144 4145 if (!vdex_out->Flush()) { 4146 PLOG(ERROR) << "Failed to flush stream after writing to vdex file." 4147 << " File: " << vdex_out->GetLocation(); 4148 return false; 4149 } 4150 4151 return true; 4152 } 4153 4154 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) { 4155 return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_); 4156 } 4157 4158 bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) { 4159 static const uint8_t kPadding[] = { 4160 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u 4161 }; 4162 DCHECK_LE(size, sizeof(kPadding)); 4163 if (UNLIKELY(!out->WriteFully(kPadding, size))) { 4164 return false; 4165 } 4166 *stat += size; 4167 return true; 4168 } 4169 4170 void OatWriter::SetMultiOatRelativePatcherAdjustment() { 4171 DCHECK(dex_files_ != nullptr); 4172 DCHECK(relative_patcher_ != nullptr); 4173 DCHECK_NE(oat_data_offset_, 0u); 4174 if (image_writer_ != nullptr && !dex_files_->empty()) { 4175 // The oat data begin may not be initialized yet but the oat file offset is ready. 4176 size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front()); 4177 size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index); 4178 relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_); 4179 } 4180 } 4181 4182 OatWriter::OatDexFile::OatDexFile(const char* dex_file_location, 4183 DexFileSource source, 4184 CreateTypeLookupTable create_type_lookup_table, 4185 uint32_t dex_file_location_checksum, 4186 size_t dex_file_size) 4187 : source_(source), 4188 create_type_lookup_table_(create_type_lookup_table), 4189 dex_file_size_(dex_file_size), 4190 offset_(0), 4191 dex_file_location_size_(strlen(dex_file_location)), 4192 dex_file_location_data_(dex_file_location), 4193 dex_file_location_checksum_(dex_file_location_checksum), 4194 dex_file_offset_(0u), 4195 lookup_table_offset_(0u), 4196 class_offsets_offset_(0u), 4197 method_bss_mapping_offset_(0u), 4198 type_bss_mapping_offset_(0u), 4199 string_bss_mapping_offset_(0u), 4200 dex_sections_layout_offset_(0u), 4201 class_offsets_() { 4202 } 4203 4204 size_t OatWriter::OatDexFile::SizeOf() const { 4205 return sizeof(dex_file_location_size_) 4206 + dex_file_location_size_ 4207 + sizeof(dex_file_location_checksum_) 4208 + sizeof(dex_file_offset_) 4209 + sizeof(class_offsets_offset_) 4210 + sizeof(lookup_table_offset_) 4211 + sizeof(method_bss_mapping_offset_) 4212 + sizeof(type_bss_mapping_offset_) 4213 + sizeof(string_bss_mapping_offset_) 4214 + sizeof(dex_sections_layout_offset_); 4215 } 4216 4217 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const { 4218 const size_t file_offset = oat_writer->oat_data_offset_; 4219 DCHECK_OFFSET_(); 4220 4221 if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) { 4222 PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation(); 4223 return false; 4224 } 4225 oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_); 4226 4227 if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) { 4228 PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation(); 4229 return false; 4230 } 4231 oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_; 4232 4233 if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) { 4234 PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation(); 4235 return false; 4236 } 4237 oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_); 4238 4239 if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) { 4240 PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation(); 4241 return false; 4242 } 4243 oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_); 4244 4245 if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) { 4246 PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation(); 4247 return false; 4248 } 4249 oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_); 4250 4251 if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) { 4252 PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation(); 4253 return false; 4254 } 4255 oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_); 4256 4257 if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) { 4258 PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation(); 4259 return false; 4260 } 4261 oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_); 4262 4263 if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) { 4264 PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation(); 4265 return false; 4266 } 4267 oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_); 4268 4269 if (!out->WriteFully(&type_bss_mapping_offset_, sizeof(type_bss_mapping_offset_))) { 4270 PLOG(ERROR) << "Failed to write type bss mapping offset to " << out->GetLocation(); 4271 return false; 4272 } 4273 oat_writer->size_oat_dex_file_type_bss_mapping_offset_ += sizeof(type_bss_mapping_offset_); 4274 4275 if (!out->WriteFully(&string_bss_mapping_offset_, sizeof(string_bss_mapping_offset_))) { 4276 PLOG(ERROR) << "Failed to write string bss mapping offset to " << out->GetLocation(); 4277 return false; 4278 } 4279 oat_writer->size_oat_dex_file_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset_); 4280 4281 return true; 4282 } 4283 4284 bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) { 4285 if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) { 4286 PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation() 4287 << " to " << out->GetLocation(); 4288 return false; 4289 } 4290 oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize(); 4291 return true; 4292 } 4293 4294 OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods, 4295 uint32_t compiled_methods_with_code, 4296 uint16_t oat_class_type) 4297 : compiled_methods_(compiled_methods) { 4298 const uint32_t num_methods = compiled_methods.size(); 4299 CHECK_LE(compiled_methods_with_code, num_methods); 4300 4301 oat_method_offsets_offsets_from_oat_class_.resize(num_methods); 4302 4303 method_offsets_.resize(compiled_methods_with_code); 4304 method_headers_.resize(compiled_methods_with_code); 4305 4306 uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf(); 4307 // We only create this instance if there are at least some compiled. 4308 if (oat_class_type == kOatClassSomeCompiled) { 4309 method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator())); 4310 method_bitmap_size_ = method_bitmap_->GetSizeOf(); 4311 oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_); 4312 oat_method_offsets_offset_from_oat_class += method_bitmap_size_; 4313 } else { 4314 method_bitmap_ = nullptr; 4315 method_bitmap_size_ = 0; 4316 } 4317 4318 for (size_t i = 0; i < num_methods; i++) { 4319 CompiledMethod* compiled_method = compiled_methods_[i]; 4320 if (HasCompiledCode(compiled_method)) { 4321 oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class; 4322 oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets); 4323 if (oat_class_type == kOatClassSomeCompiled) { 4324 method_bitmap_->SetBit(i); 4325 } 4326 } else { 4327 oat_method_offsets_offsets_from_oat_class_[i] = 0; 4328 } 4329 } 4330 } 4331 4332 size_t OatWriter::OatClass::SizeOf() const { 4333 return ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_)) 4334 + method_bitmap_size_ 4335 + (sizeof(method_offsets_[0]) * method_offsets_.size()); 4336 } 4337 4338 bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer, 4339 OutputStream* out, 4340 const size_t file_offset) const { 4341 DCHECK_OFFSET_(); 4342 if (!out->WriteFully(&status_, sizeof(status_))) { 4343 PLOG(ERROR) << "Failed to write class status to " << out->GetLocation(); 4344 return false; 4345 } 4346 oat_writer->size_oat_class_status_ += sizeof(status_); 4347 4348 if (!out->WriteFully(&type_, sizeof(type_))) { 4349 PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation(); 4350 return false; 4351 } 4352 oat_writer->size_oat_class_type_ += sizeof(type_); 4353 return true; 4354 } 4355 4356 bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const { 4357 if (method_bitmap_size_ != 0) { 4358 if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) { 4359 PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation(); 4360 return false; 4361 } 4362 oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_); 4363 4364 if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) { 4365 PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation(); 4366 return false; 4367 } 4368 oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_; 4369 } 4370 4371 if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) { 4372 PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation(); 4373 return false; 4374 } 4375 oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize(); 4376 return true; 4377 } 4378 4379 const uint8_t* OatWriter::LookupBootImageInternTableSlot(const DexFile& dex_file, 4380 dex::StringIndex string_idx) 4381 NO_THREAD_SAFETY_ANALYSIS { // Single-threaded OatWriter can avoid locking. 4382 uint32_t utf16_length; 4383 const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); 4384 DCHECK_EQ(utf16_length, CountModifiedUtf8Chars(utf8_data)); 4385 InternTable::Utf8String string(utf16_length, 4386 utf8_data, 4387 ComputeUtf16HashFromModifiedUtf8(utf8_data, utf16_length)); 4388 const InternTable* intern_table = Runtime::Current()->GetClassLinker()->intern_table_; 4389 for (const InternTable::Table::UnorderedSet& table : intern_table->strong_interns_.tables_) { 4390 auto it = table.Find(string); 4391 if (it != table.end()) { 4392 return reinterpret_cast<const uint8_t*>(std::addressof(*it)); 4393 } 4394 } 4395 LOG(FATAL) << "Did not find boot image string " << utf8_data; 4396 UNREACHABLE(); 4397 } 4398 4399 const uint8_t* OatWriter::LookupBootImageClassTableSlot(const DexFile& dex_file, 4400 dex::TypeIndex type_idx) 4401 NO_THREAD_SAFETY_ANALYSIS { // Single-threaded OatWriter can avoid locking. 4402 const char* descriptor = dex_file.StringByTypeIdx(type_idx); 4403 ClassTable::DescriptorHashPair pair(descriptor, ComputeModifiedUtf8Hash(descriptor)); 4404 ClassTable* table = Runtime::Current()->GetClassLinker()->boot_class_table_.get(); 4405 for (const ClassTable::ClassSet& class_set : table->classes_) { 4406 auto it = class_set.Find(pair); 4407 if (it != class_set.end()) { 4408 return reinterpret_cast<const uint8_t*>(std::addressof(*it)); 4409 } 4410 } 4411 LOG(FATAL) << "Did not find boot image class " << descriptor; 4412 UNREACHABLE(); 4413 } 4414 4415 debug::DebugInfo OatWriter::GetDebugInfo() const { 4416 debug::DebugInfo debug_info{}; 4417 debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(method_info_); 4418 if (VdexWillContainDexFiles()) { 4419 DCHECK_EQ(dex_files_->size(), oat_dex_files_.size()); 4420 for (size_t i = 0, size = dex_files_->size(); i != size; ++i) { 4421 const DexFile* dex_file = (*dex_files_)[i]; 4422 const OatDexFile& oat_dex_file = oat_dex_files_[i]; 4423 uint32_t dex_file_offset = oat_dex_file.dex_file_offset_; 4424 if (dex_file_offset != 0) { 4425 debug_info.dex_files.emplace(dex_file_offset, dex_file); 4426 } 4427 } 4428 } 4429 return debug_info; 4430 } 4431 4432 } // namespace linker 4433 } // namespace art 4434