changeset 15686:26cedd987c83

[inlining] moved class InliningData to package with related classes
author Miguel Garcia <miguel.m.garcia@oracle.com>
date Thu, 15 May 2014 15:45:29 +0200
parents 947f62e98c07
children ce1444862ec2
files graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/DepthSearchUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java
diffstat 4 files changed, 338 insertions(+), 301 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/DepthSearchUtil.java	Thu May 15 15:41:43 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/DepthSearchUtil.java	Thu May 15 15:45:29 2014 +0200
@@ -45,7 +45,7 @@
         // no instances
     }
 
-    static InliningUtil.Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
+    public static InliningUtil.Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context, CanonicalizerPhase canonicalizer) {
         Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
         if (macroNodeClass != null) {
             return new InliningUtil.InlineableMacroNode(macroNodeClass);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Thu May 15 15:41:43 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Thu May 15 15:45:29 2014 +0200
@@ -22,32 +22,19 @@
  */
 package com.oracle.graal.phases.common.inlining;
 
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
 import java.util.*;
 import java.util.function.*;
 
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.Graph.Mark;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.common.inlining.info.InlineInfo;
-import com.oracle.graal.phases.common.inlining.InliningUtil.Inlineable;
-import com.oracle.graal.phases.common.inlining.InliningUtil.InlineableGraph;
-import com.oracle.graal.phases.common.inlining.InliningUtil.InlineableMacroNode;
 import com.oracle.graal.phases.common.inlining.policy.GreedyInliningPolicy;
 import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
 import com.oracle.graal.phases.common.inlining.walker.CallsiteHolder;
+import com.oracle.graal.phases.common.inlining.walker.InliningData;
 import com.oracle.graal.phases.common.inlining.walker.MethodInvocation;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
 
 public class InliningPhase extends AbstractInliningPhase {
 
@@ -89,7 +76,8 @@
     /**
      * <p>
      * The space of inlining decisions is explored depth-first with the help of a stack realized by
-     * {@link InliningData}. At any point in time, its topmost element consist of:
+     * {@link com.oracle.graal.phases.common.inlining.walker.InliningData}. At any point in time,
+     * its topmost element consist of:
      * <ul>
      * <li>
      * one or more {@link CallsiteHolder}s of inlining candidates, all of them corresponding to a
@@ -127,7 +115,8 @@
      * <li>
      * try to inline: move past the current inlining candidate (remove it from the topmost element).
      * If that was the last one then try to inline the callsite that is (still) in the topmost
-     * element of {@link InliningData}, and then remove such callsite.</li>
+     * element of {@link com.oracle.graal.phases.common.inlining.walker.InliningData}, and then
+     * remove such callsite.</li>
      * </ol>
      * </p>
      *
@@ -165,287 +154,4 @@
         assert data.graphCount() == 0;
     }
 
-    /**
-     * Holds the data for building the callee graphs recursively: graphs and invocations (each
-     * invocation can have multiple graphs).
-     */
-    static class InliningData {
-
-        private static final CallsiteHolder DUMMY_CALLSITE_HOLDER = new CallsiteHolder(null, 1.0, 1.0);
-        // Metrics
-        private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
-        private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
-        private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
-
-        /**
-         * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
-         */
-        private final ArrayDeque<CallsiteHolder> graphQueue;
-        private final ArrayDeque<MethodInvocation> invocationQueue;
-        private final int maxMethodPerInlining;
-        private final CanonicalizerPhase canonicalizer;
-        private final InliningPolicy inliningPolicy;
-
-        private int maxGraphs;
-
-        public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions, int maxMethodPerInlining, CanonicalizerPhase canonicalizer, InliningPolicy inliningPolicy) {
-            assert rootGraph != null;
-            this.graphQueue = new ArrayDeque<>();
-            this.invocationQueue = new ArrayDeque<>();
-            this.maxMethodPerInlining = maxMethodPerInlining;
-            this.canonicalizer = canonicalizer;
-            this.inliningPolicy = inliningPolicy;
-            this.maxGraphs = 1;
-
-            invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
-            pushGraph(rootGraph, 1.0, 1.0);
-        }
-
-        private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInfo, Assumptions callerAssumptions, HighTierContext context) {
-            StructuredGraph callerGraph = callerCallsiteHolder.graph();
-            Mark markBeforeInlining = callerGraph.getMark();
-            InlineInfo callee = calleeInfo.callee();
-            try {
-                try (Scope scope = Debug.scope("doInline", callerGraph)) {
-                    List<Node> invokeUsages = callee.invoke().asNode().usages().snapshot();
-                    callee.inline(new Providers(context), callerAssumptions);
-                    callerAssumptions.record(calleeInfo.assumptions());
-                    metricInliningRuns.increment();
-                    Debug.dump(callerGraph, "after %s", callee);
-
-                    if (OptCanonicalizer.getValue()) {
-                        Mark markBeforeCanonicalization = callerGraph.getMark();
-                        canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
-
-                        // process invokes that are possibly created during canonicalization
-                        for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
-                            if (newNode instanceof Invoke) {
-                                callerCallsiteHolder.pushInvoke((Invoke) newNode);
-                            }
-                        }
-                    }
-
-                    callerCallsiteHolder.computeProbabilities();
-
-                    metricInliningPerformed.increment();
-                }
-            } catch (BailoutException bailout) {
-                throw bailout;
-            } catch (AssertionError | RuntimeException e) {
-                throw new GraalInternalError(e).addContext(callee.toString());
-            } catch (GraalInternalError e) {
-                throw e.addContext(callee.toString());
-            }
-        }
-
-        /**
-         * @return true iff inlining was actually performed
-         */
-        private boolean tryToInline(ToDoubleFunction<FixedNode> probabilities, CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth,
-                        HighTierContext context) {
-            InlineInfo callee = calleeInfo.callee();
-            Assumptions callerAssumptions = parentInvocation.assumptions();
-            metricInliningConsidered.increment();
-
-            if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) {
-                doInline(callerCallsiteHolder, calleeInfo, callerAssumptions, context);
-                return true;
-            }
-
-            if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
-                callee.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
-            }
-
-            return false;
-        }
-
-        /**
-         * Process the next invoke and enqueue all its graphs for processing.
-         */
-        void processNextInvoke(HighTierContext context) {
-            CallsiteHolder callsiteHolder = currentGraph();
-            Invoke invoke = callsiteHolder.popInvoke();
-            MethodInvocation callerInvocation = currentInvocation();
-            Assumptions parentAssumptions = callerInvocation.assumptions();
-            InlineInfo info = InliningUtil.getInlineInfo(this, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations());
-
-            if (info != null) {
-                double invokeProbability = callsiteHolder.invokeProbability(invoke);
-                double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
-                MethodInvocation calleeInvocation = pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
-
-                for (int i = 0; i < info.numberOfMethods(); i++) {
-                    Inlineable elem = DepthSearchUtil.getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()), canonicalizer);
-                    info.setInlinableElement(i, elem);
-                    if (elem instanceof InlineableGraph) {
-                        pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
-                    } else {
-                        assert elem instanceof InlineableMacroNode;
-                        pushDummyGraph();
-                    }
-                }
-            }
-        }
-
-        public int graphCount() {
-            return graphQueue.size();
-        }
-
-        private void pushGraph(StructuredGraph graph, double probability, double relevance) {
-            assert graph != null;
-            assert !contains(graph);
-            graphQueue.push(new CallsiteHolder(graph, probability, relevance));
-            assert graphQueue.size() <= maxGraphs;
-        }
-
-        private void pushDummyGraph() {
-            graphQueue.push(DUMMY_CALLSITE_HOLDER);
-        }
-
-        public boolean hasUnprocessedGraphs() {
-            return !graphQueue.isEmpty();
-        }
-
-        public CallsiteHolder currentGraph() {
-            return graphQueue.peek();
-        }
-
-        public void popGraph() {
-            graphQueue.pop();
-            assert graphQueue.size() <= maxGraphs;
-        }
-
-        public void popGraphs(int count) {
-            assert count >= 0;
-            for (int i = 0; i < count; i++) {
-                graphQueue.pop();
-            }
-        }
-
-        private static final Object[] NO_CONTEXT = {};
-
-        /**
-         * Gets the call hierarchy of this inlining from outer most call to inner most callee.
-         */
-        public Object[] inliningContext() {
-            if (!Debug.isDumpEnabled()) {
-                return NO_CONTEXT;
-            }
-            Object[] result = new Object[graphQueue.size()];
-            int i = 0;
-            for (CallsiteHolder g : graphQueue) {
-                result[i++] = g.method();
-            }
-            return result;
-        }
-
-        public MethodInvocation currentInvocation() {
-            return invocationQueue.peekFirst();
-        }
-
-        private MethodInvocation pushInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
-            MethodInvocation methodInvocation = new MethodInvocation(info, new Assumptions(assumptions.useOptimisticAssumptions()), probability, relevance);
-            invocationQueue.addFirst(methodInvocation);
-            maxGraphs += info.numberOfMethods();
-            assert graphQueue.size() <= maxGraphs;
-            return methodInvocation;
-        }
-
-        public void popInvocation() {
-            maxGraphs -= invocationQueue.peekFirst().callee().numberOfMethods();
-            assert graphQueue.size() <= maxGraphs;
-            invocationQueue.removeFirst();
-        }
-
-        public int countRecursiveInlining(ResolvedJavaMethod method) {
-            int count = 0;
-            for (CallsiteHolder callsiteHolder : graphQueue) {
-                if (method.equals(callsiteHolder.method())) {
-                    count++;
-                }
-            }
-            return count;
-        }
-
-        public int inliningDepth() {
-            assert invocationQueue.size() > 0;
-            return invocationQueue.size() - 1;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder result = new StringBuilder("Invocations: ");
-
-            for (MethodInvocation invocation : invocationQueue) {
-                if (invocation.callee() != null) {
-                    result.append(invocation.callee().numberOfMethods());
-                    result.append("x ");
-                    result.append(invocation.callee().invoke());
-                    result.append("; ");
-                }
-            }
-
-            result.append("\nGraphs: ");
-            for (CallsiteHolder graph : graphQueue) {
-                result.append(graph.graph());
-                result.append("; ");
-            }
-
-            return result.toString();
-        }
-
-        private boolean contains(StructuredGraph graph) {
-            for (CallsiteHolder info : graphQueue) {
-                if (info.graph() == graph) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        /**
-         * @return true iff inlining was actually performed
-         */
-        private boolean moveForward(HighTierContext context, ToDoubleFunction<FixedNode> probabilities) {
-
-            final MethodInvocation currentInvocation = currentInvocation();
-
-            final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), inliningDepth(),
-                            currentInvocation.probability(), currentInvocation.relevance(), false));
-            if (backtrack) {
-                int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
-                assert remainingGraphs > 0;
-                popGraphs(remainingGraphs);
-                popInvocation();
-                return false;
-            }
-
-            final boolean delve = currentGraph().hasRemainingInvokes() && inliningPolicy.continueInlining(currentGraph().graph());
-            if (delve) {
-                processNextInvoke(context);
-                return false;
-            }
-
-            popGraph();
-            if (currentInvocation.isRoot()) {
-                return false;
-            }
-
-            // try to inline
-            assert currentInvocation.callee().invoke().asNode().isAlive();
-            currentInvocation.incrementProcessedGraphs();
-            if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
-                popInvocation();
-                final MethodInvocation parentInvoke = currentInvocation();
-                try (Scope s = Debug.scope("Inlining", inliningContext())) {
-                    return tryToInline(probabilities, currentGraph(), currentInvocation, parentInvoke, inliningDepth() + 1, context);
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-            }
-
-            return false;
-        }
-    }
-
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu May 15 15:41:43 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu May 15 15:45:29 2014 +0200
@@ -49,8 +49,8 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.inlining.InliningPhase.*;
 import com.oracle.graal.phases.common.inlining.info.*;
