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