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 <zlib.h>
20 
21 #include "arch/arm64/instruction_set_features_arm64.h"
22 #include "art_method-inl.h"
23 #include "base/allocator.h"
24 #include "base/bit_vector.h"
25 #include "base/stl_util.h"
26 #include "base/unix_file/fd_file.h"
27 #include "class_linker.h"
28 #include "compiled_class.h"
29 #include "compiled_method.h"
30 #include "dex_file-inl.h"
31 #include "dex/verification_results.h"
32 #include "driver/compiler_driver.h"
33 #include "driver/compiler_options.h"
34 #include "gc/space/space.h"
35 #include "image_writer.h"
36 #include "linker/relative_patcher.h"
37 #include "mirror/array.h"
38 #include "mirror/class_loader.h"
39 #include "mirror/dex_cache-inl.h"
40 #include "mirror/object-inl.h"
41 #include "os.h"
42 #include "output_stream.h"
43 #include "safe_map.h"
44 #include "scoped_thread_state_change.h"
45 #include "handle_scope-inl.h"
46 #include "verifier/method_verifier.h"
47 
48 namespace art {
49 
50 #define DCHECK_OFFSET() \
51   DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \
52     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
53 
54 #define DCHECK_OFFSET_() \
55   DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
56     << "file_offset=" << file_offset << " offset_=" << offset_
57 
OatWriter(const std::vector<const DexFile * > & dex_files,uint32_t image_file_location_oat_checksum,uintptr_t image_file_location_oat_begin,int32_t image_patch_delta,const CompilerDriver * compiler,ImageWriter * image_writer,TimingLogger * timings,SafeMap<std::string,std::string> * key_value_store)58 OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
59                      uint32_t image_file_location_oat_checksum,
60                      uintptr_t image_file_location_oat_begin,
61                      int32_t image_patch_delta,
62                      const CompilerDriver* compiler,
63                      ImageWriter* image_writer,
64                      TimingLogger* timings,
65                      SafeMap<std::string, std::string>* key_value_store)
66   : compiler_driver_(compiler),
67     image_writer_(image_writer),
68     dex_files_(&dex_files),
69     size_(0u),
70     bss_size_(0u),
71     oat_data_offset_(0u),
72     image_file_location_oat_checksum_(image_file_location_oat_checksum),
73     image_file_location_oat_begin_(image_file_location_oat_begin),
74     image_patch_delta_(image_patch_delta),
75     key_value_store_(key_value_store),
76     oat_header_(nullptr),
77     size_dex_file_alignment_(0),
78     size_executable_offset_alignment_(0),
79     size_oat_header_(0),
80     size_oat_header_key_value_store_(0),
81     size_dex_file_(0),
82     size_interpreter_to_interpreter_bridge_(0),
83     size_interpreter_to_compiled_code_bridge_(0),
84     size_jni_dlsym_lookup_(0),
85     size_quick_generic_jni_trampoline_(0),
86     size_quick_imt_conflict_trampoline_(0),
87     size_quick_resolution_trampoline_(0),
88     size_quick_to_interpreter_bridge_(0),
89     size_trampoline_alignment_(0),
90     size_method_header_(0),
91     size_code_(0),
92     size_code_alignment_(0),
93     size_relative_call_thunks_(0),
94     size_misc_thunks_(0),
95     size_mapping_table_(0),
96     size_vmap_table_(0),
97     size_gc_map_(0),
98     size_oat_dex_file_location_size_(0),
99     size_oat_dex_file_location_data_(0),
100     size_oat_dex_file_location_checksum_(0),
101     size_oat_dex_file_offset_(0),
102     size_oat_dex_file_methods_offsets_(0),
103     size_oat_class_type_(0),
104     size_oat_class_status_(0),
105     size_oat_class_method_bitmaps_(0),
106     size_oat_class_method_offsets_(0),
107     method_offset_map_() {
108   CHECK(key_value_store != nullptr);
109 
110   InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
111   const InstructionSetFeatures* features = compiler_driver_->GetInstructionSetFeatures();
112   relative_patcher_ = linker::RelativePatcher::Create(instruction_set, features,
113                                                       &method_offset_map_);
114 
115   size_t offset;
116   {
117     TimingLogger::ScopedTiming split("InitOatHeader", timings);
118     offset = InitOatHeader();
119   }
120   {
121     TimingLogger::ScopedTiming split("InitOatDexFiles", timings);
122     offset = InitOatDexFiles(offset);
123   }
124   {
125     TimingLogger::ScopedTiming split("InitDexFiles", timings);
126     offset = InitDexFiles(offset);
127   }
128   {
129     TimingLogger::ScopedTiming split("InitOatClasses", timings);
130     offset = InitOatClasses(offset);
131   }
132   {
133     TimingLogger::ScopedTiming split("InitOatMaps", timings);
134     offset = InitOatMaps(offset);
135   }
136   {
137     TimingLogger::ScopedTiming split("InitOatCode", timings);
138     offset = InitOatCode(offset);
139   }
140   {
141     TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings);
142     offset = InitOatCodeDexFiles(offset);
143   }
144   size_ = offset;
145 
146   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
147   CHECK_EQ(compiler->IsImage(), image_writer_ != nullptr);
148   CHECK_EQ(compiler->IsImage(),
149            key_value_store_->find(OatHeader::kImageLocationKey) == key_value_store_->end());
150   CHECK_ALIGNED(image_patch_delta_, kPageSize);
151 }
152 
~OatWriter()153 OatWriter::~OatWriter() {
154   delete oat_header_;
155   STLDeleteElements(&oat_dex_files_);
156   STLDeleteElements(&oat_classes_);
157 }
158 
159 struct OatWriter::GcMapDataAccess {
GetDataart::OatWriter::GcMapDataAccess160   static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
161     return compiled_method->GetGcMap();
162   }
163 
GetOffsetart::OatWriter::GcMapDataAccess164   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
165     uint32_t offset = oat_class->method_headers_[method_offsets_index].gc_map_offset_;
166     return offset == 0u ? 0u :
167         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
168   }
169 
SetOffsetart::OatWriter::GcMapDataAccess170   static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
171       ALWAYS_INLINE {
172     oat_class->method_headers_[method_offsets_index].gc_map_offset_ =
173         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
174   }
175 
Nameart::OatWriter::GcMapDataAccess176   static const char* Name() {
177     return "GC map";
178   }
179 };
180 
181 struct OatWriter::MappingTableDataAccess {
GetDataart::OatWriter::MappingTableDataAccess182   static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
183     return compiled_method->GetMappingTable();
184   }
185 
GetOffsetart::OatWriter::MappingTableDataAccess186   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
187     uint32_t offset = oat_class->method_headers_[method_offsets_index].mapping_table_offset_;
188     return offset == 0u ? 0u :
189         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
190   }
191 
SetOffsetart::OatWriter::MappingTableDataAccess192   static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
193       ALWAYS_INLINE {
194     oat_class->method_headers_[method_offsets_index].mapping_table_offset_ =
195         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
196   }
197 
Nameart::OatWriter::MappingTableDataAccess198   static const char* Name() {
199     return "mapping table";
200   }
201 };
202 
203 struct OatWriter::VmapTableDataAccess {
GetDataart::OatWriter::VmapTableDataAccess204   static const SwapVector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE {
205     return compiled_method->GetVmapTable();
206   }
207 
GetOffsetart::OatWriter::VmapTableDataAccess208   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
209     uint32_t offset = oat_class->method_headers_[method_offsets_index].vmap_table_offset_;
210     return offset == 0u ? 0u :
211         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
212   }
213 
SetOffsetart::OatWriter::VmapTableDataAccess214   static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
215       ALWAYS_INLINE {
216     oat_class->method_headers_[method_offsets_index].vmap_table_offset_ =
217         (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
218   }
219 
Nameart::OatWriter::VmapTableDataAccess220   static const char* Name() {
221     return "vmap table";
222   }
223 };
224 
225 class OatWriter::DexMethodVisitor {
226  public:
DexMethodVisitor(OatWriter * writer,size_t offset)227   DexMethodVisitor(OatWriter* writer, size_t offset)
228     : writer_(writer),
229       offset_(offset),
230       dex_file_(nullptr),
231       class_def_index_(DexFile::kDexNoIndex) {
232   }
233 
StartClass(const DexFile * dex_file,size_t class_def_index)234   virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) {
235     DCHECK(dex_file_ == nullptr);
236     DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex);
237     dex_file_ = dex_file;
238     class_def_index_ = class_def_index;
239     return true;
240   }
241 
242   virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0;
243 
EndClass()244   virtual bool EndClass() {
245     if (kIsDebugBuild) {
246       dex_file_ = nullptr;
247       class_def_index_ = DexFile::kDexNoIndex;
248     }
249     return true;
250   }
251 
GetOffset() const252   size_t GetOffset() const {
253     return offset_;
254   }
255 
256  protected:
~DexMethodVisitor()257   virtual ~DexMethodVisitor() { }
258 
259   OatWriter* const writer_;
260 
261   // The offset is usually advanced for each visited method by the derived class.
262   size_t offset_;
263 
264   // The dex file and class def index are set in StartClass().
265   const DexFile* dex_file_;
266   size_t class_def_index_;
267 };
268 
269 class OatWriter::OatDexMethodVisitor : public DexMethodVisitor {
270  public:
OatDexMethodVisitor(OatWriter * writer,size_t offset)271   OatDexMethodVisitor(OatWriter* writer, size_t offset)
272     : DexMethodVisitor(writer, offset),
273       oat_class_index_(0u),
274       method_offsets_index_(0u) {
275   }
276 
StartClass(const DexFile * dex_file,size_t class_def_index)277   bool StartClass(const DexFile* dex_file, size_t class_def_index) {
278     DexMethodVisitor::StartClass(dex_file, class_def_index);
279     DCHECK_LT(oat_class_index_, writer_->oat_classes_.size());
280     method_offsets_index_ = 0u;
281     return true;
282   }
283 
EndClass()284   bool EndClass() {
285     ++oat_class_index_;
286     return DexMethodVisitor::EndClass();
287   }
288 
289  protected:
290   size_t oat_class_index_;
291   size_t method_offsets_index_;
292 };
293 
294 class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor {
295  public:
InitOatClassesMethodVisitor(OatWriter * writer,size_t offset)296   InitOatClassesMethodVisitor(OatWriter* writer, size_t offset)
297     : DexMethodVisitor(writer, offset),
298       compiled_methods_(),
299       num_non_null_compiled_methods_(0u) {
300     compiled_methods_.reserve(256u);
301   }
302 
StartClass(const DexFile * dex_file,size_t class_def_index)303   bool StartClass(const DexFile* dex_file, size_t class_def_index) {
304     DexMethodVisitor::StartClass(dex_file, class_def_index);
305     compiled_methods_.clear();
306     num_non_null_compiled_methods_ = 0u;
307     return true;
308   }
309 
VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED,const ClassDataItemIterator & it)310   bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, const ClassDataItemIterator& it) {
311     // Fill in the compiled_methods_ array for methods that have a
312     // CompiledMethod. We track the number of non-null entries in
313     // num_non_null_compiled_methods_ since we only want to allocate
314     // OatMethodOffsets for the compiled methods.
315     uint32_t method_idx = it.GetMemberIndex();
316     CompiledMethod* compiled_method =
317         writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx));
318     compiled_methods_.push_back(compiled_method);
319     if (compiled_method != nullptr) {
320         ++num_non_null_compiled_methods_;
321     }
322     return true;
323   }
324 
EndClass()325   bool EndClass() {
326     ClassReference class_ref(dex_file_, class_def_index_);
327     CompiledClass* compiled_class = writer_->compiler_driver_->GetCompiledClass(class_ref);
328     mirror::Class::Status status;
329     if (compiled_class != nullptr) {
330       status = compiled_class->GetStatus();
331     } else if (writer_->compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) {
332       status = mirror::Class::kStatusError;
333     } else {
334       status = mirror::Class::kStatusNotReady;
335     }
336 
337     OatClass* oat_class = new OatClass(offset_, compiled_methods_,
338                                        num_non_null_compiled_methods_, status);
339     writer_->oat_classes_.push_back(oat_class);
340     oat_class->UpdateChecksum(writer_->oat_header_);
341     offset_ += oat_class->SizeOf();
342     return DexMethodVisitor::EndClass();
343   }
344 
345  private:
346   std::vector<CompiledMethod*> compiled_methods_;
347   size_t num_non_null_compiled_methods_;
348 };
349 
350 class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
351  public:
InitCodeMethodVisitor(OatWriter * writer,size_t offset)352   InitCodeMethodVisitor(OatWriter* writer, size_t offset)
353     : OatDexMethodVisitor(writer, offset),
354       debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()) {
355     writer_->absolute_patch_locations_.reserve(
356         writer_->compiler_driver_->GetNonRelativeLinkerPatchCount());
357   }
358 
EndClass()359   bool EndClass() {
360     OatDexMethodVisitor::EndClass();
361     if (oat_class_index_ == writer_->oat_classes_.size()) {
362       offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_);
363     }
364     return true;
365   }
366 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)367   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
368       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
369     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
370     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
371 
372     if (compiled_method != nullptr) {
373       // Derived from CompiledMethod.
374       uint32_t quick_code_offset = 0;
375 
376       const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
377       CHECK(quick_code != nullptr);
378       uint32_t code_size = quick_code->size() * sizeof(uint8_t);
379       CHECK_NE(code_size, 0U);
380       uint32_t thumb_offset = compiled_method->CodeDelta();
381 
382       // Deduplicate code arrays if we are not producing debuggable code.
383       bool deduped = false;
384       if (debuggable_) {
385         quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
386       } else {
387         auto lb = dedupe_map_.lower_bound(compiled_method);
388         if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(compiled_method, lb->first)) {
389           quick_code_offset = lb->second;
390           deduped = true;
391         } else {
392           quick_code_offset = NewQuickCodeOffset(compiled_method, it, thumb_offset);
393           dedupe_map_.PutBefore(lb, compiled_method, quick_code_offset);
394         }
395       }
396 
397       MethodReference method_ref(dex_file_, it.GetMemberIndex());
398       auto method_lb = writer_->method_offset_map_.map.lower_bound(method_ref);
399       if (method_lb != writer_->method_offset_map_.map.end() &&
400           !writer_->method_offset_map_.map.key_comp()(method_ref, method_lb->first)) {
401         // TODO: Should this be a hard failure?
402         LOG(WARNING) << "Multiple definitions of "
403             << PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file)
404             << ((method_lb->second != quick_code_offset) ? "; OFFSET MISMATCH" : "");
405       } else {
406         writer_->method_offset_map_.map.PutBefore(method_lb, method_ref, quick_code_offset);
407       }
408 
409       // Update quick method header.
410       DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
411       OatQuickMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
412       uint32_t mapping_table_offset = method_header->mapping_table_offset_;
413       uint32_t vmap_table_offset = method_header->vmap_table_offset_;
414       uint32_t gc_map_offset = method_header->gc_map_offset_;
415       // The code offset was 0 when the mapping/vmap table offset was set, so it's set
416       // to 0-offset and we need to adjust it by code_offset.
417       uint32_t code_offset = quick_code_offset - thumb_offset;
418       if (mapping_table_offset != 0u) {
419         mapping_table_offset += code_offset;
420         DCHECK_LT(mapping_table_offset, code_offset);
421       }
422       if (vmap_table_offset != 0u) {
423         vmap_table_offset += code_offset;
424         DCHECK_LT(vmap_table_offset, code_offset);
425       }
426       if (gc_map_offset != 0u) {
427         gc_map_offset += code_offset;
428         DCHECK_LT(gc_map_offset, code_offset);
429       }
430       uint32_t frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
431       uint32_t core_spill_mask = compiled_method->GetCoreSpillMask();
432       uint32_t fp_spill_mask = compiled_method->GetFpSpillMask();
433       *method_header = OatQuickMethodHeader(mapping_table_offset, vmap_table_offset,
434                                             gc_map_offset, frame_size_in_bytes, core_spill_mask,
435                                             fp_spill_mask, code_size);
436 
437       if (!deduped) {
438         // Update offsets. (Checksum is updated when writing.)
439         offset_ += sizeof(*method_header);  // Method header is prepended before code.
440         offset_ += code_size;
441         // Record absolute patch locations.
442         if (!compiled_method->GetPatches().empty()) {
443           uintptr_t base_loc = offset_ - code_size - writer_->oat_header_->GetExecutableOffset();
444           for (const LinkerPatch& patch : compiled_method->GetPatches()) {
445             if (!patch.IsPcRelative()) {
446               writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset());
447             }
448           }
449         }
450       }
451 
452       if (writer_->compiler_driver_->GetCompilerOptions().GetGenerateDebugInfo()) {
453         // Record debug information for this function if we are doing that.
454         const uint32_t quick_code_start = quick_code_offset -
455             writer_->oat_header_->GetExecutableOffset() - thumb_offset;
456         writer_->method_info_.push_back(DebugInfo {
457             dex_file_,
458             class_def_index_,
459             it.GetMemberIndex(),
460             it.GetMethodAccessFlags(),
461             it.GetMethodCodeItem(),
462             deduped,
463             quick_code_start,
464             quick_code_start + code_size,
465             compiled_method});
466       }
467 
468       if (kIsDebugBuild) {
469         // We expect GC maps except when the class hasn't been verified or the method is native.
470         const CompilerDriver* compiler_driver = writer_->compiler_driver_;
471         ClassReference class_ref(dex_file_, class_def_index_);
472         CompiledClass* compiled_class = compiler_driver->GetCompiledClass(class_ref);
473         mirror::Class::Status status;
474         if (compiled_class != nullptr) {
475           status = compiled_class->GetStatus();
476         } else if (compiler_driver->GetVerificationResults()->IsClassRejected(class_ref)) {
477           status = mirror::Class::kStatusError;
478         } else {
479           status = mirror::Class::kStatusNotReady;
480         }
481         const SwapVector<uint8_t>* gc_map = compiled_method->GetGcMap();
482         if (gc_map != nullptr) {
483           size_t gc_map_size = gc_map->size() * sizeof(gc_map[0]);
484           bool is_native = it.MemberIsNative();
485           CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
486               << gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
487               << (status < mirror::Class::kStatusVerified) << " " << status << " "
488               << PrettyMethod(it.GetMemberIndex(), *dex_file_);
489         }
490       }
491 
492       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
493       OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_];
494       offsets->code_offset_ = quick_code_offset;
495       ++method_offsets_index_;
496     }
497 
498     return true;
499   }
500 
501  private:
502   struct CodeOffsetsKeyComparator {
operator ()art::OatWriter::InitCodeMethodVisitor::CodeOffsetsKeyComparator503     bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
504       if (lhs->GetQuickCode() != rhs->GetQuickCode()) {
505         return lhs->GetQuickCode() < rhs->GetQuickCode();
506       }
507       // If the code is the same, all other fields are likely to be the same as well.
508       if (UNLIKELY(lhs->GetMappingTable() != rhs->GetMappingTable())) {
509         return lhs->GetMappingTable() < rhs->GetMappingTable();
510       }
511       if (UNLIKELY(lhs->GetVmapTable() != rhs->GetVmapTable())) {
512         return lhs->GetVmapTable() < rhs->GetVmapTable();
513       }
514       if (UNLIKELY(lhs->GetGcMap() != rhs->GetGcMap())) {
515         return lhs->GetGcMap() < rhs->GetGcMap();
516       }
517       const auto& lhs_patches = lhs->GetPatches();
518       const auto& rhs_patches = rhs->GetPatches();
519       if (UNLIKELY(lhs_patches.size() != rhs_patches.size())) {
520         return lhs_patches.size() < rhs_patches.size();
521       }
522       auto rit = rhs_patches.begin();
523       for (const LinkerPatch& lpatch : lhs_patches) {
524         if (UNLIKELY(!(lpatch == *rit))) {
525           return lpatch < *rit;
526         }
527         ++rit;
528       }
529       return false;
530     }
531   };
532 
NewQuickCodeOffset(CompiledMethod * compiled_method,const ClassDataItemIterator & it,uint32_t thumb_offset)533   uint32_t NewQuickCodeOffset(CompiledMethod* compiled_method,
534                               const ClassDataItemIterator& it,
535                               uint32_t thumb_offset) {
536     offset_ = writer_->relative_patcher_->ReserveSpace(
537               offset_, compiled_method, MethodReference(dex_file_, it.GetMemberIndex()));
538     offset_ = compiled_method->AlignCode(offset_);
539     DCHECK_ALIGNED_PARAM(offset_,
540                          GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
541     return offset_ + sizeof(OatQuickMethodHeader) + thumb_offset;
542   }
543 
544   // Deduplication is already done on a pointer basis by the compiler driver,
545   // so we can simply compare the pointers to find out if things are duplicated.
546   SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
547 
548   // Cache of compiler's --debuggable option.
549   const bool debuggable_;
550 };
551 
552 template <typename DataAccess>
553 class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor {
554  public:
InitMapMethodVisitor(OatWriter * writer,size_t offset)555   InitMapMethodVisitor(OatWriter* writer, size_t offset)
556     : OatDexMethodVisitor(writer, offset) {
557   }
558 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it ATTRIBUTE_UNUSED)559   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED)
560       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
561     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
562     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
563 
564     if (compiled_method != nullptr) {
565       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
566       DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u);
567 
568       const SwapVector<uint8_t>* map = DataAccess::GetData(compiled_method);
569       uint32_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
570       if (map_size != 0u) {
571         auto lb = dedupe_map_.lower_bound(map);
572         if (lb != dedupe_map_.end() && !dedupe_map_.key_comp()(map, lb->first)) {
573           DataAccess::SetOffset(oat_class, method_offsets_index_, lb->second);
574         } else {
575           DataAccess::SetOffset(oat_class, method_offsets_index_, offset_);
576           dedupe_map_.PutBefore(lb, map, offset_);
577           offset_ += map_size;
578           writer_->oat_header_->UpdateChecksum(&(*map)[0], map_size);
579         }
580       }
581       ++method_offsets_index_;
582     }
583 
584     return true;
585   }
586 
587  private:
588   // Deduplication is already done on a pointer basis by the compiler driver,
589   // so we can simply compare the pointers to find out if things are duplicated.
590   SafeMap<const SwapVector<uint8_t>*, uint32_t> dedupe_map_;
591 };
592 
593 class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor {
594  public:
InitImageMethodVisitor(OatWriter * writer,size_t offset)595   InitImageMethodVisitor(OatWriter* writer, size_t offset)
596     : OatDexMethodVisitor(writer, offset),
597       pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())) {
598   }
599 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)600   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
601       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
602     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
603     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
604 
605     OatMethodOffsets offsets(0u);
606     if (compiled_method != nullptr) {
607       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
608       offsets = oat_class->method_offsets_[method_offsets_index_];
609       ++method_offsets_index_;
610     }
611 
612     ClassLinker* linker = Runtime::Current()->GetClassLinker();
613     InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_));
614     // Unchecked as we hold mutator_lock_ on entry.
615     ScopedObjectAccessUnchecked soa(Thread::Current());
616     StackHandleScope<1> hs(soa.Self());
617     Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file_)));
618     ArtMethod* method = linker->ResolveMethod(
619         *dex_file_, it.GetMemberIndex(), dex_cache, NullHandle<mirror::ClassLoader>(), nullptr,
620         invoke_type);
621     if (method == nullptr) {
622       LOG(ERROR) << "Unexpected failure to resolve a method: "
623                  << PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
624       soa.Self()->AssertPendingException();
625       mirror::Throwable* exc = soa.Self()->GetException();
626       std::string dump = exc->Dump();
627       LOG(FATAL) << dump;
628     }
629     method->SetEntryPointFromQuickCompiledCodePtrSize(reinterpret_cast<void*>(offsets.code_offset_),
630                                                       pointer_size_);
631 
632     return true;
633   }
634 
635  protected:
636   const size_t pointer_size_;
637 };
638 
639 class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
640  public:
WriteCodeMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)641   WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
642                          size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
643     : OatDexMethodVisitor(writer, relative_offset),
644       out_(out),
645       file_offset_(file_offset),
646       soa_(Thread::Current()),
647       no_thread_suspension_(soa_.Self(), "OatWriter patching"),
648       class_linker_(Runtime::Current()->GetClassLinker()),
649       dex_cache_(nullptr) {
650     if (writer_->image_writer_ != nullptr) {
651       // If we're creating the image, the address space must be ready so that we can apply patches.
652       CHECK(writer_->image_writer_->IsImageAddressSpaceReady());
653       patched_code_.reserve(16 * KB);
654     }
655   }
656 
UNLOCK_FUNCTION(Locks::mutator_lock_)657   ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) {
658   }
659 
StartClass(const DexFile * dex_file,size_t class_def_index)660   bool StartClass(const DexFile* dex_file, size_t class_def_index)
661       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
662     OatDexMethodVisitor::StartClass(dex_file, class_def_index);
663     if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) {
664       dex_cache_ = class_linker_->FindDexCache(*dex_file);
665     }
666     return true;
667   }
668 
EndClass()669   bool EndClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
670     bool result = OatDexMethodVisitor::EndClass();
671     if (oat_class_index_ == writer_->oat_classes_.size()) {
672       DCHECK(result);  // OatDexMethodVisitor::EndClass() never fails.
673       offset_ = writer_->relative_patcher_->WriteThunks(out_, offset_);
674       if (UNLIKELY(offset_ == 0u)) {
675         PLOG(ERROR) << "Failed to write final relative call thunks";
676         result = false;
677       }
678     }
679     return result;
680   }
681 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)682   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it)
683       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
684     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
685     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
686 
687     if (compiled_method != nullptr) {  // ie. not an abstract method
688       size_t file_offset = file_offset_;
689       OutputStream* out = out_;
690 
691       const SwapVector<uint8_t>* quick_code = compiled_method->GetQuickCode();
692       if (quick_code != nullptr) {
693         // Need a wrapper if we create a copy for patching.
694         ArrayRef<const uint8_t> wrapped(*quick_code);
695         uint32_t code_size = quick_code->size() * sizeof(uint8_t);
696         CHECK_NE(code_size, 0U);
697 
698         // Deduplicate code arrays.
699         const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_];
700         if (method_offsets.code_offset_ >= offset_) {
701           offset_ = writer_->relative_patcher_->WriteThunks(out, offset_);
702           if (offset_ == 0u) {
703             ReportWriteFailure("relative call thunk", it);
704             return false;
705           }
706           uint32_t aligned_offset = compiled_method->AlignCode(offset_);
707           uint32_t aligned_code_delta = aligned_offset - offset_;
708           if (aligned_code_delta != 0) {
709             if (!writer_->WriteCodeAlignment(out, aligned_code_delta)) {
710               ReportWriteFailure("code alignment padding", it);
711               return false;
712             }
713             offset_ += aligned_code_delta;
714             DCHECK_OFFSET_();
715           }
716           DCHECK_ALIGNED_PARAM(offset_,
717                                GetInstructionSetAlignment(compiled_method->GetInstructionSet()));
718           DCHECK_EQ(method_offsets.code_offset_,
719                     offset_ + sizeof(OatQuickMethodHeader) + compiled_method->CodeDelta())
720               << PrettyMethod(it.GetMemberIndex(), *dex_file_);
721           const OatQuickMethodHeader& method_header =
722               oat_class->method_headers_[method_offsets_index_];
723           writer_->oat_header_->UpdateChecksum(&method_header, sizeof(method_header));
724           if (!out->WriteFully(&method_header, sizeof(method_header))) {
725             ReportWriteFailure("method header", it);
726             return false;
727           }
728           writer_->size_method_header_ += sizeof(method_header);
729           offset_ += sizeof(method_header);
730           DCHECK_OFFSET_();
731 
732           if (!compiled_method->GetPatches().empty()) {
733             patched_code_.assign(quick_code->begin(), quick_code->end());
734             wrapped = ArrayRef<const uint8_t>(patched_code_);
735             for (const LinkerPatch& patch : compiled_method->GetPatches()) {
736               if (patch.Type() == kLinkerPatchCallRelative) {
737                 // NOTE: Relative calls across oat files are not supported.
738                 uint32_t target_offset = GetTargetOffset(patch);
739                 uint32_t literal_offset = patch.LiteralOffset();
740                 writer_->relative_patcher_->PatchCall(&patched_code_, literal_offset,
741                                                        offset_ + literal_offset, target_offset);
742               } else if (patch.Type() == kLinkerPatchDexCacheArray) {
743                 uint32_t target_offset = GetDexCacheOffset(patch);
744                 uint32_t literal_offset = patch.LiteralOffset();
745                 writer_->relative_patcher_->PatchDexCacheReference(&patched_code_, patch,
746                                                                    offset_ + literal_offset,
747                                                                    target_offset);
748               } else if (patch.Type() == kLinkerPatchCall) {
749                 uint32_t target_offset = GetTargetOffset(patch);
750                 PatchCodeAddress(&patched_code_, patch.LiteralOffset(), target_offset);
751               } else if (patch.Type() == kLinkerPatchMethod) {
752                 ArtMethod* method = GetTargetMethod(patch);
753                 PatchMethodAddress(&patched_code_, patch.LiteralOffset(), method);
754               } else if (patch.Type() == kLinkerPatchType) {
755                 mirror::Class* type = GetTargetType(patch);
756                 PatchObjectAddress(&patched_code_, patch.LiteralOffset(), type);
757               }
758             }
759           }
760 
761           writer_->oat_header_->UpdateChecksum(wrapped.data(), code_size);
762           if (!out->WriteFully(wrapped.data(), code_size)) {
763             ReportWriteFailure("method code", it);
764             return false;
765           }
766           writer_->size_code_ += code_size;
767           offset_ += code_size;
768         }
769         DCHECK_OFFSET_();
770       }
771       ++method_offsets_index_;
772     }
773 
774     return true;
775   }
776 
777  private:
778   OutputStream* const out_;
779   const size_t file_offset_;
780   const ScopedObjectAccess soa_;
781   const ScopedAssertNoThreadSuspension no_thread_suspension_;
782   ClassLinker* const class_linker_;
783   mirror::DexCache* dex_cache_;
784   std::vector<uint8_t> patched_code_;
785 
ReportWriteFailure(const char * what,const ClassDataItemIterator & it)786   void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) {
787     PLOG(ERROR) << "Failed to write " << what << " for "
788         << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation();
789   }
790 
GetTargetMethod(const LinkerPatch & patch)791   ArtMethod* GetTargetMethod(const LinkerPatch& patch)
792       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
793     MethodReference ref = patch.TargetMethod();
794     mirror::DexCache* dex_cache =
795         (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache(*ref.dex_file);
796     ArtMethod* method = dex_cache->GetResolvedMethod(
797         ref.dex_method_index, class_linker_->GetImagePointerSize());
798     CHECK(method != nullptr);
799     return method;
800   }
801 
GetTargetOffset(const LinkerPatch & patch)802   uint32_t GetTargetOffset(const LinkerPatch& patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
803     auto target_it = writer_->method_offset_map_.map.find(patch.TargetMethod());
804     uint32_t target_offset =
805         (target_it != writer_->method_offset_map_.map.end()) ? target_it->second : 0u;
806     // If there's no compiled code, point to the correct trampoline.
807     if (UNLIKELY(target_offset == 0)) {
808       ArtMethod* target = GetTargetMethod(patch);
809       DCHECK(target != nullptr);
810       size_t size = GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet());
811       const void* oat_code_offset = target->GetEntryPointFromQuickCompiledCodePtrSize(size);
812       if (oat_code_offset != 0) {
813         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset));
814         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(oat_code_offset));
815         DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickGenericJniStub(oat_code_offset));
816         target_offset = PointerToLowMemUInt32(oat_code_offset);
817       } else {
818         target_offset = target->IsNative()
819             ? writer_->oat_header_->GetQuickGenericJniTrampolineOffset()
820             : writer_->oat_header_->GetQuickToInterpreterBridgeOffset();
821       }
822     }
823     return target_offset;
824   }
825 
GetTargetType(const LinkerPatch & patch)826   mirror::Class* GetTargetType(const LinkerPatch& patch)
827       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
828     mirror::DexCache* dex_cache = (dex_file_ == patch.TargetTypeDexFile())
829         ? dex_cache_ : class_linker_->FindDexCache(*patch.TargetTypeDexFile());
830     mirror::Class* type = dex_cache->GetResolvedType(patch.TargetTypeIndex());
831     CHECK(type != nullptr);
832     return type;
833   }
834 
GetDexCacheOffset(const LinkerPatch & patch)835   uint32_t GetDexCacheOffset(const LinkerPatch& patch) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
836     if (writer_->image_writer_ != nullptr) {
837       auto* element = writer_->image_writer_->GetDexCacheArrayElementImageAddress(
838               patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset());
839       const uint8_t* oat_data = writer_->image_writer_->GetOatFileBegin() + file_offset_;
840       return reinterpret_cast<const uint8_t*>(element) - oat_data;
841     } else {
842       LOG(FATAL) << "Unimplemented.";
843       UNREACHABLE();
844     }
845   }
846 
PatchObjectAddress(std::vector<uint8_t> * code,uint32_t offset,mirror::Object * object)847   void PatchObjectAddress(std::vector<uint8_t>* code, uint32_t offset, mirror::Object* object)
848       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
849     // NOTE: Direct method pointers across oat files don't use linker patches. However, direct
850     // type pointers across oat files do. (TODO: Investigate why.)
851     if (writer_->image_writer_ != nullptr) {
852       object = writer_->image_writer_->GetImageAddress(object);
853     }
854     uint32_t address = PointerToLowMemUInt32(object);
855     DCHECK_LE(offset + 4, code->size());
856     uint8_t* data = &(*code)[offset];
857     data[0] = address & 0xffu;
858     data[1] = (address >> 8) & 0xffu;
859     data[2] = (address >> 16) & 0xffu;
860     data[3] = (address >> 24) & 0xffu;
861   }
862 
PatchMethodAddress(std::vector<uint8_t> * code,uint32_t offset,ArtMethod * method)863   void PatchMethodAddress(std::vector<uint8_t>* code, uint32_t offset, ArtMethod* method)
864       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
865     // NOTE: Direct method pointers across oat files don't use linker patches. However, direct
866     // type pointers across oat files do. (TODO: Investigate why.)
867     if (writer_->image_writer_ != nullptr) {
868       method = writer_->image_writer_->GetImageMethodAddress(method);
869     }
870     // Note: We only patch ArtMethods to low 4gb since thats where the image is.
871     uint32_t address = PointerToLowMemUInt32(method);
872     DCHECK_LE(offset + 4, code->size());
873     uint8_t* data = &(*code)[offset];
874     data[0] = address & 0xffu;
875     data[1] = (address >> 8) & 0xffu;
876     data[2] = (address >> 16) & 0xffu;
877     data[3] = (address >> 24) & 0xffu;
878   }
879 
PatchCodeAddress(std::vector<uint8_t> * code,uint32_t offset,uint32_t target_offset)880   void PatchCodeAddress(std::vector<uint8_t>* code, uint32_t offset, uint32_t target_offset)
881       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
882     uint32_t address = writer_->image_writer_ == nullptr ? target_offset :
883         PointerToLowMemUInt32(writer_->image_writer_->GetOatFileBegin() +
884                               writer_->oat_data_offset_ + target_offset);
885     DCHECK_LE(offset + 4, code->size());
886     uint8_t* data = &(*code)[offset];
887     data[0] = address & 0xffu;
888     data[1] = (address >> 8) & 0xffu;
889     data[2] = (address >> 16) & 0xffu;
890     data[3] = (address >> 24) & 0xffu;
891   }
892 };
893 
894 template <typename DataAccess>
895 class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
896  public:
WriteMapMethodVisitor(OatWriter * writer,OutputStream * out,const size_t file_offset,size_t relative_offset)897   WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset,
898                         size_t relative_offset)
899     : OatDexMethodVisitor(writer, relative_offset),
900       out_(out),
901       file_offset_(file_offset) {
902   }
903 
VisitMethod(size_t class_def_method_index,const ClassDataItemIterator & it)904   bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) {
905     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
906     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
907 
908     if (compiled_method != nullptr) {  // ie. not an abstract method
909       size_t file_offset = file_offset_;
910       OutputStream* out = out_;
911 
912       uint32_t map_offset = DataAccess::GetOffset(oat_class, method_offsets_index_);
913       ++method_offsets_index_;
914 
915       // Write deduplicated map.
916       const SwapVector<uint8_t>* map = DataAccess::GetData(compiled_method);
917       size_t map_size = map == nullptr ? 0 : map->size() * sizeof((*map)[0]);
918       DCHECK((map_size == 0u && map_offset == 0u) ||
919             (map_size != 0u && map_offset != 0u && map_offset <= offset_))
920           << map_size << " " << map_offset << " " << offset_ << " "
921           << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " for " << DataAccess::Name();
922       if (map_size != 0u && map_offset == offset_) {
923         if (UNLIKELY(!out->WriteFully(&(*map)[0], map_size))) {
924           ReportWriteFailure(it);
925           return false;
926         }
927         offset_ += map_size;
928       }
929       DCHECK_OFFSET_();
930     }
931 
932     return true;
933   }
934 
935  private:
936   OutputStream* const out_;
937   size_t const file_offset_;
938 
ReportWriteFailure(const ClassDataItemIterator & it)939   void ReportWriteFailure(const ClassDataItemIterator& it) {
940     PLOG(ERROR) << "Failed to write " << DataAccess::Name() << " for "
941         << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation();
942   }
943 };
944 
945 // Visit all methods from all classes in all dex files with the specified visitor.
VisitDexMethods(DexMethodVisitor * visitor)946 bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) {
947   for (const DexFile* dex_file : *dex_files_) {
948     const size_t class_def_count = dex_file->NumClassDefs();
949     for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) {
950       if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) {
951         return false;
952       }
953       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
954       const uint8_t* class_data = dex_file->GetClassData(class_def);
955       if (class_data != nullptr) {  // ie not an empty class, such as a marker interface
956         ClassDataItemIterator it(*dex_file, class_data);
957         while (it.HasNextStaticField()) {
958           it.Next();
959         }
960         while (it.HasNextInstanceField()) {
961           it.Next();
962         }
963         size_t class_def_method_index = 0u;
964         while (it.HasNextDirectMethod()) {
965           if (!visitor->VisitMethod(class_def_method_index, it)) {
966             return false;
967           }
968           ++class_def_method_index;
969           it.Next();
970         }
971         while (it.HasNextVirtualMethod()) {
972           if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) {
973             return false;
974           }
975           ++class_def_method_index;
976           it.Next();
977         }
978       }
979       if (UNLIKELY(!visitor->EndClass())) {
980         return false;
981       }
982     }
983   }
984   return true;
985 }
986 
InitOatHeader()987 size_t OatWriter::InitOatHeader() {
988   oat_header_ = OatHeader::Create(compiler_driver_->GetInstructionSet(),
989                                   compiler_driver_->GetInstructionSetFeatures(),
990                                   dex_files_,
991                                   image_file_location_oat_checksum_,
992                                   image_file_location_oat_begin_,
993                                   key_value_store_);
994 
995   return oat_header_->GetHeaderSize();
996 }
997 
InitOatDexFiles(size_t offset)998 size_t OatWriter::InitOatDexFiles(size_t offset) {
999   // create the OatDexFiles
1000   for (size_t i = 0; i != dex_files_->size(); ++i) {
1001     const DexFile* dex_file = (*dex_files_)[i];
1002     CHECK(dex_file != nullptr);
1003     OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file);
1004     oat_dex_files_.push_back(oat_dex_file);
1005     offset += oat_dex_file->SizeOf();
1006   }
1007   return offset;
1008 }
1009 
InitDexFiles(size_t offset)1010 size_t OatWriter::InitDexFiles(size_t offset) {
1011   // calculate the offsets within OatDexFiles to the DexFiles
1012   for (size_t i = 0; i != dex_files_->size(); ++i) {
1013     // dex files are required to be 4 byte aligned
1014     size_t original_offset = offset;
1015     offset = RoundUp(offset, 4);
1016     size_dex_file_alignment_ += offset - original_offset;
1017 
1018     // set offset in OatDexFile to DexFile
1019     oat_dex_files_[i]->dex_file_offset_ = offset;
1020 
1021     const DexFile* dex_file = (*dex_files_)[i];
1022     offset += dex_file->GetHeader().file_size_;
1023   }
1024   return offset;
1025 }
1026 
InitOatClasses(size_t offset)1027 size_t OatWriter::InitOatClasses(size_t offset) {
1028   // calculate the offsets within OatDexFiles to OatClasses
1029   InitOatClassesMethodVisitor visitor(this, offset);
1030   bool success = VisitDexMethods(&visitor);
1031   CHECK(success);
1032   offset = visitor.GetOffset();
1033 
1034   // Update oat_dex_files_.
1035   auto oat_class_it = oat_classes_.begin();
1036   for (OatDexFile* oat_dex_file : oat_dex_files_) {
1037     for (uint32_t& method_offset : oat_dex_file->methods_offsets_) {
1038       DCHECK(oat_class_it != oat_classes_.end());
1039       method_offset = (*oat_class_it)->offset_;
1040       ++oat_class_it;
1041     }
1042     oat_dex_file->UpdateChecksum(oat_header_);
1043   }
1044   CHECK(oat_class_it == oat_classes_.end());
1045 
1046   return offset;
1047 }
1048 
InitOatMaps(size_t offset)1049 size_t OatWriter::InitOatMaps(size_t offset) {
1050   #define VISIT(VisitorType)                          \
1051     do {                                              \
1052       VisitorType visitor(this, offset);              \
1053       bool success = VisitDexMethods(&visitor);       \
1054       DCHECK(success);                                \
1055       offset = visitor.GetOffset();                   \
1056     } while (false)
1057 
1058   VISIT(InitMapMethodVisitor<GcMapDataAccess>);
1059   VISIT(InitMapMethodVisitor<MappingTableDataAccess>);
1060   VISIT(InitMapMethodVisitor<VmapTableDataAccess>);
1061 
1062   #undef VISIT
1063 
1064   return offset;
1065 }
1066 
InitOatCode(size_t offset)1067 size_t OatWriter::InitOatCode(size_t offset) {
1068   // calculate the offsets within OatHeader to executable code
1069   size_t old_offset = offset;
1070   size_t adjusted_offset = offset;
1071   // required to be on a new page boundary
1072   offset = RoundUp(offset, kPageSize);
1073   oat_header_->SetExecutableOffset(offset);
1074   size_executable_offset_alignment_ = offset - old_offset;
1075   if (compiler_driver_->IsImage()) {
1076     CHECK_EQ(image_patch_delta_, 0);
1077     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
1078 
1079     #define DO_TRAMPOLINE(field, fn_name) \
1080       offset = CompiledCode::AlignCode(offset, instruction_set); \
1081       adjusted_offset = offset + CompiledCode::CodeDelta(instruction_set); \
1082       oat_header_->Set ## fn_name ## Offset(adjusted_offset); \
1083       field.reset(compiler_driver_->Create ## fn_name()); \
1084       offset += field->size();
1085 
1086     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_, InterpreterToInterpreterBridge);
1087     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_, InterpreterToCompiledCodeBridge);
1088     DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
1089     DO_TRAMPOLINE(quick_generic_jni_trampoline_, QuickGenericJniTrampoline);
1090     DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline);
1091     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
1092     DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
1093 
1094     #undef DO_TRAMPOLINE
1095   } else {
1096     oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
1097     oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
1098     oat_header_->SetJniDlsymLookupOffset(0);
1099     oat_header_->SetQuickGenericJniTrampolineOffset(0);
1100     oat_header_->SetQuickImtConflictTrampolineOffset(0);
1101     oat_header_->SetQuickResolutionTrampolineOffset(0);
1102     oat_header_->SetQuickToInterpreterBridgeOffset(0);
1103     oat_header_->SetImagePatchDelta(image_patch_delta_);
1104   }
1105   return offset;
1106 }
1107 
InitOatCodeDexFiles(size_t offset)1108 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
1109   #define VISIT(VisitorType)                          \
1110     do {                                              \
1111       VisitorType visitor(this, offset);              \
1112       bool success = VisitDexMethods(&visitor);       \
1113       DCHECK(success);                                \
1114       offset = visitor.GetOffset();                   \
1115     } while (false)
1116 
1117   VISIT(InitCodeMethodVisitor);
1118   if (compiler_driver_->IsImage()) {
1119     VISIT(InitImageMethodVisitor);
1120   }
1121 
1122   #undef VISIT
1123 
1124   return offset;
1125 }
1126 
WriteRodata(OutputStream * out)1127 bool OatWriter::WriteRodata(OutputStream* out) {
1128   const off_t raw_file_offset = out->Seek(0, kSeekCurrent);
1129   if (raw_file_offset == (off_t) -1) {
1130     LOG(ERROR) << "Failed to get file offset in " << out->GetLocation();
1131     return false;
1132   }
1133   const size_t file_offset = static_cast<size_t>(raw_file_offset);
1134   oat_data_offset_ = file_offset;
1135 
1136   // Reserve space for header. It will be written last - after updating the checksum.
1137   size_t header_size = oat_header_->GetHeaderSize();
1138   if (out->Seek(header_size, kSeekCurrent) == (off_t) -1) {
1139     PLOG(ERROR) << "Failed to reserve space for oat header in " << out->GetLocation();
1140     return false;
1141   }
1142   size_oat_header_ += sizeof(OatHeader);
1143   size_oat_header_key_value_store_ += oat_header_->GetHeaderSize() - sizeof(OatHeader);
1144 
1145   if (!WriteTables(out, file_offset)) {
1146     LOG(ERROR) << "Failed to write oat tables to " << out->GetLocation();
1147     return false;
1148   }
1149 
1150   off_t tables_end_offset = out->Seek(0, kSeekCurrent);
1151   if (tables_end_offset == (off_t) -1) {
1152     LOG(ERROR) << "Failed to seek to oat code position in " << out->GetLocation();
1153     return false;
1154   }
1155   size_t relative_offset = static_cast<size_t>(tables_end_offset) - file_offset;
1156   relative_offset = WriteMaps(out, file_offset, relative_offset);
1157   if (relative_offset == 0) {
1158     LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
1159     return false;
1160   }
1161 
1162   // Write padding.
1163   off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent);
1164   relative_offset += size_executable_offset_alignment_;
1165   DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());
1166   size_t expected_file_offset = file_offset + relative_offset;
1167   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
1168     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
1169                 << " Expected: " << expected_file_offset << " File: " << out->GetLocation();
1170     return 0;
1171   }
1172   DCHECK_OFFSET();
1173 
1174   return true;
1175 }
1176 
WriteCode(OutputStream * out)1177 bool OatWriter::WriteCode(OutputStream* out) {
1178   size_t header_size = oat_header_->GetHeaderSize();
1179   const size_t file_offset = oat_data_offset_;
1180   size_t relative_offset = oat_header_->GetExecutableOffset();
1181   DCHECK_OFFSET();
1182 
1183   relative_offset = WriteCode(out, file_offset, relative_offset);
1184   if (relative_offset == 0) {
1185     LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();
1186     return false;
1187   }
1188 
1189   relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
1190   if (relative_offset == 0) {
1191     LOG(ERROR) << "Failed to write oat code for dex files to " << out->GetLocation();
1192     return false;
1193   }
1194 
1195   const off_t oat_end_file_offset = out->Seek(0, kSeekCurrent);
1196   if (oat_end_file_offset == (off_t) -1) {
1197     LOG(ERROR) << "Failed to get oat end file offset in " << out->GetLocation();
1198     return false;
1199   }
1200 
1201   if (kIsDebugBuild) {
1202     uint32_t size_total = 0;
1203     #define DO_STAT(x) \
1204       VLOG(compiler) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
1205       size_total += x;
1206 
1207     DO_STAT(size_dex_file_alignment_);
1208     DO_STAT(size_executable_offset_alignment_);
1209     DO_STAT(size_oat_header_);
1210     DO_STAT(size_oat_header_key_value_store_);
1211     DO_STAT(size_dex_file_);
1212     DO_STAT(size_interpreter_to_interpreter_bridge_);
1213     DO_STAT(size_interpreter_to_compiled_code_bridge_);
1214     DO_STAT(size_jni_dlsym_lookup_);
1215     DO_STAT(size_quick_generic_jni_trampoline_);
1216     DO_STAT(size_quick_imt_conflict_trampoline_);
1217     DO_STAT(size_quick_resolution_trampoline_);
1218     DO_STAT(size_quick_to_interpreter_bridge_);
1219     DO_STAT(size_trampoline_alignment_);
1220     DO_STAT(size_method_header_);
1221     DO_STAT(size_code_);
1222     DO_STAT(size_code_alignment_);
1223     DO_STAT(size_relative_call_thunks_);
1224     DO_STAT(size_misc_thunks_);
1225     DO_STAT(size_mapping_table_);
1226     DO_STAT(size_vmap_table_);
1227     DO_STAT(size_gc_map_);
1228     DO_STAT(size_oat_dex_file_location_size_);
1229     DO_STAT(size_oat_dex_file_location_data_);
1230     DO_STAT(size_oat_dex_file_location_checksum_);
1231     DO_STAT(size_oat_dex_file_offset_);
1232     DO_STAT(size_oat_dex_file_methods_offsets_);
1233     DO_STAT(size_oat_class_type_);
1234     DO_STAT(size_oat_class_status_);
1235     DO_STAT(size_oat_class_method_bitmaps_);
1236     DO_STAT(size_oat_class_method_offsets_);
1237     #undef DO_STAT
1238 
1239     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
1240     CHECK_EQ(file_offset + size_total, static_cast<size_t>(oat_end_file_offset));
1241     CHECK_EQ(size_, size_total);
1242   }
1243 
1244   CHECK_EQ(file_offset + size_, static_cast<size_t>(oat_end_file_offset));
1245   CHECK_EQ(size_, relative_offset);
1246 
1247   // Write the header now that the checksum is final.
1248   if (out->Seek(file_offset, kSeekSet) == (off_t) -1) {
1249     PLOG(ERROR) << "Failed to seek to oat header position in " << out->GetLocation();
1250     return false;
1251   }
1252   DCHECK_EQ(file_offset, static_cast<size_t>(out->Seek(0, kSeekCurrent)));
1253   if (!out->WriteFully(oat_header_, header_size)) {
1254     PLOG(ERROR) << "Failed to write oat header to " << out->GetLocation();
1255     return false;
1256   }
1257   if (out->Seek(oat_end_file_offset, kSeekSet) == (off_t) -1) {
1258     PLOG(ERROR) << "Failed to seek to end after writing oat header to " << out->GetLocation();
1259     return false;
1260   }
1261   DCHECK_EQ(oat_end_file_offset, out->Seek(0, kSeekCurrent));
1262 
1263   return true;
1264 }
1265 
WriteTables(OutputStream * out,const size_t file_offset)1266 bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) {
1267   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
1268     if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
1269       PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation();
1270       return false;
1271     }
1272   }
1273   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
1274     uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
1275     off_t actual_offset = out->Seek(expected_offset, kSeekSet);
1276     if (static_cast<uint32_t>(actual_offset) != expected_offset) {
1277       const DexFile* dex_file = (*dex_files_)[i];
1278       PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
1279                   << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
1280       return false;
1281     }
1282     const DexFile* dex_file = (*dex_files_)[i];
1283     if (!out->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
1284       PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
1285                   << " to " << out->GetLocation();
1286       return false;
1287     }
1288     size_dex_file_ += dex_file->GetHeader().file_size_;
1289   }
1290   for (size_t i = 0; i != oat_classes_.size(); ++i) {
1291     if (!oat_classes_[i]->Write(this, out, file_offset)) {
1292       PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation();
1293       return false;
1294     }
1295   }
1296   return true;
1297 }
1298 
WriteMaps(OutputStream * out,const size_t file_offset,size_t relative_offset)1299 size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) {
1300   #define VISIT(VisitorType)                                              \
1301     do {                                                                  \
1302       VisitorType visitor(this, out, file_offset, relative_offset);       \
1303       if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \
1304         return 0;                                                         \
1305       }                                                                   \
1306       relative_offset = visitor.GetOffset();                              \
1307     } while (false)
1308 
1309   size_t gc_maps_offset = relative_offset;
1310   VISIT(WriteMapMethodVisitor<GcMapDataAccess>);
1311   size_gc_map_ = relative_offset - gc_maps_offset;
1312 
1313   size_t mapping_tables_offset = relative_offset;
1314   VISIT(WriteMapMethodVisitor<MappingTableDataAccess>);
1315   size_mapping_table_ = relative_offset - mapping_tables_offset;
1316 
1317   size_t vmap_tables_offset = relative_offset;
1318   VISIT(WriteMapMethodVisitor<VmapTableDataAccess>);
1319   size_vmap_table_ = relative_offset - vmap_tables_offset;
1320 
1321   #undef VISIT
1322 
1323   return relative_offset;
1324 }
1325 
WriteCode(OutputStream * out,const size_t file_offset,size_t relative_offset)1326 size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {
1327   if (compiler_driver_->IsImage()) {
1328     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
1329 
1330     #define DO_TRAMPOLINE(field) \
1331       do { \
1332         uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
1333         uint32_t alignment_padding = aligned_offset - relative_offset; \
1334         out->Seek(alignment_padding, kSeekCurrent); \
1335         size_trampoline_alignment_ += alignment_padding; \
1336         if (!out->WriteFully(&(*field)[0], field->size())) { \
1337           PLOG(ERROR) << "Failed to write " # field " to " << out->GetLocation(); \
1338           return false; \
1339         } \
1340         size_ ## field += field->size(); \
1341         relative_offset += alignment_padding + field->size(); \
1342         DCHECK_OFFSET(); \
1343       } while (false)
1344 
1345     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_);
1346     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_);
1347     DO_TRAMPOLINE(jni_dlsym_lookup_);
1348     DO_TRAMPOLINE(quick_generic_jni_trampoline_);
1349     DO_TRAMPOLINE(quick_imt_conflict_trampoline_);
1350     DO_TRAMPOLINE(quick_resolution_trampoline_);
1351     DO_TRAMPOLINE(quick_to_interpreter_bridge_);
1352     #undef DO_TRAMPOLINE
1353   }
1354   return relative_offset;
1355 }
1356 
WriteCodeDexFiles(OutputStream * out,const size_t file_offset,size_t relative_offset)1357 size_t OatWriter::WriteCodeDexFiles(OutputStream* out,
1358                                     const size_t file_offset,
1359                                     size_t relative_offset) {
1360   #define VISIT(VisitorType)                                              \
1361     do {                                                                  \
1362       VisitorType visitor(this, out, file_offset, relative_offset);       \
1363       if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \
1364         return 0;                                                         \
1365       }                                                                   \
1366       relative_offset = visitor.GetOffset();                              \
1367     } while (false)
1368 
1369   VISIT(WriteCodeMethodVisitor);
1370 
1371   #undef VISIT
1372 
1373   size_code_alignment_ += relative_patcher_->CodeAlignmentSize();
1374   size_relative_call_thunks_ += relative_patcher_->RelativeCallThunksSize();
1375   size_misc_thunks_ += relative_patcher_->MiscThunksSize();
1376 
1377   return relative_offset;
1378 }
1379 
WriteCodeAlignment(OutputStream * out,uint32_t aligned_code_delta)1380 bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) {
1381   static const uint8_t kPadding[] = {
1382       0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u
1383   };
1384   DCHECK_LE(aligned_code_delta, sizeof(kPadding));
1385   if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) {
1386     return false;
1387   }
1388   size_code_alignment_ += aligned_code_delta;
1389   return true;
1390 }
1391 
FindMethodOffset(MethodReference ref)1392 std::pair<bool, uint32_t> OatWriter::MethodOffsetMap::FindMethodOffset(MethodReference ref) {
1393   auto it = map.find(ref);
1394   if (it == map.end()) {
1395     return std::pair<bool, uint32_t>(false, 0u);
1396   } else {
1397     return std::pair<bool, uint32_t>(true, it->second);
1398   }
1399 }
1400 
OatDexFile(size_t offset,const DexFile & dex_file)1401 OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
1402   offset_ = offset;
1403   const std::string& location(dex_file.GetLocation());
1404   dex_file_location_size_ = location.size();
1405   dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
1406   dex_file_location_checksum_ = dex_file.GetLocationChecksum();
1407   dex_file_offset_ = 0;
1408   methods_offsets_.resize(dex_file.NumClassDefs());
1409 }
1410 
SizeOf() const1411 size_t OatWriter::OatDexFile::SizeOf() const {
1412   return sizeof(dex_file_location_size_)
1413           + dex_file_location_size_
1414           + sizeof(dex_file_location_checksum_)
1415           + sizeof(dex_file_offset_)
1416           + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
1417 }
1418 
UpdateChecksum(OatHeader * oat_header) const1419 void OatWriter::OatDexFile::UpdateChecksum(OatHeader* oat_header) const {
1420   oat_header->UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
1421   oat_header->UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
1422   oat_header->UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
1423   oat_header->UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
1424   oat_header->UpdateChecksum(&methods_offsets_[0],
1425                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
1426 }
1427 
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const1428 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
1429                                   OutputStream* out,
1430                                   const size_t file_offset) const {
1431   DCHECK_OFFSET_();
1432   if (!out->WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
1433     PLOG(ERROR) << "Failed to write dex file location length to " << out->GetLocation();
1434     return false;
1435   }
1436   oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
1437   if (!out->WriteFully(dex_file_location_data_, dex_file_location_size_)) {
1438     PLOG(ERROR) << "Failed to write dex file location data to " << out->GetLocation();
1439     return false;
1440   }
1441   oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
1442   if (!out->WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
1443     PLOG(ERROR) << "Failed to write dex file location checksum to " << out->GetLocation();
1444     return false;
1445   }
1446   oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
1447   if (!out->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
1448     PLOG(ERROR) << "Failed to write dex file offset to " << out->GetLocation();
1449     return false;
1450   }
1451   oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
1452   if (!out->WriteFully(&methods_offsets_[0],
1453                       sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
1454     PLOG(ERROR) << "Failed to write methods offsets to " << out->GetLocation();
1455     return false;
1456   }
1457   oat_writer->size_oat_dex_file_methods_offsets_ +=
1458       sizeof(methods_offsets_[0]) * methods_offsets_.size();
1459   return true;
1460 }
1461 
OatClass(size_t offset,const std::vector<CompiledMethod * > & compiled_methods,uint32_t num_non_null_compiled_methods,mirror::Class::Status status)1462 OatWriter::OatClass::OatClass(size_t offset,
1463                               const std::vector<CompiledMethod*>& compiled_methods,
1464                               uint32_t num_non_null_compiled_methods,
1465                               mirror::Class::Status status)
1466     : compiled_methods_(compiled_methods) {
1467   uint32_t num_methods = compiled_methods.size();
1468   CHECK_LE(num_non_null_compiled_methods, num_methods);
1469 
1470   offset_ = offset;
1471   oat_method_offsets_offsets_from_oat_class_.resize(num_methods);
1472 
1473   // Since both kOatClassNoneCompiled and kOatClassAllCompiled could
1474   // apply when there are 0 methods, we just arbitrarily say that 0
1475   // methods means kOatClassNoneCompiled and that we won't use
1476   // kOatClassAllCompiled unless there is at least one compiled
1477   // method. This means in an interpretter only system, we can assert
1478   // that all classes are kOatClassNoneCompiled.
1479   if (num_non_null_compiled_methods == 0) {
1480     type_ = kOatClassNoneCompiled;
1481   } else if (num_non_null_compiled_methods == num_methods) {
1482     type_ = kOatClassAllCompiled;
1483   } else {
1484     type_ = kOatClassSomeCompiled;
1485   }
1486 
1487   status_ = status;
1488   method_offsets_.resize(num_non_null_compiled_methods);
1489   method_headers_.resize(num_non_null_compiled_methods);
1490 
1491   uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);
1492   if (type_ == kOatClassSomeCompiled) {
1493     method_bitmap_ = new BitVector(num_methods, false, Allocator::GetMallocAllocator());
1494     method_bitmap_size_ = method_bitmap_->GetSizeOf();
1495     oat_method_offsets_offset_from_oat_class += sizeof(method_bitmap_size_);
1496     oat_method_offsets_offset_from_oat_class += method_bitmap_size_;
1497   } else {
1498     method_bitmap_ = nullptr;
1499     method_bitmap_size_ = 0;
1500   }
1501 
1502   for (size_t i = 0; i < num_methods; i++) {
1503     CompiledMethod* compiled_method = compiled_methods_[i];
1504     if (compiled_method == nullptr) {
1505       oat_method_offsets_offsets_from_oat_class_[i] = 0;
1506     } else {
1507       oat_method_offsets_offsets_from_oat_class_[i] = oat_method_offsets_offset_from_oat_class;
1508       oat_method_offsets_offset_from_oat_class += sizeof(OatMethodOffsets);
1509       if (type_ == kOatClassSomeCompiled) {
1510         method_bitmap_->SetBit(i);
1511       }
1512     }
1513   }
1514 }
1515 
~OatClass()1516 OatWriter::OatClass::~OatClass() {
1517   delete method_bitmap_;
1518 }
1519 
GetOatMethodOffsetsOffsetFromOatHeader(size_t class_def_method_index_) const1520 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
1521     size_t class_def_method_index_) const {
1522   uint32_t method_offset = GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
1523   if (method_offset == 0) {
1524     return 0;
1525   }
1526   return offset_ + method_offset;
1527 }
1528 
GetOatMethodOffsetsOffsetFromOatClass(size_t class_def_method_index_) const1529 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
1530     size_t class_def_method_index_) const {
1531   return oat_method_offsets_offsets_from_oat_class_[class_def_method_index_];
1532 }
1533 
SizeOf() const1534 size_t OatWriter::OatClass::SizeOf() const {
1535   return sizeof(status_)
1536           + sizeof(type_)
1537           + ((method_bitmap_size_ == 0) ? 0 : sizeof(method_bitmap_size_))
1538           + method_bitmap_size_
1539           + (sizeof(method_offsets_[0]) * method_offsets_.size());
1540 }
1541 
UpdateChecksum(OatHeader * oat_header) const1542 void OatWriter::OatClass::UpdateChecksum(OatHeader* oat_header) const {
1543   oat_header->UpdateChecksum(&status_, sizeof(status_));
1544   oat_header->UpdateChecksum(&type_, sizeof(type_));
1545   if (method_bitmap_size_ != 0) {
1546     CHECK_EQ(kOatClassSomeCompiled, type_);
1547     oat_header->UpdateChecksum(&method_bitmap_size_, sizeof(method_bitmap_size_));
1548     oat_header->UpdateChecksum(method_bitmap_->GetRawStorage(), method_bitmap_size_);
1549   }
1550   oat_header->UpdateChecksum(&method_offsets_[0],
1551                              sizeof(method_offsets_[0]) * method_offsets_.size());
1552 }
1553 
Write(OatWriter * oat_writer,OutputStream * out,const size_t file_offset) const1554 bool OatWriter::OatClass::Write(OatWriter* oat_writer,
1555                                 OutputStream* out,
1556                                 const size_t file_offset) const {
1557   DCHECK_OFFSET_();
1558   if (!out->WriteFully(&status_, sizeof(status_))) {
1559     PLOG(ERROR) << "Failed to write class status to " << out->GetLocation();
1560     return false;
1561   }
1562   oat_writer->size_oat_class_status_ += sizeof(status_);
1563   if (!out->WriteFully(&type_, sizeof(type_))) {
1564     PLOG(ERROR) << "Failed to write oat class type to " << out->GetLocation();
1565     return false;
1566   }
1567   oat_writer->size_oat_class_type_ += sizeof(type_);
1568   if (method_bitmap_size_ != 0) {
1569     CHECK_EQ(kOatClassSomeCompiled, type_);
1570     if (!out->WriteFully(&method_bitmap_size_, sizeof(method_bitmap_size_))) {
1571       PLOG(ERROR) << "Failed to write method bitmap size to " << out->GetLocation();
1572       return false;
1573     }
1574     oat_writer->size_oat_class_method_bitmaps_ += sizeof(method_bitmap_size_);
1575     if (!out->WriteFully(method_bitmap_->GetRawStorage(), method_bitmap_size_)) {
1576       PLOG(ERROR) << "Failed to write method bitmap to " << out->GetLocation();
1577       return false;
1578     }
1579     oat_writer->size_oat_class_method_bitmaps_ += method_bitmap_size_;
1580   }
1581   if (!out->WriteFully(&method_offsets_[0],
1582                       sizeof(method_offsets_[0]) * method_offsets_.size())) {
1583     PLOG(ERROR) << "Failed to write method offsets to " << out->GetLocation();
1584     return false;
1585   }
1586   oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
1587   return true;
1588 }
1589 
1590 }  // namespace art
1591