changeset 20985:eebb05f2d1e8

Fixes for GraphPE
author Christian Wimmer <christian.wimmer@oracle.com>
date Wed, 15 Apr 2015 21:01:33 -0700
parents 6361fa2e3321
children ec91b758ebc7
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.output graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SLTruffleGraalTestSuite.java graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLCallUntilOptimizedBuiltin.java graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLDeoptimizeWhenCompiledBuiltin.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java
diffstat 8 files changed, 128 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Wed Apr 15 21:13:43 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GraphDecoder.java	Wed Apr 15 21:01:33 2015 -0700
@@ -252,11 +252,12 @@
     public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) {
         MethodScope methodScope = new MethodScope(graph, encodedGraph, LoopExplosionKind.NONE);
         decode(methodScope, null);
-        cleanupGraph(methodScope);
+        cleanupGraph(methodScope, null);
         methodScope.graph.verify();
     }
 
     protected final void decode(MethodScope methodScope, FixedWithNextNode startNode) {
+        Graph.Mark start = methodScope.graph.getMark();
         LoopScope loopScope = new LoopScope(methodScope);
         FixedNode firstNode;
         if (startNode != null) {
@@ -284,9 +285,14 @@
         }
 
         if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
-            cleanupGraph(methodScope);
+            /*
+             * The startNode can get deleted during graph cleanup, so we use its predecessor (if
+             * available) as the starting point for loop detection.
+             */
+            FixedNode detectLoopsStart = startNode.predecessor() != null ? (FixedNode) startNode.predecessor() : startNode;
+            cleanupGraph(methodScope, start);
             Debug.dump(methodScope.graph, "Before loop detection");
-            detectLoops(methodScope.graph, firstNode);
+            detectLoops(methodScope.graph, detectLoopsStart);
         }
     }
 
@@ -1111,18 +1117,21 @@
         }
     }
 
