1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * Header file of an in-memory representation of DEX files. 17 */ 18 19 #ifndef ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ 20 #define ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ 21 22 #include <memory> // For unique_ptr 23 #include <unordered_map> 24 25 #include "base/data_hash.h" 26 #include "dex_writer.h" 27 28 namespace art { 29 30 // Compact dex writer for a single dex. 31 class CompactDexWriter : public DexWriter { 32 public: 33 explicit CompactDexWriter(DexLayout* dex_layout); 34 35 protected: 36 class Deduper { 37 public: 38 static const uint32_t kDidNotDedupe = 0; 39 40 explicit Deduper(DexContainer::Section* section); 41 42 // Deduplicate a blob of data that has been written to mem_map. 43 // Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur. 44 uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset); 45 46 // Clear dedupe state to prevent deduplication against existing items in the future. Clear()47 void Clear() { 48 dedupe_map_.clear(); 49 } 50 51 private: 52 class HashedMemoryRange { 53 public: 54 uint32_t offset_; 55 uint32_t length_; 56 57 class HashEqual { 58 public: HashEqual(DexContainer::Section * section)59 explicit HashEqual(DexContainer::Section* section) : section_(section) {} 60 61 // Equal function. operator()62 bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const { 63 if (a.length_ != b.length_) { 64 return false; 65 } 66 const uint8_t* data = Data(); 67 DCHECK_LE(a.offset_ + a.length_, section_->Size()); 68 DCHECK_LE(b.offset_ + b.length_, section_->Size()); 69 return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_); 70 } 71 72 // Hash function. operator()73 size_t operator()(const HashedMemoryRange& range) const { 74 DCHECK_LE(range.offset_ + range.length_, section_->Size()); 75 return DataHash::HashBytes(Data() + range.offset_, range.length_); 76 } 77 Data()78 ALWAYS_INLINE uint8_t* Data() const { 79 return section_->Begin(); 80 } 81 82 private: 83 DexContainer::Section* const section_; 84 }; 85 }; 86 87 // Dedupe map. 88 std::unordered_map<HashedMemoryRange, 89 uint32_t, 90 HashedMemoryRange::HashEqual, 91 HashedMemoryRange::HashEqual> dedupe_map_; 92 }; 93 94 // Handles alignment and deduping of a data section item. 95 class ScopedDataSectionItem { 96 public: 97 ScopedDataSectionItem(Stream* stream, dex_ir::Item* item, size_t alignment, Deduper* deduper); 98 ~ScopedDataSectionItem(); 99 size_t Written() const; 100 101 private: 102 Stream* const stream_; 103 dex_ir::Item* const item_; 104 const size_t alignment_; 105 Deduper* deduper_; 106 const uint32_t start_offset_; 107 }; 108 109 public: 110 class Container : public DexContainer { 111 public: GetMainSection()112 Section* GetMainSection() override { 113 return &main_section_; 114 } 115 GetDataSection()116 Section* GetDataSection() override { 117 return &data_section_; 118 } 119 IsCompactDexContainer()120 bool IsCompactDexContainer() const override { 121 return true; 122 } 123 124 private: 125 Container(); 126 127 VectorSection main_section_; 128 VectorSection data_section_; 129 Deduper data_item_dedupe_; 130 131 friend class CompactDexWriter; 132 }; 133 134 protected: 135 // Return true if we can generate compact dex for the IR. 136 bool CanGenerateCompactDex(std::string* error_msg); 137 138 bool Write(DexContainer* output, std::string* error_msg) override; 139 140 std::unique_ptr<DexContainer> CreateDexContainer() const override; 141 142 void WriteHeader(Stream* stream) override; 143 144 size_t GetHeaderSize() const override; 145 146 uint32_t WriteDebugInfoOffsetTable(Stream* stream); 147 148 void WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) override; 149 150 void WriteStringData(Stream* stream, dex_ir::StringData* string_data) override; 151 152 void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) override; 153 154 void SortDebugInfosByMethodIndex(); 155 156 CompactDexLevel GetCompactDexLevel() const; 157 158 private: 159 // Position in the compact dex file for the debug info table data starts. 160 uint32_t debug_info_offsets_pos_ = 0u; 161 162 // Offset into the debug info table data where the lookup table is. 163 uint32_t debug_info_offsets_table_offset_ = 0u; 164 165 // Base offset of where debug info starts in the dex file. 166 uint32_t debug_info_base_ = 0u; 167 168 // Part of the shared data section owned by this file. 169 uint32_t owned_data_begin_ = 0u; 170 uint32_t owned_data_end_ = 0u; 171 172 Deduper* data_item_dedupe_ = nullptr; 173 174 DISALLOW_COPY_AND_ASSIGN(CompactDexWriter); 175 }; 176 177 } // namespace art 178 179 #endif // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ 180