/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_DEX_MIR_FIELD_INFO_H_ #define ART_COMPILER_DEX_MIR_FIELD_INFO_H_ #include "base/macros.h" #include "dex_file.h" #include "dex_instruction_utils.h" #include "offsets.h" namespace art { class CompilerDriver; class DexCompilationUnit; /* * Field info is calculated from the perspective of the compilation unit that accesses * the field and stored in that unit's MIRGraph. Therefore it does not need to reference the * dex file or method for which it has been calculated. However, we do store the declaring * field index, class index and dex file of the resolved field to help distinguish between fields. */ class MirFieldInfo { public: uint16_t FieldIndex() const { return field_idx_; } void SetFieldIndex(uint16_t field_idx) { field_idx_ = field_idx; } bool IsStatic() const { return (flags_ & kFlagIsStatic) != 0u; } bool IsResolved() const { return declaring_dex_file_ != nullptr; } const DexFile* DeclaringDexFile() const { return declaring_dex_file_; } void SetDeclaringDexFile(const DexFile* dex_file) { declaring_dex_file_ = dex_file; } uint16_t DeclaringClassIndex() const { return declaring_class_idx_; } uint16_t DeclaringFieldIndex() const { return declaring_field_idx_; } bool IsVolatile() const { return (flags_ & kFlagIsVolatile) != 0u; } // IGET_QUICK, IGET_BYTE_QUICK, ... bool IsQuickened() const { return (flags_ & kFlagIsQuickened) != 0u; } DexMemAccessType MemAccessType() const { return static_cast((flags_ >> kBitMemAccessTypeBegin) & kMemAccessTypeMask); } void CheckEquals(const MirFieldInfo& other) const { CHECK_EQ(field_idx_, other.field_idx_); CHECK_EQ(flags_, other.flags_); CHECK_EQ(declaring_field_idx_, other.declaring_field_idx_); CHECK_EQ(declaring_class_idx_, other.declaring_class_idx_); CHECK_EQ(declaring_dex_file_, other.declaring_dex_file_); } protected: enum { kBitIsStatic = 0, kBitIsVolatile, kBitIsQuickened, kBitMemAccessTypeBegin, kBitMemAccessTypeEnd = kBitMemAccessTypeBegin + 3, // 3 bits for raw type. kFieldInfoBitEnd = kBitMemAccessTypeEnd }; static constexpr uint16_t kFlagIsVolatile = 1u << kBitIsVolatile; static constexpr uint16_t kFlagIsStatic = 1u << kBitIsStatic; static constexpr uint16_t kFlagIsQuickened = 1u << kBitIsQuickened; static constexpr uint16_t kMemAccessTypeMask = 7u; static_assert((1u << (kBitMemAccessTypeEnd - kBitMemAccessTypeBegin)) - 1u == kMemAccessTypeMask, "Invalid raw type mask"); MirFieldInfo(uint16_t field_idx, uint16_t flags, DexMemAccessType type) : field_idx_(field_idx), flags_(flags | static_cast(type) << kBitMemAccessTypeBegin), declaring_field_idx_(0u), declaring_class_idx_(0u), declaring_dex_file_(nullptr) { } // Make copy-ctor/assign/dtor protected to avoid slicing. MirFieldInfo(const MirFieldInfo& other) = default; MirFieldInfo& operator=(const MirFieldInfo& other) = default; ~MirFieldInfo() = default; // The field index in the compiling method's dex file. uint16_t field_idx_; // Flags, for volatility and derived class data. uint16_t flags_; // The field index in the dex file that defines field, 0 if unresolved. uint16_t declaring_field_idx_; // The type index of the class declaring the field, 0 if unresolved. uint16_t declaring_class_idx_; // The dex file that defines the class containing the field and the field, null if unresolved. const DexFile* declaring_dex_file_; }; class MirIFieldLoweringInfo : public MirFieldInfo { public: // For each requested instance field retrieve the field's declaring location (dex file, class // index and field index) and volatility and compute whether we can fast path the access // with IGET/IPUT. For fast path fields, retrieve the field offset. static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit, MirIFieldLoweringInfo* field_infos, size_t count) LOCKS_EXCLUDED(Locks::mutator_lock_); // Construct an unresolved instance field lowering info. explicit MirIFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type, bool is_quickened) : MirFieldInfo(field_idx, kFlagIsVolatile | (is_quickened ? kFlagIsQuickened : 0u), type), // Without kFlagIsStatic. field_offset_(0u) { } bool FastGet() const { return (flags_ & kFlagFastGet) != 0u; } bool FastPut() const { return (flags_ & kFlagFastPut) != 0u; } MemberOffset FieldOffset() const { return field_offset_; } void CheckEquals(const MirIFieldLoweringInfo& other) const { MirFieldInfo::CheckEquals(other); CHECK_EQ(field_offset_.Uint32Value(), other.field_offset_.Uint32Value()); } private: enum { kBitFastGet = kFieldInfoBitEnd, kBitFastPut, kIFieldLoweringInfoBitEnd }; static_assert(kIFieldLoweringInfoBitEnd <= 16, "Too many flags"); static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet; static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut; // The member offset of the field, 0u if unresolved. MemberOffset field_offset_; friend class NullCheckEliminationTest; friend class GlobalValueNumberingTest; friend class GvnDeadCodeEliminationTest; friend class LocalValueNumberingTest; friend class TypeInferenceTest; }; class MirSFieldLoweringInfo : public MirFieldInfo { public: // For each requested static field retrieve the field's declaring location (dex file, class // index and field index) and volatility and compute whether we can fast path the access with // IGET/IPUT. For fast path fields (at least for IGET), retrieve the information needed for // the field access, i.e. the field offset, whether the field is in the same class as the // method being compiled, whether the declaring class can be safely assumed to be initialized // and the type index of the declaring class in the compiled method's dex file. static void Resolve(CompilerDriver* compiler_driver, const DexCompilationUnit* mUnit, MirSFieldLoweringInfo* field_infos, size_t count) LOCKS_EXCLUDED(Locks::mutator_lock_); // Construct an unresolved static field lowering info. explicit MirSFieldLoweringInfo(uint16_t field_idx, DexMemAccessType type) : MirFieldInfo(field_idx, kFlagIsVolatile | kFlagIsStatic, type), field_offset_(0u), storage_index_(DexFile::kDexNoIndex) { } bool FastGet() const { return (flags_ & kFlagFastGet) != 0u; } bool FastPut() const { return (flags_ & kFlagFastPut) != 0u; } bool IsReferrersClass() const { return (flags_ & kFlagIsReferrersClass) != 0u; } bool IsClassInitialized() const { return (flags_ & kFlagClassIsInitialized) != 0u; } bool IsClassInDexCache() const { return (flags_ & kFlagClassIsInDexCache) != 0u; } MemberOffset FieldOffset() const { return field_offset_; } uint32_t StorageIndex() const { return storage_index_; } private: enum { kBitFastGet = kFieldInfoBitEnd, kBitFastPut, kBitIsReferrersClass, kBitClassIsInitialized, kBitClassIsInDexCache, kSFieldLoweringInfoBitEnd }; static_assert(kSFieldLoweringInfoBitEnd <= 16, "Too many flags"); static constexpr uint16_t kFlagFastGet = 1u << kBitFastGet; static constexpr uint16_t kFlagFastPut = 1u << kBitFastPut; static constexpr uint16_t kFlagIsReferrersClass = 1u << kBitIsReferrersClass; static constexpr uint16_t kFlagClassIsInitialized = 1u << kBitClassIsInitialized; static constexpr uint16_t kFlagClassIsInDexCache = 1u << kBitClassIsInDexCache; // The member offset of the field, 0u if unresolved. MemberOffset field_offset_; // The type index of the declaring class in the compiling method's dex file, // -1 if the field is unresolved or there's no appropriate TypeId in that dex file. uint32_t storage_index_; friend class ClassInitCheckEliminationTest; friend class GlobalValueNumberingTest; friend class GvnDeadCodeEliminationTest; friend class LocalValueNumberingTest; friend class TypeInferenceTest; }; } // namespace art #endif // ART_COMPILER_DEX_MIR_FIELD_INFO_H_