blob: 47edd517fa67e13fef052110dada2c1fd723485d [file] [log] [blame]
Mathieu Chartiercf76bf82017-09-25 16:22:36 -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
David Sehr334b9d72018-02-12 18:27:56 -080017#ifndef ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_
18#define ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_
Mathieu Chartiercf76bf82017-09-25 16:22:36 -070019
Mathieu Chartierf6e31472017-12-28 13:32:08 -080020#include "base/casts.h"
Mathieu Chartiercf76bf82017-09-25 16:22:36 -070021#include "dex_file.h"
Mathieu Chartier5e3cfa22018-02-20 16:53:37 -080022#include "dex/compact_offset_table.h"
Mathieu Chartiercf76bf82017-09-25 16:22:36 -070023
24namespace art {
25
26// CompactDex is a currently ART internal dex file format that aims to reduce storage/RAM usage.
27class CompactDexFile : public DexFile {
28 public:
Mathieu Chartier69147f12017-11-06 20:02:24 -080029 static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
30 static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
31
Mathieu Chartierf6e31472017-12-28 13:32:08 -080032 enum class FeatureFlags : uint32_t {
33 kDefaultMethods = 0x1,
34 };
35
Mathieu Chartierf95a75e2017-11-03 15:25:52 -070036 class Header : public DexFile::Header {
Mathieu Chartierf6e31472017-12-28 13:32:08 -080037 public:
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -080038 static const Header* At(const void* at) {
39 return reinterpret_cast<const Header*>(at);
40 }
41
Mathieu Chartierf6e31472017-12-28 13:32:08 -080042 uint32_t GetFeatureFlags() const {
43 return feature_flags_;
44 }
45
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -080046 uint32_t GetDataOffset() const {
47 return data_off_;
48 }
49
50 uint32_t GetDataSize() const {
51 return data_size_;
52 }
53
Mathieu Chartierc17b7d82018-03-14 14:00:04 -070054 // Range of the shared data section owned by the dex file. Owned in this context refers to data
55 // for this DEX that was not deduplicated to another DEX.
56 uint32_t OwnedDataBegin() const {
57 return owned_data_begin_;
58 }
59
60 uint32_t OwnedDataEnd() const {
61 return owned_data_end_;
62 }
63
Mathieu Chartierf6e31472017-12-28 13:32:08 -080064 private:
65 uint32_t feature_flags_ = 0u;
66
Mathieu Chartier8892c6b2018-01-09 15:10:17 -080067 // Position in the compact dex file for the debug info table data starts.
68 uint32_t debug_info_offsets_pos_ = 0u;
69
70 // Offset into the debug info table data where the lookup table is.
71 uint32_t debug_info_offsets_table_offset_ = 0u;
72
73 // Base offset of where debug info starts in the dex file.
74 uint32_t debug_info_base_ = 0u;
75
Mathieu Chartierc17b7d82018-03-14 14:00:04 -070076 // Range of the shared data section owned by the dex file.
77 uint32_t owned_data_begin_ = 0u;
78 uint32_t owned_data_end_ = 0u;
79
Mathieu Chartier8892c6b2018-01-09 15:10:17 -080080 friend class CompactDexFile;
Mathieu Chartierf6e31472017-12-28 13:32:08 -080081 friend class CompactDexWriter;
Mathieu Chartierf95a75e2017-11-03 15:25:52 -070082 };
Mathieu Chartier69147f12017-11-06 20:02:24 -080083
Mathieu Chartier8740c662018-01-11 14:50:02 -080084 // Like the standard code item except without a debug info offset. Each code item may have a
85 // preheader to encode large methods. In 99% of cases, the preheader is not used. This enables
86 // smaller size with a good fast path case in the accessors.
Andreas Gampe3f1dcd32018-12-28 09:39:56 -080087 struct CodeItem : public dex::CodeItem {
Mathieu Chartier8740c662018-01-11 14:50:02 -080088 static constexpr size_t kAlignment = sizeof(uint16_t);
89 // Max preheader size in uint16_ts.
90 static constexpr size_t kMaxPreHeaderSize = 6;
Mathieu Chartier8892c6b2018-01-09 15:10:17 -080091
Mathieu Chartier69147f12017-11-06 20:02:24 -080092 private:
Mathieu Chartier8892c6b2018-01-09 15:10:17 -080093 CodeItem() = default;
94
Mathieu Chartier8740c662018-01-11 14:50:02 -080095 static constexpr size_t kRegistersSizeShift = 12;
96 static constexpr size_t kInsSizeShift = 8;
97 static constexpr size_t kOutsSizeShift = 4;
98 static constexpr size_t kTriesSizeSizeShift = 0;
99 static constexpr uint16_t kFlagPreHeaderRegisterSize = 0x1 << 0;
100 static constexpr uint16_t kFlagPreHeaderInsSize = 0x1 << 1;
101 static constexpr uint16_t kFlagPreHeaderOutsSize = 0x1 << 2;
102 static constexpr uint16_t kFlagPreHeaderTriesSize = 0x1 << 3;
103 static constexpr uint16_t kFlagPreHeaderInsnsSize = 0x1 << 4;
104 static constexpr size_t kInsnsSizeShift = 5;
105 static constexpr size_t kInsnsSizeBits = sizeof(uint16_t) * kBitsPerByte - kInsnsSizeShift;
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800106
Mathieu Chartier8740c662018-01-11 14:50:02 -0800107 // Combined preheader flags for fast testing if we need to go slow path.
108 static constexpr uint16_t kFlagPreHeaderCombined =
109 kFlagPreHeaderRegisterSize |
110 kFlagPreHeaderInsSize |
111 kFlagPreHeaderOutsSize |
112 kFlagPreHeaderTriesSize |
113 kFlagPreHeaderInsnsSize;
114
115 // Create a code item and associated preheader if required based on field values.
116 // Returns the start of the preheader. The preheader buffer must be at least as large as
117 // kMaxPreHeaderSize;
118 uint16_t* Create(uint16_t registers_size,
119 uint16_t ins_size,
120 uint16_t outs_size,
121 uint16_t tries_size,
122 uint32_t insns_size_in_code_units,
123 uint16_t* out_preheader) {
124 // Dex verification ensures that registers size > ins_size, so we can subtract the registers
125 // size accordingly to reduce how often we need to use the preheader.
126 DCHECK_GE(registers_size, ins_size);
127 registers_size -= ins_size;
128 fields_ = (registers_size & 0xF) << kRegistersSizeShift;
129 fields_ |= (ins_size & 0xF) << kInsSizeShift;
130 fields_ |= (outs_size & 0xF) << kOutsSizeShift;
131 fields_ |= (tries_size & 0xF) << kTriesSizeSizeShift;
132 registers_size &= ~0xF;
133 ins_size &= ~0xF;
134 outs_size &= ~0xF;
135 tries_size &= ~0xF;
136 insns_count_and_flags_ = 0;
137 const size_t masked_count = insns_size_in_code_units & ((1 << kInsnsSizeBits) - 1);
138 insns_count_and_flags_ |= masked_count << kInsnsSizeShift;
139 insns_size_in_code_units -= masked_count;
140
141 // Since the preheader case is rare (1% of code items), use a suboptimally large but fast
142 // decoding format.
143 if (insns_size_in_code_units != 0) {
144 insns_count_and_flags_ |= kFlagPreHeaderInsnsSize;
145 --out_preheader;
146 *out_preheader = static_cast<uint16_t>(insns_size_in_code_units);
147 --out_preheader;
148 *out_preheader = static_cast<uint16_t>(insns_size_in_code_units >> 16);
149 }
150 auto preheader_encode = [&](uint16_t size, uint16_t flag) {
151 if (size != 0) {
152 insns_count_and_flags_ |= flag;
153 --out_preheader;
154 *out_preheader = size;
155 }
156 };
157 preheader_encode(registers_size, kFlagPreHeaderRegisterSize);
158 preheader_encode(ins_size, kFlagPreHeaderInsSize);
159 preheader_encode(outs_size, kFlagPreHeaderOutsSize);
160 preheader_encode(tries_size, kFlagPreHeaderTriesSize);
161 return out_preheader;
162 }
163
164 ALWAYS_INLINE bool HasPreHeader(uint16_t flag) const {
165 return (insns_count_and_flags_ & flag) != 0;
166 }
167
168 // Return true if the code item has any preheaders.
169 ALWAYS_INLINE static bool HasAnyPreHeader(uint16_t insns_count_and_flags) {
170 return (insns_count_and_flags & kFlagPreHeaderCombined) != 0;
171 }
172
173 ALWAYS_INLINE uint16_t* GetPreHeader() {
174 return reinterpret_cast<uint16_t*>(this);
175 }
176
177 ALWAYS_INLINE const uint16_t* GetPreHeader() const {
178 return reinterpret_cast<const uint16_t*>(this);
179 }
180
181 // Decode fields and read the preheader if necessary. If kDecodeOnlyInstructionCount is
182 // specified then only the instruction count is decoded.
183 template <bool kDecodeOnlyInstructionCount>
184 ALWAYS_INLINE void DecodeFields(uint32_t* insns_count,
185 uint16_t* registers_size,
186 uint16_t* ins_size,
187 uint16_t* outs_size,
188 uint16_t* tries_size) const {
189 *insns_count = insns_count_and_flags_ >> kInsnsSizeShift;
190 if (!kDecodeOnlyInstructionCount) {
191 const uint16_t fields = fields_;
192 *registers_size = (fields >> kRegistersSizeShift) & 0xF;
193 *ins_size = (fields >> kInsSizeShift) & 0xF;
194 *outs_size = (fields >> kOutsSizeShift) & 0xF;
195 *tries_size = (fields >> kTriesSizeSizeShift) & 0xF;
196 }
197 if (UNLIKELY(HasAnyPreHeader(insns_count_and_flags_))) {
198 const uint16_t* preheader = GetPreHeader();
199 if (HasPreHeader(kFlagPreHeaderInsnsSize)) {
200 --preheader;
201 *insns_count += static_cast<uint32_t>(*preheader);
202 --preheader;
203 *insns_count += static_cast<uint32_t>(*preheader) << 16;
204 }
205 if (!kDecodeOnlyInstructionCount) {
206 if (HasPreHeader(kFlagPreHeaderRegisterSize)) {
207 --preheader;
208 *registers_size += preheader[0];
209 }
210 if (HasPreHeader(kFlagPreHeaderInsSize)) {
211 --preheader;
212 *ins_size += preheader[0];
213 }
214 if (HasPreHeader(kFlagPreHeaderOutsSize)) {
215 --preheader;
216 *outs_size += preheader[0];
217 }
218 if (HasPreHeader(kFlagPreHeaderTriesSize)) {
219 --preheader;
220 *tries_size += preheader[0];
221 }
222 }
223 }
224 if (!kDecodeOnlyInstructionCount) {
225 *registers_size += *ins_size;
226 }
227 }
228
229 // Packed code item data, 4 bits each: [registers_size, ins_size, outs_size, tries_size]
230 uint16_t fields_;
231
232 // 5 bits for if either of the fields required preheader extension, 11 bits for the number of
233 // instruction code units.
234 uint16_t insns_count_and_flags_;
235
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800236 uint16_t insns_[1]; // actual array of bytecode.
237
238 ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
Mathieu Chartier8740c662018-01-11 14:50:02 -0800239 ART_FRIEND_TEST(CompactDexFileTest, CodeItemFields);
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800240 friend class CodeItemDataAccessor;
241 friend class CodeItemDebugInfoAccessor;
242 friend class CodeItemInstructionAccessor;
Mathieu Chartier6238c832018-01-04 09:55:13 -0800243 friend class CompactDexFile;
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800244 friend class CompactDexWriter;
Mathieu Chartier69147f12017-11-06 20:02:24 -0800245 DISALLOW_COPY_AND_ASSIGN(CodeItem);
246 };
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700247
Mathieu Chartier603ccab2017-10-20 14:34:28 -0700248 // Write the compact dex specific magic.
249 static void WriteMagic(uint8_t* magic);
250
251 // Write the current version, note that the input is the address of the magic.
252 static void WriteCurrentVersion(uint8_t* magic);
253
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700254 // Returns true if the byte string points to the magic value.
255 static bool IsMagicValid(const uint8_t* magic);
Roland Levillainf73caca2018-08-24 17:19:07 +0100256 bool IsMagicValid() const override;
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700257
258 // Returns true if the byte string after the magic is the correct value.
259 static bool IsVersionValid(const uint8_t* magic);
Roland Levillainf73caca2018-08-24 17:19:07 +0100260 bool IsVersionValid() const override;
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700261
Alex Lightca97ada2018-02-02 09:25:31 -0800262 // TODO This is completely a guess. We really need to do better. b/72402467
263 // We ask for 64 megabytes which should be big enough for any realistic dex file.
Roland Levillainf73caca2018-08-24 17:19:07 +0100264 size_t GetDequickenedSize() const override {
Alex Lightca97ada2018-02-02 09:25:31 -0800265 return 64 * MB;
266 }
267
Mathieu Chartierf6e31472017-12-28 13:32:08 -0800268 const Header& GetHeader() const {
269 return down_cast<const Header&>(DexFile::GetHeader());
270 }
271
Roland Levillainf73caca2018-08-24 17:19:07 +0100272 bool SupportsDefaultMethods() const override;
Mathieu Chartierf6e31472017-12-28 13:32:08 -0800273
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800274 uint32_t GetCodeItemSize(const dex::CodeItem& item) const override;
Mathieu Chartier6238c832018-01-04 09:55:13 -0800275
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800276 uint32_t GetDebugInfoOffset(uint32_t dex_method_index) const {
Mathieu Chartier5e3cfa22018-02-20 16:53:37 -0800277 return debug_info_offsets_.GetOffset(dex_method_index);
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800278 }
279
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -0800280 static uint32_t CalculateChecksum(const uint8_t* base_begin,
281 size_t base_size,
282 const uint8_t* data_begin,
283 size_t data_size);
Roland Levillainf73caca2018-08-24 17:19:07 +0100284 uint32_t CalculateChecksum() const override;
Mathieu Chartierc3a22aa2018-01-19 18:58:34 -0800285
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700286 private:
David Sehr0b426772018-07-03 23:03:42 +0000287 CompactDexFile(const uint8_t* base,
288 size_t size,
289 const uint8_t* data_begin,
290 size_t data_size,
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700291 const std::string& location,
292 uint32_t location_checksum,
David Sehr0b426772018-07-03 23:03:42 +0000293 const OatDexFile* oat_dex_file,
294 std::unique_ptr<DexFileContainer> container);
Mathieu Chartier8892c6b2018-01-09 15:10:17 -0800295
Mathieu Chartier5e3cfa22018-02-20 16:53:37 -0800296 CompactOffsetTable::Accessor debug_info_offsets_;
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700297
298 friend class DexFile;
Mathieu Chartier603ccab2017-10-20 14:34:28 -0700299 friend class DexFileLoader;
Mathieu Chartiercf76bf82017-09-25 16:22:36 -0700300 DISALLOW_COPY_AND_ASSIGN(CompactDexFile);
301};
302
303} // namespace art
304
David Sehr334b9d72018-02-12 18:27:56 -0800305#endif // ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_