blob: 62247ec9e2ad30f63be8e939b71fa66ed09be73c [file] [log] [blame]
Jeff Haoa8621002016-10-04 18:13:44 +00001/*
2 * Copyright (C) 2016 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_DEX_WRITER_H_
20#define ART_DEXLAYOUT_DEX_WRITER_H_
21
Mathieu Chartier3e0c5172017-11-12 12:58:40 -080022#include <functional>
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080023#include <memory> // For unique_ptr
Mathieu Chartier3e0c5172017-11-12 12:58:40 -080024
David Sehrc431b9d2018-03-02 12:01:51 -080025#include "base/os.h"
Jeff Haoa8621002016-10-04 18:13:44 +000026#include "base/unix_file/fd_file.h"
David Sehr9e734c72018-01-04 17:56:19 -080027#include "dex/compact_dex_level.h"
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080028#include "dex_container.h"
Mathieu Chartier8892c6b2018-01-09 15:10:17 -080029#include "dex/dex_file.h"
Jeff Haoa8621002016-10-04 18:13:44 +000030#include "dex_ir.h"
Jeff Haoa8621002016-10-04 18:13:44 +000031
Mathieu Chartier3e0c5172017-11-12 12:58:40 -080032#include <queue>
33
Jeff Haoa8621002016-10-04 18:13:44 +000034namespace art {
35
Mathieu Chartier3e0c5172017-11-12 12:58:40 -080036class DexLayout;
37class DexLayoutHotnessInfo;
38
39struct MapItem {
40 // Not using DexFile::MapItemType since compact dex and standard dex file may have different
41 // sections.
42 MapItem() = default;
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080043 MapItem(uint32_t type, uint32_t size, size_t offset)
Mathieu Chartier3e0c5172017-11-12 12:58:40 -080044 : type_(type), size_(size), offset_(offset) { }
45
46 // Sort by decreasing order since the priority_queue puts largest elements first.
47 bool operator>(const MapItem& other) const {
48 return offset_ > other.offset_;
49 }
50
51 uint32_t type_ = 0u;
52 uint32_t size_ = 0u;
53 uint32_t offset_ = 0u;
54};
55
56class MapItemQueue : public
57 std::priority_queue<MapItem, std::vector<MapItem>, std::greater<MapItem>> {
58 public:
59 void AddIfNotEmpty(const MapItem& item);
60};
61
Jeff Haoa8621002016-10-04 18:13:44 +000062class DexWriter {
63 public:
Mathieu Chartier8892c6b2018-01-09 15:10:17 -080064 static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
65 static constexpr uint32_t kDexSectionWordAlignment = 4;
Mathieu Chartier8892c6b2018-01-09 15:10:17 -080066
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080067 // Stream that writes into a dex container section. Do not have two streams pointing to the same
68 // backing storage as there may be invalidation of backing storage to resize the section.
69 // Random access stream (consider refactoring).
70 class Stream {
71 public:
72 explicit Stream(DexContainer::Section* section) : section_(section) {
73 SyncWithSection();
74 }
75
76 const uint8_t* Begin() const {
77 return data_;
78 }
79
80 // Functions are not virtual (yet) for speed.
81 size_t Tell() const {
82 return position_;
83 }
84
85 void Seek(size_t position) {
86 position_ = position;
Mathieu Chartier4e046e22018-01-25 16:55:44 -080087 EnsureStorage(0u);
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -080088 }
89
90 // Does not allow overwriting for bug prevention purposes.
91 ALWAYS_INLINE size_t Write(const void* buffer, size_t length) {
92 EnsureStorage(length);
93 for (size_t i = 0; i < length; ++i) {
94 DCHECK_EQ(data_[position_ + i], 0u);
95 }
96 memcpy(&data_[position_], buffer, length);
97 position_ += length;
98 return length;
99 }
100
101 ALWAYS_INLINE size_t Overwrite(const void* buffer, size_t length) {
102 EnsureStorage(length);
103 memcpy(&data_[position_], buffer, length);
104 position_ += length;
105 return length;
106 }
107
108 ALWAYS_INLINE size_t Clear(size_t position, size_t length) {
109 EnsureStorage(length);
110 memset(&data_[position], 0, length);
111 return length;
112 }
113
114 ALWAYS_INLINE size_t WriteSleb128(int32_t value) {
115 EnsureStorage(8);
116 uint8_t* ptr = &data_[position_];
117 const size_t len = EncodeSignedLeb128(ptr, value) - ptr;
118 position_ += len;
119 return len;
120 }
121
122 ALWAYS_INLINE size_t WriteUleb128(uint32_t value) {
123 EnsureStorage(8);
124 uint8_t* ptr = &data_[position_];
125 const size_t len = EncodeUnsignedLeb128(ptr, value) - ptr;
126 position_ += len;
127 return len;
128 }
129
130 ALWAYS_INLINE void AlignTo(const size_t alignment) {
131 position_ = RoundUp(position_, alignment);
Mathieu Chartier4e046e22018-01-25 16:55:44 -0800132 EnsureStorage(0u);
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800133 }
134
135 ALWAYS_INLINE void Skip(const size_t count) {
136 position_ += count;
Mathieu Chartier4e046e22018-01-25 16:55:44 -0800137 EnsureStorage(0u);
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800138 }
139
140 class ScopedSeek {
141 public:
142 ScopedSeek(Stream* stream, uint32_t offset) : stream_(stream), offset_(stream->Tell()) {
143 stream->Seek(offset);
144 }
145
146 ~ScopedSeek() {
147 stream_->Seek(offset_);
148 }
149
150 private:
151 Stream* const stream_;
152 const uint32_t offset_;
153 };
154
155 private:
156 ALWAYS_INLINE void EnsureStorage(size_t length) {
157 size_t end = position_ + length;
158 while (UNLIKELY(end > data_size_)) {
159 section_->Resize(data_size_ * 3 / 2 + 1);
160 SyncWithSection();
161 }
162 }
163
164 void SyncWithSection() {
165 data_ = section_->Begin();
166 data_size_ = section_->Size();
167 }
168
169 // Current position of the stream.
170 size_t position_ = 0u;
171 DexContainer::Section* const section_ = nullptr;
172 // Cached Begin() from the container to provide faster accesses.
173 uint8_t* data_ = nullptr;
174 // Cached Size from the container to provide faster accesses.
175 size_t data_size_ = 0u;
176 };
177
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800178 static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) {
179 switch (type) {
180 case DexFile::kDexTypeClassDataItem:
181 case DexFile::kDexTypeStringDataItem:
182 case DexFile::kDexTypeDebugInfoItem:
183 case DexFile::kDexTypeAnnotationItem:
184 case DexFile::kDexTypeEncodedArrayItem:
185 return alignof(uint8_t);
186
187 default:
188 // All other sections are kDexAlignedSection.
189 return DexWriter::kDexSectionWordAlignment;
190 }
191 }
192
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800193 class Container : public DexContainer {
194 public:
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100195 Section* GetMainSection() override {
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800196 return &main_section_;
197 }
Jeff Haoa8621002016-10-04 18:13:44 +0000198
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100199 Section* GetDataSection() override {
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800200 return &data_section_;
201 }
202
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100203 bool IsCompactDexContainer() const override {
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800204 return false;
205 }
206
207 private:
208 VectorSection main_section_;
209 VectorSection data_section_;
210
211 friend class CompactDexWriter;
212 };
213
214 DexWriter(DexLayout* dex_layout, bool compute_offsets);
215
Mathieu Chartier05f90d12018-02-07 13:47:17 -0800216 static bool Output(DexLayout* dex_layout,
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800217 std::unique_ptr<DexContainer>* container,
Mathieu Chartier05f90d12018-02-07 13:47:17 -0800218 bool compute_offsets,
219 std::string* error_msg) WARN_UNUSED;
Jeff Haoa8621002016-10-04 18:13:44 +0000220
Mathieu Chartierf95a75e2017-11-03 15:25:52 -0700221 virtual ~DexWriter() {}
222
223 protected:
Mathieu Chartier05f90d12018-02-07 13:47:17 -0800224 virtual bool Write(DexContainer* output, std::string* error_msg);
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800225 virtual std::unique_ptr<DexContainer> CreateDexContainer() const;
Jeff Haoa8621002016-10-04 18:13:44 +0000226
Mathieu Chartier5e496142018-01-27 13:11:14 -0800227 void WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value);
228 void WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg);
229 void WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values);
230 void WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation);
231 void WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields);
232 void WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods);
Jeff Haoa8621002016-10-04 18:13:44 +0000233
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800234 // Header and id section
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800235 virtual void WriteHeader(Stream* stream);
Mathieu Chartierf6e31472017-12-28 13:32:08 -0800236 virtual size_t GetHeaderSize() const;
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800237 // reserve_only means don't write, only reserve space. This is required since the string data
238 // offsets must be assigned.
Mathieu Chartier5e496142018-01-27 13:11:14 -0800239 void WriteStringIds(Stream* stream, bool reserve_only);
240 void WriteTypeIds(Stream* stream);
241 void WriteProtoIds(Stream* stream, bool reserve_only);
242 void WriteFieldIds(Stream* stream);
243 void WriteMethodIds(Stream* stream);
244 void WriteClassDefs(Stream* stream, bool reserve_only);
245 void WriteCallSiteIds(Stream* stream, bool reserve_only);
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800246
Mathieu Chartier5e496142018-01-27 13:11:14 -0800247 void WriteEncodedArrays(Stream* stream);
248 void WriteAnnotations(Stream* stream);
249 void WriteAnnotationSets(Stream* stream);
250 void WriteAnnotationSetRefs(Stream* stream);
251 void WriteAnnotationsDirectories(Stream* stream);
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800252
253 // Data section.
Mathieu Chartier5e496142018-01-27 13:11:14 -0800254 void WriteDebugInfoItems(Stream* stream);
255 void WriteCodeItems(Stream* stream, bool reserve_only);
256 void WriteTypeLists(Stream* stream);
257 void WriteStringDatas(Stream* stream);
258 void WriteClassDatas(Stream* stream);
259 void WriteMethodHandles(Stream* stream);
David Brazdil20c765f2018-10-27 21:45:15 +0000260 void WriteHiddenapiClassData(Stream* stream);
Mathieu Chartier5e496142018-01-27 13:11:14 -0800261 void WriteMapItems(Stream* stream, MapItemQueue* queue);
262 void GenerateAndWriteMapItems(Stream* stream);
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800263
Mathieu Chartier5e496142018-01-27 13:11:14 -0800264 virtual void WriteCodeItemPostInstructionData(Stream* stream,
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800265 dex_ir::CodeItem* item,
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800266 bool reserve_only);
Mathieu Chartierb81ecad2018-01-23 22:08:26 -0800267 virtual void WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only);
268 virtual void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info);
269 virtual void WriteStringData(Stream* stream, dex_ir::StringData* string_data);
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800270
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800271 // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the
272 // existing offset and use that for writing.
Mathieu Chartiere6b6ff82018-01-19 18:58:34 -0800273 void ProcessOffset(Stream* stream, dex_ir::Item* item);
David Brazdil17834802019-01-21 19:46:46 +0000274 void ProcessOffset(Stream* stream, dex_ir::CollectionBase* item);
Jeff Haoa8621002016-10-04 18:13:44 +0000275
Jeff Haoea7c6292016-11-14 18:10:16 -0800276 dex_ir::Header* const header_;
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800277 DexLayout* const dex_layout_;
278 bool compute_offsets_;
Jeff Haoa8621002016-10-04 18:13:44 +0000279
Mathieu Chartierf95a75e2017-11-03 15:25:52 -0700280 private:
Jeff Haoa8621002016-10-04 18:13:44 +0000281 DISALLOW_COPY_AND_ASSIGN(DexWriter);
282};
283
Jeff Haoa8621002016-10-04 18:13:44 +0000284} // namespace art
285
286#endif // ART_DEXLAYOUT_DEX_WRITER_H_