changeset 11728:7778a0f2999a

Run partial escape analysis on Truffle cache methods.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Thu, 19 Sep 2013 15:53:26 +0200
parents 271ffa2d36b3
children fdd2cdeb933c
files graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java
diffstat 2 files changed, 87 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu Sep 19 15:53:09 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Thu Sep 19 15:53:26 2013 +0200
@@ -360,6 +360,10 @@
         return true;
     }
 
+    public boolean isNew(int mark, Node node) {
+        return node.id >= mark;
+    }
+
     /**
      * Gets a mark that can be used with {@link #getNewNodes(int)}.
      */
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Thu Sep 19 15:53:09 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Thu Sep 19 15:53:26 2013 +0200
@@ -43,6 +43,7 @@
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.truffle.phases.*;
+import com.oracle.graal.virtual.phases.ea.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -109,43 +110,70 @@
                 new ConvertDeoptimizeToGuardPhase().apply(graph);
 
                 CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase(!AOTCompilation.getValue());
+                PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizerPhase);
 
-                // Canonicalize / constant propagate.
-                canonicalizerPhase.apply(graph, context);
+                int mark = 0;
+                while (true) {
+
+                    partialEscapePhase.apply(graph, context);
 
-                int mark = graph.getMark();
-                for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
-                    if (graph.getMark() != mark) {
-                        canonicalizerPhase.applyIncremental(graph, context, mark);
+                    // Conditional elimination.
+                    ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(metaAccessProvider);
+                    conditionalEliminationPhase.apply(graph);
+
+                    // Canonicalize / constant propagate.
+                    canonicalizerPhase.apply(graph, context);
 
-                        // Make sure macro substitutions such as
-                        // CompilerDirectives.transferToInterpreter get processed first.
-                        for (Node newNode : graph.getNewNodes(mark)) {
-                            if (newNode instanceof MethodCallTargetNode) {
-                                MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
-                                Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
-                                if (macroSubstitution != null) {
-                                    InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                    boolean inliningProgress = false;
+                    for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
+                        if (graph.getMark() != mark) {
+                            // Make sure macro substitutions such as
+                            // CompilerDirectives.transferToInterpreter get processed first.
+                            for (Node newNode : graph.getNewNodes(mark)) {
+                                if (newNode instanceof MethodCallTargetNode) {
+                                    MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) newNode;
+                                    Class<? extends FixedWithNextNode> macroSubstitution = replacements.getMacroSubstitution(methodCallTargetNode.targetMethod());
+                                    if (macroSubstitution != null) {
+                                        InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), methodCallTargetNode.graph(), macroSubstitution);
+                                    } else {
+                                        tryCutOffRuntimeExceptions(methodCallTargetNode);
+                                    }
                                 }
                             }
+                            mark = graph.getMark();
                         }
-                        mark = graph.getMark();
+                        if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null && shouldInline(methodCallTarget)) {
+                            inliningProgress = true;
+                            List<Node> canonicalizerUsages = new ArrayList<Node>();
+                            for (Node n : methodCallTarget.invoke().asNode().usages()) {
+                                if (n instanceof Canonicalizable) {
+                                    canonicalizerUsages.add(n);
+                                }
+                            }
+                            List<ValueNode> argumentSnapshot = methodCallTarget.arguments().snapshot();
+                            int beforeInvokeMark = graph.getMark();
+                            expandInvoke(methodCallTarget);
+                            for (Node arg : argumentSnapshot) {
+                                if (arg != null) {
+                                    for (Node argUsage : arg.usages()) {
+                                        if (graph.isNew(beforeInvokeMark, argUsage) && argUsage instanceof Canonicalizable) {
+                                            canonicalizerUsages.add(argUsage);
+                                        }
+                                    }
+                                }
+                            }
+                            canonicalizerPhase.applyIncremental(graph, context, canonicalizerUsages);
+                        }
                     }
