1 /* 2 * Copyright (c) 2015, 2016, 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 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; 29 30 import java.io.ByteArrayOutputStream; 31 import java.io.PrintStream; 32 import java.util.Collections; 33 import java.util.Formattable; 34 import java.util.Formatter; 35 import java.util.List; 36 37 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; 38 import org.graalvm.compiler.bytecode.Bytecode; 39 import org.graalvm.compiler.bytecode.BytecodeProvider; 40 import org.graalvm.compiler.code.CompilationResult; 41 import org.graalvm.compiler.core.GraalCompiler; 42 import org.graalvm.compiler.core.common.CompilationIdentifier; 43 import org.graalvm.compiler.core.common.util.CompilationAlarm; 44 import org.graalvm.compiler.debug.DebugContext; 45 import org.graalvm.compiler.debug.DebugContext.Activation; 46 import org.graalvm.compiler.debug.DebugHandlersFactory; 47 import org.graalvm.compiler.debug.DebugOptions; 48 import org.graalvm.compiler.hotspot.CompilationCounters.Options; 49 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 50 import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase; 51 import org.graalvm.compiler.java.GraphBuilderPhase; 52 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 53 import org.graalvm.compiler.lir.phases.LIRSuites; 54 import org.graalvm.compiler.nodes.StructuredGraph; 55 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 56 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 57 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; 58 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; 59 import org.graalvm.compiler.nodes.spi.Replacements; 60 import org.graalvm.compiler.options.OptionValues; 61 import org.graalvm.compiler.phases.OptimisticOptimizations; 62 import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; 63 import org.graalvm.compiler.phases.PhaseSuite; 64 import org.graalvm.compiler.phases.tiers.HighTierContext; 65 import org.graalvm.compiler.phases.tiers.Suites; 66 import org.graalvm.compiler.printer.GraalDebugHandlersFactory; 67 68 import jdk.vm.ci.code.CompilationRequest; 69 import jdk.vm.ci.code.CompilationRequestResult; 70 import jdk.vm.ci.hotspot.HotSpotCompilationRequest; 71 import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult; 72 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; 73 import jdk.vm.ci.meta.DefaultProfilingInfo; 74 import jdk.vm.ci.meta.JavaMethod; 75 import jdk.vm.ci.meta.ProfilingInfo; 76 import jdk.vm.ci.meta.ResolvedJavaMethod; 77 import jdk.vm.ci.meta.SpeculationLog; 78 import jdk.vm.ci.meta.TriState; 79 import jdk.vm.ci.runtime.JVMCICompiler; 80 81 public class HotSpotGraalCompiler implements GraalJVMCICompiler { 82 83 private final HotSpotJVMCIRuntime jvmciRuntime; 84 private final HotSpotGraalRuntimeProvider graalRuntime; 85 private final CompilationCounters compilationCounters; 86 private final BootstrapWatchDog bootstrapWatchDog; 87 private List<DebugHandlersFactory> factories; 88 89 HotSpotGraalCompiler(HotSpotJVMCIRuntime jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime, OptionValues options) { 90 this.jvmciRuntime = jvmciRuntime; 91 this.graalRuntime = graalRuntime; 92 // It is sufficient to have one compilation counter object per Graal compiler object. 93 this.compilationCounters = Options.CompilationCountLimit.getValue(options) > 0 ? new CompilationCounters(options) : null; 94 this.bootstrapWatchDog = graalRuntime.isBootstrapping() && !DebugOptions.BootstrapInitializeOnly.getValue(options) ? BootstrapWatchDog.maybeCreate(graalRuntime) : null; 95 } 96 97 public List<DebugHandlersFactory> getDebugHandlersFactories() { 98 if (factories == null) { 99 factories = Collections.singletonList(new GraalDebugHandlersFactory(graalRuntime.getHostProviders().getSnippetReflection())); 100 } 101 return factories; 102 } 103 104 @Override 105 public HotSpotGraalRuntimeProvider getGraalRuntime() { 106 return graalRuntime; 107 } 108 109 @Override 110 public CompilationRequestResult compileMethod(CompilationRequest request) { 111 return compileMethod(request, true, graalRuntime.getOptions()); 112 } 113 114 @SuppressWarnings("try") 115 CompilationRequestResult compileMethod(CompilationRequest request, boolean installAsDefault, OptionValues options) { 116 if (graalRuntime.isShutdown()) { 117 return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false); 118 } 119 120 ResolvedJavaMethod method = request.getMethod(); 121 122 if (graalRuntime.isBootstrapping()) { 123 if (DebugOptions.BootstrapInitializeOnly.getValue(options)) { 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 try (CompilationWatchDog w1 = CompilationWatchDog.watch(method, hsRequest.getId(), options); 135 BootstrapWatchDog.Watch w2 = bootstrapWatchDog == null ? null : bootstrapWatchDog.watch(request); 136 CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(options);) { 137 if (compilationCounters != null) { 138 compilationCounters.countCompilation(method); 139 } 140 CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, installAsDefault, options); 141 CompilationRequestResult r = null; 142 try (DebugContext debug = graalRuntime.openDebugContext(options, task.getCompilationIdentifier(), method, getDebugHandlersFactories()); 143 Activation a = debug.activate()) { 144 r = task.runCompilation(debug); 145 } 146 assert r != null; 147 return r; 148 } 149 } 150 151 public StructuredGraph createGraph(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) { 152 HotSpotBackend backend = graalRuntime.getHostBackend(); 153 HotSpotProviders providers = backend.getProviders(); 154 final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; 155 StructuredGraph graph = method.isNative() || isOSR ? null : getIntrinsicGraph(method, providers, compilationId, options, debug); 156 157 if (graph == null) { 158 SpeculationLog speculationLog = method.getSpeculationLog(); 159 if (speculationLog != null) { 160 speculationLog.collectFailedSpeculations(); 161 } 162 graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.ifTrue(OptAssumptions.getValue(options))).method(method).entryBCI(entryBCI).speculationLog( 163 speculationLog).useProfilingInfo(useProfilingInfo).compilationId(compilationId).build(); 164 } 165 return graph; 166 } 167 168 public CompilationResult compileHelper(CompilationResultBuilderFactory crbf, CompilationResult result, StructuredGraph graph, ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, 169 OptionValues options) { 170 171 HotSpotBackend backend = graalRuntime.getHostBackend(); 172 HotSpotProviders providers = backend.getProviders(); 173 final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; 174 175 Suites suites = getSuites(providers, options); 176 LIRSuites lirSuites = getLIRSuites(providers, options); 177 ProfilingInfo profilingInfo = useProfilingInfo ? method.getProfilingInfo(!isOSR, isOSR) : DefaultProfilingInfo.get(TriState.FALSE); 178 OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo, options); 179 180 /* 181 * Cut off never executed code profiles if there is code, e.g. after the osr loop, that is 182 * never executed. 183 */ 184 if (isOSR && !OnStackReplacementPhase.Options.DeoptAfterOSR.getValue(options)) { 185 optimisticOpts.remove(Optimization.RemoveNeverExecutedCode); 186 } 187 188 result.setEntryBCI(entryBCI); 189 boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints(); 190 PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR); 191 GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf, true); 192 193 if (!isOSR && useProfilingInfo) { 194 ProfilingInfo profile = profilingInfo; 195 profile.setCompilerIRSize(StructuredGraph.class, graph.getNodeCount()); 196 } 197 198 return result; 199 } 200 201 public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) { 202 StructuredGraph graph = createGraph(method, entryBCI, useProfilingInfo, compilationId, options, debug); 203 CompilationResult result = new CompilationResult(compilationId); 204 return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options); 205 } 206 207 /** 208 * Gets a graph produced from the intrinsic for a given method that can be compiled and 209 * installed for the method. 210 * 211 * @param method 212 * @param compilationId 213 * @param options 214 * @param debug 215 * @return an intrinsic graph that can be compiled and installed for {@code method} or null 216 */ 217 @SuppressWarnings("try") 218 public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, HotSpotProviders providers, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) { 219 Replacements replacements = providers.getReplacements(); 220 Bytecode subst = replacements.getSubstitutionBytecode(method); 221 if (subst != null) { 222 ResolvedJavaMethod substMethod = subst.getMethod(); 223 assert !substMethod.equals(method); 224 BytecodeProvider bytecodeProvider = subst.getOrigin(); 225 // @formatter:off 226 StructuredGraph graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.YES). 227 method(substMethod). 228 compilationId(compilationId). 229 recordInlinedMethods(bytecodeProvider.shouldRecordMethodDependencies()). 230 setIsSubstitution(true). 231 build(); 232 // @formatter:on 233 try (DebugContext.Scope scope = debug.scope("GetIntrinsicGraph", graph)) { 234 Plugins plugins = new Plugins(providers.getGraphBuilderPlugins()); 235 GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); 236 IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, bytecodeProvider, ROOT_COMPILATION); 237 new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config, 238 OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); 239 assert !graph.isFrozen(); 240 return graph; 241 } catch (Throwable e) { 242 debug.handle(e); 243 } 244 } 245 return null; 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 isOSR specifies if extra OSR-specific post-processing is required (default is false) 268 * @return a new suite derived from {@code suite} if any of the GBS parameters did not have a 269 * default value otherwise {@code suite} 270 */ 271 protected PhaseSuite<HighTierContext> configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean isOSR) { 272 if (shouldDebugNonSafepoints || isOSR) { 273 PhaseSuite<HighTierContext> newGbs = suite.copy(); 274 275 if (shouldDebugNonSafepoints) { 276 GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous(); 277 GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig(); 278 graphBuilderConfig = graphBuilderConfig.withNodeSourcePosition(true); 279 GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig); 280 newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase); 281 } 282 if (isOSR) { 283 // We must not clear non liveness for OSR compilations. 284 GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous(); 285 GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig(); 286 GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig); 287 newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase); 288 newGbs.appendPhase(new OnStackReplacementPhase()); 289 } 290 return newGbs; 291 } 292 return suite; 293 } 294 295 /** 296 * Converts {@code method} to a String with {@link JavaMethod#format(String)} and the format 297 * string {@code "%H.%n(%p)"}. 298 */ 299 static String str(JavaMethod method) { 300 return method.format("%H.%n(%p)"); 301 } 302 303 /** 304 * Wraps {@code obj} in a {@link Formatter} that standardizes formatting for certain objects. 305 */ 306 static Formattable fmt(Object obj) { 307 return new Formattable() { 308 @Override 309 public void formatTo(Formatter buf, int flags, int width, int precision) { 310 if (obj instanceof Throwable) { 311 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 312 ((Throwable) obj).printStackTrace(new PrintStream(baos)); 313 buf.format("%s", baos.toString()); 314 } else if (obj instanceof StackTraceElement[]) { 315 for (StackTraceElement e : (StackTraceElement[]) obj) { 316 buf.format("\t%s%n", e); 317 } 318 } else if (obj instanceof JavaMethod) { 319 buf.format("%s", str((JavaMethod) obj)); 320 } else { 321 buf.format("%s", obj); 322 } 323 } 324 }; 325 } 326 }