1 /*
2  * Copyright (c) 2009, 2020, 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  */
23 
24 
25 package org.graalvm.compiler.core;
26 
27 import org.graalvm.compiler.code.CompilationResult;
28 import org.graalvm.compiler.core.common.PermanentBailoutException;
29 import org.graalvm.compiler.core.common.RetryableBailoutException;
30 import org.graalvm.compiler.core.common.util.CompilationAlarm;
31 import org.graalvm.compiler.core.target.Backend;
32 import org.graalvm.compiler.debug.DebugCloseable;
33 import org.graalvm.compiler.debug.DebugContext;
34 import org.graalvm.compiler.debug.DebugContext.CompilerPhaseScope;
35 import org.graalvm.compiler.debug.MethodFilter;
36 import org.graalvm.compiler.debug.TimerKey;
37 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
38 import org.graalvm.compiler.lir.phases.LIRSuites;
39 import org.graalvm.compiler.nodes.StructuredGraph;
40 import org.graalvm.compiler.phases.OptimisticOptimizations;
41 import org.graalvm.compiler.phases.PhaseSuite;
42 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
43 import org.graalvm.compiler.phases.tiers.HighTierContext;
44 import org.graalvm.compiler.phases.tiers.LowTierContext;
45 import org.graalvm.compiler.phases.tiers.MidTierContext;
46 import org.graalvm.compiler.phases.tiers.Suites;
47 import org.graalvm.compiler.phases.tiers.TargetProvider;
48 import org.graalvm.compiler.phases.util.Providers;
49 
50 import jdk.vm.ci.meta.ProfilingInfo;
51 import jdk.vm.ci.meta.ResolvedJavaMethod;
52 
53 /**
54  * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}.
55  */
56 public class GraalCompiler {
57 
58     private static final TimerKey CompilerTimer = DebugContext.timer("GraalCompiler").doc("Time spent in compilation (excludes code installation).");
59     private static final TimerKey FrontEnd = DebugContext.timer("FrontEnd").doc("Time spent processing HIR.");
60 
61     /**
62      * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}.
63      */
64     public static class Request<T extends CompilationResult> {
65         public final StructuredGraph graph;
66         public final ResolvedJavaMethod installedCodeOwner;
67         public final Providers providers;
68         public final Backend backend;
69         public final PhaseSuite<HighTierContext> graphBuilderSuite;
70         public final OptimisticOptimizations optimisticOpts;
71         public final ProfilingInfo profilingInfo;
72         public final Suites suites;
73         public final LIRSuites lirSuites;
74         public final T compilationResult;
75         public final CompilationResultBuilderFactory factory;
76         public final boolean verifySourcePositions;
77 
78         /**
79          * @param graph the graph to be compiled
80          * @param installedCodeOwner the method the compiled code will be associated with once
81          *            installed. This argument can be null.
82          * @param providers
83          * @param backend
84          * @param graphBuilderSuite
85          * @param optimisticOpts
86          * @param profilingInfo
87          * @param suites
88          * @param lirSuites
89          * @param compilationResult
90          * @param factory
91          */
Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory, boolean verifySourcePositions)92         public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite,
93                         OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory,
94                         boolean verifySourcePositions) {
95             this.graph = graph;
96             this.installedCodeOwner = installedCodeOwner;
97             this.providers = providers;
98             this.backend = backend;
99             this.graphBuilderSuite = graphBuilderSuite;
100             this.optimisticOpts = optimisticOpts;
101             this.profilingInfo = profilingInfo;
102             this.suites = suites;
103             this.lirSuites = lirSuites;
104             this.compilationResult = compilationResult;
105             this.factory = factory;
106             this.verifySourcePositions = verifySourcePositions;
107         }
108 
109         /**
110          * Executes this compilation request.
111          *
112          * @return the result of the compilation
113          */
execute()114         public T execute() {
115             return GraalCompiler.compile(this);
116         }
117     }
118 
119     /**
120      * Requests compilation of a given graph.
121      *
122      * @param graph the graph to be compiled
123      * @param installedCodeOwner the method the compiled code will be associated with once
124      *            installed. This argument can be null.
125      * @return the result of the compilation
126      */
compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory, boolean verifySourcePositions)127     public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
128                     PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
129                     CompilationResultBuilderFactory factory, boolean verifySourcePositions) {
130         return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory,
131                         verifySourcePositions));
132     }
133 
134     /**
135      * Services a given compilation request.
136      *
137      * @return the result of the compilation
138      */
139     @SuppressWarnings("try")
compile(Request<T> r)140     public static <T extends CompilationResult> T compile(Request<T> r) {
141         DebugContext debug = r.graph.getDebug();
142         try (CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(r.graph.getOptions())) {
143             assert !r.graph.isFrozen();
144             try (DebugContext.Scope s0 = debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start(debug)) {
145                 emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
146                 r.backend.emitBackEnd(r.graph, null, r.installedCodeOwner, r.compilationResult, r.factory, null, r.lirSuites);
147                 if (r.verifySourcePositions) {
148                     assert r.graph.verifySourcePositions(true);
149                 }
150             } catch (Throwable e) {
151                 throw debug.handle(e);
152             }
153             checkForRequestedCrash(r.graph);
154             return r.compilationResult;
155         }
156     }
157 
158     /**
159      * Checks whether the {@link GraalCompilerOptions#CrashAt} option indicates that the compilation
160      * of {@code graph} should result in an exception.
161      *
162      * @param graph a graph currently being compiled
163      * @throws RuntimeException if the value of {@link GraalCompilerOptions#CrashAt} matches
164      *             {@code graph.method()} or {@code graph.name}
165      */
checkForRequestedCrash(StructuredGraph graph)166     private static void checkForRequestedCrash(StructuredGraph graph) {
167         String value = GraalCompilerOptions.CrashAt.getValue(graph.getOptions());
168         if (value != null) {
169             boolean bailout = false;
170             boolean permanentBailout = false;
171             String methodPattern = value;
172             if (value.endsWith(":Bailout")) {
173                 methodPattern = value.substring(0, value.length() - ":Bailout".length());
174                 bailout = true;
175             } else if (value.endsWith(":PermanentBailout")) {
176                 methodPattern = value.substring(0, value.length() - ":PermanentBailout".length());
177                 permanentBailout = true;
178             }
179             String crashLabel = null;
180             if (graph.name != null && graph.name.contains(methodPattern)) {
181                 crashLabel = graph.name;
182             }
183             if (crashLabel == null) {
184                 ResolvedJavaMethod method = graph.method();
185                 MethodFilter filter = MethodFilter.parse(methodPattern);
186                 if (filter.matches(method)) {
187                     crashLabel = method.format("%H.%n(%p)");
188                 }
189             }
190             if (crashLabel != null) {
191                 String crashMessage = "Forced crash after compiling " + crashLabel;
192                 notifyCrash(crashMessage);
193                 if (permanentBailout) {
194                     throw new PermanentBailoutException(crashMessage);
195                 }
196                 if (bailout) {
197                     throw new RetryableBailoutException(crashMessage);
198                 }
199                 throw new RuntimeException(crashMessage);
200             }
201         }
202     }
203 
204     /**
205      * Substituted by {@code com.oracle.svm.graal.hotspot.libgraal.
206      * Target_org_graalvm_compiler_core_GraalCompiler} to optionally test routing fatal error
207      * handling from libgraal to HotSpot.
208      */
209     @SuppressWarnings("unused")
notifyCrash(String crashMessage)210     private static void notifyCrash(String crashMessage) {
211     }
212 
213     /**
214      * Builds the graph, optimizes it.
215      */
216     @SuppressWarnings("try")
emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites)217     public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
218                     ProfilingInfo profilingInfo, Suites suites) {
219         DebugContext debug = graph.getDebug();
220         try (DebugContext.Scope s = debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start(debug)) {
221             HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
222             if (graph.start().next() == null) {
223                 try (CompilerPhaseScope cps = debug.enterCompilerPhase("Parsing")) {
224                     graphBuilderSuite.apply(graph, highTierContext);
225                     new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph);
226                     debug.dump(DebugContext.BASIC_LEVEL, graph, "After parsing");
227                 }
228             } else {
229                 debug.dump(DebugContext.INFO_LEVEL, graph, "initial state");
230             }
231 
232             suites.getHighTier().apply(graph, highTierContext);
233             graph.maybeCompress();
234             debug.dump(DebugContext.BASIC_LEVEL, graph, "After high tier");
235 
236             MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo);
237             suites.getMidTier().apply(graph, midTierContext);
238             graph.maybeCompress();
239             debug.dump(DebugContext.BASIC_LEVEL, graph, "After mid tier");
240 
241             LowTierContext lowTierContext = new LowTierContext(providers, target);
242             suites.getLowTier().apply(graph, lowTierContext);
243             debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier");
244 
245             debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
246             graph.logInliningTree();
247         } catch (Throwable e) {
248             throw debug.handle(e);
249         } finally {
250             graph.checkCancellation();
251         }
252     }
253 
getCompilationUnitName(StructuredGraph graph, T compilationResult)254     protected static <T extends CompilationResult> String getCompilationUnitName(StructuredGraph graph, T compilationResult) {
255         if (compilationResult != null && compilationResult.getName() != null) {
256             return compilationResult.getName();
257         }
258         ResolvedJavaMethod method = graph.method();
259         if (method == null) {
260             return "<unknown>";
261         }
262         return method.format("%H.%n(%p)");
263     }
264 }
265