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 // if not enabled, Dedupe will always return kDidNotDedupe. 41 explicit Deduper(bool enabled, DexContainer::Section* section); 42 43 // Deduplicate a blob of data that has been written to mem_map. 44 // Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur. 45 uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset); 46 47 // Clear dedupe state to prevent deduplication against existing items in the future. Clear()48 void Clear() { 49 dedupe_map_.clear(); 50 } 51 52 private: 53 class HashedMemoryRange { 54 public: 55 uint32_t offset_; 56 uint32_t length_; 57 58 class HashEqual { 59 public: HashEqual(DexContainer::Section * section)60 explicit HashEqual(DexContainer::Section* section) : section_(section) {} 61 62 // Equal function. operator()63 bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const { 64 if (a.length_ != b.length_) { 65 return false; 66 } 67 const uint8_t* data = Data(); 68 DCHECK_LE(a.offset_ + a.length_, section_->Size()); 69 DCHECK_LE(b.offset_ + b.length_, section_->Size()); 70 return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_); 71 } 72 73 // Hash function. operator()74 size_t operator()(const HashedMemoryRange& range) const { 75 DCHECK_LE(range.offset_ + range.length_, section_->Size()); 76 return HashBytes(Data() + range.offset_, range.length_); 77 } 78 Data()79 ALWAYS_INLINE uint8_t* Data() const { 80 return section_->Begin(); 81 } 82 83 private: 84 DexContainer::Section* const section_; 85 }; 86 }; 87 88 const bool enabled_; 89 90 // Dedupe map. 91 std::unordered_map<HashedMemoryRange, 92 uint32_t, 93 HashedMemoryRange::HashEqual, 94 HashedMemoryRange::HashEqual> dedupe_map_; 95 }; 96 97 // Handles alignment and deduping of a data section item. 98 class ScopedDataSectionItem { 99 public: 100 ScopedDataSectionItem(Stream* stream, dex_ir::Item* item, size_t alignment, Deduper* deduper); 101 ~ScopedDataSectionItem(); 102 size_t Written() const; 103 104 private: 105 Stream* const stream_; 106 dex_ir::Item* const item_; 107 const size_t alignment_; 108 Deduper* deduper_; 109 const uint32_t start_offset_; 110 }; 111 112 public: 113 class Container : public DexContainer { 114 public: GetMainSection()115 Section* GetMainSection() override { 116 return &main_section_; 117 } 118 GetDataSection()119 Section* GetDataSection() override { 120 return &data_section_; 121 } 122 IsCompactDexContainer()123 bool IsCompactDexContainer() const override { 124 return true; 125 } 126 127 private: 128 explicit Container(bool dedupe_code_items); 129 130 VectorSection main_section_; 131 VectorSection data_section_; 132 Deduper code_item_dedupe_; 133 Deduper data_item_dedupe_; 134 135 friend class CompactDexWriter; 136 }; 137 138 protected: 139 // Return true if we can generate compact dex for the IR. 140 bool CanGenerateCompactDex(std::string* error_msg); 141 142 bool Write(DexContainer* output, std::string* error_msg) override; 143 144 std::unique_ptr<DexContainer> CreateDexContainer() const override; 145 146 void WriteHeader(Stream* stream) override; 147 148 size_t GetHeaderSize() const override; 149 150 uint32_t WriteDebugInfoOffsetTable(Stream* stream); 151 152 void WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) override; 153 154 void WriteStringData(Stream* stream, dex_ir::StringData* string_data) override; 155 156 void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) override; 157 158 void SortDebugInfosByMethodIndex(); 159 160 CompactDexLevel GetCompactDexLevel() const; 161 162 private: 163 // Position in the compact dex file for the debug info table data starts. 164 uint32_t debug_info_offsets_pos_ = 0u; 165 166 // Offset into the debug info table data where the lookup table is. 167 uint32_t debug_info_offsets_table_offset_ = 0u; 168 169 // Base offset of where debug info starts in the dex file. 170 uint32_t debug_info_base_ = 0u; 171 172 // Part of the shared data section owned by this file. 173 uint32_t owned_data_begin_ = 0u; 174 uint32_t owned_data_end_ = 0u; 175 176 // State for where we are deduping. 177 Deduper* code_item_dedupe_ = nullptr; 178 Deduper* data_item_dedupe_ = nullptr; 179 180 DISALLOW_COPY_AND_ASSIGN(CompactDexWriter); 181 }; 182 183 } // namespace art 184 185 #endif // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ 186