< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java

Print this page

        

*** 28,37 **** --- 28,39 ---- import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; + import jdk.vm.ci.meta.MetaAccessProvider; + import jdk.vm.ci.meta.ResolvedJavaType; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.CounterKey;
*** 50,60 **** --- 52,65 ---- import org.graalvm.compiler.nodes.calc.IntegerBelowNode; import org.graalvm.compiler.nodes.calc.IntegerEqualsNode; import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; import org.graalvm.compiler.nodes.calc.IsNullNode; import org.graalvm.compiler.nodes.calc.NormalizeCompareNode; + import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; + import org.graalvm.compiler.nodes.extended.UnboxNode; import org.graalvm.compiler.nodes.java.InstanceOfNode; + import org.graalvm.compiler.nodes.java.LoadFieldNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.util.EconomicMap; import org.graalvm.util.Equivalence;
*** 254,263 **** --- 259,385 ---- } return; } } } + + if (tryEliminateBoxedReferenceEquals(tool)) { + return; + } + } + + private boolean isUnboxedFrom(MetaAccessProvider meta, ValueNode x, ValueNode src) { + if (x == src) { + return true; + } else if (x instanceof UnboxNode) { + return isUnboxedFrom(meta, ((UnboxNode) x).getValue(), src); + } else if (x instanceof PiNode) { + PiNode pi = (PiNode) x; + return isUnboxedFrom(meta, pi.getOriginalNode(), src); + } else if (x instanceof LoadFieldNode) { + LoadFieldNode load = (LoadFieldNode) x; + ResolvedJavaType integerType = meta.lookupJavaType(Integer.class); + if (load.getValue().stamp().javaType(meta).equals(integerType)) { + return isUnboxedFrom(meta, load.getValue(), src); + } else { + return false; + } + } else { + return false; + } + } + + /** + * Attempts to replace the following pattern: + * + * <pre> + * Integer x = ...; + * Integer y = ...; + * if ((x == y) || x.equals(y)) { ... } + * </pre> + * + * with: + * + * <pre> + * Integer x = ...; + * Integer y = ...; + * if (x.equals(y)) { ... } + * </pre> + * + * whenever the probability that the reference check will pass is relatively small. + * + * See GR-1315 for more information. + */ + private boolean tryEliminateBoxedReferenceEquals(SimplifierTool tool) { + if (!(condition instanceof ObjectEqualsNode)) { + return false; + } + + MetaAccessProvider meta = tool.getMetaAccess(); + ObjectEqualsNode equalsCondition = (ObjectEqualsNode) condition; + ValueNode x = equalsCondition.getX(); + ValueNode y = equalsCondition.getY(); + ResolvedJavaType integerType = meta.lookupJavaType(Integer.class); + + // At least one argument for reference equal must be a boxed primitive. + if (!x.stamp().javaType(meta).equals(integerType) && !y.stamp().javaType(meta).equals(integerType)) { + return false; + } + + // The reference equality check is usually more efficient compared to a boxing check. + // The success of the reference equals must therefore be relatively rare, otherwise it makes + // no sense to eliminate it. + if (getTrueSuccessorProbability() > 0.4) { + return false; + } + + // True branch must be empty. + if (trueSuccessor instanceof BeginNode || trueSuccessor instanceof LoopExitNode) { + if (trueSuccessor.next() instanceof EndNode) { + // Empty true branch. + } else { + return false; + } + } else { + return false; + } + + // False branch must only check the unboxed values. + UnboxNode unbox = null; + FixedGuardNode unboxCheck = null; + for (FixedNode node : falseSuccessor.getBlockNodes()) { + if (!(node instanceof BeginNode || node instanceof UnboxNode || node instanceof FixedGuardNode || node instanceof EndNode || + node instanceof LoadFieldNode || node instanceof LoopExitNode)) { + return false; + } + if (node instanceof UnboxNode) { + if (unbox == null) { + unbox = (UnboxNode) node; + } else { + return false; + } + } + if (!(node instanceof FixedGuardNode)) { + continue; + } + FixedGuardNode fixed = (FixedGuardNode) node; + if (!(fixed.condition() instanceof IntegerEqualsNode)) { + continue; + } + IntegerEqualsNode equals = (IntegerEqualsNode) fixed.condition(); + if ((isUnboxedFrom(meta, equals.getX(), x) && isUnboxedFrom(meta, equals.getY(), y)) || (isUnboxedFrom(meta, equals.getX(), y) && isUnboxedFrom(meta, equals.getY(), x))) { + unboxCheck = fixed; + } + } + if (unbox == null || unboxCheck == null) { + return false; + } + + // Falsify the reference check. + setCondition(graph().addOrUnique(LogicConstantNode.contradiction())); + + return true; } /** * Try to optimize this as if it were a {@link ConditionalNode}. */
< prev index next >