diff options
Diffstat (limited to 'compiler/oat_writer.cc')
| -rw-r--r-- | compiler/oat_writer.cc | 1271 | 
1 files changed, 712 insertions, 559 deletions
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index dc66e9c108..bbc9c3e325 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -38,6 +38,14 @@  namespace art { +#define DCHECK_OFFSET() \ +  DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \ +    << "file_offset=" << file_offset << " relative_offset=" << relative_offset + +#define DCHECK_OFFSET_() \ +  DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \ +    << "file_offset=" << file_offset << " offset_=" << offset_ +  OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,                       uint32_t image_file_location_oat_checksum,                       uintptr_t image_file_location_oat_begin, @@ -66,7 +74,7 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,      size_quick_resolution_trampoline_(0),      size_quick_to_interpreter_bridge_(0),      size_trampoline_alignment_(0), -    size_code_size_(0), +    size_method_header_(0),      size_code_(0),      size_code_alignment_(0),      size_mapping_table_(0), @@ -99,6 +107,10 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,      offset = InitOatClasses(offset);    }    { +    TimingLogger::ScopedSplit split("InitOatMaps", timings); +    offset = InitOatMaps(offset); +  } +  {      TimingLogger::ScopedSplit split("InitOatCode", timings);      offset = InitOatCode(offset);    } @@ -118,6 +130,605 @@ OatWriter::~OatWriter() {    STLDeleteElements(&oat_classes_);  } +struct OatWriter::GcMapDataAccess { +  static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE { +    return &compiled_method->GetGcMap(); +  } + +  static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE { +    return oat_class->method_offsets_[method_offsets_index].gc_map_offset_; +  } + +  static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset) +      ALWAYS_INLINE { +    oat_class->method_offsets_[method_offsets_index].gc_map_offset_ = offset; +  } + +  static const char* Name() ALWAYS_INLINE { +    return "GC map"; +  } +}; + +struct OatWriter::MappingTableDataAccess { +  static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE { +    return &compiled_method->GetMappingTable(); +  } + +  static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE { +    uint32_t offset = oat_class->method_headers_[method_offsets_index].mapping_table_offset_; +    return offset == 0u ? 0u : +        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; +  } + +  static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset) +      ALWAYS_INLINE { +    oat_class->method_headers_[method_offsets_index].mapping_table_offset_ = +        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; +  } + +  static const char* Name() ALWAYS_INLINE { +    return "mapping table"; +  } +}; + +struct OatWriter::VmapTableDataAccess { +  static const std::vector<uint8_t>* GetData(const CompiledMethod* compiled_method) ALWAYS_INLINE { +    return &compiled_method->GetVmapTable(); +  } + +  static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE { +    uint32_t offset = oat_class->method_headers_[method_offsets_index].vmap_table_offset_; +    return offset == 0u ? 0u : +        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; +  } + +  static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset) +      ALWAYS_INLINE { +    oat_class->method_headers_[method_offsets_index].vmap_table_offset_ = +        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset; +  } + +  static const char* Name() ALWAYS_INLINE { +    return "vmap table"; +  } +}; + +class OatWriter::DexMethodVisitor { + public: +  DexMethodVisitor(OatWriter* writer, size_t offset) +    : writer_(writer), +      offset_(offset), +      dex_file_(nullptr), +      class_def_index_(DexFile::kDexNoIndex) { +  } + +  virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) { +    DCHECK(dex_file_ == nullptr); +    DCHECK_EQ(class_def_index_, DexFile::kDexNoIndex); +    dex_file_ = dex_file; +    class_def_index_ = class_def_index; +    return true; +  } + +  virtual bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) = 0; + +  virtual bool EndClass() { +    if (kIsDebugBuild) { +      dex_file_ = nullptr; +      class_def_index_ = DexFile::kDexNoIndex; +    } +    return true; +  } + +  size_t GetOffset() const { +    return offset_; +  } + + protected: +  virtual ~DexMethodVisitor() { } + +  OatWriter* const writer_; + +  // The offset is usually advanced for each visited method by the derived class. +  size_t offset_; + +  // The dex file and class def index are set in StartClass(). +  const DexFile* dex_file_; +  size_t class_def_index_; +}; + +class OatWriter::OatDexMethodVisitor : public DexMethodVisitor { + public: +  OatDexMethodVisitor(OatWriter* writer, size_t offset) +    : DexMethodVisitor(writer, offset), +      oat_class_index_(0u), +      method_offsets_index_(0u) { +  } + +  bool StartClass(const DexFile* dex_file, size_t class_def_index) { +    DexMethodVisitor::StartClass(dex_file, class_def_index); +    DCHECK_LT(oat_class_index_, writer_->oat_classes_.size()); +    method_offsets_index_ = 0u; +    return true; +  } + +  bool EndClass() { +    ++oat_class_index_; +    return DexMethodVisitor::EndClass(); +  } + + protected: +  size_t oat_class_index_; +  size_t method_offsets_index_; +}; + +class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { + public: +  InitOatClassesMethodVisitor(OatWriter* writer, size_t offset) +    : DexMethodVisitor(writer, offset), +      compiled_methods_(), +      num_non_null_compiled_methods_(0u) { +    compiled_methods_.reserve(256u); +  } + +  bool StartClass(const DexFile* dex_file, size_t class_def_index) { +    DexMethodVisitor::StartClass(dex_file, class_def_index); +    compiled_methods_.clear(); +    num_non_null_compiled_methods_ = 0u; +    return true; +  } + +  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) { +    // Fill in the compiled_methods_ array for methods that have a +    // CompiledMethod. We track the number of non-null entries in +    // num_non_null_compiled_methods_ since we only want to allocate +    // OatMethodOffsets for the compiled methods. +    uint32_t method_idx = it.GetMemberIndex(); +    CompiledMethod* compiled_method = +        writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx)); +    compiled_methods_.push_back(compiled_method); +    if (compiled_method != nullptr) { +        ++num_non_null_compiled_methods_; +    } +    return true; +  } + +  bool EndClass() { +    ClassReference class_ref(dex_file_, class_def_index_); +    CompiledClass* compiled_class = writer_->compiler_driver_->GetCompiledClass(class_ref); +    mirror::Class::Status status; +    if (compiled_class != NULL) { +      status = compiled_class->GetStatus(); +    } else if (writer_->compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) { +      status = mirror::Class::kStatusError; +    } else { +      status = mirror::Class::kStatusNotReady; +    } + +    OatClass* oat_class = new OatClass(offset_, compiled_methods_, +                                       num_non_null_compiled_methods_, status); +    writer_->oat_classes_.push_back(oat_class); +    offset_ += oat_class->SizeOf(); +    return DexMethodVisitor::EndClass(); +  } + + private: +  std::vector<CompiledMethod*> compiled_methods_; +  size_t num_non_null_compiled_methods_; +}; + +class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { + public: +  InitCodeMethodVisitor(OatWriter* writer, size_t offset) +    : OatDexMethodVisitor(writer, offset) { +  } + +  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) +      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +    OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; +    CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); + +    if (compiled_method != nullptr) { +      // Derived from CompiledMethod. +      uint32_t quick_code_offset = 0; +      uint32_t frame_size_in_bytes = kStackAlignment; +      uint32_t core_spill_mask = 0; +      uint32_t fp_spill_mask = 0; + +      const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode(); +      const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode(); +      if (portable_code != nullptr) { +        CHECK(quick_code == nullptr); +        size_t oat_method_offsets_offset = +            oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index); +        compiled_method->AddOatdataOffsetToCompliledCodeOffset( +            oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_)); +      } else { +        CHECK(quick_code != nullptr); +        offset_ = compiled_method->AlignCode(offset_); +        DCHECK_ALIGNED_PARAM(offset_, +                             GetInstructionSetAlignment(compiled_method->GetInstructionSet())); +        uint32_t code_size = quick_code->size() * sizeof(uint8_t); +        CHECK_NE(code_size, 0U); +        uint32_t thumb_offset = compiled_method->CodeDelta(); +        quick_code_offset = offset_ + sizeof(OatMethodHeader) + thumb_offset; + +        std::vector<uint8_t>* cfi_info = writer_->compiler_driver_->GetCallFrameInformation(); +        if (cfi_info != nullptr) { +          // Copy in the FDE, if present +          const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo(); +          if (fde != nullptr) { +            // Copy the information into cfi_info and then fix the address in the new copy. +            int cur_offset = cfi_info->size(); +            cfi_info->insert(cfi_info->end(), fde->begin(), fde->end()); + +            // Set the 'initial_location' field to address the start of the method. +            uint32_t new_value = quick_code_offset - writer_->oat_header_->GetExecutableOffset(); +            uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t); +            (*cfi_info)[offset_to_update+0] = new_value; +            (*cfi_info)[offset_to_update+1] = new_value >> 8; +            (*cfi_info)[offset_to_update+2] = new_value >> 16; +            (*cfi_info)[offset_to_update+3] = new_value >> 24; +            std::string name = PrettyMethod(it.GetMemberIndex(), *dex_file_, false); +            writer_->method_info_.push_back(DebugInfo(name, new_value, new_value + code_size)); +          } +        } + +        DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size()); +        OatMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_]; +        method_header->code_size_ = code_size; + +        // Deduplicate code arrays. +        auto code_iter = dedupe_map_.find(compiled_method); +        if (code_iter != dedupe_map_.end()) { +          quick_code_offset = code_iter->second; +          FixupMethodHeader(method_header, quick_code_offset - thumb_offset); +        } else { +          dedupe_map_.Put(compiled_method, quick_code_offset); +          FixupMethodHeader(method_header, quick_code_offset - thumb_offset); +          writer_->oat_header_->UpdateChecksum(method_header, sizeof(*method_header)); +          offset_ += sizeof(*method_header);  // Method header is prepended before code. +          writer_->oat_header_->UpdateChecksum(&(*quick_code)[0], code_size); +          offset_ += code_size; +        } +      } +      frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); +      core_spill_mask = compiled_method->GetCoreSpillMask(); +      fp_spill_mask = compiled_method->GetFpSpillMask(); + +      if (kIsDebugBuild) { +        // We expect GC maps except when the class hasn't been verified or the method is native. +        const CompilerDriver* compiler_driver = writer_->compiler_driver_; +        ClassReference class_ref(dex_file_, class_def_index_); +        CompiledClass* compiled_class = compiler_driver->GetCompiledClass(class_ref); +        mirror::Class::Status status; +        if (compiled_class != NULL) { +          status = compiled_class->GetStatus(); +        } else if (compiler_driver->GetVerificationResults()->IsClassRejected(class_ref)) { +          status = mirror::Class::kStatusError; +        } else { +          status = mirror::Class::kStatusNotReady; +        } +        const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap(); +        size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); +        bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; +        CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified) +            << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " " +            << (status < mirror::Class::kStatusVerified) << " " << status << " " +            << PrettyMethod(it.GetMemberIndex(), *dex_file_); +      } + +      DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); +      OatMethodOffsets* offsets = &oat_class->method_offsets_[method_offsets_index_]; +      offsets->code_offset_ = quick_code_offset; +      offsets->frame_size_in_bytes_ = frame_size_in_bytes; +      offsets->core_spill_mask_ = core_spill_mask; +      offsets->fp_spill_mask_ = fp_spill_mask; +      ++method_offsets_index_; +    } + +    return true; +  } + + private: +  static void FixupMethodHeader(OatMethodHeader* method_header, uint32_t code_offset) { +    // The code offset was 0 when the mapping/vmap table offset was set, so it's set +    // to 0-offset and we need to adjust it by code_offset. +    if (method_header->mapping_table_offset_ != 0u) { +      method_header->mapping_table_offset_ += code_offset; +      DCHECK_LT(method_header->mapping_table_offset_, code_offset); +    } +    if (method_header->vmap_table_offset_ != 0u) { +      method_header->vmap_table_offset_ += code_offset; +      DCHECK_LT(method_header->vmap_table_offset_, code_offset); +    } +  } + +  // Deduplication is already done on a pointer basis by the compiler driver, +  // so we can simply compare the pointers to find out if things are duplicated. +  SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_; +}; + +template <typename DataAccess> +class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { + public: +  InitMapMethodVisitor(OatWriter* writer, size_t offset) +    : OatDexMethodVisitor(writer, offset) { +  } + +  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) +      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +    OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; +    CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); + +    if (compiled_method != nullptr) { +      DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); +      DCHECK_EQ(DataAccess::GetOffset(oat_class, method_offsets_index_), 0u); + +      const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method); +      uint32_t map_size = map->size() * sizeof((*map)[0]); +      if (map_size != 0u) { +        auto it = dedupe_map_.find(map); +        if (it != dedupe_map_.end()) { +          DataAccess::SetOffset(oat_class, method_offsets_index_, it->second); +        } else { +          DataAccess::SetOffset(oat_class, method_offsets_index_, offset_); +          dedupe_map_.Put(map, offset_); +          offset_ += map_size; +          writer_->oat_header_->UpdateChecksum(&(*map)[0], map_size); +        } +      } +      ++method_offsets_index_; +    } + +    return true; +  } + + private: +  // Deduplication is already done on a pointer basis by the compiler driver, +  // so we can simply compare the pointers to find out if things are duplicated. +  SafeMap<const std::vector<uint8_t>*, uint32_t> dedupe_map_; +}; + +class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { + public: +  InitImageMethodVisitor(OatWriter* writer, size_t offset) +    : OatDexMethodVisitor(writer, offset) { +  } + +  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) +      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { +    OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; +    CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); + +    OatMethodOffsets offsets(0u, kStackAlignment, 0u, 0u, 0u); +    if (compiled_method != nullptr) { +      DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size()); +      offsets = oat_class->method_offsets_[method_offsets_index_]; +      ++method_offsets_index_; +    } + +    // Derive frame size and spill masks for native methods without code: +    // These are generic JNI methods... +    uint32_t method_idx = it.GetMemberIndex(); +    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; +    if (is_native && compiled_method == nullptr) { +      // Compute Sirt size as putting _every_ reference into it, even null ones. +      uint32_t s_len; +      const char* shorty = dex_file_->GetMethodShorty(dex_file_->GetMethodId(method_idx), +                                                      &s_len); +      DCHECK(shorty != nullptr); +      uint32_t refs = 1;    // Native method always has "this" or class. +      for (uint32_t i = 1; i < s_len; ++i) { +        if (shorty[i] == 'L') { +          refs++; +        } +      } +      size_t pointer_size = GetInstructionSetPointerSize( +          writer_->compiler_driver_->GetInstructionSet()); +      size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(pointer_size, refs); + +      // Get the generic spill masks and base frame size. +      mirror::ArtMethod* callee_save_method = +          Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs); + +      offsets.frame_size_in_bytes_ = callee_save_method->GetFrameSizeInBytes() + sirt_size; +      offsets.core_spill_mask_ = callee_save_method->GetCoreSpillMask(); +      offsets.fp_spill_mask_ = callee_save_method->GetFpSpillMask(); +      DCHECK_EQ(offsets.gc_map_offset_, 0u); +    } + +    ClassLinker* linker = Runtime::Current()->GetClassLinker(); +    InvokeType invoke_type = it.GetMethodInvokeType(dex_file_->GetClassDef(class_def_index_)); +    // Unchecked as we hold mutator_lock_ on entry. +    ScopedObjectAccessUnchecked soa(Thread::Current()); +    SirtRef<mirror::DexCache> dex_cache(soa.Self(), linker->FindDexCache(*dex_file_)); +    SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr); +    mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, method_idx, dex_cache, +                                                      class_loader, nullptr, invoke_type); +    CHECK(method != NULL); +    method->SetFrameSizeInBytes(offsets.frame_size_in_bytes_); +    method->SetCoreSpillMask(offsets.core_spill_mask_); +    method->SetFpSpillMask(offsets.fp_spill_mask_); +    // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking. +    method->SetQuickOatCodeOffset(offsets.code_offset_); +    method->SetOatNativeGcMapOffset(offsets.gc_map_offset_); + +    return true; +  } +}; + +class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { + public: +  WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset, +                             size_t relative_offset) +    : OatDexMethodVisitor(writer, relative_offset), +      out_(out), +      file_offset_(file_offset) { +  } + +  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) { +    OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; +    const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); + +    if (compiled_method != NULL) {  // ie. not an abstract method +      size_t file_offset = file_offset_; +      OutputStream* out = out_; + +      const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode(); +      if (quick_code != nullptr) { +        CHECK(compiled_method->GetPortableCode() == nullptr); +        uint32_t aligned_offset = compiled_method->AlignCode(offset_); +        uint32_t aligned_code_delta = aligned_offset - offset_; +        if (aligned_code_delta != 0) { +          static const uint8_t kPadding[] = { +              0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u +          }; +          DCHECK_LE(aligned_code_delta, sizeof(kPadding)); +          if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) { +            ReportWriteFailure("code alignment padding", it); +            return false; +          } +          writer_->size_code_alignment_ += aligned_code_delta; +          offset_ += aligned_code_delta; +          DCHECK_OFFSET_(); +        } +        DCHECK_ALIGNED_PARAM(offset_, +                             GetInstructionSetAlignment(compiled_method->GetInstructionSet())); +        uint32_t code_size = quick_code->size() * sizeof(uint8_t); +        CHECK_NE(code_size, 0U); + +        // Deduplicate code arrays. +        const OatMethodOffsets& method_offsets = oat_class->method_offsets_[method_offsets_index_]; +        DCHECK(method_offsets.code_offset_ < offset_ || method_offsets.code_offset_ == +                   offset_ + sizeof(OatMethodHeader) + compiled_method->CodeDelta()) +            << PrettyMethod(it.GetMemberIndex(), *dex_file_); +        if (method_offsets.code_offset_ >= offset_) { +          const OatMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_]; +          if (!out->WriteFully(&method_header, sizeof(method_header))) { +            ReportWriteFailure("method header", it); +            return false; +          } +          writer_->size_method_header_ += sizeof(method_header); +          offset_ += sizeof(method_header); +          DCHECK_OFFSET_(); +          if (!out->WriteFully(&(*quick_code)[0], code_size)) { +            ReportWriteFailure("method code", it); +            return false; +          } +          writer_->size_code_ += code_size; +          offset_ += code_size; +        } +        DCHECK_OFFSET_(); +      } +      ++method_offsets_index_; +    } + +    return true; +  } + + private: +  OutputStream* const out_; +  size_t const file_offset_; + +  void ReportWriteFailure(const char* what, const ClassDataItemIterator& it) { +    PLOG(ERROR) << "Failed to write " << what << " for " +        << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation(); +  } +}; + +template <typename DataAccess> +class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { + public: +  WriteMapMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset, +                          size_t relative_offset) +    : OatDexMethodVisitor(writer, relative_offset), +      out_(out), +      file_offset_(file_offset) { +  } + +  bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) { +    OatClass* oat_class = writer_->oat_classes_[oat_class_index_]; +    const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); + +    if (compiled_method != NULL) {  // ie. not an abstract method +      size_t file_offset = file_offset_; +      OutputStream* out = out_; + +      uint32_t map_offset = DataAccess::GetOffset(oat_class, method_offsets_index_); +      ++method_offsets_index_; + +      // Write deduplicated map. +      const std::vector<uint8_t>* map = DataAccess::GetData(compiled_method); +      size_t map_size = map->size() * sizeof((*map)[0]); +      DCHECK((map_size == 0u && map_offset == 0u) || +            (map_size != 0u && map_offset != 0u && map_offset <= offset_)) +          << PrettyMethod(it.GetMemberIndex(), *dex_file_); +      if (map_size != 0u && map_offset == offset_) { +        if (UNLIKELY(!out->WriteFully(&(*map)[0], map_size))) { +          ReportWriteFailure(it); +          return false; +        } +        offset_ += map_size; +      } +      DCHECK_OFFSET_(); +    } + +    return true; +  } + + private: +  OutputStream* const out_; +  size_t const file_offset_; + +  void ReportWriteFailure(const ClassDataItemIterator& it) { +    PLOG(ERROR) << "Failed to write " << DataAccess::Name() << " for " +        << PrettyMethod(it.GetMemberIndex(), *dex_file_) << " to " << out_->GetLocation(); +  } +}; + +// Visit all methods from all classes in all dex files with the specified visitor. +bool OatWriter::VisitDexMethods(DexMethodVisitor* visitor) { +  for (const DexFile* dex_file : *dex_files_) { +    const size_t class_def_count = dex_file->NumClassDefs(); +    for (size_t class_def_index = 0; class_def_index != class_def_count; ++class_def_index) { +      if (UNLIKELY(!visitor->StartClass(dex_file, class_def_index))) { +        return false; +      } +      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); +      const byte* class_data = dex_file->GetClassData(class_def); +      if (class_data != NULL) {  // ie not an empty class, such as a marker interface +        ClassDataItemIterator it(*dex_file, class_data); +        while (it.HasNextStaticField()) { +          it.Next(); +        } +        while (it.HasNextInstanceField()) { +          it.Next(); +        } +        size_t class_def_method_index = 0u; +        while (it.HasNextDirectMethod()) { +          if (!visitor->VisitMethod(class_def_method_index, it)) { +            return false; +          } +          ++class_def_method_index; +          it.Next(); +        } +        while (it.HasNextVirtualMethod()) { +          if (UNLIKELY(!visitor->VisitMethod(class_def_method_index, it))) { +            return false; +          } +          ++class_def_method_index; +          it.Next(); +        } +      } +      if (UNLIKELY(!visitor->EndClass())) { +        return false; +      } +    } +  } +  return true; +} +  size_t OatWriter::InitOatHeader() {    // create the OatHeader    oat_header_ = new OatHeader(compiler_driver_->GetInstructionSet(), @@ -161,78 +772,42 @@ size_t OatWriter::InitDexFiles(size_t offset) {  }  size_t OatWriter::InitOatClasses(size_t offset) { -  // create the OatClasses    // calculate the offsets within OatDexFiles to OatClasses -  for (size_t i = 0; i != dex_files_->size(); ++i) { -    const DexFile* dex_file = (*dex_files_)[i]; -    for (size_t class_def_index = 0; -         class_def_index < dex_file->NumClassDefs(); -         class_def_index++) { -      oat_dex_files_[i]->methods_offsets_[class_def_index] = offset; -      const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); -      const byte* class_data = dex_file->GetClassData(class_def); -      uint32_t num_non_null_compiled_methods = 0; -      UniquePtr<std::vector<CompiledMethod*> > compiled_methods(new std::vector<CompiledMethod*>()); -      if (class_data != NULL) {  // ie not an empty class, such as a marker interface -        ClassDataItemIterator it(*dex_file, class_data); -        size_t num_direct_methods = it.NumDirectMethods(); -        size_t num_virtual_methods = it.NumVirtualMethods(); -        size_t num_methods = num_direct_methods + num_virtual_methods; - -        // Fill in the compiled_methods_ array for methods that have a -        // CompiledMethod. We track the number of non-null entries in -        // num_non_null_compiled_methods since we only want to allocate -        // OatMethodOffsets for the compiled methods. -        compiled_methods->reserve(num_methods); -        while (it.HasNextStaticField()) { -          it.Next(); -        } -        while (it.HasNextInstanceField()) { -          it.Next(); -        } -        size_t class_def_method_index = 0; -        while (it.HasNextDirectMethod()) { -          uint32_t method_idx = it.GetMemberIndex(); -          CompiledMethod* compiled_method = -              compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx)); -          compiled_methods->push_back(compiled_method); -          if (compiled_method != NULL) { -              num_non_null_compiled_methods++; -          } -          class_def_method_index++; -          it.Next(); -        } -        while (it.HasNextVirtualMethod()) { -          uint32_t method_idx = it.GetMemberIndex(); -          CompiledMethod* compiled_method = -              compiler_driver_->GetCompiledMethod(MethodReference(dex_file, method_idx)); -          compiled_methods->push_back(compiled_method); -          if (compiled_method != NULL) { -              num_non_null_compiled_methods++; -          } -          class_def_method_index++; -          it.Next(); -        } -      } - -      ClassReference class_ref(dex_file, class_def_index); -      CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref); -      mirror::Class::Status status; -      if (compiled_class != NULL) { -        status = compiled_class->GetStatus(); -      } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) { -        status = mirror::Class::kStatusError; -      } else { -        status = mirror::Class::kStatusNotReady; -      } - -      OatClass* oat_class = new OatClass(offset, compiled_methods.release(), -                                         num_non_null_compiled_methods, status); -      oat_classes_.push_back(oat_class); -      offset += oat_class->SizeOf(); +  InitOatClassesMethodVisitor visitor(this, offset); +  bool success = VisitDexMethods(&visitor); +  CHECK(success); +  offset = visitor.GetOffset(); + +  // Update oat_dex_files_. +  auto oat_class_it = oat_classes_.begin(); +  for (OatDexFile* oat_dex_file : oat_dex_files_) { +    for (uint32_t& offset : oat_dex_file->methods_offsets_) { +      DCHECK(oat_class_it != oat_classes_.end()); +      offset = (*oat_class_it)->offset_; +      ++oat_class_it;      } -    oat_dex_files_[i]->UpdateChecksum(oat_header_); +    oat_dex_file->UpdateChecksum(oat_header_);    } +  CHECK(oat_class_it == oat_classes_.end()); + +  return offset; +} + +size_t OatWriter::InitOatMaps(size_t offset) { +  #define VISIT(VisitorType)                          \ +    do {                                              \ +      VisitorType visitor(this, offset);              \ +      bool success = VisitDexMethods(&visitor);       \ +      DCHECK(success);                                \ +      offset = visitor.GetOffset();                   \ +    } while (false) + +  VISIT(InitMapMethodVisitor<GcMapDataAccess>); +  VISIT(InitMapMethodVisitor<MappingTableDataAccess>); +  VISIT(InitMapMethodVisitor<VmapTableDataAccess>); + +  #undef VISIT +    return offset;  } @@ -280,280 +855,24 @@ size_t OatWriter::InitOatCode(size_t offset) {  }  size_t OatWriter::InitOatCodeDexFiles(size_t offset) { -  size_t oat_class_index = 0; -  for (size_t i = 0; i != dex_files_->size(); ++i) { -    const DexFile* dex_file = (*dex_files_)[i]; -    CHECK(dex_file != NULL); -    offset = InitOatCodeDexFile(offset, &oat_class_index, *dex_file); -  } -  return offset; -} - -size_t OatWriter::InitOatCodeDexFile(size_t offset, -                                     size_t* oat_class_index, -                                     const DexFile& dex_file) { -  for (size_t class_def_index = 0; -       class_def_index < dex_file.NumClassDefs(); -       class_def_index++, (*oat_class_index)++) { -    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); -    offset = InitOatCodeClassDef(offset, *oat_class_index, class_def_index, dex_file, class_def); -    oat_classes_[*oat_class_index]->UpdateChecksum(oat_header_); -  } -  return offset; -} - -size_t OatWriter::InitOatCodeClassDef(size_t offset, -                                      size_t oat_class_index, size_t class_def_index, -                                      const DexFile& dex_file, -                                      const DexFile::ClassDef& class_def) { -  const byte* class_data = dex_file.GetClassData(class_def); -  if (class_data == NULL) { -    // empty class, such as a marker interface -    return offset; -  } -  ClassDataItemIterator it(dex_file, class_data); -  CHECK_LE(oat_classes_[oat_class_index]->method_offsets_.size(), -           it.NumDirectMethods() + it.NumVirtualMethods()); -  // Skip fields -  while (it.HasNextStaticField()) { -    it.Next(); -  } -  while (it.HasNextInstanceField()) { -    it.Next(); -  } -  // Process methods -  size_t class_def_method_index = 0; -  size_t method_offsets_index = 0; -  while (it.HasNextDirectMethod()) { -    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; -    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, -                               &method_offsets_index, is_native, -                               it.GetMethodInvokeType(class_def), it.GetMemberIndex(), dex_file); -    class_def_method_index++; -    it.Next(); -  } -  while (it.HasNextVirtualMethod()) { -    bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; -    offset = InitOatCodeMethod(offset, oat_class_index, class_def_index, class_def_method_index, -                               &method_offsets_index, is_native, -                               it.GetMethodInvokeType(class_def), it.GetMemberIndex(), dex_file); -    class_def_method_index++; -    it.Next(); -  } -  DCHECK(!it.HasNext()); -  CHECK_LE(method_offsets_index, class_def_method_index); -  return offset; -} - -size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, -                                    size_t __attribute__((unused)) class_def_index, -                                    size_t class_def_method_index, -                                    size_t* method_offsets_index, -                                    bool __attribute__((unused)) is_native, -                                    InvokeType invoke_type, -                                    uint32_t method_idx, const DexFile& dex_file) { -  // Derived from CompiledMethod if available. -  uint32_t quick_code_offset = 0; -  uint32_t frame_size_in_bytes = kStackAlignment; -  uint32_t core_spill_mask = 0; -  uint32_t fp_spill_mask = 0; -  uint32_t mapping_table_offset = 0; -  uint32_t vmap_table_offset = 0; -  uint32_t gc_map_offset = 0; - -  OatClass* oat_class = oat_classes_[oat_class_index]; -  CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); - -  if (compiled_method != nullptr) { -    const std::vector<uint8_t>* portable_code = compiled_method->GetPortableCode(); -    const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode(); -    if (portable_code != nullptr) { -      CHECK(quick_code == nullptr); -      size_t oat_method_offsets_offset = -          oat_class->GetOatMethodOffsetsOffsetFromOatHeader(class_def_method_index); -      compiled_method->AddOatdataOffsetToCompliledCodeOffset( -          oat_method_offsets_offset + OFFSETOF_MEMBER(OatMethodOffsets, code_offset_)); -    } else { -      CHECK(quick_code != nullptr); -      offset = compiled_method->AlignCode(offset); -      DCHECK_ALIGNED_PARAM(offset, -                           GetInstructionSetAlignment(compiled_method->GetInstructionSet())); - -      uint32_t code_size = quick_code->size() * sizeof(uint8_t); -      CHECK_NE(code_size, 0U); -      uint32_t thumb_offset = compiled_method->CodeDelta(); -      quick_code_offset = offset + sizeof(code_size) + thumb_offset; - -      std::vector<uint8_t>* cfi_info = compiler_driver_->GetCallFrameInformation(); -      if (cfi_info != nullptr) { -      // Copy in the FDE, if present -      const std::vector<uint8_t>* fde = compiled_method->GetCFIInfo(); -        if (fde != nullptr) { -          // Copy the information into cfi_info and then fix the address in the new copy. -          int cur_offset = cfi_info->size(); -          cfi_info->insert(cfi_info->end(), fde->begin(), fde->end()); - -          // Set the 'initial_location' field to address the start of the method. -          uint32_t new_value = quick_code_offset - oat_header_->GetExecutableOffset(); -          uint32_t offset_to_update = cur_offset + 2*sizeof(uint32_t); -          (*cfi_info)[offset_to_update+0] = new_value; -          (*cfi_info)[offset_to_update+1] = new_value >> 8; -          (*cfi_info)[offset_to_update+2] = new_value >> 16; -          (*cfi_info)[offset_to_update+3] = new_value >> 24; -          method_info_.push_back(DebugInfo(PrettyMethod(method_idx, dex_file, false), -                                           new_value, new_value + code_size)); -        } -      } - -      // Deduplicate code arrays -      SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = -          code_offsets_.find(quick_code); -      if (code_iter != code_offsets_.end()) { -        quick_code_offset = code_iter->second; -      } else { -        code_offsets_.Put(quick_code, quick_code_offset); -        offset += sizeof(code_size);  // code size is prepended before code -        offset += code_size; -        oat_header_->UpdateChecksum(&(*quick_code)[0], code_size); -      } -    } -    frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); -    core_spill_mask = compiled_method->GetCoreSpillMask(); -    fp_spill_mask = compiled_method->GetFpSpillMask(); - -    const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable(); -    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); -    mapping_table_offset = (mapping_table_size == 0) ? 0 : offset; - -    // Deduplicate mapping tables -    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter = -        mapping_table_offsets_.find(&mapping_table); -    if (mapping_iter != mapping_table_offsets_.end()) { -      mapping_table_offset = mapping_iter->second; -    } else { -      mapping_table_offsets_.Put(&mapping_table, mapping_table_offset); -      offset += mapping_table_size; -      oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size); -    } - -    const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable(); -    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); -    vmap_table_offset = (vmap_table_size == 0) ? 0 : offset; - -    // Deduplicate vmap tables -    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter = -        vmap_table_offsets_.find(&vmap_table); -    if (vmap_iter != vmap_table_offsets_.end()) { -      vmap_table_offset = vmap_iter->second; -    } else { -      vmap_table_offsets_.Put(&vmap_table, vmap_table_offset); -      offset += vmap_table_size; -      oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size); -    } - -    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap(); -    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); -    gc_map_offset = (gc_map_size == 0) ? 0 : offset; - -    if (kIsDebugBuild) { -      // We expect GC maps except when the class hasn't been verified or the method is native -      ClassReference class_ref(&dex_file, class_def_index); -      CompiledClass* compiled_class = compiler_driver_->GetCompiledClass(class_ref); -      mirror::Class::Status status; -      if (compiled_class != NULL) { -        status = compiled_class->GetStatus(); -      } else if (compiler_driver_->GetVerificationResults()->IsClassRejected(class_ref)) { -        status = mirror::Class::kStatusError; -      } else { -        status = mirror::Class::kStatusNotReady; -      } -      CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified) -          << &gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " " -          << (status < mirror::Class::kStatusVerified) << " " << status << " " -          << PrettyMethod(method_idx, dex_file); -    } - -    // Deduplicate GC maps -    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = -        gc_map_offsets_.find(&gc_map); -    if (gc_map_iter != gc_map_offsets_.end()) { -      gc_map_offset = gc_map_iter->second; -    } else { -      gc_map_offsets_.Put(&gc_map, gc_map_offset); -      offset += gc_map_size; -      oat_header_->UpdateChecksum(&gc_map[0], gc_map_size); -    } - -    oat_class->method_offsets_[*method_offsets_index] = -        OatMethodOffsets(quick_code_offset, -                         frame_size_in_bytes, -                         core_spill_mask, -                         fp_spill_mask, -                         mapping_table_offset, -                         vmap_table_offset, -                         gc_map_offset); -    (*method_offsets_index)++; -  } - - +  #define VISIT(VisitorType)                          \ +    do {                                              \ +      VisitorType visitor(this, offset);              \ +      bool success = VisitDexMethods(&visitor);       \ +      DCHECK(success);                                \ +      offset = visitor.GetOffset();                   \ +    } while (false) + +  VISIT(InitCodeMethodVisitor);    if (compiler_driver_->IsImage()) { -    // Derive frame size and spill masks for native methods without code: -    // These are generic JNI methods... -    if (is_native && compiled_method == nullptr) { -      // Compute Sirt size as putting _every_ reference into it, even null ones. -      uint32_t s_len; -      const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx), &s_len); -      DCHECK(shorty != nullptr); -      uint32_t refs = 1;    // Native method always has "this" or class. -      for (uint32_t i = 1; i < s_len; ++i) { -        if (shorty[i] == 'L') { -          refs++; -        } -      } -      size_t pointer_size = GetInstructionSetPointerSize(compiler_driver_->GetInstructionSet()); -      size_t sirt_size = StackIndirectReferenceTable::GetAlignedSirtSizeTarget(pointer_size, refs); - -      // Get the generic spill masks and base frame size. -      mirror::ArtMethod* callee_save_method = -          Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs); - -      frame_size_in_bytes = callee_save_method->GetFrameSizeInBytes() + sirt_size; -      core_spill_mask = callee_save_method->GetCoreSpillMask(); -      fp_spill_mask = callee_save_method->GetFpSpillMask(); -      mapping_table_offset = 0; -      vmap_table_offset = 0; -      gc_map_offset = 0; -    } - -    ClassLinker* linker = Runtime::Current()->GetClassLinker(); -    // Unchecked as we hold mutator_lock_ on entry. -    ScopedObjectAccessUnchecked soa(Thread::Current()); -    SirtRef<mirror::DexCache> dex_cache(soa.Self(), linker->FindDexCache(dex_file)); -    SirtRef<mirror::ClassLoader> class_loader(soa.Self(), nullptr); -    mirror::ArtMethod* method = linker->ResolveMethod(dex_file, method_idx, dex_cache, -                                                      class_loader, nullptr, invoke_type); -    CHECK(method != NULL); -    method->SetFrameSizeInBytes(frame_size_in_bytes); -    method->SetCoreSpillMask(core_spill_mask); -    method->SetFpSpillMask(fp_spill_mask); -    method->SetOatMappingTableOffset(mapping_table_offset); -    // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking. -    method->SetQuickOatCodeOffset(quick_code_offset); -    method->SetOatVmapTableOffset(vmap_table_offset); -    method->SetOatNativeGcMapOffset(gc_map_offset); +    VISIT(InitImageMethodVisitor);    } +  #undef VISIT +    return offset;  } -#define DCHECK_OFFSET() \ -  DCHECK_EQ(static_cast<off_t>(file_offset + relative_offset), out->Seek(0, kSeekCurrent)) \ -    << "file_offset=" << file_offset << " relative_offset=" << relative_offset - -#define DCHECK_OFFSET_() \ -  DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \ -    << "file_offset=" << file_offset << " offset_=" << offset_ -  bool OatWriter::Write(OutputStream* out) {    const size_t file_offset = out->Seek(0, kSeekCurrent); @@ -574,7 +893,14 @@ bool OatWriter::Write(OutputStream* out) {      return false;    } -  size_t relative_offset = WriteCode(out, file_offset); +  size_t relative_offset = out->Seek(0, kSeekCurrent) - file_offset; +  relative_offset = WriteMaps(out, file_offset, relative_offset); +  if (relative_offset == 0) { +    LOG(ERROR) << "Failed to write oat code to " << out->GetLocation(); +    return false; +  } + +  relative_offset = WriteCode(out, file_offset, relative_offset);    if (relative_offset == 0) {      LOG(ERROR) << "Failed to write oat code to " << out->GetLocation();      return false; @@ -608,7 +934,7 @@ bool OatWriter::Write(OutputStream* out) {      DO_STAT(size_quick_resolution_trampoline_);      DO_STAT(size_quick_to_interpreter_bridge_);      DO_STAT(size_trampoline_alignment_); -    DO_STAT(size_code_size_); +    DO_STAT(size_method_header_);      DO_STAT(size_code_);      DO_STAT(size_code_alignment_);      DO_STAT(size_mapping_table_); @@ -669,9 +995,37 @@ bool OatWriter::WriteTables(OutputStream* out, const size_t file_offset) {    return true;  } -size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset) { -  size_t relative_offset = oat_header_->GetExecutableOffset(); +size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) { +  #define VISIT(VisitorType)                                              \ +    do {                                                                  \ +      VisitorType visitor(this, out, file_offset, relative_offset);       \ +      if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \ +        return 0;                                                         \ +      }                                                                   \ +      relative_offset = visitor.GetOffset();                              \ +    } while (false) + +  size_t gc_maps_offset = relative_offset; +  VISIT(WriteMapMethodVisitor<GcMapDataAccess>); +  size_gc_map_ = relative_offset - gc_maps_offset; + +  size_t mapping_tables_offset = relative_offset; +  VISIT(WriteMapMethodVisitor<MappingTableDataAccess>); +  size_mapping_table_ = relative_offset - mapping_tables_offset; + +  size_t vmap_tables_offset = relative_offset; +  VISIT(WriteMapMethodVisitor<VmapTableDataAccess>); +  size_vmap_table_ = relative_offset - vmap_tables_offset; + +  #undef VISIT + +  return relative_offset; +} + +size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) {    off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent); +  relative_offset += size_executable_offset_alignment_; +  DCHECK_EQ(relative_offset, oat_header_->GetExecutableOffset());    size_t expected_file_offset = file_offset + relative_offset;    if (static_cast<uint32_t>(new_offset) != expected_file_offset) {      PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset @@ -715,218 +1069,18 @@ size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset) {  size_t OatWriter::WriteCodeDexFiles(OutputStream* out,                                      const size_t file_offset,                                      size_t relative_offset) { -  size_t oat_class_index = 0; -  for (size_t i = 0; i != oat_dex_files_.size(); ++i) { -    const DexFile* dex_file = (*dex_files_)[i]; -    CHECK(dex_file != NULL); -    relative_offset = WriteCodeDexFile(out, file_offset, relative_offset, &oat_class_index, -                                       *dex_file); -    if (relative_offset == 0) { -      return 0; -    } -  } -  return relative_offset; -} - -size_t OatWriter::WriteCodeDexFile(OutputStream* out, const size_t file_offset, -                                   size_t relative_offset, size_t* oat_class_index, -                                   const DexFile& dex_file) { -  for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); -      class_def_index++, (*oat_class_index)++) { -    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); -    relative_offset = WriteCodeClassDef(out, file_offset, relative_offset, *oat_class_index, -                                        dex_file, class_def); -    if (relative_offset == 0) { -      return 0; -    } -  } -  return relative_offset; -} - -void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx, -                                   const DexFile& dex_file, const OutputStream& out) const { -  PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file) -      << " to " << out.GetLocation(); -} +  #define VISIT(VisitorType)                                              \ +    do {                                                                  \ +      VisitorType visitor(this, out, file_offset, relative_offset);       \ +      if (UNLIKELY(!VisitDexMethods(&visitor))) {                         \ +        return 0;                                                         \ +      }                                                                   \ +      relative_offset = visitor.GetOffset();                              \ +    } while (false) -size_t OatWriter::WriteCodeClassDef(OutputStream* out, -                                    const size_t file_offset, -                                    size_t relative_offset, -                                    size_t oat_class_index, -                                    const DexFile& dex_file, -                                    const DexFile::ClassDef& class_def) { -  const byte* class_data = dex_file.GetClassData(class_def); -  if (class_data == NULL) { -    // ie. an empty class such as a marker interface -    return relative_offset; -  } -  ClassDataItemIterator it(dex_file, class_data); -  // Skip fields -  while (it.HasNextStaticField()) { -    it.Next(); -  } -  while (it.HasNextInstanceField()) { -    it.Next(); -  } -  // Process methods -  size_t class_def_method_index = 0; -  size_t method_offsets_index = 0; -  while (it.HasNextDirectMethod()) { -    bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; -    relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index, -                                      class_def_method_index, &method_offsets_index, is_static, -                                      it.GetMemberIndex(), dex_file); -    if (relative_offset == 0) { -      return 0; -    } -    class_def_method_index++; -    it.Next(); -  } -  while (it.HasNextVirtualMethod()) { -    relative_offset = WriteCodeMethod(out, file_offset, relative_offset, oat_class_index, -                                      class_def_method_index, &method_offsets_index, false, -                                      it.GetMemberIndex(), dex_file); -    if (relative_offset == 0) { -      return 0; -    } -    class_def_method_index++; -    it.Next(); -  } -  DCHECK(!it.HasNext()); -  CHECK_LE(method_offsets_index, class_def_method_index); -  return relative_offset; -} +  VISIT(WriteCodeMethodVisitor); -size_t OatWriter::WriteCodeMethod(OutputStream* out, const size_t file_offset, -                                  size_t relative_offset, size_t oat_class_index, -                                  size_t class_def_method_index, size_t* method_offsets_index, -                                  bool is_static, uint32_t method_idx, const DexFile& dex_file) { -  OatClass* oat_class = oat_classes_[oat_class_index]; -  const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); - -  if (compiled_method != NULL) {  // ie. not an abstract method -    const OatMethodOffsets method_offsets = oat_class->method_offsets_[*method_offsets_index]; -    (*method_offsets_index)++; -    const std::vector<uint8_t>* quick_code = compiled_method->GetQuickCode(); -    if (quick_code != nullptr) { -      CHECK(compiled_method->GetPortableCode() == nullptr); -      uint32_t aligned_offset = compiled_method->AlignCode(relative_offset); -      uint32_t aligned_code_delta = aligned_offset - relative_offset; -      if (aligned_code_delta != 0) { -        off_t new_offset = out->Seek(aligned_code_delta, kSeekCurrent); -        size_code_alignment_ += aligned_code_delta; -        uint32_t expected_offset = file_offset + aligned_offset; -        if (static_cast<uint32_t>(new_offset) != expected_offset) { -          PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset -              << " Expected: " << expected_offset << " File: " << out->GetLocation(); -          return 0; -        } -        relative_offset += aligned_code_delta; -        DCHECK_OFFSET(); -      } -      DCHECK_ALIGNED_PARAM(relative_offset, -                           GetInstructionSetAlignment(compiled_method->GetInstructionSet())); - -      uint32_t code_size = quick_code->size() * sizeof(uint8_t); -      CHECK_NE(code_size, 0U); - -      // Deduplicate code arrays -      size_t code_offset = relative_offset + sizeof(code_size) + compiled_method->CodeDelta(); -      SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = -          code_offsets_.find(quick_code); -      if (code_iter != code_offsets_.end() && code_offset != method_offsets.code_offset_) { -        DCHECK(code_iter->second == method_offsets.code_offset_) -              << PrettyMethod(method_idx, dex_file); -      } else { -        DCHECK(code_offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file); -        if (!out->WriteFully(&code_size, sizeof(code_size))) { -          ReportWriteFailure("method code size", method_idx, dex_file, *out); -          return 0; -        } -        size_code_size_ += sizeof(code_size); -        relative_offset += sizeof(code_size); -        DCHECK_OFFSET(); -        if (!out->WriteFully(&(*quick_code)[0], code_size)) { -          ReportWriteFailure("method code", method_idx, dex_file, *out); -          return 0; -        } -        size_code_ += code_size; -        relative_offset += code_size; -      } -      DCHECK_OFFSET(); -    } -    const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable(); -    size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); - -    // Deduplicate mapping tables -    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator mapping_iter = -        mapping_table_offsets_.find(&mapping_table); -    if (mapping_iter != mapping_table_offsets_.end() && -        relative_offset != method_offsets.mapping_table_offset_) { -      DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) -          || mapping_iter->second == method_offsets.mapping_table_offset_) -          << PrettyMethod(method_idx, dex_file); -    } else { -      DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) -          || relative_offset == method_offsets.mapping_table_offset_) -          << PrettyMethod(method_idx, dex_file); -      if (!out->WriteFully(&mapping_table[0], mapping_table_size)) { -        ReportWriteFailure("mapping table", method_idx, dex_file, *out); -        return 0; -      } -      size_mapping_table_ += mapping_table_size; -      relative_offset += mapping_table_size; -    } -    DCHECK_OFFSET(); - -    const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable(); -    size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); - -    // Deduplicate vmap tables -    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator vmap_iter = -        vmap_table_offsets_.find(&vmap_table); -    if (vmap_iter != vmap_table_offsets_.end() && -        relative_offset != method_offsets.vmap_table_offset_) { -      DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) -          || vmap_iter->second == method_offsets.vmap_table_offset_) -          << PrettyMethod(method_idx, dex_file); -    } else { -      DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) -          || relative_offset == method_offsets.vmap_table_offset_) -          << PrettyMethod(method_idx, dex_file); -      if (!out->WriteFully(&vmap_table[0], vmap_table_size)) { -        ReportWriteFailure("vmap table", method_idx, dex_file, *out); -        return 0; -      } -      size_vmap_table_ += vmap_table_size; -      relative_offset += vmap_table_size; -    } -    DCHECK_OFFSET(); - -    const std::vector<uint8_t>& gc_map = compiled_method->GetGcMap(); -    size_t gc_map_size = gc_map.size() * sizeof(gc_map[0]); - -    // Deduplicate GC maps -    SafeMap<const std::vector<uint8_t>*, uint32_t>::iterator gc_map_iter = -        gc_map_offsets_.find(&gc_map); -    if (gc_map_iter != gc_map_offsets_.end() && -        relative_offset != method_offsets.gc_map_offset_) { -      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0) -          || gc_map_iter->second == method_offsets.gc_map_offset_) -          << PrettyMethod(method_idx, dex_file); -    } else { -      DCHECK((gc_map_size == 0 && method_offsets.gc_map_offset_ == 0) -          || relative_offset == method_offsets.gc_map_offset_) -          << PrettyMethod(method_idx, dex_file); -      if (!out->WriteFully(&gc_map[0], gc_map_size)) { -        ReportWriteFailure("GC map", method_idx, dex_file, *out); -        return 0; -      } -      size_gc_map_ += gc_map_size; -      relative_offset += gc_map_size; -    } -    DCHECK_OFFSET(); -  } +  #undef VISIT    return relative_offset;  } @@ -993,15 +1147,14 @@ bool OatWriter::OatDexFile::Write(OatWriter* oat_writer,  }  OatWriter::OatClass::OatClass(size_t offset, -                              std::vector<CompiledMethod*>* compiled_methods, +                              const std::vector<CompiledMethod*>& compiled_methods,                                uint32_t num_non_null_compiled_methods, -                              mirror::Class::Status status) { -  CHECK(compiled_methods !=  NULL); -  uint32_t num_methods = compiled_methods->size(); +                              mirror::Class::Status status) +    : compiled_methods_(compiled_methods) { +  uint32_t num_methods = compiled_methods.size();    CHECK_LE(num_non_null_compiled_methods, num_methods);    offset_ = offset; -  compiled_methods_ = compiled_methods;    oat_method_offsets_offsets_from_oat_class_.resize(num_methods);    // Since both kOatClassNoneCompiled and kOatClassAllCompiled could @@ -1020,6 +1173,7 @@ OatWriter::OatClass::OatClass(size_t offset,    status_ = status;    method_offsets_.resize(num_non_null_compiled_methods); +  method_headers_.resize(num_non_null_compiled_methods);    uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);    if (type_ == kOatClassSomeCompiled) { @@ -1033,7 +1187,7 @@ OatWriter::OatClass::OatClass(size_t offset,    }    for (size_t i = 0; i < num_methods; i++) { -    CompiledMethod* compiled_method = (*compiled_methods_)[i]; +    CompiledMethod* compiled_method = compiled_methods_[i];      if (compiled_method == NULL) {        oat_method_offsets_offsets_from_oat_class_[i] = 0;      } else { @@ -1048,7 +1202,6 @@ OatWriter::OatClass::OatClass(size_t offset,  OatWriter::OatClass::~OatClass() {    delete method_bitmap_; -  delete compiled_methods_;  }  size_t OatWriter::OatClass::GetOatMethodOffsetsOffsetFromOatHeader(  |