diff options
author | 2015-05-20 17:52:13 +0100 | |
---|---|---|
committer | 2015-05-29 11:43:04 +0100 | |
commit | 104fd8a3f30ddcf07831250571aa2a233cd5c04d (patch) | |
tree | 7aec8353b7d3906da500595fc81de11ad6f1ad40 /compiler/optimizing | |
parent | 81d804a51d4fc415e1544a5a09505db049f4eda6 (diff) |
Bring Reference Type Propagation to Instance/StaticInstanceField
For this, we need the field index in FieldInfo, hence the add of the field.
Change-Id: Id219bd826d8496acf3981307a8c42e2eb6ddb712
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/builder.cc | 27 | ||||
-rw-r--r-- | compiler/optimizing/gvn_test.cc | 153 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 42 | ||||
-rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 45 | ||||
-rw-r--r-- | compiler/optimizing/reference_type_propagation.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/register_allocator_test.cc | 32 |
6 files changed, 225 insertions, 78 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index c4f033df52..edce9487f8 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -824,13 +824,17 @@ bool HGraphBuilder::BuildInstanceFieldAccess(const Instruction& instruction, value, field_type, resolved_field->GetOffset(), - resolved_field->IsVolatile())); + resolved_field->IsVolatile(), + field_index, + *dex_file_)); } else { current_block_->AddInstruction(new (arena_) HInstanceFieldGet( current_block_->GetLastInstruction(), field_type, resolved_field->GetOffset(), - resolved_field->IsVolatile())); + resolved_field->IsVolatile(), + field_index, + *dex_file_)); UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction()); } @@ -932,13 +936,20 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, temps.Add(cls); HInstruction* value = LoadLocal(source_or_dest_reg, field_type); DCHECK_EQ(value->GetType(), field_type); - current_block_->AddInstruction( - new (arena_) HStaticFieldSet(cls, value, field_type, resolved_field->GetOffset(), - resolved_field->IsVolatile())); + current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls, + value, + field_type, + resolved_field->GetOffset(), + resolved_field->IsVolatile(), + field_index, + *dex_file_)); } else { - current_block_->AddInstruction( - new (arena_) HStaticFieldGet(cls, field_type, resolved_field->GetOffset(), - resolved_field->IsVolatile())); + current_block_->AddInstruction(new (arena_) HStaticFieldGet(cls, + field_type, + resolved_field->GetOffset(), + resolved_field->IsVolatile(), + field_index, + *dex_file_)); UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction()); } return true; diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc index c3ce7e142a..d8a09ffc38 100644 --- a/compiler/optimizing/gvn_test.cc +++ b/compiler/optimizing/gvn_test.cc @@ -40,23 +40,40 @@ TEST(GVNTest, LocalFieldElimination) { graph->AddBlock(block); entry->AddSuccessor(block); - block->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, - MemberOffset(42), false)); - block->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, - MemberOffset(42), false)); + block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); + block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); HInstruction* to_remove = block->GetLastInstruction(); - block->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, - MemberOffset(43), false)); + block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimNot, + MemberOffset(43), + false, + kUnknownFieldIndex, + graph->GetDexFile())); HInstruction* different_offset = block->GetLastInstruction(); // Kill the value. - block->AddInstruction(new (&allocator) HInstanceFieldSet( - parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false)); - block->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimNot, - MemberOffset(42), false)); + block->AddInstruction(new (&allocator) HInstanceFieldSet(parameter, + parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); + block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); HInstruction* use_after_kill = block->GetLastInstruction(); block->AddInstruction(new (&allocator) HExit()); @@ -88,9 +105,12 @@ TEST(GVNTest, GlobalFieldElimination) { HBasicBlock* block = new (&allocator) HBasicBlock(graph); graph->AddBlock(block); entry->AddSuccessor(block); - block->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); block->AddInstruction(new (&allocator) HIf(block->GetLastInstruction())); HBasicBlock* then = new (&allocator) HBasicBlock(graph); @@ -105,17 +125,26 @@ TEST(GVNTest, GlobalFieldElimination) { then->AddSuccessor(join); else_->AddSuccessor(join); - then->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + then->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); then->AddInstruction(new (&allocator) HGoto()); - else_->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + else_->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); else_->AddInstruction(new (&allocator) HGoto()); - join->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + join->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); join->AddInstruction(new (&allocator) HExit()); graph->TryBuildingSsa(); @@ -144,9 +173,12 @@ TEST(GVNTest, LoopFieldElimination) { HBasicBlock* block = new (&allocator) HBasicBlock(graph); graph->AddBlock(block); entry->AddSuccessor(block); - block->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + block->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); block->AddInstruction(new (&allocator) HGoto()); HBasicBlock* loop_header = new (&allocator) HBasicBlock(graph); @@ -161,26 +193,40 @@ TEST(GVNTest, LoopFieldElimination) { loop_header->AddSuccessor(exit); loop_body->AddSuccessor(loop_header); - loop_header->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + loop_header->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); HInstruction* field_get_in_loop_header = loop_header->GetLastInstruction(); loop_header->AddInstruction(new (&allocator) HIf(block->GetLastInstruction())); // Kill inside the loop body to prevent field gets inside the loop header // and the body to be GVN'ed. - loop_body->AddInstruction(new (&allocator) HInstanceFieldSet( - parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false)); + loop_body->AddInstruction(new (&allocator) HInstanceFieldSet(parameter, + parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); HInstruction* field_set = loop_body->GetLastInstruction(); - loop_body->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + loop_body->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); HInstruction* field_get_in_loop_body = loop_body->GetLastInstruction(); loop_body->AddInstruction(new (&allocator) HGoto()); - exit->AddInstruction( - new (&allocator) HInstanceFieldGet(parameter, Primitive::kPrimBoolean, - MemberOffset(42), false)); + exit->AddInstruction(new (&allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); HInstruction* field_get_in_exit = exit->GetLastInstruction(); exit->AddInstruction(new (&allocator) HExit()); @@ -266,8 +312,13 @@ TEST(GVNTest, LoopSideEffects) { // Check that the loops don't have side effects. { // Make one block with a side effect. - entry->AddInstruction(new (&allocator) HInstanceFieldSet( - parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false)); + entry->AddInstruction(new (&allocator) HInstanceFieldSet(parameter, + parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile())); SideEffectsAnalysis side_effects(graph); side_effects.Run(); @@ -280,8 +331,13 @@ TEST(GVNTest, LoopSideEffects) { // Check that the side effects of the outer loop does not affect the inner loop. { outer_loop_body->InsertInstructionBefore( - new (&allocator) HInstanceFieldSet( - parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false), + new (&allocator) HInstanceFieldSet(parameter, + parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile()), outer_loop_body->GetLastInstruction()); SideEffectsAnalysis side_effects(graph); @@ -297,8 +353,13 @@ TEST(GVNTest, LoopSideEffects) { { outer_loop_body->RemoveInstruction(outer_loop_body->GetFirstInstruction()); inner_loop_body->InsertInstructionBefore( - new (&allocator) HInstanceFieldSet( - parameter, parameter, Primitive::kPrimNot, MemberOffset(42), false), + new (&allocator) HInstanceFieldSet(parameter, + parameter, + Primitive::kPrimNot, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile()), inner_loop_body->GetLastInstruction()); SideEffectsAnalysis side_effects(graph); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index a44d745c11..d9d09aafa2 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -60,6 +60,8 @@ static const int kDefaultNumberOfBackEdges = 1; static constexpr uint32_t kMaxIntShiftValue = 0x1f; static constexpr uint64_t kMaxLongShiftValue = 0x3f; +static constexpr uint32_t kUnknownFieldIndex = static_cast<uint32_t>(-1); + static constexpr InvokeType kInvalidInvokeType = static_cast<InvokeType>(-1); enum IfCondition { @@ -3140,17 +3142,29 @@ class HNullCheck : public HExpression<1> { class FieldInfo : public ValueObject { public: - FieldInfo(MemberOffset field_offset, Primitive::Type field_type, bool is_volatile) - : field_offset_(field_offset), field_type_(field_type), is_volatile_(is_volatile) {} + FieldInfo(MemberOffset field_offset, + Primitive::Type field_type, + bool is_volatile, + uint32_t index, + const DexFile& dex_file) + : field_offset_(field_offset), + field_type_(field_type), + is_volatile_(is_volatile), + index_(index), + dex_file_(dex_file) {} MemberOffset GetFieldOffset() const { return field_offset_; } Primitive::Type GetFieldType() const { return field_type_; } + uint32_t GetFieldIndex() const { return index_; } + const DexFile& GetDexFile() const { return dex_file_; } bool IsVolatile() const { return is_volatile_; } private: const MemberOffset field_offset_; const Primitive::Type field_type_; const bool is_volatile_; + uint32_t index_; + const DexFile& dex_file_; }; class HInstanceFieldGet : public HExpression<1> { @@ -3158,9 +3172,11 @@ class HInstanceFieldGet : public HExpression<1> { HInstanceFieldGet(HInstruction* value, Primitive::Type field_type, MemberOffset field_offset, - bool is_volatile) + bool is_volatile, + uint32_t field_idx, + const DexFile& dex_file) : HExpression(field_type, SideEffects::DependsOnSomething()), - field_info_(field_offset, field_type, is_volatile) { + field_info_(field_offset, field_type, is_volatile, field_idx, dex_file) { SetRawInputAt(0, value); } @@ -3198,9 +3214,11 @@ class HInstanceFieldSet : public HTemplateInstruction<2> { HInstruction* value, Primitive::Type field_type, MemberOffset field_offset, - bool is_volatile) + bool is_volatile, + uint32_t field_idx, + const DexFile& dex_file) : HTemplateInstruction(SideEffects::ChangesSomething()), - field_info_(field_offset, field_type, is_volatile), + field_info_(field_offset, field_type, is_volatile, field_idx, dex_file), value_can_be_null_(true) { SetRawInputAt(0, object); SetRawInputAt(1, value); @@ -3591,9 +3609,11 @@ class HStaticFieldGet : public HExpression<1> { HStaticFieldGet(HInstruction* cls, Primitive::Type field_type, MemberOffset field_offset, - bool is_volatile) + bool is_volatile, + uint32_t field_idx, + const DexFile& dex_file) : HExpression(field_type, SideEffects::DependsOnSomething()), - field_info_(field_offset, field_type, is_volatile) { + field_info_(field_offset, field_type, is_volatile, field_idx, dex_file) { SetRawInputAt(0, cls); } @@ -3628,9 +3648,11 @@ class HStaticFieldSet : public HTemplateInstruction<2> { HInstruction* value, Primitive::Type field_type, MemberOffset field_offset, - bool is_volatile) + bool is_volatile, + uint32_t field_idx, + const DexFile& dex_file) : HTemplateInstruction(SideEffects::ChangesSomething()), - field_info_(field_offset, field_type, is_volatile), + field_info_(field_offset, field_type, is_volatile, field_idx, dex_file), value_can_be_null_(true) { SetRawInputAt(0, cls); SetRawInputAt(1, value); diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 91b2e6f9ea..f7d2ed1240 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -35,17 +35,22 @@ void ReferenceTypePropagation::Run() { void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { // TODO: handle other instructions that give type info - // (Call/Field accesses/array accesses) + // (Call/array accesses) // Initialize exact types first for faster convergence. for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { HInstruction* instr = it.Current(); + // TODO: Make ReferenceTypePropagation a visitor or create a new one. if (instr->IsNewInstance()) { VisitNewInstance(instr->AsNewInstance()); } else if (instr->IsLoadClass()) { VisitLoadClass(instr->AsLoadClass()); } else if (instr->IsNewArray()) { VisitNewArray(instr->AsNewArray()); + } else if (instr->IsInstanceFieldGet()) { + VisitInstanceFieldGet(instr->AsInstanceFieldGet()); + } else if (instr->IsStaticFieldGet()) { + VisitStaticFieldGet(instr->AsStaticFieldGet()); } } @@ -161,6 +166,14 @@ void ReferenceTypePropagation::BoundTypeForIfInstanceOf(HBasicBlock* block) { } } +void ReferenceTypePropagation::SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass) { + if (klass != nullptr) { + ScopedObjectAccess soa(Thread::Current()); + MutableHandle<mirror::Class> handle = handles_->NewHandle(klass); + instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, true)); + } +} + void ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr, uint16_t type_idx, const DexFile& dex_file) { @@ -169,11 +182,7 @@ void ReferenceTypePropagation::UpdateReferenceTypeInfo(HInstruction* instr, ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); // Get type from dex cache assuming it was populated by the verifier. - mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); - if (resolved_class != nullptr) { - MutableHandle<mirror::Class> handle = handles_->NewHandle(resolved_class); - instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(handle, true)); - } + SetClassAsTypeInfo(instr, dex_cache->GetResolvedType(type_idx)); } void ReferenceTypePropagation::VisitNewInstance(HNewInstance* instr) { @@ -184,6 +193,30 @@ void ReferenceTypePropagation::VisitNewArray(HNewArray* instr) { UpdateReferenceTypeInfo(instr, instr->GetTypeIndex(), instr->GetDexFile()); } +void ReferenceTypePropagation::UpdateFieldAccessTypeInfo(HInstruction* instr, + const FieldInfo& info) { + // The field index is unknown only during tests. + if (instr->GetType() != Primitive::kPrimNot || info.GetFieldIndex() == kUnknownFieldIndex) { + return; + } + + ScopedObjectAccess soa(Thread::Current()); + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + mirror::DexCache* dex_cache = cl->FindDexCache(info.GetDexFile()); + ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), dex_cache); + DCHECK(field != nullptr); + mirror::Class* klass = field->GetType<false>(); + SetClassAsTypeInfo(instr, klass); +} + +void ReferenceTypePropagation::VisitInstanceFieldGet(HInstanceFieldGet* instr) { + UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo()); +} + +void ReferenceTypePropagation::VisitStaticFieldGet(HStaticFieldGet* instr) { + UpdateFieldAccessTypeInfo(instr, instr->GetFieldInfo()); +} + void ReferenceTypePropagation::VisitLoadClass(HLoadClass* instr) { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index 12c3362b26..74e425fb3e 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -45,6 +45,8 @@ class ReferenceTypePropagation : public HOptimization { void VisitNewArray(HNewArray* instr); void VisitPhi(HPhi* phi); void VisitBasicBlock(HBasicBlock* block); + void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info); + void SetClassAsTypeInfo(HInstruction* instr, mirror::Class* klass); void UpdateBoundType(HBoundType* bound_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void UpdatePhi(HPhi* phi) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -52,6 +54,8 @@ class ReferenceTypePropagation : public HOptimization { void BoundTypeForIfNotNull(HBasicBlock* block); void BoundTypeForIfInstanceOf(HBasicBlock* block); void UpdateReferenceTypeInfo(HInstruction* instr, uint16_t type_idx, const DexFile& dex_file); + void VisitInstanceFieldGet(HInstanceFieldGet* instr); + void VisitStaticFieldGet(HStaticFieldGet* instr); void ProcessWorklist(); void AddToWorklist(HInstruction* instr); diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc index b72ffb8bf7..d07a14a3e6 100644 --- a/compiler/optimizing/register_allocator_test.cc +++ b/compiler/optimizing/register_allocator_test.cc @@ -474,8 +474,12 @@ static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator, graph->AddBlock(block); entry->AddSuccessor(block); - HInstruction* test = new (allocator) HInstanceFieldGet( - parameter, Primitive::kPrimBoolean, MemberOffset(22), false); + HInstruction* test = new (allocator) HInstanceFieldGet(parameter, + Primitive::kPrimBoolean, + MemberOffset(22), + false, + kUnknownFieldIndex, + graph->GetDexFile()); block->AddInstruction(test); block->AddInstruction(new (allocator) HIf(test)); HBasicBlock* then = new (allocator) HBasicBlock(graph); @@ -494,10 +498,18 @@ static HGraph* BuildIfElseWithPhi(ArenaAllocator* allocator, *phi = new (allocator) HPhi(allocator, 0, 0, Primitive::kPrimInt); join->AddPhi(*phi); - *input1 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt, - MemberOffset(42), false); - *input2 = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt, - MemberOffset(42), false); + *input1 = new (allocator) HInstanceFieldGet(parameter, + Primitive::kPrimInt, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile()); +*input2 = new (allocator) HInstanceFieldGet(parameter, + Primitive::kPrimInt, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile()); then->AddInstruction(*input1); else_->AddInstruction(*input2); join->AddInstruction(new (allocator) HExit()); @@ -604,8 +616,12 @@ static HGraph* BuildFieldReturn(ArenaAllocator* allocator, graph->AddBlock(block); entry->AddSuccessor(block); - *field = new (allocator) HInstanceFieldGet(parameter, Primitive::kPrimInt, - MemberOffset(42), false); + *field = new (allocator) HInstanceFieldGet(parameter, + Primitive::kPrimInt, + MemberOffset(42), + false, + kUnknownFieldIndex, + graph->GetDexFile()); block->AddInstruction(*field); *ret = new (allocator) HReturn(*field); block->AddInstruction(*ret); |