-    protected void cleanupGraph(MethodScope methodScope) {
+    protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         assert verifyEdges(methodScope);
 
         Debug.dump(methodScope.graph, "Before removing redundant merges");
-        for (MergeNode mergeNode : methodScope.graph.getNodes(MergeNode.TYPE)) {
-            if (mergeNode.forwardEndCount() == 1) {
-                methodScope.graph.reduceTrivialMerge(mergeNode);
+        for (Node node : methodScope.graph.getNewNodes(start)) {
+            if (node instanceof MergeNode) {
+                MergeNode mergeNode = (MergeNode) node;
+                if (mergeNode.forwardEndCount() == 1) {
+                    methodScope.graph.reduceTrivialMerge(mergeNode);
+                }
             }
         }
 
         Debug.dump(methodScope.graph, "Before removing redundant begins");
-        for (Node node : methodScope.graph.getNodes()) {
+        for (Node node : methodScope.graph.getNewNodes(start)) {
             if (node instanceof BeginNode || node instanceof KillingBeginNode) {
                 if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) {
                     GraphUtil.unlinkFixedNode((AbstractBeginNode) node);
@@ -1132,7 +1141,7 @@
         }
 
         Debug.dump(methodScope.graph, "Before removing unused non-fixed nodes");
-        for (Node node : methodScope.graph.getNodes()) {
+        for (Node node : methodScope.graph.getNewNodes(start)) {
             if (!(node instanceof FixedNode) && node.hasNoUsages()) {
                 GraphUtil.killCFG(node);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.output	Wed Apr 15 21:01:33 2015 -0700
@@ -0,0 +1,2 @@
+[deoptimizeWhenCompiled]
+[deoptimizeWhenCompiled]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/sl/TestDeoptInInlinedFunction.sl	Wed Apr 15 21:01:33 2015 -0700
@@ -0,0 +1,21 @@
+/* 
+ * This tests that simple arithmetic gets inlined.
+ */
+function add(a, b) {
+    deoptimizeWhenCompiled(a == 50); 
+    return a + b;
+}
+
+
+function test() {
+    i = 0;
+    while (i < 100) {
+        i = add(i, 1);
+    }
+    return i;
+}
+
+function main() {
+    waitForOptimization(callUntilOptimized(test, 1 == 2));
+    test();
+}  
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SLTruffleGraalTestSuite.java	Wed Apr 15 21:13:43 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/SLTruffleGraalTestSuite.java	Wed Apr 15 21:01:33 2015 -0700
@@ -49,6 +49,7 @@
         SLTestRunner.installBuiltin(SLGenerateDummyNodesBuiltinFactory.getInstance());
         SLTestRunner.installBuiltin(SLCallFunctionsWithBuiltinFactory.getInstance());
         SLTestRunner.installBuiltin(SLIsCompilationConstantBuiltinFactory.getInstance());
+        SLTestRunner.installBuiltin(SLDeoptimizeWhenCompiledBuiltinFactory.getInstance());
 
         /* test specific builtins */
         SLTestRunner.installBuiltin(SLTestTruffleBoundary01BuiltinFactory.getInstance());
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLCallUntilOptimizedBuiltin.java	Wed Apr 15 21:13:43 2015 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLCallUntilOptimizedBuiltin.java	Wed Apr 15 21:01:33 2015 -0700
@@ -49,7 +49,12 @@
     @Child private IndirectCallNode indirectCall = Truffle.getRuntime().createIndirectCallNode();
 
     @Specialization
-    public SLFunction callUntilCompiled(VirtualFrame frame, SLFunction function) {
+    public SLFunction callUntilCompiled(VirtualFrame frame, SLFunction function, @SuppressWarnings("unused") SLNull checkTarget) {
+        return callUntilCompiled(frame, function, false);
+    }
+
+    @Specialization
+    public SLFunction callUntilCompiled(VirtualFrame frame, SLFunction function, boolean checkTarget) {
         OptimizedCallTarget target = ((OptimizedCallTarget) function.getCallTarget());
         for (int i = 0; i < MAX_CALLS; i++) {
             if (isCompiling(target)) {
@@ -63,7 +68,9 @@
         // call one more in compiled
         indirectCall.call(frame, target, EMPTY_ARGS);
 
-        checkTarget(target);
+        if (checkTarget) {
+            checkTarget(target);
+        }
 
         return function;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/builtins/SLDeoptimizeWhenCompiledBuiltin.java	Wed Apr 15 21:01:33 2015 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.test.builtins;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.sl.runtime.*;
+
+/**
+ * Forces a deoptimization as soon as the method runs in compiled code.
+ */
+@NodeInfo(shortName = "deoptimizeWhenCompiled")
+public abstract class SLDeoptimizeWhenCompiledBuiltin extends SLGraalRuntimeBuiltin {
+
+    @Specialization
+    public SLNull deoptimzeWhenCompiled(boolean condition) {
+        if (CompilerDirectives.inCompiledCode()) {
+            if (condition) {
+                printMessage();
+                CompilerDirectives.transferToInterpreterAndInvalidate();
+            }
+        }
+        return SLNull.SINGLETON;
+    }
+
+    @TruffleBoundary
+    private void printMessage() {
+        getContext().getOutput().println("[deoptimizeWhenCompiled]");
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java	Wed Apr 15 21:13:43 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PEGraphDecoder.java	Wed Apr 15 21:01:33 2015 -0700
@@ -128,9 +128,11 @@
 
     protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
         protected final PEMethodScope methodScope;
+        protected final Invoke invoke;
 
-        public PENonAppendGraphBuilderContext(PEMethodScope methodScope) {
+        public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
             this.methodScope = methodScope;
+            this.invoke = invoke;
         }
 
         @Override
@@ -210,7 +212,7 @@
 
         @Override
         public int bci() {
-            throw unimplemented();
+            return invoke.bci();
         }
 
         @Override
@@ -228,8 +230,8 @@
         protected FixedWithNextNode lastInstr;
         protected ValueNode pushedNode;
 
-        public PEAppendGraphBuilderContext(PEMethodScope methodScope, FixedWithNextNode lastInstr) {
-            super(methodScope);
+        public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
+            super(inlineScope, inlineScope.invokeData.invoke);
             this.lastInstr = lastInstr;
         }
 
@@ -319,14 +321,14 @@
         PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugin,
                         parameterPlugin, null);
         decode(methodScope, null);
-        cleanupGraph(methodScope);
+        cleanupGraph(methodScope, null);
         methodScope.graph.verify();
     }
 
     @Override
-    protected void cleanupGraph(MethodScope methodScope) {
+    protected void cleanupGraph(MethodScope methodScope, Graph.Mark start) {
         GraphBuilderPhase.connectLoopEndToBegin(methodScope.graph);
-        super.cleanupGraph(methodScope);
+        super.cleanupGraph(methodScope, start);
     }
 
     @Override
@@ -378,7 +380,7 @@
         }
 
         if (methodScope.inlineInvokePlugin != null) {
-            methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope), callTarget.targetMethod(), invokeData.invoke);
+            methodScope.inlineInvokePlugin.notifyOfNoninlinedInvoke(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke);
         }
         return false;
     }
@@ -439,7 +441,7 @@
         }
 
         ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
-        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope);
+        GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke);
         InlineInfo inlineInfo = methodScope.inlineInvokePlugin.getInlineInfo(graphBuilderContext, targetMethod, arguments, callTarget.returnType());
         if (inlineInfo == null) {
             return false;
@@ -619,7 +621,7 @@
                 return result;
 
             } else if (methodScope.parameterPlugin != null) {
-                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope);
+                GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null);
                 Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, ((ParameterNode) node).index(), ((ParameterNode) node).stamp());
                 if (result != null) {
                     return result;
@@ -657,7 +659,11 @@
             Kind invokeReturnKind = methodScope.invokeData.invoke.asNode().getKind();
             FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind);
 
-            if (methodScope.caller != null) {
+            /*
+             * When the encoded graph has methods inlining, we can already have a proper caller
+             * state. If not, we set the caller state here.
+             */
+            if (outerState.outerFrameState() == null && methodScope.caller != null) {
                 ensureOuterStateDecoded(methodScope.caller);
                 outerState.setOuterFrameState(methodScope.caller.outerState);
             }
@@ -680,7 +686,7 @@
             registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false);
             FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId);
 
-            if (methodScope.caller != null) {
+            if (exceptionState.outerFrameState() == null && methodScope.caller != null) {
                 ensureOuterStateDecoded(methodScope.caller);
                 exceptionState.setOuterFrameState(methodScope.caller.outerState);
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Apr 15 21:13:43 2015 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Wed Apr 15 21:01:33 2015 -0700
@@ -184,7 +184,9 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
-            assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now";
+            if (replacements.hasSubstitution(original, builder.bci())) {
+                return null;
+            }
             assert !builder.parsingReplacement();
 
             if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) {
@@ -260,7 +262,9 @@
             if (original.getAnnotation(TruffleBoundary.class) != null) {
                 return null;
             }
-            assert !replacements.hasSubstitution(original, builder.bci()) : "Replacements must have been processed by now";
+            if (replacements.hasSubstitution(original, builder.bci())) {
+                return null;
+            }
 
             if (original.equals(callSiteProxyMethod) || original.equals(callDirectMethod)) {
                 return null;
@@ -337,7 +341,7 @@
 
         ParameterPlugin parameterPlugin = new InterceptReceiverPlugin(callTarget);
 
-        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(parsingInvocationPlugins.getParent());
+        InvocationPlugins decodingInvocationPlugins = new InvocationPlugins(providers.getMetaAccess());
         TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), decodingInvocationPlugins, false, snippetReflection);
         InlineInvokePlugin decodingInlinePlugin = new PEInlineInvokePlugin(callTarget.getInlining(), (ReplacementsImpl) providers.getReplacements());
         if (PrintTruffleExpansionHistogram.getValue()) {