From: Nicolas Geoffray Date: Thu, 13 Aug 2015 01:28:14 +0000 (-0700) Subject: Small optimization improvements. X-Git-Tag: android-x86-7.1-r1~889^2~573^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=efa8468c78fdd808043dfb664b56541f3f2dd0e8;p=android-x86%2Fart.git Small optimization improvements. - Tune CanBeNull for HBoundType. - Remove LoadClass when we know the class is loaded. - Tune CanBeNull for StringInit. Change-Id: I564ed33a506d65e991a514342bdfd1610bed0cf5 --- diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index 931a1c3cb..df6e550b4 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 dba923324..efb708974 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 d1c113456..1349df9b1 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. diff --git a/test/494-checker-instanceof-tests/src/Main.java b/test/494-checker-instanceof-tests/src/Main.java index bff9c72de..2eac6c92a 100644 --- a/test/494-checker-instanceof-tests/src/Main.java +++ b/test/494-checker-instanceof-tests/src/Main.java @@ -129,6 +129,26 @@ public class Main { return $inline$interfaceTypeTest(finalUnrelatedField); } + // Check that we remove the LoadClass instruction from the graph. + /// CHECK-START: boolean Main.knownTestWithLoadedClass() register (after) + /// CHECK-NOT: LoadClass + public static boolean knownTestWithLoadedClass() { + return new String() instanceof String; + } + + // Check that we do not remove the LoadClass instruction from the graph. + /// CHECK-START: boolean Main.knownTestWithUnloadedClass() register (after) + /// CHECK: <> IntConstant 0 + /// CHECK: LoadClass + /// CHECK: Return [<>] + public static boolean knownTestWithUnloadedClass() { + return $inline$returnMain() instanceof String; + } + + public static Object $inline$returnMain() { + return new Main(); + } + public static void expect(boolean expected, boolean actual) { if (expected != actual) { throw new Error("Unexpected result"); diff --git a/test/495-checker-checkcast-tests/src/Main.java b/test/495-checker-checkcast-tests/src/Main.java index aa6d5a75f..4b2bf09d3 100644 --- a/test/495-checker-checkcast-tests/src/Main.java +++ b/test/495-checker-checkcast-tests/src/Main.java @@ -112,6 +112,33 @@ public class Main { return $inline$interfaceTypeTest(finalUnrelatedField); } + /// CHECK-START: java.lang.String Main.knownTestWithLoadedClass() register (after) + /// CHECK-NOT: LoadClass + public static String knownTestWithLoadedClass() { + return (String)$inline$getString(); + } + + /// CHECK-START: Itf Main.knownTestWithUnloadedClass() register (after) + /// CHECK: LoadClass + public static Itf knownTestWithUnloadedClass() { + return (Itf)$inline$getString(); + } + + public static Object $inline$getString() { + return new String(); + } + + public static Object $inline$getMain() { + return new Main(); + } + + /// CHECK-START: void Main.nonNullBoundType() register (after) + /// CHECK-NOT: NullCheck + public static void nonNullBoundType() { + Main main = (Main)$inline$getMain(); + main.getClass(); + } + public static void main(String[] args) { classTypeTestNull(); try {