changeset 10612:549a7568ce14

Introduce new Truffle compiler options: TruffleOperationCacheMaxNodes and TraceTruffleCompilationExceptions Perform inlining for cached Truffle graphs.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 06 Jul 2013 11:56:27 +0200
parents 1546866ebb8d
children 7220a8568e8c e9241e9cfcd5
files graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java
diffstat 4 files changed, 125 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Sat Jul 06 00:29:59 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Sat Jul 06 11:56:27 2013 +0200
@@ -220,6 +220,7 @@
         }
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
+            CompilerDirectives.transferToInterpreter();
             resize();
         }
         tags[slotIndex] = (byte) accessKind.ordinal();
@@ -237,9 +238,11 @@
         }
         int slotIndex = slot.getIndex();
         if (slotIndex >= tags.length) {
+            CompilerDirectives.transferToInterpreter();
             resize();
         }
         if (tags[slotIndex] != accessKind.ordinal()) {
+            CompilerDirectives.transferToInterpreter();
             descriptor.getTypeConversion().updateFrameSlot(this, slot, getValue(slot));
             if (tags[slotIndex] != accessKind.ordinal()) {
                 throw new FrameSlotTypeException();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Sat Jul 06 00:29:59 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Sat Jul 06 11:56:27 2013 +0200
@@ -254,6 +254,8 @@
                     if (arg.isConstant()) {
                         Constant constant = arg.asConstant();
                         local.replaceAndDelete(ConstantNode.forConstant(constant, metaAccessProvider, graph));
+                    } else {
+                        local.setStamp(arg.stamp());
                     }
                 }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Sat Jul 06 00:29:59 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Sat Jul 06 11:56:27 2013 +0200
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.phases.GraalOptions.*;
 
+import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.*;
 
@@ -34,11 +35,15 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.*;
 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.*;
 
 /**
  * Implementation of a cache for Truffle graphs for improving partial evaluation time.
@@ -98,7 +103,7 @@
 
                 optimizeGraph(newGraph);
                 cache.put(method, newGraph);
-                if (TruffleCompilerOptions.TraceTruffleCompilationDetails.getValue()) {
+                if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
                     TTY.println(String.format("[truffle] added to graph cache method %s with %d nodes.", method, newGraph.getNodeCount()));
                 }
                 return newGraph;
@@ -108,21 +113,124 @@
     }
 
     private void optimizeGraph(StructuredGraph newGraph) {
-        // Canonicalize / constant propagate.
+
+        ConditionalEliminationPhase eliminate = new ConditionalEliminationPhase(metaAccessProvider);
+        ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase = new ConvertDeoptimizeToGuardPhase();
+
         Assumptions assumptions = new Assumptions(false);
         CanonicalizerPhase.Instance canonicalizerPhase = new CanonicalizerPhase.Instance(metaAccessProvider, assumptions, !AOTCompilation.getValue(), null, null);
-        canonicalizerPhase.apply(newGraph);
+
+        Integer maxNodes = TruffleCompilerOptions.TruffleOperationCacheMaxNodes.getValue();
+
+        while (newGraph.getNodeCount() <= maxNodes) {
+
+            int mark = newGraph.getMark();
+
+            expandGraph(newGraph, maxNodes);
+
+            // Canonicalize / constant propagate.
+            canonicalizerPhase.apply(newGraph);
+
+            // Convert deopt to guards.
+            convertDeoptimizeToGuardPhase.apply(newGraph);
+
+            // Conditional elimination.
+            eliminate.apply(newGraph);
+
+            if (newGraph.getNewNodes(mark).count() == 0) {
+                // No progress => exit iterative optimization.
+                break;
+            }
+        }
+
+        HighTierContext context = new HighTierContext(metaAccessProvider, assumptions, replacements);
+        PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, new CanonicalizerPhase(true));
+        partialEscapePhase.apply(newGraph, context);
+
+        if (newGraph.getNodeCount() > maxNodes && TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
+            TTY.println(String.format("[truffle] PERFORMANCE WARNING: method %s got too large with %d nodes.", newGraph.method(), newGraph.getNodeCount()));
+        }
+    }
+
+    private void expandGraph(StructuredGraph newGraph, int maxNodes) {
+        NodeBitMap visitedNodes = newGraph.createNodeBitMap(true);
+        Queue<AbstractBeginNode> workQueue = new LinkedList<>();
+        workQueue.add(newGraph.start());
+
+        while (!workQueue.isEmpty() && newGraph.getNodeCount() <= maxNodes) {
+            AbstractBeginNode start = workQueue.poll();
+            expandPath(newGraph, maxNodes, visitedNodes, start, workQueue);
+        }
+    }
 
-        // Intrinsify methods.
-        new ReplaceIntrinsicsPhase(replacements).apply(newGraph);
+    private void expandPath(StructuredGraph newGraph, int maxNodes, NodeBitMap visitedNodes, AbstractBeginNode start, Queue<AbstractBeginNode> workQueue) {
+        FixedNode next = start;
+        while (!visitedNodes.isMarked(next)) {
+            visitedNodes.mark(next);
+            if (next instanceof Invoke) {
+                Invoke invoke = (Invoke) next;
+                next = expandInvoke(invoke);
+                if (newGraph.getNodeCount() > maxNodes) {
+                    return;
+                }
+            }
 
-        // Convert deopt to guards.
-        new ConvertDeoptimizeToGuardPhase().apply(newGraph);
+            if (next instanceof ControlSplitNode) {
+                ControlSplitNode controlSplitNode = (ControlSplitNode) next;
+                AbstractBeginNode maxProbNode = null;
+                for (Node succ : controlSplitNode.cfgSuccessors()) {
+                    AbstractBeginNode successor = (AbstractBeginNode) succ;
+                    if (maxProbNode == null || controlSplitNode.probability(successor) > controlSplitNode.probability(maxProbNode)) {
+                        maxProbNode = successor;
+                    }
+                }
+                for (Node succ : controlSplitNode.cfgSuccessors()) {
+                    AbstractBeginNode successor = (AbstractBeginNode) succ;
+                    if (successor != maxProbNode) {
+                        workQueue.add(successor);
+                    }
+                }
+                next = maxProbNode;
+            } else if (next instanceof EndNode) {
+                EndNode endNode = (EndNode) next;
+                next = endNode.merge();
+            } else if (next instanceof ControlSinkNode) {
+                return;
+            } else if (next instanceof FixedWithNextNode) {
+                FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) next;
+                next = fixedWithNextNode.next();
+            }
+        }
+    }
+
+    private FixedNode expandInvoke(Invoke invoke) {
+        if (invoke.callTarget() instanceof MethodCallTargetNode) {
+            final MethodCallTargetNode methodCallTargetNode = (MethodCallTargetNode) invoke.callTarget();
+            if ((methodCallTargetNode.invokeKind() == InvokeKind.Special || methodCallTargetNode.invokeKind() == InvokeKind.Static) &&
+                            !Modifier.isNative(methodCallTargetNode.targetMethod().getModifiers())) {
+                StructuredGraph inlinedGraph = Debug.scope("ExpandInvoke", methodCallTargetNode.targetMethod(), new Callable<StructuredGraph>() {
+
+                    public StructuredGraph call() {
+                        StructuredGraph inlineGraph = replacements.getMethodSubstitution(methodCallTargetNode.targetMethod());
+                        if (inlineGraph == null) {
+                            inlineGraph = parseGraph(methodCallTargetNode.targetMethod());
+                        }
+                        return inlineGraph;
+                    }
+                });
+                FixedNode fixedNode = (FixedNode) invoke.predecessor();
+                InliningUtil.inline(invoke, inlinedGraph, true);
+                return fixedNode;
+            }
+        }
+        return invoke.next();
     }
 
     private StructuredGraph parseGraph(ResolvedJavaMethod method) {
         StructuredGraph graph = new StructuredGraph(method);
         new GraphBuilderPhase(metaAccessProvider, config, optimisticOptimizations).apply(graph);
+        // Intrinsify methods.
+        new ReplaceIntrinsicsPhase(replacements).apply(graph);
         return graph;
     }
 
@@ -131,7 +239,7 @@
         for (LocalNode localNode : graph.getNodes(LocalNode.class)) {
             Stamp newStamp = localNode.stamp().meet(arguments.get(localNode.index()).stamp());
             if (!newStamp.equals(localNode.stamp())) {
-                if (TruffleCompilerOptions.TraceTruffleCompilationDetails.getValue()) {
+                if (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue()) {
                     TTY.println(String.format("[truffle] graph cache entry too specific for method %s argument %s previous stamp %s new stamp %s.", graph.method(), localNode, localNode.stamp(),
                                     newStamp));
                 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Sat Jul 06 00:29:59 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Sat Jul 06 11:56:27 2013 +0200
@@ -53,6 +53,8 @@
     public static final OptionValue<Boolean> TruffleFunctionInlining = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Integer> TruffleConstantUnrollLimit = new OptionValue<>(32);
+    @Option(help = "")
+    public static final OptionValue<Integer> TruffleOperationCacheMaxNodes = new OptionValue<>(200);
 
     // tracing
     @Option(help = "")
@@ -60,6 +62,8 @@
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleCompilationDetails = new OptionValue<>(false);
     @Option(help = "")
+    public static final OptionValue<Boolean> TraceTruffleCacheDetails = new OptionValue<>(false);
+    @Option(help = "")
     public static final OptionValue<Boolean> TruffleInlinePrinter = new OptionValue<>(false);
     @Option(help = "")
     public static final OptionValue<Boolean> TraceTruffleCompilationExceptions = new OptionValue<>(true);