# HG changeset patch # User Thomas Wuerthinger # Date 1379255227 -7200 # Node ID 8f8f6afeb97a25ab67999f8e12e983c2b72dbcb1 # Parent 2278d53b4d38ed6604c2fc2bea70b36c95d1fc61 New caching mechanism in TruffleCache for better compilation performance. Clean up of partial evaluator phases. diff -r 2278d53b4d38 -r 8f8f6afeb97a graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java --- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Sun Sep 15 16:25:03 2013 +0200 +++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java Sun Sep 15 16:27:07 2013 +0200 @@ -126,4 +126,9 @@ private static boolean checkDeoptimizations(ProfilingInfo profilingInfo, DeoptimizationReason reason) { return profilingInfo.getDeoptimizationCount(reason) < GraalOptions.DeoptsToDisableOptimisticOptimization.getValue(); } + + @Override + public String toString() { + return enabledOpts.toString(); + } } diff -r 2278d53b4d38 -r 8f8f6afeb97a 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 Sun Sep 15 16:25:03 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Sun Sep 15 16:27:07 2013 +0200 @@ -139,6 +139,8 @@ // Make sure frame does not escape. expandTree(config, graph, newFrameNode, assumptions); + new VerifyFrameDoesNotEscapePhase().apply(graph, false); + if (TruffleInlinePrinter.getValue()) { InlinePrinterProcessor.printTree(); InlinePrinterProcessor.reset(); @@ -167,19 +169,12 @@ InliningPhase inliningPhase = new InliningPhase(canonicalizer); inliningPhase.apply(graph, context); - // Convert deopt to guards. - new ConvertDeoptimizeToGuardPhase().apply(graph); - - // Canonicalize / constant propagate. - canonicalizer.apply(graph, context); - for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) { Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage()); throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception); } // EA frame and clean up. - new VerifyFrameDoesNotEscapePhase().apply(graph, false); new PartialEscapePhase(false, canonicalizer).apply(graph, context); new VerifyNoIntrinsicsLeftPhase().apply(graph, false); for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) { @@ -198,12 +193,6 @@ } } } - - // Convert deopt to guards. - new ConvertDeoptimizeToGuardPhase().apply(graph); - - // Canonicalize / constant propagate. - canonicalizer.apply(graph, context); } }); @@ -259,25 +248,12 @@ private StructuredGraph parseGraph(final ResolvedJavaMethod targetMethod, final NodeInputList arguments, final Assumptions assumptions) { - final StructuredGraph graph = truffleCache.lookup(targetMethod, arguments, assumptions); + final StructuredGraph graph = truffleCache.lookup(targetMethod, arguments, assumptions, canonicalizer); Debug.scope("parseGraph", targetMethod, new Runnable() { @Override public void run() { - // Canonicalize / constant propagate. - PhaseContext context = new PhaseContext(metaAccessProvider, assumptions, replacements); - canonicalizer.apply(graph, context); - - // Intrinsify methods. - new ReplaceIntrinsicsPhase(replacements).apply(graph); - - // Inline trivial getter methods - new InlineTrivialGettersPhase(metaAccessProvider, canonicalizer).apply(graph, context); - - // Convert deopt to guards. - new ConvertDeoptimizeToGuardPhase().apply(graph); - if (graph.hasLoops()) { boolean unrolled; do { @@ -288,9 +264,9 @@ if (ex.counted().isConstantMaxTripCount()) { long constant = ex.counted().constantMaxTripCount(); if (constant <= TruffleConstantUnrollLimit.getValue() || targetMethod.getAnnotation(ExplodeLoop.class) != null) { + PhaseContext context = new PhaseContext(metaAccessProvider, assumptions, replacements); LoopTransformations.fullUnroll(ex, context, canonicalizer); Debug.dump(graph, "After loop unrolling %d times", constant); - canonicalizer.apply(graph, context); unrolled = true; break; } diff -r 2278d53b4d38 -r 8f8f6afeb97a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Sun Sep 15 16:25:03 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java Sun Sep 15 16:27:07 2013 +0200 @@ -57,7 +57,8 @@ } private static boolean verifyFieldValue(ResolvedJavaField field, Constant constant) { - assert field.getAnnotation(Child.class) == null || constant.isNull() || constant.asObject() instanceof com.oracle.truffle.api.nodes.Node : "@Child field value must be a Node: " + field; + assert field.getAnnotation(Child.class) == null || constant.isNull() || constant.asObject() instanceof com.oracle.truffle.api.nodes.Node : "@Child field value must be a Node: " + field + + ", but was: " + constant.asObject(); return true; } } diff -r 2278d53b4d38 -r 8f8f6afeb97a 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 Sun Sep 15 16:25:03 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java Sun Sep 15 16:27:07 2013 +0200 @@ -34,6 +34,7 @@ import com.oracle.graal.debug.internal.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.Node; +import com.oracle.graal.graph.iterators.*; import com.oracle.graal.java.*; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; @@ -48,6 +49,7 @@ import com.oracle.graal.virtual.phases.ea.*; import com.oracle.truffle.api.*; import com.oracle.truffle.api.nodes.*; +import com.oracle.truffle.api.nodes.Node.*; /** * Implementation of a cache for Truffle graphs for improving partial evaluation time. @@ -59,6 +61,7 @@ private final OptimisticOptimizations optimisticOptimizations; private final Replacements replacements; + private final HashMap rawCache = new HashMap<>(); private final HashMap cache = new HashMap<>(); public TruffleCache(MetaAccessProvider metaAccessProvider, GraphBuilderConfiguration config, OptimisticOptimizations optimisticOptimizations, Replacements replacements) { @@ -68,7 +71,7 @@ this.replacements = replacements; } - public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions) { + public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList arguments, final Assumptions assumptions, final CanonicalizerPhase finalCanonicalizer) { StructuredGraph resultGraph = null; if (cache.containsKey(method)) { @@ -82,7 +85,7 @@ resultGraph = Debug.sandbox("TruffleCache", new Object[]{metaAccessProvider, method}, DebugScope.getConfig(), new Callable() { public StructuredGraph call() { - StructuredGraph newGraph = parseGraph(method); + StructuredGraph newGraph = parseGraph(method).copy(); // Get stamps from actual arguments. List stamps = new ArrayList<>(); @@ -101,15 +104,20 @@ } // Set stamps into graph before optimizing. + List modifiedLocals = new ArrayList<>(arguments.size()); for (LocalNode localNode : newGraph.getNodes(LocalNode.class)) { int index = localNode.index(); Stamp stamp = stamps.get(index); - localNode.setStamp(stamp); + + if (!stamp.equals(localNode.stamp())) { + localNode.setStamp(stamp); + modifiedLocals.add(localNode); + } } Assumptions tmpAssumptions = new Assumptions(false); - optimizeGraph(newGraph, tmpAssumptions); + optimizeGraph(newGraph, tmpAssumptions, newGraph.getNodes().snapshot()); PhaseContext context = new PhaseContext(metaAccessProvider, tmpAssumptions, replacements); PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, new CanonicalizerPhase(!AOTCompilation.getValue())); @@ -124,6 +132,8 @@ }); } + // histogram.add(resultGraph); + final StructuredGraph clonedResultGraph = resultGraph.copy(); Debug.sandbox("TruffleCacheConstants", new Object[]{metaAccessProvider, method}, DebugScope.getConfig(), new Runnable() { @@ -131,24 +141,64 @@ public void run() { Debug.dump(clonedResultGraph, "before applying constants"); + List modifiedLocals = new ArrayList<>(arguments.size()); // Pass on constant arguments. for (LocalNode local : clonedResultGraph.getNodes(LocalNode.class)) { ValueNode arg = arguments.get(local.index()); if (arg.isConstant()) { Constant constant = arg.asConstant(); - local.replaceAndDelete(ConstantNode.forConstant(constant, metaAccessProvider, clonedResultGraph)); - } else { + ConstantNode constantNode = ConstantNode.forConstant(constant, metaAccessProvider, clonedResultGraph); + local.replaceAndDelete(constantNode); + modifiedLocals.add(constantNode); + } else if (!local.stamp().equals(arg.stamp())) { local.setStamp(arg.stamp()); + modifiedLocals.add(local); } } Debug.dump(clonedResultGraph, "after applying constants"); - optimizeGraph(clonedResultGraph, assumptions); + List modifiedLocalsUsages = new ArrayList<>(modifiedLocals.size() * 2); + for (Node local : modifiedLocals) { + for (Node usage : local.usages()) { + if (usage instanceof Canonicalizable) { + modifiedLocalsUsages.add(usage); + } + } + } + optimizeGraph(clonedResultGraph, assumptions, modifiedLocalsUsages); + + modifiedLocalsUsages.clear(); + for (Node local : modifiedLocals) { + for (Node usage : local.usages()) { + if (usage instanceof Canonicalizable) { + modifiedLocalsUsages.add(usage); + } + } + } + + int newNodesMark = clonedResultGraph.getMark(); + new ReplaceLoadFinalPhase().apply(clonedResultGraph); + for (Node n : clonedResultGraph.getNewNodes(newNodesMark)) { + if (n instanceof Canonicalizable) { + modifiedLocalsUsages.add(n); + } + } + finalCanonicalizer.applyIncremental(clonedResultGraph, new PhaseContext(metaAccessProvider, assumptions, replacements), modifiedLocalsUsages); + + for (Node n : clonedResultGraph.getNodes()) { + if (n instanceof LoadFieldNode) { + LoadFieldNode loadFieldNode = (LoadFieldNode) n; + if (loadFieldNode.field().getAnnotation(Child.class) != null) { + throw new RuntimeException("found remaining child load field "); + } + + } + } } }); return clonedResultGraph; } - private void optimizeGraph(StructuredGraph newGraph, Assumptions assumptions) { + private void optimizeGraph(StructuredGraph newGraph, Assumptions assumptions, Iterable changedNodes) { PhaseContext context = new PhaseContext(metaAccessProvider, assumptions, replacements); ConditionalEliminationPhase conditionalEliminationPhase = new ConditionalEliminationPhase(metaAccessProvider); ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase = new ConvertDeoptimizeToGuardPhase(); @@ -157,20 +207,21 @@ int maxNodes = TruffleCompilerOptions.TruffleOperationCacheMaxNodes.getValue(); - contractGraph(newGraph, conditionalEliminationPhase, convertDeoptimizeToGuardPhase, canonicalizerPhase, readEliminationPhase, context); + contractGraph(newGraph, conditionalEliminationPhase, convertDeoptimizeToGuardPhase, canonicalizerPhase, readEliminationPhase, changedNodes, context); while (newGraph.getNodeCount() <= maxNodes) { int mark = newGraph.getMark(); expandGraph(newGraph, maxNodes); + NodeIterable newNodes = newGraph.getNewNodes(mark); - if (newGraph.getNewNodes(mark).count() == 0) { + if (newNodes.isEmpty()) { // No progress => exit iterative optimization. break; } - contractGraph(newGraph, conditionalEliminationPhase, convertDeoptimizeToGuardPhase, canonicalizerPhase, readEliminationPhase, context); + contractGraph(newGraph, conditionalEliminationPhase, convertDeoptimizeToGuardPhase, canonicalizerPhase, readEliminationPhase, newNodes, context); } if (newGraph.getNodeCount() > maxNodes && (TruffleCompilerOptions.TraceTruffleCacheDetails.getValue() || TruffleCompilerOptions.TraceTrufflePerformanceWarnings.getValue())) { @@ -179,11 +230,10 @@ } private static void contractGraph(StructuredGraph newGraph, ConditionalEliminationPhase conditionalEliminationPhase, ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase, - CanonicalizerPhase canonicalizerPhase, EarlyReadEliminationPhase readEliminationPhase, PhaseContext context) { - new ReplaceLoadFinalPhase().apply(newGraph); + CanonicalizerPhase canonicalizerPhase, EarlyReadEliminationPhase readEliminationPhase, Iterable newNodes, PhaseContext context) { // Canonicalize / constant propagate. - canonicalizerPhase.apply(newGraph, context); + canonicalizerPhase.applyIncremental(newGraph, context, newNodes); // Early read eliminiation readEliminationPhase.apply(newGraph, context); @@ -298,12 +348,29 @@ return invoke.asNode(); } - 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; + private StructuredGraph parseGraph(final ResolvedJavaMethod method) { + if (rawCache.containsKey(method)) { + return rawCache.get(method); + } + + StructuredGraph resultGraph = Debug.sandbox("InnerTruffleCache", new Object[]{metaAccessProvider, method}, DebugScope.getConfig(), new Callable() { + + public StructuredGraph call() { + final StructuredGraph graph = new StructuredGraph(method); + new GraphBuilderPhase(metaAccessProvider, config, optimisticOptimizations).apply(graph); + // Intrinsify methods. + new ReplaceIntrinsicsPhase(replacements).apply(graph); + for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) { + if (d.getDeoptimizationReason() == DeoptimizationReason.Unresolved) { + // Cannot store this graph. + return graph; + } + } + rawCache.put(method, graph); + return graph; + } + }); + return resultGraph; } private static boolean checkArgumentStamps(StructuredGraph graph, NodeInputList arguments) { diff -r 2278d53b4d38 -r 8f8f6afeb97a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/InlineTrivialGettersPhase.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/InlineTrivialGettersPhase.java Sun Sep 15 16:25:03 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2013, 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.phases; - -import com.oracle.graal.api.meta.*; -import com.oracle.graal.debug.*; -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.phases.*; -import com.oracle.graal.phases.common.*; -import com.oracle.graal.phases.tiers.*; -import com.oracle.graal.truffle.*; - -/** - * Inline all trivial getters (i.e. simple field loads). - */ -public class InlineTrivialGettersPhase extends BasePhase { - - private static final int TRIVIAL_GETTER_SIZE = 5; - private final MetaAccessProvider metaAccessProvider; - private final CanonicalizerPhase canonicalizer; - - public InlineTrivialGettersPhase(MetaAccessProvider metaAccessProvider, CanonicalizerPhase canonicalizer) { - this.metaAccessProvider = metaAccessProvider; - this.canonicalizer = canonicalizer; - } - - @Override - protected void run(StructuredGraph graph, PhaseContext context) { - for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) { - if (methodCallTarget.isAlive()) { - InvokeKind invokeKind = methodCallTarget.invokeKind(); - if (invokeKind == InvokeKind.Special) { - ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod(); - if (methodCallTarget.receiver().isConstant() && !methodCallTarget.receiver().isNullConstant()) { - if (targetMethod.getCodeSize() == TRIVIAL_GETTER_SIZE && targetMethod.getDeclaringClass().isInitialized() && targetMethod.getName().startsWith("get")) { - StructuredGraph inlineGraph = new StructuredGraph(targetMethod); - new GraphBuilderPhase(metaAccessProvider, GraphBuilderConfiguration.getDefault(), TruffleCompilerImpl.Optimizations).apply(inlineGraph); - int mark = graph.getMark(); - InliningUtil.inline(methodCallTarget.invoke(), inlineGraph, false); - Debug.dump(graph, "After inlining trivial getter %s", targetMethod.toString()); - canonicalizer.applyIncremental(graph, context, mark); - } - } - } - } - } - } -} diff -r 2278d53b4d38 -r 8f8f6afeb97a graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceLoadFinalPhase.java --- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceLoadFinalPhase.java Sun Sep 15 16:25:03 2013 +0200 +++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceLoadFinalPhase.java Sun Sep 15 16:27:07 2013 +0200 @@ -42,6 +42,8 @@ if (!loadFieldNode.isStatic() && isCompilationFinal(loadFieldNode.field())) { graph.replaceFixedWithFixed(loadIndexedNode, graph.add(new LoadIndexedFinalNode(loadIndexedNode.array(), loadIndexedNode.index(), loadIndexedNode.elementKind()))); } + } else if (loadIndexedNode.array() instanceof ConstantNode) { + graph.replaceFixedWithFixed(loadIndexedNode, graph.add(new LoadIndexedFinalNode(loadIndexedNode.array(), loadIndexedNode.index(), loadIndexedNode.elementKind()))); } } }