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