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