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 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