diff options
| -rw-r--r-- | dex2oat/linker/oat_writer.cc | 16 | ||||
| -rw-r--r-- | dexlayout/compact_dex_writer.cc | 218 | ||||
| -rw-r--r-- | dexlayout/compact_dex_writer.h | 122 | ||||
| -rw-r--r-- | dexlayout/dex_container.h | 80 | ||||
| -rw-r--r-- | dexlayout/dex_ir.h | 4 | ||||
| -rw-r--r-- | dexlayout/dex_writer.cc | 616 | ||||
| -rw-r--r-- | dexlayout/dex_writer.h | 234 | ||||
| -rw-r--r-- | dexlayout/dexlayout.cc | 74 | ||||
| -rw-r--r-- | dexlayout/dexlayout.h | 35 | ||||
| -rw-r--r-- | dexlayout/dexlayout_main.cc | 7 | ||||
| -rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc | 20 | ||||
| -rw-r--r-- | runtime/dex/dex_file_verifier.cc | 8 |
12 files changed, 878 insertions, 556 deletions
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index f790db2b6c..ccb3ad8103 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -39,6 +39,7 @@ #include "dex/dex_file_types.h" #include "dex/standard_dex_file.h" #include "dex/verification_results.h" +#include "dex_container.h" #include "dexlayout.h" #include "driver/compiler_driver-inl.h" #include "driver/compiler_options.h" @@ -3496,18 +3497,21 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil return false; } Options options; - options.output_to_memmap_ = true; options.compact_dex_level_ = compact_dex_level_; options.update_checksum_ = true; - DexLayout dex_layout(options, profile_compilation_info_, nullptr); - dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0); - std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap()); + DexLayout dex_layout(options, profile_compilation_info_, /*file*/ nullptr, /*header*/ nullptr); + std::unique_ptr<DexContainer> out_data; + dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0, &out_data); oat_dex_file->dex_sections_layout_ = dex_layout.GetSections(); // Dex layout can affect the size of the dex file, so we update here what we have set // when adding the dex file as a source. - const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(mem_map->Begin()); + const UnalignedDexFileHeader* header = + AsUnalignedDexFileHeader(out_data->GetMainSection()->Begin()); oat_dex_file->dex_file_size_ = header->file_size_; - if (!WriteDexFile(out, oat_dex_file, mem_map->Begin(), /* update_input_vdex */ false)) { + if (!WriteDexFile(out, + oat_dex_file, + out_data->GetMainSection()->Begin(), + /* update_input_vdex */ false)) { return false; } CHECK_EQ(oat_dex_file->dex_file_location_checksum_, dex_file->GetLocationChecksum()); diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc index dd1eee7c59..2f601b6b1a 100644 --- a/dexlayout/compact_dex_writer.cc +++ b/dexlayout/compact_dex_writer.cc @@ -24,20 +24,20 @@ namespace art { -CompactDexWriter::CompactDexWriter(dex_ir::Header* header, - MemMap* mem_map, - DexLayout* dex_layout, - CompactDexLevel compact_dex_level) - : DexWriter(header, mem_map, dex_layout, /*compute_offsets*/ true), - compact_dex_level_(compact_dex_level), - data_dedupe_(/*bucket_count*/ 32, - HashedMemoryRange::HashEqual(mem_map->Begin()), - HashedMemoryRange::HashEqual(mem_map->Begin())) { - CHECK(compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone); +CompactDexWriter::CompactDexWriter(DexLayout* dex_layout) + : DexWriter(dex_layout, /*compute_offsets*/ true) { + CHECK(GetCompactDexLevel() != CompactDexLevel::kCompactDexLevelNone); } -uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(uint32_t offset) { - const uint32_t start_offset = offset; +CompactDexLevel CompactDexWriter::GetCompactDexLevel() const { + return dex_layout_->GetOptions().compact_dex_level_; +} + +CompactDexWriter::Container::Container(bool dedupe_code_items) + : code_item_dedupe_(dedupe_code_items, &data_section_) {} + +uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) { + const uint32_t start_offset = stream->Tell(); const dex_ir::Collections& collections = header_->GetCollections(); // Debug offsets for method indexes. 0 means no debug info. std::vector<uint32_t> debug_info_offsets(collections.MethodIdsSize(), 0u); @@ -79,15 +79,16 @@ uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(uint32_t offset) { &debug_info_base_, &debug_info_offsets_table_offset_); // Align the table and write it out. - offset = RoundUp(offset, CompactDexDebugInfoOffsetTable::kAlignment); - debug_info_offsets_pos_ = offset; - offset += Write(data.data(), data.size(), offset); + stream->AlignTo(CompactDexDebugInfoOffsetTable::kAlignment); + debug_info_offsets_pos_ = stream->Tell(); + stream->Write(data.data(), data.size()); // Verify that the whole table decodes as expected and measure average performance. const bool kMeasureAndTestOutput = dex_layout_->GetOptions().verify_output_; if (kMeasureAndTestOutput && !debug_info_offsets.empty()) { uint64_t start_time = NanoTime(); - CompactDexDebugInfoOffsetTable::Accessor accessor(mem_map_->Begin() + debug_info_offsets_pos_, + stream->Begin(); + CompactDexDebugInfoOffsetTable::Accessor accessor(stream->Begin() + debug_info_offsets_pos_, debug_info_base_, debug_info_offsets_table_offset_); @@ -99,19 +100,19 @@ uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(uint32_t offset) { << (end_time - start_time) / debug_info_offsets.size(); } - return offset - start_offset; + return stream->Tell() - start_offset; } -uint32_t CompactDexWriter::WriteCodeItem(dex_ir::CodeItem* code_item, - uint32_t offset, +uint32_t CompactDexWriter::WriteCodeItem(Stream* stream, + dex_ir::CodeItem* code_item, bool reserve_only) { DCHECK(code_item != nullptr); DCHECK(!reserve_only) << "Not supported because of deduping."; - const uint32_t start_offset = offset; + const uint32_t start_offset = stream->Tell(); // Align to minimum requirements, additional alignment requirements are handled below after we // know the preheader size. - offset = RoundUp(offset, CompactDexFile::CodeItem::kAlignment); + stream->AlignTo(CompactDexFile::CodeItem::kAlignment); CompactDexFile::CodeItem disk_code_item; @@ -127,7 +128,7 @@ uint32_t CompactDexWriter::WriteCodeItem(dex_ir::CodeItem* code_item, const size_t preheader_bytes = (preheader_end - preheader) * sizeof(preheader[0]); static constexpr size_t kPayloadInstructionRequiredAlignment = 4; - const uint32_t current_code_item_start = offset + preheader_bytes; + const uint32_t current_code_item_start = stream->Tell() + preheader_bytes; if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment)) { // If the preheader is going to make the code unaligned, consider adding 2 bytes of padding // before if required. @@ -137,49 +138,60 @@ uint32_t CompactDexWriter::WriteCodeItem(dex_ir::CodeItem* code_item, if (opcode == Instruction::FILL_ARRAY_DATA || opcode == Instruction::PACKED_SWITCH || opcode == Instruction::SPARSE_SWITCH) { - offset += RoundUp(current_code_item_start, kPayloadInstructionRequiredAlignment) - - current_code_item_start; + stream->Skip( + RoundUp(current_code_item_start, kPayloadInstructionRequiredAlignment) - + current_code_item_start); break; } } } - const uint32_t data_start = offset; + const uint32_t data_start = stream->Tell(); // Write preheader first. - offset += Write(reinterpret_cast<const uint8_t*>(preheader), preheader_bytes, offset); + stream->Write(reinterpret_cast<const uint8_t*>(preheader), preheader_bytes); // Registered offset is after the preheader. - ProcessOffset(&offset, code_item); + ProcessOffset(stream, code_item); // Avoid using sizeof so that we don't write the fake instruction array at the end of the code // item. - offset += Write(&disk_code_item, - OFFSETOF_MEMBER(CompactDexFile::CodeItem, insns_), - offset); + stream->Write(&disk_code_item, OFFSETOF_MEMBER(CompactDexFile::CodeItem, insns_)); // Write the instructions. - offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset); + stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t)); // Write the post instruction data. - offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only); + WriteCodeItemPostInstructionData(stream, code_item, reserve_only); - if (dex_layout_->GetOptions().dedupe_code_items_ && compute_offsets_) { - // After having written, try to dedupe the whole code item (excluding padding). - uint32_t deduped_offset = DedupeData(data_start, offset, code_item->GetOffset()); - if (deduped_offset != kDidNotDedupe) { + if (compute_offsets_) { + // After having written, maybe dedupe the whole code item (excluding padding). + const uint32_t deduped_offset = code_item_dedupe_->Dedupe(data_start, + stream->Tell(), + code_item->GetOffset()); + if (deduped_offset != Deduper::kDidNotDedupe) { code_item->SetOffset(deduped_offset); // Undo the offset for all that we wrote since we deduped. - offset = start_offset; + stream->Seek(start_offset); } } - return offset - start_offset; + return stream->Tell() - start_offset; } -uint32_t CompactDexWriter::DedupeData(uint32_t data_start, - uint32_t data_end, - uint32_t item_offset) { + +CompactDexWriter::Deduper::Deduper(bool enabled, DexContainer::Section* section) + : enabled_(enabled), + dedupe_map_(/*bucket_count*/ 32, + HashedMemoryRange::HashEqual(section), + HashedMemoryRange::HashEqual(section)) {} + +uint32_t CompactDexWriter::Deduper::Dedupe(uint32_t data_start, + uint32_t data_end, + uint32_t item_offset) { + if (!enabled_) { + return kDidNotDedupe; + } HashedMemoryRange range {data_start, data_end - data_start}; - auto existing = data_dedupe_.emplace(range, item_offset); + auto existing = dedupe_map_.emplace(range, item_offset); if (!existing.second) { - // Failed to insert, item already existed in the map. + // Failed to insert means we deduped, return the existing item offset. return existing.first->second; } return kDidNotDedupe; @@ -223,7 +235,7 @@ void CompactDexWriter::SortDebugInfosByMethodIndex() { }); } -void CompactDexWriter::WriteHeader() { +void CompactDexWriter::WriteHeader(Stream* stream) { CompactDexFile::Header header; CompactDexFile::WriteMagic(&header.magic_[0]); CompactDexFile::WriteCurrentVersion(&header.magic_[0]); @@ -263,78 +275,99 @@ void CompactDexWriter::WriteHeader() { if (header_->SupportDefaultMethods()) { header.feature_flags_ |= static_cast<uint32_t>(CompactDexFile::FeatureFlags::kDefaultMethods); } - UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u)); + stream->Seek(0); + stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header)); } size_t CompactDexWriter::GetHeaderSize() const { return sizeof(CompactDexFile::Header); } -void CompactDexWriter::WriteMemMap() { +void CompactDexWriter::Write(DexContainer* output) { + CHECK(output->IsCompactDexContainer()); + Container* const container = down_cast<Container*>(output); + // For now, use the same stream for both data and metadata. + Stream stream(output->GetMainSection()); + Stream* main_stream = &stream; + Stream* data_stream = &stream; + code_item_dedupe_ = &container->code_item_dedupe_; + // Starting offset is right after the header. - uint32_t offset = GetHeaderSize(); + main_stream->Seek(GetHeaderSize()); dex_ir::Collections& collection = header_->GetCollections(); // Based on: https://source.android.com/devices/tech/dalvik/dex-format // Since the offsets may not be calculated already, the writing must be done in the correct order. - const uint32_t string_ids_offset = offset; - offset += WriteStringIds(offset, /*reserve_only*/ true); - offset += WriteTypeIds(offset); - const uint32_t proto_ids_offset = offset; - offset += WriteProtoIds(offset, /*reserve_only*/ true); - offset += WriteFieldIds(offset); - offset += WriteMethodIds(offset); - const uint32_t class_defs_offset = offset; - offset += WriteClassDefs(offset, /*reserve_only*/ true); - const uint32_t call_site_ids_offset = offset; - offset += WriteCallSiteIds(offset, /*reserve_only*/ true); - offset += WriteMethodHandles(offset); + const uint32_t string_ids_offset = main_stream->Tell(); + WriteStringIds(main_stream, /*reserve_only*/ true); + WriteTypeIds(main_stream); + const uint32_t proto_ids_offset = main_stream->Tell(); + WriteProtoIds(main_stream, /*reserve_only*/ true); + WriteFieldIds(main_stream); + WriteMethodIds(main_stream); + const uint32_t class_defs_offset = main_stream->Tell(); + WriteClassDefs(main_stream, /*reserve_only*/ true); + const uint32_t call_site_ids_offset = main_stream->Tell(); + WriteCallSiteIds(main_stream, /*reserve_only*/ true); + WriteMethodHandles(main_stream); uint32_t data_offset_ = 0u; if (compute_offsets_) { // Data section. - offset = RoundUp(offset, kDataSectionAlignment); - data_offset_ = offset; + data_stream->AlignTo(kDataSectionAlignment); + data_offset_ = data_stream->Tell(); } // Write code item first to minimize the space required for encoded methods. // For cdex, the code items don't depend on the debug info. - offset += WriteCodeItems(offset, /*reserve_only*/ false); + WriteCodeItems(data_stream, /*reserve_only*/ false); // Sort the debug infos by method index order, this reduces size by ~0.1% by reducing the size of // the debug info offset table. SortDebugInfosByMethodIndex(); - offset += WriteDebugInfoItems(offset); + WriteDebugInfoItems(data_stream); - offset += WriteEncodedArrays(offset); - offset += WriteAnnotations(offset); - offset += WriteAnnotationSets(offset); - offset += WriteAnnotationSetRefs(offset); - offset += WriteAnnotationsDirectories(offset); - offset += WriteTypeLists(offset); - offset += WriteClassDatas(offset); - offset += WriteStringDatas(offset); + WriteEncodedArrays(data_stream); + WriteAnnotations(data_stream); + WriteAnnotationSets(data_stream); + WriteAnnotationSetRefs(data_stream); + WriteAnnotationsDirectories(data_stream); + WriteTypeLists(data_stream); + WriteClassDatas(data_stream); + WriteStringDatas(data_stream); // Write delayed id sections that depend on data sections. - WriteStringIds(string_ids_offset, /*reserve_only*/ false); - WriteProtoIds(proto_ids_offset, /*reserve_only*/ false); - WriteClassDefs(class_defs_offset, /*reserve_only*/ false); - WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false); + { + Stream::ScopedSeek seek(main_stream, string_ids_offset); + WriteStringIds(main_stream, /*reserve_only*/ false); + } + { + Stream::ScopedSeek seek(main_stream, proto_ids_offset); + WriteProtoIds(main_stream, /*reserve_only*/ false); + } + { + Stream::ScopedSeek seek(main_stream, class_defs_offset); + WriteClassDefs(main_stream, /*reserve_only*/ false); + } + { + Stream::ScopedSeek seek(main_stream, call_site_ids_offset); + WriteCallSiteIds(main_stream, /*reserve_only*/ false); + } // Write the map list. if (compute_offsets_) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList)); - collection.SetMapListOffset(offset); + data_stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList)); + collection.SetMapListOffset(data_stream->Tell()); } else { - offset = collection.MapListOffset(); + data_stream->Seek(collection.MapListOffset()); } - offset += GenerateAndWriteMapItems(offset); - offset = RoundUp(offset, kDataSectionAlignment); + GenerateAndWriteMapItems(data_stream); + data_stream->AlignTo(kDataSectionAlignment); // Map items are included in the data section. if (compute_offsets_) { - header_->SetDataSize(offset - data_offset_); + header_->SetDataSize(data_stream->Tell() - data_offset_); if (header_->DataSize() != 0) { // Offset must be zero when the size is zero. header_->SetDataOffset(data_offset_); @@ -348,25 +381,34 @@ void CompactDexWriter::WriteMemMap() { if (link_data.size() > 0) { CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size())); if (compute_offsets_) { - header_->SetLinkOffset(offset); + header_->SetLinkOffset(data_stream->Tell()); + } else { + data_stream->Seek(header_->LinkOffset()); } - offset += Write(&link_data[0], link_data.size(), header_->LinkOffset()); + data_stream->Write(&link_data[0], link_data.size()); } // Write debug info offset table last to make dex file verifier happy. - offset += WriteDebugInfoOffsetTable(offset); + WriteDebugInfoOffsetTable(data_stream); // Write header last. if (compute_offsets_) { - header_->SetFileSize(offset); + header_->SetFileSize(main_stream->Tell()); } - WriteHeader(); + WriteHeader(main_stream); if (dex_layout_->GetOptions().update_checksum_) { - header_->SetChecksum(DexFile::CalculateChecksum(mem_map_->Begin(), offset)); + header_->SetChecksum(DexFile::CalculateChecksum(main_stream->Begin(), header_->FileSize())); // Rewrite the header with the calculated checksum. - WriteHeader(); + WriteHeader(main_stream); } + // Trim the map to make it sized as large as the dex file. + output->GetMainSection()->Resize(header_->FileSize()); +} + +std::unique_ptr<DexContainer> CompactDexWriter::CreateDexContainer() const { + return std::unique_ptr<DexContainer>( + new CompactDexWriter::Container(dex_layout_->GetOptions().dedupe_code_items_)); } } // namespace art diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h index cb53caebc6..626b85a86b 100644 --- a/dexlayout/compact_dex_writer.h +++ b/dexlayout/compact_dex_writer.h @@ -19,6 +19,7 @@ #ifndef ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ #define ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ +#include <memory> // For unique_ptr #include <unordered_map> #include "dex_writer.h" @@ -26,62 +27,108 @@ namespace art { -class HashedMemoryRange { +// Compact dex writer for a single dex. +class CompactDexWriter : public DexWriter { public: - uint32_t offset_; - uint32_t length_; + explicit CompactDexWriter(DexLayout* dex_layout); - class HashEqual { + protected: + class Deduper { public: - explicit HashEqual(const uint8_t* data) : data_(data) {} + static const uint32_t kDidNotDedupe = 0; - // Equal function. - bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const { - return a.length_ == b.length_ && std::equal(data_ + a.offset_, - data_ + a.offset_ + a.length_, - data_ + b.offset_); - } + // if not enabled, Dedupe will always return kDidNotDedupe. + explicit Deduper(bool enabled, DexContainer::Section* section); - // Hash function. - size_t operator()(const HashedMemoryRange& range) const { - return HashBytes(data_ + range.offset_, range.length_); - } + // Deduplicate a blob of data that has been written to mem_map. + // Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur. + uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset); private: - const uint8_t* data_; + class HashedMemoryRange { + public: + uint32_t offset_; + uint32_t length_; + + class HashEqual { + public: + explicit HashEqual(DexContainer::Section* section) : section_(section) {} + + // Equal function. + bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const { + if (a.length_ != b.length_) { + return false; + } + const uint8_t* data = Data(); + return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_); + } + + // Hash function. + size_t operator()(const HashedMemoryRange& range) const { + return HashBytes(Data() + range.offset_, range.length_); + } + + ALWAYS_INLINE uint8_t* Data() const { + return section_->Begin(); + } + + private: + DexContainer::Section* const section_; + }; + }; + + const bool enabled_; + + // Dedupe map. + std::unordered_map<HashedMemoryRange, + uint32_t, + HashedMemoryRange::HashEqual, + HashedMemoryRange::HashEqual> dedupe_map_; }; -}; -class CompactDexWriter : public DexWriter { public: - CompactDexWriter(dex_ir::Header* header, - MemMap* mem_map, - DexLayout* dex_layout, - CompactDexLevel compact_dex_level); + class Container : public DexContainer { + public: + Section* GetMainSection() OVERRIDE { + return &main_section_; + } + + Section* GetDataSection() OVERRIDE { + return &data_section_; + } + + bool IsCompactDexContainer() const OVERRIDE { + return true; + } + + private: + explicit Container(bool dedupe_code_items); + + VectorSection main_section_; + VectorSection data_section_; + Deduper code_item_dedupe_; + + friend class CompactDexWriter; + }; protected: - void WriteMemMap() OVERRIDE; + void Write(DexContainer* output) OVERRIDE; + + std::unique_ptr<DexContainer> CreateDexContainer() const OVERRIDE; - void WriteHeader() OVERRIDE; + void WriteHeader(Stream* stream) OVERRIDE; size_t GetHeaderSize() const OVERRIDE; - uint32_t WriteDebugInfoOffsetTable(uint32_t offset); + uint32_t WriteDebugInfoOffsetTable(Stream* stream); - uint32_t WriteCodeItem(dex_ir::CodeItem* code_item, uint32_t offset, bool reserve_only) OVERRIDE; + uint32_t WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) OVERRIDE; void SortDebugInfosByMethodIndex(); - // Deduplicate a blob of data that has been written to mem_map. The backing storage is the actual - // mem_map contents to reduce RAM usage. - // Returns the offset of the deduplicated data or 0 if kDidNotDedupe did not occur. - uint32_t DedupeData(uint32_t data_start, uint32_t data_end, uint32_t item_offset); + CompactDexLevel GetCompactDexLevel() const; private: - const CompactDexLevel compact_dex_level_; - - static const uint32_t kDidNotDedupe = 0; - // Position in the compact dex file for the debug info table data starts. uint32_t debug_info_offsets_pos_ = 0u; @@ -91,11 +138,8 @@ class CompactDexWriter : public DexWriter { // Base offset of where debug info starts in the dex file. uint32_t debug_info_base_ = 0u; - // Dedupe map. - std::unordered_map<HashedMemoryRange, - uint32_t, - HashedMemoryRange::HashEqual, - HashedMemoryRange::HashEqual> data_dedupe_; + // State for where we are deduping. + Deduper* code_item_dedupe_ = nullptr; DISALLOW_COPY_AND_ASSIGN(CompactDexWriter); }; diff --git a/dexlayout/dex_container.h b/dexlayout/dex_container.h new file mode 100644 index 0000000000..7c426cbc53 --- /dev/null +++ b/dexlayout/dex_container.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file of an in-memory representation of DEX files. + */ + +#ifndef ART_DEXLAYOUT_DEX_CONTAINER_H_ +#define ART_DEXLAYOUT_DEX_CONTAINER_H_ + +#include <vector> + +namespace art { + +// Dex container holds the artifacts produced by dexlayout and contains up to two sections: a main +// section and a data section. +// This container may also hold metadata used for multi dex deduplication in the future. +class DexContainer { + public: + virtual ~DexContainer() {} + + class Section { + public: + virtual ~Section() {} + + // Returns the start of the memory region. + virtual uint8_t* Begin() = 0; + + // Size in bytes. + virtual size_t Size() const = 0; + + // Resize the backing storage. + virtual void Resize(size_t size) = 0; + + // Returns the end of the memory region. + uint8_t* End() { + return Begin() + Size(); + } + }; + + // Vector backed section. + class VectorSection : public Section { + public: + virtual ~VectorSection() {} + + uint8_t* Begin() OVERRIDE { + return &data_[0]; + } + + size_t Size() const OVERRIDE { + return data_.size(); + } + + void Resize(size_t size) OVERRIDE { + data_.resize(size, 0u); + } + + private: + std::vector<uint8_t> data_; + }; + + virtual Section* GetMainSection() = 0; + virtual Section* GetDataSection() = 0; + virtual bool IsCompactDexContainer() const = 0; +}; + +} // namespace art + +#endif // ART_DEXLAYOUT_DEX_CONTAINER_H_ diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 3627717abe..1a84d2307d 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -486,11 +486,11 @@ class Item { virtual ~Item() { } // Return the assigned offset. - uint32_t GetOffset() const { + uint32_t GetOffset() const WARN_UNUSED { CHECK(OffsetAssigned()); return offset_; } - uint32_t GetSize() const { return size_; } + uint32_t GetSize() const WARN_UNUSED { return size_; } void SetOffset(uint32_t offset) { offset_ = offset; } void SetSize(uint32_t size) { size_ = size; } bool OffsetAssigned() const { diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index d26c9481b4..eb038a008b 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -30,7 +30,7 @@ namespace art { -size_t EncodeIntValue(int32_t value, uint8_t* buffer) { +static size_t EncodeIntValue(int32_t value, uint8_t* buffer) { size_t length = 0; if (value >= 0) { while (value > 0x7f) { @@ -47,7 +47,7 @@ size_t EncodeIntValue(int32_t value, uint8_t* buffer) { return length; } -size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) { +static size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) { size_t length = 0; do { buffer[length++] = static_cast<uint8_t>(value); @@ -56,7 +56,7 @@ size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) { return length; } -size_t EncodeLongValue(int64_t value, uint8_t* buffer) { +static size_t EncodeLongValue(int64_t value, uint8_t* buffer) { size_t length = 0; if (value >= 0) { while (value > 0x7f) { @@ -78,7 +78,7 @@ union FloatUnion { uint32_t i_; }; -size_t EncodeFloatValue(float value, uint8_t* buffer) { +static size_t EncodeFloatValue(float value, uint8_t* buffer) { FloatUnion float_union; float_union.f_ = value; uint32_t int_value = float_union.i_; @@ -95,7 +95,7 @@ union DoubleUnion { uint64_t l_; }; -size_t EncodeDoubleValue(double value, uint8_t* buffer) { +static size_t EncodeDoubleValue(double value, uint8_t* buffer) { DoubleUnion double_union; double_union.d_ = value; uint64_t long_value = double_union.l_; @@ -107,26 +107,13 @@ size_t EncodeDoubleValue(double value, uint8_t* buffer) { return 7 - index; } -size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) { - DCHECK_LE(offset + length, mem_map_->Size()); - memcpy(mem_map_->Begin() + offset, buffer, length); - return length; -} +DexWriter::DexWriter(DexLayout* dex_layout, bool compute_offsets) + : header_(dex_layout->GetHeader()), + dex_layout_(dex_layout), + compute_offsets_(compute_offsets) {} -size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) { - uint8_t buffer[8]; - EncodeSignedLeb128(buffer, value); - return Write(buffer, SignedLeb128Size(value), offset); -} - -size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) { - uint8_t buffer[8]; - EncodeUnsignedLeb128(buffer, value); - return Write(buffer, UnsignedLeb128Size(value), offset); -} - -size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) { - size_t original_offset = offset; +size_t DexWriter::WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value) { + size_t original_offset = stream->Tell(); size_t start = 0; size_t length; uint8_t buffer[8]; @@ -175,284 +162,285 @@ size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer); break; case DexFile::kDexAnnotationArray: - offset += WriteEncodedValueHeader(type, 0, offset); - offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset); - return offset - original_offset; + WriteEncodedValueHeader(stream, type, 0); + WriteEncodedArray(stream, encoded_value->GetEncodedArray()->GetEncodedValues()); + return stream->Tell() - original_offset; case DexFile::kDexAnnotationAnnotation: - offset += WriteEncodedValueHeader(type, 0, offset); - offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset); - return offset - original_offset; + WriteEncodedValueHeader(stream, type, 0); + WriteEncodedAnnotation(stream, encoded_value->GetEncodedAnnotation()); + return stream->Tell() - original_offset; case DexFile::kDexAnnotationNull: - return WriteEncodedValueHeader(type, 0, offset); + return WriteEncodedValueHeader(stream, type, 0); case DexFile::kDexAnnotationBoolean: - return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset); + return WriteEncodedValueHeader(stream, type, encoded_value->GetBoolean() ? 1 : 0); default: return 0; } - offset += WriteEncodedValueHeader(type, length - 1, offset); - offset += Write(buffer + start, length, offset); - return offset - original_offset; + WriteEncodedValueHeader(stream, type, length - 1); + stream->Write(buffer + start, length); + return stream->Tell() - original_offset; } -size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) { +size_t DexWriter::WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg) { uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) }; - return Write(buffer, sizeof(uint8_t), offset); + return stream->Write(buffer, sizeof(uint8_t)); } -size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) { - size_t original_offset = offset; - offset += WriteUleb128(values->size(), offset); +size_t DexWriter::WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values) { + size_t original_offset = stream->Tell(); + stream->WriteUleb128(values->size()); for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) { - offset += WriteEncodedValue(value.get(), offset); + WriteEncodedValue(stream, value.get()); } - return offset - original_offset; + return stream->Tell() - original_offset; } -size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) { - size_t original_offset = offset; - offset += WriteUleb128(annotation->GetType()->GetIndex(), offset); - offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset); +size_t DexWriter::WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation) { + size_t original_offset = stream->Tell(); + stream->WriteUleb128(annotation->GetType()->GetIndex()); + stream->WriteUleb128(annotation->GetAnnotationElements()->size()); for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element : *annotation->GetAnnotationElements()) { - offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset); - offset += WriteEncodedValue(annotation_element->GetValue(), offset); + stream->WriteUleb128(annotation_element->GetName()->GetIndex()); + WriteEncodedValue(stream, annotation_element->GetValue()); } - return offset - original_offset; + return stream->Tell() - original_offset; } -size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) { - size_t original_offset = offset; +size_t DexWriter::WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields) { + size_t original_offset = stream->Tell(); uint32_t prev_index = 0; for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) { uint32_t index = field->GetFieldId()->GetIndex(); - offset += WriteUleb128(index - prev_index, offset); - offset += WriteUleb128(field->GetAccessFlags(), offset); + stream->WriteUleb128(index - prev_index); + stream->WriteUleb128(field->GetAccessFlags()); prev_index = index; } - return offset - original_offset; + return stream->Tell() - original_offset; } -size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) { - size_t original_offset = offset; +size_t DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods) { + size_t original_offset = stream->Tell(); uint32_t prev_index = 0; for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) { uint32_t index = method->GetMethodId()->GetIndex(); uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset(); - offset += WriteUleb128(index - prev_index, offset); - offset += WriteUleb128(method->GetAccessFlags(), offset); - offset += WriteUleb128(code_off, offset); + stream->WriteUleb128(index - prev_index); + stream->WriteUleb128(method->GetAccessFlags()); + stream->WriteUleb128(code_off); prev_index = index; } - return offset - original_offset; + return stream->Tell() - original_offset; } // TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding // function that takes a CollectionVector<T> and uses overloading. -uint32_t DexWriter::WriteStringIds(uint32_t offset, bool reserve_only) { - const uint32_t start = offset; +uint32_t DexWriter::WriteStringIds(Stream* stream, bool reserve_only) { + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringIdItem)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem)); if (reserve_only) { - offset += string_id->GetSize(); + stream->Skip(string_id->GetSize()); } else { uint32_t string_data_off = string_id->DataItem()->GetOffset(); - offset += Write(&string_data_off, string_id->GetSize(), offset); + stream->Write(&string_data_off, string_id->GetSize()); } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetStringIdsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteStringDatas(uint32_t offset) { - const uint32_t start = offset; +uint32_t DexWriter::WriteStringDatas(Stream* stream) { + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::StringData>& string_data : header_->GetCollections().StringDatas()) { - ProcessOffset(&offset, string_data.get()); - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeStringDataItem)); - offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset); + ProcessOffset(stream, string_data.get()); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringDataItem)); + stream->WriteUleb128(CountModifiedUtf8Chars(string_data->Data())); + stream->Write(string_data->Data(), strlen(string_data->Data())); // Skip null terminator (already zeroed out, no need to write). - offset += Write(string_data->Data(), strlen(string_data->Data()), offset) + 1u; + stream->Skip(1); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetStringDatasOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteTypeIds(uint32_t offset) { +uint32_t DexWriter::WriteTypeIds(Stream* stream) { uint32_t descriptor_idx[1]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeIdItem)); - ProcessOffset(&offset, type_id.get()); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem)); + ProcessOffset(stream, type_id.get()); descriptor_idx[0] = type_id->GetStringId()->GetIndex(); - offset += Write(descriptor_idx, type_id->GetSize(), offset); + stream->Write(descriptor_idx, type_id->GetSize()); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetTypeIdsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteTypeLists(uint32_t offset) { +uint32_t DexWriter::WriteTypeLists(Stream* stream) { uint32_t size[1]; uint16_t list[1]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::TypeList>& type_list : header_->GetCollections().TypeLists()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeTypeList)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList)); size[0] = type_list->GetTypeList()->size(); - ProcessOffset(&offset, type_list.get()); - offset += Write(size, sizeof(uint32_t), offset); + ProcessOffset(stream, type_list.get()); + stream->Write(size, sizeof(uint32_t)); for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { list[0] = type_id->GetIndex(); - offset += Write(list, sizeof(uint16_t), offset); + stream->Write(list, sizeof(uint16_t)); } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetTypeListsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteProtoIds(uint32_t offset, bool reserve_only) { +uint32_t DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) { uint32_t buffer[3]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeProtoIdItem)); - ProcessOffset(&offset, proto_id.get()); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem)); + ProcessOffset(stream, proto_id.get()); if (reserve_only) { - offset += proto_id->GetSize(); + stream->Skip(proto_id->GetSize()); } else { buffer[0] = proto_id->Shorty()->GetIndex(); buffer[1] = proto_id->ReturnType()->GetIndex(); buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); - offset += Write(buffer, proto_id->GetSize(), offset); + stream->Write(buffer, proto_id->GetSize()); } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetProtoIdsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteFieldIds(uint32_t offset) { +uint32_t DexWriter::WriteFieldIds(Stream* stream) { uint16_t buffer[4]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeFieldIdItem)); - ProcessOffset(&offset, field_id.get()); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem)); + ProcessOffset(stream, field_id.get()); buffer[0] = field_id->Class()->GetIndex(); buffer[1] = field_id->Type()->GetIndex(); buffer[2] = field_id->Name()->GetIndex(); buffer[3] = field_id->Name()->GetIndex() >> 16; - offset += Write(buffer, field_id->GetSize(), offset); + stream->Write(buffer, field_id->GetSize()); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetFieldIdsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteMethodIds(uint32_t offset) { +uint32_t DexWriter::WriteMethodIds(Stream* stream) { uint16_t buffer[4]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodIdItem)); - ProcessOffset(&offset, method_id.get()); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem)); + ProcessOffset(stream, method_id.get()); buffer[0] = method_id->Class()->GetIndex(); buffer[1] = method_id->Proto()->GetIndex(); buffer[2] = method_id->Name()->GetIndex(); buffer[3] = method_id->Name()->GetIndex() >> 16; - offset += Write(buffer, method_id->GetSize(), offset); + stream->Write(buffer, method_id->GetSize()); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetMethodIdsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteEncodedArrays(uint32_t offset) { - const uint32_t start = offset; +uint32_t DexWriter::WriteEncodedArrays(Stream* stream) { + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array : header_->GetCollections().EncodedArrayItems()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeEncodedArrayItem)); - ProcessOffset(&offset, encoded_array.get()); - offset += WriteEncodedArray(encoded_array->GetEncodedValues(), offset); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem)); + ProcessOffset(stream, encoded_array.get()); + WriteEncodedArray(stream, encoded_array->GetEncodedValues()); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetEncodedArrayItemsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteAnnotations(uint32_t offset) { +uint32_t DexWriter::WriteAnnotations(Stream* stream) { uint8_t visibility[1]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : header_->GetCollections().AnnotationItems()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationItem)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem)); visibility[0] = annotation->GetVisibility(); - ProcessOffset(&offset, annotation.get()); - offset += Write(visibility, sizeof(uint8_t), offset); - offset += WriteEncodedAnnotation(annotation->GetAnnotation(), offset); + ProcessOffset(stream, annotation.get()); + stream->Write(visibility, sizeof(uint8_t)); + WriteEncodedAnnotation(stream, annotation->GetAnnotation()); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetAnnotationItemsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteAnnotationSets(uint32_t offset) { +uint32_t DexWriter::WriteAnnotationSets(Stream* stream) { uint32_t size[1]; uint32_t annotation_off[1]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set : header_->GetCollections().AnnotationSetItems()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetItem)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem)); size[0] = annotation_set->GetItems()->size(); - ProcessOffset(&offset, annotation_set.get()); - offset += Write(size, sizeof(uint32_t), offset); + ProcessOffset(stream, annotation_set.get()); + stream->Write(size, sizeof(uint32_t)); for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) { annotation_off[0] = annotation->GetOffset(); - offset += Write(annotation_off, sizeof(uint32_t), offset); + stream->Write(annotation_off, sizeof(uint32_t)); } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetAnnotationSetItemsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteAnnotationSetRefs(uint32_t offset) { +uint32_t DexWriter::WriteAnnotationSetRefs(Stream* stream) { uint32_t size[1]; uint32_t annotations_off[1]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref : header_->GetCollections().AnnotationSetRefLists()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationSetRefList)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList)); size[0] = annotation_set_ref->GetItems()->size(); - ProcessOffset(&offset, annotation_set_ref.get()); - offset += Write(size, sizeof(uint32_t), offset); + ProcessOffset(stream, annotation_set_ref.get()); + stream->Write(size, sizeof(uint32_t)); for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) { annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset(); - offset += Write(annotations_off, sizeof(uint32_t), offset); + stream->Write(annotations_off, sizeof(uint32_t)); } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetAnnotationSetRefListsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteAnnotationsDirectories(uint32_t offset) { +uint32_t DexWriter::WriteAnnotationsDirectories(Stream* stream) { uint32_t directory_buffer[4]; uint32_t annotation_buffer[2]; - const uint32_t start = offset; + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory : header_->GetCollections().AnnotationsDirectoryItems()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem)); - ProcessOffset(&offset, annotations_directory.get()); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem)); + ProcessOffset(stream, annotations_directory.get()); directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : annotations_directory->GetClassAnnotation()->GetOffset(); directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : @@ -461,13 +449,13 @@ uint32_t DexWriter::WriteAnnotationsDirectories(uint32_t offset) { annotations_directory->GetMethodAnnotations()->size(); directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 : annotations_directory->GetParameterAnnotations()->size(); - offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset); + stream->Write(directory_buffer, 4 * sizeof(uint32_t)); if (annotations_directory->GetFieldAnnotations() != nullptr) { for (std::unique_ptr<dex_ir::FieldAnnotation>& field : *annotations_directory->GetFieldAnnotations()) { annotation_buffer[0] = field->GetFieldId()->GetIndex(); annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset(); - offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); + stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); } } if (annotations_directory->GetMethodAnnotations() != nullptr) { @@ -475,7 +463,7 @@ uint32_t DexWriter::WriteAnnotationsDirectories(uint32_t offset) { *annotations_directory->GetMethodAnnotations()) { annotation_buffer[0] = method->GetMethodId()->GetIndex(); annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset(); - offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); + stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); } } if (annotations_directory->GetParameterAnnotations() != nullptr) { @@ -483,37 +471,36 @@ uint32_t DexWriter::WriteAnnotationsDirectories(uint32_t offset) { *annotations_directory->GetParameterAnnotations()) { annotation_buffer[0] = parameter->GetMethodId()->GetIndex(); annotation_buffer[1] = parameter->GetAnnotations()->GetOffset(); - offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); + stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); } } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteDebugInfoItems(uint32_t offset) { - const uint32_t start = offset; +uint32_t DexWriter::WriteDebugInfoItems(Stream* stream) { + const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info : header_->GetCollections().DebugInfoItems()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeDebugInfoItem)); - ProcessOffset(&offset, debug_info.get()); - offset += Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), offset); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem)); + ProcessOffset(stream, debug_info.get()); + stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize()); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetDebugInfoItemsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteCodeItemPostInstructionData(dex_ir::CodeItem* code_item, - uint32_t offset, +uint32_t DexWriter::WriteCodeItemPostInstructionData(Stream* stream, + dex_ir::CodeItem* code_item, bool reserve_only) { - const uint32_t start_offset = offset; + const uint32_t start_offset = stream->Tell(); if (code_item->TriesSize() != 0) { - // Align for the try items. - offset = RoundUp(offset, DexFile::TryItem::kAlignment); + stream->AlignTo(DexFile::TryItem::kAlignment); // Write try items. for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) { DexFile::TryItem disk_try_item; @@ -522,38 +509,37 @@ uint32_t DexWriter::WriteCodeItemPostInstructionData(dex_ir::CodeItem* code_item disk_try_item.insn_count_ = try_item->InsnCount(); disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset(); } - offset += Write(&disk_try_item, sizeof(disk_try_item), offset); + stream->Write(&disk_try_item, sizeof(disk_try_item)); } - size_t max_offset = offset; // Leave offset pointing to the end of the try items. - UNUSED(WriteUleb128(code_item->Handlers()->size(), offset)); + const size_t offset = stream->Tell(); + size_t max_offset = offset + stream->WriteUleb128(code_item->Handlers()->size()); for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) { - size_t list_offset = offset + handlers->GetListOffset(); + stream->Seek(offset + handlers->GetListOffset()); uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 : handlers->GetHandlers()->size(); - list_offset += WriteSleb128(size, list_offset); + stream->WriteSleb128(size); for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) { if (handler->GetTypeId() != nullptr) { - list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset); + stream->WriteUleb128(handler->GetTypeId()->GetIndex()); } - list_offset += WriteUleb128(handler->GetAddress(), list_offset); + stream->WriteUleb128(handler->GetAddress()); } // TODO: Clean this up to write the handlers in address order. - max_offset = std::max(max_offset, list_offset); + max_offset = std::max(max_offset, stream->Tell()); } - offset = max_offset; + stream->Seek(max_offset); } - - return offset - start_offset; + return stream->Tell() - start_offset; } -uint32_t DexWriter::WriteCodeItem(dex_ir::CodeItem* code_item, - uint32_t offset, +uint32_t DexWriter::WriteCodeItem(Stream* stream, + dex_ir::CodeItem* code_item, bool reserve_only) { DCHECK(code_item != nullptr); - const uint32_t start_offset = offset; - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCodeItem)); - ProcessOffset(&offset, code_item); + const uint32_t start_offset = stream->Tell(); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem)); + ProcessOffset(stream, code_item); StandardDexFile::CodeItem disk_code_item; if (!reserve_only) { @@ -568,50 +554,50 @@ uint32_t DexWriter::WriteCodeItem(dex_ir::CodeItem* code_item, } // Avoid using sizeof so that we don't write the fake instruction array at the end of the code // item. - offset += Write(&disk_code_item, - OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_), - offset); + stream->Write(&disk_code_item, OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_)); // Write the instructions. - offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset); + stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t)); // Write the post instruction data. - offset += WriteCodeItemPostInstructionData(code_item, offset, reserve_only); - return offset - start_offset; + WriteCodeItemPostInstructionData(stream, code_item, reserve_only); + if (reserve_only) { + stream->Clear(start_offset, stream->Tell() - start_offset); + } + return stream->Tell() - start_offset; } -uint32_t DexWriter::WriteCodeItems(uint32_t offset, bool reserve_only) { +uint32_t DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) { DexLayoutSection* code_section = nullptr; if (!reserve_only && dex_layout_ != nullptr) { code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>( DexLayoutSections::SectionType::kSectionTypeCode)]; } - uint32_t start = offset; + const uint32_t start = stream->Tell(); for (auto& code_item : header_->GetCollections().CodeItems()) { - const size_t code_item_size = WriteCodeItem(code_item.get(), offset, reserve_only); + const size_t code_item_size = WriteCodeItem(stream, code_item.get(), reserve_only); // Only add the section hotness info once. if (!reserve_only && code_section != nullptr) { auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get()); if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) { code_section->parts_[static_cast<size_t>(it->second)].CombineSection( - offset, - offset + code_item_size); + stream->Tell() - code_item_size, + stream->Tell()); } } - offset += code_item_size; } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetCodeItemsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteClassDefs(uint32_t offset, bool reserve_only) { - const uint32_t start = offset; +uint32_t DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) { + const uint32_t start = stream->Tell(); uint32_t class_def_buffer[8]; for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDefItem)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem)); if (reserve_only) { - offset += class_def->GetSize(); + stream->Skip(class_def->GetSize()); } else { class_def_buffer[0] = class_def->ClassType()->GetIndex(); class_def_buffer[1] = class_def->GetAccessFlags(); @@ -626,94 +612,94 @@ uint32_t DexWriter::WriteClassDefs(uint32_t offset, bool reserve_only) { class_def->GetClassData()->GetOffset(); class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 : class_def->StaticValues()->GetOffset(); - offset += Write(class_def_buffer, class_def->GetSize(), offset); + stream->Write(class_def_buffer, class_def->GetSize()); } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetClassDefsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteClassDatas(uint32_t offset) { - const uint32_t start = offset; +uint32_t DexWriter::WriteClassDatas(Stream* stream) { + const uint32_t start = stream->Tell(); for (const std::unique_ptr<dex_ir::ClassData>& class_data : header_->GetCollections().ClassDatas()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeClassDataItem)); - ProcessOffset(&offset, class_data.get()); - offset += WriteUleb128(class_data->StaticFields()->size(), offset); - offset += WriteUleb128(class_data->InstanceFields()->size(), offset); - offset += WriteUleb128(class_data->DirectMethods()->size(), offset); - offset += WriteUleb128(class_data->VirtualMethods()->size(), offset); - offset += WriteEncodedFields(class_data->StaticFields(), offset); - offset += WriteEncodedFields(class_data->InstanceFields(), offset); - offset += WriteEncodedMethods(class_data->DirectMethods(), offset); - offset += WriteEncodedMethods(class_data->VirtualMethods(), offset); - } - if (compute_offsets_ && start != offset) { + stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem)); + ProcessOffset(stream, class_data.get()); + stream->WriteUleb128(class_data->StaticFields()->size()); + stream->WriteUleb128(class_data->InstanceFields()->size()); + stream->WriteUleb128(class_data->DirectMethods()->size()); + stream->WriteUleb128(class_data->VirtualMethods()->size()); + WriteEncodedFields(stream, class_data->StaticFields()); + WriteEncodedFields(stream, class_data->InstanceFields()); + WriteEncodedMethods(stream, class_data->DirectMethods()); + WriteEncodedMethods(stream, class_data->VirtualMethods()); + } + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetClassDatasOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteCallSiteIds(uint32_t offset, bool reserve_only) { - const uint32_t start = offset; +uint32_t DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) { + const uint32_t start = stream->Tell(); uint32_t call_site_off[1]; for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id : header_->GetCollections().CallSiteIds()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeCallSiteIdItem)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem)); if (reserve_only) { - offset += call_site_id->GetSize(); + stream->Skip(call_site_id->GetSize()); } else { call_site_off[0] = call_site_id->CallSiteItem()->GetOffset(); - offset += Write(call_site_off, call_site_id->GetSize(), offset); + stream->Write(call_site_off, call_site_id->GetSize()); } } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetCallSiteIdsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteMethodHandles(uint32_t offset) { - const uint32_t start = offset; +uint32_t DexWriter::WriteMethodHandles(Stream* stream) { + const uint32_t start = stream->Tell(); uint16_t method_handle_buff[4]; for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle : header_->GetCollections().MethodHandleItems()) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMethodHandleItem)); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem)); method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType()); method_handle_buff[1] = 0; // unused. method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex(); method_handle_buff[3] = 0; // unused. - offset += Write(method_handle_buff, method_handle->GetSize(), offset); + stream->Write(method_handle_buff, method_handle->GetSize()); } - if (compute_offsets_ && start != offset) { + if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetMethodHandleItemsOffset(start); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::WriteMapItems(uint32_t offset, MapItemQueue* queue) { +uint32_t DexWriter::WriteMapItems(Stream* stream, MapItemQueue* queue) { // All the sections should already have been added. uint16_t uint16_buffer[2]; uint32_t uint32_buffer[2]; uint16_buffer[1] = 0; uint32_buffer[0] = queue->size(); - const uint32_t start = offset; - offset += Write(uint32_buffer, sizeof(uint32_t), offset); + const uint32_t start = stream->Tell(); + stream->Write(uint32_buffer, sizeof(uint32_t)); while (!queue->empty()) { const MapItem& map_item = queue->top(); uint16_buffer[0] = map_item.type_; uint32_buffer[0] = map_item.size_; uint32_buffer[1] = map_item.offset_; - offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset); - offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); + stream->Write(uint16_buffer, 2 * sizeof(uint16_t)); + stream->Write(uint32_buffer, 2 * sizeof(uint32_t)); queue->pop(); } - return offset - start; + return stream->Tell() - start; } -uint32_t DexWriter::GenerateAndWriteMapItems(uint32_t offset) { +uint32_t DexWriter::GenerateAndWriteMapItems(Stream* stream) { dex_ir::Collections& collection = header_->GetCollections(); MapItemQueue queue; @@ -777,10 +763,10 @@ uint32_t DexWriter::GenerateAndWriteMapItems(uint32_t offset) { collection.AnnotationsDirectoryItemsOffset())); // Write the map items. - return WriteMapItems(offset, &queue); + return WriteMapItems(stream, &queue); } -void DexWriter::WriteHeader() { +void DexWriter::WriteHeader(Stream* stream) { StandardDexFile::Header header; if (CompactDexFile::IsMagicValid(header_->Magic())) { StandardDexFile::WriteMagic(header.magic_); @@ -818,78 +804,97 @@ void DexWriter::WriteHeader() { CHECK_EQ(sizeof(header), GetHeaderSize()); static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec"); - UNUSED(Write(reinterpret_cast<uint8_t*>(&header), sizeof(header), 0u)); + stream->Seek(0); + stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header)); } size_t DexWriter::GetHeaderSize() const { return sizeof(StandardDexFile::Header); } -void DexWriter::WriteMemMap() { +void DexWriter::Write(DexContainer* output) { + Stream stream_storage(output->GetMainSection()); + Stream* stream = &stream_storage; + // Starting offset is right after the header. - uint32_t offset = GetHeaderSize(); + stream->Seek(GetHeaderSize()); dex_ir::Collections& collection = header_->GetCollections(); // Based on: https://source.android.com/devices/tech/dalvik/dex-format // Since the offsets may not be calculated already, the writing must be done in the correct order. - const uint32_t string_ids_offset = offset; - offset += WriteStringIds(offset, /*reserve_only*/ true); - offset += WriteTypeIds(offset); - const uint32_t proto_ids_offset = offset; - offset += WriteProtoIds(offset, /*reserve_only*/ true); - offset += WriteFieldIds(offset); - offset += WriteMethodIds(offset); - const uint32_t class_defs_offset = offset; - offset += WriteClassDefs(offset, /*reserve_only*/ true); - const uint32_t call_site_ids_offset = offset; - offset += WriteCallSiteIds(offset, /*reserve_only*/ true); - offset += WriteMethodHandles(offset); + const uint32_t string_ids_offset = stream->Tell(); + WriteStringIds(stream, /*reserve_only*/ true); + WriteTypeIds(stream); + const uint32_t proto_ids_offset = stream->Tell(); + WriteProtoIds(stream, /*reserve_only*/ true); + WriteFieldIds(stream); + WriteMethodIds(stream); + const uint32_t class_defs_offset = stream->Tell(); + WriteClassDefs(stream, /*reserve_only*/ true); + const uint32_t call_site_ids_offset = stream->Tell(); + WriteCallSiteIds(stream, /*reserve_only*/ true); + WriteMethodHandles(stream); uint32_t data_offset_ = 0u; if (compute_offsets_) { // Data section. - offset = RoundUp(offset, kDataSectionAlignment); - data_offset_ = offset; + stream->AlignTo(kDataSectionAlignment); + data_offset_ = stream->Tell(); } // Write code item first to minimize the space required for encoded methods. // Reserve code item space since we need the debug offsets to actually write them. - const uint32_t code_items_offset = offset; - offset += WriteCodeItems(offset, /*reserve_only*/ true); + const uint32_t code_items_offset = stream->Tell(); + WriteCodeItems(stream, /*reserve_only*/ true); // Write debug info section. - offset += WriteDebugInfoItems(offset); - // Actually write code items since debug info offsets are calculated now. - WriteCodeItems(code_items_offset, /*reserve_only*/ false); - - offset += WriteEncodedArrays(offset); - offset += WriteAnnotations(offset); - offset += WriteAnnotationSets(offset); - offset += WriteAnnotationSetRefs(offset); - offset += WriteAnnotationsDirectories(offset); - offset += WriteTypeLists(offset); - offset += WriteClassDatas(offset); - offset += WriteStringDatas(offset); + WriteDebugInfoItems(stream); + { + // Actually write code items since debug info offsets are calculated now. + Stream::ScopedSeek seek(stream, code_items_offset); + WriteCodeItems(stream, /*reserve_only*/ false); + } + + WriteEncodedArrays(stream); + WriteAnnotations(stream); + WriteAnnotationSets(stream); + WriteAnnotationSetRefs(stream); + WriteAnnotationsDirectories(stream); + WriteTypeLists(stream); + WriteClassDatas(stream); + WriteStringDatas(stream); // Write delayed id sections that depend on data sections. - WriteStringIds(string_ids_offset, /*reserve_only*/ false); - WriteProtoIds(proto_ids_offset, /*reserve_only*/ false); - WriteClassDefs(class_defs_offset, /*reserve_only*/ false); - WriteCallSiteIds(call_site_ids_offset, /*reserve_only*/ false); + { + Stream::ScopedSeek seek(stream, string_ids_offset); + WriteStringIds(stream, /*reserve_only*/ false); + } + { + Stream::ScopedSeek seek(stream, proto_ids_offset); + WriteProtoIds(stream, /*reserve_only*/ false); + } + { + Stream::ScopedSeek seek(stream, class_defs_offset); + WriteClassDefs(stream, /*reserve_only*/ false); + } + { + Stream::ScopedSeek seek(stream, call_site_ids_offset); + WriteCallSiteIds(stream, /*reserve_only*/ false); + } // Write the map list. if (compute_offsets_) { - offset = RoundUp(offset, SectionAlignment(DexFile::kDexTypeMapList)); - collection.SetMapListOffset(offset); + stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList)); + collection.SetMapListOffset(stream->Tell()); } else { - offset = collection.MapListOffset(); + stream->Seek(collection.MapListOffset()); } - offset += GenerateAndWriteMapItems(offset); - offset = RoundUp(offset, kDataSectionAlignment); + GenerateAndWriteMapItems(stream); + stream->AlignTo(kDataSectionAlignment); // Map items are included in the data section. if (compute_offsets_) { - header_->SetDataSize(offset - data_offset_); + header_->SetDataSize(stream->Tell() - data_offset_); if (header_->DataSize() != 0) { // Offset must be zero when the size is zero. header_->SetDataOffset(data_offset_); @@ -903,37 +908,45 @@ void DexWriter::WriteMemMap() { if (link_data.size() > 0) { CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size())); if (compute_offsets_) { - header_->SetLinkOffset(offset); + header_->SetLinkOffset(stream->Tell()); + } else { + stream->Seek(header_->LinkOffset()); } - offset += Write(&link_data[0], link_data.size(), header_->LinkOffset()); + stream->Write(&link_data[0], link_data.size()); } // Write header last. if (compute_offsets_) { - header_->SetFileSize(offset); + header_->SetFileSize(stream->Tell()); } - WriteHeader(); + WriteHeader(stream); if (dex_layout_->GetOptions().update_checksum_) { - header_->SetChecksum(DexFile::CalculateChecksum(mem_map_->Begin(), offset)); + header_->SetChecksum(DexFile::CalculateChecksum(stream->Begin(), header_->FileSize())); // Rewrite the header with the calculated checksum. - WriteHeader(); + WriteHeader(stream); } + + // Trim the map to make it sized as large as the dex file. + output->GetMainSection()->Resize(header_->FileSize()); } -void DexWriter::Output(dex_ir::Header* header, - MemMap* mem_map, - DexLayout* dex_layout, - bool compute_offsets, - CompactDexLevel compact_dex_level) { +void DexWriter::Output(DexLayout* dex_layout, + std::unique_ptr<DexContainer>* container, + bool compute_offsets) { CHECK(dex_layout != nullptr); std::unique_ptr<DexWriter> writer; - if (compact_dex_level != CompactDexLevel::kCompactDexLevelNone) { - writer.reset(new CompactDexWriter(header, mem_map, dex_layout, compact_dex_level)); + if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) { + CHECK(compute_offsets) << "Compact dex requires computing offsets"; + writer.reset(new CompactDexWriter(dex_layout)); } else { - writer.reset(new DexWriter(header, mem_map, dex_layout, compute_offsets)); + writer.reset(new DexWriter(dex_layout, compute_offsets)); + } + DCHECK(container != nullptr); + if (*container == nullptr) { + *container = writer->CreateDexContainer(); } - writer->WriteMemMap(); + writer->Write(container->get()); } void MapItemQueue::AddIfNotEmpty(const MapItem& item) { @@ -942,4 +955,17 @@ void MapItemQueue::AddIfNotEmpty(const MapItem& item) { } } +void DexWriter::ProcessOffset(Stream* stream, dex_ir::Item* item) { + if (compute_offsets_) { + item->SetOffset(stream->Tell()); + } else { + // Not computing offsets, just use the one in the item. + stream->Seek(item->GetOffset()); + } +} + +std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const { + return std::unique_ptr<DexContainer>(new DexWriter::Container); +} + } // namespace art diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h index 892ea7414b..e581a8b61b 100644 --- a/dexlayout/dex_writer.h +++ b/dexlayout/dex_writer.h @@ -20,9 +20,11 @@ #define ART_DEXLAYOUT_DEX_WRITER_H_ #include <functional> +#include <memory> // For unique_ptr #include "base/unix_file/fd_file.h" #include "dex/compact_dex_level.h" +#include "dex_container.h" #include "dex/dex_file.h" #include "dex_ir.h" #include "mem_map.h" @@ -39,7 +41,7 @@ struct MapItem { // Not using DexFile::MapItemType since compact dex and standard dex file may have different // sections. MapItem() = default; - MapItem(uint32_t type, uint32_t size, uint32_t offset) + MapItem(uint32_t type, uint32_t size, size_t offset) : type_(type), size_(size), offset_(offset) { } // Sort by decreasing order since the priority_queue puts largest elements first. @@ -63,6 +65,114 @@ class DexWriter { static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2; static constexpr uint32_t kDexSectionWordAlignment = 4; + // Stream that writes into a dex container section. Do not have two streams pointing to the same + // backing storage as there may be invalidation of backing storage to resize the section. + // Random access stream (consider refactoring). + class Stream { + public: + explicit Stream(DexContainer::Section* section) : section_(section) { + SyncWithSection(); + } + + const uint8_t* Begin() const { + return data_; + } + + // Functions are not virtual (yet) for speed. + size_t Tell() const { + return position_; + } + + void Seek(size_t position) { + position_ = position; + } + + // Does not allow overwriting for bug prevention purposes. + ALWAYS_INLINE size_t Write(const void* buffer, size_t length) { + EnsureStorage(length); + for (size_t i = 0; i < length; ++i) { + DCHECK_EQ(data_[position_ + i], 0u); + } + memcpy(&data_[position_], buffer, length); + position_ += length; + return length; + } + + ALWAYS_INLINE size_t Overwrite(const void* buffer, size_t length) { + EnsureStorage(length); + memcpy(&data_[position_], buffer, length); + position_ += length; + return length; + } + + ALWAYS_INLINE size_t Clear(size_t position, size_t length) { + EnsureStorage(length); + memset(&data_[position], 0, length); + return length; + } + + ALWAYS_INLINE size_t WriteSleb128(int32_t value) { + EnsureStorage(8); + uint8_t* ptr = &data_[position_]; + const size_t len = EncodeSignedLeb128(ptr, value) - ptr; + position_ += len; + return len; + } + + ALWAYS_INLINE size_t WriteUleb128(uint32_t value) { + EnsureStorage(8); + uint8_t* ptr = &data_[position_]; + const size_t len = EncodeUnsignedLeb128(ptr, value) - ptr; + position_ += len; + return len; + } + + ALWAYS_INLINE void AlignTo(const size_t alignment) { + position_ = RoundUp(position_, alignment); + } + + ALWAYS_INLINE void Skip(const size_t count) { + position_ += count; + } + + class ScopedSeek { + public: + ScopedSeek(Stream* stream, uint32_t offset) : stream_(stream), offset_(stream->Tell()) { + stream->Seek(offset); + } + + ~ScopedSeek() { + stream_->Seek(offset_); + } + + private: + Stream* const stream_; + const uint32_t offset_; + }; + + private: + ALWAYS_INLINE void EnsureStorage(size_t length) { + size_t end = position_ + length; + while (UNLIKELY(end > data_size_)) { + section_->Resize(data_size_ * 3 / 2 + 1); + SyncWithSection(); + } + } + + void SyncWithSection() { + data_ = section_->Begin(); + data_size_ = section_->Size(); + } + + // Current position of the stream. + size_t position_ = 0u; + DexContainer::Section* const section_ = nullptr; + // Cached Begin() from the container to provide faster accesses. + uint8_t* data_ = nullptr; + // Cached Size from the container to provide faster accesses. + size_t data_size_ = 0u; + }; + static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) { switch (type) { case DexFile::kDexTypeClassDataItem: @@ -78,83 +188,85 @@ class DexWriter { } } - DexWriter(dex_ir::Header* header, - MemMap* mem_map, - DexLayout* dex_layout, - bool compute_offsets) - : header_(header), - mem_map_(mem_map), - dex_layout_(dex_layout), - compute_offsets_(compute_offsets) {} - - static void Output(dex_ir::Header* header, - MemMap* mem_map, - DexLayout* dex_layout, - bool compute_offsets, - CompactDexLevel compact_dex_level); + class Container : public DexContainer { + public: + Section* GetMainSection() OVERRIDE { + return &main_section_; + } + + Section* GetDataSection() OVERRIDE { + return &data_section_; + } + + bool IsCompactDexContainer() const OVERRIDE { + return false; + } + + private: + VectorSection main_section_; + VectorSection data_section_; + + friend class CompactDexWriter; + }; + + DexWriter(DexLayout* dex_layout, bool compute_offsets); + + static void Output(DexLayout* dex_layout, + std::unique_ptr<DexContainer>* container, + bool compute_offsets); virtual ~DexWriter() {} protected: - virtual void WriteMemMap(); - - size_t Write(const void* buffer, size_t length, size_t offset) WARN_UNUSED; - size_t WriteSleb128(uint32_t value, size_t offset) WARN_UNUSED; - size_t WriteUleb128(uint32_t value, size_t offset) WARN_UNUSED; - size_t WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) WARN_UNUSED; - size_t WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) WARN_UNUSED; - size_t WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) WARN_UNUSED; - size_t WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) WARN_UNUSED; - size_t WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) WARN_UNUSED; - size_t WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) WARN_UNUSED; + virtual void Write(DexContainer* output); + virtual std::unique_ptr<DexContainer> CreateDexContainer() const; + + size_t WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value); + size_t WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg); + size_t WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values); + size_t WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation); + size_t WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields); + size_t WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods); // Header and id section - virtual void WriteHeader(); + virtual void WriteHeader(Stream* stream); virtual size_t GetHeaderSize() const; // reserve_only means don't write, only reserve space. This is required since the string data // offsets must be assigned. - uint32_t WriteStringIds(uint32_t offset, bool reserve_only); - uint32_t WriteTypeIds(uint32_t offset); - uint32_t WriteProtoIds(uint32_t offset, bool reserve_only); - uint32_t WriteFieldIds(uint32_t offset); - uint32_t WriteMethodIds(uint32_t offset); - uint32_t WriteClassDefs(uint32_t offset, bool reserve_only); - uint32_t WriteCallSiteIds(uint32_t offset, bool reserve_only); - - uint32_t WriteEncodedArrays(uint32_t offset); - uint32_t WriteAnnotations(uint32_t offset); - uint32_t WriteAnnotationSets(uint32_t offset); - uint32_t WriteAnnotationSetRefs(uint32_t offset); - uint32_t WriteAnnotationsDirectories(uint32_t offset); + uint32_t WriteStringIds(Stream* stream, bool reserve_only); + uint32_t WriteTypeIds(Stream* stream); + uint32_t WriteProtoIds(Stream* stream, bool reserve_only); + uint32_t WriteFieldIds(Stream* stream); + uint32_t WriteMethodIds(Stream* stream); + uint32_t WriteClassDefs(Stream* stream, bool reserve_only); + uint32_t WriteCallSiteIds(Stream* stream, bool reserve_only); + + uint32_t WriteEncodedArrays(Stream* stream); + uint32_t WriteAnnotations(Stream* stream); + uint32_t WriteAnnotationSets(Stream* stream); + uint32_t WriteAnnotationSetRefs(Stream* stream); + uint32_t WriteAnnotationsDirectories(Stream* stream); // Data section. - uint32_t WriteDebugInfoItems(uint32_t offset); - uint32_t WriteCodeItems(uint32_t offset, bool reserve_only); - uint32_t WriteTypeLists(uint32_t offset); - uint32_t WriteStringDatas(uint32_t offset); - uint32_t WriteClassDatas(uint32_t offset); - uint32_t WriteMethodHandles(uint32_t offset); - uint32_t WriteMapItems(uint32_t offset, MapItemQueue* queue); - uint32_t GenerateAndWriteMapItems(uint32_t offset); - - virtual uint32_t WriteCodeItemPostInstructionData(dex_ir::CodeItem* item, - uint32_t offset, + uint32_t WriteDebugInfoItems(Stream* stream); + uint32_t WriteCodeItems(Stream* stream, bool reserve_only); + uint32_t WriteTypeLists(Stream* stream); + uint32_t WriteStringDatas(Stream* stream); + uint32_t WriteClassDatas(Stream* stream); + uint32_t WriteMethodHandles(Stream* stream); + uint32_t WriteMapItems(Stream* stream, MapItemQueue* queue); + uint32_t GenerateAndWriteMapItems(Stream* stream); + + virtual uint32_t WriteCodeItemPostInstructionData(Stream* stream, + dex_ir::CodeItem* item, bool reserve_only); - virtual uint32_t WriteCodeItem(dex_ir::CodeItem* item, uint32_t offset, bool reserve_only); + virtual uint32_t WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only); // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the // existing offset and use that for writing. - void ProcessOffset(uint32_t* const offset, dex_ir::Item* item) { - if (compute_offsets_) { - item->SetOffset(*offset); - } else { - // Not computing offsets, just use the one in the item. - *offset = item->GetOffset(); - } - } + void ProcessOffset(Stream* stream, dex_ir::Item* item); dex_ir::Header* const header_; - MemMap* const mem_map_; DexLayout* const dex_layout_; bool compute_offsets_; diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 3d3b121190..d33a0bde03 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -1813,21 +1813,14 @@ void DexLayout::LayoutOutputFile(const DexFile* dex_file) { LayoutCodeItems(dex_file); } -void DexLayout::OutputDexFile(const DexFile* dex_file, bool compute_offsets) { - const std::string& dex_file_location = dex_file->GetLocation(); +void DexLayout::OutputDexFile(const DexFile* input_dex_file, + bool compute_offsets, + std::unique_ptr<DexContainer>* dex_container) { + const std::string& dex_file_location = input_dex_file->GetLocation(); std::string error_msg; std::unique_ptr<File> new_file; - // Since we allow dex growth, we need to size the map larger than the original input to be safe. - // Reserve an extra 10% to add some buffer room. Note that this is probably more than - // necessary. - static constexpr size_t kReserveFraction = 10; - // Add an extra constant amount since the compact dex header and extra tables may cause more - // expansion than fits in the reserve fraction for small dex files. - // TODO: Move to using a resizable buffer like a vector. - static constexpr size_t kExtraReserve = 128 * KB; - const size_t max_size = header_->FileSize() + kExtraReserve + - header_->FileSize() / kReserveFraction; - if (!options_.output_to_memmap_) { + // If options_.output_dex_directory_ is non null, we are outputting to a file. + if (options_.output_dex_directory_ != nullptr) { std::string output_location(options_.output_dex_directory_); size_t last_slash = dex_file_location.rfind('/'); std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1); @@ -1843,31 +1836,17 @@ void DexLayout::OutputDexFile(const DexFile* dex_file, bool compute_offsets) { LOG(ERROR) << "Could not create dex writer output file: " << output_location; return; } - if (ftruncate(new_file->Fd(), max_size) != 0) { - LOG(ERROR) << "Could not grow dex writer output file: " << output_location;; - new_file->Erase(); - return; - } - mem_map_.reset(MemMap::MapFile(max_size, PROT_READ | PROT_WRITE, MAP_SHARED, - new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg)); - } else { - mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, max_size, - PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg)); - } - if (mem_map_ == nullptr) { - LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg; - if (new_file != nullptr) { - new_file->Erase(); - } - return; } - DexWriter::Output(header_, mem_map_.get(), this, compute_offsets, options_.compact_dex_level_); + DexWriter::Output(this, dex_container, compute_offsets); + DexContainer* const container = dex_container->get(); + DexContainer::Section* const main_section = container->GetMainSection(); + DexContainer::Section* const data_section = container->GetDataSection(); + CHECK_EQ(data_section->Size(), 0u) << "Unsupported"; if (new_file != nullptr) { - // Since we make the memmap larger than needed, shrink the file back down to not leave extra - // padding. - int res = new_file->SetLength(header_->FileSize()); - if (res != 0) { - LOG(ERROR) << "Truncating file resulted in " << res; + if (!new_file->WriteFully(main_section->Begin(), main_section->Size())) { + LOG(ERROR) << "Failed tow write dex file to " << dex_file_location; + new_file->Erase(); + return; } UNUSED(new_file->FlushCloseOrErase()); } @@ -1878,8 +1857,11 @@ void DexLayout::OutputDexFile(const DexFile* dex_file, bool compute_offsets) { */ void DexLayout::ProcessDexFile(const char* file_name, const DexFile* dex_file, - size_t dex_file_index) { - const bool output = options_.output_dex_directory_ != nullptr || options_.output_to_memmap_; + size_t dex_file_index, + std::unique_ptr<DexContainer>* dex_container) { + const bool has_output_container = dex_container != nullptr; + const bool output = options_.output_dex_directory_ != nullptr || has_output_container; + // Try to avoid eagerly assigning offsets to find bugs since GetOffset will abort if the offset // is unassigned. bool eagerly_assign_offsets = false; @@ -1918,22 +1900,29 @@ void DexLayout::ProcessDexFile(const char* file_name, if (do_layout) { LayoutOutputFile(dex_file); } + // The output needs a dex container, use a temporary one. + std::unique_ptr<DexContainer> temp_container; + if (dex_container == nullptr) { + dex_container = &temp_container; + } // If we didn't set the offsets eagerly, we definitely need to compute them here. - OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets); + OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets, dex_container); // Clear header before verifying to reduce peak RAM usage. const size_t file_size = header_->FileSize(); header.reset(); // Verify the output dex file's structure, only enabled by default for debug builds. - if (options_.verify_output_) { + if (options_.verify_output_ && has_output_container) { std::string error_msg; std::string location = "memory mapped file for " + std::string(file_name); // Dex file verifier cannot handle compact dex. bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone; const ArtDexFileLoader dex_file_loader; + DexContainer::Section* section = (*dex_container)->GetMainSection(); + DCHECK_EQ(file_size, section->Size()); std::unique_ptr<const DexFile> output_dex_file( - dex_file_loader.Open(mem_map_->Begin(), + dex_file_loader.Open(section->Begin(), file_size, location, /* checksum */ 0, @@ -1988,7 +1977,8 @@ int DexLayout::ProcessFile(const char* file_name) { fprintf(out_file_, "Checksum verified\n"); } else { for (size_t i = 0; i < dex_files.size(); i++) { - ProcessDexFile(file_name, dex_files[i].get(), i); + // Pass in a null container to avoid output by default. + ProcessDexFile(file_name, dex_files[i].get(), i, /*dex_container*/ nullptr); } } return 0; diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index cb0eabc7db..00d24dbda4 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -28,6 +28,7 @@ #include <unordered_map> #include "dex/compact_dex_level.h" +#include "dex_container.h" #include "dex/dex_file_layout.h" #include "dex_ir.h" #include "mem_map.h" @@ -55,7 +56,7 @@ class Options { bool disassemble_ = false; bool exports_only_ = false; bool ignore_bad_checksum_ = false; - bool output_to_memmap_ = false; + bool output_to_container_ = false; bool show_annotations_ = false; bool show_file_headers_ = false; bool show_section_headers_ = false; @@ -82,6 +83,18 @@ class DexLayoutHotnessInfo { class DexLayout { public: + class VectorOutputContainer { + public: + // Begin is not necessarily aligned (for now). + uint8_t* Begin() { + return &data_[0]; + } + + private: + std::vector<uint8_t> data_; + }; + + // Setting this to false disables class def layout entirely, which is stronger than strictly // necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550). static constexpr bool kChangeClassDefOrder = false; @@ -89,18 +102,21 @@ class DexLayout { DexLayout(Options& options, ProfileCompilationInfo* info, FILE* out_file, - dex_ir::Header* - header = nullptr) - : options_(options), info_(info), out_file_(out_file), header_(header) { } + dex_ir::Header* header) + : options_(options), + info_(info), + out_file_(out_file), + header_(header) { } int ProcessFile(const char* file_name); - void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index); + void ProcessDexFile(const char* file_name, + const DexFile* dex_file, + size_t dex_file_index, + std::unique_ptr<DexContainer>* dex_container); dex_ir::Header* GetHeader() const { return header_; } void SetHeader(dex_ir::Header* header) { header_ = header; } - MemMap* GetAndReleaseMemMap() { return mem_map_.release(); } - DexLayoutSections& GetSections() { return dex_sections_; } @@ -150,7 +166,9 @@ class DexLayout { // Creates a new layout for the dex file based on profile info. // Currently reorders ClassDefs, ClassDataItems, and CodeItems. void LayoutOutputFile(const DexFile* dex_file); - void OutputDexFile(const DexFile* dex_file, bool compute_offsets); + void OutputDexFile(const DexFile* input_dex_file, + bool compute_offsets, + std::unique_ptr<DexContainer>* dex_container); void DumpCFG(const DexFile* dex_file, int idx); void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code); @@ -159,7 +177,6 @@ class DexLayout { ProfileCompilationInfo* info_; FILE* out_file_; dex_ir::Header* header_; - std::unique_ptr<MemMap> mem_map_; DexLayoutSections dex_sections_; // Layout hotness information is only calculated when dexlayout is enabled. DexLayoutHotnessInfo layout_hotness_info_; diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc index 83fb99a734..ece0f932ce 100644 --- a/dexlayout/dexlayout_main.cc +++ b/dexlayout/dexlayout_main.cc @@ -80,7 +80,7 @@ int DexlayoutDriver(int argc, char** argv) { // Parse all arguments. while (1) { - const int ic = getopt(argc, argv, "abcdefghil:mo:p:stvw:x:"); + const int ic = getopt(argc, argv, "abcdefghil:o:p:stvw:x:"); if (ic < 0) { break; // done } @@ -119,9 +119,6 @@ int DexlayoutDriver(int argc, char** argv) { want_usage = true; } break; - case 'm': // output dex files to a memmap - options.output_to_memmap_ = true; - break; case 'o': // output file options.output_file_name_ = optarg; break; @@ -197,7 +194,7 @@ int DexlayoutDriver(int argc, char** argv) { } // Create DexLayout instance. - DexLayout dex_layout(options, profile_info.get(), out_file); + DexLayout dex_layout(options, profile_info.get(), out_file, /*header*/ nullptr); // Process all files supplied on command line. int result = 0; diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index dcc834abe9..323137aa5b 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -35,6 +35,7 @@ #include "dex/dex_file_loader.h" // Runtime includes. +#include "dex_container.h" #include "dex/compact_dex_level.h" #include "dex_to_dex_decompiler.h" #include "dexlayout.h" @@ -92,18 +93,21 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi if (original.IsCompactDexFile()) { // Since we are supposed to return a standard dex, convert back using dexlayout. art::Options options; - options.output_to_memmap_ = true; options.compact_dex_level_ = art::CompactDexLevel::kCompactDexLevelNone; options.update_checksum_ = true; - art::DexLayout dex_layout(options, nullptr, nullptr); - dex_layout.ProcessDexFile(new_dex_file->GetLocation().c_str(), new_dex_file.get(), 0); - std::unique_ptr<art::MemMap> mem_map(dex_layout.GetAndReleaseMemMap()); - - const uint32_t dex_file_size = - reinterpret_cast<const art::DexFile::Header*>(mem_map->Begin())->file_size_; + art::DexLayout dex_layout(options, + /*info*/ nullptr, + /*out_file*/ nullptr, + /*header*/ nullptr); + std::unique_ptr<art::DexContainer> dex_container; + dex_layout.ProcessDexFile(new_dex_file->GetLocation().c_str(), + new_dex_file.get(), + 0, + &dex_container); + art::DexContainer::Section* main_section = dex_container->GetMainSection(); // Overwrite the dex file stored in data with the new result. data.clear(); - data.insert(data.end(), mem_map->Begin(), mem_map->Begin() + dex_file_size); + data.insert(data.end(), main_section->Begin(), main_section->End()); new_dex_file = dex_file_loader.Open( data.data(), data.size(), diff --git a/runtime/dex/dex_file_verifier.cc b/runtime/dex/dex_file_verifier.cc index 7265aad1ba..5800bb1006 100644 --- a/runtime/dex/dex_file_verifier.cc +++ b/runtime/dex/dex_file_verifier.cc @@ -453,6 +453,7 @@ bool DexFileVerifier::CheckMap() { uint32_t count = map->size_; uint32_t last_offset = 0; + uint32_t last_type = 0; uint32_t data_item_count = 0; uint32_t data_items_left = header_->data_size_; uint32_t used_bits = 0; @@ -465,7 +466,11 @@ bool DexFileVerifier::CheckMap() { // Check the items listed in the map. for (uint32_t i = 0; i < count; i++) { if (UNLIKELY(last_offset >= item->offset_ && i != 0)) { - ErrorStringPrintf("Out of order map item: %x then %x", last_offset, item->offset_); + ErrorStringPrintf("Out of order map item: %x then %x for type %x last type was %x", + last_offset, + item->offset_, + static_cast<uint32_t>(item->type_), + last_type); return false; } if (UNLIKELY(item->offset_ >= header_->file_size_)) { @@ -501,6 +506,7 @@ bool DexFileVerifier::CheckMap() { used_bits |= bit; last_offset = item->offset_; + last_type = item->type_; item++; } |