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