1 /*
   2  * Copyright (c) 2017, 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.core.gen;
  26 
  27 import java.util.Collection;
  28 import java.util.List;
  29 
  30 import jdk.internal.vm.compiler.collections.EconomicSet;
  31 import org.graalvm.compiler.code.CompilationResult;
  32 import org.graalvm.compiler.core.LIRGenerationPhase;
  33 import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext;
  34 import org.graalvm.compiler.core.common.GraalOptions;
  35 import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder;
  36 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
  37 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  38 import org.graalvm.compiler.core.target.Backend;
  39 import org.graalvm.compiler.debug.CounterKey;
  40 import org.graalvm.compiler.debug.DebugCloseable;
  41 import org.graalvm.compiler.debug.DebugContext;
  42 import org.graalvm.compiler.debug.GraalError;
  43 import org.graalvm.compiler.debug.TimerKey;
  44 import org.graalvm.compiler.lir.LIR;
  45 import org.graalvm.compiler.lir.alloc.OutOfRegistersException;
  46 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  47 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
  48 import org.graalvm.compiler.lir.framemap.FrameMap;
  49 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  50 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
  51 import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
  52 import org.graalvm.compiler.lir.phases.LIRSuites;
  53 import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
  54 import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
  55 import org.graalvm.compiler.nodes.StructuredGraph;
  56 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
  57 import org.graalvm.compiler.nodes.cfg.Block;
  58 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  59 
  60 import jdk.vm.ci.code.RegisterConfig;
  61 import jdk.vm.ci.code.TargetDescription;
  62 import jdk.vm.ci.code.site.ConstantReference;
  63 import jdk.vm.ci.code.site.DataPatch;
  64 import jdk.vm.ci.meta.Assumptions;
  65 import jdk.vm.ci.meta.JavaConstant;
  66 import jdk.vm.ci.meta.JavaKind;
  67 import jdk.vm.ci.meta.ResolvedJavaField;
  68 import jdk.vm.ci.meta.ResolvedJavaMethod;
  69 import jdk.vm.ci.meta.SpeculationLog;
  70 import jdk.vm.ci.meta.VMConstant;
  71 
  72 public class LIRCompilerBackend {
  73     private static final TimerKey EmitLIR = DebugContext.timer("EmitLIR").doc("Time spent generating LIR from HIR.");
  74     private static final TimerKey EmitCode = DebugContext.timer("EmitCode").doc("Time spent generating machine code from LIR.");
  75     private static final TimerKey BackEnd = DebugContext.timer("BackEnd").doc("Time spent in EmitLIR and EmitCode.");
  76 
  77     @SuppressWarnings("try")
  78     public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, ResolvedJavaMethod installedCodeOwner, Backend backend, T compilationResult,
  79                     CompilationResultBuilderFactory factory, RegisterConfig registerConfig, LIRSuites lirSuites) {
  80         DebugContext debug = graph.getDebug();
  81         try (DebugContext.Scope s = debug.scope("BackEnd", graph.getLastSchedule()); DebugCloseable a = BackEnd.start(debug)) {
  82             LIRGenerationResult lirGen = null;
  83             lirGen = emitLIR(backend, graph, stub, registerConfig, lirSuites);
  84             try (DebugContext.Scope s2 = debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
  85                 int bytecodeSize = graph.method() == null ? 0 : graph.getBytecodeSize();
  86                 compilationResult.setHasUnsafeAccess(graph.hasUnsafeAccess());
  87                 emitCode(backend,
  88                                 graph.getAssumptions(),
  89                                 graph.method(),
  90                                 graph.getMethods(),
  91                                 graph.getFields(),
  92                                 graph.getSpeculationLog(),
  93                                 bytecodeSize,
  94                                 lirGen,
  95                                 compilationResult,
  96                                 installedCodeOwner,
  97                                 factory);
  98             } catch (Throwable e) {
  99                 throw debug.handle(e);
 100             }
 101         } catch (Throwable e) {
 102             throw debug.handle(e);
 103         } finally {
 104             graph.checkCancellation();
 105         }
 106     }
 107 
 108     @SuppressWarnings("try")
 109     public static LIRGenerationResult emitLIR(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites) {
 110         String registerPressure = GraalOptions.RegisterPressure.getValue(graph.getOptions());
 111         String[] allocationRestrictedTo = registerPressure == null ? null : registerPressure.split(",");
 112         try {
 113             return emitLIR0(backend, graph, stub, registerConfig, lirSuites, allocationRestrictedTo);
 114         } catch (OutOfRegistersException e) {
 115             if (allocationRestrictedTo != null) {
 116                 allocationRestrictedTo = null;
 117                 return emitLIR0(backend, graph, stub, registerConfig, lirSuites, allocationRestrictedTo);
 118             }
 119             /* If the re-execution fails we convert the exception into a "hard" failure */
 120             throw new GraalError(e);
 121         } finally {
 122             graph.checkCancellation();
 123         }
 124     }
 125 
 126     @SuppressWarnings("try")
 127     private static LIRGenerationResult emitLIR0(Backend backend, StructuredGraph graph, Object stub, RegisterConfig registerConfig, LIRSuites lirSuites,
 128                     String[] allocationRestrictedTo) {
 129         DebugContext debug = graph.getDebug();
 130         try (DebugContext.Scope ds = debug.scope("EmitLIR"); DebugCloseable a = EmitLIR.start(debug)) {
 131             assert !graph.hasValueProxies();
 132 
 133             ScheduleResult schedule = graph.getLastSchedule();
 134             Block[] blocks = schedule.getCFG().getBlocks();
 135             Block startBlock = schedule.getCFG().getStartBlock();
 136             assert startBlock != null;
 137             assert startBlock.getPredecessorCount() == 0;
 138 
 139             AbstractBlockBase<?>[] codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
 140             AbstractBlockBase<?>[] linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
 141             LIR lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder, graph.getOptions(), graph.getDebug());
 142 
 143             LIRGenerationProvider lirBackend = (LIRGenerationProvider) backend;
 144             LIRGenerationResult lirGenRes = lirBackend.newLIRGenerationResult(graph.compilationId(), lir, registerConfig, graph, stub);
 145             LIRGeneratorTool lirGen = lirBackend.newLIRGenerator(lirGenRes);
 146             NodeLIRBuilderTool nodeLirGen = lirBackend.newNodeLIRBuilder(graph, lirGen);
 147 
 148             // LIR generation
 149             LIRGenerationContext context = new LIRGenerationContext(lirGen, nodeLirGen, graph, schedule);
 150             new LIRGenerationPhase().apply(backend.getTarget(), lirGenRes, context);
 151 
 152             try (DebugContext.Scope s = debug.scope("LIRStages", nodeLirGen, lirGenRes, lir)) {
 153                 // Dump LIR along with HIR (the LIR is looked up from context)
 154                 debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "After LIR generation");
 155                 LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig, allocationRestrictedTo));
 156                 return result;
 157             } catch (Throwable e) {
 158                 throw debug.handle(e);
 159             }
 160         } catch (Throwable e) {
 161             throw debug.handle(e);
 162         } finally {
 163             graph.checkCancellation();
 164         }
 165     }
 166 
 167     private static LIRGenerationResult emitLowLevel(TargetDescription target, LIRGenerationResult lirGenRes, LIRGeneratorTool lirGen, LIRSuites lirSuites,
 168                     RegisterAllocationConfig registerAllocationConfig) {
 169         DebugContext debug = lirGenRes.getLIR().getDebug();
 170         PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
 171         lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, preAllocOptContext);
 172         debug.dump(DebugContext.BASIC_LEVEL, lirGenRes.getLIR(), "After PreAllocationOptimizationStage");
 173 
 174         AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory(), registerAllocationConfig);
 175         lirSuites.getAllocationStage().apply(target, lirGenRes, allocContext);
 176         debug.dump(DebugContext.BASIC_LEVEL, lirGenRes.getLIR(), "After AllocationStage");
 177 
 178         PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext(lirGen);
 179         lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, postAllocOptContext);
 180         debug.dump(DebugContext.BASIC_LEVEL, lirGenRes.getLIR(), "After PostAllocationOptimizationStage");
 181 
 182         return lirGenRes;
 183     }
 184 
 185     @SuppressWarnings("try")
 186     public static void emitCode(Backend backend,
 187                     Assumptions assumptions,
 188                     ResolvedJavaMethod rootMethod,
 189                     Collection<ResolvedJavaMethod> inlinedMethods,
 190                     EconomicSet<ResolvedJavaField> accessedFields,
 191                     SpeculationLog speculationLog,
 192                     int bytecodeSize,
 193                     LIRGenerationResult lirGenRes,
 194                     CompilationResult compilationResult,
 195                     ResolvedJavaMethod installedCodeOwner,
 196                     CompilationResultBuilderFactory factory) {
 197         DebugContext debug = lirGenRes.getLIR().getDebug();
 198         try (DebugCloseable a = EmitCode.start(debug)) {
 199             LIRGenerationProvider lirBackend = (LIRGenerationProvider) backend;
 200 
 201             FrameMap frameMap = lirGenRes.getFrameMap();
 202             CompilationResultBuilder crb = lirBackend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory);
 203             lirBackend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner);
 204             if (assumptions != null && !assumptions.isEmpty()) {
 205                 compilationResult.setAssumptions(assumptions.toArray());
 206             }
 207             if (rootMethod != null) {
 208                 compilationResult.setMethods(rootMethod, inlinedMethods);
 209                 compilationResult.setFields(accessedFields);
 210                 compilationResult.setBytecodeSize(bytecodeSize);
 211             }
 212             if (speculationLog != null) {
 213                 compilationResult.setSpeculationLog(speculationLog);
 214             }
 215             crb.finish();
 216             if (debug.isCountEnabled()) {
 217                 List<DataPatch> ldp = compilationResult.getDataPatches();
 218                 JavaKind[] kindValues = JavaKind.values();
 219                 CounterKey[] dms = new CounterKey[kindValues.length];
 220                 for (int i = 0; i < dms.length; i++) {
 221                     dms[i] = DebugContext.counter("DataPatches-%s", kindValues[i]);
 222                 }
 223 
 224                 for (DataPatch dp : ldp) {
 225                     JavaKind kind = JavaKind.Illegal;
 226                     if (dp.reference instanceof ConstantReference) {
 227                         VMConstant constant = ((ConstantReference) dp.reference).getConstant();
 228                         if (constant instanceof JavaConstant) {
 229                             kind = ((JavaConstant) constant).getJavaKind();
 230                         }
 231                     }
 232                     dms[kind.ordinal()].add(debug, 1);
 233                 }
 234 
 235                 DebugContext.counter("CompilationResults").increment(debug);
 236                 DebugContext.counter("CodeBytesEmitted").add(debug, compilationResult.getTargetCodeSize());
 237                 DebugContext.counter("InfopointsEmitted").add(debug, compilationResult.getInfopoints().size());
 238                 DebugContext.counter("DataPatches").add(debug, ldp.size());
 239                 DebugContext.counter("ExceptionHandlersEmitted").add(debug, compilationResult.getExceptionHandlers().size());
 240             }
 241 
 242             debug.dump(DebugContext.BASIC_LEVEL, compilationResult, "After code generation");
 243         }
 244     }
 245 }