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 17 #ifndef ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_ 18 #define ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_ 19 20 #include <memory> 21 22 #include "base/casts.h" 23 #include "dex/compact_offset_table.h" 24 #include "dex_file.h" 25 26 namespace art { 27 28 // CompactDex is a currently ART internal dex file format that aims to reduce storage/RAM usage. 29 class CompactDexFile : public DexFile { 30 public: 31 static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' }; 32 // Last change: remove code item deduping. 33 static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'}; 34 35 enum class FeatureFlags : uint32_t { 36 kDefaultMethods = 0x1, 37 }; 38 39 class Header : public DexFile::Header { 40 public: At(const void * at)41 static const Header* At(const void* at) { 42 return reinterpret_cast<const Header*>(at); 43 } 44 GetFeatureFlags()45 uint32_t GetFeatureFlags() const { 46 return feature_flags_; 47 } 48 GetDataOffset()49 uint32_t GetDataOffset() const { 50 return data_off_; 51 } 52 GetDataSize()53 uint32_t GetDataSize() const { 54 return data_size_; 55 } 56 57 // Range of the shared data section owned by the dex file. Owned in this context refers to data 58 // for this DEX that was not deduplicated to another DEX. OwnedDataBegin()59 uint32_t OwnedDataBegin() const { 60 return owned_data_begin_; 61 } 62 OwnedDataEnd()63 uint32_t OwnedDataEnd() const { 64 return owned_data_end_; 65 } 66 67 private: 68 uint32_t feature_flags_ = 0u; 69 70 // Position in the compact dex file for the debug info table data starts. 71 uint32_t debug_info_offsets_pos_ = 0u; 72 73 // Offset into the debug info table data where the lookup table is. 74 uint32_t debug_info_offsets_table_offset_ = 0u; 75 76 // Base offset of where debug info starts in the dex file. 77 uint32_t debug_info_base_ = 0u; 78 79 // Range of the shared data section owned by the dex file. 80 uint32_t owned_data_begin_ = 0u; 81 uint32_t owned_data_end_ = 0u; 82 83 friend class CompactDexFile; 84 friend class CompactDexWriter; 85 }; 86 87 // Like the standard code item except without a debug info offset. Each code item may have a 88 // preheader to encode large methods. In 99% of cases, the preheader is not used. This enables 89 // smaller size with a good fast path case in the accessors. 90 struct CodeItem : public dex::CodeItem { 91 static constexpr size_t kAlignment = sizeof(uint16_t); 92 // Max preheader size in uint16_ts. 93 static constexpr size_t kMaxPreHeaderSize = 6; 94 FieldsOffsetCodeItem95 static constexpr size_t FieldsOffset() { 96 return OFFSETOF_MEMBER(CodeItem, fields_); 97 } 98 InsnsCountAndFlagsOffsetCodeItem99 static constexpr size_t InsnsCountAndFlagsOffset() { 100 return OFFSETOF_MEMBER(CodeItem, insns_count_and_flags_); 101 } 102 InsnsOffsetCodeItem103 static constexpr size_t InsnsOffset() { 104 return OFFSETOF_MEMBER(CodeItem, insns_); 105 } 106 107 static constexpr size_t kRegistersSizeShift = 12; 108 static constexpr size_t kInsSizeShift = 8; 109 static constexpr size_t kOutsSizeShift = 4; 110 static constexpr size_t kTriesSizeSizeShift = 0; 111 static constexpr uint16_t kBitPreHeaderRegistersSize = 0; 112 static constexpr uint16_t kBitPreHeaderInsSize = 1; 113 static constexpr uint16_t kBitPreHeaderOutsSize = 2; 114 static constexpr uint16_t kBitPreHeaderTriesSize = 3; 115 static constexpr uint16_t kBitPreHeaderInsnsSize = 4; 116 static constexpr uint16_t kFlagPreHeaderRegistersSize = 0x1 << kBitPreHeaderRegistersSize; 117 static constexpr uint16_t kFlagPreHeaderInsSize = 0x1 << kBitPreHeaderInsSize; 118 static constexpr uint16_t kFlagPreHeaderOutsSize = 0x1 << kBitPreHeaderOutsSize; 119 static constexpr uint16_t kFlagPreHeaderTriesSize = 0x1 << kBitPreHeaderTriesSize; 120 static constexpr uint16_t kFlagPreHeaderInsnsSize = 0x1 << kBitPreHeaderInsnsSize; 121 static constexpr size_t kInsnsSizeShift = 5; 122 static constexpr size_t kInsnsSizeBits = sizeof(uint16_t) * kBitsPerByte - kInsnsSizeShift; 123 124 private: 125 CodeItem() = default; 126 127 // Combined preheader flags for fast testing if we need to go slow path. 128 static constexpr uint16_t kFlagPreHeaderCombined = 129 kFlagPreHeaderRegistersSize | 130 kFlagPreHeaderInsSize | 131 kFlagPreHeaderOutsSize | 132 kFlagPreHeaderTriesSize | 133 kFlagPreHeaderInsnsSize; 134 135 // Create a code item and associated preheader if required based on field values. 136 // Returns the start of the preheader. The preheader buffer must be at least as large as 137 // kMaxPreHeaderSize; CreateCodeItem138 uint16_t* Create(uint16_t registers_size, 139 uint16_t ins_size, 140 uint16_t outs_size, 141 uint16_t tries_size, 142 uint32_t insns_size_in_code_units, 143 uint16_t* out_preheader) { 144 // Dex verification ensures that registers size > ins_size, so we can subtract the registers 145 // size accordingly to reduce how often we need to use the preheader. 146 DCHECK_GE(registers_size, ins_size); 147 registers_size -= ins_size; 148 fields_ = (registers_size & 0xF) << kRegistersSizeShift; 149 fields_ |= (ins_size & 0xF) << kInsSizeShift; 150 fields_ |= (outs_size & 0xF) << kOutsSizeShift; 151 fields_ |= (tries_size & 0xF) << kTriesSizeSizeShift; 152 registers_size &= ~0xF; 153 ins_size &= ~0xF; 154 outs_size &= ~0xF; 155 tries_size &= ~0xF; 156 insns_count_and_flags_ = 0; 157 const size_t masked_count = insns_size_in_code_units & ((1 << kInsnsSizeBits) - 1); 158 insns_count_and_flags_ |= masked_count << kInsnsSizeShift; 159 insns_size_in_code_units -= masked_count; 160 161 // Since the preheader case is rare (1% of code items), use a suboptimally large but fast 162 // decoding format. 163 if (insns_size_in_code_units != 0) { 164 insns_count_and_flags_ |= kFlagPreHeaderInsnsSize; 165 --out_preheader; 166 *out_preheader = static_cast<uint16_t>(insns_size_in_code_units); 167 --out_preheader; 168 *out_preheader = static_cast<uint16_t>(insns_size_in_code_units >> 16); 169 } 170 auto preheader_encode = [&](uint16_t size, uint16_t flag) { 171 if (size != 0) { 172 insns_count_and_flags_ |= flag; 173 --out_preheader; 174 *out_preheader = size; 175 } 176 }; 177 preheader_encode(registers_size, kFlagPreHeaderRegistersSize); 178 preheader_encode(ins_size, kFlagPreHeaderInsSize); 179 preheader_encode(outs_size, kFlagPreHeaderOutsSize); 180 preheader_encode(tries_size, kFlagPreHeaderTriesSize); 181 return out_preheader; 182 } 183 HasPreHeaderCodeItem184 ALWAYS_INLINE bool HasPreHeader(uint16_t flag) const { 185 return (insns_count_and_flags_ & flag) != 0; 186 } 187 188 // Return true if the code item has any preheaders. HasAnyPreHeaderCodeItem189 ALWAYS_INLINE static bool HasAnyPreHeader(uint16_t insns_count_and_flags) { 190 return (insns_count_and_flags & kFlagPreHeaderCombined) != 0; 191 } 192 GetPreHeaderCodeItem193 ALWAYS_INLINE uint16_t* GetPreHeader() { 194 return reinterpret_cast<uint16_t*>(this); 195 } 196 GetPreHeaderCodeItem197 ALWAYS_INLINE const uint16_t* GetPreHeader() const { 198 return reinterpret_cast<const uint16_t*>(this); 199 } 200 201 // Decode fields and read the preheader if necessary. If kDecodeOnlyInstructionCount is 202 // specified then only the instruction count is decoded. 203 template <bool kDecodeOnlyInstructionCount> DecodeFieldsCodeItem204 ALWAYS_INLINE void DecodeFields(uint32_t* insns_count, 205 uint16_t* registers_size, 206 uint16_t* ins_size, 207 uint16_t* outs_size, 208 uint16_t* tries_size) const { 209 *insns_count = insns_count_and_flags_ >> kInsnsSizeShift; 210 if (!kDecodeOnlyInstructionCount) { 211 const uint16_t fields = fields_; 212 *registers_size = (fields >> kRegistersSizeShift) & 0xF; 213 *ins_size = (fields >> kInsSizeShift) & 0xF; 214 *outs_size = (fields >> kOutsSizeShift) & 0xF; 215 *tries_size = (fields >> kTriesSizeSizeShift) & 0xF; 216 } 217 if (UNLIKELY(HasAnyPreHeader(insns_count_and_flags_))) { 218 const uint16_t* preheader = GetPreHeader(); 219 if (HasPreHeader(kFlagPreHeaderInsnsSize)) { 220 --preheader; 221 *insns_count += static_cast<uint32_t>(*preheader); 222 --preheader; 223 *insns_count += static_cast<uint32_t>(*preheader) << 16; 224 } 225 if (!kDecodeOnlyInstructionCount) { 226 if (HasPreHeader(kFlagPreHeaderRegistersSize)) { 227 --preheader; 228 *registers_size += preheader[0]; 229 } 230 if (HasPreHeader(kFlagPreHeaderInsSize)) { 231 --preheader; 232 *ins_size += preheader[0]; 233 } 234 if (HasPreHeader(kFlagPreHeaderOutsSize)) { 235 --preheader; 236 *outs_size += preheader[0]; 237 } 238 if (HasPreHeader(kFlagPreHeaderTriesSize)) { 239 --preheader; 240 *tries_size += preheader[0]; 241 } 242 } 243 } 244 if (!kDecodeOnlyInstructionCount) { 245 *registers_size += *ins_size; 246 } 247 } 248 249 // Packed code item data, 4 bits each: [registers_size, ins_size, outs_size, tries_size] 250 uint16_t fields_; 251 252 // 5 bits for if either of the fields required preheader extension, 11 bits for the number of 253 // instruction code units. 254 uint16_t insns_count_and_flags_; 255 256 uint16_t insns_[1]; // actual array of bytecode. 257 258 ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor); 259 ART_FRIEND_TEST(CompactDexFileTest, CodeItemFields); 260 friend class CodeItemDataAccessor; 261 friend class CodeItemDebugInfoAccessor; 262 friend class CodeItemInstructionAccessor; 263 friend class CompactDexFile; 264 friend class CompactDexWriter; 265 DISALLOW_COPY_AND_ASSIGN(CodeItem); 266 }; 267 268 // Write the compact dex specific magic. 269 static void WriteMagic(uint8_t* magic); 270 271 // Write the current version, note that the input is the address of the magic. 272 static void WriteCurrentVersion(uint8_t* magic); 273 274 // Returns true if the byte string points to the magic value. 275 static bool IsMagicValid(const uint8_t* magic); 276 bool IsMagicValid() const override; 277 278 // Returns true if the byte string after the magic is the correct value. 279 static bool IsVersionValid(const uint8_t* magic); 280 bool IsVersionValid() const override; 281 282 // TODO This is completely a guess. We really need to do better. b/72402467 283 // We ask for 64 megabytes which should be big enough for any realistic dex file. GetDequickenedSize()284 size_t GetDequickenedSize() const override { 285 return 64 * MB; 286 } 287 GetHeader()288 const Header& GetHeader() const { 289 return down_cast<const Header&>(DexFile::GetHeader()); 290 } 291 292 bool SupportsDefaultMethods() const override; 293 294 uint32_t GetCodeItemSize(const dex::CodeItem& item) const override; 295 GetDebugInfoOffset(uint32_t dex_method_index)296 uint32_t GetDebugInfoOffset(uint32_t dex_method_index) const { 297 return debug_info_offsets_.GetOffset(dex_method_index); 298 } 299 300 static uint32_t CalculateChecksum(const uint8_t* base_begin, 301 size_t base_size, 302 const uint8_t* data_begin, 303 size_t data_size); 304 uint32_t CalculateChecksum() const override; 305 306 private: 307 CompactDexFile(const uint8_t* base, 308 size_t size, 309 const std::string& location, 310 uint32_t location_checksum, 311 const OatDexFile* oat_dex_file, 312 // Shared since several dex files may be stored in the same logical container. 313 std::shared_ptr<DexFileContainer> container); 314 315 CompactOffsetTable::Accessor debug_info_offsets_; 316 317 friend class DexFile; 318 friend class DexFileLoader; 319 DISALLOW_COPY_AND_ASSIGN(CompactDexFile); 320 }; 321 322 } // namespace art 323 324 #endif // ART_LIBDEXFILE_DEX_COMPACT_DEX_FILE_H_ 325