1 /* 2 * Copyright (c) 2009, 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.core; 24 25 import static org.graalvm.compiler.core.GraalCompilerOptions.EmitLIRRepeatCount; 26 import static org.graalvm.compiler.core.common.GraalOptions.UseGraalInstrumentation; 27 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional; 28 29 import java.util.Collection; 30 import java.util.List; 31 32 import org.graalvm.compiler.code.CompilationResult; 33 import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext; 34 import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder; 35 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; 36 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 37 import org.graalvm.compiler.core.common.util.CompilationAlarm; 38 import org.graalvm.compiler.core.target.Backend; 39 import org.graalvm.compiler.debug.Debug; 40 import org.graalvm.compiler.debug.Debug.Scope; 41 import org.graalvm.compiler.debug.DebugCloseable; 42 import org.graalvm.compiler.debug.DebugCounter; 43 import org.graalvm.compiler.debug.DebugTimer; 44 import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo; 45 import org.graalvm.compiler.lir.BailoutAndRestartBackendException; 46 import org.graalvm.compiler.lir.LIR; 47 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 48 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 49 import org.graalvm.compiler.lir.framemap.FrameMap; 50 import org.graalvm.compiler.lir.framemap.FrameMapBuilder; 51 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 52 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 53 import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext; 54 import org.graalvm.compiler.lir.phases.LIRSuites; 55 import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; 56 import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext; 57 import org.graalvm.compiler.nodes.StructuredGraph; 58 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 59 import org.graalvm.compiler.nodes.cfg.Block; 60 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 61 import org.graalvm.compiler.options.OptionValue.OverrideScope; 62 import org.graalvm.compiler.phases.OptimisticOptimizations; 63 import org.graalvm.compiler.phases.PhaseSuite; 64 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; 65 import org.graalvm.compiler.phases.common.instrumentation.ExtractInstrumentationPhase; 66 import org.graalvm.compiler.phases.schedule.SchedulePhase; 67 import org.graalvm.compiler.phases.tiers.HighTierContext; 68 import org.graalvm.compiler.phases.tiers.LowTierContext; 69 import org.graalvm.compiler.phases.tiers.MidTierContext; 70 import org.graalvm.compiler.phases.tiers.Suites; 71 import org.graalvm.compiler.phases.tiers.TargetProvider; 72 import org.graalvm.compiler.phases.util.Providers; 73 74 import jdk.vm.ci.code.RegisterConfig; 75 import jdk.vm.ci.code.TargetDescription; 76 import jdk.vm.ci.code.site.ConstantReference; 77 import jdk.vm.ci.code.site.DataPatch; 78 import jdk.vm.ci.meta.Assumptions; 79 import jdk.vm.ci.meta.JavaConstant; 80 import jdk.vm.ci.meta.JavaKind; 81 import jdk.vm.ci.meta.ProfilingInfo; 82 import jdk.vm.ci.meta.ResolvedJavaField; 83 import jdk.vm.ci.meta.ResolvedJavaMethod; 84 import jdk.vm.ci.meta.VMConstant; 85 86 /** 87 * Static methods for orchestrating the compilation of a {@linkplain StructuredGraph graph}. 88 */ 89 public class GraalCompiler { 90 91 private static final DebugTimer CompilerTimer = Debug.timer("GraalCompiler"); 92 private static final DebugTimer FrontEnd = Debug.timer("FrontEnd"); 93 private static final DebugTimer BackEnd = Debug.timer("BackEnd"); 94 private static final DebugTimer EmitLIR = Debug.timer("EmitLIR"); 95 private static final DebugTimer EmitCode = Debug.timer("EmitCode"); 96 private static final LIRGenerationPhase LIR_GENERATION_PHASE = new LIRGenerationPhase(); 97 98 /** 99 * Encapsulates all the inputs to a {@linkplain GraalCompiler#compile(Request) compilation}. 100 */ 101 public static class Request<T extends CompilationResult> { 102 public final StructuredGraph graph; 103 public final ResolvedJavaMethod installedCodeOwner; 104 public final Providers providers; 105 public final Backend backend; 106 public final PhaseSuite<HighTierContext> graphBuilderSuite; 107 public final OptimisticOptimizations optimisticOpts; 108 public final ProfilingInfo profilingInfo; 109 public final Suites suites; 110 public final LIRSuites lirSuites; 111 public final T compilationResult; 112 public final CompilationResultBuilderFactory factory; 113 114 /** 115 * @param graph the graph to be compiled 116 * @param installedCodeOwner the method the compiled code will be associated with once 117 * installed. This argument can be null. 118 * @param providers 119 * @param backend 120 * @param graphBuilderSuite 121 * @param optimisticOpts 122 * @param profilingInfo 123 * @param suites 124 * @param lirSuites 125 * @param compilationResult 126 * @param factory 127 */ 128 public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite, 129 OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) { 130 this.graph = graph; 131 this.installedCodeOwner = installedCodeOwner; 132 this.providers = providers; 133 this.backend = backend; 134 this.graphBuilderSuite = graphBuilderSuite; 135 this.optimisticOpts = optimisticOpts; 136 this.profilingInfo = profilingInfo; 137 this.suites = suites; 138 this.lirSuites = lirSuites; 139 this.compilationResult = compilationResult; 140 this.factory = factory; 141 } 142 143 /** 144 * Executes this compilation request. 145 * 146 * @return the result of the compilation 147 */ 148 public T execute() { 149 return GraalCompiler.compile(this); 150 } 151 } 152 153 /** 154 * Requests compilation of a given graph. 155 * 156 * @param graph the graph to be compiled 157 * @param installedCodeOwner the method the compiled code will be associated with once 158 * installed. This argument can be null. 159 * @return the result of the compilation 160 */ 161 public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, 162 PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, 163 CompilationResultBuilderFactory factory) { 164 return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory)); 165 } 166 167 /** 168 * Services a given compilation request. 169 * 170 * @return the result of the compilation 171 */ 172 @SuppressWarnings("try") 173 public static <T extends CompilationResult> T compile(Request<T> r) { 174 try (Scope s = MethodMetricsRootScopeInfo.createRootScopeIfAbsent(r.installedCodeOwner); 175 CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod()) { 176 assert !r.graph.isFrozen(); 177 try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start()) { 178 emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites); 179 emitBackEnd(r.graph, null, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites); 180 } catch (Throwable e) { 181 throw Debug.handle(e); 182 } 183 return r.compilationResult; 184 } 185 } 186 187 /** 188 * Builds the graph, optimizes it. 189 */ 190 @SuppressWarnings("try") 191 public static void emitFrontEnd(Providers providers, TargetProvider target, StructuredGraph graph, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, 192 ProfilingInfo profilingInfo, Suites suites) { 193 try (Scope s = Debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start()) { 194 HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts); 195 if (graph.start().next() == null) { 196 graphBuilderSuite.apply(graph, highTierContext); 197 new DeadCodeEliminationPhase(Optional).apply(graph); 198 } else { 199 Debug.dump(Debug.INFO_LOG_LEVEL, graph, "initial state"); 200 } 201 if (UseGraalInstrumentation.getValue()) { 202 new ExtractInstrumentationPhase().apply(graph, highTierContext); 203 } 204 205 suites.getHighTier().apply(graph, highTierContext); 206 graph.maybeCompress(); 207 208 MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo); 209 suites.getMidTier().apply(graph, midTierContext); 210 graph.maybeCompress(); 211 212 LowTierContext lowTierContext = new LowTierContext(providers, target); 213 suites.getLowTier().apply(graph, lowTierContext); 214 215 Debug.dump(Debug.BASIC_LOG_LEVEL, graph.getLastSchedule(), "Final HIR schedule"); 216 } catch (Throwable e) { 217 throw Debug.handle(e); 218 } 219 } 220 221 @SuppressWarnings("try") 222 public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, ResolvedJavaMethod installedCodeOwner, Backend backend, T compilationResult, 223 CompilationResultBuilderFactory factory, RegisterConfig registerConfig, LIRSuites lirSuites) { 224 try (Scope s = Debug.scope("BackEnd", graph.getLastSchedule()); DebugCloseable a = BackEnd.start()) { 225 // Repeatedly run the LIR code generation pass to improve statistical profiling results. 226 for (int i = 0; i < EmitLIRRepeatCount.getValue(); i++) { 227 SchedulePhase dummySchedule = new SchedulePhase(); 228 dummySchedule.apply(graph); 229 emitLIR(backend, graph, stub, registerConfig, lirSuites); 230 } 231 232 LIRGenerationResult lirGen = null; 233 lirGen = emitLIR(backend, graph, stub, registerConfig, lirSuites); 234 try (Scope s2 = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) { 235 int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize(); 236 compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess()); 237 emitCode(backend, graph.getAssumptions(), graph.method(), graph.getMethods(), graph.getFields(), bytecodeSize, lirGen, compilationResult, installedCodeOwner, factory); 238 } catch (Throwable e) { 239 throw Debug.handle(e); 240 } 241 } catch (Throwable e) { 242 throw Debug.handle(e); 243 } 244 } 245 246 @SuppressWarnings("try") 247 public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) { 248 OverrideScope overrideScope = null; 249 LIRSuites lirSuites0 = lirSuites; 250 while (true) { 251 try (OverrideScope scope = overrideScope) { 252 return emitLIR0(backend, graph, stub, registerConfig, lirSuites0); 253 } catch (BailoutAndRestartBackendException e) { 254 if (BailoutAndRestartBackendException.Options.LIRUnlockBackendRestart.getValue() && e.shouldRestart()) { 255 overrideScope = e.getOverrideScope(); 256 lirSuites0 = e.updateLIRSuites(lirSuites); 257 if (lirSuites0 != null) { 258 continue; 259 } 260 } 261 /* 262 * The BailoutAndRestartBackendException is permanent. If restart fails or is 263 * disabled we throw the bailout. 264 */ 265 throw e; 266 } 267 } 268 } 269 270 @SuppressWarnings("try") 271 private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) { 272 try (Scope ds = Debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start()) { 273 ScheduleResult schedule = graph.getLastSchedule(); 274 Block[] blocks = schedule.getCFG().getBlocks(); 275 Block startBlock = schedule.getCFG().getStartBlock(); 276 assert startBlock != null; 277 assert startBlock.getPredecessorCount() == 0; 278 279 LIR lir = null; 280 AbstractBlockBase<?>[] codeEmittingOrder = null; 281 AbstractBlockBase<?>[] linearScanOrder = null; 282 try (Scope s = Debug.scope("ComputeLinearScanOrder", lir)) { 283 codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock); 284 linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock); 285 286 lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder); 287 Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After linear scan order"); 288 } catch (Throwable e) { 289 throw Debug.handle(e); 290 } 291 FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig); 292 LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, graph, stub); 293 LIRGeneratorTool lirGen = backend.newLIRGenerator(lirGenRes); 294 NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen); 295 296 // LIR generation 297 LIRGenerationContext context = new LIRGenerationContext(lirGen, nodeLirGen, graph, schedule); 298 LIR_GENERATION_PHASE.apply(backend.getTarget(), lirGenRes, context); 299 300 try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) { 301 Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "After LIR generation"); 302 LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig)); 303 Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "Before code generation"); 304 return result; 305 } catch (Throwable e) { 306 throw Debug.handle(e); 307 } 308 } catch (Throwable e) { 309 throw Debug.handle(e); 310 } 311 } 312 313 protected static <T extends CompilationResult> String getCompilationUnitName(StructuredGraph graph, T compilationResult) { 314 if (compilationResult != null && compilationResult.getName() != null) { 315 return compilationResult.getName(); 316 } 317 ResolvedJavaMethod method = graph.method(); 318 if (method == null) { 319 return "<unknown>"; 320 } 321 return method.format("%H.%n(%p)"); 322 } 323 324 public static LIRGenerationResult emitLowLevel(TargetDescription target, LIRGenerationResult lirGenRes, LIRGeneratorTool lirGen, LIRSuites lirSuites, 325 RegisterAllocationConfig registerAllocationConfig) { 326 PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen); 327 lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, preAllocOptContext); 328 329 AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig); 330 lirSuites.getAllocationStage().apply(target, lirGenRes, allocContext); 331 332 PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen); 333 lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, postAllocOptContext); 334 335 return lirGenRes; 336 } 337 338 @SuppressWarnings("try") 339 public static void emitCode(Backend backend, Assumptions assumptions, ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods, Collection<ResolvedJavaField> accessedFields, 340 int bytecodeSize, LIRGenerationResult lirGenRes, 341 CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) { 342 try (DebugCloseable a = EmitCode.start()) { 343 FrameMap frameMap = lirGenRes.getFrameMap(); 344 CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory); 345 backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner); 346 if (assumptions != null && !assumptions.isEmpty()) { 347 compilationResult.setAssumptions(assumptions.toArray()); 348 } 349 if (rootMethod != null) { 350 compilationResult.setMethods(rootMethod, inlinedMethods); 351 compilationResult.setFields(accessedFields); 352 compilationResult.setBytecodeSize(bytecodeSize); 353 } 354 crb.finish(); 355 if (Debug.isCountEnabled()) { 356 List<DataPatch> ldp = compilationResult.getDataPatches(); 357 JavaKind[] kindValues = JavaKind.values(); 358 DebugCounter[] dms = new DebugCounter[kindValues.length]; 359 for (int i = 0; i < dms.length; i++) { 360 dms[i] = Debug.counter("DataPatches-%s", kindValues[i]); 361 } 362 363 for (DataPatch dp : ldp) { 364 JavaKind kind = JavaKind.Illegal; 365 if (dp.reference instanceof ConstantReference) { 366 VMConstant constant = ((ConstantReference) dp.reference).getConstant(); 367 if (constant instanceof JavaConstant) { 368 kind = ((JavaConstant) constant).getJavaKind(); 369 } 370 } 371 dms[kind.ordinal()].add(1); 372 } 373 374 Debug.counter("CompilationResults").increment(); 375 Debug.counter("CodeBytesEmitted").add(compilationResult.getTargetCodeSize()); 376 Debug.counter("InfopointsEmitted").add(compilationResult.getInfopoints().size()); 377 Debug.counter("DataPatches").add(ldp.size()); 378 Debug.counter("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size()); 379 } 380 381 Debug.dump(Debug.BASIC_LOG_LEVEL, compilationResult, "After code generation"); 382 } 383 } 384 }