diff options
| -rw-r--r-- | compiler/optimizing/nodes.h | 20 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.cc | 39 | ||||
| -rw-r--r-- | compiler/optimizing/reference_type_propagation.h | 1 | ||||
| -rw-r--r-- | test/444-checker-nce/src/Main.java | 24 | ||||
| -rw-r--r-- | tools/libcore_failures.txt | 26 |
5 files changed, 105 insertions, 5 deletions
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index de448cc483..7e075644ef 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1039,6 +1039,8 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { virtual bool CanThrow() const { return false; } bool HasSideEffects() const { return side_effects_.HasSideEffects(); } + virtual bool ActAsNullConstant() const { return false; } + // Does not apply for all instructions, but having this at top level greatly // simplifies the null check elimination. virtual bool CanBeNull() const { @@ -1049,10 +1051,14 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { virtual bool CanDoImplicitNullCheck() const { return false; } void SetReferenceTypeInfo(ReferenceTypeInfo reference_type_info) { + DCHECK_EQ(GetType(), Primitive::kPrimNot); reference_type_info_ = reference_type_info; } - ReferenceTypeInfo GetReferenceTypeInfo() const { return reference_type_info_; } + ReferenceTypeInfo GetReferenceTypeInfo() const { + DCHECK_EQ(GetType(), Primitive::kPrimNot); + return reference_type_info_; + } void AddUseAt(HInstruction* user, size_t index) { DCHECK(user != nullptr); @@ -1838,6 +1844,8 @@ class HNullConstant : public HConstant { size_t ComputeHashCode() const OVERRIDE { return 0; } + bool ActAsNullConstant() const OVERRIDE { return true; } + DECLARE_INSTRUCTION(NullConstant); private: @@ -1852,11 +1860,16 @@ class HIntConstant : public HConstant { int32_t GetValue() const { return value_; } - virtual bool InstructionDataEquals(HInstruction* other) const { + bool InstructionDataEquals(HInstruction* other) const OVERRIDE { return other->AsIntConstant()->value_ == value_; } - virtual size_t ComputeHashCode() const { return GetValue(); } + size_t ComputeHashCode() const OVERRIDE { return GetValue(); } + + // TODO: Null is represented by the `0` constant. In most cases we replace it + // with a HNullConstant but we don't do it when comparing (a != null). This + // method is an workaround until we fix the above. + bool ActAsNullConstant() const OVERRIDE { return value_ == 0; } DECLARE_INSTRUCTION(IntConstant); @@ -3063,6 +3076,7 @@ class HBoundType : public HExpression<1> { HBoundType(HInstruction* input, ReferenceTypeInfo bound_type) : HExpression(Primitive::kPrimNot, SideEffects::None()), bound_type_(bound_type) { + DCHECK_EQ(input->GetType(), Primitive::kPrimNot); SetRawInputAt(0, input); } diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 76b8d7eacf..479b87fea0 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -23,8 +23,6 @@ namespace art { -// TODO: handle: a !=/== null. - void ReferenceTypePropagation::Run() { // To properly propagate type info we need to visit in the dominator-based order. // Reverse post order guarantees a node's dominators are visited first. @@ -55,9 +53,46 @@ void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) { } // Add extra nodes to bound types. + BoundTypeForIfNotNull(block); BoundTypeForIfInstanceOf(block); } +void ReferenceTypePropagation::BoundTypeForIfNotNull(HBasicBlock* block) { + HInstruction* lastInstruction = block->GetLastInstruction(); + if (!lastInstruction->IsIf()) { + return; + } + HInstruction* ifInput = lastInstruction->InputAt(0); + if (!ifInput->IsNotEqual() && !ifInput->IsEqual()) { + return; + } + HInstruction* input0 = ifInput->InputAt(0); + HInstruction* input1 = ifInput->InputAt(1); + HInstruction* obj; + + if ((input0->GetType() == Primitive::kPrimNot) && input1->ActAsNullConstant()) { + obj = input0; + } else if ((input1->GetType() == Primitive::kPrimNot) && input0->ActAsNullConstant()) { + obj = input1; + } else { + return; + } + + HBoundType* bound_type = + new (graph_->GetArena()) HBoundType(obj, ReferenceTypeInfo::CreateTop(false)); + + block->InsertInstructionBefore(bound_type, lastInstruction); + HBasicBlock* notNullBlock = ifInput->IsNotEqual() + ? lastInstruction->AsIf()->IfTrueSuccessor() + : lastInstruction->AsIf()->IfFalseSuccessor(); + for (HUseIterator<HInstruction*> it(obj->GetUses()); !it.Done(); it.Advance()) { + HInstruction* user = it.Current()->GetUser(); + if (notNullBlock->Dominates(user->GetBlock())) { + user->ReplaceInput(bound_type, it.Current()->GetIndex()); + } + } +} + // Detects if `block` is the True block for the pattern // `if (x instanceof ClassX) { }` // If that's the case insert an HBoundType instruction to bound the type of `x` diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h index e346dbfc6c..815caab4f3 100644 --- a/compiler/optimizing/reference_type_propagation.h +++ b/compiler/optimizing/reference_type_propagation.h @@ -51,6 +51,7 @@ class ReferenceTypePropagation : public HOptimization { void UpdateBoundType(HBoundType* bound_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void UpdatePhi(HPhi* phi) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + void BoundTypeForIfNotNull(HBasicBlock* block); void BoundTypeForIfInstanceOf(HBasicBlock* block); void ProcessWorklist(); diff --git a/test/444-checker-nce/src/Main.java b/test/444-checker-nce/src/Main.java index 9fb9c4668b..656c7916fd 100644 --- a/test/444-checker-nce/src/Main.java +++ b/test/444-checker-nce/src/Main.java @@ -214,6 +214,30 @@ public class Main { return m; } + // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (before) + // CHECK: NullCheck + + // CHECK-START: Main Main.scopeIfNotNullRemove(Main) instruction_simplifier_after_types (after) + // CHECK-NOT: NullCheck + public Main scopeIfNotNullRemove(Main m) { + if (m != null) { + return m.g(); + } + return m; + } + + // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (before) + // CHECK: NullCheck + + // CHECK-START: Main Main.scopeIfKeep(Main) instruction_simplifier_after_types (after) + // CHECK: NullCheck + public Main scopeIfKeep(Main m) { + if (m == null) { + m = new Main(); + } + return m.g(); + } + public Main() {} public Main(int dummy) {} diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index d74a0cc4cb..a09d86f306 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -45,6 +45,32 @@ "org.apache.harmony.tests.java.text.MessageFormatTest#test19011159"] }, { + description: "Failing due to a locale problem on hammerhead.", + result: EXEC_FAILED, + modes: [device], + names: ["libcore.icu.DateIntervalFormatTest#test10089890", + "libcore.icu.DateIntervalFormatTest#test10209343_when_not_this_year", + "libcore.icu.DateIntervalFormatTest#test10560853_for_single_day_events", + "libcore.icu.DateIntervalFormatTest#test10560853_when_time_not_displayed", + "libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeDateTimeString", + "libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanString", + "libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeTimeSpanStringAbbrev", + "libcore.java.text.OldDateFormatTest#test_parseLString", + "libcore.java.text.SimpleDateFormatTest#testDstZoneNameWithNonDstTimestamp", + "libcore.java.text.SimpleDateFormatTest#testDstZoneWithNonDstTimestampForNonHourDstZone", + "libcore.java.text.SimpleDateFormatTest#testNonDstZoneNameWithDstTimestamp", + "libcore.java.text.SimpleDateFormatTest#testNonDstZoneWithDstTimestampForNonHourDstZone", + "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parseLjava_lang_StringLjava_text_ParsePosition"] +}, +{ + description: "Failing due to switched off network stack on volantisg.", + result: EXEC_FAILED, + modes: [device], + names: ["org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest", + "org.apache.harmony.luni.tests.internal.net.www.protocol.https.HttpsURLConnectionTest", + "org.apache.harmony.luni.tests.java.net.URLConnectionTest"] +}, +{ description: "Test timeouts", result: EXEC_TIMEOUT, modes: [device], |