# HG changeset patch # User Miguel Garcia # Date 1399317805 -7200 # Node ID fbe9e7088e3500ce54b650c2b1c4516f895ae9c4 # Parent 4f603d776eccfd6528a70b3ebf913e3f4daffa4d# Parent 77eca555014fdb0519d010e6418d5203fca21ad7 Merge diff -r 77eca555014f -r fbe9e7088e35 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java Mon May 05 18:45:03 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java Mon May 05 21:23:25 2014 +0200 @@ -122,7 +122,7 @@ assert !StampTool.isObjectAlwaysNull(subject) : "Null as per stamp subjects should have been handled above"; // --------- checkCast deemed unsatisfiable by subject-stamp alone --------- - if (state.knownNotToConform(subject, toType)) { + if (state.knownNotToPassCheckCast(subject, toType)) { postponedDeopts.addDeoptBefore(checkCast, checkCast.isForStoreCheck() ? ArrayStoreException : ClassCastException); state.impossiblePath(); // let FixedGuardNode(false).simplify() prune the dead-code control-path diff -r 77eca555014f -r fbe9e7088e35 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java Mon May 05 18:45:03 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java Mon May 05 21:23:25 2014 +0200 @@ -237,6 +237,17 @@ // picked cached substitution return result; } + if (FlowUtil.hasLegalObjectStamp(v) && state.isNull(v)) { + // it's ok to return nullConstant in deverbosify unlike in downcast + metricNullInserted.increment(); + return nullConstant; + } + if (v instanceof ValueProxy) { + return v; + } + if (!(n instanceof FloatingNode)) { + return n; + } if ((visited != null && visited.contains(n)) || added.contains(v)) { return v; } @@ -254,30 +265,13 @@ * Past this point, if we ever want `n` to be deverbosified, it must be looked-up by one of * the cases above. One sure way to achieve that is with `rememberSubstitution(old, new)` */ - if (v instanceof ValueProxy) { - return downcast(v); - } - if (n instanceof FloatingNode) { - /* - * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not - * possible anymore it resorts to calling `downcast()`. Thus it's ok to take the - * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be - * missed. - */ - return deverbosifyFloatingNode((FloatingNode) n); - } - - if (FlowUtil.hasLegalObjectStamp(v)) { - if (state.isNull(v)) { - // it's ok to return nullConstant in deverbosify unlike in downcast - metricNullInserted.increment(); - return nullConstant; - } - return downcast(v); - } - - return n; + /* + * `deverbosifyFloatingNode()` will drill down over floating inputs, when that not possible + * anymore it resorts to calling `downcast()`. Thus it's ok to take the + * `deverbosifyFloatingNode()` route first, as no downcasting opportunity will be missed. + */ + return deverbosifyFloatingNode((FloatingNode) n); } /** @@ -341,16 +335,7 @@ } if (changed == null) { assert visited.contains(f) || added.contains(f); - if (FlowUtil.hasLegalObjectStamp(f)) { - /* - * No input has changed doesn't imply there's no witness to refine the - * floating-object value. - */ - ValueNode d = downcast(f); - return d; - } else { - return f; - } + return f; } FlowUtil.inferStampAndCheck(changed); added.add(changed); @@ -474,6 +459,11 @@ if (state.isNull(scrutinee)) { metricInstanceOfRemoved.increment(); return falseConstant; + } else if (state.knownNotToPassInstanceOf(scrutinee, instanceOf.type())) { + // scrutinee turns out to be null -> falseConstant right answer + // scrutinee not null, but known-not-to-conform -> falseConstant + metricInstanceOfRemoved.increment(); + return falseConstant; } else if (state.isNonNull(scrutinee) && state.knownToConform(scrutinee, instanceOf.type())) { metricInstanceOfRemoved.increment(); return trueConstant; @@ -486,21 +476,19 @@ * performed; otherwise the unmodified argument. * */ - private FloatingNode baseCaseIsNullNode(IsNullNode isNull) { - ValueNode object = isNull.object(); + private FloatingNode baseCaseIsNullNode(IsNullNode isNu) { + ValueNode object = isNu.object(); if (!FlowUtil.hasLegalObjectStamp(object)) { - return isNull; + return isNu; } - ValueNode scrutinee = GraphUtil.unproxify(isNull.object()); - GuardingNode evidence = state.nonTrivialNullAnchor(scrutinee); - if (evidence != null) { + if (state.isNull(object)) { metricNullCheckRemoved.increment(); return trueConstant; - } else if (state.isNonNull(scrutinee)) { + } else if (state.isNonNull(object)) { metricNullCheckRemoved.increment(); return falseConstant; } - return isNull; + return isNu; } /** @@ -547,7 +535,7 @@ if (cast != null) { if (state.knownToConform(cast.subject, cast.type)) { return trueConstant; - } else if (state.knownNotToConform(cast.subject, cast.type)) { + } else if (state.knownNotToPassCheckCast(cast.subject, cast.type)) { return falseConstant; } return orNode; diff -r 77eca555014f -r fbe9e7088e35 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Mon May 05 18:45:03 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Mon May 05 21:23:25 2014 +0200 @@ -232,13 +232,8 @@ // `begin` denotes the default case of the TypeSwitchNode return; } - if (state.knownNotToConform(loadHub.object(), type)) { - postponedDeopts.addDeoptAfter(begin, UnreachedCode); - state.impossiblePath(); - return; - } // it's unwarranted to assume loadHub.object() to be non-null - // it also seems unwarranted state.trackCC(loadHub.object(), type, begin); + state.trackCC(loadHub.object(), type, begin); } } @@ -310,9 +305,16 @@ * */ private MethodCallTargetNode deverbosifyInputsCopyOnWrite(MethodCallTargetNode parent) { + final MethodCallTargetNode.InvokeKind ik = parent.invokeKind(); + final boolean shouldTryDevirt = (ik == MethodCallTargetNode.InvokeKind.Interface || ik == MethodCallTargetNode.InvokeKind.Virtual); + boolean shouldDowncastReceiver = shouldTryDevirt; MethodCallTargetNode changed = null; for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) { - Node j = reasoner.deverbosify(i); + ValueNode j = (ValueNode) reasoner.deverbosify(i); + if (shouldDowncastReceiver) { + shouldDowncastReceiver = false; + j = reasoner.downcast(j); + } if (i != j) { assert j != parent; if (changed == null) { diff -r 77eca555014f -r fbe9e7088e35 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java --- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java Mon May 05 18:45:03 2014 +0200 +++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/State.java Mon May 05 21:23:25 2014 +0200 @@ -408,7 +408,8 @@ } /** - * @return true iff the argument is known to stand for an object conforming to the given type. + * @return true iff the argument definitely stands for an object-value that conforms to the + * given type. */ public boolean knownToConform(ValueNode object, ResolvedJavaType to) { assert FlowUtil.hasLegalObjectStamp(object); @@ -430,15 +431,16 @@ } /** - * @return true iff the argument is known to stand for an object that definitely does not - * conform to the given type. + * @return true iff the argument is known to stand for an object that is definitely non-null and + * moreover does not conform to the given type. */ - public boolean knownNotToConform(ValueNode object, ResolvedJavaType to) { + public boolean knownNotToPassCheckCast(ValueNode object, ResolvedJavaType to) { assert FlowUtil.hasLegalObjectStamp(object); assert !to.isPrimitive(); final ValueNode scrutinee = GraphUtil.unproxify(object); if (isNull(scrutinee)) { // known-null means it conforms to whatever `to` + // and thus passes the check-cast return false; } if (!isNonNull(scrutinee)) { @@ -457,6 +459,34 @@ return false; } + /** + * @return true iff the argument is known to stand for an object that definitely does not + * conform to the given type (no matter whether the object turns out to be null or + * non-null). + */ + public boolean knownNotToPassInstanceOf(ValueNode object, ResolvedJavaType to) { + assert FlowUtil.hasLegalObjectStamp(object); + assert !to.isPrimitive(); + final ValueNode scrutinee = GraphUtil.unproxify(object); + if (isNull(scrutinee)) { + return true; + } + ResolvedJavaType stampType = StampTool.typeOrNull(object); + if (stampType != null && knownNotToConform(stampType, to)) { + // object turns out to be null, positive answer is correct + // object turns out non-null, positive answer is also correct + return true; + } + Witness w = typeInfo(scrutinee); + boolean witnessAnswer = w != null && !w.cluelessAboutType() && knownNotToConform(w.type(), to); + if (witnessAnswer) { + // object turns out to be null, positive answer is correct + // object turns out non-null, positive answer is also correct + return true; + } + return false; + } + // @formatter:off /** * \ | | | | @@ -699,7 +729,7 @@ private void addFactInstanceOf(boolean isTrue, InstanceOfNode instanceOf, GuardingNode anchor) { ValueNode object = instanceOf.object(); if (isTrue) { - if (knownNotToConform(object, instanceOf.type())) { + if (knownNotToPassInstanceOf(object, instanceOf.type())) { impossiblePath(); return; }