changeset 16044:2662fb9c37e2

Truffle: invalidate inlining decisions on rewrites.
author Christian Humer <christian.humer@gmail.com>
date Thu, 05 Jun 2014 20:33:33 +0200
parents 369a3f9d1ceb
children a8322288e838 ebdeb414d64c
files graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningPolicy.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java
diffstat 9 files changed, 130 insertions(+), 115 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Thu Jun 05 19:13:13 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultInliningPolicy.java	Thu Jun 05 20:33:33 2014 +0200
@@ -34,9 +34,8 @@
         return profile.getFrequency() / profile.getDeepNodeCount();
     }
 
-    public boolean isAllowed(TruffleInliningProfile profile, int currentBudgetLeft) {
+    public boolean isAllowed(TruffleInliningProfile profile, int currentNodeCount) {
         if (profile.isRecursiveCall()) {
-            // recursive call found
             profile.setFailedReason(REASON_RECURSION);
             return false;
         }
@@ -45,7 +44,7 @@
             return true;
         }
 
-        if (currentBudgetLeft - profile.getDeepNodeCount() < 0) {
+        if (currentNodeCount + profile.getDeepNodeCount() > TruffleInliningMaxCallerSize.getValue()) {
             profile.setFailedReason(REASON_MAXIMUM_TOTAL_NODE_COUNT);
             return false;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Thu Jun 05 19:13:13 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Thu Jun 05 20:33:33 2014 +0200
@@ -121,6 +121,7 @@
     @Override
     public void invalidate() {
         this.runtime.invalidateInstalledCode(this);
+        invalidateInlining();
     }
 
     protected void invalidate(Node oldNode, Node newNode, CharSequence reason) {
@@ -133,6 +134,23 @@
         cancelInstalledTask(oldNode, newNode, reason);
     }
 
+    public void invalidateInlining() {
+        if (inliningPerformed) {
+            inliningPerformed = false;
+            getRootNode().accept(new NodeVisitor() {
+                public boolean visit(Node node) {
+                    if (node instanceof OptimizedDirectCallNode) {
+                        OptimizedDirectCallNode callNode = (OptimizedDirectCallNode) node;
+                        if (callNode.isInlined()) {
+                            callNode.resetInlining();
+                        }
+                    }
+                    return true;
+                }
+            });
+        }
+    }
+
     private void cancelInstalledTask(Node oldNode, Node newNode, CharSequence reason) {
         if (this.runtime.cancelInstalledTask(this)) {
             logOptimizingUnqueued(this, oldNode, newNode, reason);
@@ -242,19 +260,19 @@
             return;
         }
         TruffleInliningHandler handler = new TruffleInliningHandler(new DefaultInliningPolicy());
-        TruffleInliningResult result = handler.decideInlining(this, 0);
+        TruffleInliningDecision result = handler.decideInlining(this, 0);
         performInlining(result);
         logInliningDecision(result);
     }
 
-    private static void performInlining(TruffleInliningResult result) {
+    private static void performInlining(TruffleInliningDecision result) {
         if (result.getCallTarget().inliningPerformed) {
             return;
         }
         result.getCallTarget().inliningPerformed = true;
         for (TruffleInliningProfile profile : result) {
             profile.getCallNode().inline();
-            TruffleInliningResult recursiveResult = profile.getRecursiveResult();
+            TruffleInliningDecision recursiveResult = profile.getRecursiveResult();
             if (recursiveResult != null) {
                 performInlining(recursiveResult);
             }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Thu Jun 05 19:13:13 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTargetLog.java	Thu Jun 05 20:33:33 2014 +0200
@@ -53,7 +53,7 @@
     private OptimizedCallTargetLog() {
     }
 
-    public static void logInliningDecision(TruffleInliningResult result) {
+    public static void logInliningDecision(TruffleInliningDecision result) {
         if (!TraceTruffleInlining.getValue()) {
             return;
         }
@@ -63,7 +63,7 @@
         logInliningDone(result.getCallTarget());
     }
 
-    private static void logInliningDecisionRecursive(TruffleInliningResult result, int depth) {
+    private static void logInliningDecisionRecursive(TruffleInliningDecision result, int depth) {
         List<OptimizedDirectCallNode> callNodes = searchCallNodes(result.getCallTarget());
         for (OptimizedDirectCallNode callNode : callNodes) {
             TruffleInliningProfile profile = result.getProfiles().get(callNode);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java	Thu Jun 05 19:13:13 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedDirectCallNode.java	Thu Jun 05 20:33:33 2014 +0200
@@ -72,6 +72,14 @@
         }
     }
 
+    public void resetInlining() {
+        CompilerAsserts.neverPartOfCompilation();
+        if (inlined) {
+            inlined = false;
+            getCurrentCallTarget().invalidateInlining();
+        }
+    }
+
     @Override
     public boolean isInlinable() {
         return true;
@@ -219,4 +227,5 @@
     public static OptimizedDirectCallNode create(OptimizedCallTarget target) {
         return new OptimizedDirectCallNode(target);
     }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningDecision.java	Thu Jun 05 20:33:33 2014 +0200
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+import java.util.*;
+
+public final class TruffleInliningDecision implements Iterable<TruffleInliningProfile> {
+
+    private final OptimizedCallTarget callTarget;
+    private final Map<OptimizedDirectCallNode, TruffleInliningProfile> profiles;
+    private final Set<TruffleInliningProfile> inlined;
+    private final int nodeCount;
+
+    public TruffleInliningDecision(OptimizedCallTarget callTarget, List<TruffleInliningProfile> profiles, Set<TruffleInliningProfile> inlined, int nodeCount) {
+        this.callTarget = callTarget;
+        this.profiles = new HashMap<>();
+        for (TruffleInliningProfile profile : profiles) {
+            this.profiles.put(profile.getCallNode(), profile);
+        }
+        this.nodeCount = nodeCount;
+        this.inlined = inlined;
+    }
+
+    public Map<OptimizedDirectCallNode, TruffleInliningProfile> getProfiles() {
+        return profiles;
+    }
+
+    public int getNodeCount() {
+        return nodeCount;
+    }
+
+    public OptimizedCallTarget getCallTarget() {
+        return callTarget;
+    }
+
+    public boolean isInlined(OptimizedDirectCallNode path) {
+        return inlined.contains(profiles.get(path));
+    }
+
+    public int size() {
+        return inlined.size();
+    }
+
+    public Iterator<TruffleInliningProfile> iterator() {
+        return Collections.unmodifiableSet(inlined).iterator();
+    }
+
+    @Override
+    public String toString() {
+        return inlined.toString();
+    }
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Thu Jun 05 19:13:13 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningHandler.java	Thu Jun 05 20:33:33 2014 +0200
@@ -31,68 +31,62 @@
     private static final int MAXIMUM_RECURSIVE_DEPTH = 15;
     private static final ProfileScoreComparator INLINING_SCORE = new ProfileScoreComparator();
     private final TruffleInliningPolicy policy;
-    private final Map<OptimizedCallTarget, TruffleInliningResult> resultCache;
+    private final Map<OptimizedCallTarget, TruffleInliningDecision> resultCache;
 
     public TruffleInliningHandler(TruffleInliningPolicy policy) {
         this.policy = policy;
         this.resultCache = new HashMap<>();
     }
 
-    public TruffleInliningResult decideInlining(OptimizedCallTarget target, int depth) {
+    public TruffleInliningDecision decideInlining(OptimizedCallTarget target, int depth) {
         if (resultCache.containsKey(target)) {
             return resultCache.get(target);
         }
-        resultCache.put(target, null);
-        TruffleInliningResult result = decideInliningImpl(target, depth);
+        resultCache.put(target, null); // important for recursion detection
+        TruffleInliningDecision result = createInliningDecision(target, depth);
         resultCache.put(target, result);
         return result;
     }
 
-    private TruffleInliningResult decideInliningImpl(OptimizedCallTarget target, int depth) {
-        List<TruffleInliningProfile> profiles = lookupProfiles(target, depth);
+    private TruffleInliningDecision createInliningDecision(OptimizedCallTarget target, int depth) {
+        List<TruffleInliningProfile> profiles = createProfiles(target, depth);
         Set<TruffleInliningProfile> inlined = new HashSet<>();
         Collections.sort(profiles, INLINING_SCORE);
-        int budget = TruffleCompilerOptions.TruffleInliningMaxCallerSize.getValue() - OptimizedCallUtils.countNonTrivialNodes(target, true);
+        int deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true);
         int index = 0;
+
         for (TruffleInliningProfile profile : profiles) {
             profile.setQueryIndex(index++);
-            if (policy.isAllowed(profile, budget)) {
+            if (policy.isAllowed(profile, deepNodeCount)) {
                 inlined.add(profile);
-                budget -= profile.getDeepNodeCount();
+                deepNodeCount += profile.getDeepNodeCount();
             }
         }
 
-        int deepNodeCount = TruffleCompilerOptions.TruffleInliningMaxCallerSize.getValue() - budget;
-        return new TruffleInliningResult(target, profiles, inlined, deepNodeCount);
+        return new TruffleInliningDecision(target, profiles, inlined, deepNodeCount);
     }
 
-    private List<TruffleInliningProfile> lookupProfiles(final OptimizedCallTarget target, int depth) {
-        final List<OptimizedDirectCallNode> callNodes = new ArrayList<>();
+    private List<TruffleInliningProfile> createProfiles(final OptimizedCallTarget target, final int depth) {
+        final List<TruffleInliningProfile> profiles = new ArrayList<>();
         target.getRootNode().accept(new NodeVisitor() {
             public boolean visit(Node node) {
                 if (node instanceof OptimizedDirectCallNode) {
-                    callNodes.add((OptimizedDirectCallNode) node);
+                    profiles.add(createProfile(target, (OptimizedDirectCallNode) node, depth));
                 }
                 return true;
             }
         });
-        final List<TruffleInliningProfile> profiles = new ArrayList<>();
-        for (OptimizedDirectCallNode callNode : callNodes) {
-            profiles.add(lookupProfile(target, callNode, depth));
-        }
         return profiles;
     }
 
-    public TruffleInliningProfile lookupProfile(OptimizedCallTarget parentTarget, OptimizedDirectCallNode ocn, int depth) {
+    public TruffleInliningProfile createProfile(OptimizedCallTarget parentTarget, OptimizedDirectCallNode ocn, int depth) {
         OptimizedCallTarget target = ocn.getCurrentCallTarget();
 
-        int callSites = ocn.getCurrentCallTarget().getKnownCallSiteCount();
         int nodeCount = OptimizedCallUtils.countNonTrivialNodes(target, false);
         double frequency = calculateFrequency(parentTarget, ocn);
-        boolean forced = ocn.isInliningForced();
 
         int deepNodeCount;
-        TruffleInliningResult recursiveResult;
+        TruffleInliningDecision recursiveResult;
         boolean recursiveCall = false;
         if (target.inliningPerformed || depth > MAXIMUM_RECURSIVE_DEPTH) {
             deepNodeCount = OptimizedCallUtils.countNonTrivialNodes(target, true);
@@ -107,7 +101,7 @@
             }
         }
 
-        TruffleInliningProfile profile = new TruffleInliningProfile(ocn, callSites, nodeCount, deepNodeCount, frequency, forced, recursiveCall, recursiveResult);
+        TruffleInliningProfile profile = new TruffleInliningProfile(ocn, nodeCount, deepNodeCount, frequency, recursiveCall, recursiveResult);
         profile.setScore(policy.calculateScore(profile));
         return profile;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningPolicy.java	Thu Jun 05 19:13:13 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningPolicy.java	Thu Jun 05 20:33:33 2014 +0200
@@ -24,7 +24,7 @@
 
 public interface TruffleInliningPolicy {
 
-    boolean isAllowed(TruffleInliningProfile profile, int currentBudgetLeft);
+    boolean isAllowed(TruffleInliningProfile profile, int currentNodeCount);
 
     double calculateScore(TruffleInliningProfile profile);
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Thu Jun 05 19:13:13 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Thu Jun 05 20:33:33 2014 +0200
@@ -29,25 +29,20 @@
     private final OptimizedDirectCallNode callNode;
     private final int nodeCount;
     private final int deepNodeCount;
-    private final int callSites;
     private final double frequency;
-    private final boolean forced;
     private final boolean recursiveCall;
-    private final TruffleInliningResult recursiveResult;
+    private final TruffleInliningDecision recursiveResult;
 
     private String failedReason;
     private int queryIndex = -1;
     private double score;
 
-    public TruffleInliningProfile(OptimizedDirectCallNode callNode, int callSites, int nodeCount, int deepNodeCount, double frequency, boolean forced, boolean recursiveCall,
-                    TruffleInliningResult recursiveResult) {
+    public TruffleInliningProfile(OptimizedDirectCallNode callNode, int nodeCount, int deepNodeCount, double frequency, boolean recursiveCall, TruffleInliningDecision recursiveResult) {
         this.callNode = callNode;
-        this.callSites = callSites;
         this.nodeCount = nodeCount;
         this.deepNodeCount = deepNodeCount;
         this.frequency = frequency;
         this.recursiveCall = recursiveCall;
-        this.forced = forced;
         this.recursiveResult = recursiveResult;
     }
 
@@ -60,14 +55,14 @@
     }
 
     public int getCallSites() {
-        return callSites;
+        return callNode.getCurrentCallTarget().getKnownCallSiteCount();
     }
 
     public int getNodeCount() {
         return nodeCount;
     }
 
-    public TruffleInliningResult getRecursiveResult() {
+    public TruffleInliningDecision getRecursiveResult() {
         return recursiveResult;
     }
 
@@ -96,7 +91,7 @@
     }
 
     public boolean isForced() {
-        return forced;
+        return callNode.isInliningForced();
     }
 
     public double getFrequency() {
@@ -112,7 +107,7 @@
         properties.put("nodeCount", String.format("%5d/%5d", deepNodeCount, nodeCount));
         properties.put("frequency", frequency);
         properties.put("score", String.format("%8.4f", getScore()));
-        properties.put(String.format("index=%3d, force=%s, callSites=%2d", queryIndex, (forced ? "Y" : "N"), callSites), "");
+        properties.put(String.format("index=%3d, force=%s, callSites=%2d", queryIndex, (isForced() ? "Y" : "N"), getCallSites()), "");
         properties.put("reason", failedReason);
         return properties;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningResult.java	Thu Jun 05 19:13:13 2014 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +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;
-
-import java.util.*;
-
-public final class TruffleInliningResult implements Iterable<TruffleInliningProfile> {
-
-    private final OptimizedCallTarget callTarget;
-    private final Map<OptimizedDirectCallNode, TruffleInliningProfile> profiles;
-    private final Set<TruffleInliningProfile> inlined;
-    private final int nodeCount;
-
-    public TruffleInliningResult(OptimizedCallTarget callTarget, List<TruffleInliningProfile> profiles, Set<TruffleInliningProfile> inlined, int nodeCount) {
-        this.callTarget = callTarget;
-        this.profiles = new HashMap<>();
-        for (TruffleInliningProfile profile : profiles) {
-            this.profiles.put(profile.getCallNode(), profile);
-        }
-        this.nodeCount = nodeCount;
-        this.inlined = inlined;
-    }
-
-    public Map<OptimizedDirectCallNode, TruffleInliningProfile> getProfiles() {
-        return profiles;
-    }
-
-    public int getNodeCount() {
-        return nodeCount;
-    }
-
-    public OptimizedCallTarget getCallTarget() {
-        return callTarget;
-    }
-
-    public boolean isInlined(OptimizedDirectCallNode path) {
-        return inlined.contains(profiles.get(path));
-    }
-
-    public int size() {
-        return inlined.size();
-    }
-
-    public Iterator<TruffleInliningProfile> iterator() {
-        return Collections.unmodifiableSet(inlined).iterator();
-    }
-
-    @Override
-    public String toString() {
-        return inlined.toString();
-    }
-}