diff options
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 18 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 4 | ||||
-rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 7 |
3 files changed, 27 insertions, 2 deletions
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 931a1c3cb7..df6e550b4a 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -238,12 +238,19 @@ void InstructionSimplifierVisitor::VisitCheckCast(HCheckCast* check_cast) { } bool outcome; - if (TypeCheckHasKnownOutcome(check_cast->InputAt(1)->AsLoadClass(), object, &outcome)) { + HLoadClass* load_class = check_cast->InputAt(1)->AsLoadClass(); + if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) { if (outcome) { check_cast->GetBlock()->RemoveInstruction(check_cast); if (stats_ != nullptr) { stats_->RecordStat(MethodCompilationStat::kRemovedCheckedCast); } + if (!load_class->HasUses()) { + // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw. + // However, here we know that it cannot because the checkcast was successfull, hence + // the class was already loaded. + load_class->GetBlock()->RemoveInstruction(load_class); + } } else { // Don't do anything for exceptional cases for now. Ideally we should remove // all instructions and blocks this instruction dominates. @@ -268,7 +275,8 @@ void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) { } bool outcome; - if (TypeCheckHasKnownOutcome(instruction->InputAt(1)->AsLoadClass(), object, &outcome)) { + HLoadClass* load_class = instruction->InputAt(1)->AsLoadClass(); + if (TypeCheckHasKnownOutcome(load_class, object, &outcome)) { if (outcome && can_be_null) { // Type test will succeed, we just need a null test. HNotEqual* test = new (graph->GetArena()) HNotEqual(graph->GetNullConstant(), object); @@ -280,6 +288,12 @@ void InstructionSimplifierVisitor::VisitInstanceOf(HInstanceOf* instruction) { } RecordSimplification(); instruction->GetBlock()->RemoveInstruction(instruction); + if (outcome && !load_class->HasUses()) { + // We cannot rely on DCE to remove the class because the `HLoadClass` thinks it can throw. + // However, here we know that it cannot because the instanceof check was successfull, hence + // the class was already loaded. + load_class->GetBlock()->RemoveInstruction(load_class); + } } } diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index dba9233240..efb708974d 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -3023,6 +3023,10 @@ class HInvokeStaticOrDirect : public HInvoke { return false; } + bool CanBeNull() const OVERRIDE { + return return_type_ == Primitive::kPrimNot && !IsStringInit(); + } + InvokeType GetInvokeType() const { return invoke_type_; } bool IsRecursive() const { return is_recursive_; } bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); } diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index d1c1134565..1349df9b16 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -167,6 +167,9 @@ static HBoundType* CreateBoundType(ArenaAllocator* arena, bound_type->SetReferenceTypeInfo( ReferenceTypeInfo::Create(class_rti.GetTypeHandle(), /* is_exact */ false)); } + if (upper_can_be_null) { + bound_type->SetCanBeNull(obj->CanBeNull()); + } return bound_type; } @@ -485,6 +488,10 @@ void RTPVisitor::VisitCheckCast(HCheckCast* check_cast) { true /* CheckCast succeeds for nulls. */); check_cast->GetBlock()->InsertInstructionAfter(bound_type, check_cast); } else { + // Update nullability of the existing bound type, which may not have known + // that its input was not null when it was being created. + bound_type = check_cast->GetNext()->AsBoundType(); + bound_type->SetCanBeNull(obj->CanBeNull()); // We already have a bound type on the position we would need to insert // the new one. The existing bound type should dominate all the users // (dchecked) so there's no need to continue. |