changeset 11646:8f8f6afeb97a

New caching mechanism in TruffleCache for better compilation performance. Clean up of partial evaluator phases.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 15 Sep 2013 16:27:07 +0200
parents 2278d53b4d38
children a21a54b7ead1
files graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/InlineTrivialGettersPhase.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceLoadFinalPhase.java
diffstat 6 files changed, 100 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- 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();
+    }
 }
--- 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<ValueNode> 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;
                                 }
--- 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;
     }
 }
--- 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<ResolvedJavaMethod, StructuredGraph> rawCache = new HashMap<>();
     private final HashMap<ResolvedJavaMethod, StructuredGraph> 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<ValueNode> arguments, final Assumptions assumptions) {
+    public StructuredGraph lookup(final ResolvedJavaMethod method, final NodeInputList<ValueNode> 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<StructuredGraph>() {
 
                 public StructuredGraph call() {
-                    StructuredGraph newGraph = parseGraph(method);
+                    StructuredGraph newGraph = parseGraph(method).copy();
 
                     // Get stamps from actual arguments.
                     List<Stamp> stamps = new ArrayList<>();
@@ -101,15 +104,20 @@
                     }
 
                     // Set stamps into graph before optimizing.
+                    List<Node> 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<Node> 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<Node> 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<Node> 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<Node> 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<Node> 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<StructuredGraph>() {
+
+            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<ValueNode> arguments) {
--- 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<PhaseContext> {
-
-    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);
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
--- 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())));
             }
         }
     }