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