summaryrefslogtreecommitdiff
path: root/compiler/optimizing/nodes.h
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/nodes.h')
-rw-r--r--compiler/optimizing/nodes.h229
1 files changed, 97 insertions, 132 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 4a77bed44a..7d6f6164ec 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -171,6 +171,7 @@ class HInstructionList : public ValueObject {
friend class HGraph;
friend class HInstruction;
friend class HInstructionIterator;
+ friend class HInstructionIteratorHandleChanges;
friend class HBackwardInstructionIterator;
DISALLOW_COPY_AND_ASSIGN(HInstructionList);
@@ -330,6 +331,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
invoke_type_(invoke_type),
in_ssa_form_(false),
should_generate_constructor_barrier_(should_generate_constructor_barrier),
+ number_of_cha_guards_(0),
instruction_set_(instruction_set),
cached_null_constant_(nullptr),
cached_int_constants_(std::less<int32_t>(), arena->Adapter(kArenaAllocConstantsMap)),
@@ -551,9 +553,7 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
}
bool HasShouldDeoptimizeFlag() const {
- // TODO: if all CHA guards can be eliminated, there is no need for the flag
- // even if cha_single_implementation_list_ is not empty.
- return !cha_single_implementation_list_.empty();
+ return number_of_cha_guards_ != 0;
}
bool HasTryCatch() const { return has_try_catch_; }
@@ -572,6 +572,10 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
ReferenceTypeInfo GetInexactObjectRti() const { return inexact_object_rti_; }
+ uint32_t GetNumberOfCHAGuards() { return number_of_cha_guards_; }
+ void SetNumberOfCHAGuards(uint32_t num) { number_of_cha_guards_ = num; }
+ void IncrementNumberOfCHAGuards() { number_of_cha_guards_++; }
+
private:
void RemoveInstructionsAsUsersFromDeadBlocks(const ArenaBitVector& visited) const;
void RemoveDeadBlocks(const ArenaBitVector& visited);
@@ -667,6 +671,10 @@ class HGraph : public ArenaObject<kArenaAllocGraph> {
const bool should_generate_constructor_barrier_;
+ // Number of CHA guards in the graph. Used to short-circuit the
+ // CHA guard optimization pass when there is no CHA guard left.
+ uint32_t number_of_cha_guards_;
+
const InstructionSet instruction_set_;
// Cached constants.
@@ -2305,6 +2313,9 @@ class HInstruction : public ArenaObject<kArenaAllocInstruction> {
};
std::ostream& operator<<(std::ostream& os, const HInstruction::InstructionKind& rhs);
+// Iterates over the instructions, while preserving the next instruction
+// in case the current instruction gets removed from the list by the user
+// of this iterator.
class HInstructionIterator : public ValueObject {
public:
explicit HInstructionIterator(const HInstructionList& instructions)
@@ -2326,6 +2337,28 @@ class HInstructionIterator : public ValueObject {
DISALLOW_COPY_AND_ASSIGN(HInstructionIterator);
};
+// Iterates over the instructions without saving the next instruction,
+// therefore handling changes in the graph potentially made by the user
+// of this iterator.
+class HInstructionIteratorHandleChanges : public ValueObject {
+ public:
+ explicit HInstructionIteratorHandleChanges(const HInstructionList& instructions)
+ : instruction_(instructions.first_instruction_) {
+ }
+
+ bool Done() const { return instruction_ == nullptr; }
+ HInstruction* Current() const { return instruction_; }
+ void Advance() {
+ instruction_ = instruction_->GetNext();
+ }
+
+ private:
+ HInstruction* instruction_;
+
+ DISALLOW_COPY_AND_ASSIGN(HInstructionIteratorHandleChanges);
+};
+
+
class HBackwardInstructionIterator : public ValueObject {
public:
explicit HBackwardInstructionIterator(const HInstructionList& instructions)
@@ -2349,6 +2382,11 @@ class HBackwardInstructionIterator : public ValueObject {
class HVariableInputSizeInstruction : public HInstruction {
public:
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE {
+ return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
+ }
+
void AddInput(HInstruction* input);
void InsertInputAt(size_t index, HInstruction* input);
void RemoveInputAt(size_t index);
@@ -2489,11 +2527,6 @@ class HPhi FINAL : public HVariableInputSizeInstruction {
bool IsCatchPhi() const { return GetBlock()->IsCatchBlock(); }
- using HInstruction::GetInputRecords; // Keep the const version visible.
- ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
- return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
- }
-
Primitive::Type GetType() const OVERRIDE { return GetPackedField<TypeField>(); }
void SetType(Primitive::Type new_type) {
// Make sure that only valid type changes occur. The following are allowed:
@@ -2925,14 +2958,20 @@ class HDeoptimize FINAL : public HTemplateInstruction<1> {
// if it's true, starts to do deoptimization.
// It has a 4-byte slot on stack.
// TODO: allocate a register for this flag.
-class HShouldDeoptimizeFlag FINAL : public HExpression<0> {
+class HShouldDeoptimizeFlag FINAL : public HVariableInputSizeInstruction {
public:
- // TODO: use SideEffects to aid eliminating some CHA guards.
- explicit HShouldDeoptimizeFlag(uint32_t dex_pc)
- : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) {
+ // CHA guards are only optimized in a separate pass and it has no side effects
+ // with regard to other passes.
+ HShouldDeoptimizeFlag(ArenaAllocator* arena, uint32_t dex_pc)
+ : HVariableInputSizeInstruction(SideEffects::None(), dex_pc, arena, 0, kArenaAllocCHA) {
}
- // We don't eliminate CHA guards yet.
+ Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimInt; }
+
+ // We do all CHA guard elimination/motion in a single pass, after which there is no
+ // further guard elimination/motion since a guard might have been used for justification
+ // of the elimination of another guard. Therefore, we pretend this guard cannot be moved
+ // to avoid other optimizations trying to move it.
bool CanBeMoved() const OVERRIDE { return false; }
DECLARE_INSTRUCTION(ShouldDeoptimizeFlag);
@@ -3816,11 +3855,6 @@ class HInvoke : public HVariableInputSizeInstruction {
public:
bool NeedsEnvironment() const OVERRIDE;
- using HInstruction::GetInputRecords; // Keep the const version visible.
- ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE {
- return ArrayRef<HUserRecord<HInstruction*>>(inputs_);
- }
-
void SetArgumentAt(size_t index, HInstruction* argument) {
SetRawInputAt(index, argument);
}
@@ -3974,12 +4008,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
// Used for app->boot calls with non-relocatable image and for JIT-compiled calls.
kDirectAddress,
- // Use ArtMethod* at an address that will be known at link time, embed the direct
- // address in the code. If the image is relocatable, emit .patch_oat entry.
- // Used for app->boot calls with relocatable image and boot->boot calls, whether
- // the image relocatable or not.
- kDirectAddressWithFixup,
-
// Load from resolved methods array in the dex cache using a PC-relative load.
// Used when we need to use the dex cache, for example for invoke-static that
// may cause class initialization (the entry may point to a resolution method),
@@ -3998,20 +4026,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
// Recursive call, use local PC-relative call instruction.
kCallSelf,
- // Use PC-relative call instruction patched at link time.
- // Used for calls within an oat file, boot->boot or app->app.
- kCallPCRelative,
-
- // Call to a known target address, embed the direct address in code.
- // Used for app->boot call with non-relocatable image and for JIT-compiled calls.
- kCallDirect,
-
- // Call to a target address that will be known at link time, embed the direct
- // address in code. If the image is relocatable, emit .patch_oat entry.
- // Used for app->boot calls with relocatable image and boot->boot calls, whether
- // the image relocatable or not.
- kCallDirectWithFixup,
-
// Use code pointer from the ArtMethod*.
// Used when we don't know the target code. This is also the last-resort-kind used when
// other kinds are unimplemented or impractical (i.e. slow) on a particular architecture.
@@ -4027,7 +4041,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
// - the method address for kDirectAddress
// - the dex cache arrays offset for kDexCachePcRel.
uint64_t method_load_data;
- uint64_t direct_code_ptr;
};
HInvokeStaticOrDirect(ArenaAllocator* arena,
@@ -4137,7 +4150,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
return false;
}
}
- bool HasDirectCodePtr() const { return GetCodePtrLocation() == CodePtrLocation::kCallDirect; }
QuickEntrypointEnum GetStringInitEntryPoint() const {
DCHECK(IsStringInit());
@@ -4154,11 +4166,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke {
return dispatch_info_.method_load_data;
}
- uint64_t GetDirectCodePtr() const {
- DCHECK(HasDirectCodePtr());
- return dispatch_info_.direct_code_ptr;
- }
-
ClinitCheckRequirement GetClinitCheckRequirement() const {
return GetPackedField<ClinitCheckRequirementField>();
}
@@ -5075,60 +5082,62 @@ class HNullCheck FINAL : public HExpression<1> {
DISALLOW_COPY_AND_ASSIGN(HNullCheck);
};
+// Embeds an ArtField and all the information required by the compiler. We cache
+// that information to avoid requiring the mutator lock every time we need it.
class FieldInfo : public ValueObject {
public:
- FieldInfo(MemberOffset field_offset,
+ FieldInfo(ArtField* field,
+ MemberOffset field_offset,
Primitive::Type field_type,
bool is_volatile,
uint32_t index,
uint16_t declaring_class_def_index,
- const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
- : field_offset_(field_offset),
+ const DexFile& dex_file)
+ : field_(field),
+ field_offset_(field_offset),
field_type_(field_type),
is_volatile_(is_volatile),
index_(index),
declaring_class_def_index_(declaring_class_def_index),
- dex_file_(dex_file),
- dex_cache_(dex_cache) {}
+ dex_file_(dex_file) {}
+ ArtField* GetField() const { return field_; }
MemberOffset GetFieldOffset() const { return field_offset_; }
Primitive::Type GetFieldType() const { return field_type_; }
uint32_t GetFieldIndex() const { return index_; }
uint16_t GetDeclaringClassDefIndex() const { return declaring_class_def_index_;}
const DexFile& GetDexFile() const { return dex_file_; }
bool IsVolatile() const { return is_volatile_; }
- Handle<mirror::DexCache> GetDexCache() const { return dex_cache_; }
private:
+ ArtField* const field_;
const MemberOffset field_offset_;
const Primitive::Type field_type_;
const bool is_volatile_;
const uint32_t index_;
const uint16_t declaring_class_def_index_;
const DexFile& dex_file_;
- const Handle<mirror::DexCache> dex_cache_;
};
class HInstanceFieldGet FINAL : public HExpression<1> {
public:
HInstanceFieldGet(HInstruction* value,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HExpression(field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetRawInputAt(0, value);
}
@@ -5164,22 +5173,22 @@ class HInstanceFieldSet FINAL : public HTemplateInstruction<2> {
public:
HInstanceFieldSet(HInstruction* object,
HInstruction* value,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HTemplateInstruction(SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetPackedFlag<kFlagValueCanBeNull>(true);
SetRawInputAt(0, object);
SetRawInputAt(1, value);
@@ -5537,9 +5546,7 @@ class HLoadClass FINAL : public HInstruction {
const DexFile& dex_file,
bool is_referrers_class,
uint32_t dex_pc,
- bool needs_access_check,
- bool is_in_dex_cache,
- bool is_in_boot_image)
+ bool needs_access_check)
: HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc),
special_input_(HUserRecord<HInstruction*>(current_method)),
type_index_(type_index),
@@ -5552,8 +5559,8 @@ class HLoadClass FINAL : public HInstruction {
SetPackedField<LoadKindField>(
is_referrers_class ? LoadKind::kReferrersClass : LoadKind::kDexCacheViaMethod);
SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check);
- SetPackedFlag<kFlagIsInDexCache>(is_in_dex_cache);
- SetPackedFlag<kFlagIsInBootImage>(is_in_boot_image);
+ SetPackedFlag<kFlagIsInDexCache>(false);
+ SetPackedFlag<kFlagIsInBootImage>(false);
SetPackedFlag<kFlagGenerateClInitCheck>(false);
}
@@ -5782,41 +5789,31 @@ class HLoadString FINAL : public HInstruction {
uint32_t dex_pc)
: HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc),
special_input_(HUserRecord<HInstruction*>(current_method)),
- string_index_(string_index) {
- SetPackedFlag<kFlagIsInDexCache>(false);
+ string_index_(string_index),
+ dex_file_(dex_file) {
SetPackedField<LoadKindField>(LoadKind::kDexCacheViaMethod);
- load_data_.dex_file_ = &dex_file;
}
- void SetLoadKindWithAddress(LoadKind load_kind, uint64_t address) {
- DCHECK(HasAddress(load_kind));
- load_data_.address = address;
- SetLoadKindInternal(load_kind);
- }
-
- void SetLoadKindWithStringReference(LoadKind load_kind,
- const DexFile& dex_file,
- dex::StringIndex string_index) {
- DCHECK(HasStringReference(load_kind));
- load_data_.dex_file_ = &dex_file;
- string_index_ = string_index;
- SetLoadKindInternal(load_kind);
- }
+ void SetLoadKind(LoadKind load_kind);
LoadKind GetLoadKind() const {
return GetPackedField<LoadKindField>();
}
- const DexFile& GetDexFile() const;
+ const DexFile& GetDexFile() const {
+ return dex_file_;
+ }
dex::StringIndex GetStringIndex() const {
- DCHECK(HasStringReference(GetLoadKind()) || /* For slow paths. */ !IsInDexCache());
return string_index_;
}
- uint64_t GetAddress() const {
- DCHECK(HasAddress(GetLoadKind()));
- return load_data_.address;
+ Handle<mirror::String> GetString() const {
+ return string_;
+ }
+
+ void SetString(Handle<mirror::String> str) {
+ string_ = str;
}
bool CanBeMoved() const OVERRIDE { return true; }
@@ -5835,7 +5832,7 @@ class HLoadString FINAL : public HInstruction {
load_kind == LoadKind::kJitTableAddress) {
return false;
}
- return !IsInDexCache();
+ return true;
}
bool NeedsDexCacheOfDeclaringClass() const OVERRIDE {
@@ -5849,15 +5846,6 @@ class HLoadString FINAL : public HInstruction {
return SideEffects::CanTriggerGC();
}
- bool IsInDexCache() const { return GetPackedFlag<kFlagIsInDexCache>(); }
-
- void MarkInDexCache() {
- SetPackedFlag<kFlagIsInDexCache>(true);
- DCHECK(!NeedsEnvironment());
- RemoveEnvironment();
- SetSideEffects(SideEffects::None());
- }
-
void AddSpecialInput(HInstruction* special_input);
using HInstruction::GetInputRecords; // Keep the const version visible.
@@ -5873,26 +5861,13 @@ class HLoadString FINAL : public HInstruction {
DECLARE_INSTRUCTION(LoadString);
private:
- static constexpr size_t kFlagIsInDexCache = kNumberOfGenericPackedBits;
- static constexpr size_t kFieldLoadKind = kFlagIsInDexCache + 1;
+ static constexpr size_t kFieldLoadKind = kNumberOfGenericPackedBits;
static constexpr size_t kFieldLoadKindSize =
MinimumBitsToStore(static_cast<size_t>(LoadKind::kLast));
static constexpr size_t kNumberOfLoadStringPackedBits = kFieldLoadKind + kFieldLoadKindSize;
static_assert(kNumberOfLoadStringPackedBits <= kMaxNumberOfPackedBits, "Too many packed fields.");
using LoadKindField = BitField<LoadKind, kFieldLoadKind, kFieldLoadKindSize>;
- static bool HasStringReference(LoadKind load_kind) {
- return load_kind == LoadKind::kBootImageLinkTimeAddress ||
- load_kind == LoadKind::kBootImageLinkTimePcRelative ||
- load_kind == LoadKind::kBssEntry ||
- load_kind == LoadKind::kDexCacheViaMethod ||
- load_kind == LoadKind::kJitTableAddress;
- }
-
- static bool HasAddress(LoadKind load_kind) {
- return load_kind == LoadKind::kBootImageAddress;
- }
-
void SetLoadKindInternal(LoadKind load_kind);
// The special input is the HCurrentMethod for kDexCacheViaMethod.
@@ -5900,26 +5875,16 @@ class HLoadString FINAL : public HInstruction {
// for PC-relative loads, i.e. kDexCachePcRelative or kBootImageLinkTimePcRelative.
HUserRecord<HInstruction*> special_input_;
- // String index serves also as the hash code and it's also needed for slow-paths,
- // so it must not be overwritten with other load data.
dex::StringIndex string_index_;
+ const DexFile& dex_file_;
- union {
- const DexFile* dex_file_; // For string reference.
- uint64_t address; // Up to 64-bit, needed for kDexCacheAddress on 64-bit targets.
- } load_data_;
+ Handle<mirror::String> string_;
DISALLOW_COPY_AND_ASSIGN(HLoadString);
};
std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs);
// Note: defined outside class to see operator<<(., HLoadString::LoadKind).
-inline const DexFile& HLoadString::GetDexFile() const {
- DCHECK(HasStringReference(GetLoadKind())) << GetLoadKind();
- return *load_data_.dex_file_;
-}
-
-// Note: defined outside class to see operator<<(., HLoadString::LoadKind).
inline void HLoadString::AddSpecialInput(HInstruction* special_input) {
// The special input is used for PC-relative loads on some architectures,
// including literal pool loads, which are PC-relative too.
@@ -5970,22 +5935,22 @@ class HClinitCheck FINAL : public HExpression<1> {
class HStaticFieldGet FINAL : public HExpression<1> {
public:
HStaticFieldGet(HInstruction* cls,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HExpression(field_type, SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetRawInputAt(0, cls);
}
@@ -6018,22 +5983,22 @@ class HStaticFieldSet FINAL : public HTemplateInstruction<2> {
public:
HStaticFieldSet(HInstruction* cls,
HInstruction* value,
+ ArtField* field,
Primitive::Type field_type,
MemberOffset field_offset,
bool is_volatile,
uint32_t field_idx,
uint16_t declaring_class_def_index,
const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache,
uint32_t dex_pc)
: HTemplateInstruction(SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
- field_info_(field_offset,
+ field_info_(field,
+ field_offset,
field_type,
is_volatile,
field_idx,
declaring_class_def_index,
- dex_file,
- dex_cache) {
+ dex_file) {
SetPackedFlag<kFlagValueCanBeNull>(true);
SetRawInputAt(0, cls);
SetRawInputAt(1, value);