1/*
2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.phases.common.inlining;
24
25import java.util.Map;
26
27import org.graalvm.compiler.nodes.Invoke;
28import org.graalvm.compiler.nodes.StructuredGraph;
29import org.graalvm.compiler.options.Option;
30import org.graalvm.compiler.options.OptionType;
31import org.graalvm.compiler.options.OptionValue;
32import org.graalvm.compiler.phases.common.AbstractInliningPhase;
33import org.graalvm.compiler.phases.common.CanonicalizerPhase;
34import org.graalvm.compiler.phases.common.inlining.policy.GreedyInliningPolicy;
35import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy;
36import org.graalvm.compiler.phases.common.inlining.walker.InliningData;
37import org.graalvm.compiler.phases.tiers.HighTierContext;
38
39public class InliningPhase extends AbstractInliningPhase {
40
41    public static class Options {
42
43        @Option(help = "Unconditionally inline intrinsics", type = OptionType.Debug)//
44        public static final OptionValue<Boolean> AlwaysInlineIntrinsics = new OptionValue<>(false);
45
46        /**
47         * This is a defensive measure against known pathologies of the inliner where the breadth of
48         * the inlining call tree exploration can be wide enough to prevent inlining from completing
49         * in reasonable time.
50         */
51        @Option(help = "Per-compilation method inlining exploration limit before giving up (use 0 to disable)", type = OptionType.Debug)//
52        public static final OptionValue<Integer> MethodInlineBailoutLimit = new OptionValue<>(5000);
53    }
54
55    private final InliningPolicy inliningPolicy;
56    private final CanonicalizerPhase canonicalizer;
57
58    private int maxMethodPerInlining = Integer.MAX_VALUE;
59
60    public InliningPhase(CanonicalizerPhase canonicalizer) {
61        this(new GreedyInliningPolicy(null), canonicalizer);
62    }
63
64    public InliningPhase(Map<Invoke, Double> hints, CanonicalizerPhase canonicalizer) {
65        this(new GreedyInliningPolicy(hints), canonicalizer);
66    }
67
68    public InliningPhase(InliningPolicy policy, CanonicalizerPhase canonicalizer) {
69        this.inliningPolicy = policy;
70        this.canonicalizer = canonicalizer;
71    }
72
73    public CanonicalizerPhase getCanonicalizer() {
74        return canonicalizer;
75    }
76
77    @Override
78    public float codeSizeIncrease() {
79        return 10_000f;
80    }
81
82    public void setMaxMethodsPerInlining(int max) {
83        maxMethodPerInlining = max;
84    }
85
86    /**
87     *
88     * This method sets in motion the inlining machinery.
89     *
90     * @see InliningData
91     * @see InliningData#moveForward()
92     *
93     */
94    @Override
95    protected void run(final StructuredGraph graph, final HighTierContext context) {
96        final InliningData data = new InliningData(graph, context, maxMethodPerInlining, canonicalizer, inliningPolicy);
97
98        int count = 0;
99        assert data.repOK();
100        int limit = Options.MethodInlineBailoutLimit.getValue();
101        while (data.hasUnprocessedGraphs()) {
102            boolean wasInlined = data.moveForward();
103            assert data.repOK();
104            count++;
105            if (!wasInlined) {
106                if (limit > 0 && count == limit) {
107                    // Limit the amount of exploration which is done
108                    break;
109                }
110            }
111        }
112
113        assert data.inliningDepth() == 0 || count == limit;
114        assert data.graphCount() == 0 || count == limit;
115    }
116
117}
118