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