-                    if (methodCallTarget.isAlive() && methodCallTarget.invoke() != null) {
-                        expandInvoke(methodCallTarget.invoke());
+
+                    // Convert deopt to guards.
+                    new ConvertDeoptimizeToGuardPhase().apply(graph);
+
+                    if (!inliningProgress) {
+                        break;
                     }
                 }
 
-                // Convert deopt to guards.
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
-
-                // Canonicalize / constant propagate.
-                canonicalizerPhase.apply(graph, context);
-
-                // Conditional elimination.
-                ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(metaAccessProvider);
-                conditionalEliminationPhase.apply(graph);
-
                 if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
                     TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, graph.getNodeCount()));
                 }
@@ -156,42 +184,36 @@
         return resultGraph;
     }
 
-    private FixedNode expandInvoke(Invoke invoke) {
-        if (invoke.callTarget() instanceof MethodCallTargetNode) {
-            final MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) invoke.callTarget();
+    private void expandInvoke(MethodCallTargetNode methodCallTargetNode) {
+        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
+        if (inlineGraph == null) {
+            inlineGraph = TruffleCache.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null);
+        }
+        if (inlineGraph == this.markerGraph) {
+            // Can happen for recursive calls.
+            throw new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() + ", must annotate such calls with @CompilerDirectives.Slowpath!");
+        }
+        Invoke invoke = methodCallTargetNode.invoke();
+        InliningUtil.inline(invoke, inlineGraph, true);
+    }
 
-            if ((methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
-                            !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
-                            methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null) {
-                if (methodCallTargetNode.targetMethod().isConstructor()) {
-                    ResolvedJavaType runtimeException = metaAccessProvider.lookupJavaType(RuntimeException.class);
-                    if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass())) {
-                        DeoptimizeNode deoptNode = invoke.asNode().graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
-                        FixedNode invokeNode = methodCallTargetNode.invoke().asNode();
-                        invokeNode.replaceAtPredecessor(deoptNode);
-                        GraphUtil.killCFG(invokeNode);
-                        return deoptNode;
-                    }
-                }
-                StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable<StructuredGraph>() {
-
-                    public StructuredGraph call() {
-                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
-                        if (inlineGraph == null) {
-                            inlineGraph = TruffleCache.this.lookup(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), null, null);
-                        }
-                        return inlineGraph;
-                    }
-                });
-                if (inlinedGraph == this.markerGraph) {
-                    // Can happen for recursive calls.
-                    throw new IllegalStateException("Found illegal recursive call to " + methodCallTargetNode.targetMethod() + ", must annotate such calls with @CompilerDirectives.Slowpath!");
-                }
-                FixedNode fixedNode = (FixedNode) invoke.predecessor();
-                InliningUtil.inline(invoke, inlinedGraph, true);
-                return fixedNode;
+    private boolean tryCutOffRuntimeExceptions(MethodCallTargetNode methodCallTargetNode) {
+        if (methodCallTargetNode.targetMethod().isConstructor()) {
+            ResolvedJavaType runtimeException = metaAccessProvider.lookupJavaType(RuntimeException.class);
+            if (runtimeException.isAssignableFrom(methodCallTargetNode.targetMethod().getDeclaringClass())) {
+                DeoptimizeNode deoptNode = methodCallTargetNode.graph().add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
+                FixedNode invokeNode = methodCallTargetNode.invoke().asNode();
+                invokeNode.replaceAtPredecessor(deoptNode);
+                GraphUtil.killCFG(invokeNode);
+                return true;
             }
         }
-        return invoke.asNode();
+        return false;
+    }
+
+    private static boolean shouldInline(final MethodCallTargetNode methodCallTargetNode) {
+        return (methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
+                        !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers()) && methodCallTargetNode.targetMethod().getAnnotation(ExplodeLoop.class) == null &&
+                        methodCallTargetNode.targetMethod().getAnnotation(CompilerDirectives.SlowPath.class) == null;
     }
 }