Home | History | Annotate | Download | only in compiler
      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 "base/stl_util.h"
     22 #include "base/unix_file/fd_file.h"
     23 #include "class_linker.h"
     24 #include "dex_file-inl.h"
     25 #include "gc/space/space.h"
     26 #include "mirror/art_method-inl.h"
     27 #include "mirror/array.h"
     28 #include "mirror/class_loader.h"
     29 #include "mirror/object-inl.h"
     30 #include "os.h"
     31 #include "output_stream.h"
     32 #include "safe_map.h"
     33 #include "scoped_thread_state_change.h"
     34 #include "verifier/method_verifier.h"
     35 
     36 namespace art {
     37 
     38 OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
     39                      uint32_t image_file_location_oat_checksum,
     40                      uint32_t image_file_location_oat_begin,
     41                      const std::string& image_file_location,
     42                      const CompilerDriver* compiler)
     43   : compiler_driver_(compiler),
     44     dex_files_(&dex_files),
     45     image_file_location_oat_checksum_(image_file_location_oat_checksum),
     46     image_file_location_oat_begin_(image_file_location_oat_begin),
     47     image_file_location_(image_file_location),
     48     oat_header_(NULL),
     49     size_dex_file_alignment_(0),
     50     size_executable_offset_alignment_(0),
     51     size_oat_header_(0),
     52     size_oat_header_image_file_location_(0),
     53     size_dex_file_(0),
     54     size_interpreter_to_interpreter_bridge_(0),
     55     size_interpreter_to_compiled_code_bridge_(0),
     56     size_jni_dlsym_lookup_(0),
     57     size_portable_resolution_trampoline_(0),
     58     size_portable_to_interpreter_bridge_(0),
     59     size_quick_resolution_trampoline_(0),
     60     size_quick_to_interpreter_bridge_(0),
     61     size_trampoline_alignment_(0),
     62     size_code_size_(0),
     63     size_code_(0),
     64     size_code_alignment_(0),
     65     size_mapping_table_(0),
     66     size_vmap_table_(0),
     67     size_gc_map_(0),
     68     size_oat_dex_file_location_size_(0),
     69     size_oat_dex_file_location_data_(0),
     70     size_oat_dex_file_location_checksum_(0),
     71     size_oat_dex_file_offset_(0),
     72     size_oat_dex_file_methods_offsets_(0),
     73     size_oat_class_status_(0),
     74     size_oat_class_method_offsets_(0) {
     75   size_t offset = InitOatHeader();
     76   offset = InitOatDexFiles(offset);
     77   offset = InitDexFiles(offset);
     78   offset = InitOatClasses(offset);
     79   offset = InitOatCode(offset);
     80   offset = InitOatCodeDexFiles(offset);
     81   size_ = offset;
     82 
     83   CHECK_EQ(dex_files_->size(), oat_dex_files_.size());
     84   CHECK(image_file_location.empty() == compiler->IsImage());
     85 }
     86 
     87 OatWriter::~OatWriter() {
     88   delete oat_header_;
     89   STLDeleteElements(&oat_dex_files_);
     90   STLDeleteElements(&oat_classes_);
     91 }
     92 
     93 size_t OatWriter::InitOatHeader() {
     94   // create the OatHeader
     95   oat_header_ = new OatHeader(compiler_driver_->GetInstructionSet(),
     96                               dex_files_,
     97                               image_file_location_oat_checksum_,
     98                               image_file_location_oat_begin_,
     99                               image_file_location_);
    100   size_t offset = sizeof(*oat_header_);
    101   offset += image_file_location_.size();
    102   return offset;
    103 }
    104 
    105 size_t OatWriter::InitOatDexFiles(size_t offset) {
    106   // create the OatDexFiles
    107   for (size_t i = 0; i != dex_files_->size(); ++i) {
    108     const DexFile* dex_file = (*dex_files_)[i];
    109     CHECK(dex_file != NULL);
    110     OatDexFile* oat_dex_file = new OatDexFile(offset, *dex_file);
    111     oat_dex_files_.push_back(oat_dex_file);
    112     offset += oat_dex_file->SizeOf();
    113   }
    114   return offset;
    115 }
    116 
    117 size_t OatWriter::InitDexFiles(size_t offset) {
    118   // calculate the offsets within OatDexFiles to the DexFiles
    119   for (size_t i = 0; i != dex_files_->size(); ++i) {
    120     // dex files are required to be 4 byte aligned
    121     size_t original_offset = offset;
    122     offset = RoundUp(offset, 4);
    123     size_dex_file_alignment_ += offset - original_offset;
    124 
    125     // set offset in OatDexFile to DexFile
    126     oat_dex_files_[i]->dex_file_offset_ = offset;
    127 
    128     const DexFile* dex_file = (*dex_files_)[i];
    129     offset += dex_file->GetHeader().file_size_;
    130   }
    131   return offset;
    132 }
    133 
    134 size_t OatWriter::InitOatClasses(size_t offset) {
    135   // create the OatClasses
    136   // calculate the offsets within OatDexFiles to OatClasses
    137   for (size_t i = 0; i != dex_files_->size(); ++i) {
    138     const DexFile* dex_file = (*dex_files_)[i];
    139     for (size_t class_def_index = 0;
    140          class_def_index < dex_file->NumClassDefs();
    141          class_def_index++) {
    142       oat_dex_files_[i]->methods_offsets_[class_def_index] = offset;
    143       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
    144       const byte* class_data = dex_file->GetClassData(class_def);
    145       uint32_t num_methods = 0;
    146       if (class_data != NULL) {  // ie not an empty class, such as a marker interface
    147         ClassDataItemIterator it(*dex_file, class_data);
    148         size_t num_direct_methods = it.NumDirectMethods();
    149         size_t num_virtual_methods = it.NumVirtualMethods();
    150         num_methods = num_direct_methods + num_virtual_methods;
    151       }
    152 
    153       ClassReference class_ref(dex_file, class_def_index);
    154       CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
    155       mirror::Class::Status status;
    156       if (compiled_class != NULL) {
    157         status = compiled_class->GetStatus();
    158       } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
    159         status = mirror::Class::kStatusError;
    160       } else {
    161         status = mirror::Class::kStatusNotReady;
    162       }
    163 
    164       OatClass* oat_class = new OatClass(offset, status, num_methods);
    165       oat_classes_.push_back(oat_class);
    166       offset += oat_class->SizeOf();
    167     }
    168     oat_dex_files_[i]->UpdateChecksum(*oat_header_);
    169   }
    170   return offset;
    171 }
    172 
    173 size_t OatWriter::InitOatCode(size_t offset) {
    174   // calculate the offsets within OatHeader to executable code
    175   size_t old_offset = offset;
    176   // required to be on a new page boundary
    177   offset = RoundUp(offset, kPageSize);
    178   oat_header_->SetExecutableOffset(offset);
    179   size_executable_offset_alignment_ = offset - old_offset;
    180   if (compiler_driver_->IsImage()) {
    181     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
    182 
    183     #define DO_TRAMPOLINE(field, fn_name) \
    184       offset = CompiledCode::AlignCode(offset, instruction_set); \
    185       oat_header_->Set ## fn_name ## Offset(offset); \
    186       field.reset(compiler_driver_->Create ## fn_name()); \
    187       offset += field->size();
    188 
    189     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_, InterpreterToInterpreterBridge);
    190     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_, InterpreterToCompiledCodeBridge);
    191     DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup);
    192     DO_TRAMPOLINE(portable_resolution_trampoline_, PortableResolutionTrampoline);
    193     DO_TRAMPOLINE(portable_to_interpreter_bridge_, PortableToInterpreterBridge);
    194     DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline);
    195     DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge);
    196 
    197     #undef DO_TRAMPOLINE
    198   } else {
    199     oat_header_->SetInterpreterToInterpreterBridgeOffset(0);
    200     oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0);
    201     oat_header_->SetJniDlsymLookupOffset(0);
    202     oat_header_->SetPortableResolutionTrampolineOffset(0);
    203     oat_header_->SetPortableToInterpreterBridgeOffset(0);
    204     oat_header_->SetQuickResolutionTrampolineOffset(0);
    205     oat_header_->SetQuickToInterpreterBridgeOffset(0);
    206   }
    207   return offset;
    208 }
    209 
    210 size_t OatWriter::InitOatCodeDexFiles(size_t offset) {
    211   size_t oat_class_index = 0;
    212   for (size_t i = 0; i != dex_files_->size(); ++i) {
    213     const DexFile* dex_file = (*dex_files_)[i];
    214     CHECK(dex_file != NULL);
    215     offset = InitOatCodeDexFile(offset, oat_class_index, *dex_file);
    216   }
    217   return offset;
    218 }
    219 
    220 size_t OatWriter::InitOatCodeDexFile(size_t offset,
    221                                      size_t& oat_class_index,
    222                                      const DexFile& dex_file) {
    223   for (size_t class_def_index = 0;
    224        class_def_index < dex_file.NumClassDefs();
    225        class_def_index++, oat_class_index++) {
    226     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
    227     offset = InitOatCodeClassDef(offset, oat_class_index, class_def_index, dex_file, class_def);
    228     oat_classes_[oat_class_index]->UpdateChecksum(*oat_header_);
    229   }
    230   return offset;
    231 }
    232 
    233 size_t OatWriter::InitOatCodeClassDef(size_t offset,
    234                                       size_t oat_class_index, size_t class_def_index,
    235                                       const DexFile& dex_file,
    236                                       const DexFile::ClassDef& class_def) {
    237   const byte* class_data = dex_file.GetClassData(class_def);
    238   if (class_data == NULL) {
    239     // empty class, such as a marker interface
    240     return offset;
    241   }
    242   ClassDataItemIterator it(dex_file, class_data);
    243   CHECK_EQ(oat_classes_[oat_class_index]->method_offsets_.size(),
    244            it.NumDirectMethods() + it.NumVirtualMethods());
    245   // Skip fields
    246   while (it.HasNextStaticField()) {
    247     it.Next();
    248   }
    249   while (it.HasNextInstanceField()) {
    250     it.Next();
    251   }
    252   // Process methods
    253   size_t class_def_method_index = 0;
    254   while (it.HasNextDirectMethod()) {
    255     bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
    256     offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
    257                                is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
    258                                &dex_file);
    259     class_def_method_index++;
    260     it.Next();
    261   }
    262   while (it.HasNextVirtualMethod()) {
    263     bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
    264     offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index,
    265                                is_native, it.GetMethodInvokeType(class_def), it.GetMemberIndex(),
    266                                &dex_file);
    267     class_def_method_index++;
    268     it.Next();
    269   }
    270   DCHECK(!it.HasNext());
    271   return offset;
    272 }
    273 
    274 size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index,
    275                                     size_t __attribute__((unused)) class_def_index,
    276                                     size_t class_def_method_index,
    277                                     bool __attribute__((unused)) is_native,
    278                                     InvokeType invoke_type,
    279                                     uint32_t method_idx, const DexFile* dex_file) {
    280   // derived from CompiledMethod if available
    281   uint32_t code_offset = 0;
    282   uint32_t frame_size_in_bytes = kStackAlignment;
    283   uint32_t core_spill_mask = 0;
    284   uint32_t fp_spill_mask = 0;
    285   uint32_t mapping_table_offset = 0;
    286   uint32_t vmap_table_offset = 0;
    287   uint32_t gc_map_offset = 0;
    288 
    289   OatClass* oat_class = oat_classes_[oat_class_index];
    290 #if defined(ART_USE_PORTABLE_COMPILER)
    291   size_t oat_method_offsets_offset =
    292       oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index);
    293 #endif
    294 
    295   CompiledMethod* compiled_method =
    296       compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx));
    297   if (compiled_method != NULL) {
    298 #if defined(ART_USE_PORTABLE_COMPILER)
    299     compiled_method->AddOatdataOffsetToCompliledCodeOffset(
    300         oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_));
    301 #else
    302     const std::vector<uint8_t>& code = compiled_method->GetCode();
    303     offset = compiled_method->AlignCode(offset);
    304     DCHECK_ALIGNED(offset, kArmAlignment);
    305     uint32_t code_size = code.size() * sizeof(code[0]);
    306     CHECK_NE(code_size, 0U);
    307     uint32_t thumb_offset = compiled_method->CodeDelta();
    308     code_offset = offset + sizeof(code_size) + thumb_offset;
    309 
    310     // Deduplicate code arrays
    311     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
    312     if (code_iter != code_offsets_.end()) {
    313       code_offset = code_iter->second;
    314     } else {
    315       code_offsets_.Put(&code, code_offset);
    316       offset += sizeof(code_size);  // code size is prepended before code
    317       offset += code_size;
    318       oat_header_->UpdateChecksum(&code[0], code_size);
    319     }
    320 #endif
    321     frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
    322     core_spill_mask = compiled_method->GetCoreSpillMask();
    323     fp_spill_mask = compiled_method->GetFpSpillMask();
    324 
    325     const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
    326     size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
    327     mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
    328 
    329     // Deduplicate mapping tables
    330     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter =
    331         mapping_table_offsets_.find(&mapping_table);
    332     if (mapping_iter != mapping_table_offsets_.end()) {
    333       mapping_table_offset = mapping_iter->second;
    334     } else {
    335       mapping_table_offsets_.Put(&mapping_table, mapping_table_offset);
    336       offset += mapping_table_size;
    337       oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
    338     }
    339 
    340     const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
    341     size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
    342     vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
    343 
    344     // Deduplicate vmap tables
    345     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter =
    346         vmap_table_offsets_.find(&vmap_table);
    347     if (vmap_iter != vmap_table_offsets_.end()) {
    348       vmap_table_offset = vmap_iter->second;
    349     } else {
    350       vmap_table_offsets_.Put(&vmap_table, vmap_table_offset);
    351       offset += vmap_table_size;
    352       oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
    353     }
    354 
    355     const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
    356     size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
    357     gc_map_offset = (gc_map_size == 0) ? 0 : offset;
    358 
    359 #if !defined(NDEBUG)
    360     // We expect GC maps except when the class hasn't been verified or the method is native
    361     ClassReference class_ref(dex_file, class_def_index);
    362     CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref);
    363     mirror::Class::Status status;
    364     if (compiled_class != NULL) {
    365       status = compiled_class->GetStatus();
    366     } else if (verifier::MethodVerifier::IsClassRejected(class_ref)) {
    367       status = mirror::Class::kStatusError;
    368     } else {
    369       status = mirror::Class::kStatusNotReady;
    370     }
    371     CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
    372         << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
    373         << (status < mirror::Class::kStatusVerified) << " " << status << " "
    374         << PrettyMethod(method_idx, *dex_file);
    375 #endif
    376 
    377     // Deduplicate GC maps
    378     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
    379         gc_map_offsets_.find(&gc_map);
    380     if (gc_map_iter != gc_map_offsets_.end()) {
    381       gc_map_offset = gc_map_iter->second;
    382     } else {
    383       gc_map_offsets_.Put(&gc_map, gc_map_offset);
    384       offset += gc_map_size;
    385       oat_header_->UpdateChecksum(&gc_map[0], gc_map_size);
    386     }
    387   }
    388 
    389   oat_class->method_offsets_[class_def_method_index] =
    390       OatMethodOffsets(code_offset,
    391                        frame_size_in_bytes,
    392                        core_spill_mask,
    393                        fp_spill_mask,
    394                        mapping_table_offset,
    395                        vmap_table_offset,
    396                        gc_map_offset);
    397 
    398   if (compiler_driver_->IsImage()) {
    399     ClassLinker* linker = Runtime::Current()->GetClassLinker();
    400     mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file);
    401     // Unchecked as we hold mutator_lock_ on entry.
    402     ScopedObjectAccessUnchecked soa(Thread::Current());
    403     mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache,
    404                                                            NULL, NULL, invoke_type);
    405     CHECK(method != NULL);
    406     method->SetFrameSizeInBytes(frame_size_in_bytes);
    407     method->SetCoreSpillMask(core_spill_mask);
    408     method->SetFpSpillMask(fp_spill_mask);
    409     method->SetOatMappingTableOffset(mapping_table_offset);
    410     // Don't overwrite static method trampoline
    411     if (!method->IsStatic() || method->IsConstructor() ||
    412         method->GetDeclaringClass()->IsInitialized()) {
    413       method->SetOatCodeOffset(code_offset);
    414     } else {
    415       method->SetEntryPointFromCompiledCode(NULL);
    416     }
    417     method->SetOatVmapTableOffset(vmap_table_offset);
    418     method->SetOatNativeGcMapOffset(gc_map_offset);
    419   }
    420 
    421   return offset;
    422 }
    423 
    424 #define DCHECK_OFFSET() \
    425   DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out.Seek(0, kSeekCurrent)) \
    426     << "file_offset=" << file_offset << " relative_offset=" << relative_offset
    427 
    428 #define DCHECK_OFFSET_() \
    429   DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out.Seek(0, kSeekCurrent)) \
    430     << "file_offset=" << file_offset << " offset_=" << offset_
    431 
    432 bool OatWriter::Write(OutputStream& out) {
    433   const size_t file_offset = out.Seek(0, kSeekCurrent);
    434 
    435   if (!out.WriteFully(oat_header_, sizeof(*oat_header_))) {
    436     PLOG(ERROR) << "Failed to write oat header to " << out.GetLocation();
    437     return false;
    438   }
    439   size_oat_header_ += sizeof(*oat_header_);
    440 
    441   if (!out.WriteFully(image_file_location_.data(), image_file_location_.size())) {
    442     PLOG(ERROR) << "Failed to write oat header image file location to " << out.GetLocation();
    443     return false;
    444   }
    445   size_oat_header_image_file_location_ += image_file_location_.size();
    446 
    447   if (!WriteTables(out, file_offset)) {
    448     LOG(ERROR) << "Failed to write oat tables to " << out.GetLocation();
    449     return false;
    450   }
    451 
    452   size_t relative_offset = WriteCode(out, file_offset);
    453   if (relative_offset == 0) {
    454     LOG(ERROR) << "Failed to write oat code to " << out.GetLocation();
    455     return false;
    456   }
    457 
    458   relative_offset = WriteCodeDexFiles(out, file_offset, relative_offset);
    459   if (relative_offset == 0) {
    460     LOG(ERROR) << "Failed to write oat code for dex files to " << out.GetLocation();
    461     return false;
    462   }
    463 
    464   if (kIsDebugBuild) {
    465     uint32_t size_total = 0;
    466     #define DO_STAT(x) \
    467       VLOG(compiler) << #x "=" << PrettySize(x) << " (" << x << "B)"; \
    468       size_total += x;
    469 
    470     DO_STAT(size_dex_file_alignment_);
    471     DO_STAT(size_executable_offset_alignment_);
    472     DO_STAT(size_oat_header_);
    473     DO_STAT(size_oat_header_image_file_location_);
    474     DO_STAT(size_dex_file_);
    475     DO_STAT(size_interpreter_to_interpreter_bridge_);
    476     DO_STAT(size_interpreter_to_compiled_code_bridge_);
    477     DO_STAT(size_jni_dlsym_lookup_);
    478     DO_STAT(size_portable_resolution_trampoline_);
    479     DO_STAT(size_portable_to_interpreter_bridge_);
    480     DO_STAT(size_quick_resolution_trampoline_);
    481     DO_STAT(size_quick_to_interpreter_bridge_);
    482     DO_STAT(size_trampoline_alignment_);
    483     DO_STAT(size_code_size_);
    484     DO_STAT(size_code_);
    485     DO_STAT(size_code_alignment_);
    486     DO_STAT(size_mapping_table_);
    487     DO_STAT(size_vmap_table_);
    488     DO_STAT(size_gc_map_);
    489     DO_STAT(size_oat_dex_file_location_size_);
    490     DO_STAT(size_oat_dex_file_location_data_);
    491     DO_STAT(size_oat_dex_file_location_checksum_);
    492     DO_STAT(size_oat_dex_file_offset_);
    493     DO_STAT(size_oat_dex_file_methods_offsets_);
    494     DO_STAT(size_oat_class_status_);
    495     DO_STAT(size_oat_class_method_offsets_);
    496     #undef DO_STAT
    497 
    498     VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
    499     CHECK_EQ(file_offset + size_total, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
    500     CHECK_EQ(size_, size_total);
    501   }
    502 
    503   CHECK_EQ(file_offset + size_, static_cast<uint32_t>(out.Seek(0, kSeekCurrent)));
    504   CHECK_EQ(size_, relative_offset);
    505 
    506   return true;
    507 }
    508 
    509 bool OatWriter::WriteTables(OutputStream& out, const size_t file_offset) {
    510   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
    511     if (!oat_dex_files_[i]->Write(this, out, file_offset)) {
    512       PLOG(ERROR) << "Failed to write oat dex information to " << out.GetLocation();
    513       return false;
    514     }
    515   }
    516   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
    517     uint32_t expected_offset = file_offset + oat_dex_files_[i]->dex_file_offset_;
    518     off_t actual_offset = out.Seek(expected_offset, kSeekSet);
    519     if (static_cast<uint32_t>(actual_offset) != expected_offset) {
    520       const DexFile* dex_file = (*dex_files_)[i];
    521       PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
    522                   << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
    523       return false;
    524     }
    525     const DexFile* dex_file = (*dex_files_)[i];
    526     if (!out.WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
    527       PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation()
    528                   << " to " << out.GetLocation();
    529       return false;
    530     }
    531     size_dex_file_ += dex_file->GetHeader().file_size_;
    532   }
    533   for (size_t i = 0; i != oat_classes_.size(); ++i) {
    534     if (!oat_classes_[i]->Write(this, out, file_offset)) {
    535       PLOG(ERROR) << "Failed to write oat methods information to " << out.GetLocation();
    536       return false;
    537     }
    538   }
    539   return true;
    540 }
    541 
    542 size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) {
    543   size_t relative_offset = oat_header_->GetExecutableOffset();
    544   off_t new_offset = out.Seek(size_executable_offset_alignment_, kSeekCurrent);
    545   size_t expected_file_offset = file_offset + relative_offset;
    546   if (static_cast<uint32_t>(new_offset) != expected_file_offset) {
    547     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
    548                 << " Expected: " << expected_file_offset << " File: " << out.GetLocation();
    549     return 0;
    550   }
    551   DCHECK_OFFSET();
    552   if (compiler_driver_->IsImage()) {
    553     InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
    554 
    555     #define DO_TRAMPOLINE(field) \
    556       do { \
    557         uint32_t aligned_offset = CompiledCode::AlignCode(relative_offset, instruction_set); \
    558         uint32_t alignment_padding = aligned_offset - relative_offset; \
    559         out.Seek(alignment_padding, kSeekCurrent); \
    560         size_trampoline_alignment_ += alignment_padding; \
    561         if (!out.WriteFully(&(*field)[0], field->size())) { \
    562           PLOG(ERROR) << "Failed to write " # field " to " << out.GetLocation(); \
    563           return false; \
    564         } \
    565         size_ ## field += field->size(); \
    566         relative_offset += alignment_padding + field->size(); \
    567         DCHECK_OFFSET(); \
    568       } while (false)
    569 
    570     DO_TRAMPOLINE(interpreter_to_interpreter_bridge_);
    571     DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_);
    572     DO_TRAMPOLINE(jni_dlsym_lookup_);
    573     DO_TRAMPOLINE(portable_resolution_trampoline_);
    574     DO_TRAMPOLINE(portable_to_interpreter_bridge_);
    575     DO_TRAMPOLINE(quick_resolution_trampoline_);
    576     DO_TRAMPOLINE(quick_to_interpreter_bridge_);
    577     #undef DO_TRAMPOLINE
    578   }
    579   return relative_offset;
    580 }
    581 
    582 size_t OatWriter::WriteCodeDexFiles(OutputStream& out,
    583                                     const size_t file_offset,
    584                                     size_t relative_offset) {
    585   size_t oat_class_index = 0;
    586   for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
    587     const DexFile* dex_file = (*dex_files_)[i];
    588     CHECK(dex_file != NULL);
    589     relative_offset = WriteCodeDexFile(out, file_offset, relative_offset, oat_class_index,
    590                                        *dex_file);
    591     if (relative_offset == 0) {
    592       return 0;
    593     }
    594   }
    595   return relative_offset;
    596 }
    597 
    598 size_t OatWriter::WriteCodeDexFile(OutputStream& out, const size_t file_offset,
    599                                    size_t relative_offset, size_t& oat_class_index,
    600                                    const DexFile& dex_file) {
    601   for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs();
    602       class_def_index++, oat_class_index++) {
    603     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
    604     relative_offset = WriteCodeClassDef(out, file_offset, relative_offset, oat_class_index,
    605                                         dex_file, class_def);
    606     if (relative_offset == 0) {
    607       return 0;
    608     }
    609   }
    610   return relative_offset;
    611 }
    612 
    613 void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx,
    614                                    const DexFile& dex_file, OutputStream& out) const {
    615   PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file)
    616       << " to " << out.GetLocation();
    617 }
    618 
    619 size_t OatWriter::WriteCodeClassDef(OutputStream& out,
    620                                     const size_t file_offset,
    621                                     size_t relative_offset,
    622                                     size_t oat_class_index,
    623                                     const DexFile& dex_file,
    624                                     const DexFile::ClassDef& class_def) {
    625   const byte* class_data = dex_file.GetClassData(class_def);
    626   if (class_data == NULL) {
    627     // ie. an empty class such as a marker interface
    628     return relative_offset;
    629   }
    630   ClassDataItemIterator it(dex_file, class_data);
    631   // Skip fields
    632   while (it.HasNextStaticField()) {
    633     it.Next();
    634   }
    635   while (it.HasNextInstanceField()) {
    636     it.Next();
    637   }
    638   // Process methods
    639   size_t class_def_method_index = 0;
    640   while (it.HasNextDirectMethod()) {
    641     bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0;
    642     relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
    643                                       class_def_method_index, is_static, it.GetMemberIndex(),
    644                                       dex_file);
    645     if (relative_offset == 0) {
    646       return 0;
    647     }
    648     class_def_method_index++;
    649     it.Next();
    650   }
    651   while (it.HasNextVirtualMethod()) {
    652     relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index,
    653                                       class_def_method_index, false, it.GetMemberIndex(), dex_file);
    654     if (relative_offset == 0) {
    655       return 0;
    656     }
    657     class_def_method_index++;
    658     it.Next();
    659   }
    660   return relative_offset;
    661 }
    662 
    663 size_t OatWriter::WriteCodeMethod(OutputStream& out, const size_t file_offset,
    664                                   size_t relative_offset, size_t oat_class_index,
    665                                   size_t class_def_method_index, bool is_static,
    666                                   uint32_t method_idx, const DexFile& dex_file) {
    667   const CompiledMethod* compiled_method =
    668       compiler_driver_->GetCompiledMethod(MethodReference(&dex_file, method_idx));
    669 
    670   OatMethodOffsets method_offsets =
    671       oat_classes_[oat_class_index]->method_offsets_[class_def_method_index];
    672 
    673 
    674   if (compiled_method != NULL) {  // ie. not an abstract method
    675 #if !defined(ART_USE_PORTABLE_COMPILER)
    676     uint32_t aligned_offset = compiled_method->AlignCode(relative_offset);
    677     uint32_t aligned_code_delta = aligned_offset - relative_offset;
    678     if (aligned_code_delta != 0) {
    679       off_t new_offset = out.Seek(aligned_code_delta, kSeekCurrent);
    680       size_code_alignment_ += aligned_code_delta;
    681       uint32_t expected_offset = file_offset + aligned_offset;
    682       if (static_cast<uint32_t>(new_offset) != expected_offset) {
    683         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
    684                     << " Expected: " << expected_offset << " File: " << out.GetLocation();
    685         return 0;
    686       }
    687       relative_offset += aligned_code_delta;
    688       DCHECK_OFFSET();
    689     }
    690     DCHECK_ALIGNED(relative_offset, kArmAlignment);
    691     const std::vector<uint8_t>& code = compiled_method->GetCode();
    692     uint32_t code_size = code.size() * sizeof(code[0]);
    693     CHECK_NE(code_size, 0U);
    694 
    695     // Deduplicate code arrays
    696     size_t code_offset = relative_offset + sizeof(code_size) + compiled_method->CodeDelta();
    697     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
    698     if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) {
    699       DCHECK(code_iter->second == method_offsets.code_offset_)
    700           << PrettyMethod(method_idx, dex_file);
    701     } else {
    702       DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
    703       if (!out.WriteFully(&code_size, sizeof(code_size))) {
    704         ReportWriteFailure("method code size", method_idx, dex_file, out);
    705         return 0;
    706       }
    707       size_code_size_ += sizeof(code_size);
    708       relative_offset += sizeof(code_size);
    709       DCHECK_OFFSET();
    710       if (!out.WriteFully(&code[0], code_size)) {
    711         ReportWriteFailure("method code", method_idx, dex_file, out);
    712         return 0;
    713       }
    714       size_code_ += code_size;
    715       relative_offset += code_size;
    716     }
    717     DCHECK_OFFSET();
    718 #endif
    719 
    720     const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
    721     size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
    722 
    723     // Deduplicate mapping tables
    724     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter =
    725         mapping_table_offsets_.find(&mapping_table);
    726     if (mapping_iter != mapping_table_offsets_.end() &&
    727         relative_offset != method_offsets.mapping_table_offset_) {
    728       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
    729           || mapping_iter->second == method_offsets.mapping_table_offset_)
    730           << PrettyMethod(method_idx, dex_file);
    731     } else {
    732       DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0)
    733           || relative_offset == method_offsets.mapping_table_offset_)
    734           << PrettyMethod(method_idx, dex_file);
    735       if (!out.WriteFully(&mapping_table[0], mapping_table_size)) {
    736         ReportWriteFailure("mapping table", method_idx, dex_file, out);
    737         return 0;
    738       }
    739       size_mapping_table_ += mapping_table_size;
    740       relative_offset += mapping_table_size;
    741     }
    742     DCHECK_OFFSET();
    743 
    744     const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
    745     size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
    746 
    747     // Deduplicate vmap tables
    748     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter =
    749         vmap_table_offsets_.find(&vmap_table);
    750     if (vmap_iter != vmap_table_offsets_.end() &&
    751         relative_offset != method_offsets.vmap_table_offset_) {
    752       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
    753           || vmap_iter->second == method_offsets.vmap_table_offset_)
    754           << PrettyMethod(method_idx, dex_file);
    755     } else {
    756       DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0)
    757           || relative_offset == method_offsets.vmap_table_offset_)
    758           << PrettyMethod(method_idx, dex_file);
    759       if (!out.WriteFully(&vmap_table[0], vmap_table_size)) {
    760         ReportWriteFailure("vmap table", method_idx, dex_file, out);
    761         return 0;
    762       }
    763       size_vmap_table_ += vmap_table_size;
    764       relative_offset += vmap_table_size;
    765     }
    766     DCHECK_OFFSET();
    767 
    768     const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap();
    769     size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]);
    770 
    771     // Deduplicate GC maps
    772     SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter =
    773         gc_map_offsets_.find(&gc_map);
    774     if (gc_map_iter != gc_map_offsets_.end() &&
    775         relative_offset != method_offsets.gc_map_offset_) {
    776       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
    777           || gc_map_iter->second == method_offsets.gc_map_offset_)
    778           << PrettyMethod(method_idx, dex_file);
    779     } else {
    780       DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0)
    781           || relative_offset == method_offsets.gc_map_offset_)
    782           << PrettyMethod(method_idx, dex_file);
    783       if (!out.WriteFully(&gc_map[0], gc_map_size)) {
    784         ReportWriteFailure("GC map", method_idx, dex_file, out);
    785         return 0;
    786       }
    787       size_gc_map_ += gc_map_size;
    788       relative_offset += gc_map_size;
    789     }
    790     DCHECK_OFFSET();
    791   }
    792 
    793   return relative_offset;
    794 }
    795 
    796 OatWriter::OatDexFile::OatDexFile(size_t offset, const DexFile& dex_file) {
    797   offset_ = offset;
    798   const std::string& location(dex_file.GetLocation());
    799   dex_file_location_size_ = location.size();
    800   dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
    801   dex_file_location_checksum_ = dex_file.GetLocationChecksum();
    802   dex_file_offset_ = 0;
    803   methods_offsets_.resize(dex_file.NumClassDefs());
    804 }
    805 
    806 size_t OatWriter::OatDexFile::SizeOf() const {
    807   return sizeof(dex_file_location_size_)
    808           + dex_file_location_size_
    809           + sizeof(dex_file_location_checksum_)
    810           + sizeof(dex_file_offset_)
    811           + (sizeof(methods_offsets_[0]) * methods_offsets_.size());
    812 }
    813 
    814 void OatWriter::OatDexFile::UpdateChecksum(OatHeader& oat_header) const {
    815   oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
    816   oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
    817   oat_header.UpdateChecksum(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_));
    818   oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
    819   oat_header.UpdateChecksum(&methods_offsets_[0],
    820                             sizeof(methods_offsets_[0]) * methods_offsets_.size());
    821 }
    822 
    823 bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,
    824                                   OutputStream& out,
    825                                   const size_t file_offset) const {
    826   DCHECK_OFFSET_();
    827   if (!out.WriteFully(&dex_file_location_size_, sizeof(dex_file_location_size_))) {
    828     PLOG(ERROR) << "Failed to write dex file location length to " << out.GetLocation();
    829     return false;
    830   }
    831   oat_writer->size_oat_dex_file_location_size_ += sizeof(dex_file_location_size_);
    832   if (!out.WriteFully(dex_file_location_data_, dex_file_location_size_)) {
    833     PLOG(ERROR) << "Failed to write dex file location data to " << out.GetLocation();
    834     return false;
    835   }
    836   oat_writer->size_oat_dex_file_location_data_ += dex_file_location_size_;
    837   if (!out.WriteFully(&dex_file_location_checksum_, sizeof(dex_file_location_checksum_))) {
    838     PLOG(ERROR) << "Failed to write dex file location checksum to " << out.GetLocation();
    839     return false;
    840   }
    841   oat_writer->size_oat_dex_file_location_checksum_ += sizeof(dex_file_location_checksum_);
    842   if (!out.WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
    843     PLOG(ERROR) << "Failed to write dex file offset to " << out.GetLocation();
    844     return false;
    845   }
    846   oat_writer->size_oat_dex_file_offset_ += sizeof(dex_file_offset_);
    847   if (!out.WriteFully(&methods_offsets_[0],
    848                       sizeof(methods_offsets_[0]) * methods_offsets_.size())) {
    849     PLOG(ERROR) << "Failed to write methods offsets to " << out.GetLocation();
    850     return false;
    851   }
    852   oat_writer->size_oat_dex_file_methods_offsets_ +=
    853       sizeof(methods_offsets_[0]) * methods_offsets_.size();
    854   return true;
    855 }
    856 
    857 OatWriter::OatClass::OatClass(size_t offset, mirror::Class::Status status, uint32_t methods_count) {
    858   offset_ = offset;
    859   status_ = status;
    860   method_offsets_.resize(methods_count);
    861 }
    862 
    863 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(
    864     size_t class_def_method_index_) const {
    865   return offset_ + GetOatMethodOffsetsOffsetFromOatClass(class_def_method_index_);
    866 }
    867 
    868 size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatClass(
    869     size_t class_def_method_index_) const {
    870   return sizeof(status_)
    871           + (sizeof(method_offsets_[0]) * class_def_method_index_);
    872 }
    873 
    874 size_t OatWriter::OatClass::SizeOf() const {
    875   return GetOatMethodOffsetsOffsetFromOatClass(method_offsets_.size());
    876 }
    877 
    878 void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
    879   oat_header.UpdateChecksum(&status_, sizeof(status_));
    880   oat_header.UpdateChecksum(&method_offsets_[0],
    881                             sizeof(method_offsets_[0]) * method_offsets_.size());
    882 }
    883 
    884 bool OatWriter::OatClass::Write(OatWriter* oat_writer,
    885                                 OutputStream& out,
    886                                 const size_t file_offset) const {
    887   DCHECK_OFFSET_();
    888   if (!out.WriteFully(&status_, sizeof(status_))) {
    889     PLOG(ERROR) << "Failed to write class status to " << out.GetLocation();
    890     return false;
    891   }
    892   oat_writer->size_oat_class_status_ += sizeof(status_);
    893   DCHECK_EQ(static_cast<off_t>(file_offset + GetOatMethodOffsetsOffsetFromOatHeader(0)),
    894             out.Seek(0, kSeekCurrent));
    895   if (!out.WriteFully(&method_offsets_[0],
    896                       sizeof(method_offsets_[0]) * method_offsets_.size())) {
    897     PLOG(ERROR) << "Failed to write method offsets to " << out.GetLocation();
    898     return false;
    899   }
    900   oat_writer->size_oat_class_method_offsets_ += sizeof(method_offsets_[0]) * method_offsets_.size();
    901   DCHECK_EQ(static_cast<off_t>(file_offset +
    902                                GetOatMethodOffsetsOffsetFromOatHeader(method_offsets_.size())),
    903             out.Seek(0, kSeekCurrent));
    904   return true;
    905 }
    906 
    907 }  // namespace art
    908