changeset 16150:f98b033b6050

[inliner] propagating fresh-instantiation info through call-hierarchy
author Miguel Garcia <miguel.m.garcia@oracle.com>
date Wed, 18 Jun 2014 14:12:06 +0200
parents c64c5f5913fd
children 76895499bc88
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java
diffstat 4 files changed, 187 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Sat Jun 14 17:10:43 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/Inlineable.java	Wed Jun 18 14:12:06 2014 +0200
@@ -32,6 +32,8 @@
 public interface Inlineable {
 
     static Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+        assert method != null;
+        assert invoke != null;
         Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
         if (macroNodeClass != null) {
             return new InlineableMacroNode(macroNodeClass);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Sat Jun 14 17:10:43 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Wed Jun 18 14:12:06 2014 +0200
@@ -24,12 +24,10 @@
 
 import com.oracle.graal.api.meta.MetaUtil;
 import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.FixedNode;
-import com.oracle.graal.nodes.Invoke;
-import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.graph.FixedNodeProbabilityCache;
 
-import java.util.LinkedList;
+import java.util.*;
 import java.util.function.ToDoubleFunction;
 
 import static com.oracle.graal.compiler.common.GraalOptions.CapInheritedRelevance;
@@ -52,19 +50,30 @@
  */
 public final class CallsiteHolderExplorable extends CallsiteHolder {
 
+    /**
+     * Graph in which inlining may be performed at one or more of the callsites containined in
+     * {@link #remainingInvokes}
+     */
     private final StructuredGraph graph;
+
     private final LinkedList<Invoke> remainingInvokes;
     private final double probability;
     private final double relevance;
 
+    /**
+     * @see #getFixedParams()
+     */
+    private final Set<ParameterNode> fixedParams;
+
     private final ToDoubleFunction<FixedNode> probabilities;
     private final ComputeInliningRelevance computeInliningRelevance;
 
-    public CallsiteHolderExplorable(StructuredGraph graph, double probability, double relevance) {
+    public CallsiteHolderExplorable(StructuredGraph graph, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
         assert graph != null;
         this.graph = graph;
         this.probability = probability;
         this.relevance = relevance;
+        this.fixedParams = fixedParamsAt(freshlyInstantiatedArguments);
         remainingInvokes = new InliningIterator(graph).apply();
         if (remainingInvokes.isEmpty()) {
             probabilities = null;
@@ -74,6 +83,65 @@
             computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
             computeProbabilities();
         }
+        assert repOK();
+    }
+
+    /**
+     * @see #getFixedParams()
+     */
+    @SuppressWarnings("unchecked")
+    private Set<ParameterNode> fixedParamsAt(BitSet freshlyInstantiatedArguments) {
+        if (freshlyInstantiatedArguments == null || freshlyInstantiatedArguments.isEmpty()) {
+            return Collections.EMPTY_SET;
+        }
+        Set<ParameterNode> result = new HashSet<>();
+        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+            if (freshlyInstantiatedArguments.get(p.index())) {
+                result.add(p);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * <p>
+     * Parameters for which the callsite targeting {@link #graph()} provides "fixed" arguments. That
+     * callsite isn't referenced by this instance. Instead, it belongs to the graph of the caller of
+     * this {@link CallsiteHolderExplorable}
+     * </p>
+     *
+     * <p>
+     * Constant arguments don't contribute to fixed-params: those params have been removed already,
+     * see {@link com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph}.
+     * </p>
+     *
+     * <p>
+     * Instead, fixed-params are those receiving freshly instantiated arguments (possibly
+     * instantiated several levels up in the call-hierarchy)
+     * </p>
+     * */
+    public Set<ParameterNode> getFixedParams() {
+        return fixedParams;
+    }
+
+    public boolean repOK() {
+        for (Invoke invoke : remainingInvokes) {
+            if (!invoke.asNode().isAlive() || !containsInvoke(invoke)) {
+                assert false;
+                return false;
+            }
+            if (!allArgsNonNull(invoke)) {
+                assert false;
+                return false;
+            }
+        }
+        for (ParameterNode fixedParam : fixedParams) {
+            if (!containsParam(fixedParam)) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
     }
 
     @Override
@@ -99,6 +167,16 @@
         remainingInvokes.push(invoke);
     }
 
+    public static boolean allArgsNonNull(Invoke invoke) {
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            if (arg == null) {
+                assert false;
+                return false;
+            }
+        }
+        return true;
+    }
+
     public boolean containsInvoke(Invoke invoke) {
         for (Invoke i : graph().getInvokes()) {
             if (i == invoke) {
@@ -108,6 +186,15 @@
         return false;
     }
 
+    public boolean containsParam(ParameterNode param) {
+        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+            if (p == param) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     public void computeProbabilities() {
         computeInliningRelevance.compute();
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Sat Jun 14 17:10:43 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Wed Jun 18 14:12:06 2014 +0200
@@ -34,7 +34,9 @@
 import com.oracle.graal.graph.Graph;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.AbstractNewObjectNode;
 import com.oracle.graal.nodes.java.MethodCallTargetNode;
+import com.oracle.graal.nodes.virtual.VirtualObjectNode;
 import com.oracle.graal.phases.OptimisticOptimizations;
 import com.oracle.graal.phases.common.CanonicalizerPhase;
 import com.oracle.graal.phases.common.inlining.InliningUtil;
@@ -110,8 +112,12 @@
         this.maxGraphs = 1;
 
         Assumptions rootAssumptions = context.getAssumptions();
-        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
-        graphQueue.push(new CallsiteHolderExplorable(rootGraph, 1.0, 1.0));
+        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0, null));
+        graphQueue.push(new CallsiteHolderExplorable(rootGraph, 1.0, 1.0, null));
+    }
+
+    public static boolean isFreshInstantiation(ValueNode arg) {
+        return (arg instanceof AbstractNewObjectNode) || (arg instanceof VirtualObjectNode);
     }
 
     private String checkTargetConditionsHelper(ResolvedJavaMethod method) {
@@ -468,11 +474,53 @@
             info.populateInlinableElements(context, calleeAssumptions, canonicalizer);
             double invokeProbability = callsiteHolder.invokeProbability(invoke);
             double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
-            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance);
+            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance, freshlyInstantiatedArguments(invoke, callsiteHolder.getFixedParams()));
             pushInvocationAndGraphs(methodInvocation);
         }
     }
 
+    /**
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(com.oracle.graal.nodes.ValueNode)}</li>
+     * <li>a fixed-param, ie a {@link ParameterNode} receiving a freshly instantiated argument</li>
+     * </uL>
+     * </p>
+     *
+     * @return the positions of freshly instantiated arguments in the argument list of the
+     *         <code>invoke</code>, or null if no such positions exist.
+     */
+    public static BitSet freshlyInstantiatedArguments(Invoke invoke, Set<ParameterNode> fixedParams) {
+        assert fixedParams != null;
+        assert paramsAndInvokeAreInSameGraph(invoke, fixedParams);
+        BitSet result = null;
+        int argIdx = 0;
+        for (ValueNode arg : invoke.callTarget().arguments()) {
+            assert arg != null;
+            if (isFreshInstantiation(arg) || fixedParams.contains(arg)) {
+                if (result == null) {
+                    result = new BitSet();
+                }
+                result.set(argIdx);
+            }
+            argIdx++;
+        }
+        return result;
+    }
+
+    private static boolean paramsAndInvokeAreInSameGraph(Invoke invoke, Set<ParameterNode> fixedParams) {
+        if (fixedParams.isEmpty()) {
+            return true;
+        }
+        for (ParameterNode p : fixedParams) {
+            if (p.graph() != invoke.asNode().graph()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public int graphCount() {
         return graphQueue.size();
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Sat Jun 14 17:10:43 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Wed Jun 18 14:12:06 2014 +0200
@@ -32,6 +32,8 @@
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
 import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
 
+import java.util.BitSet;
+
 /**
  * <p>
  * An instance of this class denotes a callsite being analyzed for inlining.
@@ -52,11 +54,39 @@
 
     private int processedGraphs;
 
-    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+    /**
+     * <p>
+     * The immutable positions of freshly instantiated arguments (ie, positions in
+     * <code>callee.invoke.callTarget.arguments</code>).
+     * </p>
+     *
+     * <p>
+     * A freshly instantiated argument is either:
+     * <uL>
+     * <li>an {@link InliningData#isFreshInstantiation(com.oracle.graal.nodes.ValueNode)}</li>
+     * <li>a fixed-param of the graph containing the callsite (ie, of <code>callee.graph()</code>
+     * that contains <code>callee.invoke</code>)</li>
+     * </uL>
+     * </p>
+     *
+     * <p>
+     * Given those positions, the
+     * {@link com.oracle.graal.phases.common.inlining.walker.CallsiteHolderExplorable} instantiated
+     * in {@link #buildCallsiteHolderForElement(int)} can determine which of <i>its</i> parameters
+     * are fixed.
+     * </p>
+     */
+    private final BitSet freshlyInstantiatedArguments;
+
+    private final int sizeFreshArgs;
+
+    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
         this.callee = info;
         this.assumptions = assumptions;
         this.probability = probability;
         this.relevance = relevance;
+        this.freshlyInstantiatedArguments = freshlyInstantiatedArguments;
+        this.sizeFreshArgs = freshlyInstantiatedArguments == null ? 0 : freshlyInstantiatedArguments.cardinality();
     }
 
     public void incrementProcessedGraphs() {
@@ -93,11 +123,21 @@
         return callee == null;
     }
 
+    public BitSet getFreshlyInstantiatedArguments() {
+        return freshlyInstantiatedArguments;
+    }
+
+    public int getSizeFreshArgs() {
+        return sizeFreshArgs;
+    }
+
     public CallsiteHolder buildCallsiteHolderForElement(int index) {
         Inlineable elem = callee.inlineableElementAt(index);
         if (elem instanceof InlineableGraph) {
             InlineableGraph ig = (InlineableGraph) elem;
-            return new CallsiteHolderExplorable(ig.getGraph(), probability * callee.probabilityAt(index), relevance * callee.relevanceAt(index));
+            final double invokeProbability = probability * callee.probabilityAt(index);
+            final double invokeRelevance = relevance * callee.relevanceAt(index);
+            return new CallsiteHolderExplorable(ig.getGraph(), invokeProbability, invokeRelevance, freshlyInstantiatedArguments);
         } else {
             assert elem instanceof InlineableMacroNode;
             return CallsiteHolderDummy.DUMMY_CALLSITE_HOLDER;