changeset 20141:6fbf1c53feeb

Merge.
author Doug Simon <doug.simon@oracle.com>
date Thu, 02 Apr 2015 16:08:55 +0200
parents bf4526ed41bd (current diff) 7ad60a16bbb0 (diff)
children 6d51420ee69f
files
diffstat 5 files changed, 460 insertions(+), 257 deletions(-) [+]
line wrap: on
line diff
--- 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<ReturnNode> 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);
--- 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<ReturnNode> 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();
--- 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()) {
--- 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();
                 }
             }
         }
     }
-
 }
--- 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) {