# HG changeset patch # User Thomas Wuerthinger # Date 1373104587 -7200 # Node ID 549a7568ce14c0bff972b788c9e9de5f98530a64 # Parent 1546866ebb8d1ea186ae703f652b015d9c76b73b Introduce new Truffle compiler options: TruffleOperationCacheMaxNodes and TraceTruffleCompilationExceptions Perform inlining for cached Truffle graphs. diff -r 1546866ebb8d -r 549a7568ce14 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java --- 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(); diff -r 1546866ebb8d -r 549a7568ce14 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java --- 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()); } } diff -r 1546866ebb8d -r 549a7568ce14 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java --- 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 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 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() { + + 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)); } diff -r 1546866ebb8d -r 549a7568ce14 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java --- 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 TruffleFunctionInlining = new OptionValue<>(true); @Option(help = "") public static final OptionValue TruffleConstantUnrollLimit = new OptionValue<>(32); + @Option(help = "") + public static final OptionValue TruffleOperationCacheMaxNodes = new OptionValue<>(200); // tracing @Option(help = "") @@ -60,6 +62,8 @@ @Option(help = "") public static final OptionValue TraceTruffleCompilationDetails = new OptionValue<>(false); @Option(help = "") + public static final OptionValue TraceTruffleCacheDetails = new OptionValue<>(false); + @Option(help = "") public static final OptionValue TruffleInlinePrinter = new OptionValue<>(false); @Option(help = "") public static final OptionValue TraceTruffleCompilationExceptions = new OptionValue<>(true);