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