001/*
002 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.phases.common.inlining.walker;
024
025import java.util.*;
026import java.util.function.*;
027
028import jdk.internal.jvmci.meta.*;
029
030import com.oracle.graal.graph.*;
031import com.oracle.graal.nodes.*;
032import com.oracle.graal.phases.common.inlining.policy.*;
033import com.oracle.graal.phases.graph.*;
034
035/**
036 * <p>
037 * A {@link CallsiteHolder} whose graph has been copied already and thus can be modified without
038 * affecting the original (usually cached) version.
039 * </p>
040 *
041 * <p>
042 * An instance of this class is derived from an
043 * {@link com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph InlineableGraph} and
044 * contains a subset of the information there: just the {@link Invoke} nodes from it. Such nodes are
045 * candidates for depth-first search of further inlining opportunities (thus the adjective
046 * "explorable" given to this class)
047 * </p>
048 *
049 * @see InliningData#moveForward()
050 */
051public final class CallsiteHolderExplorable extends CallsiteHolder {
052
053    /**
054     * Graph in which inlining may be performed at one or more of the callsites containined in
055     * {@link #remainingInvokes}.
056     */
057    private final StructuredGraph graph;
058
059    private final LinkedList<Invoke> remainingInvokes;
060    private final double probability;
061    private final double relevance;
062
063    /**
064     * @see #getFixedParams()
065     */
066    private final Set<ParameterNode> fixedParams;
067
068    private final ToDoubleFunction<FixedNode> probabilities;
069    private final ComputeInliningRelevance computeInliningRelevance;
070
071    public CallsiteHolderExplorable(StructuredGraph graph, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
072        assert graph != null;
073        this.graph = graph;
074        this.probability = probability;
075        this.relevance = relevance;
076        this.fixedParams = fixedParamsAt(freshlyInstantiatedArguments);
077        remainingInvokes = new InliningIterator(graph).apply();
078        if (remainingInvokes.isEmpty()) {
079            probabilities = null;
080            computeInliningRelevance = null;
081        } else {
082            probabilities = new FixedNodeProbabilityCache();
083            computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
084            computeProbabilities();
085        }
086        assert repOK();
087    }
088
089    /**
090     * @see #getFixedParams()
091     */
092    @SuppressWarnings("unchecked")
093    private Set<ParameterNode> fixedParamsAt(BitSet freshlyInstantiatedArguments) {
094        if (freshlyInstantiatedArguments == null || freshlyInstantiatedArguments.isEmpty()) {
095            return Collections.EMPTY_SET;
096        }
097        Set<ParameterNode> result = Node.newSet();
098        for (ParameterNode p : graph.getNodes(ParameterNode.TYPE)) {
099            if (freshlyInstantiatedArguments.get(p.index())) {
100                result.add(p);
101            }
102        }
103        return result;
104    }
105
106    /**
107     * <p>
108     * Parameters for which the callsite targeting {@link #graph()} provides "fixed" arguments. That
109     * callsite isn't referenced by this instance. Instead, it belongs to the graph of the caller of
110     * this {@link CallsiteHolderExplorable}
111     * </p>
112     *
113     * <p>
114     * Constant arguments don't contribute to fixed-params: those params have been removed already,
115     * see {@link com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph}.
116     * </p>
117     *
118     * <p>
119     * Instead, fixed-params are those receiving freshly instantiated arguments (possibly
120     * instantiated several levels up in the call-hierarchy)
121     * </p>
122     * */
123    public Set<ParameterNode> getFixedParams() {
124        return fixedParams;
125    }
126
127    public boolean repOK() {
128        for (Invoke invoke : remainingInvokes) {
129            if (!invoke.asNode().isAlive() || !containsInvoke(invoke)) {
130                assert false;
131                return false;
132            }
133            if (!allArgsNonNull(invoke)) {
134                assert false;
135                return false;
136            }
137        }
138        for (ParameterNode fixedParam : fixedParams) {
139            if (!containsParam(fixedParam)) {
140                assert false;
141                return false;
142            }
143        }
144        return true;
145    }
146
147    @Override
148    public ResolvedJavaMethod method() {
149        return graph == null ? null : graph.method();
150    }
151
152    @Override
153    public boolean hasRemainingInvokes() {
154        return !remainingInvokes.isEmpty();
155    }
156
157    @Override
158    public StructuredGraph graph() {
159        return graph;
160    }
161
162    public Invoke popInvoke() {
163        return remainingInvokes.removeFirst();
164    }
165
166    public void pushInvoke(Invoke invoke) {
167        remainingInvokes.push(invoke);
168    }
169
170    public static boolean allArgsNonNull(Invoke invoke) {
171        for (ValueNode arg : invoke.callTarget().arguments()) {
172            if (arg == null) {
173                assert false;
174                return false;
175            }
176        }
177        return true;
178    }
179
180    public boolean containsInvoke(Invoke invoke) {
181        for (Invoke i : graph().getInvokes()) {
182            if (i == invoke) {
183                return true;
184            }
185        }
186        return false;
187    }
188
189    public boolean containsParam(ParameterNode param) {
190        for (ParameterNode p : graph.getNodes(ParameterNode.TYPE)) {
191            if (p == param) {
192                return true;
193            }
194        }
195        return false;
196    }
197
198    public void computeProbabilities() {
199        computeInliningRelevance.compute();
200    }
201
202    public double invokeProbability(Invoke invoke) {
203        return probability * probabilities.applyAsDouble(invoke.asNode());
204    }
205
206    public double invokeRelevance(Invoke invoke) {
207        return Math.min(AbstractInliningPolicy.CapInheritedRelevance, relevance) * computeInliningRelevance.getRelevance(invoke);
208    }
209
210    @Override
211    public String toString() {
212        return (graph != null ? method().format("%H.%n(%p)") : "<null method>") + remainingInvokes;
213    }
214}