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