changeset 12479:36a438ebab50

duplicate VirtualObjectNodes when peeling / unrolling loops
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 18 Oct 2013 14:51:56 +0200
parents b4b7d39cdf73
children 47200418768d
files graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java
diffstat 2 files changed, 91 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri Oct 18 13:49:41 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EscapeAnalysisTest.java	Fri Oct 18 14:51:56 2013 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import java.util.concurrent.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -32,12 +30,14 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
+import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
 
@@ -223,31 +223,97 @@
         testEscapeAnalysis("testNewNodeSnippet", null, false);
     }
 
-    private ReturnNode testEscapeAnalysis(String snippet, final Constant expectedConstantResult, final boolean iterativeEscapeAnalysis) {
-        ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(snippet));
-        final StructuredGraph graph = new StructuredGraph(method);
+    private static final TestObject2 staticObj = new TestObject2(null);
+
+    public static Object testFullyUnrolledLoopSnippet() {
+        /*
+         * This tests a case that can appear if PEA is performed both before and after loop
+         * unrolling/peeling: If the VirtualInstanceNode is not anchored correctly to stay within
+         * the loop, it will not be duplicated, and therefore the resulting object will reference
+         * itself, and not a second (different) object.
+         */
+        TestObject2 obj = staticObj;
+        for (int i = 0; i < 2; i++) {
+            obj = new TestObject2(obj);
+        }
+        return obj.o;
+    }
 
-        return Debug.scope("GraalCompiler", new Object[]{graph, method, getCodeCache()}, new Callable<ReturnNode>() {
+    @Test
+    public void testFullyUnrolledLoop() {
+        testEscapeAnalysisUnrolled("testFullyUnrolledLoopSnippet");
+    }
+
+    private static Object staticField;
+
+    private static TestObject2 inlinedPart(TestObject2 obj) {
+        TestObject2 ret = new TestObject2(obj);
+        staticField = null;
+        return ret;
+    }
+
+    public static Object testPeeledLoopSnippet() {
+        TestObject2 obj = staticObj;
+        int i = 0;
+        do {
+            obj = inlinedPart(obj);
+        } while (i++ < 10);
+        staticField = obj;
+        return obj.o;
+    }
 
-            public ReturnNode call() {
-                new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+    @Test
+    public void testPeeledLoop() {
+        testEscapeAnalysisPeeled("testPeeledLoopSnippet");
+    }
+
+    private StructuredGraph graph;
+    private HighTierContext context;
+    private ReturnNode returnNode;
+
+    private void testEscapeAnalysis(String snippet, final Constant expectedConstantResult, final boolean iterativeEscapeAnalysis) {
+        prepareGraph(snippet, iterativeEscapeAnalysis);
+        if (expectedConstantResult != null) {
+            Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
+            Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
+        }
+        int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() +
+                        graph.getNodes().filter(CommitAllocationNode.class).count();
+        Assert.assertEquals(0, newInstanceCount);
+    }
 
+    private void testEscapeAnalysisUnrolled(String snippet) {
+        prepareGraph(snippet, false);
+        new LoopFullUnrollPhase(new CanonicalizerPhase(true)).apply(graph, context);
+        new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context);
+        Assert.assertTrue(returnNode.result() instanceof AllocatedObjectNode);
+        CommitAllocationNode commit = ((AllocatedObjectNode) returnNode.result()).getCommit();
+        Assert.assertEquals(1, commit.getValues().size());
+        Assert.assertEquals(1, commit.getVirtualObjects().size());
+        Assert.assertTrue("non-cyclic data structure expected", commit.getVirtualObjects().get(0) != commit.getValues().get(0));
+    }
+
+    private void testEscapeAnalysisPeeled(String snippet) {
+        prepareGraph(snippet, false);
+        new LoopTransformHighPhase().apply(graph);
+        new LoopTransformLowPhase().apply(graph);
+        new SchedulePhase().apply(graph);
+    }
+
+    private void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) {
+        graph = new StructuredGraph(getMetaAccess().lookupJavaMethod(getMethod(snippet)));
+        Debug.scope("GraalCompiler", new Object[]{graph, getMetaAccess().lookupJavaMethod(getMethod(snippet)), getCodeCache()}, new Runnable() {
+
+            public void run() {
+                new GraphBuilderPhase(getMetaAccess(), getForeignCalls(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
                 Assumptions assumptions = new Assumptions(false);
-                HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
+                context = new HighTierContext(getProviders(), assumptions, null, getDefaultPhasePlan(), OptimisticOptimizations.ALL);
                 new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
                 new DeadCodeEliminationPhase().apply(graph);
                 new CanonicalizerPhase(true).apply(graph, context);
                 new PartialEscapePhase(iterativeEscapeAnalysis, new CanonicalizerPhase(true)).apply(graph, context);
                 Assert.assertEquals(1, graph.getNodes().filter(ReturnNode.class).count());
-                ReturnNode returnNode = graph.getNodes().filter(ReturnNode.class).first();
-                if (expectedConstantResult != null) {
-                    Assert.assertTrue(returnNode.result().toString(), returnNode.result().isConstant());
-                    Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant());
-                }
-                int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() +
-                                graph.getNodes().filter(CommitAllocationNode.class).count();
-                Assert.assertEquals(0, newInstanceCount);
-                return returnNode;
+                returnNode = graph.getNodes().filter(ReturnNode.class).first();
             }
         });
     }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri Oct 18 13:49:41 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Fri Oct 18 14:51:56 2013 +0200
@@ -32,6 +32,7 @@
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
 import com.oracle.graal.nodes.VirtualState.VirtualClosure;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.virtual.*;
 
 public abstract class LoopFragment {
 
@@ -181,10 +182,16 @@
         final NodeBitMap notloopNodes = graph.createNodeBitMap(true);
         for (AbstractBeginNode b : blocks) {
             for (Node n : b.getBlockNodes()) {
+                if (n instanceof CommitAllocationNode) {
+                    for (VirtualObjectNode obj : ((CommitAllocationNode) n).getVirtualObjects()) {
+                        markFloating(obj, nodes, notloopNodes);
+                    }
+                }
                 for (Node usage : n.usages()) {
                     markFloating(usage, nodes, notloopNodes);
                 }
             }
+
         }
 
         return nodes;