Home | History | Annotate | Download | only in dex
      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:
     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 
    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.
    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 
    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.
    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