diff options
| -rw-r--r-- | dexlayout/compact_dex_writer.cc | 86 | ||||
| -rw-r--r-- | dexlayout/compact_dex_writer.h | 23 | ||||
| -rw-r--r-- | dexlayout/dex_writer.cc | 38 | ||||
| -rw-r--r-- | dexlayout/dex_writer.h | 4 |
4 files changed, 109 insertions, 42 deletions
diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc index ef31c3f212..6149e75753 100644 --- a/dexlayout/compact_dex_writer.cc +++ b/dexlayout/compact_dex_writer.cc @@ -34,7 +34,8 @@ CompactDexLevel CompactDexWriter::GetCompactDexLevel() const { } CompactDexWriter::Container::Container(bool dedupe_code_items) - : code_item_dedupe_(dedupe_code_items, &data_section_) {} + : code_item_dedupe_(dedupe_code_items, &data_section_), + data_item_dedupe_(/*dedupe*/ true, &data_section_) {} uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) { const uint32_t start_offset = stream->Tell(); @@ -103,16 +104,45 @@ uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) { return stream->Tell() - start_offset; } -uint32_t CompactDexWriter::WriteCodeItem(Stream* stream, - dex_ir::CodeItem* code_item, - bool reserve_only) { +CompactDexWriter::ScopedDataSectionItem::ScopedDataSectionItem(Stream* stream, + dex_ir::Item* item, + size_t alignment, + Deduper* deduper) + : stream_(stream), + item_(item), + alignment_(alignment), + deduper_(deduper), + start_offset_(stream->Tell()) { + stream_->AlignTo(alignment_); +} + +CompactDexWriter::ScopedDataSectionItem::~ScopedDataSectionItem() { + // After having written, maybe dedupe the whole code item (excluding padding). + const uint32_t deduped_offset = deduper_->Dedupe(start_offset_, + stream_->Tell(), + item_->GetOffset()); + // In case we dedupe to something with wrong alignment, just say we didn't dedupe. + if (deduped_offset != Deduper::kDidNotDedupe && IsAlignedParam(deduped_offset, alignment_)) { + item_->SetOffset(deduped_offset); + stream_->Clear(start_offset_, stream_->Tell() - start_offset_); + // Undo the offset for all that we wrote since we deduped. + stream_->Seek(start_offset_); + } +} + +size_t CompactDexWriter::ScopedDataSectionItem::Written() const { + return stream_->Tell() - start_offset_; +} + +void 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 = stream->Tell(); - - // Align to minimum requirements, additional alignment requirements are handled below after we - // know the preheader size. - stream->AlignTo(CompactDexFile::CodeItem::kAlignment); + ScopedDataSectionItem data_item(stream, + code_item, + CompactDexFile::CodeItem::kAlignment, + code_item_dedupe_); CompactDexFile::CodeItem disk_code_item; @@ -146,8 +176,6 @@ uint32_t CompactDexWriter::WriteCodeItem(Stream* stream, } } - const uint32_t data_start = stream->Tell(); - // Write preheader first. stream->Write(reinterpret_cast<const uint8_t*>(preheader), preheader_bytes); // Registered offset is after the preheader. @@ -159,21 +187,15 @@ uint32_t CompactDexWriter::WriteCodeItem(Stream* stream, stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t)); // Write the post instruction data. WriteCodeItemPostInstructionData(stream, code_item, reserve_only); +} - 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); - stream->Clear(start_offset, stream->Tell() - start_offset); - // Undo the offset for all that we wrote since we deduped. - stream->Seek(start_offset); - } - } - - return stream->Tell() - start_offset; +void CompactDexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) { + ScopedDataSectionItem data_item(stream, + debug_info, + SectionAlignment(DexFile::kDexTypeDebugInfoItem), + data_item_dedupe_); + ProcessOffset(stream, debug_info); + stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize()); } @@ -284,11 +306,24 @@ size_t CompactDexWriter::GetHeaderSize() const { return sizeof(CompactDexFile::Header); } +void CompactDexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) { + ScopedDataSectionItem data_item(stream, + string_data, + SectionAlignment(DexFile::kDexTypeStringDataItem), + data_item_dedupe_); + ProcessOffset(stream, string_data); + 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). + stream->Skip(1); +} + 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 temp_main_stream(output->GetMainSection()); + CHECK_EQ(output->GetMainSection()->Size(), 0u); Stream temp_data_stream(output->GetDataSection()); Stream* main_stream = &temp_main_stream; Stream* data_stream = &temp_data_stream; @@ -299,6 +334,7 @@ void CompactDexWriter::Write(DexContainer* output) { static_cast<uint32_t>(output->GetDataSection()->Size()), kDataSectionAlignment)); code_item_dedupe_ = &container->code_item_dedupe_; + data_item_dedupe_ = &container->data_item_dedupe_; // Starting offset is right after the header. main_stream->Seek(GetHeaderSize()); diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h index 626b85a86b..4834bfc3af 100644 --- a/dexlayout/compact_dex_writer.h +++ b/dexlayout/compact_dex_writer.h @@ -86,6 +86,21 @@ class CompactDexWriter : public DexWriter { HashedMemoryRange::HashEqual> dedupe_map_; }; + // Handles alignment and deduping of a data section item. + class ScopedDataSectionItem { + public: + ScopedDataSectionItem(Stream* stream, dex_ir::Item* item, size_t alignment, Deduper* deduper); + ~ScopedDataSectionItem(); + size_t Written() const; + + private: + Stream* const stream_; + dex_ir::Item* const item_; + const size_t alignment_; + Deduper* deduper_; + const uint32_t start_offset_; + }; + public: class Container : public DexContainer { public: @@ -107,6 +122,7 @@ class CompactDexWriter : public DexWriter { VectorSection main_section_; VectorSection data_section_; Deduper code_item_dedupe_; + Deduper data_item_dedupe_; friend class CompactDexWriter; }; @@ -122,7 +138,11 @@ class CompactDexWriter : public DexWriter { uint32_t WriteDebugInfoOffsetTable(Stream* stream); - uint32_t WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) OVERRIDE; + void WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) OVERRIDE; + + void WriteStringData(Stream* stream, dex_ir::StringData* string_data) OVERRIDE; + + void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) OVERRIDE; void SortDebugInfosByMethodIndex(); @@ -140,6 +160,7 @@ class CompactDexWriter : public DexWriter { // State for where we are deduping. Deduper* code_item_dedupe_ = nullptr; + Deduper* data_item_dedupe_ = nullptr; DISALLOW_COPY_AND_ASSIGN(CompactDexWriter); }; diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index 67d0f9ac68..a9aa97dc80 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -254,15 +254,19 @@ uint32_t DexWriter::WriteStringIds(Stream* stream, bool reserve_only) { return stream->Tell() - start; } +void DexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) { + ProcessOffset(stream, string_data); + 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). + stream->Skip(1); +} + 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(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). - stream->Skip(1); + WriteStringData(stream, string_data.get()); } if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetStringDatasOffset(start); @@ -483,13 +487,17 @@ uint32_t DexWriter::WriteAnnotationsDirectories(Stream* stream) { return stream->Tell() - start; } +void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) { + stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem)); + ProcessOffset(stream, debug_info); + stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize()); +} + uint32_t DexWriter::WriteDebugInfoItems(Stream* stream) { const uint32_t start = stream->Tell(); for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info : header_->GetCollections().DebugInfoItems()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem)); - ProcessOffset(stream, debug_info.get()); - stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize()); + WriteDebugInfoItem(stream, debug_info.get()); } if (compute_offsets_ && start != stream->Tell()) { header_->GetCollections().SetDebugInfoItemsOffset(start); @@ -535,9 +543,9 @@ uint32_t DexWriter::WriteCodeItemPostInstructionData(Stream* stream, return stream->Tell() - start_offset; } -uint32_t DexWriter::WriteCodeItem(Stream* stream, - dex_ir::CodeItem* code_item, - bool reserve_only) { +void DexWriter::WriteCodeItem(Stream* stream, + dex_ir::CodeItem* code_item, + bool reserve_only) { DCHECK(code_item != nullptr); const uint32_t start_offset = stream->Tell(); stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem)); @@ -564,7 +572,6 @@ uint32_t DexWriter::WriteCodeItem(Stream* stream, if (reserve_only) { stream->Clear(start_offset, stream->Tell() - start_offset); } - return stream->Tell() - start_offset; } uint32_t DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) { @@ -575,13 +582,14 @@ uint32_t DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) { } const uint32_t start = stream->Tell(); for (auto& code_item : header_->GetCollections().CodeItems()) { - const size_t code_item_size = WriteCodeItem(stream, code_item.get(), reserve_only); + uint32_t start_offset = stream->Tell(); + 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( - stream->Tell() - code_item_size, + start_offset, stream->Tell()); } } diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h index e581a8b61b..e6e05334e4 100644 --- a/dexlayout/dex_writer.h +++ b/dexlayout/dex_writer.h @@ -260,7 +260,9 @@ class DexWriter { virtual uint32_t WriteCodeItemPostInstructionData(Stream* stream, dex_ir::CodeItem* item, bool reserve_only); - virtual uint32_t WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only); + virtual void WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only); + virtual void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info); + virtual void WriteStringData(Stream* stream, dex_ir::StringData* string_data); // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the // existing offset and use that for writing. |