blob: 4b142a85bbd1ef26f8a4b75d4274be8bd88020e3 [file] [log] [blame]
Mathieu Chartierf95a75e2017-11-03 15:25:52 -07001/*
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 Chartiere6b6ff82018-01-19 18:58:34 -080022#include <memory> // For unique_ptr
Mathieu Chartier66c9df12018-01-16 14:45:20 -080023#include <unordered_map>
24
David Sehrc431b9d2018-03-02 12:01:51 -080025#include "base/utils.h"
Mathieu Chartierf95a75e2017-11-03 15:25:52 -070026#include "dex_writer.h"
27
28namespace art {
29
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080030// Compact dex writer for a single dex.
31class CompactDexWriter : public DexWriter {
Mathieu Chartier66c9df12018-01-16 14:45:20 -080032 public:
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080033 explicit CompactDexWriter(DexLayout* dex_layout);
Mathieu Chartier66c9df12018-01-16 14:45:20 -080034
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080035 protected:
36 class Deduper {
Mathieu Chartier66c9df12018-01-16 14:45:20 -080037 public:
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080038 static const uint32_t kDidNotDedupe = 0;
Mathieu Chartier66c9df12018-01-16 14:45:20 -080039
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080040 // 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 Chartier279e3a32018-01-24 18:17:55 -080047 // Clear dedupe state to prevent deduplication against existing items in the future.
48 void Clear() {
49 dedupe_map_.clear();
50 }
51
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080052 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 Chartier4e046e22018-01-25 16:55:44 -080068 DCHECK_LE(a.offset_ + a.length_, section_->Size());
69 DCHECK_LE(b.offset_ + b.length_, section_->Size());
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080070 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 Chartier4e046e22018-01-25 16:55:44 -080075 DCHECK_LE(range.offset_ + range.length_, section_->Size());
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080076 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 Chartierb81ecad2018-01-23 22:08:26 -080097 // 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 Chartiere6b6ff82018-01-19 18:58:34 -0800112 public:
113 class Container : public DexContainer {
114 public:
115 Section* GetMainSection() OVERRIDE {
116 return &main_section_;
Mathieu Chartier66c9df12018-01-16 14:45:20 -0800117 }
118
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800119 Section* GetDataSection() OVERRIDE {
120 return &data_section_;
121 }
122
123 bool IsCompactDexContainer() const OVERRIDE {
124 return true;
Mathieu Chartier66c9df12018-01-16 14:45:20 -0800125 }
126
127 private:
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800128 explicit Container(bool dedupe_code_items);
Mathieu Chartier66c9df12018-01-16 14:45:20 -0800129
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800130 VectorSection main_section_;
131 VectorSection data_section_;
132 Deduper code_item_dedupe_;
Mathieu Chartierb81ecad2018-01-23 22:08:26 -0800133 Deduper data_item_dedupe_;
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800134
135 friend class CompactDexWriter;
136 };
Mathieu Chartierf95a75e2017-11-03 15:25:52 -0700137
138 protected:
Mathieu Chartier05f90d12018-02-07 13:47:17 -0800139 // 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 Chartier8892c6b2018-01-09 15:10:17 -0800143
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800144 std::unique_ptr<DexContainer> CreateDexContainer() const OVERRIDE;
145
146 void WriteHeader(Stream* stream) OVERRIDE;
Mathieu Chartierf95a75e2017-11-03 15:25:52 -0700147
Mathieu Chartierf6e31472017-12-28 13:32:08 -0800148 size_t GetHeaderSize() const OVERRIDE;
149
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800150 uint32_t WriteDebugInfoOffsetTable(Stream* stream);
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800151
Mathieu Chartierb81ecad2018-01-23 22:08:26 -0800152 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 Chartier8892c6b2018-01-09 15:10:17 -0800157
158 void SortDebugInfosByMethodIndex();
159
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800160 CompactDexLevel GetCompactDexLevel() const;
Mathieu Chartier66c9df12018-01-16 14:45:20 -0800161
Mathieu Chartierf95a75e2017-11-03 15:25:52 -0700162 private:
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800163 // 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 Chartierc17b7d82018-03-14 14:00:04 -0700172 // 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 Chartiere6b6ff82018-01-19 18:58:34 -0800176 // State for where we are deduping.
177 Deduper* code_item_dedupe_ = nullptr;
Mathieu Chartierb81ecad2018-01-23 22:08:26 -0800178 Deduper* data_item_dedupe_ = nullptr;
Mathieu Chartier66c9df12018-01-16 14:45:20 -0800179
Mathieu Chartierf95a75e2017-11-03 15:25:52 -0700180 DISALLOW_COPY_AND_ASSIGN(CompactDexWriter);
181};
182
183} // namespace art
184
185#endif // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_