1 /*
2  * Copyright (c) 2015, 2018, 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.hotspot;
26 
27 import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions;
28 
29 import java.io.ByteArrayOutputStream;
30 import java.io.PrintStream;
31 import java.util.Collections;
32 import java.util.Formattable;
33 import java.util.Formatter;
34 import java.util.List;
35 
36 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
37 import org.graalvm.compiler.code.CompilationResult;
38 import org.graalvm.compiler.core.GraalCompiler;
39 import org.graalvm.compiler.core.common.CompilationIdentifier;
40 import org.graalvm.compiler.core.common.util.CompilationAlarm;
41 import org.graalvm.compiler.debug.DebugContext;
42 import org.graalvm.compiler.debug.DebugContext.Activation;
43 import org.graalvm.compiler.debug.DebugHandlersFactory;
44 import org.graalvm.compiler.debug.DebugOptions;
45 import org.graalvm.compiler.hotspot.CompilationCounters.Options;
46 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
47 import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase;
48 import org.graalvm.compiler.java.GraphBuilderPhase;
49 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
50 import org.graalvm.compiler.lir.phases.LIRSuites;
51 import org.graalvm.compiler.nodes.StructuredGraph;
52 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
53 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
54 import org.graalvm.compiler.options.OptionValues;
55 import org.graalvm.compiler.phases.OptimisticOptimizations;
56 import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
57 import org.graalvm.compiler.phases.PhaseSuite;
58 import org.graalvm.compiler.phases.tiers.HighTierContext;
59 import org.graalvm.compiler.phases.tiers.Suites;
60 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
61 
62 import jdk.vm.ci.code.CompilationRequest;
63 import jdk.vm.ci.code.CompilationRequestResult;
64 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
65 import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult;
66 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
67 import jdk.vm.ci.meta.DefaultProfilingInfo;
68 import jdk.vm.ci.meta.JavaMethod;
69 import jdk.vm.ci.meta.ProfilingInfo;
70 import jdk.vm.ci.meta.ResolvedJavaMethod;
71 import jdk.vm.ci.meta.SpeculationLog;
72 import jdk.vm.ci.meta.TriState;
73 import jdk.vm.ci.runtime.JVMCICompiler;
74 
75 public class HotSpotGraalCompiler implements GraalJVMCICompiler {
76 
77     private final HotSpotJVMCIRuntime jvmciRuntime;
78     private final HotSpotGraalRuntimeProvider graalRuntime;
79     private final CompilationCounters compilationCounters;
80     private final BootstrapWatchDog bootstrapWatchDog;
81     private List<DebugHandlersFactory> factories;
82 
HotSpotGraalCompiler(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime, OptionValues options)83     HotSpotGraalCompiler(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime, OptionValues options) {
84         this.jvmciRuntime = jvmciRuntime;
85         this.graalRuntime = graalRuntime;
86         // It is sufficient to have one compilation counter object per Graal compiler object.
87         this.compilationCounters = Options.CompilationCountLimit.getValue(options) > 0 ? new CompilationCounters(options) : null;
88         this.bootstrapWatchDog = graalRuntime.isBootstrapping() && !DebugOptions.BootstrapInitializeOnly.getValue(options) ? BootstrapWatchDog.maybeCreate(graalRuntime) : null;
89     }
90 
getDebugHandlersFactories()91     public List<DebugHandlersFactory> getDebugHandlersFactories() {
92         if (factories == null) {
93             factories = Collections.singletonList(new GraalDebugHandlersFactory(graalRuntime.getHostProviders().getSnippetReflection()));
94         }
95         return factories;
96     }
97 
98     @Override
getGraalRuntime()99     public HotSpotGraalRuntimeProvider getGraalRuntime() {
100         return graalRuntime;
101     }
102 
103     @Override
compileMethod(CompilationRequest request)104     public CompilationRequestResult compileMethod(CompilationRequest request) {
105         return compileMethod(request, true, graalRuntime.getOptions());
106     }
107 
108     @SuppressWarnings("try")
compileMethod(CompilationRequest request, boolean installAsDefault, OptionValues options)109     CompilationRequestResult compileMethod(CompilationRequest request, boolean installAsDefault, OptionValues options) {
110         if (graalRuntime.isShutdown()) {
111             return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false);
112         }
113 
114         ResolvedJavaMethod method = request.getMethod();
115 
116         if (graalRuntime.isBootstrapping()) {
117             if (DebugOptions.BootstrapInitializeOnly.getValue(options)) {
118                 return HotSpotCompilationRequestResult.failure(String.format("Skip compilation because %s is enabled", DebugOptions.BootstrapInitializeOnly.getName()), true);
119             }
120             if (bootstrapWatchDog != null) {
121                 if (bootstrapWatchDog.hitCriticalCompilationRateOrTimeout()) {
122                     // Drain the compilation queue to expedite completion of the bootstrap
123                     return HotSpotCompilationRequestResult.failure("hit critical bootstrap compilation rate or timeout", true);
124                 }
125             }
126         }
127         HotSpotCompilationRequest hsRequest = (HotSpotCompilationRequest) request;
128         try (CompilationWatchDog w1 = CompilationWatchDog.watch(method, hsRequest.getId(), options);
129                         BootstrapWatchDog.Watch w2 = bootstrapWatchDog == null ? null : bootstrapWatchDog.watch(request);
130                         CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(options);) {
131             if (compilationCounters != null) {
132                 compilationCounters.countCompilation(method);
133             }
134             CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, installAsDefault, options);
135             CompilationRequestResult r = null;
136             try (DebugContext debug = graalRuntime.openDebugContext(options, task.getCompilationIdentifier(), method, getDebugHandlersFactories(), DebugContext.DEFAULT_LOG_STREAM);
137                             Activation a = debug.activate()) {
138                 r = task.runCompilation(debug);
139             }
140             assert r != null;
141             return r;
142         }
143     }
144 
createGraph(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug)145     public StructuredGraph createGraph(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
146         HotSpotBackend backend = graalRuntime.getHostBackend();
147         HotSpotProviders providers = backend.getProviders();
148         final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
149         StructuredGraph graph = method.isNative() || isOSR ? null : providers.getReplacements().getIntrinsicGraph(method, compilationId, debug);
150 
151         if (graph == null) {
152             SpeculationLog speculationLog = method.getSpeculationLog();
153             if (speculationLog != null) {
154                 speculationLog.collectFailedSpeculations();
155             }
156             graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.ifTrue(OptAssumptions.getValue(options))).method(method).entryBCI(entryBCI).speculationLog(
157                             speculationLog).useProfilingInfo(useProfilingInfo).compilationId(compilationId).build();
158         }
159         return graph;
160     }
161 
compileHelper(CompilationResultBuilderFactory crbf, CompilationResult result, StructuredGraph graph, ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, OptionValues options)162     public CompilationResult compileHelper(CompilationResultBuilderFactory crbf, CompilationResult result, StructuredGraph graph, ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo,
163                     OptionValues options) {
164 
165         HotSpotBackend backend = graalRuntime.getHostBackend();
166         HotSpotProviders providers = backend.getProviders();
167         final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
168 
169         Suites suites = getSuites(providers, options);
170         LIRSuites lirSuites = getLIRSuites(providers, options);
171         ProfilingInfo profilingInfo = useProfilingInfo ? method.getProfilingInfo(!isOSR, isOSR) : DefaultProfilingInfo.get(TriState.FALSE);
172         OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo, options);
173 
174         /*
175          * Cut off never executed code profiles if there is code, e.g. after the osr loop, that is
176          * never executed.
177          */
178         if (isOSR && !OnStackReplacementPhase.Options.DeoptAfterOSR.getValue(options)) {
179             optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
180         }
181 
182         result.setEntryBCI(entryBCI);
183         boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints();
184         PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR);
185         GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf, true);
186 
187         if (!isOSR && useProfilingInfo) {
188             ProfilingInfo profile = profilingInfo;
189             profile.setCompilerIRSize(StructuredGraph.class, graph.getNodeCount());
190         }
191 
192         return result;
193     }
194 
compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug)195     public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) {
196         StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug);
197         CompilationResult result = new CompilationResult(compilationId);
198         return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options);
199     }
200 
getOptimisticOpts(ProfilingInfo profilingInfo, OptionValues options)201     protected OptimisticOptimizations getOptimisticOpts(ProfilingInfo profilingInfo, OptionValues options) {
202         return new OptimisticOptimizations(profilingInfo, options);
203     }
204 
getSuites(HotSpotProviders providers, OptionValues options)205     protected Suites getSuites(HotSpotProviders providers, OptionValues options) {
206         return providers.getSuites().getDefaultSuites(options);
207     }
208 
getLIRSuites(HotSpotProviders providers, OptionValues options)209     protected LIRSuites getLIRSuites(HotSpotProviders providers, OptionValues options) {
210         return providers.getSuites().getDefaultLIRSuites(options);
211     }
212 
213     /**
214      * Reconfigures a given graph builder suite (GBS) if one of the given GBS parameter values is
215      * not the default.
216      *
217      * @param suite the graph builder suite
218      * @param shouldDebugNonSafepoints specifies if extra debug info should be generated (default is
219      *            false)
220      * @param isOSR specifies if extra OSR-specific post-processing is required (default is false)
221      * @return a new suite derived from {@code suite} if any of the GBS parameters did not have a
222      *         default value otherwise {@code suite}
223      */
configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean isOSR)224     protected PhaseSuite<HighTierContext> configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean isOSR) {
225         if (shouldDebugNonSafepoints || isOSR) {
226             PhaseSuite<HighTierContext> newGbs = suite.copy();
227 
228             if (shouldDebugNonSafepoints) {
229                 GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
230                 GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
231                 graphBuilderConfig = graphBuilderConfig.withNodeSourcePosition(true);
232                 GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig);
233                 newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
234             }
235             if (isOSR) {
236                 // We must not clear non liveness for OSR compilations.
237                 GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous();
238                 GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig();
239                 GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig);
240                 newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase);
241                 newGbs.appendPhase(new OnStackReplacementPhase());
242             }
243             return newGbs;
244         }
245         return suite;
246     }
247 
248     /**
249      * Converts {@code method} to a String with {@link JavaMethod#format(String)} and the format
250      * string {@code "%H.%n(%p)"}.
251      */
str(JavaMethod method)252     static String str(JavaMethod method) {
253         return method.format("%H.%n(%p)");
254     }
255 
256     /**
257      * Wraps {@code obj} in a {@link Formatter} that standardizes formatting for certain objects.
258      */
fmt(Object obj)259     static Formattable fmt(Object obj) {
260         return new Formattable() {
261             @Override
262             public void formatTo(Formatter buf, int flags, int width, int precision) {
263                 if (obj instanceof Throwable) {
264                     ByteArrayOutputStream baos = new ByteArrayOutputStream();
265                     ((Throwable) obj).printStackTrace(new PrintStream(baos));
266                     buf.format("%s", baos.toString());
267                 } else if (obj instanceof StackTraceElement[]) {
268                     for (StackTraceElement e : (StackTraceElement[]) obj) {
269                         buf.format("\t%s%n", e);
270                     }
271                 } else if (obj instanceof JavaMethod) {
272                     buf.format("%s", str((JavaMethod) obj));
273                 } else {
274                     buf.format("%s", obj);
275                 }
276             }
277         };
278     }
279 }
280