1 /* 2 * Copyright (C) 2014 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_COMPILER_DEX_MIR_FIELD_INFO_H_ 18 #define ART_COMPILER_DEX_MIR_FIELD_INFO_H_ 19 20 #include "base/macros.h" 21 #include "dex_file.h" 22 #include "dex_instruction_utils.h" 23 #include "offsets.h" 24 25 namespace art { 26 27 class CompilerDriver; 28 class DexCompilationUnit; 29 30 /* 31 * Field info is calculated from the perspective of the compilation unit that accesses 32 * the field and stored in that unit's MIRGraph. Therefore it does not need to reference the 33 * dex file or method for which it has been calculated. However, we do store the declaring 34 * field index, class index and dex file of the resolved field to help distinguish between fields. 35 */ 36 37 class MirFieldInfo { 38 public: FieldIndex()39 uint16_t FieldIndex() const { 40 return field_idx_; 41 } SetFieldIndex(uint16_t field_idx)42 void SetFieldIndex(uint16_t field_idx) { 43 field_idx_ = field_idx; 44 } 45 IsStatic()46 bool IsStatic() const { 47 return (flags_ & kFlagIsStatic) != 0u; 48 } 49 IsResolved()50 bool IsResolved() const { 51 return declaring_dex_file_ != nullptr; 52 } 53 DeclaringDexFile()54 const DexFile* DeclaringDexFile() const { 55 return declaring_dex_file_; 56 } SetDeclaringDexFile(const DexFile * dex_file)57 void SetDeclaringDexFile(const DexFile* dex_file) { 58 declaring_dex_file_ = dex_file; 59 } 60 DeclaringClassIndex()61 uint16_t DeclaringClassIndex() const { 62 return declaring_class_idx_; 63 } 64 DeclaringFieldIndex()65 uint16_t DeclaringFieldIndex() const { 66 return declaring_field_idx_; 67 } 68 IsVolatile()69 bool IsVolatile() const { 70 return (flags_ & kFlagIsVolatile) != 0u; 71 } 72 73 // IGET_QUICK, IGET_BYTE_QUICK, ... IsQuickened()74 bool IsQuickened() const { 75 return (flags_ & kFlagIsQuickened) != 0u; 76 } 77 MemAccessType()78 DexMemAccessType MemAccessType() const { 79 return static_cast<DexMemAccessType>((flags_ >> kBitMemAccessTypeBegin) & kMemAccessTypeMask); 80 } 81 CheckEquals(const MirFieldInfo & other)82 void CheckEquals(const MirFieldInfo& other) const { 83 CHECK_EQ(field_idx_, other.field_idx_); 84 CHECK_EQ(flags_, other.flags_); 85 CHECK_EQ(declaring_field_idx_, other.declaring_field_idx_); 86 CHECK_EQ(declaring_class_idx_, other.declaring_class_idx_); 87 CHECK_EQ(declaring_dex_file_, other.declaring_dex_file_); 88 } 89 90 protected: 91 enum { 92 kBitIsStatic = 0, 93 kBitIsVolatile, 94 kBitIsQuickened, 95 kBitMemAccessTypeBegin, 96 kBitMemAccessTypeEnd = kBitMemAccessTypeBegin + 3, // 3 bits for raw type. 97 kFieldInfoBitEnd = kBitMemAccessTypeEnd 98 }; 99 static constexpr uint16_t kFlagIsVolatile = 1u << kBitIsVolatile; 100 static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic; 101 static constexpr uint16_t kFlagIsQuickened = 1u << kBitIsQuickened; 102 static constexpr uint16_t kMemAccessTypeMask = 7u; 103 static_assert((1u << (kBitMemAccessTypeEnd - kBitMemAccessTypeBegin)) - 1u == kMemAccessTypeMask, 104 "Invalid raw type mask"); 105 MirFieldInfo(uint16_t field_idx,uint16_t flags,DexMemAccessType type)106 MirFieldInfo(uint16_t field_idx, uint16_t flags, DexMemAccessType type) 107 : field_idx_(field_idx), 108 flags_(flags | static_cast<uint16_t>(type) << kBitMemAccessTypeBegin), 109 declaring_field_idx_(0u), 110 declaring_class_idx_(0u), 111 declaring_dex_file_(nullptr) { 112 } 113 114 // Make copy-ctor/assign/dtor protected to avoid slicing. 115 MirFieldInfo(const MirFieldInfo& other) = default; 116 MirFieldInfo& operator=(const MirFieldInfo& other) = default; 117 ~MirFieldInfo() = default; 118 119 // The field index in the compiling method's dex file. 120 uint16_t field_idx_; 121 // Flags, for volatility and derived class data. 122 uint16_t flags_; 123 // The field index in the dex file that defines field, 0 if unresolved. 124 uint16_t declaring_field_idx_; 125 // The type index of the class declaring the field, 0 if unresolved. 126 uint16_t declaring_class_idx_; 127 // The dex file that defines the class containing the field and the field, null if unresolved. 128 const DexFile* declaring_dex_file_; 129 }; 130 131 class MirIFieldLoweringInfo : public MirFieldInfo { 132 public: 133 // For each requested instance field retrieve the field's declaring location (dex file, class 134 // index and field index) and volatility and compute whether we can fast path the access 135 // with IGET/IPUT. For fast path fields, retrieve the field offset. 136 static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit, 137 MirIFieldLoweringInfo* field_infos, size_t count) 138 LOCKS_EXCLUDED(Locks::mutator_lock_); 139 140 // Construct an unresolved instance field lowering info. MirIFieldLoweringInfo(uint16_t field_idx,DexMemAccessType type,bool is_quickened)141 explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type, bool is_quickened) 142 : MirFieldInfo(field_idx, 143 kFlagIsVolatile | (is_quickened ? kFlagIsQuickened : 0u), 144 type), // Without kFlagIsStatic. 145 field_offset_(0u) { 146 } 147 FastGet()148 bool FastGet() const { 149 return (flags_ & kFlagFastGet) != 0u; 150 } 151 FastPut()152 bool FastPut() const { 153 return (flags_ & kFlagFastPut) != 0u; 154 } 155 FieldOffset()156 MemberOffset FieldOffset() const { 157 return field_offset_; 158 } 159 CheckEquals(const MirIFieldLoweringInfo & other)160 void CheckEquals(const MirIFieldLoweringInfo& other) const { 161 MirFieldInfo::CheckEquals(other); 162 CHECK_EQ(field_offset_.Uint32Value(), other.field_offset_.Uint32Value()); 163 } 164 165 private: 166 enum { 167 kBitFastGet = kFieldInfoBitEnd, 168 kBitFastPut, 169 kIFieldLoweringInfoBitEnd 170 }; 171 static_assert(kIFieldLoweringInfoBitEnd <= 16, "Too many flags"); 172 static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet; 173 static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut; 174 175 // The member offset of the field, 0u if unresolved. 176 MemberOffset field_offset_; 177 178 friend class NullCheckEliminationTest; 179 friend class GlobalValueNumberingTest; 180 friend class GvnDeadCodeEliminationTest; 181 friend class LocalValueNumberingTest; 182 friend class TypeInferenceTest; 183 }; 184 185 class MirSFieldLoweringInfo : public MirFieldInfo { 186 public: 187 // For each requested static field retrieve the field's declaring location (dex file, class 188 // index and field index) and volatility and compute whether we can fast path the access with 189 // IGET/IPUT. For fast path fields (at least for IGET), retrieve the information needed for 190 // the field access, i.e. the field offset, whether the field is in the same class as the 191 // method being compiled, whether the declaring class can be safely assumed to be initialized 192 // and the type index of the declaring class in the compiled method's dex file. 193 static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit, 194 MirSFieldLoweringInfo* field_infos, size_t count) 195 LOCKS_EXCLUDED(Locks::mutator_lock_); 196 197 // Construct an unresolved static field lowering info. MirSFieldLoweringInfo(uint16_t field_idx,DexMemAccessType type)198 explicit MirSFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type) 199 : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic, type), 200 field_offset_(0u), 201 storage_index_(DexFile::kDexNoIndex) { 202 } 203 FastGet()204 bool FastGet() const { 205 return (flags_ & kFlagFastGet) != 0u; 206 } 207 FastPut()208 bool FastPut() const { 209 return (flags_ & kFlagFastPut) != 0u; 210 } 211 IsReferrersClass()212 bool IsReferrersClass() const { 213 return (flags_ & kFlagIsReferrersClass) != 0u; 214 } 215 IsClassInitialized()216 bool IsClassInitialized() const { 217 return (flags_ & kFlagClassIsInitialized) != 0u; 218 } 219 IsClassInDexCache()220 bool IsClassInDexCache() const { 221 return (flags_ & kFlagClassIsInDexCache) != 0u; 222 } 223 FieldOffset()224 MemberOffset FieldOffset() const { 225 return field_offset_; 226 } 227 StorageIndex()228 uint32_t StorageIndex() const { 229 return storage_index_; 230 } 231 232 private: 233 enum { 234 kBitFastGet = kFieldInfoBitEnd, 235 kBitFastPut, 236 kBitIsReferrersClass, 237 kBitClassIsInitialized, 238 kBitClassIsInDexCache, 239 kSFieldLoweringInfoBitEnd 240 }; 241 static_assert(kSFieldLoweringInfoBitEnd <= 16, "Too many flags"); 242 static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet; 243 static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut; 244 static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass; 245 static constexpr uint16_t kFlagClassIsInitialized = 1u << kBitClassIsInitialized; 246 static constexpr uint16_t kFlagClassIsInDexCache = 1u << kBitClassIsInDexCache; 247 248 // The member offset of the field, 0u if unresolved. 249 MemberOffset field_offset_; 250 // The type index of the declaring class in the compiling method's dex file, 251 // -1 if the field is unresolved or there's no appropriate TypeId in that dex file. 252 uint32_t storage_index_; 253 254 friend class ClassInitCheckEliminationTest; 255 friend class GlobalValueNumberingTest; 256 friend class GvnDeadCodeEliminationTest; 257 friend class LocalValueNumberingTest; 258 friend class TypeInferenceTest; 259 }; 260 261 } // namespace art 262 263 #endif // ART_COMPILER_DEX_MIR_FIELD_INFO_H_ 264