summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/nodes.h20
-rw-r--r--compiler/optimizing/reference_type_propagation.cc39
-rw-r--r--compiler/optimizing/reference_type_propagation.h1
-rw-r--r--test/444-checker-nce/src/Main.java24
-rw-r--r--tools/libcore_failures.txt26
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],