1/*
2 * Copyright (c) 2015, 2016, 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.hotspot.meta;
24
25import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
26import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
27import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases;
28import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
29
30import java.util.ListIterator;
31
32import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
33import org.graalvm.compiler.hotspot.HotSpotBackend;
34import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
35import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling;
36import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase;
37import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase;
38import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
39import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase;
40import org.graalvm.compiler.hotspot.phases.aot.AOTInliningPolicy;
41import org.graalvm.compiler.hotspot.phases.aot.EliminateRedundantInitializationPhase;
42import org.graalvm.compiler.hotspot.phases.aot.ReplaceConstantNodesPhase;
43import org.graalvm.compiler.hotspot.phases.profiling.FinalizeProfileNodesPhase;
44import org.graalvm.compiler.java.GraphBuilderPhase;
45import org.graalvm.compiler.java.SuitesProviderBase;
46import org.graalvm.compiler.lir.phases.LIRSuites;
47import org.graalvm.compiler.nodes.EncodedGraph;
48import org.graalvm.compiler.nodes.GraphEncoder;
49import org.graalvm.compiler.nodes.SimplifyingGraphDecoder;
50import org.graalvm.compiler.nodes.StructuredGraph;
51import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
52import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
53import org.graalvm.compiler.options.OptionValues;
54import org.graalvm.compiler.phases.BasePhase;
55import org.graalvm.compiler.phases.PhaseSuite;
56import org.graalvm.compiler.phases.common.CanonicalizerPhase;
57import org.graalvm.compiler.phases.common.LoweringPhase;
58import org.graalvm.compiler.phases.common.inlining.InliningPhase;
59import org.graalvm.compiler.phases.tiers.HighTierContext;
60import org.graalvm.compiler.phases.tiers.MidTierContext;
61import org.graalvm.compiler.phases.tiers.Suites;
62import org.graalvm.compiler.phases.tiers.SuitesCreator;
63
64/**
65 * HotSpot implementation of {@link SuitesCreator}.
66 */
67public class HotSpotSuitesProvider extends SuitesProviderBase {
68
69    protected final GraalHotSpotVMConfig config;
70    protected final HotSpotGraalRuntimeProvider runtime;
71
72    private final SuitesCreator defaultSuitesCreator;
73
74    public HotSpotSuitesProvider(SuitesCreator defaultSuitesCreator, GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime) {
75        this.defaultSuitesCreator = defaultSuitesCreator;
76        this.config = config;
77        this.runtime = runtime;
78        this.defaultGraphBuilderSuite = createGraphBuilderSuite();
79    }
80
81    @Override
82    public Suites createSuites(OptionValues options) {
83        Suites ret = defaultSuitesCreator.createSuites(options);
84
85        if (ImmutableCode.getValue(options)) {
86            // lowering introduces class constants, therefore it must be after lowering
87            ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(config));
88            if (VerifyPhases.getValue(options)) {
89                ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase());
90            }
91            if (GeneratePIC.getValue(options)) {
92                ListIterator<BasePhase<? super HighTierContext>> highTierLowering = ret.getHighTier().findPhase(LoweringPhase.class);
93                highTierLowering.previous();
94                highTierLowering.add(new EliminateRedundantInitializationPhase());
95                if (HotSpotAOTProfilingPlugin.Options.TieredAOT.getValue(options)) {
96                    highTierLowering.add(new FinalizeProfileNodesPhase(HotSpotAOTProfilingPlugin.Options.TierAInvokeInlineeNotifyFreqLog.getValue(options)));
97                }
98                ListIterator<BasePhase<? super MidTierContext>> midTierLowering = ret.getMidTier().findPhase(LoweringPhase.class);
99                midTierLowering.add(new ReplaceConstantNodesPhase());
100
101                // Replace inlining policy
102                if (Inline.getValue(options)) {
103                    ListIterator<BasePhase<? super HighTierContext>> iter = ret.getHighTier().findPhase(InliningPhase.class);
104                    InliningPhase inlining = (InliningPhase) iter.previous();
105                    CanonicalizerPhase canonicalizer = inlining.getCanonicalizer();
106                    iter.set(new InliningPhase(new AOTInliningPolicy(null), canonicalizer));
107                }
108            }
109        }
110
111        ret.getMidTier().appendPhase(new WriteBarrierAdditionPhase(config));
112        if (VerifyPhases.getValue(options)) {
113            ret.getMidTier().appendPhase(new WriteBarrierVerificationPhase(config));
114        }
115
116        return ret;
117    }
118
119    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
120        PhaseSuite<HighTierContext> suite = defaultSuitesCreator.getDefaultGraphBuilderSuite().copy();
121        assert appendGraphEncoderTest(suite);
122        return suite;
123    }
124
125    /**
126     * When assertions are enabled, we encode and decode every parsed graph, to ensure that the
127     * encoding and decoding process work correctly. The decoding performs canonicalization during
128     * decoding, so the decoded graph can be different than the encoded graph - we cannot check them
129     * for equality here. However, the encoder {@link GraphEncoder#verifyEncoding verifies the
130     * encoding itself}, i.e., performs a decoding without canonicalization and checks the graphs
131     * for equality.
132     */
133    private boolean appendGraphEncoderTest(PhaseSuite<HighTierContext> suite) {
134        suite.appendPhase(new BasePhase<HighTierContext>() {
135            @Override
136            protected void run(StructuredGraph graph, HighTierContext context) {
137                EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch);
138
139                StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), graph.getDebug(), AllowAssumptions.YES).method(graph.method()).build();
140                SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(),
141                                context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()));
142                graphDecoder.decode(encodedGraph);
143            }
144
145            @Override
146            protected CharSequence getName() {
147                return "VerifyEncodingDecoding";
148            }
149        });
150        return true;
151    }
152
153    /**
154     * Modifies a given {@link GraphBuilderConfiguration} to record per node source information.
155     *
156     * @param gbs the current graph builder suite to modify
157     */
158    public static PhaseSuite<HighTierContext> withNodeSourcePosition(PhaseSuite<HighTierContext> gbs) {
159        PhaseSuite<HighTierContext> newGbs = gbs.copy();
160        GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
161        GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
162        GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig.withNodeSourcePosition(true));
163        newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
164        return newGbs;
165    }
166
167    @Override
168    public LIRSuites createLIRSuites(OptionValues options) {
169        LIRSuites suites = defaultSuitesCreator.createLIRSuites(options);
170        String profileInstructions = HotSpotBackend.Options.ASMInstructionProfiling.getValue(options);
171        if (profileInstructions != null) {
172            suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
173        }
174        return suites;
175    }
176}
177