# HG changeset patch # User Lukas Stadler # Date 1395226890 -3600 # Node ID 1d853e629891b036c62b6d2bd8e20f0f77fcb11e # Parent aef9e422407699c4a1521935f16184d86cc13519 fixed canonicalization of ArrayEqualsNode, added Virtualizable implementation diff -r aef9e4224076 -r 1d853e629891 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java --- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Wed Mar 19 09:08:22 2014 +0100 +++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Wed Mar 19 12:01:30 2014 +0100 @@ -29,8 +29,12 @@ import com.oracle.graal.api.code.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.phases.*; +import com.oracle.graal.phases.common.*; +import com.oracle.graal.phases.tiers.*; import com.oracle.graal.replacements.*; import com.oracle.graal.replacements.nodes.*; +import com.oracle.graal.virtual.phases.ea.*; /** * Tests {@link ArraysSubstitutions}. @@ -350,4 +354,90 @@ } } + @Test + public void testConstants() { + test("testConstantsSnippet"); + } + + public static final int[] constantArray1 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + public static final int[] constantArray2 = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + + public static boolean testConstantsSnippet() { + constantArray2[0] = 10; + try { + return Arrays.equals(constantArray1, constantArray2); + } finally { + constantArray2[0] = 1; + } + } + + @Test + public void testCanonicalLength() { + StructuredGraph graph = parse("testCanonicalLengthSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0); + } + + public static final int[] constantArray3 = new int[]{1, 2, 3}; + + public static boolean testCanonicalLengthSnippet() { + return Arrays.equals(constantArray1, constantArray3); + } + + @Test + public void testCanonicalEqual() { + StructuredGraph graph = parse("testCanonicalEqualSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1); + } + + public static boolean testCanonicalEqualSnippet() { + return Arrays.equals(constantArray1, constantArray1); + } + + @Test + public void testVirtualEqual() { + StructuredGraph graph = parse("testVirtualEqualSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 1); + } + + public static boolean testVirtualEqualSnippet() { + int[] array1 = new int[]{1, 2, 3, 4}; + int[] array2 = new int[]{1, 2, 3, 4}; + return Arrays.equals(array1, array2); + } + + @Test + public void testVirtualNotEqual() { + StructuredGraph graph = parse("testVirtualNotEqualSnippet"); + Assumptions assumptions = new Assumptions(false); + HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL); + new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context); + new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions)); + + Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asConstant().asLong() == 0); + } + + public static boolean testVirtualNotEqualSnippet(int x) { + int[] array1 = new int[]{1, 2, 100, x}; + int[] array2 = new int[]{1, 2, 3, 4}; + return Arrays.equals(array1, array2); + } } diff -r aef9e4224076 -r 1d853e629891 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Wed Mar 19 09:08:22 2014 +0100 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java Wed Mar 19 12:01:30 2014 +0100 @@ -22,8 +22,6 @@ */ package com.oracle.graal.replacements.nodes; -import java.util.*; - import com.oracle.graal.api.meta.*; import com.oracle.graal.compiler.gen.*; import com.oracle.graal.compiler.target.*; @@ -31,12 +29,14 @@ import com.oracle.graal.graph.spi.*; import com.oracle.graal.lir.*; import com.oracle.graal.nodes.*; +import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; +import com.oracle.graal.nodes.util.*; /** * Compares two arrays with the same length. */ -public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable { +public class ArrayEqualsNode extends FixedWithNextNode implements LIRGenLowerable, Canonicalizable, Virtualizable { /** {@link Kind} of the arrays to compare. */ private final Kind kind; @@ -65,42 +65,45 @@ @Override public Node canonical(CanonicalizerTool tool) { - if (!array1.isConstant() || !array2.isConstant()) { - return this; + if (usages().isEmpty()) { + return null; } + if (GraphUtil.unproxify(array1) == GraphUtil.unproxify(array2)) { + return ConstantNode.forBoolean(true, graph()); + } + return this; + } - Object a1 = array1.asConstant().asObject(); - Object a2 = array2.asConstant().asObject(); - boolean x; - switch (kind) { - case Boolean: - x = Arrays.equals((boolean[]) a1, (boolean[]) a2); - break; - case Byte: - x = Arrays.equals((byte[]) a1, (byte[]) a2); - break; - case Char: - x = Arrays.equals((char[]) a1, (char[]) a2); - break; - case Short: - x = Arrays.equals((short[]) a1, (short[]) a2); - break; - case Int: - x = Arrays.equals((int[]) a1, (int[]) a2); - break; - case Long: - x = Arrays.equals((long[]) a1, (long[]) a2); - break; - case Float: - x = Arrays.equals((float[]) a1, (float[]) a2); - break; - case Double: - x = Arrays.equals((double[]) a1, (double[]) a2); - break; - default: - throw GraalInternalError.shouldNotReachHere("unknown kind " + kind); + public void virtualize(VirtualizerTool tool) { + State state1 = tool.getObjectState(array1); + if (state1 != null) { + State state2 = tool.getObjectState(array2); + if (state2 != null) { + if (state1.getVirtualObject() == state2.getVirtualObject()) { + // the same virtual objects will always have the same contents + tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); + } else if (state1.getVirtualObject().entryCount() == state2.getVirtualObject().entryCount()) { + int entryCount = state1.getVirtualObject().entryCount(); + boolean allEqual = true; + for (int i = 0; i < entryCount; i++) { + ValueNode entry1 = state1.getEntry(i); + ValueNode entry2 = state2.getEntry(i); + if (entry1 != entry2) { + // the contents might be different + allEqual = false; + } + if (entry1.stamp().alwaysDistinct(entry2.stamp())) { + // the contents are different + tool.replaceWithValue(ConstantNode.forBoolean(false, graph())); + return; + } + } + if (allEqual) { + tool.replaceWithValue(ConstantNode.forBoolean(true, graph())); + } + } + } } - return ConstantNode.forBoolean(x, graph()); } @NodeIntrinsic