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
25namespace art {
26
27class CompilerDriver;
28class 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
37class MirFieldInfo {
38 public:
39  uint16_t FieldIndex() const {
40    return field_idx_;
41  }
42  void SetFieldIndex(uint16_t field_idx) {
43    field_idx_ = field_idx;
44  }
45
46  bool IsStatic() const {
47    return (flags_ & kFlagIsStatic) != 0u;
48  }
49
50  bool IsResolved() const {
51    return declaring_dex_file_ != nullptr;
52  }
53
54  const DexFile* DeclaringDexFile() const {
55    return declaring_dex_file_;
56  }
57  void SetDeclaringDexFile(const DexFile* dex_file) {
58    declaring_dex_file_ = dex_file;
59  }
60
61  uint16_t DeclaringClassIndex() const {
62    return declaring_class_idx_;
63  }
64
65  uint16_t DeclaringFieldIndex() const {
66    return declaring_field_idx_;
67  }
68
69  bool IsVolatile() const {
70    return (flags_ & kFlagIsVolatile) != 0u;
71  }
72
73  // IGET_QUICK, IGET_BYTE_QUICK, ...
74  bool IsQuickened() const {
75    return (flags_ & kFlagIsQuickened) != 0u;
76  }
77
78  DexMemAccessType MemAccessType() const {
79    return static_cast<DexMemAccessType>((flags_ >> kBitMemAccessTypeBegin) & kMemAccessTypeMask);
80  }
81
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
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
131class 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.
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
148  bool FastGet() const {
149    return (flags_ & kFlagFastGet) != 0u;
150  }
151
152  bool FastPut() const {
153    return (flags_ & kFlagFastPut) != 0u;
154  }
155
156  MemberOffset FieldOffset() const {
157    return field_offset_;
158  }
159
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
185class 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.
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
204  bool FastGet() const {
205    return (flags_ & kFlagFastGet) != 0u;
206  }
207
208  bool FastPut() const {
209    return (flags_ & kFlagFastPut) != 0u;
210  }
211
212  bool IsReferrersClass() const {
213    return (flags_ & kFlagIsReferrersClass) != 0u;
214  }
215
216  bool IsClassInitialized() const {
217    return (flags_ & kFlagClassIsInitialized) != 0u;
218  }
219
220  bool IsClassInDexCache() const {
221    return (flags_ & kFlagClassIsInDexCache) != 0u;
222  }
223
224  MemberOffset FieldOffset() const {
225    return field_offset_;
226  }
227
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