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