• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "oat_writer.h"
18 
19 #include <unistd.h>
20 #include <zlib.h>
21 
22 #include "arch/arm64/instruction_set_features_arm64.h"
23 #include "art_method-inl.h"
24 #include "base/allocator.h"
25 #include "base/bit_vector-inl.h"
26 #include "base/enums.h"
27 #include "base/file_magic.h"
28 #include "base/stl_util.h"
29 #include "base/unix_file/fd_file.h"
30 #include "class_linker.h"
31 #include "compiled_method.h"
32 #include "debug/method_debug_info.h"
33 #include "dex/verification_results.h"
34 #include "dex_file-inl.h"
35 #include "dexlayout.h"
36 #include "driver/compiler_driver-inl.h"
37 #include "driver/compiler_options.h"
38 #include "gc/space/image_space.h"
39 #include "gc/space/space.h"
40 #include "handle_scope-inl.h"
41 #include "image_writer.h"
42 #include "linker/buffered_output_stream.h"
43 #include "linker/file_output_stream.h"
44 #include "linker/method_bss_mapping_encoder.h"
45 #include "linker/multi_oat_relative_patcher.h"
46 #include "linker/output_stream.h"
47 #include "mirror/array.h"
48 #include "mirror/class_loader.h"
49 #include "mirror/dex_cache-inl.h"
50 #include "mirror/object-inl.h"
51 #include "oat_quick_method_header.h"
52 #include "os.h"
53 #include "safe_map.h"
54 #include "scoped_thread_state_change-inl.h"
55 #include "type_lookup_table.h"
56 #include "utils/dex_cache_arrays_layout-inl.h"
57 #include "vdex_file.h"
58 #include "verifier/verifier_deps.h"
59 #include "zip_archive.h"
60 
61 namespace art {
62 
63 namespace {  // anonymous namespace
64 
65 // If we write dex layout info in the oat file.
66 static constexpr bool kWriteDexLayoutInfo = true;
67 
68 typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader;
69 
AsUnalignedDexFileHeader(const uint8_t * raw_data)70 const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) {
71     return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data);
72 }
73 
74 class ChecksumUpdatingOutputStream : public OutputStream {
75  public:
ChecksumUpdatingOutputStream(OutputStream * out,OatHeader * oat_header)76   ChecksumUpdatingOutputStream(OutputStream* out, OatHeader* oat_header)
77       : OutputStream(out->GetLocation()), out_(out), oat_header_(oat_header) { }
78 
WriteFully(const void * buffer,size_t byte_count)79   bool WriteFully(const void* buffer, size_t byte_count) OVERRIDE {
80     oat_header_->UpdateChecksum(buffer, byte_count);
81     return out_->WriteFully(buffer, byte_count);
82   }
83 
Seek(off_t offset,Whence whence)84   off_t Seek(off_t offset, Whence whence) OVERRIDE {
85     return out_->Seek(offset, whence);
86   }
87 
Flush()88   bool Flush() OVERRIDE {
89     return out_->Flush();
90   }
91 
92  private:
93   OutputStream* const out_;
94   OatHeader* const oat_header_;
95 };
96 
CodeAlignmentSize(uint32_t header_offset,const CompiledMethod & compiled_method)97 inline uint32_t CodeAlignmentSize(uint32_t header_offset, const CompiledMethod& compiled_method) {
98   // We want to align the code rather than the preheader.
99   uint32_t unaligned_code_offset = header_offset + sizeof(OatQuickMethodHeader);
100   uint32_t aligned_code_offset =  compiled_method.AlignCode(unaligned_code_offset);
101   return aligned_code_offset - unaligned_code_offset;
102 }
103 
104 }  // anonymous namespace
105 
106 // Defines the location of the raw dex file to write.
107 class OatWriter::DexFileSource {
108  public:
109   enum Type {
110     kNone,
111     kZipEntry,
112     kRawFile,
113     kRawData,
114   };
115 
DexFileSource(ZipEntry * zip_entry)116   explicit DexFileSource(ZipEntry* zip_entry)
117       : type_(kZipEntry), source_(zip_entry) {
118     DCHECK(source_ != nullptr);
119   }
120 
DexFileSource(File * raw_file)121   explicit DexFileSource(File* raw_file)
122       : type_(kRawFile), source_(raw_file) {
123     DCHECK(source_ != nullptr);
124   }
125 
DexFileSource(const uint8_t * dex_file)126   explicit DexFileSource(const uint8_t* dex_file)
127       : type_(kRawData), source_(dex_file) {
128     DCHECK(source_ != nullptr);
129   }
130 
GetType() const131   Type GetType() const { return type_; }
IsZipEntry() const132   bool IsZipEntry() const { return type_ == kZipEntry; }
IsRawFile() const133   bool IsRawFile() const { return type_ == kRawFile; }
IsRawData() const134   bool IsRawData() const { return type_ == kRawData; }
135 
GetZipEntry() const136   ZipEntry* GetZipEntry() const {
137     DCHECK(IsZipEntry());
138     DCHECK(source_ != nullptr);
139     return static_cast<ZipEntry*>(const_cast<void*>(source_));
140   }
141 
GetRawFile() const142   File* GetRawFile() const {
143     DCHECK(IsRawFile());
144     DCHECK(source_ != nullptr);
145     return static_cast<File*>(const_cast<void*>(source_));
146   }
147 
GetRawData() const148   const uint8_t* GetRawData() const {
149     DCHECK(IsRawData());
150     DCHECK(source_ != nullptr);
151     return static_cast<const uint8_t*>(source_);
152   }
153 
Clear()154   void Clear() {
155     type_ = kNone;
156     source_ = nullptr;
157   }
158 
159  private:
160   Type type_;
161   const void* source_;
162 };
163 
164 // OatClassHeader is the header only part of the oat class that is required even when compilation
165 // is not enabled.
166 class OatWriter::OatClassHeader {
167  public:
OatClassHeader(uint32_t offset,uint32_t num_non_null_compiled_methods,uint32_t num_methods,mirror::Class::Status status)168   OatClassHeader(uint32_t offset,
169                  uint32_t num_non_null_compiled_methods,
170                  uint32_t num_methods,
171                  mirror::Class::Status status)
172       : status_(status),
173         offset_(offset) {
174     // We just arbitrarily say that 0 methods means kOatClassNoneCompiled and that we won't use
175     // kOatClassAllCompiled unless there is at least one compiled method. This means in an
176     // interpreter only system, we can assert that all classes are kOatClassNoneCompiled.
177     if (num_non_null_compiled_methods == 0) {
178       type_ = kOatClassNoneCompiled;
179     } else if (num_non_null_compiled_methods == num_methods) {
180       type_ = kOatClassAllCompiled;
181     } else {
182       type_ = kOatClassSomeCompiled;
183     }
184   }
185 
186   bool Write(OatWriter* oat_writer, OutputStream* out, const size_t file_offset) const;
187 
SizeOf()188   static size_t SizeOf() {
189     return sizeof(status_) + sizeof(type_);
190   }
191 
192   // Data to write.
193   static_assert(mirror::Class::Status::kStatusMax < (1 << 16), "class status won't fit in 16bits");
194   int16_t status_;
195 
196   static_assert(OatClassType::kOatClassMax < (1 << 16), "oat_class type won't fit in 16bits");
197   uint16_t type_;
198 
199   // Offset of start of OatClass from beginning of OatHeader. It is
200   // used to validate file position when writing.
201   uint32_t offset_;
202 };
203 
204 // The actual oat class body contains the information about compiled methods. It is only required
205 // for compiler filters that have any compilation.
206 class OatWriter::OatClass {
207  public:
208   OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
209            uint32_t compiled_methods_with_code,
210            uint16_t oat_class_type);
211   OatClass(OatClass&& src) = default;
212   size_t SizeOf() const;
213   bool Write(OatWriter* oat_writer, OutputStream* out) const;
214 
GetCompiledMethod(size_t class_def_method_index) const215   CompiledMethod* GetCompiledMethod(size_t class_def_method_index) const {
216     return compiled_methods_[class_def_method_index];
217   }
218 
219   // CompiledMethods for each class_def_method_index, or null if no method is available.
220   dchecked_vector<CompiledMethod*> compiled_methods_;
221 
222   // Offset from OatClass::offset_ to the OatMethodOffsets for the
223   // class_def_method_index. If 0, it means the corresponding
224   // CompiledMethod entry in OatClass::compiled_methods_ should be
225   // null and that the OatClass::type_ should be kOatClassBitmap.
226   dchecked_vector<uint32_t> oat_method_offsets_offsets_from_oat_class_;
227 
228   // Data to write.
229   uint32_t method_bitmap_size_;
230 
231   // bit vector indexed by ClassDef method index. When
232   // OatClassType::type_ is kOatClassBitmap, a set bit indicates the
233   // method has an OatMethodOffsets in methods_offsets_, otherwise
234   // the entry was ommited to save space. If OatClassType::type_ is
235   // not is kOatClassBitmap, the bitmap will be null.
236   std::unique_ptr<BitVector> method_bitmap_;
237 
238   // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
239   // present in the OatClass. Note that some may be missing if
240   // OatClass::compiled_methods_ contains null values (and
241   // oat_method_offsets_offsets_from_oat_class_ should contain 0
242   // values in this case).
243   dchecked_vector<OatMethodOffsets> method_offsets_;
244   dchecked_vector<OatQuickMethodHeader> method_headers_;
245 
246  private:
GetMethodOffsetsRawSize() const247   size_t GetMethodOffsetsRawSize() const {
248     return method_offsets_.size() * sizeof(method_offsets_[0]);
249   }
250 
251   DISALLOW_COPY_AND_ASSIGN(OatClass);
252 };
253 
254 class OatWriter::OatDexFile {
255  public:
256   OatDexFile(const char* dex_file_location,
257              DexFileSource source,
258              CreateTypeLookupTable create_type_lookup_table);
259   OatDexFile(OatDexFile&& src) = default;
260 
GetLocation() const261   const char* GetLocation() const {
262     return dex_file_location_data_;
263   }
264 
265   size_t SizeOf() const;
266   bool Write(OatWriter* oat_writer, OutputStream* out) const;
267   bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out);
268 
GetClassOffsetsRawSize() const269   size_t GetClassOffsetsRawSize() const {
270     return class_offsets_.size() * sizeof(class_offsets_[0]);
271   }
272 
273   // The source of the dex file.
274   DexFileSource source_;
275 
276   // Whether to create the type lookup table.
277   CreateTypeLookupTable create_type_lookup_table_;
278 
279   // Dex file size. Initialized when writing the dex file.
280   size_t dex_file_size_;
281 
282   // Offset of start of OatDexFile from beginning of OatHeader. It is
283   // used to validate file position when writing.
284   size_t offset_;
285 
286   // Data to write.
287   uint32_t dex_file_location_size_;
288   const char* dex_file_location_data_;
289   uint32_t dex_file_location_checksum_;
290   uint32_t dex_file_offset_;
291   uint32_t class_offsets_offset_;
292   uint32_t lookup_table_offset_;
293   uint32_t method_bss_mapping_offset_;
294   uint32_t dex_sections_layout_offset_;
295 
296   // Data to write to a separate section.
297   dchecked_vector<uint32_t> class_offsets_;
298 
299   // Dex section layout info to serialize.
300   DexLayoutSections dex_sections_layout_;
301 
302  private:
303   DISALLOW_COPY_AND_ASSIGN(OatDexFile);
304 };
305 
306 #define DCHECK_OFFSET() \
307   DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
308     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
309 
310 #define DCHECK_OFFSET_() \
311   DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
312     << "file_offset=" << file_offset << " offset_=" << offset_
313 
OatWriter(bool compiling_boot_image,TimingLogger * timings,ProfileCompilationInfo * info)314 OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
315   : write_state_(WriteState::kAddingDexFileSources),
316     timings_(timings),
317     raw_dex_files_(),
318     zip_archives_(),
319     zipped_dex_files_(),
320     zipped_dex_file_locations_(),
321     compiler_driver_(nullptr),
322     image_writer_(nullptr),
323     compiling_boot_image_(compiling_boot_image),
324     dex_files_(nullptr),
325     vdex_size_(0u),
326     vdex_dex_files_offset_(0u),
327     vdex_verifier_deps_offset_(0u),
328     vdex_quickening_info_offset_(0u),
329     oat_size_(0u),
330     bss_start_(0u),
331     bss_size_(0u),
332     bss_methods_offset_(0u),
333     bss_roots_offset_(0u),
334     bss_method_entry_references_(),
335     bss_method_entries_(),
336     bss_type_entries_(),
337     bss_string_entries_(),
338     oat_data_offset_(0u),
339     oat_header_(nullptr),
340     size_vdex_header_(0),
341     size_vdex_checksums_(0),
342     size_dex_file_alignment_(0),
343     size_executable_offset_alignment_(0),
344     size_oat_header_(0),
345     size_oat_header_key_value_store_(0),
346     size_dex_file_(0),
347     size_verifier_deps_(0),
348     size_verifier_deps_alignment_(0),
349     size_quickening_info_(0),
350     size_quickening_info_alignment_(0),
351     size_interpreter_to_interpreter_bridge_(0),
352     size_interpreter_to_compiled_code_bridge_(0),
353     size_jni_dlsym_lookup_(0),
354     size_quick_generic_jni_trampoline_(0),
355     size_quick_imt_conflict_trampoline_(0),
356     size_quick_resolution_trampoline_(0),
357     size_quick_to_interpreter_bridge_(0),
358     size_trampoline_alignment_(0),
359     size_method_header_(0),
360     size_code_(0),
361     size_code_alignment_(0),
362     size_relative_call_thunks_(0),
363     size_misc_thunks_(0),
364     size_vmap_table_(0),
365     size_method_info_(0),
366     size_oat_dex_file_location_size_(0),
367     size_oat_dex_file_location_data_(0),
368     size_oat_dex_file_location_checksum_(0),
369     size_oat_dex_file_offset_(0),
370     size_oat_dex_file_class_offsets_offset_(0),
371     size_oat_dex_file_lookup_table_offset_(0),
372     size_oat_dex_file_dex_layout_sections_offset_(0),
373     size_oat_dex_file_dex_layout_sections_(0),
374     size_oat_dex_file_dex_layout_sections_alignment_(0),
375     size_oat_dex_file_method_bss_mapping_offset_(0),
376     size_oat_lookup_table_alignment_(0),
377     size_oat_lookup_table_(0),
378     size_oat_class_offsets_alignment_(0),
379     size_oat_class_offsets_(0),
380     size_oat_class_type_(0),
381     size_oat_class_status_(0),
382     size_oat_class_method_bitmaps_(0),
383     size_oat_class_method_offsets_(0),
384     size_method_bss_mappings_(0u),
385     relative_patcher_(nullptr),
386     absolute_patch_locations_(),
387     profile_compilation_info_(info) {
388 }
389 
AddDexFileSource(const char * filename,const char * location,CreateTypeLookupTable create_type_lookup_table)390 bool OatWriter::AddDexFileSource(const char* filename,
391                                  const char* location,
392                                  CreateTypeLookupTable create_type_lookup_table) {
393   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
394   uint32_t magic;
395   std::string error_msg;
396   File fd = OpenAndReadMagic(filename, &magic, &error_msg);
397   if (fd.Fd() == -1) {
398     PLOG(ERROR) << "Failed to read magic number from dex file: '" << filename << "'";
399     return false;
400   } else if (IsDexMagic(magic)) {
401     // The file is open for reading, not writing, so it's OK to let the File destructor
402     // close it without checking for explicit Close(), so pass checkUsage = false.
403     raw_dex_files_.emplace_back(new File(fd.Release(), location, /* checkUsage */ false));
404     oat_dex_files_.emplace_back(location,
405                                 DexFileSource(raw_dex_files_.back().get()),
406                                 create_type_lookup_table);
407   } else if (IsZipMagic(magic)) {
408     if (!AddZippedDexFilesSource(std::move(fd), location, create_type_lookup_table)) {
409       return false;
410     }
411   } else {
412     LOG(ERROR) << "Expected valid zip or dex file: '" << filename << "'";
413     return false;
414   }
415   return true;
416 }
417 
418 // Add dex file source(s) from a zip file specified by a file handle.
AddZippedDexFilesSource(File && zip_fd,const char * location,CreateTypeLookupTable create_type_lookup_table)419 bool OatWriter::AddZippedDexFilesSource(File&& zip_fd,
420                                         const char* location,
421                                         CreateTypeLookupTable create_type_lookup_table) {
422   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
423   std::string error_msg;
424   zip_archives_.emplace_back(ZipArchive::OpenFromFd(zip_fd.Release(), location, &error_msg));
425   ZipArchive* zip_archive = zip_archives_.back().get();
426   if (zip_archive == nullptr) {
427     LOG(ERROR) << "Failed to open zip from file descriptor for '" << location << "': "
428         << error_msg;
429     return false;
430   }
431   for (size_t i = 0; ; ++i) {
432     std::string entry_name = DexFile::GetMultiDexClassesDexName(i);
433     std::unique_ptr<ZipEntry> entry(zip_archive->Find(entry_name.c_str(), &error_msg));
434     if (entry == nullptr) {
435       break;
436     }
437     zipped_dex_files_.push_back(std::move(entry));
438     zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
439     const char* full_location = zipped_dex_file_locations_.back().c_str();
440     oat_dex_files_.emplace_back(full_location,
441                                 DexFileSource(zipped_dex_files_.back().get()),
442                                 create_type_lookup_table);
443   }
444   if (zipped_dex_file_locations_.empty()) {
445     LOG(ERROR) << "No dex files in zip file '" << location << "': " << error_msg;
446     return false;
447   }
448   return true;
449 }
450 
451 // Add dex file source(s) from a vdex file specified by a file handle.
AddVdexDexFilesSource(const VdexFile & vdex_file,const char * location,CreateTypeLookupTable create_type_lookup_table)452 bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
453                                       const char* location,
454                                       CreateTypeLookupTable create_type_lookup_table) {
455   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
456   const uint8_t* current_dex_data = nullptr;
457   for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) {
458     current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
459     if (current_dex_data == nullptr) {
460       LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
461       return false;
462     }
463     if (!DexFile::IsMagicValid(current_dex_data)) {
464       LOG(ERROR) << "Invalid magic in vdex file created from " << location;
465       return false;
466     }
467     // We used `zipped_dex_file_locations_` to keep the strings in memory.
468     zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
469     const char* full_location = zipped_dex_file_locations_.back().c_str();
470     oat_dex_files_.emplace_back(full_location,
471                                 DexFileSource(current_dex_data),
472                                 create_type_lookup_table);
473     oat_dex_files_.back().dex_file_location_checksum_ = vdex_file.GetLocationChecksum(i);
474   }
475 
476   if (vdex_file.GetNextDexFileData(current_dex_data) != nullptr) {
477     LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
478     return false;
479   }
480 
481   if (oat_dex_files_.empty()) {
482     LOG(ERROR) << "No dex files in vdex file created from " << location;
483     return false;
484   }
485   return true;
486 }
487 
488 // Add dex file source from raw memory.
AddRawDexFileSource(const ArrayRef<const uint8_t> & data,const char * location,uint32_t location_checksum,CreateTypeLookupTable create_type_lookup_table)489 bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
490                                     const char* location,
491                                     uint32_t location_checksum,
492                                     CreateTypeLookupTable create_type_lookup_table) {
493   DCHECK(write_state_ == WriteState::kAddingDexFileSources);
494   if (data.size() < sizeof(DexFile::Header)) {
495     LOG(ERROR) << "Provided data is shorter than dex file header. size: "
496                << data.size() << " File: " << location;
497     return false;
498   }
499   if (!ValidateDexFileHeader(data.data(), location)) {
500     return false;
501   }
502   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(data.data());
503   if (data.size() < header->file_size_) {
504     LOG(ERROR) << "Truncated dex file data. Data size: " << data.size()
505                << " file size from header: " << header->file_size_ << " File: " << location;
506     return false;
507   }
508 
509   oat_dex_files_.emplace_back(location, DexFileSource(data.data()), create_type_lookup_table);
510   oat_dex_files_.back().dex_file_location_checksum_ = location_checksum;
511   return true;
512 }
513 
GetSourceLocations() const514 dchecked_vector<std::string> OatWriter::GetSourceLocations() const {
515   dchecked_vector<std::string> locations;
516   locations.reserve(oat_dex_files_.size());
517   for (const OatDexFile& oat_dex_file : oat_dex_files_) {
518     locations.push_back(oat_dex_file.GetLocation());
519   }
520   return locations;
521 }
522 
MayHaveCompiledMethods() const523 bool OatWriter::MayHaveCompiledMethods() const {
524   return CompilerFilter::IsAnyCompilationEnabled(
525       GetCompilerDriver()->GetCompilerOptions().GetCompilerFilter());
526 }
527 
WriteAndOpenDexFiles(File * vdex_file,OutputStream * oat_rodata,InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,SafeMap<std::string,std::string> * key_value_store,bool verify,bool update_input_vdex,std::unique_ptr<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)528 bool OatWriter::WriteAndOpenDexFiles(
529     File* vdex_file,
530     OutputStream* oat_rodata,
531     InstructionSet instruction_set,
532     const InstructionSetFeatures* instruction_set_features,
533     SafeMap<std::string, std::string>* key_value_store,
534     bool verify,
535     bool update_input_vdex,
536     /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
537     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
538   CHECK(write_state_ == WriteState::kAddingDexFileSources);
539 
540   // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
541   if (!RecordOatDataOffset(oat_rodata)) {
542      return false;
543   }
544 
545   std::unique_ptr<MemMap> dex_files_map;
546   std::vector<std::unique_ptr<const DexFile>> dex_files;
547 
548   // Initialize VDEX and OAT headers.
549   if (kIsVdexEnabled) {
550     // Reserve space for Vdex header and checksums.
551     vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
552   }
553   oat_size_ = InitOatHeader(instruction_set,
554                             instruction_set_features,
555                             dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
556                             key_value_store);
557 
558   ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
559 
560   if (kIsVdexEnabled) {
561     std::unique_ptr<BufferedOutputStream> vdex_out =
562         std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
563     // Write DEX files into VDEX, mmap and open them.
564     if (!WriteDexFiles(vdex_out.get(), vdex_file, update_input_vdex) ||
565         !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
566       return false;
567     }
568   } else {
569     DCHECK(!update_input_vdex);
570     // Write DEX files into OAT, mmap and open them.
571     if (!WriteDexFiles(oat_rodata, vdex_file, update_input_vdex) ||
572         !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
573       return false;
574     }
575 
576     // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
577     // difficult because we're not using the OutputStream directly.
578     if (!oat_dex_files_.empty()) {
579       size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
580       oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
581     }
582   }
583 
584   // Write type lookup tables into the oat file.
585   if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
586     return false;
587   }
588 
589   // Write dex layout sections into the oat file.
590   if (!WriteDexLayoutSections(&checksum_updating_rodata, dex_files)) {
591     return false;
592   }
593 
594   *opened_dex_files_map = std::move(dex_files_map);
595   *opened_dex_files = std::move(dex_files);
596   write_state_ = WriteState::kPrepareLayout;
597   return true;
598 }
599 
PrepareLayout(linker::MultiOatRelativePatcher * relative_patcher)600 void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) {
601   CHECK(write_state_ == WriteState::kPrepareLayout);
602 
603   relative_patcher_ = relative_patcher;
604   SetMultiOatRelativePatcherAdjustment();
605 
606   if (compiling_boot_image_) {
607     CHECK(image_writer_ != nullptr);
608   }
609   InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
610   CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
611 
612   {
613     TimingLogger::ScopedTiming split("InitBssLayout", timings_);
614     InitBssLayout(instruction_set);
615   }
616 
617   uint32_t offset = oat_size_;
618   {
619     TimingLogger::ScopedTiming split("InitClassOffsets", timings_);
620     offset = InitClassOffsets(offset);
621   }
622   {
623     TimingLogger::ScopedTiming split("InitOatClasses", timings_);
624     offset = InitOatClasses(offset);
625   }
626   {
627     TimingLogger::ScopedTiming split("InitMethodBssMappings", timings_);
628     offset = InitMethodBssMappings(offset);
629   }
630   {
631     TimingLogger::ScopedTiming split("InitOatMaps", timings_);
632     offset = InitOatMaps(offset);
633   }
634   {
635     TimingLogger::ScopedTiming split("InitOatDexFiles", timings_);
636     oat_header_->SetOatDexFilesOffset(offset);
637     offset = InitOatDexFiles(offset);
638   }
639   {
640     TimingLogger::ScopedTiming split("InitOatCode", timings_);
641     offset = InitOatCode(offset);
642   }
643   {
644     TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
645     offset = InitOatCodeDexFiles(offset);
646   }
647   oat_size_ = offset;
648   bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u;
649 
650   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
651   if (compiling_boot_image_) {
652     CHECK_EQ(image_writer_ != nullptr,
653              oat_header_->GetStoreValueByKey(OatHeader::kImageLocationKey) == nullptr);
654   }
655 
656   write_state_ = WriteState::kWriteRoData;
657 }
658 
~OatWriter()659 OatWriter::~OatWriter() {
660 }
661 
662 class OatWriter::DexMethodVisitor {
663  public:
DexMethodVisitor(OatWriter * writer,size_t offset)664   DexMethodVisitor(OatWriter* writer, size_t offset)
665       : writer_(writer),
666         offset_(offset),
667         dex_file_(nullptr),
668         class_def_index_(DexFile::kDexNoIndex) {}
669 
StartClass(const DexFile * dex_file,size_t class_def_index)670   virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
671     DCHECK(dex_file_ == nullptr);
672     DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
673     dex_file_ = dex_file;
674     class_def_index_ = class_def_index;
675     return true;
676   }
677 
678   virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
679 
EndClass()680   virtual bool EndClass() {
681     if (kIsDebugBuild) {
682       dex_file_ = nullptr;
683       class_def_index_ = DexFile::kDexNoIndex;
684     }
685     return true;
686   }
687 
GetOffset() const688   size_t GetOffset() const {
689     return offset_;
690   }
691 
692  protected:
~DexMethodVisitor()693   virtual ~DexMethodVisitor() { }
694 
695   OatWriter* const writer_;
696 
697   // The offset is usually advanced for each visited method by the derived class.
698   size_t offset_;
699 
700   // The dex file and class def index are set in StartClass().
701   const DexFile* dex_file_;
702   size_t class_def_index_;
703 };
704 
705 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
706  public:
OatDexMethodVisitor(OatWriter * writer,size_t offset)707   OatDexMethodVisitor(OatWriter* writer, size_t offset)
708       : DexMethodVisitor(writer, offset),
709         oat_class_index_(0u),
710         method_offsets_index_(0u) {}
711 
StartClass(const DexFile * dex_file,size_t class_def_index)712   bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
713     DexMethodVisitor::StartClass(dex_file, class_def_index);
714     if (kIsDebugBuild && writer_->MayHaveCompiledMethods()) {
715       // There are no oat classes if there aren't any compiled methods.
716       CHECK_LT(oat_class_index_, writer_->oat_classes_.size());
717     }
718     method_offsets_index_ = 0u;
719     return true;
720   }
721 
EndClass()722   bool EndClass() OVERRIDE {
723     ++oat_class_index_;
724     return DexMethodVisitor::EndClass();
725   }
726 
727  protected:
728   size_t oat_class_index_;
729   size_t method_offsets_index_;
730 };
731 
HasCompiledCode(const CompiledMethod * method)732 static bool HasCompiledCode(const CompiledMethod* method) {
733   // The dextodexcompiler puts the quickening info table into the CompiledMethod
734   // for simplicity. For such methods, we will emit an OatQuickMethodHeader
735   // only when vdex is disabled.
736   return method != nullptr && (!method->GetQuickCode().empty() || !kIsVdexEnabled);
737 }
738 
HasQuickeningInfo(const CompiledMethod * method)739 static bool HasQuickeningInfo(const CompiledMethod* method) {
740   return method != nullptr && method->GetQuickCode().empty() && !method->GetVmapTable().empty();
741 }
742 
743 class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
744  public:
InitBssLayoutMethodVisitor(OatWriter * writer)745   explicit InitBssLayoutMethodVisitor(OatWriter* writer)
746       : DexMethodVisitor(writer, /* offset */ 0u) {}
747 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)748   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
749                    const ClassDataItemIterator& it) OVERRIDE {
750     // Look for patches with .bss references and prepare maps with placeholders for their offsets.
751     CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod(
752         MethodReference(dex_file_, it.GetMemberIndex()));
753     if (HasCompiledCode(compiled_method)) {
754       for (const LinkerPatch& patch : compiled_method->GetPatches()) {
755         if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) {
756           MethodReference target_method = patch.TargetMethod();
757           auto refs_it = writer_->bss_method_entry_references_.find(target_method.dex_file);
758           if (refs_it == writer_->bss_method_entry_references_.end()) {
759             refs_it = writer_->bss_method_entry_references_.Put(
760                 target_method.dex_file,
761                 BitVector(target_method.dex_file->NumMethodIds(),
762                           /* expandable */ false,
763                           Allocator::GetMallocAllocator()));
764             refs_it->second.ClearAllBits();
765           }
766           refs_it->second.SetBit(target_method.dex_method_index);
767           writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u);
768         } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) {
769           TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
770           writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u);
771         } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
772           StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
773           writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
774         }
775       }
776     } else {
777       DCHECK(compiled_method == nullptr || compiled_method->GetPatches().empty());
778     }
779     return true;
780   }
781 };
782 
783 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
784  public:
InitOatClassesMethodVisitor(OatWriter * writer,size_t offset)785   InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
786       : DexMethodVisitor(writer, offset),
787         compiled_methods_(),
788         compiled_methods_with_code_(0u) {
789     size_t num_classes = 0u;
790     for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) {
791       num_classes += oat_dex_file.class_offsets_.size();
792     }
793     // If we aren't compiling only reserve headers.
794     writer_->oat_class_headers_.reserve(num_classes);
795     if (writer->MayHaveCompiledMethods()) {
796       writer->oat_classes_.reserve(num_classes);
797     }
798     compiled_methods_.reserve(256u);
799     // If there are any classes, the class offsets allocation aligns the offset.
800     DCHECK(num_classes == 0u || IsAligned<4u>(offset));
801   }
802 
StartClass(const DexFile * dex_file,size_t class_def_index)803   bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE {
804     DexMethodVisitor::StartClass(dex_file, class_def_index);
805     compiled_methods_.clear();
806     compiled_methods_with_code_ = 0u;
807     return true;
808   }
809 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)810   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,
811                    const ClassDataItemIterator& it) OVERRIDE {
812     // Fill in the compiled_methods_ array for methods that have a
813     // CompiledMethod. We track the number of non-null entries in
814     // compiled_methods_with_code_ since we only want to allocate
815     // OatMethodOffsets for the compiled methods.
816     uint32_t method_idx = it.GetMemberIndex();
817     CompiledMethod* compiled_method =
818         writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
819     compiled_methods_.push_back(compiled_method);
820     if (HasCompiledCode(compiled_method)) {
821       ++compiled_methods_with_code_;
822     }
823     return true;
824   }
825 
EndClass()826   bool EndClass() OVERRIDE {
827     ClassReference class_ref(dex_file_, class_def_index_);
828     mirror::Class::Status status;
829     bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status);
830     if (!found) {
831       VerificationResults* results = writer_->compiler_driver_->GetVerificationResults();
832       if (results != nullptr && results->IsClassRejected(class_ref)) {
833         // The oat class status is used only for verification of resolved classes,
834         // so use kStatusErrorResolved whether the class was resolved or unresolved
835         // during compile-time verification.
836         status = mirror::Class::kStatusErrorResolved;
837       } else {
838         status = mirror::Class::kStatusNotReady;
839       }
840     }
841 
842     writer_->oat_class_headers_.emplace_back(offset_,
843                                              compiled_methods_with_code_,
844                                              compiled_methods_.size(),
845                                              status);
846     OatClassHeader& header = writer_->oat_class_headers_.back();
847     offset_ += header.SizeOf();
848     if (writer_->MayHaveCompiledMethods()) {
849       writer_->oat_classes_.emplace_back(compiled_methods_,
850                                          compiled_methods_with_code_,
851                                          header.type_);
852       offset_ += writer_->oat_classes_.back().SizeOf();
853     }
854     return DexMethodVisitor::EndClass();
855   }
856 
857  private:
858   dchecked_vector<CompiledMethod*> compiled_methods_;
859   size_t compiled_methods_with_code_;
860 };
861 
862 class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
863  public:
InitCodeMethodVisitor(OatWriter * writer,size_t offset)864   InitCodeMethodVisitor(OatWriter* writer, size_t offset)
865       : OatDexMethodVisitor(writer, offset),
866         debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) {
867     writer_->absolute_patch_locations_.reserve(
868         writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
869   }
870 
EndClass()871   bool EndClass() OVERRIDE {
872     OatDexMethodVisitor::EndClass();
873     if (oat_class_index_ == writer_->oat_classes_.size()) {
874       offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
875     }
876     return true;
877   }
878 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)879   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
880       REQUIRES_SHARED(Locks::mutator_lock_) {
881     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
882     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
883 
884     if (HasCompiledCode(compiled_method)) {
885       // Derived from CompiledMethod.
886       uint32_t quick_code_offset = 0;
887 
888       ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
889       uint32_t code_size = quick_code.size() * sizeof(uint8_t);
890       uint32_t thumb_offset = compiled_method->CodeDelta();
891 
892       // Deduplicate code arrays if we are not producing debuggable code.
893       bool deduped = true;
894       MethodReference method_ref(dex_file_, it.GetMemberIndex());
895       if (debuggable_) {
896         quick_code_offset = writer_->relative_patcher_->GetOffset(method_ref);
897         if (quick_code_offset != 0u) {
898           // Duplicate methods, we want the same code for both of them so that the oat writer puts
899           // the same code in both ArtMethods so that we do not get different oat code at runtime.
900         } else {
901           quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
902           deduped = false;
903         }
904       } else {
905         quick_code_offset = dedupe_map_.GetOrCreate(
906             compiled_method,
907             [this, &deduped, compiled_method, &it, thumb_offset]() {
908               deduped = false;
909               return NewQuickCodeOffset(compiled_method, it, thumb_offset);
910             });
911       }
912 
913       if (code_size != 0) {
914         if (writer_->relative_patcher_->GetOffset(method_ref) != 0u) {
915           // TODO: Should this be a hard failure?
916           LOG(WARNING) << "Multiple definitions of "
917               << method_ref.dex_file->PrettyMethod(method_ref.dex_method_index)
918               << " offsets " << writer_->relative_patcher_->GetOffset(method_ref)
919               << " " << quick_code_offset;
920         } else {
921           writer_->relative_patcher_->SetOffset(method_ref, quick_code_offset);
922         }
923       }
924 
925       // Update quick method header.
926       DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
927       OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
928       uint32_t vmap_table_offset = method_header->GetVmapTableOffset();
929       uint32_t method_info_offset = method_header->GetMethodInfoOffset();
930       // The code offset was 0 when the mapping/vmap table offset was set, so it's set
931       // to 0-offset and we need to adjust it by code_offset.
932       uint32_t code_offset = quick_code_offset - thumb_offset;
933       if (!compiled_method->GetQuickCode().empty()) {
934         // If the code is compiled, we write the offset of the stack map relative
935         // to the code,
936         if (vmap_table_offset != 0u) {
937           vmap_table_offset += code_offset;
938           DCHECK_LT(vmap_table_offset, code_offset);
939         }
940         if (method_info_offset != 0u) {
941           method_info_offset += code_offset;
942           DCHECK_LT(method_info_offset, code_offset);
943         }
944       } else {
945         CHECK(!kIsVdexEnabled);
946         // We write the offset of the quickening info relative to the code.
947         vmap_table_offset += code_offset;
948         DCHECK_LT(vmap_table_offset, code_offset);
949       }
950       uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
951       uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
952       uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
953       *method_header = OatQuickMethodHeader(vmap_table_offset,
954                                             method_info_offset,
955                                             frame_size_in_bytes,
956                                             core_spill_mask,
957                                             fp_spill_mask,
958                                             code_size);
959 
960       if (!deduped) {
961         // Update offsets. (Checksum is updated when writing.)
962         offset_ += sizeof(*method_header);  // Method header is prepended before code.
963         offset_ += code_size;
964         // Record absolute patch locations.
965         if (!compiled_method->GetPatches().empty()) {
966           uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
967           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
968             if (!patch.IsPcRelative()) {
969               writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
970             }
971           }
972         }
973       }
974 
975       const CompilerOptions& compiler_options = writer_->compiler_driver_->GetCompilerOptions();
976       // Exclude quickened dex methods (code_size == 0) since they have no native code.
977       if (compiler_options.GenerateAnyDebugInfo() && code_size != 0) {
978         bool has_code_info = method_header->IsOptimized();
979         // Record debug information for this function if we are doing that.
980         debug::MethodDebugInfo info = debug::MethodDebugInfo();
981         info.trampoline_name = nullptr;
982         info.dex_file = dex_file_;
983         info.class_def_index = class_def_index_;
984         info.dex_method_index = it.GetMemberIndex();
985         info.access_flags = it.GetMethodAccessFlags();
986         info.code_item = it.GetMethodCodeItem();
987         info.isa = compiled_method->GetInstructionSet();
988         info.deduped = deduped;
989         info.is_native_debuggable = compiler_options.GetNativeDebuggable();
990         info.is_optimized = method_header->IsOptimized();
991         info.is_code_address_text_relative = true;
992         info.code_address = code_offset - writer_->oat_header_->GetExecutableOffset();
993         info.code_size = code_size;
994         info.frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
995         info.code_info = has_code_info ? compiled_method->GetVmapTable().data() : nullptr;
996         info.cfi = compiled_method->GetCFIInfo();
997         writer_->method_info_.push_back(info);
998       }
999 
1000       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1001       OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
1002       offsets->code_offset_ = quick_code_offset;
1003       ++method_offsets_index_;
1004     }
1005 
1006     return true;
1007   }
1008 
1009  private:
1010   struct CodeOffsetsKeyComparator {
operator ()art::OatWriter::InitCodeMethodVisitor::CodeOffsetsKeyComparator1011     bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
1012       // Code is deduplicated by CompilerDriver, compare only data pointers.
1013       if (lhs->GetQuickCode().data() != rhs->GetQuickCode().data()) {
1014         return lhs->GetQuickCode().data() < rhs->GetQuickCode().data();
1015       }
1016       // If the code is the same, all other fields are likely to be the same as well.
1017       if (UNLIKELY(lhs->GetVmapTable().data() != rhs->GetVmapTable().data())) {
1018         return lhs->GetVmapTable().data() < rhs->GetVmapTable().data();
1019       }
1020       if (UNLIKELY(lhs->GetMethodInfo().data() != rhs->GetMethodInfo().data())) {
1021         return lhs->GetMethodInfo().data() < rhs->GetMethodInfo().data();
1022       }
1023       if (UNLIKELY(lhs->GetPatches().data() != rhs->GetPatches().data())) {
1024         return lhs->GetPatches().data() < rhs->GetPatches().data();
1025       }
1026       return false;
1027     }
1028   };
1029 
NewQuickCodeOffset(CompiledMethod * compiled_method,const ClassDataItemIterator & it,uint32_t thumb_offset)1030   uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
1031                               const ClassDataItemIterator& it,
1032                               uint32_t thumb_offset) {
1033     offset_ = writer_->relative_patcher_->ReserveSpace(
1034         offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
1035     offset_ += CodeAlignmentSize(offset_, *compiled_method);
1036     DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1037                          GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1038     return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
1039   }
1040 
1041   // Deduplication is already done on a pointer basis by the compiler driver,
1042   // so we can simply compare the pointers to find out if things are duplicated.
1043   SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
1044 
1045   // Cache of compiler's --debuggable option.
1046   const bool debuggable_;
1047 };
1048 
1049 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
1050  public:
InitMapMethodVisitor(OatWriter * writer,size_t offset)1051   InitMapMethodVisitor(OatWriter* writer, size_t offset)
1052       : OatDexMethodVisitor(writer, offset) {}
1053 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it ATTRIBUTE_UNUSED)1054   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
1055       OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
1056     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1057     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1058 
1059     if (HasCompiledCode(compiled_method)) {
1060       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1061       DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset(), 0u);
1062 
1063       ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1064       uint32_t map_size = map.size() * sizeof(map[0]);
1065       if (map_size != 0u) {
1066         size_t offset = dedupe_map_.GetOrCreate(
1067             map.data(),
1068             [this, map_size]() {
1069               uint32_t new_offset = offset_;
1070               offset_ += map_size;
1071               return new_offset;
1072             });
1073         // Code offset is not initialized yet, so set the map offset to 0u-offset.
1074         DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1075         oat_class->method_headers_[method_offsets_index_].SetVmapTableOffset(0u - offset);
1076       }
1077       ++method_offsets_index_;
1078     }
1079 
1080     return true;
1081   }
1082 
1083  private:
1084   // Deduplication is already done on a pointer basis by the compiler driver,
1085   // so we can simply compare the pointers to find out if things are duplicated.
1086   SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1087 };
1088 
1089 class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor {
1090  public:
InitMethodInfoVisitor(OatWriter * writer,size_t offset)1091   InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {}
1092 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it ATTRIBUTE_UNUSED)1093   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
1094       OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
1095     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1096     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1097 
1098     if (HasCompiledCode(compiled_method)) {
1099       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1100       DCHECK_EQ(oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset(), 0u);
1101       ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1102       const uint32_t map_size = map.size() * sizeof(map[0]);
1103       if (map_size != 0u) {
1104         size_t offset = dedupe_map_.GetOrCreate(
1105             map.data(),
1106             [this, map_size]() {
1107               uint32_t new_offset = offset_;
1108               offset_ += map_size;
1109               return new_offset;
1110             });
1111         // Code offset is not initialized yet, so set the map offset to 0u-offset.
1112         DCHECK_EQ(oat_class->method_offsets_[method_offsets_index_].code_offset_, 0u);
1113         oat_class->method_headers_[method_offsets_index_].SetMethodInfoOffset(0u - offset);
1114       }
1115       ++method_offsets_index_;
1116     }
1117 
1118     return true;
1119   }
1120 
1121  private:
1122   // Deduplication is already done on a pointer basis by the compiler driver,
1123   // so we can simply compare the pointers to find out if things are duplicated.
1124   SafeMap<const uint8_t*, uint32_t> dedupe_map_;
1125 };
1126 
1127 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
1128  public:
InitImageMethodVisitor(OatWriter * writer,size_t offset,const std::vector<const DexFile * > * dex_files)1129   InitImageMethodVisitor(OatWriter* writer,
1130                          size_t offset,
1131                          const std::vector<const DexFile*>* dex_files)
1132       : OatDexMethodVisitor(writer, offset),
1133         pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1134         class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1135         dex_files_(dex_files),
1136         class_linker_(Runtime::Current()->GetClassLinker()) {}
1137 
1138   // Handle copied methods here. Copy pointer to quick code from
1139   // an origin method to a copied method only if they are
1140   // in the same oat file. If the origin and the copied methods are
1141   // in different oat files don't touch the copied method.
1142   // References to other oat files are not supported yet.
StartClass(const DexFile * dex_file,size_t class_def_index)1143   bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
1144       REQUIRES_SHARED(Locks::mutator_lock_) {
1145     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1146     // Skip classes that are not in the image.
1147     if (!IsImageClass()) {
1148       return true;
1149     }
1150     ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1151     const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1152     mirror::Class* klass = dex_cache->GetResolvedType(class_def.class_idx_);
1153     if (klass != nullptr) {
1154       for (ArtMethod& method : klass->GetCopiedMethods(pointer_size_)) {
1155         // Find origin method. Declaring class and dex_method_idx
1156         // in the copied method should be the same as in the origin
1157         // method.
1158         mirror::Class* declaring_class = method.GetDeclaringClass();
1159         ArtMethod* origin = declaring_class->FindClassMethod(
1160             declaring_class->GetDexCache(),
1161             method.GetDexMethodIndex(),
1162             pointer_size_);
1163         CHECK(origin != nullptr);
1164         CHECK(!origin->IsDirect());
1165         CHECK(origin->GetDeclaringClass() == declaring_class);
1166         if (IsInOatFile(&declaring_class->GetDexFile())) {
1167           const void* code_ptr =
1168               origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1169           if (code_ptr == nullptr) {
1170             methods_to_process_.push_back(std::make_pair(&method, origin));
1171           } else {
1172             method.SetEntryPointFromQuickCompiledCodePtrSize(
1173                 code_ptr, pointer_size_);
1174           }
1175         }
1176       }
1177     }
1178     return true;
1179   }
1180 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1181   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
1182       REQUIRES_SHARED(Locks::mutator_lock_) {
1183     // Skip methods that are not in the image.
1184     if (!IsImageClass()) {
1185       return true;
1186     }
1187 
1188     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1189     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1190 
1191     OatMethodOffsets offsets(0u);
1192     if (HasCompiledCode(compiled_method)) {
1193       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
1194       offsets = oat_class->method_offsets_[method_offsets_index_];
1195       ++method_offsets_index_;
1196     }
1197 
1198     Thread* self = Thread::Current();
1199     ObjPtr<mirror::DexCache> dex_cache = class_linker_->FindDexCache(self, *dex_file_);
1200     ArtMethod* method;
1201     if (writer_->HasBootImage()) {
1202       const InvokeType invoke_type = it.GetMethodInvokeType(
1203           dex_file_->GetClassDef(class_def_index_));
1204       // Unchecked as we hold mutator_lock_ on entry.
1205       ScopedObjectAccessUnchecked soa(self);
1206       StackHandleScope<1> hs(self);
1207       method = class_linker_->ResolveMethod<ClassLinker::ResolveMode::kNoChecks>(
1208           *dex_file_,
1209           it.GetMemberIndex(),
1210           hs.NewHandle(dex_cache),
1211           ScopedNullHandle<mirror::ClassLoader>(),
1212           nullptr,
1213           invoke_type);
1214       if (method == nullptr) {
1215         LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
1216             << dex_file_->PrettyMethod(it.GetMemberIndex(), true);
1217         self->AssertPendingException();
1218         mirror::Throwable* exc = self->GetException();
1219         std::string dump = exc->Dump();
1220         LOG(FATAL) << dump;
1221         UNREACHABLE();
1222       }
1223     } else {
1224       // Should already have been resolved by the compiler.
1225       // It may not be resolved if the class failed to verify, in this case, don't set the
1226       // entrypoint. This is not fatal since we shall use a resolution method.
1227       method = class_linker_->LookupResolvedMethod(it.GetMemberIndex(), dex_cache, class_loader_);
1228     }
1229     if (method != nullptr &&
1230         compiled_method != nullptr &&
1231         compiled_method->GetQuickCode().size() != 0) {
1232       method->SetEntryPointFromQuickCompiledCodePtrSize(
1233           reinterpret_cast<void*>(offsets.code_offset_), pointer_size_);
1234     }
1235 
1236     return true;
1237   }
1238 
1239   // Check whether current class is image class
IsImageClass()1240   bool IsImageClass() {
1241     const DexFile::TypeId& type_id =
1242         dex_file_->GetTypeId(dex_file_->GetClassDef(class_def_index_).class_idx_);
1243     const char* class_descriptor = dex_file_->GetTypeDescriptor(type_id);
1244     return writer_->GetCompilerDriver()->IsImageClass(class_descriptor);
1245   }
1246 
1247   // Check whether specified dex file is in the compiled oat file.
IsInOatFile(const DexFile * dex_file)1248   bool IsInOatFile(const DexFile* dex_file) {
1249     return ContainsElement(*dex_files_, dex_file);
1250   }
1251 
1252   // Assign a pointer to quick code for copied methods
1253   // not handled in the method StartClass
Postprocess()1254   void Postprocess() {
1255     for (std::pair<ArtMethod*, ArtMethod*>& p : methods_to_process_) {
1256       ArtMethod* method = p.first;
1257       ArtMethod* origin = p.second;
1258       const void* code_ptr =
1259           origin->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1260       if (code_ptr != nullptr) {
1261         method->SetEntryPointFromQuickCompiledCodePtrSize(code_ptr, pointer_size_);
1262       }
1263     }
1264   }
1265 
1266  private:
1267   const PointerSize pointer_size_;
1268   ObjPtr<mirror::ClassLoader> class_loader_;
1269   const std::vector<const DexFile*>* dex_files_;
1270   ClassLinker* const class_linker_;
1271   std::vector<std::pair<ArtMethod*, ArtMethod*>> methods_to_process_;
1272 };
1273 
1274 class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
1275  public:
WriteCodeMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1276   WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
1277                          size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
1278       : OatDexMethodVisitor(writer, relative_offset),
1279         pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())),
1280         class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr),
1281         out_(out),
1282         file_offset_(file_offset),
1283         soa_(Thread::Current()),
1284         no_thread_suspension_("OatWriter patching"),
1285         class_linker_(Runtime::Current()->GetClassLinker()),
1286         dex_cache_(nullptr) {
1287     patched_code_.reserve(16 * KB);
1288     if (writer_->HasBootImage()) {
1289       // If we're creating the image, the address space must be ready so that we can apply patches.
1290       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
1291     }
1292   }
1293 
UNLOCK_FUNCTION(Locks::mutator_lock_)1294   ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
1295   }
1296 
StartClass(const DexFile * dex_file,size_t class_def_index)1297   bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE
1298       REQUIRES_SHARED(Locks::mutator_lock_) {
1299     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
1300     if (writer_->GetCompilerDriver()->GetCompilerOptions().IsAotCompilationEnabled()) {
1301       // Only need to set the dex cache if we have compilation. Other modes might have unloaded it.
1302       if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
1303         dex_cache_ = class_linker_->FindDexCache(Thread::Current(), *dex_file);
1304         DCHECK(dex_cache_ != nullptr);
1305       }
1306     }
1307     return true;
1308   }
1309 
EndClass()1310   bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
1311     bool result = OatDexMethodVisitor::EndClass();
1312     if (oat_class_index_ == writer_->oat_classes_.size()) {
1313       DCHECK(result);  // OatDexMethodVisitor::EndClass() never fails.
1314       offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
1315       if (UNLIKELY(offset_ == 0u)) {
1316         PLOG(ERROR) << "Failed to write final relative call thunks";
1317         result = false;
1318       }
1319     }
1320     return result;
1321   }
1322 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1323   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE
1324       REQUIRES_SHARED(Locks::mutator_lock_) {
1325     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1326     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1327 
1328     // No thread suspension since dex_cache_ that may get invalidated if that occurs.
1329     ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
1330     if (HasCompiledCode(compiled_method)) {
1331       size_t file_offset = file_offset_;
1332       OutputStream* out = out_;
1333 
1334       ArrayRef<const uint8_t> quick_code = compiled_method->GetQuickCode();
1335       uint32_t code_size = quick_code.size() * sizeof(uint8_t);
1336 
1337       // Deduplicate code arrays.
1338       const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
1339       if (method_offsets.code_offset_ > offset_) {
1340         offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
1341         if (offset_ == 0u) {
1342           ReportWriteFailure("relative call thunk", it);
1343           return false;
1344         }
1345         uint32_t alignment_size = CodeAlignmentSize(offset_, *compiled_method);
1346         if (alignment_size != 0) {
1347           if (!writer_->WriteCodeAlignment(out, alignment_size)) {
1348             ReportWriteFailure("code alignment padding", it);
1349             return false;
1350           }
1351           offset_ += alignment_size;
1352           DCHECK_OFFSET_();
1353         }
1354         DCHECK_ALIGNED_PARAM(offset_ + sizeof(OatQuickMethodHeader),
1355                              GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
1356         DCHECK_EQ(method_offsets.code_offset_,
1357                   offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
1358             << dex_file_->PrettyMethod(it.GetMemberIndex());
1359         const OatQuickMethodHeader& method_header =
1360             oat_class->method_headers_[method_offsets_index_];
1361         if (!out->WriteFully(&method_header, sizeof(method_header))) {
1362           ReportWriteFailure("method header", it);
1363           return false;
1364         }
1365         writer_->size_method_header_ += sizeof(method_header);
1366         offset_ += sizeof(method_header);
1367         DCHECK_OFFSET_();
1368 
1369         if (!compiled_method->GetPatches().empty()) {
1370           patched_code_.assign(quick_code.begin(), quick_code.end());
1371           quick_code = ArrayRef<const uint8_t>(patched_code_);
1372           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
1373             uint32_t literal_offset = patch.LiteralOffset();
1374             switch (patch.GetType()) {
1375               case LinkerPatch::Type::kMethodBssEntry: {
1376                 uint32_t target_offset =
1377                     writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod());
1378                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1379                                                                      patch,
1380                                                                      offset_ + literal_offset,
1381                                                                      target_offset);
1382                 break;
1383               }
1384               case LinkerPatch::Type::kCallRelative: {
1385                 // NOTE: Relative calls across oat files are not supported.
1386                 uint32_t target_offset = GetTargetOffset(patch);
1387                 writer_->relative_patcher_->PatchCall(&patched_code_,
1388                                                       literal_offset,
1389                                                       offset_ + literal_offset,
1390                                                       target_offset);
1391                 break;
1392               }
1393               case LinkerPatch::Type::kStringRelative: {
1394                 uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch));
1395                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1396                                                                      patch,
1397                                                                      offset_ + literal_offset,
1398                                                                      target_offset);
1399                 break;
1400               }
1401               case LinkerPatch::Type::kStringBssEntry: {
1402                 StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
1403                 uint32_t target_offset =
1404                     writer_->bss_start_ + writer_->bss_string_entries_.Get(ref);
1405                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1406                                                                      patch,
1407                                                                      offset_ + literal_offset,
1408                                                                      target_offset);
1409                 break;
1410               }
1411               case LinkerPatch::Type::kTypeRelative: {
1412                 uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
1413                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1414                                                                      patch,
1415                                                                      offset_ + literal_offset,
1416                                                                      target_offset);
1417                 break;
1418               }
1419               case LinkerPatch::Type::kTypeBssEntry: {
1420                 TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex());
1421                 uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref);
1422                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1423                                                                      patch,
1424                                                                      offset_ + literal_offset,
1425                                                                      target_offset);
1426                 break;
1427               }
1428               case LinkerPatch::Type::kCall: {
1429                 uint32_t target_offset = GetTargetOffset(patch);
1430                 PatchCodeAddress(&patched_code_, literal_offset, target_offset);
1431                 break;
1432               }
1433               case LinkerPatch::Type::kMethodRelative: {
1434                 uint32_t target_offset = GetTargetMethodOffset(GetTargetMethod(patch));
1435                 writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
1436                                                                      patch,
1437                                                                      offset_ + literal_offset,
1438                                                                      target_offset);
1439                 break;
1440               }
1441               case LinkerPatch::Type::kBakerReadBarrierBranch: {
1442                 writer_->relative_patcher_->PatchBakerReadBarrierBranch(&patched_code_,
1443                                                                         patch,
1444                                                                         offset_ + literal_offset);
1445                 break;
1446               }
1447               default: {
1448                 DCHECK(false) << "Unexpected linker patch type: " << patch.GetType();
1449                 break;
1450               }
1451             }
1452           }
1453         }
1454 
1455         if (!out->WriteFully(quick_code.data(), code_size)) {
1456           ReportWriteFailure("method code", it);
1457           return false;
1458         }
1459         writer_->size_code_ += code_size;
1460         offset_ += code_size;
1461       }
1462       DCHECK_OFFSET_();
1463       ++method_offsets_index_;
1464     }
1465 
1466     return true;
1467   }
1468 
1469  private:
1470   const PointerSize pointer_size_;
1471   ObjPtr<mirror::ClassLoader> class_loader_;
1472   OutputStream* const out_;
1473   const size_t file_offset_;
1474   const ScopedObjectAccess soa_;
1475   const ScopedAssertNoThreadSuspension no_thread_suspension_;
1476   ClassLinker* const class_linker_;
1477   ObjPtr<mirror::DexCache> dex_cache_;
1478   std::vector<uint8_t> patched_code_;
1479 
ReportWriteFailure(const char * what,const ClassDataItemIterator & it)1480   void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
1481     PLOG(ERROR) << "Failed to write " << what << " for "
1482         << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1483   }
1484 
GetTargetMethod(const LinkerPatch & patch)1485   ArtMethod* GetTargetMethod(const LinkerPatch& patch)
1486       REQUIRES_SHARED(Locks::mutator_lock_) {
1487     MethodReference ref = patch.TargetMethod();
1488     ObjPtr<mirror::DexCache> dex_cache =
1489         (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(
1490             Thread::Current(), *ref.dex_file);
1491     ArtMethod* method =
1492         class_linker_->LookupResolvedMethod(ref.dex_method_index, dex_cache, class_loader_);
1493     CHECK(method != nullptr);
1494     return method;
1495   }
1496 
GetTargetOffset(const LinkerPatch & patch)1497   uint32_t GetTargetOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1498     uint32_t target_offset = writer_->relative_patcher_->GetOffset(patch.TargetMethod());
1499     // If there's no new compiled code, either we're compiling an app and the target method
1500     // is in the boot image, or we need to point to the correct trampoline.
1501     if (UNLIKELY(target_offset == 0)) {
1502       ArtMethod* target = GetTargetMethod(patch);
1503       DCHECK(target != nullptr);
1504       const void* oat_code_offset =
1505           target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_);
1506       if (oat_code_offset != 0) {
1507         DCHECK(!writer_->HasBootImage());
1508         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
1509         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
1510         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
1511         target_offset = PointerToLowMemUInt32(oat_code_offset);
1512       } else {
1513         target_offset = target->IsNative()
1514             ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
1515             : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
1516       }
1517     }
1518     return target_offset;
1519   }
1520 
GetDexCache(const DexFile * target_dex_file)1521   ObjPtr<mirror::DexCache> GetDexCache(const DexFile* target_dex_file)
1522       REQUIRES_SHARED(Locks::mutator_lock_) {
1523     return (target_dex_file == dex_file_)
1524         ? dex_cache_
1525         : class_linker_->FindDexCache(Thread::Current(), *target_dex_file);
1526   }
1527 
GetTargetType(const LinkerPatch & patch)1528   mirror::Class* GetTargetType(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1529     DCHECK(writer_->HasImage());
1530     ObjPtr<mirror::DexCache> dex_cache = GetDexCache(patch.TargetTypeDexFile());
1531     ObjPtr<mirror::Class> type =
1532         ClassLinker::LookupResolvedType(patch.TargetTypeIndex(), dex_cache, class_loader_);
1533     CHECK(type != nullptr);
1534     return type.Ptr();
1535   }
1536 
GetTargetString(const LinkerPatch & patch)1537   mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
1538     ScopedObjectAccessUnchecked soa(Thread::Current());
1539     ClassLinker* linker = Runtime::Current()->GetClassLinker();
1540     mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
1541                                                   patch.TargetStringIndex(),
1542                                                   GetDexCache(patch.TargetStringDexFile()));
1543     DCHECK(string != nullptr);
1544     DCHECK(writer_->HasBootImage() ||
1545            Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(string));
1546     return string;
1547   }
1548 
GetTargetMethodOffset(ArtMethod * method)1549   uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
1550     DCHECK(writer_->HasBootImage());
1551     method = writer_->image_writer_->GetImageMethodAddress(method);
1552     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1553     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1554     // TODO: Clean up offset types. The target offset must be treated as signed.
1555     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method) - oat_data_begin);
1556   }
1557 
GetTargetObjectOffset(mirror::Object * object)1558   uint32_t GetTargetObjectOffset(mirror::Object* object) REQUIRES_SHARED(Locks::mutator_lock_) {
1559     DCHECK(writer_->HasBootImage());
1560     object = writer_->image_writer_->GetImageAddress(object);
1561     size_t oat_index = writer_->image_writer_->GetOatIndexForDexFile(dex_file_);
1562     uintptr_t oat_data_begin = writer_->image_writer_->GetOatDataBegin(oat_index);
1563     // TODO: Clean up offset types. The target offset must be treated as signed.
1564     return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object) - oat_data_begin);
1565   }
1566 
PatchObjectAddress(std::vector<uint8_t> * code,uint32_t offset,mirror::Object * object)1567   void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
1568       REQUIRES_SHARED(Locks::mutator_lock_) {
1569     if (writer_->HasBootImage()) {
1570       object = writer_->image_writer_->GetImageAddress(object);
1571     } else {
1572       // NOTE: We're using linker patches for app->boot references when the image can
1573       // be relocated and therefore we need to emit .oat_patches. We're not using this
1574       // for app->app references, so check that the object is in the image space.
1575       DCHECK(Runtime::Current()->GetHeap()->FindSpaceFromObject(object, false)->IsImageSpace());
1576     }
1577     // Note: We only patch targeting Objects in image which is in the low 4gb.
1578     uint32_t address = PointerToLowMemUInt32(object);
1579     DCHECK_LE(offset + 4, code->size());
1580     uint8_t* data = &(*code)[offset];
1581     data[0] = address & 0xffu;
1582     data[1] = (address >> 8) & 0xffu;
1583     data[2] = (address >> 16) & 0xffu;
1584     data[3] = (address >> 24) & 0xffu;
1585   }
1586 
PatchCodeAddress(std::vector<uint8_t> * code,uint32_t offset,uint32_t target_offset)1587   void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
1588       REQUIRES_SHARED(Locks::mutator_lock_) {
1589     uint32_t address = target_offset;
1590     if (writer_->HasBootImage()) {
1591       size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_);
1592       // TODO: Clean up offset types.
1593       // The target_offset must be treated as signed for cross-oat patching.
1594       const void* target = reinterpret_cast<const void*>(
1595           writer_->image_writer_->GetOatDataBegin(oat_index) +
1596           static_cast<int32_t>(target_offset));
1597       address = PointerToLowMemUInt32(target);
1598     }
1599     DCHECK_LE(offset + 4, code->size());
1600     uint8_t* data = &(*code)[offset];
1601     data[0] = address & 0xffu;
1602     data[1] = (address >> 8) & 0xffu;
1603     data[2] = (address >> 16) & 0xffu;
1604     data[3] = (address >> 24) & 0xffu;
1605   }
1606 };
1607 
1608 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
1609  public:
WriteMapMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1610   WriteMapMethodVisitor(OatWriter* writer,
1611                         OutputStream* out,
1612                         const size_t file_offset,
1613                         size_t relative_offset)
1614       : OatDexMethodVisitor(writer, relative_offset),
1615         out_(out),
1616         file_offset_(file_offset) {}
1617 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1618   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
1619     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1620     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1621 
1622     if (HasCompiledCode(compiled_method)) {
1623       size_t file_offset = file_offset_;
1624       OutputStream* out = out_;
1625 
1626       uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetVmapTableOffset();
1627       uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1628       ++method_offsets_index_;
1629 
1630       DCHECK((compiled_method->GetVmapTable().size() == 0u && map_offset == 0u) ||
1631              (compiled_method->GetVmapTable().size() != 0u && map_offset != 0u))
1632           << compiled_method->GetVmapTable().size() << " " << map_offset << " "
1633           << dex_file_->PrettyMethod(it.GetMemberIndex());
1634 
1635       // If vdex is enabled, only emit the map for compiled code. The quickening info
1636       // is emitted in the vdex already.
1637       if (map_offset != 0u) {
1638         // Transform map_offset to actual oat data offset.
1639         map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1640         DCHECK_NE(map_offset, 0u);
1641         DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1642 
1643         ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
1644         size_t map_size = map.size() * sizeof(map[0]);
1645         if (map_offset == offset_) {
1646           // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1647           if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1648             ReportWriteFailure(it);
1649             return false;
1650           }
1651           offset_ += map_size;
1652         }
1653       }
1654       DCHECK_OFFSET_();
1655     }
1656 
1657     return true;
1658   }
1659 
1660  private:
1661   OutputStream* const out_;
1662   size_t const file_offset_;
1663 
ReportWriteFailure(const ClassDataItemIterator & it)1664   void ReportWriteFailure(const ClassDataItemIterator& it) {
1665     PLOG(ERROR) << "Failed to write map for "
1666         << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1667   }
1668 };
1669 
1670 class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor {
1671  public:
WriteMethodInfoVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)1672   WriteMethodInfoVisitor(OatWriter* writer,
1673                          OutputStream* out,
1674                          const size_t file_offset,
1675                          size_t relative_offset)
1676       : OatDexMethodVisitor(writer, relative_offset),
1677         out_(out),
1678         file_offset_(file_offset) {}
1679 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)1680   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE {
1681     OatClass* oat_class = &writer_->oat_classes_[oat_class_index_];
1682     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
1683 
1684     if (HasCompiledCode(compiled_method)) {
1685       size_t file_offset = file_offset_;
1686       OutputStream* out = out_;
1687       uint32_t map_offset = oat_class->method_headers_[method_offsets_index_].GetMethodInfoOffset();
1688       uint32_t code_offset = oat_class->method_offsets_[method_offsets_index_].code_offset_;
1689       ++method_offsets_index_;
1690       DCHECK((compiled_method->GetMethodInfo().size() == 0u && map_offset == 0u) ||
1691              (compiled_method->GetMethodInfo().size() != 0u && map_offset != 0u))
1692           << compiled_method->GetMethodInfo().size() << " " << map_offset << " "
1693           << dex_file_->PrettyMethod(it.GetMemberIndex());
1694       if (map_offset != 0u) {
1695         // Transform map_offset to actual oat data offset.
1696         map_offset = (code_offset - compiled_method->CodeDelta()) - map_offset;
1697         DCHECK_NE(map_offset, 0u);
1698         DCHECK_LE(map_offset, offset_) << dex_file_->PrettyMethod(it.GetMemberIndex());
1699 
1700         ArrayRef<const uint8_t> map = compiled_method->GetMethodInfo();
1701         size_t map_size = map.size() * sizeof(map[0]);
1702         if (map_offset == offset_) {
1703           // Write deduplicated map (code info for Optimizing or transformation info for dex2dex).
1704           if (UNLIKELY(!out->WriteFully(map.data(), map_size))) {
1705             ReportWriteFailure(it);
1706             return false;
1707           }
1708           offset_ += map_size;
1709         }
1710       }
1711       DCHECK_OFFSET_();
1712     }
1713 
1714     return true;
1715   }
1716 
1717  private:
1718   OutputStream* const out_;
1719   size_t const file_offset_;
1720 
ReportWriteFailure(const ClassDataItemIterator & it)1721   void ReportWriteFailure(const ClassDataItemIterator& it) {
1722     PLOG(ERROR) << "Failed to write map for "
1723         << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to " << out_->GetLocation();
1724   }
1725 };
1726 
1727 // Visit all methods from all classes in all dex files with the specified visitor.
VisitDexMethods(DexMethodVisitor * visitor)1728 bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
1729   for (const DexFile* dex_file : *dex_files_) {
1730     const size_t class_def_count = dex_file->NumClassDefs();
1731     for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
1732       if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
1733         return false;
1734       }
1735       if (MayHaveCompiledMethods()) {
1736         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
1737         const uint8_t* class_data = dex_file->GetClassData(class_def);
1738         if (class_data != nullptr) {  // ie not an empty class, such as a marker interface
1739           ClassDataItemIterator it(*dex_file, class_data);
1740           it.SkipAllFields();
1741           size_t class_def_method_index = 0u;
1742           while (it.HasNextDirectMethod()) {
1743             if (!visitor->VisitMethod(class_def_method_index, it)) {
1744               return false;
1745             }
1746             ++class_def_method_index;
1747             it.Next();
1748           }
1749           while (it.HasNextVirtualMethod()) {
1750             if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
1751               return false;
1752             }
1753             ++class_def_method_index;
1754             it.Next();
1755           }
1756         }
1757       }
1758       if (UNLIKELY(!visitor->EndClass())) {
1759         return false;
1760       }
1761     }
1762   }
1763   return true;
1764 }
1765 
InitOatHeader(InstructionSet instruction_set,const InstructionSetFeatures * instruction_set_features,uint32_t num_dex_files,SafeMap<std::string,std::string> * key_value_store)1766 size_t OatWriter::InitOatHeader(InstructionSet instruction_set,
1767                                 const InstructionSetFeatures* instruction_set_features,
1768                                 uint32_t num_dex_files,
1769                                 SafeMap<std::string, std::string>* key_value_store) {
1770   TimingLogger::ScopedTiming split("InitOatHeader", timings_);
1771   oat_header_.reset(OatHeader::Create(instruction_set,
1772                                       instruction_set_features,
1773                                       num_dex_files,
1774                                       key_value_store));
1775   size_oat_header_ += sizeof(OatHeader);
1776   size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
1777   return oat_header_->GetHeaderSize();
1778 }
1779 
InitClassOffsets(size_t offset)1780 size_t OatWriter::InitClassOffsets(size_t offset) {
1781   // Reserve space for class offsets in OAT and update class_offsets_offset_.
1782   for (OatDexFile& oat_dex_file : oat_dex_files_) {
1783     DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u);
1784     if (!oat_dex_file.class_offsets_.empty()) {
1785       // Class offsets are required to be 4 byte aligned.
1786       offset = RoundUp(offset, 4u);
1787       oat_dex_file.class_offsets_offset_ = offset;
1788       offset += oat_dex_file.GetClassOffsetsRawSize();
1789       DCHECK_ALIGNED(offset, 4u);
1790     }
1791   }
1792   return offset;
1793 }
1794 
InitOatClasses(size_t offset)1795 size_t OatWriter::InitOatClasses(size_t offset) {
1796   // calculate the offsets within OatDexFiles to OatClasses
1797   InitOatClassesMethodVisitor visitor(this, offset);
1798   bool success = VisitDexMethods(&visitor);
1799   CHECK(success);
1800   offset = visitor.GetOffset();
1801 
1802   // Update oat_dex_files_.
1803   auto oat_class_it = oat_class_headers_.begin();
1804   for (OatDexFile& oat_dex_file : oat_dex_files_) {
1805     for (uint32_t& class_offset : oat_dex_file.class_offsets_) {
1806       DCHECK(oat_class_it != oat_class_headers_.end());
1807       class_offset = oat_class_it->offset_;
1808       ++oat_class_it;
1809     }
1810   }
1811   CHECK(oat_class_it == oat_class_headers_.end());
1812 
1813   return offset;
1814 }
1815 
InitOatMaps(size_t offset)1816 size_t OatWriter::InitOatMaps(size_t offset) {
1817   if (!MayHaveCompiledMethods()) {
1818     return offset;
1819   }
1820   {
1821     InitMapMethodVisitor visitor(this, offset);
1822     bool success = VisitDexMethods(&visitor);
1823     DCHECK(success);
1824     offset = visitor.GetOffset();
1825   }
1826   {
1827     InitMethodInfoVisitor visitor(this, offset);
1828     bool success = VisitDexMethods(&visitor);
1829     DCHECK(success);
1830     offset = visitor.GetOffset();
1831   }
1832   return offset;
1833 }
1834 
InitMethodBssMappings(size_t offset)1835 size_t OatWriter::InitMethodBssMappings(size_t offset) {
1836   size_t number_of_dex_files = 0u;
1837   for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
1838     const DexFile* dex_file = (*dex_files_)[i];
1839     auto it = bss_method_entry_references_.find(dex_file);
1840     if (it != bss_method_entry_references_.end()) {
1841       const BitVector& method_indexes = it->second;
1842       ++number_of_dex_files;
1843       // If there are any classes, the class offsets allocation aligns the offset
1844       // and we cannot have method bss mappings without class offsets.
1845       static_assert(alignof(MethodBssMapping) == 4u, "MethodBssMapping alignment check.");
1846       DCHECK_ALIGNED(offset, 4u);
1847       oat_dex_files_[i].method_bss_mapping_offset_ = offset;
1848 
1849       linker::MethodBssMappingEncoder encoder(
1850           GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
1851       size_t number_of_entries = 0u;
1852       bool first_index = true;
1853       for (uint32_t method_index : method_indexes.Indexes()) {
1854         uint32_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
1855         if (first_index || !encoder.TryMerge(method_index, bss_offset)) {
1856           encoder.Reset(method_index, bss_offset);
1857           ++number_of_entries;
1858           first_index = false;
1859         }
1860       }
1861       DCHECK_NE(number_of_entries, 0u);
1862       offset += MethodBssMapping::ComputeSize(number_of_entries);
1863     }
1864   }
1865   // Check that all dex files targeted by method bss entries are in `*dex_files_`.
1866   CHECK_EQ(number_of_dex_files, bss_method_entry_references_.size());
1867   return offset;
1868 }
1869 
InitOatDexFiles(size_t offset)1870 size_t OatWriter::InitOatDexFiles(size_t offset) {
1871   // Initialize offsets of oat dex files.
1872   for (OatDexFile& oat_dex_file : oat_dex_files_) {
1873     oat_dex_file.offset_ = offset;
1874     offset += oat_dex_file.SizeOf();
1875   }
1876   return offset;
1877 }
1878 
InitOatCode(size_t offset)1879 size_t OatWriter::InitOatCode(size_t offset) {
1880   // calculate the offsets within OatHeader to executable code
1881   size_t old_offset = offset;
1882   size_t adjusted_offset = offset;
1883   // required to be on a new page boundary
1884   offset = RoundUp(offset, kPageSize);
1885   oat_header_->SetExecutableOffset(offset);
1886   size_executable_offset_alignment_ = offset - old_offset;
1887   if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
1888     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
1889 
1890     #define DO_TRAMPOLINE(field, fn_name) \
1891       offset = CompiledCode::AlignCode(offset, instruction_set); \
1892       adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1893       oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
1894       (field) = compiler_driver_->Create ## fn_name(); \
1895       offset += (field)->size();
1896 
1897     DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
1898     DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
1899     DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
1900     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1901     DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
1902 
1903     #undef DO_TRAMPOLINE
1904   } else {
1905     oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1906     oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1907     oat_header_->SetJniDlsymLookupOffset(0);
1908     oat_header_->SetQuickGenericJniTrampolineOffset(0);
1909     oat_header_->SetQuickImtConflictTrampolineOffset(0);
1910     oat_header_->SetQuickResolutionTrampolineOffset(0);
1911     oat_header_->SetQuickToInterpreterBridgeOffset(0);
1912   }
1913   return offset;
1914 }
1915 
InitOatCodeDexFiles(size_t offset)1916 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
1917   if (!compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
1918     return offset;
1919   }
1920   InitCodeMethodVisitor code_visitor(this, offset);
1921   bool success = VisitDexMethods(&code_visitor);
1922   DCHECK(success);
1923   offset = code_visitor.GetOffset();
1924 
1925   if (HasImage()) {
1926     InitImageMethodVisitor image_visitor(this, offset, dex_files_);
1927     success = VisitDexMethods(&image_visitor);
1928     image_visitor.Postprocess();
1929     DCHECK(success);
1930     offset = image_visitor.GetOffset();
1931   }
1932 
1933   return offset;
1934 }
1935 
InitBssLayout(InstructionSet instruction_set)1936 void OatWriter::InitBssLayout(InstructionSet instruction_set) {
1937   {
1938     InitBssLayoutMethodVisitor visitor(this);
1939     bool success = VisitDexMethods(&visitor);
1940     DCHECK(success);
1941   }
1942 
1943   DCHECK_EQ(bss_size_, 0u);
1944   if (HasBootImage()) {
1945     DCHECK(bss_string_entries_.empty());
1946     if (bss_method_entries_.empty() && bss_type_entries_.empty()) {
1947       // Nothing to put to the .bss section.
1948       return;
1949     }
1950   }
1951 
1952   // Allocate space for app dex cache arrays in the .bss section.
1953   PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
1954   if (!HasBootImage()) {
1955     for (const DexFile* dex_file : *dex_files_) {
1956       DexCacheArraysLayout layout(pointer_size, dex_file);
1957       bss_size_ += layout.Size();
1958     }
1959   }
1960 
1961   bss_methods_offset_ = bss_size_;
1962 
1963   // Prepare offsets for .bss ArtMethod entries.
1964   for (auto& entry : bss_method_entries_) {
1965     DCHECK_EQ(entry.second, 0u);
1966     entry.second = bss_size_;
1967     bss_size_ += static_cast<size_t>(pointer_size);
1968   }
1969 
1970   bss_roots_offset_ = bss_size_;
1971 
1972   // Prepare offsets for .bss Class entries.
1973   for (auto& entry : bss_type_entries_) {
1974     DCHECK_EQ(entry.second, 0u);
1975     entry.second = bss_size_;
1976     bss_size_ += sizeof(GcRoot<mirror::Class>);
1977   }
1978   // Prepare offsets for .bss String entries.
1979   for (auto& entry : bss_string_entries_) {
1980     DCHECK_EQ(entry.second, 0u);
1981     entry.second = bss_size_;
1982     bss_size_ += sizeof(GcRoot<mirror::String>);
1983   }
1984 }
1985 
WriteRodata(OutputStream * out)1986 bool OatWriter::WriteRodata(OutputStream* out) {
1987   CHECK(write_state_ == WriteState::kWriteRoData);
1988 
1989   size_t file_offset = oat_data_offset_;
1990   off_t current_offset = out->Seek(0, kSeekCurrent);
1991   if (current_offset == static_cast<off_t>(-1)) {
1992     PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation();
1993   }
1994   DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize());
1995   size_t relative_offset = current_offset - file_offset;
1996 
1997   // Wrap out to update checksum with each write.
1998   ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
1999   out = &checksum_updating_out;
2000 
2001   relative_offset = WriteClassOffsets(out, file_offset, relative_offset);
2002   if (relative_offset == 0) {
2003     PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation();
2004     return false;
2005   }
2006 
2007   relative_offset = WriteClasses(out, file_offset, relative_offset);
2008   if (relative_offset == 0) {
2009     PLOG(ERROR) << "Failed to write classes to " << out->GetLocation();
2010     return false;
2011   }
2012 
2013   relative_offset = WriteMethodBssMappings(out, file_offset, relative_offset);
2014   if (relative_offset == 0) {
2015     PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation();
2016     return false;
2017   }
2018 
2019   relative_offset = WriteMaps(out, file_offset, relative_offset);
2020   if (relative_offset == 0) {
2021     PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2022     return false;
2023   }
2024 
2025   relative_offset = WriteOatDexFiles(out, file_offset, relative_offset);
2026   if (relative_offset == 0) {
2027     PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
2028     return false;
2029   }
2030 
2031   // Write padding.
2032   off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
2033   relative_offset += size_executable_offset_alignment_;
2034   DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
2035   size_t expected_file_offset = file_offset + relative_offset;
2036   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
2037     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
2038                 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
2039     return 0;
2040   }
2041   DCHECK_OFFSET();
2042 
2043   write_state_ = WriteState::kWriteText;
2044   return true;
2045 }
2046 
2047 class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor {
2048  public:
WriteQuickeningInfoMethodVisitor(OatWriter * writer,OutputStream * out,uint32_t offset,SafeMap<const uint8_t *,uint32_t> * offset_map)2049   WriteQuickeningInfoMethodVisitor(OatWriter* writer,
2050                                    OutputStream* out,
2051                                    uint32_t offset,
2052                                    SafeMap<const uint8_t*, uint32_t>* offset_map)
2053       : DexMethodVisitor(writer, offset),
2054         out_(out),
2055         written_bytes_(0u),
2056         offset_map_(offset_map) {}
2057 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)2058   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it)
2059       OVERRIDE {
2060     uint32_t method_idx = it.GetMemberIndex();
2061     CompiledMethod* compiled_method =
2062         writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
2063 
2064     if (HasQuickeningInfo(compiled_method)) {
2065       ArrayRef<const uint8_t> map = compiled_method->GetVmapTable();
2066       // Deduplication is already done on a pointer basis by the compiler driver,
2067       // so we can simply compare the pointers to find out if things are duplicated.
2068       if (offset_map_->find(map.data()) == offset_map_->end()) {
2069         uint32_t length = map.size() * sizeof(map.front());
2070         offset_map_->Put(map.data(), written_bytes_);
2071         if (!out_->WriteFully(&length, sizeof(length)) ||
2072             !out_->WriteFully(map.data(), length)) {
2073           PLOG(ERROR) << "Failed to write quickening info for "
2074                       << dex_file_->PrettyMethod(it.GetMemberIndex()) << " to "
2075                       << out_->GetLocation();
2076           return false;
2077         }
2078         written_bytes_ += sizeof(length) + length;
2079         offset_ += sizeof(length) + length;
2080       }
2081     }
2082 
2083     return true;
2084   }
2085 
GetNumberOfWrittenBytes() const2086   size_t GetNumberOfWrittenBytes() const {
2087     return written_bytes_;
2088   }
2089 
2090  private:
2091   OutputStream* const out_;
2092   size_t written_bytes_;
2093   // Maps quickening map to its offset in the file.
2094   SafeMap<const uint8_t*, uint32_t>* offset_map_;
2095 };
2096 
2097 class OatWriter::WriteQuickeningIndicesMethodVisitor {
2098  public:
WriteQuickeningIndicesMethodVisitor(OutputStream * out,uint32_t indices_offset,const SafeMap<const uint8_t *,uint32_t> & offset_map,std::vector<uint32_t> * dex_files_offset)2099   WriteQuickeningIndicesMethodVisitor(OutputStream* out,
2100                                       uint32_t indices_offset,
2101                                       const SafeMap<const uint8_t*, uint32_t>& offset_map,
2102                                       std::vector<uint32_t>* dex_files_offset)
2103       : out_(out),
2104         indices_offset_(indices_offset),
2105         written_bytes_(0u),
2106         dex_files_offset_(dex_files_offset),
2107         offset_map_(offset_map) {}
2108 
VisitDexMethods(const std::vector<const DexFile * > & dex_files,const CompilerDriver & driver)2109   bool VisitDexMethods(const std::vector<const DexFile*>& dex_files, const CompilerDriver& driver) {
2110     for (const DexFile* dex_file : dex_files) {
2111       // Record the offset for this current dex file. It will be written in the vdex file
2112       // later.
2113       dex_files_offset_->push_back(indices_offset_ + GetNumberOfWrittenBytes());
2114       const size_t class_def_count = dex_file->NumClassDefs();
2115       for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
2116         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
2117         const uint8_t* class_data = dex_file->GetClassData(class_def);
2118         if (class_data == nullptr) {
2119           continue;
2120         }
2121         for (ClassDataItemIterator class_it(*dex_file, class_data);
2122              class_it.HasNext();
2123              class_it.Next()) {
2124           if (!class_it.IsAtMethod()) {
2125             continue;
2126           }
2127           uint32_t method_idx = class_it.GetMemberIndex();
2128           CompiledMethod* compiled_method =
2129               driver.GetCompiledMethod(MethodReference(dex_file, method_idx));
2130           if (HasQuickeningInfo(compiled_method)) {
2131             uint32_t code_item_offset = class_it.GetMethodCodeItemOffset();
2132             uint32_t offset = offset_map_.Get(compiled_method->GetVmapTable().data());
2133             if (!out_->WriteFully(&code_item_offset, sizeof(code_item_offset)) ||
2134                 !out_->WriteFully(&offset, sizeof(offset))) {
2135               PLOG(ERROR) << "Failed to write quickening info for "
2136                           << dex_file->PrettyMethod(method_idx) << " to "
2137                           << out_->GetLocation();
2138               return false;
2139             }
2140             written_bytes_ += sizeof(code_item_offset) + sizeof(offset);
2141           }
2142         }
2143       }
2144     }
2145     return true;
2146   }
2147 
GetNumberOfWrittenBytes() const2148   size_t GetNumberOfWrittenBytes() const {
2149     return written_bytes_;
2150   }
2151 
2152  private:
2153   OutputStream* const out_;
2154   const uint32_t indices_offset_;
2155   size_t written_bytes_;
2156   std::vector<uint32_t>* dex_files_offset_;
2157   // Maps quickening map to its offset in the file.
2158   const SafeMap<const uint8_t*, uint32_t>& offset_map_;
2159 };
2160 
WriteQuickeningInfo(OutputStream * vdex_out)2161 bool OatWriter::WriteQuickeningInfo(OutputStream* vdex_out) {
2162   if (!kIsVdexEnabled) {
2163     return true;
2164   }
2165 
2166   size_t initial_offset = vdex_size_;
2167   size_t start_offset = RoundUp(initial_offset, 4u);
2168 
2169   vdex_size_ = start_offset;
2170   vdex_quickening_info_offset_ = vdex_size_;
2171   size_quickening_info_alignment_ = start_offset - initial_offset;
2172 
2173   off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2174   if (actual_offset != static_cast<off_t>(start_offset)) {
2175     PLOG(ERROR) << "Failed to seek to quickening info section. Actual: " << actual_offset
2176                 << " Expected: " << start_offset
2177                 << " Output: " << vdex_out->GetLocation();
2178     return false;
2179   }
2180 
2181   if (compiler_driver_->GetCompilerOptions().IsAnyCompilationEnabled()) {
2182     std::vector<uint32_t> dex_files_indices;
2183     SafeMap<const uint8_t*, uint32_t> offset_map;
2184     WriteQuickeningInfoMethodVisitor visitor1(this, vdex_out, start_offset, &offset_map);
2185     if (!VisitDexMethods(&visitor1)) {
2186       PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2187       return false;
2188     }
2189 
2190     WriteQuickeningIndicesMethodVisitor visitor2(vdex_out,
2191                                                  visitor1.GetNumberOfWrittenBytes(),
2192                                                  offset_map,
2193                                                  &dex_files_indices);
2194     if (!visitor2.VisitDexMethods(*dex_files_, *compiler_driver_)) {
2195       PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2196       return false;
2197     }
2198 
2199     DCHECK_EQ(dex_files_->size(), dex_files_indices.size());
2200     if (!vdex_out->WriteFully(
2201             dex_files_indices.data(), sizeof(dex_files_indices[0]) * dex_files_indices.size())) {
2202       PLOG(ERROR) << "Failed to write the vdex quickening info. File: " << vdex_out->GetLocation();
2203       return false;
2204     }
2205 
2206     if (!vdex_out->Flush()) {
2207       PLOG(ERROR) << "Failed to flush stream after writing quickening info."
2208                   << " File: " << vdex_out->GetLocation();
2209       return false;
2210     }
2211     size_quickening_info_ = visitor1.GetNumberOfWrittenBytes() +
2212                             visitor2.GetNumberOfWrittenBytes() +
2213                             dex_files_->size() * sizeof(uint32_t);
2214   } else {
2215     // We know we did not quicken.
2216     size_quickening_info_ = 0;
2217   }
2218 
2219   vdex_size_ += size_quickening_info_;
2220   return true;
2221 }
2222 
WriteVerifierDeps(OutputStream * vdex_out,verifier::VerifierDeps * verifier_deps)2223 bool OatWriter::WriteVerifierDeps(OutputStream* vdex_out, verifier::VerifierDeps* verifier_deps) {
2224   if (!kIsVdexEnabled) {
2225     return true;
2226   }
2227 
2228   if (verifier_deps == nullptr) {
2229     // Nothing to write. Record the offset, but no need
2230     // for alignment.
2231     vdex_verifier_deps_offset_ = vdex_size_;
2232     return true;
2233   }
2234 
2235   size_t initial_offset = vdex_size_;
2236   size_t start_offset = RoundUp(initial_offset, 4u);
2237 
2238   vdex_size_ = start_offset;
2239   vdex_verifier_deps_offset_ = vdex_size_;
2240   size_verifier_deps_alignment_ = start_offset - initial_offset;
2241 
2242   off_t actual_offset = vdex_out->Seek(start_offset, kSeekSet);
2243   if (actual_offset != static_cast<off_t>(start_offset)) {
2244     PLOG(ERROR) << "Failed to seek to verifier deps section. Actual: " << actual_offset
2245                 << " Expected: " << start_offset
2246                 << " Output: " << vdex_out->GetLocation();
2247     return false;
2248   }
2249 
2250   std::vector<uint8_t> buffer;
2251   verifier_deps->Encode(*dex_files_, &buffer);
2252 
2253   if (!vdex_out->WriteFully(buffer.data(), buffer.size())) {
2254     PLOG(ERROR) << "Failed to write verifier deps."
2255                 << " File: " << vdex_out->GetLocation();
2256     return false;
2257   }
2258   if (!vdex_out->Flush()) {
2259     PLOG(ERROR) << "Failed to flush stream after writing verifier deps."
2260                 << " File: " << vdex_out->GetLocation();
2261     return false;
2262   }
2263 
2264   size_verifier_deps_ = buffer.size();
2265   vdex_size_ += size_verifier_deps_;
2266   return true;
2267 }
2268 
WriteCode(OutputStream * out)2269 bool OatWriter::WriteCode(OutputStream* out) {
2270   CHECK(write_state_ == WriteState::kWriteText);
2271 
2272   // Wrap out to update checksum with each write.
2273   ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get());
2274   out = &checksum_updating_out;
2275 
2276   SetMultiOatRelativePatcherAdjustment();
2277 
2278   const size_t file_offset = oat_data_offset_;
2279   size_t relative_offset = oat_header_->GetExecutableOffset();
2280   DCHECK_OFFSET();
2281 
2282   relative_offset = WriteCode(out, file_offset, relative_offset);
2283   if (relative_offset == 0) {
2284     LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
2285     return false;
2286   }
2287 
2288   relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
2289   if (relative_offset == 0) {
2290     LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
2291     return false;
2292   }
2293 
2294   const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
2295   if (oat_end_file_offset == static_cast<off_t>(-1)) {
2296     LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
2297     return false;
2298   }
2299 
2300   if (kIsDebugBuild) {
2301     uint32_t size_total = 0;
2302     #define DO_STAT(x) \
2303       VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
2304       size_total += (x);
2305 
2306     DO_STAT(size_vdex_header_);
2307     DO_STAT(size_vdex_checksums_);
2308     DO_STAT(size_dex_file_alignment_);
2309     DO_STAT(size_executable_offset_alignment_);
2310     DO_STAT(size_oat_header_);
2311     DO_STAT(size_oat_header_key_value_store_);
2312     DO_STAT(size_dex_file_);
2313     DO_STAT(size_verifier_deps_);
2314     DO_STAT(size_verifier_deps_alignment_);
2315     DO_STAT(size_quickening_info_);
2316     DO_STAT(size_quickening_info_alignment_);
2317     DO_STAT(size_interpreter_to_interpreter_bridge_);
2318     DO_STAT(size_interpreter_to_compiled_code_bridge_);
2319     DO_STAT(size_jni_dlsym_lookup_);
2320     DO_STAT(size_quick_generic_jni_trampoline_);
2321     DO_STAT(size_quick_imt_conflict_trampoline_);
2322     DO_STAT(size_quick_resolution_trampoline_);
2323     DO_STAT(size_quick_to_interpreter_bridge_);
2324     DO_STAT(size_trampoline_alignment_);
2325     DO_STAT(size_method_header_);
2326     DO_STAT(size_code_);
2327     DO_STAT(size_code_alignment_);
2328     DO_STAT(size_relative_call_thunks_);
2329     DO_STAT(size_misc_thunks_);
2330     DO_STAT(size_vmap_table_);
2331     DO_STAT(size_method_info_);
2332     DO_STAT(size_oat_dex_file_location_size_);
2333     DO_STAT(size_oat_dex_file_location_data_);
2334     DO_STAT(size_oat_dex_file_location_checksum_);
2335     DO_STAT(size_oat_dex_file_offset_);
2336     DO_STAT(size_oat_dex_file_class_offsets_offset_);
2337     DO_STAT(size_oat_dex_file_lookup_table_offset_);
2338     DO_STAT(size_oat_dex_file_dex_layout_sections_offset_);
2339     DO_STAT(size_oat_dex_file_dex_layout_sections_);
2340     DO_STAT(size_oat_dex_file_dex_layout_sections_alignment_);
2341     DO_STAT(size_oat_dex_file_method_bss_mapping_offset_);
2342     DO_STAT(size_oat_lookup_table_alignment_);
2343     DO_STAT(size_oat_lookup_table_);
2344     DO_STAT(size_oat_class_offsets_alignment_);
2345     DO_STAT(size_oat_class_offsets_);
2346     DO_STAT(size_oat_class_type_);
2347     DO_STAT(size_oat_class_status_);
2348     DO_STAT(size_oat_class_method_bitmaps_);
2349     DO_STAT(size_oat_class_method_offsets_);
2350     DO_STAT(size_method_bss_mappings_);
2351     #undef DO_STAT
2352 
2353     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
2354 
2355     CHECK_EQ(vdex_size_ + oat_size_, size_total);
2356     CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
2357   }
2358 
2359   CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
2360   CHECK_EQ(oat_size_, relative_offset);
2361 
2362   write_state_ = WriteState::kWriteHeader;
2363   return true;
2364 }
2365 
WriteHeader(OutputStream * out,uint32_t image_file_location_oat_checksum,uintptr_t image_file_location_oat_begin,int32_t image_patch_delta)2366 bool OatWriter::WriteHeader(OutputStream* out,
2367                             uint32_t image_file_location_oat_checksum,
2368                             uintptr_t image_file_location_oat_begin,
2369                             int32_t image_patch_delta) {
2370   CHECK(write_state_ == WriteState::kWriteHeader);
2371 
2372   oat_header_->SetImageFileLocationOatChecksum(image_file_location_oat_checksum);
2373   oat_header_->SetImageFileLocationOatDataBegin(image_file_location_oat_begin);
2374   if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
2375     CHECK_EQ(image_patch_delta, 0);
2376     CHECK_EQ(oat_header_->GetImagePatchDelta(), 0);
2377   } else {
2378     CHECK_ALIGNED(image_patch_delta, kPageSize);
2379     oat_header_->SetImagePatchDelta(image_patch_delta);
2380   }
2381   oat_header_->UpdateChecksumWithHeaderData();
2382 
2383   const size_t file_offset = oat_data_offset_;
2384 
2385   off_t current_offset = out->Seek(0, kSeekCurrent);
2386   if (current_offset == static_cast<off_t>(-1)) {
2387     PLOG(ERROR) << "Failed to get current offset from " << out->GetLocation();
2388     return false;
2389   }
2390   if (out->Seek(file_offset, kSeekSet) == static_cast<off_t>(-1)) {
2391     PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
2392     return false;
2393   }
2394   DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
2395 
2396   // Flush all other data before writing the header.
2397   if (!out->Flush()) {
2398     PLOG(ERROR) << "Failed to flush before writing oat header to " << out->GetLocation();
2399     return false;
2400   }
2401   // Write the header.
2402   size_t header_size = oat_header_->GetHeaderSize();
2403   if (!out->WriteFully(oat_header_.get(), header_size)) {
2404     PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
2405     return false;
2406   }
2407   // Flush the header data.
2408   if (!out->Flush()) {
2409     PLOG(ERROR) << "Failed to flush after writing oat header to " << out->GetLocation();
2410     return false;
2411   }
2412 
2413   if (out->Seek(current_offset, kSeekSet) == static_cast<off_t>(-1)) {
2414     PLOG(ERROR) << "Failed to seek back after writing oat header to " << out->GetLocation();
2415     return false;
2416   }
2417   DCHECK_EQ(current_offset, out->Seek(0, kSeekCurrent));
2418 
2419   write_state_ = WriteState::kDone;
2420   return true;
2421 }
2422 
WriteClassOffsets(OutputStream * out,size_t file_offset,size_t relative_offset)2423 size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) {
2424   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2425     if (oat_dex_file.class_offsets_offset_ != 0u) {
2426       // Class offsets are required to be 4 byte aligned.
2427       if (UNLIKELY(!IsAligned<4u>(relative_offset))) {
2428         size_t padding_size =  RoundUp(relative_offset, 4u) - relative_offset;
2429         if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) {
2430           return 0u;
2431         }
2432         relative_offset += padding_size;
2433       }
2434       DCHECK_OFFSET();
2435       if (!oat_dex_file.WriteClassOffsets(this, out)) {
2436         return 0u;
2437       }
2438       relative_offset += oat_dex_file.GetClassOffsetsRawSize();
2439     }
2440   }
2441   return relative_offset;
2442 }
2443 
WriteClasses(OutputStream * out,size_t file_offset,size_t relative_offset)2444 size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) {
2445   const bool may_have_compiled = MayHaveCompiledMethods();
2446   if (may_have_compiled) {
2447     CHECK_EQ(oat_class_headers_.size(), oat_classes_.size());
2448   }
2449   for (size_t i = 0; i < oat_class_headers_.size(); ++i) {
2450     // If there are any classes, the class offsets allocation aligns the offset.
2451     DCHECK_ALIGNED(relative_offset, 4u);
2452     DCHECK_OFFSET();
2453     if (!oat_class_headers_[i].Write(this, out, oat_data_offset_)) {
2454       return 0u;
2455     }
2456     relative_offset += oat_class_headers_[i].SizeOf();
2457     if (may_have_compiled) {
2458       if (!oat_classes_[i].Write(this, out)) {
2459         return 0u;
2460       }
2461       relative_offset += oat_classes_[i].SizeOf();
2462     }
2463   }
2464   return relative_offset;
2465 }
2466 
WriteMaps(OutputStream * out,size_t file_offset,size_t relative_offset)2467 size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) {
2468   {
2469     size_t vmap_tables_offset = relative_offset;
2470     WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset);
2471     if (UNLIKELY(!VisitDexMethods(&visitor))) {
2472       return 0;
2473     }
2474     relative_offset = visitor.GetOffset();
2475     size_vmap_table_ = relative_offset - vmap_tables_offset;
2476   }
2477   {
2478     size_t method_infos_offset = relative_offset;
2479     WriteMethodInfoVisitor visitor(this, out, file_offset, relative_offset);
2480     if (UNLIKELY(!VisitDexMethods(&visitor))) {
2481       return 0;
2482     }
2483     relative_offset = visitor.GetOffset();
2484     size_method_info_ = relative_offset - method_infos_offset;
2485   }
2486 
2487   return relative_offset;
2488 }
2489 
WriteMethodBssMappings(OutputStream * out,size_t file_offset,size_t relative_offset)2490 size_t OatWriter::WriteMethodBssMappings(OutputStream* out,
2491                                          size_t file_offset,
2492                                          size_t relative_offset) {
2493   TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_);
2494 
2495   for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
2496     const DexFile* dex_file = (*dex_files_)[i];
2497     OatDexFile* oat_dex_file = &oat_dex_files_[i];
2498     auto it = bss_method_entry_references_.find(dex_file);
2499     if (it != bss_method_entry_references_.end()) {
2500       const BitVector& method_indexes = it->second;
2501       // If there are any classes, the class offsets allocation aligns the offset
2502       // and we cannot have method bss mappings without class offsets.
2503       static_assert(alignof(MethodBssMapping) == sizeof(uint32_t),
2504                     "MethodBssMapping alignment check.");
2505       DCHECK_ALIGNED(relative_offset, sizeof(uint32_t));
2506 
2507       linker::MethodBssMappingEncoder encoder(
2508           GetInstructionSetPointerSize(oat_header_->GetInstructionSet()));
2509       // Allocate a sufficiently large MethodBssMapping.
2510       size_t number_of_method_indexes = method_indexes.NumSetBits();
2511       DCHECK_NE(number_of_method_indexes, 0u);
2512       size_t max_mappings_size = MethodBssMapping::ComputeSize(number_of_method_indexes);
2513       DCHECK_ALIGNED(max_mappings_size, sizeof(uint32_t));
2514       std::unique_ptr<uint32_t[]> storage(new uint32_t[max_mappings_size / sizeof(uint32_t)]);
2515       MethodBssMapping* mappings = new(storage.get()) MethodBssMapping(number_of_method_indexes);
2516       mappings->ClearPadding();
2517       // Encode the MethodBssMapping.
2518       auto init_it = mappings->begin();
2519       bool first_index = true;
2520       for (uint32_t method_index : method_indexes.Indexes()) {
2521         size_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index));
2522         if (first_index) {
2523           first_index = false;
2524           encoder.Reset(method_index, bss_offset);
2525         } else if (!encoder.TryMerge(method_index, bss_offset)) {
2526           *init_it = encoder.GetEntry();
2527           ++init_it;
2528           encoder.Reset(method_index, bss_offset);
2529         }
2530       }
2531       // Store the last entry and shrink the mapping to the actual size.
2532       *init_it = encoder.GetEntry();
2533       ++init_it;
2534       DCHECK(init_it <= mappings->end());
2535       mappings->SetSize(std::distance(mappings->begin(), init_it));
2536       size_t mappings_size = MethodBssMapping::ComputeSize(mappings->size());
2537 
2538       DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_);
2539       DCHECK_OFFSET();
2540       if (!out->WriteFully(storage.get(), mappings_size)) {
2541         return 0u;
2542       }
2543       size_method_bss_mappings_ += mappings_size;
2544       relative_offset += mappings_size;
2545     } else {
2546       DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_);
2547     }
2548   }
2549   return relative_offset;
2550 }
2551 
WriteOatDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)2552 size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) {
2553   TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_);
2554 
2555   for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
2556     OatDexFile* oat_dex_file = &oat_dex_files_[i];
2557     DCHECK_EQ(relative_offset, oat_dex_file->offset_);
2558     DCHECK_OFFSET();
2559 
2560     // Write OatDexFile.
2561     if (!oat_dex_file->Write(this, out)) {
2562       return 0u;
2563     }
2564     relative_offset += oat_dex_file->SizeOf();
2565   }
2566 
2567   return relative_offset;
2568 }
2569 
WriteCode(OutputStream * out,size_t file_offset,size_t relative_offset)2570 size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) {
2571   if (compiler_driver_->GetCompilerOptions().IsBootImage()) {
2572     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
2573 
2574     #define DO_TRAMPOLINE(field) \
2575       do { \
2576         uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
2577         uint32_t alignment_padding = aligned_offset - relative_offset; \
2578         out->Seek(alignment_padding, kSeekCurrent); \
2579         size_trampoline_alignment_ += alignment_padding; \
2580         if (!out->WriteFully((field)->data(), (field)->size())) { \
2581           PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
2582           return false; \
2583         } \
2584         size_ ## field += (field)->size(); \
2585         relative_offset += alignment_padding + (field)->size(); \
2586         DCHECK_OFFSET(); \
2587       } while (false)
2588 
2589     DO_TRAMPOLINE(jni_dlsym_lookup_);
2590     DO_TRAMPOLINE(quick_generic_jni_trampoline_);
2591     DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
2592     DO_TRAMPOLINE(quick_resolution_trampoline_);
2593     DO_TRAMPOLINE(quick_to_interpreter_bridge_);
2594     #undef DO_TRAMPOLINE
2595   }
2596   return relative_offset;
2597 }
2598 
WriteCodeDexFiles(OutputStream * out,size_t file_offset,size_t relative_offset)2599 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
2600                                     size_t file_offset,
2601                                     size_t relative_offset) {
2602   #define VISIT(VisitorType)                                              \
2603     do {                                                                  \
2604       VisitorType visitor(this, out, file_offset, relative_offset);       \
2605       if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \
2606         return 0;                                                         \
2607       }                                                                   \
2608       relative_offset = visitor.GetOffset();                              \
2609     } while (false)
2610 
2611   VISIT(WriteCodeMethodVisitor);
2612 
2613   #undef VISIT
2614 
2615   size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
2616   size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
2617   size_misc_thunks_ += relative_patcher_->MiscThunksSize();
2618 
2619   return relative_offset;
2620 }
2621 
RecordOatDataOffset(OutputStream * out)2622 bool OatWriter::RecordOatDataOffset(OutputStream* out) {
2623   // Get the elf file offset of the oat file.
2624   const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
2625   if (raw_file_offset == static_cast<off_t>(-1)) {
2626     LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
2627     return false;
2628   }
2629   oat_data_offset_ = static_cast<size_t>(raw_file_offset);
2630   return true;
2631 }
2632 
ReadDexFileHeader(File * file,OatDexFile * oat_dex_file)2633 bool OatWriter::ReadDexFileHeader(File* file, OatDexFile* oat_dex_file) {
2634   // Read the dex file header and perform minimal verification.
2635   uint8_t raw_header[sizeof(DexFile::Header)];
2636   if (!file->ReadFully(&raw_header, sizeof(DexFile::Header))) {
2637     PLOG(ERROR) << "Failed to read dex file header. Actual: "
2638                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2639     return false;
2640   }
2641   if (!ValidateDexFileHeader(raw_header, oat_dex_file->GetLocation())) {
2642     return false;
2643   }
2644 
2645   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2646   oat_dex_file->dex_file_size_ = header->file_size_;
2647   oat_dex_file->dex_file_location_checksum_ = header->checksum_;
2648   oat_dex_file->class_offsets_.resize(header->class_defs_size_);
2649   return true;
2650 }
2651 
ValidateDexFileHeader(const uint8_t * raw_header,const char * location)2652 bool OatWriter::ValidateDexFileHeader(const uint8_t* raw_header, const char* location) {
2653   if (!DexFile::IsMagicValid(raw_header)) {
2654     LOG(ERROR) << "Invalid magic number in dex file header. " << " File: " << location;
2655     return false;
2656   }
2657   if (!DexFile::IsVersionValid(raw_header)) {
2658     LOG(ERROR) << "Invalid version number in dex file header. " << " File: " << location;
2659     return false;
2660   }
2661   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_header);
2662   if (header->file_size_ < sizeof(DexFile::Header)) {
2663     LOG(ERROR) << "Dex file header specifies file size insufficient to contain the header."
2664                << " File: " << location;
2665     return false;
2666   }
2667   return true;
2668 }
2669 
WriteDexFiles(OutputStream * out,File * file,bool update_input_vdex)2670 bool OatWriter::WriteDexFiles(OutputStream* out, File* file, bool update_input_vdex) {
2671   TimingLogger::ScopedTiming split("Write Dex files", timings_);
2672 
2673   vdex_dex_files_offset_ = vdex_size_;
2674 
2675   // Write dex files.
2676   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2677     if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
2678       return false;
2679     }
2680   }
2681 
2682   CloseSources();
2683   return true;
2684 }
2685 
CloseSources()2686 void OatWriter::CloseSources() {
2687   for (OatDexFile& oat_dex_file : oat_dex_files_) {
2688     oat_dex_file.source_.Clear();  // Get rid of the reference, it's about to be invalidated.
2689   }
2690   zipped_dex_files_.clear();
2691   zip_archives_.clear();
2692   raw_dex_files_.clear();
2693 }
2694 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,bool update_input_vdex)2695 bool OatWriter::WriteDexFile(OutputStream* out,
2696                              File* file,
2697                              OatDexFile* oat_dex_file,
2698                              bool update_input_vdex) {
2699   if (!SeekToDexFile(out, file, oat_dex_file)) {
2700     return false;
2701   }
2702   if (profile_compilation_info_ != nullptr) {
2703     CHECK(!update_input_vdex) << "We should never update the input vdex when doing dexlayout";
2704     if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
2705       return false;
2706     }
2707   } else if (oat_dex_file->source_.IsZipEntry()) {
2708     DCHECK(!update_input_vdex);
2709     if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
2710       return false;
2711     }
2712   } else if (oat_dex_file->source_.IsRawFile()) {
2713     DCHECK(!update_input_vdex);
2714     if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
2715       return false;
2716     }
2717   } else {
2718     DCHECK(oat_dex_file->source_.IsRawData());
2719     if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData(), update_input_vdex)) {
2720       return false;
2721     }
2722   }
2723 
2724   // Update current size and account for the written data.
2725   if (kIsVdexEnabled) {
2726     DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
2727     vdex_size_ += oat_dex_file->dex_file_size_;
2728   } else {
2729     DCHECK(!update_input_vdex);
2730     DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
2731     oat_size_ += oat_dex_file->dex_file_size_;
2732   }
2733   size_dex_file_ += oat_dex_file->dex_file_size_;
2734   return true;
2735 }
2736 
SeekToDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file)2737 bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
2738   // Dex files are required to be 4 byte aligned.
2739   size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
2740   size_t start_offset = RoundUp(initial_offset, 4);
2741   size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
2742   size_dex_file_alignment_ += start_offset - initial_offset;
2743 
2744   // Seek to the start of the dex file and flush any pending operations in the stream.
2745   // Verify that, after flushing the stream, the file is at the same offset as the stream.
2746   off_t actual_offset = out->Seek(file_offset, kSeekSet);
2747   if (actual_offset != static_cast<off_t>(file_offset)) {
2748     PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
2749                 << " Expected: " << file_offset
2750                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2751     return false;
2752   }
2753   if (!out->Flush()) {
2754     PLOG(ERROR) << "Failed to flush before writing dex file."
2755                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2756     return false;
2757   }
2758   actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2759   if (actual_offset != static_cast<off_t>(file_offset)) {
2760     PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
2761                 << " Expected: " << file_offset
2762                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2763     return false;
2764   }
2765 
2766   if (kIsVdexEnabled) {
2767     vdex_size_ = start_offset;
2768   } else {
2769     oat_size_ = start_offset;
2770   }
2771   oat_dex_file->dex_file_offset_ = start_offset;
2772   return true;
2773 }
2774 
LayoutAndWriteDexFile(OutputStream * out,OatDexFile * oat_dex_file)2775 bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
2776   TimingLogger::ScopedTiming split("Dex Layout", timings_);
2777   std::string error_msg;
2778   std::string location(oat_dex_file->GetLocation());
2779   std::unique_ptr<const DexFile> dex_file;
2780   if (oat_dex_file->source_.IsZipEntry()) {
2781     ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
2782     std::unique_ptr<MemMap> mem_map(
2783         zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
2784     if (mem_map == nullptr) {
2785       LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg;
2786       return false;
2787     }
2788     dex_file = DexFile::Open(location,
2789                              zip_entry->GetCrc32(),
2790                              std::move(mem_map),
2791                              /* verify */ true,
2792                              /* verify_checksum */ true,
2793                              &error_msg);
2794   } else if (oat_dex_file->source_.IsRawFile()) {
2795     File* raw_file = oat_dex_file->source_.GetRawFile();
2796     dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
2797   } else {
2798     // The source data is a vdex file.
2799     CHECK(oat_dex_file->source_.IsRawData())
2800         << static_cast<size_t>(oat_dex_file->source_.GetType());
2801     const uint8_t* raw_dex_file = oat_dex_file->source_.GetRawData();
2802     // Note: The raw data has already been checked to contain the header
2803     // and all the data that the header specifies as the file size.
2804     DCHECK(raw_dex_file != nullptr);
2805     DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation()));
2806     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
2807     // Since the source may have had its layout changed, or may be quickened, don't verify it.
2808     dex_file = DexFile::Open(raw_dex_file,
2809                              header->file_size_,
2810                              location,
2811                              oat_dex_file->dex_file_location_checksum_,
2812                              nullptr,
2813                              /* verify */ false,
2814                              /* verify_checksum */ false,
2815                              &error_msg);
2816   }
2817   if (dex_file == nullptr) {
2818     LOG(ERROR) << "Failed to open dex file for layout: " << error_msg;
2819     return false;
2820   }
2821   Options options;
2822   options.output_to_memmap_ = true;
2823   DexLayout dex_layout(options, profile_compilation_info_, nullptr);
2824   dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
2825   std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
2826   if (!WriteDexFile(out, oat_dex_file, mem_map->Begin(), /* update_input_vdex */ false)) {
2827     return false;
2828   }
2829   oat_dex_file->dex_sections_layout_ = dex_layout.GetSections();
2830   // Set the checksum of the new oat dex file to be the original file's checksum.
2831   oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
2832   return true;
2833 }
2834 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,ZipEntry * dex_file)2835 bool OatWriter::WriteDexFile(OutputStream* out,
2836                              File* file,
2837                              OatDexFile* oat_dex_file,
2838                              ZipEntry* dex_file) {
2839   size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2840   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
2841 
2842   // Extract the dex file and get the extracted size.
2843   std::string error_msg;
2844   if (!dex_file->ExtractToFile(*file, &error_msg)) {
2845     LOG(ERROR) << "Failed to extract dex file from ZIP entry: " << error_msg
2846                << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2847     return false;
2848   }
2849   if (file->Flush() != 0) {
2850     PLOG(ERROR) << "Failed to flush dex file from ZIP entry."
2851                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2852     return false;
2853   }
2854   off_t extracted_end = lseek(file->Fd(), 0, SEEK_CUR);
2855   if (extracted_end == static_cast<off_t>(-1)) {
2856     PLOG(ERROR) << "Failed get end offset after writing dex file from ZIP entry."
2857                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2858     return false;
2859   }
2860   if (extracted_end < static_cast<off_t>(start_offset)) {
2861     LOG(ERROR) << "Dex file end position is before start position! End: " << extracted_end
2862                << " Start: " << start_offset
2863                << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2864     return false;
2865   }
2866   uint64_t extracted_size = static_cast<uint64_t>(extracted_end - start_offset);
2867   if (extracted_size < sizeof(DexFile::Header)) {
2868     LOG(ERROR) << "Extracted dex file is shorter than dex file header. size: "
2869                << extracted_size << " File: " << oat_dex_file->GetLocation();
2870     return false;
2871   }
2872 
2873   // Read the dex file header and extract required data to OatDexFile.
2874   off_t actual_offset = lseek(file->Fd(), start_offset, SEEK_SET);
2875   if (actual_offset != static_cast<off_t>(start_offset)) {
2876     PLOG(ERROR) << "Failed to seek back to dex file header. Actual: " << actual_offset
2877                 << " Expected: " << start_offset
2878                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2879     return false;
2880   }
2881   if (!ReadDexFileHeader(file, oat_dex_file)) {
2882     return false;
2883   }
2884   if (extracted_size < oat_dex_file->dex_file_size_) {
2885     LOG(ERROR) << "Extracted truncated dex file. Extracted size: " << extracted_size
2886                << " file size from header: " << oat_dex_file->dex_file_size_
2887                << " File: " << oat_dex_file->GetLocation();
2888     return false;
2889   }
2890 
2891   // Override the checksum from header with the CRC from ZIP entry.
2892   oat_dex_file->dex_file_location_checksum_ = dex_file->GetCrc32();
2893 
2894   // Seek both file and stream to the end offset.
2895   size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2896   actual_offset = lseek(file->Fd(), end_offset, SEEK_SET);
2897   if (actual_offset != static_cast<off_t>(end_offset)) {
2898     PLOG(ERROR) << "Failed to seek to end of dex file. Actual: " << actual_offset
2899                 << " Expected: " << end_offset
2900                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2901     return false;
2902   }
2903   actual_offset = out->Seek(end_offset, kSeekSet);
2904   if (actual_offset != static_cast<off_t>(end_offset)) {
2905     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2906                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2907     return false;
2908   }
2909   if (!out->Flush()) {
2910     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2911                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2912     return false;
2913   }
2914 
2915   // If we extracted more than the size specified in the header, truncate the file.
2916   if (extracted_size > oat_dex_file->dex_file_size_) {
2917     if (file->SetLength(end_offset) != 0) {
2918       PLOG(ERROR) << "Failed to truncate excessive dex file length."
2919                   << " File: " << oat_dex_file->GetLocation()
2920                   << " Output: " << file->GetPath();
2921       return false;
2922     }
2923   }
2924 
2925   return true;
2926 }
2927 
WriteDexFile(OutputStream * out,File * file,OatDexFile * oat_dex_file,File * dex_file)2928 bool OatWriter::WriteDexFile(OutputStream* out,
2929                              File* file,
2930                              OatDexFile* oat_dex_file,
2931                              File* dex_file) {
2932   size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
2933   DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
2934 
2935   off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
2936   if (input_offset != static_cast<off_t>(0)) {
2937     PLOG(ERROR) << "Failed to seek to dex file header. Actual: " << input_offset
2938                 << " Expected: 0"
2939                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2940     return false;
2941   }
2942   if (!ReadDexFileHeader(dex_file, oat_dex_file)) {
2943     return false;
2944   }
2945 
2946   // Copy the input dex file using sendfile().
2947   if (!file->Copy(dex_file, 0, oat_dex_file->dex_file_size_)) {
2948     PLOG(ERROR) << "Failed to copy dex file to oat file."
2949                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2950     return false;
2951   }
2952   if (file->Flush() != 0) {
2953     PLOG(ERROR) << "Failed to flush dex file."
2954                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2955     return false;
2956   }
2957 
2958   // Check file position and seek the stream to the end offset.
2959   size_t end_offset = start_offset + oat_dex_file->dex_file_size_;
2960   off_t actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
2961   if (actual_offset != static_cast<off_t>(end_offset)) {
2962     PLOG(ERROR) << "Unexpected file position after copying dex file. Actual: " << actual_offset
2963                 << " Expected: " << end_offset
2964                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2965     return false;
2966   }
2967   actual_offset = out->Seek(end_offset, kSeekSet);
2968   if (actual_offset != static_cast<off_t>(end_offset)) {
2969     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
2970                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
2971     return false;
2972   }
2973   if (!out->Flush()) {
2974     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
2975                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
2976     return false;
2977   }
2978 
2979   return true;
2980 }
2981 
WriteDexFile(OutputStream * out,OatDexFile * oat_dex_file,const uint8_t * dex_file,bool update_input_vdex)2982 bool OatWriter::WriteDexFile(OutputStream* out,
2983                              OatDexFile* oat_dex_file,
2984                              const uint8_t* dex_file,
2985                              bool update_input_vdex) {
2986   // Note: The raw data has already been checked to contain the header
2987   // and all the data that the header specifies as the file size.
2988   DCHECK(dex_file != nullptr);
2989   DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
2990   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
2991 
2992   if (update_input_vdex) {
2993     // The vdex already contains the dex code, no need to write it again.
2994   } else {
2995     if (!out->WriteFully(dex_file, header->file_size_)) {
2996       PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
2997                   << " to " << out->GetLocation();
2998       return false;
2999     }
3000     if (!out->Flush()) {
3001       PLOG(ERROR) << "Failed to flush stream after writing dex file."
3002                   << " File: " << oat_dex_file->GetLocation();
3003       return false;
3004     }
3005   }
3006 
3007   // Update dex file size and resize class offsets in the OatDexFile.
3008   // Note: For raw data, the checksum is passed directly to AddRawDexFileSource().
3009   // Note: For vdex, the checksum is copied from the existing vdex file.
3010   oat_dex_file->dex_file_size_ = header->file_size_;
3011   oat_dex_file->class_offsets_.resize(header->class_defs_size_);
3012   return true;
3013 }
3014 
OpenDexFiles(File * file,bool verify,std::unique_ptr<MemMap> * opened_dex_files_map,std::vector<std::unique_ptr<const DexFile>> * opened_dex_files)3015 bool OatWriter::OpenDexFiles(
3016     File* file,
3017     bool verify,
3018     /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
3019     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
3020   TimingLogger::ScopedTiming split("OpenDexFiles", timings_);
3021 
3022   if (oat_dex_files_.empty()) {
3023     // Nothing to do.
3024     return true;
3025   }
3026 
3027   size_t map_offset = oat_dex_files_[0].dex_file_offset_;
3028   size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
3029 
3030   std::string error_msg;
3031   std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
3032       length,
3033       PROT_READ | PROT_WRITE,
3034       MAP_SHARED,
3035       file->Fd(),
3036       kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
3037       /* low_4gb */ false,
3038       file->GetPath().c_str(),
3039       &error_msg));
3040   if (dex_files_map == nullptr) {
3041     LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
3042                << " error: " << error_msg;
3043     return false;
3044   }
3045   std::vector<std::unique_ptr<const DexFile>> dex_files;
3046   for (OatDexFile& oat_dex_file : oat_dex_files_) {
3047     // Make sure no one messed with input files while we were copying data.
3048     // At the very least we need consistent file size and number of class definitions.
3049     const uint8_t* raw_dex_file =
3050         dex_files_map->Begin() + oat_dex_file.dex_file_offset_ - map_offset;
3051     if (!ValidateDexFileHeader(raw_dex_file, oat_dex_file.GetLocation())) {
3052       // Note: ValidateDexFileHeader() already logged an error message.
3053       LOG(ERROR) << "Failed to verify written dex file header!"
3054           << " Output: " << file->GetPath() << " ~ " << std::hex << map_offset
3055           << " ~ " << static_cast<const void*>(raw_dex_file);
3056       return false;
3057     }
3058     const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file);
3059     if (header->file_size_ != oat_dex_file.dex_file_size_) {
3060       LOG(ERROR) << "File size mismatch in written dex file header! Expected: "
3061           << oat_dex_file.dex_file_size_ << " Actual: " << header->file_size_
3062           << " Output: " << file->GetPath();
3063       return false;
3064     }
3065     if (header->class_defs_size_ != oat_dex_file.class_offsets_.size()) {
3066       LOG(ERROR) << "Class defs size mismatch in written dex file header! Expected: "
3067           << oat_dex_file.class_offsets_.size() << " Actual: " << header->class_defs_size_
3068           << " Output: " << file->GetPath();
3069       return false;
3070     }
3071 
3072     // Now, open the dex file.
3073     dex_files.emplace_back(DexFile::Open(raw_dex_file,
3074                                          oat_dex_file.dex_file_size_,
3075                                          oat_dex_file.GetLocation(),
3076                                          oat_dex_file.dex_file_location_checksum_,
3077                                          /* oat_dex_file */ nullptr,
3078                                          verify,
3079                                          verify,
3080                                          &error_msg));
3081     if (dex_files.back() == nullptr) {
3082       LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation()
3083                  << " Error: " << error_msg;
3084       return false;
3085     }
3086   }
3087 
3088   *opened_dex_files_map = std::move(dex_files_map);
3089   *opened_dex_files = std::move(dex_files);
3090   return true;
3091 }
3092 
WriteTypeLookupTables(OutputStream * oat_rodata,const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3093 bool OatWriter::WriteTypeLookupTables(
3094     OutputStream* oat_rodata,
3095     const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3096   TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
3097 
3098   uint32_t expected_offset = oat_data_offset_ + oat_size_;
3099   off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3100   if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3101     PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
3102                 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3103     return false;
3104   }
3105 
3106   DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3107   for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3108     OatDexFile* oat_dex_file = &oat_dex_files_[i];
3109     DCHECK_EQ(oat_dex_file->lookup_table_offset_, 0u);
3110 
3111     if (oat_dex_file->create_type_lookup_table_ != CreateTypeLookupTable::kCreate ||
3112         oat_dex_file->class_offsets_.empty()) {
3113       continue;
3114     }
3115 
3116     size_t table_size = TypeLookupTable::RawDataLength(oat_dex_file->class_offsets_.size());
3117     if (table_size == 0u) {
3118       continue;
3119     }
3120 
3121     // Create the lookup table. When `nullptr` is given as the storage buffer,
3122     // TypeLookupTable allocates its own and OatDexFile takes ownership.
3123     const DexFile& dex_file = *opened_dex_files[i];
3124     {
3125       std::unique_ptr<TypeLookupTable> type_lookup_table =
3126           TypeLookupTable::Create(dex_file, /* storage */ nullptr);
3127       type_lookup_table_oat_dex_files_.push_back(
3128           std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
3129       dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
3130     }
3131     TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
3132 
3133     // Type tables are required to be 4 byte aligned.
3134     size_t initial_offset = oat_size_;
3135     size_t rodata_offset = RoundUp(initial_offset, 4);
3136     size_t padding_size = rodata_offset - initial_offset;
3137 
3138     if (padding_size != 0u) {
3139       std::vector<uint8_t> buffer(padding_size, 0u);
3140       if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3141         PLOG(ERROR) << "Failed to write lookup table alignment padding."
3142                     << " File: " << oat_dex_file->GetLocation()
3143                     << " Output: " << oat_rodata->GetLocation();
3144         return false;
3145       }
3146     }
3147 
3148     DCHECK_EQ(oat_data_offset_ + rodata_offset,
3149               static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3150     DCHECK_EQ(table_size, table->RawDataLength());
3151 
3152     if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
3153       PLOG(ERROR) << "Failed to write lookup table."
3154                   << " File: " << oat_dex_file->GetLocation()
3155                   << " Output: " << oat_rodata->GetLocation();
3156       return false;
3157     }
3158 
3159     oat_dex_file->lookup_table_offset_ = rodata_offset;
3160 
3161     oat_size_ += padding_size + table_size;
3162     size_oat_lookup_table_ += table_size;
3163     size_oat_lookup_table_alignment_ += padding_size;
3164   }
3165 
3166   if (!oat_rodata->Flush()) {
3167     PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
3168                 << " File: " << oat_rodata->GetLocation();
3169     return false;
3170   }
3171 
3172   return true;
3173 }
3174 
WriteDexLayoutSections(OutputStream * oat_rodata,const std::vector<std::unique_ptr<const DexFile>> & opened_dex_files)3175 bool OatWriter::WriteDexLayoutSections(
3176     OutputStream* oat_rodata,
3177     const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
3178   TimingLogger::ScopedTiming split(__FUNCTION__, timings_);
3179 
3180   if (!kWriteDexLayoutInfo) {
3181     return true;;
3182   }
3183 
3184   uint32_t expected_offset = oat_data_offset_ + oat_size_;
3185   off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
3186   if (static_cast<uint32_t>(actual_offset) != expected_offset) {
3187     PLOG(ERROR) << "Failed to seek to dex layout section offset section. Actual: " << actual_offset
3188                 << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
3189     return false;
3190   }
3191 
3192   DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
3193   size_t rodata_offset = oat_size_;
3194   for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
3195     OatDexFile* oat_dex_file = &oat_dex_files_[i];
3196     DCHECK_EQ(oat_dex_file->dex_sections_layout_offset_, 0u);
3197 
3198     // Write dex layout section alignment bytes.
3199     const size_t padding_size =
3200         RoundUp(rodata_offset, alignof(DexLayoutSections)) - rodata_offset;
3201     if (padding_size != 0u) {
3202       std::vector<uint8_t> buffer(padding_size, 0u);
3203       if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
3204         PLOG(ERROR) << "Failed to write lookup table alignment padding."
3205                     << " File: " << oat_dex_file->GetLocation()
3206                     << " Output: " << oat_rodata->GetLocation();
3207         return false;
3208       }
3209       size_oat_dex_file_dex_layout_sections_alignment_ += padding_size;
3210       rodata_offset += padding_size;
3211     }
3212 
3213     DCHECK_ALIGNED(rodata_offset, alignof(DexLayoutSections));
3214     DCHECK_EQ(oat_data_offset_ + rodata_offset,
3215               static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
3216     DCHECK(oat_dex_file != nullptr);
3217     if (!oat_rodata->WriteFully(&oat_dex_file->dex_sections_layout_,
3218                                 sizeof(oat_dex_file->dex_sections_layout_))) {
3219       PLOG(ERROR) << "Failed to write dex layout sections."
3220                   << " File: " << oat_dex_file->GetLocation()
3221                   << " Output: " << oat_rodata->GetLocation();
3222       return false;
3223     }
3224     oat_dex_file->dex_sections_layout_offset_ = rodata_offset;
3225     size_oat_dex_file_dex_layout_sections_ += sizeof(oat_dex_file->dex_sections_layout_);
3226     rodata_offset += sizeof(oat_dex_file->dex_sections_layout_);
3227   }
3228   oat_size_ = rodata_offset;
3229 
3230   if (!oat_rodata->Flush()) {
3231     PLOG(ERROR) << "Failed to flush stream after writing type dex layout sections."
3232                 << " File: " << oat_rodata->GetLocation();
3233     return false;
3234   }
3235 
3236   return true;
3237 }
3238 
WriteChecksumsAndVdexHeader(OutputStream * vdex_out)3239 bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
3240   if (!kIsVdexEnabled) {
3241     return true;
3242   }
3243   // Write checksums
3244   off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
3245   if (actual_offset != sizeof(VdexFile::Header)) {
3246     PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
3247                 << " File: " << vdex_out->GetLocation();
3248     return false;
3249   }
3250 
3251   for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
3252     OatDexFile* oat_dex_file = &oat_dex_files_[i];
3253     if (!vdex_out->WriteFully(
3254             &oat_dex_file->dex_file_location_checksum_, sizeof(VdexFile::VdexChecksum))) {
3255       PLOG(ERROR) << "Failed to write dex file location checksum. File: "
3256                   << vdex_out->GetLocation();
3257       return false;
3258     }
3259     size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
3260   }
3261 
3262   // Write header.
3263   actual_offset = vdex_out->Seek(0, kSeekSet);
3264   if (actual_offset != 0) {
3265     PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
3266                 << " File: " << vdex_out->GetLocation();
3267     return false;
3268   }
3269 
3270   DCHECK_NE(vdex_dex_files_offset_, 0u);
3271   DCHECK_NE(vdex_verifier_deps_offset_, 0u);
3272 
3273   size_t dex_section_size = vdex_verifier_deps_offset_ - vdex_dex_files_offset_;
3274   size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
3275   size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
3276 
3277   VdexFile::Header vdex_header(oat_dex_files_.size(),
3278                                dex_section_size,
3279                                verifier_deps_section_size,
3280                                quickening_info_section_size);
3281   if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
3282     PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
3283     return false;
3284   }
3285   size_vdex_header_ = sizeof(VdexFile::Header);
3286 
3287   if (!vdex_out->Flush()) {
3288     PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
3289                 << " File: " << vdex_out->GetLocation();
3290     return false;
3291   }
3292 
3293   return true;
3294 }
3295 
WriteCodeAlignment(OutputStream * out,uint32_t aligned_code_delta)3296 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
3297   return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_);
3298 }
3299 
WriteUpTo16BytesAlignment(OutputStream * out,uint32_t size,uint32_t * stat)3300 bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) {
3301   static const uint8_t kPadding[] = {
3302       0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
3303   };
3304   DCHECK_LE(size, sizeof(kPadding));
3305   if (UNLIKELY(!out->WriteFully(kPadding, size))) {
3306     return false;
3307   }
3308   *stat += size;
3309   return true;
3310 }
3311 
SetMultiOatRelativePatcherAdjustment()3312 void OatWriter::SetMultiOatRelativePatcherAdjustment() {
3313   DCHECK(dex_files_ != nullptr);
3314   DCHECK(relative_patcher_ != nullptr);
3315   DCHECK_NE(oat_data_offset_, 0u);
3316   if (image_writer_ != nullptr && !dex_files_->empty()) {
3317     // The oat data begin may not be initialized yet but the oat file offset is ready.
3318     size_t oat_index = image_writer_->GetOatIndexForDexFile(dex_files_->front());
3319     size_t elf_file_offset = image_writer_->GetOatFileOffset(oat_index);
3320     relative_patcher_->StartOatFile(elf_file_offset + oat_data_offset_);
3321   }
3322 }
3323 
OatDexFile(const char * dex_file_location,DexFileSource source,CreateTypeLookupTable create_type_lookup_table)3324 OatWriter::OatDexFile::OatDexFile(const char* dex_file_location,
3325                                   DexFileSource source,
3326                                   CreateTypeLookupTable create_type_lookup_table)
3327     : source_(source),
3328       create_type_lookup_table_(create_type_lookup_table),
3329       dex_file_size_(0),
3330       offset_(0),
3331       dex_file_location_size_(strlen(dex_file_location)),
3332       dex_file_location_data_(dex_file_location),
3333       dex_file_location_checksum_(0u),
3334       dex_file_offset_(0u),
3335       class_offsets_offset_(0u),
3336       lookup_table_offset_(0u),
3337       method_bss_mapping_offset_(0u),
3338       dex_sections_layout_offset_(0u),
3339       class_offsets_() {
3340 }
3341 
SizeOf() const3342 size_t OatWriter::OatDexFile::SizeOf() const {
3343   return sizeof(dex_file_location_size_)
3344           + dex_file_location_size_
3345           + sizeof(dex_file_location_checksum_)
3346           + sizeof(dex_file_offset_)
3347           + sizeof(class_offsets_offset_)
3348           + sizeof(lookup_table_offset_)
3349           + sizeof(method_bss_mapping_offset_)
3350           + sizeof(dex_sections_layout_offset_);
3351 }
3352 
Write(OatWriter * oat_writer,OutputStream * out) const3353 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
3354   const size_t file_offset = oat_writer->oat_data_offset_;
3355   DCHECK_OFFSET_();
3356 
3357   if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
3358     PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
3359     return false;
3360   }
3361   oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
3362 
3363   if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
3364     PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
3365     return false;
3366   }
3367   oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
3368 
3369   if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
3370     PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
3371     return false;
3372   }
3373   oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
3374 
3375   if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
3376     PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
3377     return false;
3378   }
3379   oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
3380 
3381   if (!out->WriteFully(&class_offsets_offset_, sizeof(class_offsets_offset_))) {
3382     PLOG(ERROR) << "Failed to write class offsets offset to " << out->GetLocation();
3383     return false;
3384   }
3385   oat_writer->size_oat_dex_file_class_offsets_offset_ += sizeof(class_offsets_offset_);
3386 
3387   if (!out->WriteFully(&lookup_table_offset_, sizeof(lookup_table_offset_))) {
3388     PLOG(ERROR) << "Failed to write lookup table offset to " << out->GetLocation();
3389     return false;
3390   }
3391   oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_);
3392 
3393   if (!out->WriteFully(&dex_sections_layout_offset_, sizeof(dex_sections_layout_offset_))) {
3394     PLOG(ERROR) << "Failed to write dex section layout info to " << out->GetLocation();
3395     return false;
3396   }
3397   oat_writer->size_oat_dex_file_dex_layout_sections_offset_ += sizeof(dex_sections_layout_offset_);
3398 
3399   if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) {
3400     PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation();
3401     return false;
3402   }
3403   oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_);
3404 
3405   return true;
3406 }
3407 
WriteClassOffsets(OatWriter * oat_writer,OutputStream * out)3408 bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) {
3409   if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) {
3410     PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation()
3411                 << " to " << out->GetLocation();
3412     return false;
3413   }
3414   oat_writer->size_oat_class_offsets_ += GetClassOffsetsRawSize();
3415   return true;
3416 }
3417 
OatClass(const dchecked_vector<CompiledMethod * > & compiled_methods,uint32_t compiled_methods_with_code,uint16_t oat_class_type)3418 OatWriter::OatClass::OatClass(const dchecked_vector<CompiledMethod*>& compiled_methods,
3419                               uint32_t compiled_methods_with_code,
3420                               uint16_t oat_class_type)
3421     : compiled_methods_(compiled_methods) {
3422   const uint32_t num_methods = compiled_methods.size();
3423   CHECK_LE(compiled_methods_with_code, num_methods);
3424 
3425   oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
3426 
3427   method_offsets_.resize(compiled_methods_with_code);
3428   method_headers_.resize(compiled_methods_with_code);
3429 
3430   uint32_t oat_method_offsets_offset_from_oat_class = OatClassHeader::SizeOf();
3431   // We only create this instance if there are at least some compiled.
3432   if (oat_class_type == kOatClassSomeCompiled) {
3433     method_bitmap_.reset(new BitVector(num_methods, false, Allocator::GetMallocAllocator()));
3434     method_bitmap_size_ = method_bitmap_->GetSizeOf();
3435     oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
3436     oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
3437   } else {
3438     method_bitmap_ = nullptr;
3439     method_bitmap_size_ = 0;
3440   }
3441 
3442   for (size_t i = 0; i < num_methods; i++) {
3443     CompiledMethod* compiled_method = compiled_methods_[i];
3444     if (HasCompiledCode(compiled_method)) {
3445       oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
3446       oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
3447       if (oat_class_type == kOatClassSomeCompiled) {
3448         method_bitmap_->SetBit(i);
3449       }
3450     } else {
3451       oat_method_offsets_offsets_from_oat_class_[i] = 0;
3452     }
3453   }
3454 }
3455 
SizeOf() const3456 size_t OatWriter::OatClass::SizeOf() const {
3457   return ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
3458           + method_bitmap_size_
3459           + (sizeof(method_offsets_[0]) * method_offsets_.size());
3460 }
3461 
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const3462 bool OatWriter::OatClassHeader::Write(OatWriter* oat_writer,
3463                                       OutputStream* out,
3464                                       const size_t file_offset) const {
3465   DCHECK_OFFSET_();
3466   if (!out->WriteFully(&status_, sizeof(status_))) {
3467     PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
3468     return false;
3469   }
3470   oat_writer->size_oat_class_status_ += sizeof(status_);
3471 
3472   if (!out->WriteFully(&type_, sizeof(type_))) {
3473     PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
3474     return false;
3475   }
3476   oat_writer->size_oat_class_type_ += sizeof(type_);
3477   return true;
3478 }
3479 
Write(OatWriter * oat_writer,OutputStream * out) const3480 bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const {
3481   if (method_bitmap_size_ != 0) {
3482     if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
3483       PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
3484       return false;
3485     }
3486     oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
3487 
3488     if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
3489       PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
3490       return false;
3491     }
3492     oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
3493   }
3494 
3495   if (!out->WriteFully(method_offsets_.data(), GetMethodOffsetsRawSize())) {
3496     PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
3497     return false;
3498   }
3499   oat_writer->size_oat_class_method_offsets_ += GetMethodOffsetsRawSize();
3500   return true;
3501 }
3502 
3503 }  // namespace art
3504