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