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