blob: b6dc27d26eece6a6efeae153f41111a9a2c8865b [file] [log] [blame]
/*
* 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;
class ScopedObjectAccess;
/*
* 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<DexMemAccessType>((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<uint16_t>(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(const ScopedObjectAccess& soa,
CompilerDriver* compiler_driver,
const DexCompilationUnit* mUnit,
MirIFieldLoweringInfo* field_infos,
size_t count)
SHARED_REQUIRES(Locks::mutator_lock_);
// Construct an unresolved instance field lowering info.
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)
REQUIRES(!Locks::mutator_lock_);
// Construct an unresolved static field lowering info.
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_