# HG changeset patch # User Doug Simon # Date 1427983735 -7200 # Node ID 6fbf1c53feeb245d2524441dd35843f83aa7d2ae # Parent bf4526ed41bd0b44c1cf0041a0de39325c3ba9d1# Parent 7ad60a16bbb0007059679390a3f0eff38a33551a Merge. diff -r bf4526ed41bd -r 6fbf1c53feeb graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java Thu Apr 02 16:08:26 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java Thu Apr 02 16:08:55 2015 +0200 @@ -22,23 +22,225 @@ */ package com.oracle.graal.compiler.test.ea; +import java.util.*; + import org.junit.*; +import com.oracle.graal.compiler.test.*; +import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; -public class EarlyReadEliminationTest extends PEAReadEliminationTest { +public class EarlyReadEliminationTest extends GraalCompilerTest { + + protected StructuredGraph graph; + + public static Object staticField; + + public static class TestObject { + + public int x; + public int y; + + public TestObject(int x, int y) { + this.x = x; + this.y = y; + } + } + + public static class TestObject2 { + + public Object x; + public Object y; + + public TestObject2(Object x, Object y) { + this.x = x; + this.y = y; + } + } + + public static class TestObject3 extends TestObject { + + public int z; + + public TestObject3(int x, int y, int z) { + super(x, y); + this.z = z; + } + } + + @SuppressWarnings("all") + public static int testSimpleSnippet(TestObject a) { + a.x = 2; + staticField = a; + return a.x; + } + + @Test + public void testSimple() { + ValueNode result = getReturn("testSimpleSnippet").result(); + assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); + assertTrue(result.isConstant()); + assertDeepEquals(2, result.asJavaConstant().asInt()); + } + + @SuppressWarnings("all") + public static int testSimpleConflictSnippet(TestObject a, TestObject b) { + a.x = 2; + b.x = 3; + staticField = a; + return a.x; + } + + @Test + public void testSimpleConflict() { + ValueNode result = getReturn("testSimpleConflictSnippet").result(); + assertFalse(result.isConstant()); + assertTrue(result instanceof LoadFieldNode); + } + + @SuppressWarnings("all") + public static int testParamSnippet(TestObject a, int b) { + a.x = b; + return a.x; + } + + @Test + public void testParam() { + ValueNode result = getReturn("testParamSnippet").result(); + assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); + assertDeepEquals(graph.getParameter(1), result); + } + + @SuppressWarnings("all") + public static int testMaterializedSnippet(int a) { + TestObject obj = new TestObject(a, 0); + staticField = obj; + return obj.x; + } @Test - public void dummy() { - // dummy test to make the harness recognize this class as a JUnit test + public void testMaterialized() { + ValueNode result = getReturn("testMaterializedSnippet").result(); + assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); + assertDeepEquals(graph.getParameter(0), result); + } + + @SuppressWarnings("all") + public static int testSimpleLoopSnippet(TestObject obj, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + } + return obj.x; + } + + @Test + public void testSimpleLoop() { + ValueNode result = getReturn("testSimpleLoopSnippet").result(); + assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); + assertDeepEquals(graph.getParameter(1), result); + } + + @SuppressWarnings("all") + public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + staticField = obj; + obj2.x = 10; + obj.x = 0; + } + return obj.x; + } + + @Test + public void testBadLoop() { + ValueNode result = getReturn("testBadLoopSnippet").result(); + assertDeepEquals(0, graph.getNodes().filter(LoadFieldNode.class).count()); + assertTrue(result instanceof ProxyNode); + assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode); + } + + @SuppressWarnings("all") + public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) { + obj.x = a; + for (int i = 0; i < 10; i++) { + obj.x = 0; + obj2.x = 10; + } + return obj.x; + } + + @Test + public void testBadLoop2() { + ValueNode result = getReturn("testBadLoop2Snippet").result(); + assertDeepEquals(1, graph.getNodes().filter(LoadFieldNode.class).count()); + assertTrue(result instanceof LoadFieldNode); } - @Override - protected void processMethod(final String snippet) { + @SuppressWarnings("all") + public static int testPhiSnippet(TestObject a, int b) { + if (b < 0) { + a.x = 1; + } else { + a.x = 2; + } + return a.x; + } + + @Test + public void testPhi() { + processMethod("testPhiSnippet"); + assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); + List returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot(); + assertDeepEquals(2, returnNodes.size()); + assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode); + assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode); + assertTrue(returnNodes.get(0).result().isConstant()); + assertTrue(returnNodes.get(1).result().isConstant()); + } + + @SuppressWarnings("all") + public static void testSimpleStoreSnippet(TestObject a, int b) { + a.x = b; + a.x = b; + } + + @Test + public void testSimpleStore() { + processMethod("testSimpleStoreSnippet"); + assertDeepEquals(1, graph.getNodes().filter(StoreFieldNode.class).count()); + } + + public static int testValueProxySnippet(boolean b, TestObject o) { + int sum = 0; + if (b) { + sum += o.x; + } else { + TestObject3 p = (TestObject3) o; + sum += p.x; + } + sum += o.x; + return sum; + } + + @Test + public void testValueProxy() { + processMethod("testValueProxySnippet"); + assertDeepEquals(2, graph.getNodes().filter(LoadFieldNode.class).count()); + } + + ReturnNode getReturn(String snippet) { + processMethod(snippet); + assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); + return graph.getNodes(ReturnNode.TYPE).first(); + } + + protected void processMethod(String snippet) { graph = parseEager(getResolvedJavaMethod(snippet), AllowAssumptions.NO); HighTierContext context = getDefaultHighTierContext(); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); diff -r bf4526ed41bd -r 6fbf1c53feeb graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java --- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Thu Apr 02 16:08:26 2015 +0200 +++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Thu Apr 02 16:08:55 2015 +0200 @@ -22,224 +22,176 @@ */ package com.oracle.graal.compiler.test.ea; -import java.util.*; - import org.junit.*; -import com.oracle.graal.compiler.test.*; -import com.oracle.graal.nodes.*; +import sun.misc.*; + +import com.oracle.graal.compiler.common.*; import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions; +import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; import com.oracle.graal.phases.common.*; import com.oracle.graal.phases.common.inlining.*; import com.oracle.graal.phases.tiers.*; import com.oracle.graal.virtual.phases.ea.*; -public class PEAReadEliminationTest extends GraalCompilerTest { - - protected StructuredGraph graph; - - public static Object staticField; - - public static class TestObject { +public class PEAReadEliminationTest extends EarlyReadEliminationTest { - public int x; - public int y; - - public TestObject(int x, int y) { - this.x = x; - this.y = y; - } + public static int testIndexed1Snippet(int[] array) { + array[1] = 1; + array[2] = 2; + array[3] = 3; + array[4] = 4; + array[5] = 5; + array[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6]; } - public static class TestObject2 { - - public Object x; - public Object y; - - public TestObject2(Object x, Object y) { - this.x = x; - this.y = y; - } + @Test + public void testIndexed1() { + processMethod("testIndexed1Snippet"); + assertDeepEquals(0, graph.getNodes().filter(LoadIndexedNode.class).count()); } - public static class TestObject3 extends TestObject { - - public int z; - - public TestObject3(int x, int y, int z) { - super(x, y); - this.z = z; - } - } - - @SuppressWarnings("all") - public static int testSimpleSnippet(TestObject a) { - a.x = 2; - staticField = a; - return a.x; + public static int testIndexed2Snippet(int v, int[] array) { + array[1] = 1; + array[2] = 2; + array[3] = 3; + array[v] = 0; + array[4] = 4; + array[5] = 5; + array[6] = 6; + array[4] = 4; + array[5] = 5; + array[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6]; } @Test - public void testSimple() { - ValueNode result = getReturn("testSimpleSnippet").result(); - assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); - assertTrue(result.isConstant()); - assertDeepEquals(2, result.asJavaConstant().asInt()); + public void testIndexed2() { + processMethod("testIndexed2Snippet"); + assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); + assertDeepEquals(7, graph.getNodes().filter(StoreIndexedNode.class).count()); } - @SuppressWarnings("all") - public static int testSimpleConflictSnippet(TestObject a, TestObject b) { - a.x = 2; - b.x = 3; - staticField = a; - return a.x; + public static int testIndexed3Snippet(int v, int[] array, short[] array2) { + array[1] = 1; + array2[1] = 1; + array[2] = 2; + array2[2] = 2; + array[3] = 3; + array2[3] = 3; + array[v] = 0; + array[4] = 4; + array2[4] = 4; + array[5] = 5; + array2[5] = 5; + array[6] = 6; + array2[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6] + array2[1] + array2[2] + array2[3] + array2[4] + array2[5] + array2[6]; } @Test - public void testSimpleConflict() { - ValueNode result = getReturn("testSimpleConflictSnippet").result(); - assertFalse(result.isConstant()); - assertTrue(result instanceof LoadFieldNode); - } - - @SuppressWarnings("all") - public static int testParamSnippet(TestObject a, int b) { - a.x = b; - return a.x; + public void testIndexed3() { + processMethod("testIndexed3Snippet"); + assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); } - @Test - public void testParam() { - ValueNode result = getReturn("testParamSnippet").result(); - assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); - assertDeepEquals(graph.getParameter(1), result); - } + private static native void nonInlineable(); - @SuppressWarnings("all") - public static int testMaterializedSnippet(int a) { - TestObject obj = new TestObject(a, 0); - staticField = obj; - return obj.x; + public static int testIndexed4Snippet(int[] array) { + array[1] = 1; + array[2] = 2; + array[3] = 3; + nonInlineable(); + array[4] = 4; + array[5] = 5; + array[6] = 6; + return array[1] + array[2] + array[3] + array[4] + array[5] + array[6]; } @Test - public void testMaterialized() { - ValueNode result = getReturn("testMaterializedSnippet").result(); - assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); - assertDeepEquals(graph.getParameter(0), result); + public void testIndexed4() { + processMethod("testIndexed4Snippet"); + assertDeepEquals(3, graph.getNodes().filter(LoadIndexedNode.class).count()); } - @SuppressWarnings("all") - public static int testSimpleLoopSnippet(TestObject obj, int a, int b) { - obj.x = a; - for (int i = 0; i < 10; i++) { - staticField = obj; - } - return obj.x; + private static final long offsetInt1 = Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * 1; + private static final long offsetInt2 = Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * 2; + + public static int testUnsafe1Snippet(int v, int[] array) { + int s = UnsafeAccess.unsafe.getInt(array, offsetInt1); + UnsafeAccess.unsafe.putInt(array, offsetInt1, v); + UnsafeAccess.unsafe.putInt(array, offsetInt2, v); + return s + UnsafeAccess.unsafe.getInt(array, offsetInt1) + UnsafeAccess.unsafe.getInt(array, offsetInt2); } @Test - public void testSimpleLoop() { - ValueNode result = getReturn("testSimpleLoopSnippet").result(); - assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); - assertDeepEquals(graph.getParameter(1), result); - } - - @SuppressWarnings("all") - public static int testBadLoopSnippet(TestObject obj, TestObject obj2, int a, int b) { - obj.x = a; - for (int i = 0; i < 10; i++) { - staticField = obj; - obj2.x = 10; - obj.x = 0; - } - return obj.x; + public void testUnsafe1() { + processMethod("testUnsafe1Snippet"); + assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count()); } - @Test - public void testBadLoop() { - ValueNode result = getReturn("testBadLoopSnippet").result(); - assertDeepEquals(0, graph.getNodes().filter(LoadFieldNode.class).count()); - assertTrue(result instanceof ProxyNode); - assertTrue(((ProxyNode) result).value() instanceof ValuePhiNode); - } - - @SuppressWarnings("all") - public static int testBadLoop2Snippet(TestObject obj, TestObject obj2, int a, int b) { - obj.x = a; - for (int i = 0; i < 10; i++) { - obj.x = 0; - obj2.x = 10; - } - return obj.x; + public static int testUnsafe2Snippet(int v, Object array) { + int s = UnsafeAccess.unsafe.getInt(array, offsetInt1); + UnsafeAccess.unsafe.putInt(array, offsetInt1, v); + UnsafeAccess.unsafe.putInt(array, offsetInt2, v); + return s + UnsafeAccess.unsafe.getInt(array, offsetInt1) + UnsafeAccess.unsafe.getInt(array, offsetInt2); } @Test - public void testBadLoop2() { - ValueNode result = getReturn("testBadLoop2Snippet").result(); - assertDeepEquals(1, graph.getNodes().filter(LoadFieldNode.class).count()); - assertTrue(result instanceof LoadFieldNode); + public void testUnsafe2() { + processMethod("testUnsafe2Snippet"); + assertDeepEquals(3, graph.getNodes().filter(UnsafeLoadNode.class).count()); } - @SuppressWarnings("all") - public static int testPhiSnippet(TestObject a, int b) { - if (b < 0) { - a.x = 1; - } else { - a.x = 2; - } - return a.x; + private static final long offsetObject1 = Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * 1; + private static final long offsetObject2 = Unsafe.ARRAY_OBJECT_BASE_OFFSET + Unsafe.ARRAY_OBJECT_INDEX_SCALE * 2; + + public static int testUnsafe3Snippet(int v, Object[] array) { + int s = (Integer) UnsafeAccess.unsafe.getObject(array, offsetObject1); + UnsafeAccess.unsafe.putObject(array, offsetObject1, v); + UnsafeAccess.unsafe.putObject(array, offsetObject2, v); + return s + (Integer) UnsafeAccess.unsafe.getObject(array, offsetObject1) + (Integer) UnsafeAccess.unsafe.getObject(array, offsetObject2); } @Test - public void testPhi() { - processMethod("testPhiSnippet"); - assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty()); - List returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot(); - assertDeepEquals(2, returnNodes.size()); - assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode); - assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode); - assertTrue(returnNodes.get(0).result().isConstant()); - assertTrue(returnNodes.get(1).result().isConstant()); + public void testUnsafe3() { + processMethod("testUnsafe3Snippet"); + assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count()); } - @SuppressWarnings("all") - public static void testSimpleStoreSnippet(TestObject a, int b) { - a.x = b; - a.x = b; + public static int testUnsafe4Snippet(int v, Object[] array) { + int s = (Integer) UnsafeAccess.unsafe.getObject(array, offsetObject1); + UnsafeAccess.unsafe.putObject(array, offsetObject1, v); + UnsafeAccess.unsafe.putObject(array, offsetObject2, v); + array[v] = null; + return s + (Integer) UnsafeAccess.unsafe.getObject(array, offsetObject1) + (Integer) UnsafeAccess.unsafe.getObject(array, offsetObject2); } @Test - public void testSimpleStore() { - processMethod("testSimpleStoreSnippet"); - assertDeepEquals(1, graph.getNodes().filter(StoreFieldNode.class).count()); + public void testUnsafe4() { + processMethod("testUnsafe4Snippet"); + assertDeepEquals(3, graph.getNodes().filter(UnsafeLoadNode.class).count()); } - public static int testValueProxySnippet(boolean b, TestObject o) { - int sum = 0; - if (b) { - sum += o.x; - } else { - TestObject3 p = (TestObject3) o; - sum += p.x; - } - sum += o.x; - return sum; + private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1; + private static final long offsetLong2 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 2; + + public static int testUnsafe5Snippet(int v, long[] array) { + int s = UnsafeAccess.unsafe.getInt(array, offsetLong1); + UnsafeAccess.unsafe.putInt(array, offsetLong1, v); + UnsafeAccess.unsafe.putInt(array, offsetLong2, v); + return s + UnsafeAccess.unsafe.getInt(array, offsetLong1) + UnsafeAccess.unsafe.getInt(array, offsetLong2); } @Test - public void testValueProxy() { - processMethod("testValueProxySnippet"); - assertDeepEquals(2, graph.getNodes().filter(LoadFieldNode.class).count()); + public void testUnsafe5() { + processMethod("testUnsafe5Snippet"); + assertDeepEquals(1, graph.getNodes().filter(UnsafeLoadNode.class).count()); } - final ReturnNode getReturn(String snippet) { - processMethod(snippet); - assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count()); - return graph.getNodes(ReturnNode.TYPE).first(); - } - + @Override protected void processMethod(final String snippet) { graph = parseEager(snippet, AllowAssumptions.NO); HighTierContext context = getDefaultHighTierContext(); diff -r bf4526ed41bd -r 6fbf1c53feeb graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Thu Apr 02 16:08:26 2015 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java Thu Apr 02 16:08:55 2015 +0200 @@ -80,6 +80,10 @@ @Override public int entryIndexForOffset(long constantOffset, Kind expectedEntryKind) { + return entryIndexForOffset(constantOffset, expectedEntryKind, componentType, length); + } + + public static int entryIndexForOffset(long constantOffset, Kind expectedEntryKind, ResolvedJavaType componentType, int length) { int baseOffset; int indexScale; switch (componentType.getKind()) { diff -r bf4526ed41bd -r 6fbf1c53feeb graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java --- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Thu Apr 02 16:08:26 2015 +0200 +++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java Thu Apr 02 16:08:55 2015 +0200 @@ -26,8 +26,9 @@ import com.oracle.graal.debug.*; import com.oracle.graal.graph.*; import com.oracle.graal.nodeinfo.*; +import com.oracle.graal.nodes.CallTargetNode.InvokeKind; import com.oracle.graal.nodes.*; -import com.oracle.graal.nodes.CallTargetNode.InvokeKind; +import com.oracle.graal.nodes.java.*; import com.oracle.graal.nodes.spi.*; import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.virtual.*; @@ -90,37 +91,68 @@ @Override public void virtualize(VirtualizerTool tool) { - if (getSourcePosition().isConstant() && getDestinationPosition().isConstant() && getLength().isConstant()) { - int srcPos = getSourcePosition().asJavaConstant().asInt(); - int destPos = getDestinationPosition().asJavaConstant().asInt(); - int length = getLength().asJavaConstant().asInt(); - State srcState = tool.getObjectState(getSource()); + ValueNode sourcePosition = tool.getReplacedValue(getSourcePosition()); + ValueNode destinationPosition = tool.getReplacedValue(getDestinationPosition()); + ValueNode length = tool.getReplacedValue(getLength()); + + if (sourcePosition.isConstant() && destinationPosition.isConstant() && length.isConstant()) { + int srcPos = sourcePosition.asJavaConstant().asInt(); + int destPos = destinationPosition.asJavaConstant().asInt(); + int len = length.asJavaConstant().asInt(); State destState = tool.getObjectState(getDestination()); - if (srcState != null && srcState.getState() == EscapeState.Virtual && destState != null && destState.getState() == EscapeState.Virtual) { - VirtualObjectNode srcVirtual = srcState.getVirtualObject(); + if (destState != null && destState.getState() == EscapeState.Virtual) { VirtualObjectNode destVirtual = destState.getVirtualObject(); - if (!(srcVirtual instanceof VirtualArrayNode) || !(destVirtual instanceof VirtualArrayNode)) { + if (!(destVirtual instanceof VirtualArrayNode)) { + return; + } + if (len < 0 || !checkBounds(destPos, len, destVirtual)) { return; } - if (((VirtualArrayNode) srcVirtual).componentType().getKind() != Kind.Object || ((VirtualArrayNode) destVirtual).componentType().getKind() != Kind.Object) { - return; - } - if (length < 0 || !checkBounds(srcPos, length, srcVirtual) || !checkBounds(destPos, length, destVirtual)) { - return; - } - if (!checkEntryTypes(srcPos, length, srcState, destVirtual.type().getComponentType(), tool)) { - return; - } - for (int i = 0; i < length; i++) { - tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i), false); - } - tool.delete(); - if (Debug.isLogEnabled()) { - Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPos, getDestination(), destPos, length); + State srcState = tool.getObjectState(getSource()); + if (srcState != null && srcState.getState() == EscapeState.Virtual) { + VirtualObjectNode srcVirtual = srcState.getVirtualObject(); + if (((VirtualArrayNode) destVirtual).componentType().getKind() != Kind.Object) { + return; + } + if (!(srcVirtual instanceof VirtualArrayNode)) { + return; + } + if (((VirtualArrayNode) srcVirtual).componentType().getKind() != Kind.Object) { + return; + } + if (!checkBounds(srcPos, len, srcVirtual)) { + return; + } + if (!checkEntryTypes(srcPos, len, srcState, destVirtual.type().getComponentType(), tool)) { + return; + } + for (int i = 0; i < len; i++) { + tool.setVirtualEntry(destState, destPos + i, srcState.getEntry(srcPos + i), false); + } + tool.delete(); + if (Debug.isLogEnabled()) { + Debug.log("virtualized arraycopyf(%s, %d, %s, %d, %d)", getSource(), srcPos, getDestination(), destPos, len); + } + } else { + ValueNode source = srcState == null ? tool.getReplacedValue(getSource()) : srcState.getMaterializedValue(); + ResolvedJavaType sourceType = StampTool.typeOrNull(source); + if (sourceType == null || !sourceType.isArray()) { + return; + } + ResolvedJavaType sourceComponentType = sourceType.getComponentType(); + ResolvedJavaType destComponentType = destVirtual.type().getComponentType(); + if (!sourceComponentType.equals(destComponentType)) { + return; + } + for (int i = 0; i < len; i++) { + LoadIndexedNode load = new LoadIndexedNode(source, ConstantNode.forInt(i + srcPos, graph()), destComponentType.getKind()); + tool.addNode(load); + tool.setVirtualEntry(destState, destPos + i, load, false); + } + tool.delete(); } } } } - } diff -r bf4526ed41bd -r 6fbf1c53feeb graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java --- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Thu Apr 02 16:08:26 2015 +0200 +++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java Thu Apr 02 16:08:55 2015 +0200 @@ -32,7 +32,9 @@ import com.oracle.graal.nodes.cfg.*; import com.oracle.graal.nodes.extended.*; import com.oracle.graal.nodes.java.*; +import com.oracle.graal.nodes.type.*; import com.oracle.graal.nodes.util.*; +import com.oracle.graal.nodes.virtual.*; import com.oracle.graal.phases.schedule.*; import com.oracle.graal.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry; @@ -73,6 +75,10 @@ return processArrayLength((ArrayLengthNode) node, state, effects); } else if (node instanceof UnboxNode) { return processUnbox((UnboxNode) node, state, effects); + } else if (node instanceof UnsafeLoadNode) { + return processUnsafeLoad((UnsafeLoadNode) node, state, effects); + } else if (node instanceof UnsafeStoreNode) { + return processUnsafeStore((UnsafeStoreNode) node, state, effects); } else if (node instanceof MemoryCheckpoint.Single) { METRIC_MEMORYCHECKPOINT.increment(); LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity(); @@ -87,72 +93,97 @@ return false; } - private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) { - ValueNode array = GraphUtil.unproxify(length.array()); - ValueNode cachedValue = state.getReadCache(array, ARRAY_LENGTH_LOCATION, -1, this); + private boolean processStore(FixedNode store, ValueNode object, LocationIdentity identity, int index, ValueNode value, PEReadEliminationBlockState state, GraphEffectList effects) { + ValueNode unproxiedObject = GraphUtil.unproxify(object); + ValueNode cachedValue = state.getReadCache(object, identity, index, this); + + ValueNode finalValue = getScalarAlias(value); + boolean result = false; + if (GraphUtil.unproxify(finalValue) == GraphUtil.unproxify(cachedValue)) { + effects.deleteNode(store); + result = true; + } + state.killReadCache(identity, index); + state.addReadCache(unproxiedObject, identity, index, finalValue, this); + return result; + } + + private boolean processLoad(FixedNode load, ValueNode object, LocationIdentity identity, int index, PEReadEliminationBlockState state, GraphEffectList effects) { + ValueNode unproxiedObject = GraphUtil.unproxify(object); + ValueNode cachedValue = state.getReadCache(unproxiedObject, identity, index, this); if (cachedValue != null) { - effects.replaceAtUsages(length, cachedValue); - addScalarAlias(length, cachedValue); + effects.replaceAtUsages(load, cachedValue); + addScalarAlias(load, cachedValue); return true; } else { - state.addReadCache(array, ARRAY_LENGTH_LOCATION, -1, length, this); + state.addReadCache(unproxiedObject, identity, index, load, this); + return false; + } + } + + private boolean processUnsafeLoad(UnsafeLoadNode load, PEReadEliminationBlockState state, GraphEffectList effects) { + if (load.offset().isConstant()) { + ResolvedJavaType type = StampTool.typeOrNull(load.object()); + if (type != null && type.isArray()) { + long offset = load.offset().asJavaConstant().asLong(); + int index = VirtualArrayNode.entryIndexForOffset(offset, load.accessKind(), type.getComponentType(), Integer.MAX_VALUE); + ValueNode object = GraphUtil.unproxify(load.object()); + LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getKind()); + ValueNode cachedValue = state.getReadCache(object, location, index, this); + if (cachedValue != null && load.stamp().isCompatible(cachedValue.stamp())) { + effects.replaceAtUsages(load, cachedValue); + addScalarAlias(load, cachedValue); + return true; + } else { + state.addReadCache(object, location, index, load, this); + } + } } return false; } - private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) { - if (!store.isVolatile()) { - ValueNode object = GraphUtil.unproxify(store.object()); - ValueNode cachedValue = state.getReadCache(object, store.field().getLocationIdentity(), -1, this); - - ValueNode value = getScalarAlias(store.value()); - boolean result = false; - if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { - effects.deleteNode(store); - result = true; + private boolean processUnsafeStore(UnsafeStoreNode store, PEReadEliminationBlockState state, GraphEffectList effects) { + ResolvedJavaType type = StampTool.typeOrNull(store.object()); + if (type != null && type.isArray()) { + LocationIdentity location = NamedLocationIdentity.getArrayLocation(type.getComponentType().getKind()); + if (store.offset().isConstant()) { + long offset = store.offset().asJavaConstant().asLong(); + int index = VirtualArrayNode.entryIndexForOffset(offset, store.accessKind(), type.getComponentType(), Integer.MAX_VALUE); + return processStore(store, store.object(), location, index, store.value(), state, effects); + } else { + processIdentity(state, location); } - state.killReadCache(store.field().getLocationIdentity(), -1); - state.addReadCache(object, store.field().getLocationIdentity(), -1, value, this); - return result; } else { - processIdentity(state, any()); + state.killReadCache(); } return false; } + private boolean processArrayLength(ArrayLengthNode length, PEReadEliminationBlockState state, GraphEffectList effects) { + return processLoad(length, length.array(), ARRAY_LENGTH_LOCATION, -1, state, effects); + } + + private boolean processStoreField(StoreFieldNode store, PEReadEliminationBlockState state, GraphEffectList effects) { + if (store.isVolatile()) { + state.killReadCache(); + return false; + } + return processStore(store, store.object(), store.field().getLocationIdentity(), -1, store.value(), state, effects); + } + private boolean processLoadField(LoadFieldNode load, PEReadEliminationBlockState state, GraphEffectList effects) { if (load.isVolatile()) { - processIdentity(state, any()); - } else { - ValueNode object = GraphUtil.unproxify(load.object()); - ValueNode cachedValue = state.getReadCache(object, load.field().getLocationIdentity(), -1, this); - if (cachedValue != null) { - effects.replaceAtUsages(load, cachedValue); - addScalarAlias(load, cachedValue); - return true; - } else { - state.addReadCache(object, load.field().getLocationIdentity(), -1, load, this); - } + state.killReadCache(); + return false; } - return false; + return processLoad(load, load.object(), load.field().getLocationIdentity(), -1, state, effects); } private boolean processStoreIndexed(StoreIndexedNode store, PEReadEliminationBlockState state, GraphEffectList effects) { LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(store.elementKind()); if (store.index().isConstant()) { int index = ((JavaConstant) store.index().asConstant()).asInt(); - ValueNode object = GraphUtil.unproxify(store.array()); - ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this); - - ValueNode value = getScalarAlias(store.value()); - boolean result = false; - if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) { - effects.deleteNode(store); - result = true; - } - state.killReadCache(arrayLocation, index); - state.addReadCache(object, arrayLocation, index, value, this); - return result; + return processStore(store, store.array(), arrayLocation, index, store.value(), state, effects); } else { state.killReadCache(arrayLocation, -1); } @@ -163,31 +194,13 @@ if (load.index().isConstant()) { int index = ((JavaConstant) load.index().asConstant()).asInt(); LocationIdentity arrayLocation = NamedLocationIdentity.getArrayLocation(load.elementKind()); - ValueNode object = GraphUtil.unproxify(load.array()); - ValueNode cachedValue = state.getReadCache(object, arrayLocation, index, this); - if (cachedValue != null) { - effects.replaceAtUsages(load, cachedValue); - addScalarAlias(load, cachedValue); - return true; - } else { - state.addReadCache(object, arrayLocation, index, load, this); - } + return processLoad(load, load.array(), arrayLocation, index, state, effects); } return false; } private boolean processUnbox(UnboxNode unbox, PEReadEliminationBlockState state, GraphEffectList effects) { - ValueNode object = GraphUtil.unproxify(unbox.getValue()); - LocationIdentity identity = UNBOX_LOCATIONS.get(unbox.getBoxingKind()); - ValueNode cachedValue = state.getReadCache(object, identity, -1, this); - if (cachedValue != null) { - effects.replaceAtUsages(unbox, cachedValue); - addScalarAlias(unbox, cachedValue); - return true; - } else { - state.addReadCache(object, identity, -1, unbox, this); - } - return false; + return processLoad(unbox, unbox.getValue(), UNBOX_LOCATIONS.get(unbox.getBoxingKind()), -1, state, effects); } private static void processIdentity(PEReadEliminationBlockState state, LocationIdentity identity) {