+import com.oracle.graal.phases.common.inlining.walker.InliningData;
 
 public class InliningUtil {
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu May 15 15:45:29 2014 +0200
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2011, 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.phases.common.inlining.walker;
+
+import com.oracle.graal.api.code.Assumptions;
+import com.oracle.graal.api.code.BailoutException;
+import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.compiler.common.GraalInternalError;
+import com.oracle.graal.debug.Debug;
+import com.oracle.graal.debug.DebugMetric;
+import com.oracle.graal.graph.Graph;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.nodes.FixedNode;
+import com.oracle.graal.nodes.Invoke;
+import com.oracle.graal.nodes.StructuredGraph;
+import com.oracle.graal.phases.common.CanonicalizerPhase;
+import com.oracle.graal.phases.common.inlining.DepthSearchUtil;
+import com.oracle.graal.phases.common.inlining.InliningUtil;
+import com.oracle.graal.phases.common.inlining.info.InlineInfo;
+import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
+import com.oracle.graal.phases.tiers.HighTierContext;
+import com.oracle.graal.phases.util.Providers;
+
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.function.ToDoubleFunction;
+
+import static com.oracle.graal.compiler.common.GraalOptions.OptCanonicalizer;
+
+/**
+ * Holds the data for building the callee graphs recursively: graphs and invocations (each
+ * invocation can have multiple graphs).
+ */
+public class InliningData {
+
+    private static final CallsiteHolder DUMMY_CALLSITE_HOLDER = new CallsiteHolder(null, 1.0, 1.0);
+    // Metrics
+    private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
+    private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
+    private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
+
+    /**
+     * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
+     */
+    private final ArrayDeque<CallsiteHolder> graphQueue;
+    private final ArrayDeque<MethodInvocation> invocationQueue;
+    private final int maxMethodPerInlining;
+    private final CanonicalizerPhase canonicalizer;
+    private final InliningPolicy inliningPolicy;
+
+    private int maxGraphs;
+
+    public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions, int maxMethodPerInlining, CanonicalizerPhase canonicalizer, InliningPolicy inliningPolicy) {
+        assert rootGraph != null;
+        this.graphQueue = new ArrayDeque<>();
+        this.invocationQueue = new ArrayDeque<>();
+        this.maxMethodPerInlining = maxMethodPerInlining;
+        this.canonicalizer = canonicalizer;
+        this.inliningPolicy = inliningPolicy;
+        this.maxGraphs = 1;
+
+        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
+        pushGraph(rootGraph, 1.0, 1.0);
+    }
+
+    private void doInline(CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInfo, Assumptions callerAssumptions, HighTierContext context) {
+        StructuredGraph callerGraph = callerCallsiteHolder.graph();
+        Graph.Mark markBeforeInlining = callerGraph.getMark();
+        InlineInfo callee = calleeInfo.callee();
+        try {
+            try (Debug.Scope scope = Debug.scope("doInline", callerGraph)) {
+                List<Node> invokeUsages = callee.invoke().asNode().usages().snapshot();
+                callee.inline(new Providers(context), callerAssumptions);
+                callerAssumptions.record(calleeInfo.assumptions());
+                metricInliningRuns.increment();
+                Debug.dump(callerGraph, "after %s", callee);
+
+                if (OptCanonicalizer.getValue()) {
+                    Graph.Mark markBeforeCanonicalization = callerGraph.getMark();
+                    canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
+
+                    // process invokes that are possibly created during canonicalization
+                    for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
+                        if (newNode instanceof Invoke) {
+                            callerCallsiteHolder.pushInvoke((Invoke) newNode);
+                        }
+                    }
+                }
+
+                callerCallsiteHolder.computeProbabilities();
+
+                metricInliningPerformed.increment();
+            }
+        } catch (BailoutException bailout) {
+            throw bailout;
+        } catch (AssertionError | RuntimeException e) {
+            throw new GraalInternalError(e).addContext(callee.toString());
+        } catch (GraalInternalError e) {
+            throw e.addContext(callee.toString());
+        }
+    }
+
+    /**
+     * @return true iff inlining was actually performed
+     */
+    private boolean tryToInline(ToDoubleFunction<FixedNode> probabilities, CallsiteHolder callerCallsiteHolder, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth,
+                    HighTierContext context) {
+        InlineInfo callee = calleeInfo.callee();
+        Assumptions callerAssumptions = parentInvocation.assumptions();
+        metricInliningConsidered.increment();
+
+        if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) {
+            doInline(callerCallsiteHolder, calleeInfo, callerAssumptions, context);
+            return true;
+        }
+
+        if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
+            callee.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
+        }
+
+        return false;
+    }
+
+    /**
+     * Process the next invoke and enqueue all its graphs for processing.
+     */
+    void processNextInvoke(HighTierContext context) {
+        CallsiteHolder callsiteHolder = currentGraph();
+        Invoke invoke = callsiteHolder.popInvoke();
+        MethodInvocation callerInvocation = currentInvocation();
+        Assumptions parentAssumptions = callerInvocation.assumptions();
+        InlineInfo info = InliningUtil.getInlineInfo(this, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations());
+
+        if (info != null) {
+            double invokeProbability = callsiteHolder.invokeProbability(invoke);
+            double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
+            MethodInvocation calleeInvocation = pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
+
+            for (int i = 0; i < info.numberOfMethods(); i++) {
+                InliningUtil.Inlineable elem = DepthSearchUtil.getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()), canonicalizer);
+                info.setInlinableElement(i, elem);
+                if (elem instanceof InliningUtil.InlineableGraph) {
+                    pushGraph(((InliningUtil.InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
+                } else {
+                    assert elem instanceof InliningUtil.InlineableMacroNode;
+                    pushDummyGraph();
+                }
+            }
+        }
+    }
+
+    public int graphCount() {
+        return graphQueue.size();
+    }
+
+    private void pushGraph(StructuredGraph graph, double probability, double relevance) {
+        assert graph != null;
+        assert !contains(graph);
+        graphQueue.push(new CallsiteHolder(graph, probability, relevance));
+        assert graphQueue.size() <= maxGraphs;
+    }
+
+    private void pushDummyGraph() {
+        graphQueue.push(DUMMY_CALLSITE_HOLDER);
+    }
+
+    public boolean hasUnprocessedGraphs() {
+        return !graphQueue.isEmpty();
+    }
+
+    public CallsiteHolder currentGraph() {
+        return graphQueue.peek();
+    }
+
+    public void popGraph() {
+        graphQueue.pop();
+        assert graphQueue.size() <= maxGraphs;
+    }
+
+    public void popGraphs(int count) {
+        assert count >= 0;
+        for (int i = 0; i < count; i++) {
+            graphQueue.pop();
+        }
+    }
+
+    private static final Object[] NO_CONTEXT = {};
+
+    /**
+     * Gets the call hierarchy of this inlining from outer most call to inner most callee.
+     */
+    public Object[] inliningContext() {
+        if (!Debug.isDumpEnabled()) {
+            return NO_CONTEXT;
+        }
+        Object[] result = new Object[graphQueue.size()];
+        int i = 0;
+        for (CallsiteHolder g : graphQueue) {
+            result[i++] = g.method();
+        }
+        return result;
+    }
+
+    public MethodInvocation currentInvocation() {
+        return invocationQueue.peekFirst();
+    }
+
+    private MethodInvocation pushInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+        MethodInvocation methodInvocation = new MethodInvocation(info, new Assumptions(assumptions.useOptimisticAssumptions()), probability, relevance);
+        invocationQueue.addFirst(methodInvocation);
+        maxGraphs += info.numberOfMethods();
+        assert graphQueue.size() <= maxGraphs;
+        return methodInvocation;
+    }
+
+    public void popInvocation() {
+        maxGraphs -= invocationQueue.peekFirst().callee().numberOfMethods();
+        assert graphQueue.size() <= maxGraphs;
+        invocationQueue.removeFirst();
+    }
+
+    public int countRecursiveInlining(ResolvedJavaMethod method) {
+        int count = 0;
+        for (CallsiteHolder callsiteHolder : graphQueue) {
+            if (method.equals(callsiteHolder.method())) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public int inliningDepth() {
+        assert invocationQueue.size() > 0;
+        return invocationQueue.size() - 1;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder("Invocations: ");
+
+        for (MethodInvocation invocation : invocationQueue) {
+            if (invocation.callee() != null) {
+                result.append(invocation.callee().numberOfMethods());
+                result.append("x ");
+                result.append(invocation.callee().invoke());
+                result.append("; ");
+            }
+        }
+
+        result.append("\nGraphs: ");
+        for (CallsiteHolder graph : graphQueue) {
+            result.append(graph.graph());
+            result.append("; ");
+        }
+
+        return result.toString();
+    }
+
+    private boolean contains(StructuredGraph graph) {
+        for (CallsiteHolder info : graphQueue) {
+            if (info.graph() == graph) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return true iff inlining was actually performed
+     */
+    public boolean moveForward(HighTierContext context, ToDoubleFunction<FixedNode> probabilities) {
+
+        final MethodInvocation currentInvocation = currentInvocation();
+
+        final boolean backtrack = (!currentInvocation.isRoot() && !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), inliningDepth(),
+                        currentInvocation.probability(), currentInvocation.relevance(), false));
+        if (backtrack) {
+            int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
+            assert remainingGraphs > 0;
+            popGraphs(remainingGraphs);
+            popInvocation();
+            return false;
+        }
+
+        final boolean delve = currentGraph().hasRemainingInvokes() && inliningPolicy.continueInlining(currentGraph().graph());
+        if (delve) {
+            processNextInvoke(context);
+            return false;
+        }
+
+        popGraph();
+        if (currentInvocation.isRoot()) {
+            return false;
+        }
+
+        // try to inline
+        assert currentInvocation.callee().invoke().asNode().isAlive();
+        currentInvocation.incrementProcessedGraphs();
+        if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
+            popInvocation();
+            final MethodInvocation parentInvoke = currentInvocation();
+            try (Debug.Scope s = Debug.scope("Inlining", inliningContext())) {
+                return tryToInline(probabilities, currentGraph(), currentInvocation, parentInvoke, inliningDepth() + 1, context);
+            } catch (Throwable e) {
+                throw Debug.handle(e);
+            }
+        }
+
+        return false;
+    }
+}