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 package org.graalvm.compiler.hotspot; 24 25 import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions; 26 import static org.graalvm.compiler.nodes.StructuredGraph.NO_PROFILING_INFO; 27 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; 28 29 import java.io.ByteArrayOutputStream; 30 import java.io.PrintStream; 31 import java.util.Formattable; 32 import java.util.Formatter; 33 34 import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; 35 import org.graalvm.compiler.code.CompilationResult; 36 import org.graalvm.compiler.core.GraalCompiler; 37 import org.graalvm.compiler.core.common.CompilationIdentifier; 38 import org.graalvm.compiler.core.common.util.CompilationAlarm; 39 import org.graalvm.compiler.debug.Debug; 40 import org.graalvm.compiler.debug.DebugConfigScope; 41 import org.graalvm.compiler.debug.DebugEnvironment; 42 import org.graalvm.compiler.debug.GraalDebugConfig; 43 import org.graalvm.compiler.debug.TTY; 44 import org.graalvm.compiler.debug.TopLevelDebugConfig; 45 import org.graalvm.compiler.debug.internal.DebugScope; 46 import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo; 47 import org.graalvm.compiler.hotspot.CompilationCounters.Options; 48 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 49 import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase; 50 import org.graalvm.compiler.java.GraphBuilderPhase; 51 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 52 import org.graalvm.compiler.lir.phases.LIRSuites; 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.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; 57 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; 58 import org.graalvm.compiler.nodes.spi.Replacements; 59 import org.graalvm.compiler.phases.OptimisticOptimizations; 60 import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; 61 import org.graalvm.compiler.phases.PhaseSuite; 62 import org.graalvm.compiler.phases.tiers.HighTierContext; 63 import org.graalvm.compiler.phases.tiers.Suites; 64 65 import jdk.vm.ci.code.CompilationRequest; 66 import jdk.vm.ci.code.CompilationRequestResult; 67 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider; 68 import jdk.vm.ci.hotspot.HotSpotCompilationRequest; 69 import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult; 70 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; 71 import jdk.vm.ci.meta.DefaultProfilingInfo; 72 import jdk.vm.ci.meta.JavaMethod; 73 import jdk.vm.ci.meta.ProfilingInfo; 74 import jdk.vm.ci.meta.ResolvedJavaMethod; 75 import jdk.vm.ci.meta.SpeculationLog; 76 import jdk.vm.ci.meta.TriState; 77 import jdk.vm.ci.runtime.JVMCICompiler; 78 79 public class HotSpotGraalCompiler implements GraalJVMCICompiler { 80 81 private final HotSpotJVMCIRuntimeProvider jvmciRuntime; 82 private final HotSpotGraalRuntimeProvider graalRuntime; 83 private final CompilationCounters compilationCounters; 84 private final BootstrapWatchDog bootstrapWatchDog; 85 86 HotSpotGraalCompiler(HotSpotJVMCIRuntimeProvider jvmciRuntime, HotSpotGraalRuntimeProvider graalRuntime) { 87 this.jvmciRuntime = jvmciRuntime; 88 this.graalRuntime = graalRuntime; 89 // It is sufficient to have one compilation counter object per Graal compiler object. 90 this.compilationCounters = Options.CompilationCountLimit.getValue() > 0 ? new CompilationCounters() : null; 91 this.bootstrapWatchDog = graalRuntime.isBootstrapping() && !GraalDebugConfig.Options.BootstrapInitializeOnly.getValue() ? BootstrapWatchDog.maybeCreate(graalRuntime) : null; 92 } 93 94 @Override 95 public HotSpotGraalRuntimeProvider getGraalRuntime() { 96 return graalRuntime; 97 } 98 99 @Override 100 @SuppressWarnings("try") 101 public CompilationRequestResult compileMethod(CompilationRequest request) { 102 if (graalRuntime.isBootstrapping() && GraalDebugConfig.Options.BootstrapInitializeOnly.getValue()) { 103 return HotSpotCompilationRequestResult.failure(String.format("Skip compilation because %s is enabled", GraalDebugConfig.Options.BootstrapInitializeOnly.getName()), true); 104 } 105 if (bootstrapWatchDog != null && graalRuntime.isBootstrapping()) { 106 if (bootstrapWatchDog.hitCriticalCompilationRateOrTimeout()) { 107 // Drain the compilation queue to expedite completion of the bootstrap 108 return HotSpotCompilationRequestResult.failure("hit critical bootstrap compilation rate or timeout", true); 109 } 110 } 111 ResolvedJavaMethod method = request.getMethod(); 112 HotSpotCompilationRequest hsRequest = (HotSpotCompilationRequest) request; 113 try (CompilationWatchDog w1 = CompilationWatchDog.watch(method, hsRequest.getId()); 114 BootstrapWatchDog.Watch w2 = bootstrapWatchDog == null ? null : bootstrapWatchDog.watch(request); 115 CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod();) { 116 if (compilationCounters != null) { 117 compilationCounters.countCompilation(method); 118 } 119 // Ensure a debug configuration for this thread is initialized 120 if (Debug.isEnabled() && DebugScope.getConfig() == null) { 121 DebugEnvironment.initialize(TTY.out, graalRuntime.getHostProviders().getSnippetReflection()); 122 } 123 CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, true); 124 CompilationRequestResult r = null; 125 try (DebugConfigScope dcs = Debug.setConfig(new TopLevelDebugConfig()); 126 Debug.Scope s = Debug.methodMetricsScope("HotSpotGraalCompiler", MethodMetricsRootScopeInfo.create(method), true, method)) { 127 r = task.runCompilation(); 128 } 129 assert r != null; 130 return r; 131 } 132 } 133 134 public void compileTheWorld() throws Throwable { 135 HotSpotCodeCacheProvider codeCache = (HotSpotCodeCacheProvider) jvmciRuntime.getHostJVMCIBackend().getCodeCache(); 136 int iterations = CompileTheWorldOptions.CompileTheWorldIterations.getValue(); 137 for (int i = 0; i < iterations; i++) { 138 codeCache.resetCompilationStatistics(); 139 TTY.println("CompileTheWorld : iteration " + i); 140 CompileTheWorld ctw = new CompileTheWorld(jvmciRuntime, this); 141 ctw.compile(); 142 } 143 System.exit(0); 144 } 145 146 public CompilationResult compile(ResolvedJavaMethod method, int entryBCI, boolean useProfilingInfo, CompilationIdentifier compilationId) { 147 HotSpotBackend backend = graalRuntime.getHostBackend(); 148 HotSpotProviders providers = backend.getProviders(); 149 final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; 150 StructuredGraph graph = method.isNative() || isOSR ? null : getIntrinsicGraph(method, providers, compilationId); 151 152 if (graph == null) { 153 SpeculationLog speculationLog = method.getSpeculationLog(); 154 if (speculationLog != null) { 155 speculationLog.collectFailedSpeculations(); 156 } 157 graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()), speculationLog, useProfilingInfo, compilationId); 158 } 159 160 Suites suites = getSuites(providers); 161 LIRSuites lirSuites = getLIRSuites(providers); 162 ProfilingInfo profilingInfo = useProfilingInfo ? method.getProfilingInfo(!isOSR, isOSR) : DefaultProfilingInfo.get(TriState.FALSE); 163 OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo); 164 if (isOSR) { 165 // In OSR compiles, we cannot rely on never executed code profiles, because 166 // all code after the OSR loop is never executed. 167 optimisticOpts.remove(Optimization.RemoveNeverExecutedCode); 168 } 169 CompilationResult result = new CompilationResult(); 170 result.setEntryBCI(entryBCI); 171 boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints(); 172 PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR); 173 GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, CompilationResultBuilderFactory.Default); 174 175 if (!isOSR && useProfilingInfo) { 176 ProfilingInfo profile = profilingInfo; 177 profile.setCompilerIRSize(StructuredGraph.class, graph.getNodeCount()); 178 } 179 180 return result; 181 } 182 183 /** 184 * Gets a graph produced from the intrinsic for a given method that can be compiled and 185 * installed for the method. 186 * 187 * @param method 188 * @param compilationId 189 * @return an intrinsic graph that can be compiled and installed for {@code method} or null 190 */ 191 @SuppressWarnings("try") 192 public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, HotSpotProviders providers, CompilationIdentifier compilationId) { 193 Replacements replacements = providers.getReplacements(); 194 ResolvedJavaMethod substMethod = replacements.getSubstitutionMethod(method); 195 if (substMethod != null) { 196 assert !substMethod.equals(method); 197 StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES, NO_PROFILING_INFO, compilationId); 198 try (Debug.Scope scope = Debug.scope("GetIntrinsicGraph", graph)) { 199 Plugins plugins = new Plugins(providers.getGraphBuilderPlugins()); 200 GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); 201 IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, replacements.getReplacementBytecodeProvider(), ROOT_COMPILATION); 202 new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config, 203 OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); 204 assert !graph.isFrozen(); 205 return graph; 206 } catch (Throwable e) { 207 Debug.handle(e); 208 } 209 } 210 return null; 211 } 212 213 protected OptimisticOptimizations getOptimisticOpts(ProfilingInfo profilingInfo) { 214 return new OptimisticOptimizations(profilingInfo); 215 } 216 217 protected Suites getSuites(HotSpotProviders providers) { 218 return providers.getSuites().getDefaultSuites(); 219 } 220 221 protected LIRSuites getLIRSuites(HotSpotProviders providers) { 222 return providers.getSuites().getDefaultLIRSuites(); 223 } 224 225 /** 226 * Reconfigures a given graph builder suite (GBS) if one of the given GBS parameter values is 227 * not the default. 228 * 229 * @param suite the graph builder suite 230 * @param shouldDebugNonSafepoints specifies if extra debug info should be generated (default is 231 * false) 232 * @param isOSR specifies if extra OSR-specific post-processing is required (default is false) 233 * @return a new suite derived from {@code suite} if any of the GBS parameters did not have a 234 * default value otherwise {@code suite} 235 */ 236 protected PhaseSuite<HighTierContext> configGraphBuilderSuite(PhaseSuite<HighTierContext> suite, boolean shouldDebugNonSafepoints, boolean isOSR) { 237 if (shouldDebugNonSafepoints || isOSR) { 238 PhaseSuite<HighTierContext> newGbs = suite.copy(); 239 240 if (shouldDebugNonSafepoints) { 241 GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) newGbs.findPhase(GraphBuilderPhase.class).previous(); 242 GraphBuilderConfiguration graphBuilderConfig = graphBuilderPhase.getGraphBuilderConfig(); 243 graphBuilderConfig = graphBuilderConfig.withNodeSourcePosition(true); 244 GraphBuilderPhase newGraphBuilderPhase = new GraphBuilderPhase(graphBuilderConfig); 245 newGbs.findPhase(GraphBuilderPhase.class).set(newGraphBuilderPhase); 246 } 247 if (isOSR) { 248 newGbs.appendPhase(new OnStackReplacementPhase()); 249 } 250 return newGbs; 251 } 252 return suite; 253 } 254 255 /** 256 * Converts {@code method} to a String with {@link JavaMethod#format(String)} and the format 257 * string {@code "%H.%n(%p)"}. 258 */ 259 static String str(JavaMethod method) { 260 return method.format("%H.%n(%p)"); 261 } 262 263 /** 264 * Wraps {@code obj} in a {@link Formatter} that standardizes formatting for certain objects. 265 */ 266 static Formattable fmt(Object obj) { 267 return new Formattable() { 268 @Override 269 public void formatTo(Formatter buf, int flags, int width, int precision) { 270 if (obj instanceof Throwable) { 271 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 272 ((Throwable) obj).printStackTrace(new PrintStream(baos)); 273 buf.format("%s", baos.toString()); 274 } else if (obj instanceof StackTraceElement[]) { 275 for (StackTraceElement e : (StackTraceElement[]) obj) { 276 buf.format("\t%s%n", e); 277 } 278 } else if (obj instanceof JavaMethod) { 279 buf.format("%s", str((JavaMethod) obj)); 280 } else { 281 buf.format("%s", obj); 282 } 283 } 284 }; 285 } 286 }