Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 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 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 22 | #include <memory> // For unique_ptr |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 23 | #include <unordered_map> |
| 24 | |
David Sehr | c431b9d | 2018-03-02 12:01:51 -0800 | [diff] [blame] | 25 | #include "base/utils.h" |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 26 | #include "dex_writer.h" |
| 27 | |
| 28 | namespace art { |
| 29 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 30 | // Compact dex writer for a single dex. |
| 31 | class CompactDexWriter : public DexWriter { |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 32 | public: |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 33 | explicit CompactDexWriter(DexLayout* dex_layout); |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 34 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 35 | protected: |
| 36 | class Deduper { |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 37 | public: |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 38 | static const uint32_t kDidNotDedupe = 0; |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 39 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 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 | |
Mathieu Chartier | 279e3a3 | 2018-01-24 18:17:55 -0800 | [diff] [blame] | 47 | // Clear dedupe state to prevent deduplication against existing items in the future. |
| 48 | void Clear() { |
| 49 | dedupe_map_.clear(); |
| 50 | } |
| 51 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 52 | private: |
| 53 | class HashedMemoryRange { |
| 54 | public: |
| 55 | uint32_t offset_; |
| 56 | uint32_t length_; |
| 57 | |
| 58 | class HashEqual { |
| 59 | public: |
| 60 | explicit HashEqual(DexContainer::Section* section) : section_(section) {} |
| 61 | |
| 62 | // Equal function. |
| 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(); |
Mathieu Chartier | 4e046e2 | 2018-01-25 16:55:44 -0800 | [diff] [blame] | 68 | DCHECK_LE(a.offset_ + a.length_, section_->Size()); |
| 69 | DCHECK_LE(b.offset_ + b.length_, section_->Size()); |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 70 | return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_); |
| 71 | } |
| 72 | |
| 73 | // Hash function. |
| 74 | size_t operator()(const HashedMemoryRange& range) const { |
Mathieu Chartier | 4e046e2 | 2018-01-25 16:55:44 -0800 | [diff] [blame] | 75 | DCHECK_LE(range.offset_ + range.length_, section_->Size()); |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 76 | return HashBytes(Data() + range.offset_, range.length_); |
| 77 | } |
| 78 | |
| 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 | |
Mathieu Chartier | b81ecad | 2018-01-23 22:08:26 -0800 | [diff] [blame] | 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 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 112 | public: |
| 113 | class Container : public DexContainer { |
| 114 | public: |
| 115 | Section* GetMainSection() OVERRIDE { |
| 116 | return &main_section_; |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 117 | } |
| 118 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 119 | Section* GetDataSection() OVERRIDE { |
| 120 | return &data_section_; |
| 121 | } |
| 122 | |
| 123 | bool IsCompactDexContainer() const OVERRIDE { |
| 124 | return true; |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | private: |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 128 | explicit Container(bool dedupe_code_items); |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 129 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 130 | VectorSection main_section_; |
| 131 | VectorSection data_section_; |
| 132 | Deduper code_item_dedupe_; |
Mathieu Chartier | b81ecad | 2018-01-23 22:08:26 -0800 | [diff] [blame] | 133 | Deduper data_item_dedupe_; |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 134 | |
| 135 | friend class CompactDexWriter; |
| 136 | }; |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 137 | |
| 138 | protected: |
Mathieu Chartier | 05f90d1 | 2018-02-07 13:47:17 -0800 | [diff] [blame] | 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; |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 143 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 144 | std::unique_ptr<DexContainer> CreateDexContainer() const OVERRIDE; |
| 145 | |
| 146 | void WriteHeader(Stream* stream) OVERRIDE; |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 147 | |
Mathieu Chartier | f6e3147 | 2017-12-28 13:32:08 -0800 | [diff] [blame] | 148 | size_t GetHeaderSize() const OVERRIDE; |
| 149 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 150 | uint32_t WriteDebugInfoOffsetTable(Stream* stream); |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 151 | |
Mathieu Chartier | b81ecad | 2018-01-23 22:08:26 -0800 | [diff] [blame] | 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; |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 157 | |
| 158 | void SortDebugInfosByMethodIndex(); |
| 159 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 160 | CompactDexLevel GetCompactDexLevel() const; |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 161 | |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 162 | private: |
Mathieu Chartier | 8892c6b | 2018-01-09 15:10:17 -0800 | [diff] [blame] | 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 | |
Mathieu Chartier | c17b7d8 | 2018-03-14 14:00:04 -0700 | [diff] [blame] | 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 | |
Mathieu Chartier | e6b6ff8 | 2018-01-19 18:58:34 -0800 | [diff] [blame] | 176 | // State for where we are deduping. |
| 177 | Deduper* code_item_dedupe_ = nullptr; |
Mathieu Chartier | b81ecad | 2018-01-23 22:08:26 -0800 | [diff] [blame] | 178 | Deduper* data_item_dedupe_ = nullptr; |
Mathieu Chartier | 66c9df1 | 2018-01-16 14:45:20 -0800 | [diff] [blame] | 179 | |
Mathieu Chartier | f95a75e | 2017-11-03 15:25:52 -0700 | [diff] [blame] | 180 | DISALLOW_COPY_AND_ASSIGN(CompactDexWriter); |
| 181 | }; |
| 182 | |
| 183 | } // namespace art |
| 184 | |
| 185 | #endif // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ |