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 "offsets.h"
23 
24 namespace art {
25 
26 class CompilerDriver;
27 class DexCompilationUnit;
28 
29 /*
30  * Field info is calculated from the perspective of the compilation unit that accesses
31  * the field and stored in that unit's MIRGraph. Therefore it does not need to reference the
32  * dex file or method for which it has been calculated. However, we do store the declaring
33  * field index, class index and dex file of the resolved field to help distinguish between fields.
34  */
35 
36 class MirFieldInfo {
37  public:
FieldIndex()38   uint16_t FieldIndex() const {
39     return field_idx_;
40   }
41 
IsStatic()42   bool IsStatic() const {
43     return (flags_ & kFlagIsStatic) != 0u;
44   }
45 
IsResolved()46   bool IsResolved() const {
47     return declaring_dex_file_ != nullptr;
48   }
49 
DeclaringDexFile()50   const DexFile* DeclaringDexFile() const {
51     return declaring_dex_file_;
52   }
53 
DeclaringClassIndex()54   uint16_t DeclaringClassIndex() const {
55     return declaring_class_idx_;
56   }
57 
DeclaringFieldIndex()58   uint16_t DeclaringFieldIndex() const {
59     return declaring_field_idx_;
60   }
61 
IsVolatile()62   bool IsVolatile() const {
63     return (flags_ & kFlagIsVolatile) != 0u;
64   }
65 
66  protected:
67   enum {
68     kBitIsStatic = 0,
69     kBitIsVolatile,
70     kFieldInfoBitEnd
71   };
72   static constexpr uint16_t kFlagIsVolatile = 1u << kBitIsVolatile;
73   static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic;
74 
MirFieldInfo(uint16_t field_idx,uint16_t flags)75   MirFieldInfo(uint16_t field_idx, uint16_t flags)
76       : field_idx_(field_idx),
77         flags_(flags),
78         declaring_field_idx_(0u),
79         declaring_class_idx_(0u),
80         declaring_dex_file_(nullptr) {
81   }
82 
83   // Make copy-ctor/assign/dtor protected to avoid slicing.
84   MirFieldInfo(const MirFieldInfo& other) = default;
85   MirFieldInfo& operator=(const MirFieldInfo& other) = default;
86   ~MirFieldInfo() = default;
87 
88   // The field index in the compiling method's dex file.
89   uint16_t field_idx_;
90   // Flags, for volatility and derived class data.
91   uint16_t flags_;
92   // The field index in the dex file that defines field, 0 if unresolved.
93   uint16_t declaring_field_idx_;
94   // The type index of the class declaring the field, 0 if unresolved.
95   uint16_t declaring_class_idx_;
96   // The dex file that defines the class containing the field and the field, nullptr if unresolved.
97   const DexFile* declaring_dex_file_;
98 };
99 
100 class MirIFieldLoweringInfo : public MirFieldInfo {
101  public:
102   // For each requested instance field retrieve the field's declaring location (dex file, class
103   // index and field index) and volatility and compute whether we can fast path the access
104   // with IGET/IPUT. For fast path fields, retrieve the field offset.
105   static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit,
106                       MirIFieldLoweringInfo* field_infos, size_t count)
107       LOCKS_EXCLUDED(Locks::mutator_lock_);
108 
109   // Construct an unresolved instance field lowering info.
MirIFieldLoweringInfo(uint16_t field_idx)110   explicit MirIFieldLoweringInfo(uint16_t field_idx)
111       : MirFieldInfo(field_idx, kFlagIsVolatile),  // Without kFlagIsStatic.
112         field_offset_(0u) {
113   }
114 
FastGet()115   bool FastGet() const {
116     return (flags_ & kFlagFastGet) != 0u;
117   }
118 
FastPut()119   bool FastPut() const {
120     return (flags_ & kFlagFastPut) != 0u;
121   }
122 
FieldOffset()123   MemberOffset FieldOffset() const {
124     return field_offset_;
125   }
126 
127  private:
128   enum {
129     kBitFastGet = kFieldInfoBitEnd,
130     kBitFastPut,
131     kIFieldLoweringInfoBitEnd
132   };
133   COMPILE_ASSERT(kIFieldLoweringInfoBitEnd <= 16, too_many_flags);
134   static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet;
135   static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut;
136 
137   // The member offset of the field, 0u if unresolved.
138   MemberOffset field_offset_;
139 
140   friend class GlobalValueNumberingTest;
141   friend class LocalValueNumberingTest;
142 };
143 
144 class MirSFieldLoweringInfo : public MirFieldInfo {
145  public:
146   // For each requested static field retrieve the field's declaring location (dex file, class
147   // index and field index) and volatility and compute whether we can fast path the access with
148   // IGET/IPUT. For fast path fields (at least for IGET), retrieve the information needed for
149   // the field access, i.e. the field offset, whether the field is in the same class as the
150   // method being compiled, whether the declaring class can be safely assumed to be initialized
151   // and the type index of the declaring class in the compiled method's dex file.
152   static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit,
153                       MirSFieldLoweringInfo* field_infos, size_t count)
154       LOCKS_EXCLUDED(Locks::mutator_lock_);
155 
156   // Construct an unresolved static field lowering info.
MirSFieldLoweringInfo(uint16_t field_idx)157   explicit MirSFieldLoweringInfo(uint16_t field_idx)
158       : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic),
159         field_offset_(0u),
160         storage_index_(DexFile::kDexNoIndex) {
161   }
162 
FastGet()163   bool FastGet() const {
164     return (flags_ & kFlagFastGet) != 0u;
165   }
166 
FastPut()167   bool FastPut() const {
168     return (flags_ & kFlagFastPut) != 0u;
169   }
170 
IsReferrersClass()171   bool IsReferrersClass() const {
172     return (flags_ & kFlagIsReferrersClass) != 0u;
173   }
174 
IsInitialized()175   bool IsInitialized() const {
176     return (flags_ & kFlagIsInitialized) != 0u;
177   }
178 
FieldOffset()179   MemberOffset FieldOffset() const {
180     return field_offset_;
181   }
182 
StorageIndex()183   uint32_t StorageIndex() const {
184     return storage_index_;
185   }
186 
187  private:
188   enum {
189     kBitFastGet = kFieldInfoBitEnd,
190     kBitFastPut,
191     kBitIsReferrersClass,
192     kBitIsInitialized,
193     kSFieldLoweringInfoBitEnd
194   };
195   COMPILE_ASSERT(kSFieldLoweringInfoBitEnd <= 16, too_many_flags);
196   static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet;
197   static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut;
198   static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass;
199   static constexpr uint16_t kFlagIsInitialized = 1u << kBitIsInitialized;
200 
201   // The member offset of the field, 0u if unresolved.
202   MemberOffset field_offset_;
203   // The type index of the declaring class in the compiling method's dex file,
204   // -1 if the field is unresolved or there's no appropriate TypeId in that dex file.
205   uint32_t storage_index_;
206 
207   friend class ClassInitCheckEliminationTest;
208   friend class GlobalValueNumberingTest;
209   friend class LocalValueNumberingTest;
210 };
211 
212 }  // namespace art
213 
214 #endif  // ART_COMPILER_DEX_MIR_FIELD_INFO_H_
215