1 /* 2 * Copyright (c) 2009, 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.core; 26 27 import org.graalvm.compiler.code.CompilationResult; 28 import org.graalvm.compiler.core.common.PermanentBailoutException; 29 import org.graalvm.compiler.core.common.RetryableBailoutException; 30 import org.graalvm.compiler.core.common.util.CompilationAlarm; 31 import org.graalvm.compiler.core.target.Backend; 32 import org.graalvm.compiler.debug.DebugCloseable; 33 import org.graalvm.compiler.debug.DebugContext; 34 import org.graalvm.compiler.debug.DebugContext.CompilerPhaseScope; 35 import org.graalvm.compiler.debug.MethodFilter; 36 import org.graalvm.compiler.debug.TimerKey; 37 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 38 import org.graalvm.compiler.lir.phases.LIRSuites; 39 import org.graalvm.compiler.nodes.StructuredGraph; 40 import org.graalvm.compiler.phases.OptimisticOptimizations; 41 import org.graalvm.compiler.phases.PhaseSuite; 42 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; 43 import org.graalvm.compiler.phases.tiers.HighTierContext; 44 import org.graalvm.compiler.phases.tiers.LowTierContext; 45 import org.graalvm.compiler.phases.tiers.MidTierContext; 46 import org.graalvm.compiler.phases.tiers.Suites; 47 import org.graalvm.compiler.phases.tiers.TargetProvider; 48 import org.graalvm.compiler.phases.util.Providers; 49 50 import jdk.vm.ci.meta.ProfilingInfo; 51 import jdk.vm.ci.meta.ResolvedJavaMethod; 52 53 /** 54 * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}. 55 */ 56 public class GraalCompiler { 57 58 private static final TimerKey CompilerTimer = DebugContext.timer("GraalCompiler").doc("Time spent in compilation (excludes code installation)."); 59 private static final TimerKey FrontEnd = DebugContext.timer("FrontEnd").doc("Time spent processing HIR."); 60 61 /** 62 * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}. 63 */ 64 public static class Request<T extends CompilationResult> { 65 public final StructuredGraph graph; 66 public final ResolvedJavaMethod installedCodeOwner; 67 public final Providers providers; 68 public final Backend backend; 69 public final PhaseSuite<HighTierContext> graphBuilderSuite; 70 public final OptimisticOptimizations optimisticOpts; 71 public final ProfilingInfo profilingInfo; 72 public final Suites suites; 73 public final LIRSuites lirSuites; 74 public final T compilationResult; 75 public final CompilationResultBuilderFactory factory; 76 public final boolean verifySourcePositions; 77 78 /** 79 * @param graph the graph to be compiled 80 * @param installedCodeOwner the method the compiled code will be associated with once 81 * installed. This argument can be null. 82 * @param providers 83 * @param backend 84 * @param graphBuilderSuite 85 * @param optimisticOpts 86 * @param profilingInfo 87 * @param suites 88 * @param lirSuites 89 * @param compilationResult 90 * @param factory 91 */ Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory, boolean verifySourcePositions)92 public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite, 93 OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory, 94 boolean verifySourcePositions) { 95 this.graph = graph; 96 this.installedCodeOwner = installedCodeOwner; 97 this.providers = providers; 98 this.backend = backend; 99 this.graphBuilderSuite = graphBuilderSuite; 100 this.optimisticOpts = optimisticOpts; 101 this.profilingInfo = profilingInfo; 102 this.suites = suites; 103 this.lirSuites = lirSuites; 104 this.compilationResult = compilationResult; 105 this.factory = factory; 106 this.verifySourcePositions = verifySourcePositions; 107 } 108 109 /** 110 * Executes this compilation request. 111 * 112 * @return the result of the compilation 113 */ execute()114 public T execute() { 115 return GraalCompiler.compile(this); 116 } 117 } 118 119 /** 120 * Requests compilation of a given graph. 121 * 122 * @param graph the graph to be compiled 123 * @param installedCodeOwner the method the compiled code will be associated with once 124 * installed. This argument can be null. 125 * @return the result of the compilation 126 */ compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory, boolean verifySourcePositions)127 public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, 128 PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, 129 CompilationResultBuilderFactory factory, boolean verifySourcePositions) { 130 return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory, 131 verifySourcePositions)); 132 } 133 134 /** 135 * Services a given compilation request. 136 * 137 * @return the result of the compilation 138 */ 139 @SuppressWarnings("try") compile(Request<T> r)140 public static <T extends CompilationResult> T compile(Request<T> r) { 141 DebugContext debug = r.graph.getDebug(); 142 try (CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(r.graph.getOptions())) { 143 assert !r.graph.isFrozen(); 144 try (DebugContext.Scope s0 = debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start(debug)) { 145 emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites); 146 r.backend.emitBackEnd(r.graph, null, r.installedCodeOwner, r.compilationResult, r.factory, null, r.lirSuites); 147 if (r.verifySourcePositions) { 148 assert r.graph.verifySourcePositions(true); 149 } 150 } catch (Throwable e) { 151 throw debug.handle(e); 152 } 153 checkForRequestedCrash(r.graph); 154 return r.compilationResult; 155 } 156 } 157 158 /** 159 * Checks whether the {@link GraalCompilerOptions#CrashAt} option indicates that the compilation 160 * of {@code graph} should result in an exception. 161 * 162 * @param graph a graph currently being compiled 163 * @throws RuntimeException if the value of {@link GraalCompilerOptions#CrashAt} matches 164 * {@code graph.method()} or {@code graph.name} 165 */ checkForRequestedCrash(StructuredGraph graph)166 private static void checkForRequestedCrash(StructuredGraph graph) { 167 String value = GraalCompilerOptions.CrashAt.getValue(graph.getOptions()); 168 if (value != null) { 169 boolean bailout = false; 170 boolean permanentBailout = false; 171 String methodPattern = value; 172 if (value.endsWith(":Bailout")) { 173 methodPattern = value.substring(0, value.length() - ":Bailout".length()); 174 bailout = true; 175 } else if (value.endsWith(":PermanentBailout")) { 176 methodPattern = value.substring(0, value.length() - ":PermanentBailout".length()); 177 permanentBailout = true; 178 } 179 String crashLabel = null; 180 if (graph.name != null && graph.name.contains(methodPattern)) { 181 crashLabel = graph.name; 182 } 183 if (crashLabel == null) { 184 ResolvedJavaMethod method = graph.method(); 185 MethodFilter filter = MethodFilter.parse(methodPattern); 186 if (filter.matches(method)) { 187 crashLabel = method.format("%H.%n(%p)"); 188 } 189 } 190 if (crashLabel != null) { 191 String crashMessage = "Forced crash after compiling " + crashLabel; 192 notifyCrash(crashMessage); 193 if (permanentBailout) { 194 throw new PermanentBailoutException(crashMessage); 195 } 196 if (bailout) { 197 throw new RetryableBailoutException(crashMessage); 198 } 199 throw new RuntimeException(crashMessage); 200 } 201 } 202 } 203 204 /** 205 * Substituted by {@code com.oracle.svm.graal.hotspot.libgraal. 206 * Target_org_graalvm_compiler_core_GraalCompiler} to optionally test routing fatal error 207 * handling from libgraal to HotSpot. 208 */ 209 @SuppressWarnings("unused") notifyCrash(String crashMessage)210 private static void notifyCrash(String crashMessage) { 211 } 212 213 /** 214 * Builds the graph, optimizes it. 215 */ 216 @SuppressWarnings("try") emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites)217 public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, 218 ProfilingInfo profilingInfo, Suites suites) { 219 DebugContext debug = graph.getDebug(); 220 try (DebugContext.Scope s = debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start(debug)) { 221 HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts); 222 if (graph.start().next() == null) { 223 try (CompilerPhaseScope cps = debug.enterCompilerPhase("Parsing")) { 224 graphBuilderSuite.apply(graph, highTierContext); 225 new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph); 226 debug.dump(DebugContext.BASIC_LEVEL, graph, "After parsing"); 227 } 228 } else { 229 debug.dump(DebugContext.INFO_LEVEL, graph, "initial state"); 230 } 231 232 suites.getHighTier().apply(graph, highTierContext); 233 graph.maybeCompress(); 234 debug.dump(DebugContext.BASIC_LEVEL, graph, "After high tier"); 235 236 MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo); 237 suites.getMidTier().apply(graph, midTierContext); 238 graph.maybeCompress(); 239 debug.dump(DebugContext.BASIC_LEVEL, graph, "After mid tier"); 240 241 LowTierContext lowTierContext = new LowTierContext(providers, target); 242 suites.getLowTier().apply(graph, lowTierContext); 243 debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier"); 244 245 debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule"); 246 graph.logInliningTree(); 247 } catch (Throwable e) { 248 throw debug.handle(e); 249 } finally { 250 graph.checkCancellation(); 251 } 252 } 253 getCompilationUnitName(StructuredGraph graph, T compilationResult)254 protected static <T extends CompilationResult> String getCompilationUnitName(StructuredGraph graph, T compilationResult) { 255 if (compilationResult != null && compilationResult.getName() != null) { 256 return compilationResult.getName(); 257 } 258 ResolvedJavaMethod method = graph.method(); 259 if (method == null) { 260 return "<unknown>"; 261 } 262 return method.format("%H.%n(%p)"); 263 } 264 } 265