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 24 25 package org.graalvm.compiler.core.target; 26 27 import java.util.ArrayList; 28 29 import jdk.internal.vm.compiler.collections.EconomicSet; 30 import org.graalvm.compiler.asm.Assembler; 31 import org.graalvm.compiler.code.CompilationResult; 32 import org.graalvm.compiler.core.common.CompilationIdentifier; 33 import org.graalvm.compiler.core.common.LIRKind; 34 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; 35 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 36 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; 37 import org.graalvm.compiler.debug.DebugContext; 38 import org.graalvm.compiler.lir.LIR; 39 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 40 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 41 import org.graalvm.compiler.lir.framemap.FrameMap; 42 import org.graalvm.compiler.lir.framemap.FrameMapBuilder; 43 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 44 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 45 import org.graalvm.compiler.nodes.StructuredGraph; 46 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 47 import org.graalvm.compiler.phases.tiers.SuitesProvider; 48 import org.graalvm.compiler.phases.tiers.TargetProvider; 49 import org.graalvm.compiler.phases.util.Providers; 50 51 import jdk.vm.ci.code.BailoutException; 52 import jdk.vm.ci.code.CodeCacheProvider; 53 import jdk.vm.ci.code.CompilationRequest; 54 import jdk.vm.ci.code.CompiledCode; 55 import jdk.vm.ci.code.InstalledCode; 56 import jdk.vm.ci.code.Register; 57 import jdk.vm.ci.code.RegisterConfig; 58 import jdk.vm.ci.code.TargetDescription; 59 import jdk.vm.ci.code.ValueKindFactory; 60 import jdk.vm.ci.meta.ConstantReflectionProvider; 61 import jdk.vm.ci.meta.JavaKind; 62 import jdk.vm.ci.meta.MetaAccessProvider; 63 import jdk.vm.ci.meta.ResolvedJavaMethod; 64 import jdk.vm.ci.meta.SpeculationLog; 65 66 /** 67 * Represents a compiler backend for Graal. 68 */ 69 public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKind> { 70 71 private final Providers providers; 72 private final ArrayList<CodeInstallationTaskFactory> codeInstallationTaskFactories; 73 74 public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class); 75 public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class); 76 77 protected Backend(Providers providers) { 78 this.providers = providers; 79 this.codeInstallationTaskFactories = new ArrayList<>(); 80 } 81 82 public synchronized void addCodeInstallationTask(CodeInstallationTaskFactory factory) { 83 this.codeInstallationTaskFactories.add(factory); 84 } 85 86 public Providers getProviders() { 87 return providers; 88 } 89 90 public CodeCacheProvider getCodeCache() { 91 return providers.getCodeCache(); 92 } 93 94 public MetaAccessProvider getMetaAccess() { 95 return providers.getMetaAccess(); 96 } 97 98 public ConstantReflectionProvider getConstantReflection() { 99 return providers.getConstantReflection(); 100 } 101 102 public ForeignCallsProvider getForeignCalls() { 103 return providers.getForeignCalls(); 104 } 105 106 public abstract SuitesProvider getSuites(); 107 108 @Override 109 public TargetDescription getTarget() { 110 return providers.getCodeCache().getTarget(); 111 } 112 113 @Override 114 public LIRKind getValueKind(JavaKind javaKind) { 115 return LIRKind.fromJavaKind(getTarget().arch, javaKind); 116 } 117 118 /** 119 * The given registerConfig is optional, in case null is passed the default RegisterConfig from 120 * the CodeCacheProvider will be used. 121 */ 122 public abstract FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig); 123 124 /** 125 * Creates a new configuration for register allocation. 126 * 127 * @param allocationRestrictedTo if not {@code null}, register allocation will be restricted to 128 * registers whose names appear in this array 129 */ 130 public abstract RegisterAllocationConfig newRegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo); 131 132 public abstract FrameMap newFrameMap(RegisterConfig registerConfig); 133 134 public abstract LIRGeneratorTool newLIRGenerator(LIRGenerationResult lirGenRes); 135 136 public abstract LIRGenerationResult newLIRGenerationResult(CompilationIdentifier compilationId, LIR lir, FrameMapBuilder frameMapBuilder, StructuredGraph graph, 137 Object stub); 138 139 public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen); 140 141 /** 142 * Creates the assembler used to emit the machine code. 143 */ 144 protected abstract Assembler createAssembler(FrameMap frameMap); 145 146 /** 147 * Creates the object used to fill in the details of a given compilation result. 148 */ 149 public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult, 150 CompilationResultBuilderFactory factory); 151 152 /** 153 * Turns a Graal {@link CompilationResult} into a {@link CompiledCode} object that can be passed 154 * to the VM for code installation. 155 */ 156 protected abstract CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult); 157 158 /** 159 * @see #createInstalledCode(DebugContext, ResolvedJavaMethod, CompilationRequest, 160 * CompilationResult, SpeculationLog, InstalledCode, boolean, Object[]) 161 */ 162 public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationResult compilationResult, 163 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { 164 return createInstalledCode(debug, method, null, compilationResult, speculationLog, predefinedInstalledCode, isDefault, null); 165 } 166 167 /** 168 * @see #createInstalledCode(DebugContext, ResolvedJavaMethod, CompilationRequest, 169 * CompilationResult, SpeculationLog, InstalledCode, boolean, Object[]) 170 */ 171 @SuppressWarnings("try") 172 public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, 173 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { 174 return createInstalledCode(debug, method, compilationRequest, compilationResult, speculationLog, predefinedInstalledCode, isDefault, null); 175 } 176 177 /** 178 * Installs code based on a given compilation result. 179 * 180 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 181 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 182 * @param compilationRequest the compilation request or {@code null} 183 * @param compilationResult the code to be installed 184 * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a 185 * reference to the installed code. If {@code null}, a new {@link InstalledCode} 186 * object will be created. 187 * @param speculationLog the speculation log to be used 188 * @param isDefault specifies if the installed code should be made the default implementation of 189 * {@code compRequest.getMethod()}. The default implementation for a method is the 190 * code executed for standard calls to the method. This argument is ignored if 191 * {@code compRequest == null}. 192 * @param context a custom debug context to use for the code installation 193 * @return a reference to the compiled and ready-to-run installed code 194 * @throws BailoutException if the code installation failed 195 */ 196 @SuppressWarnings("try") 197 public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, 198 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault, Object[] context) { 199 Object[] debugContext = context != null ? context : new Object[]{getProviders().getCodeCache(), method, compilationResult}; 200 CodeInstallationTask[] tasks; 201 synchronized (this) { 202 tasks = new CodeInstallationTask[codeInstallationTaskFactories.size()]; 203 for (int i = 0; i < codeInstallationTaskFactories.size(); i++) { 204 tasks[i] = codeInstallationTaskFactories.get(i).create(); 205 } 206 } 207 try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext); 208 DebugContext.Activation a = debug.activate()) { 209 210 InstalledCode installedCode; 211 try { 212 preCodeInstallationTasks(tasks, compilationResult, predefinedInstalledCode); 213 CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); 214 installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); 215 assert predefinedInstalledCode == null || installedCode == predefinedInstalledCode; 216 } catch (Throwable t) { 217 failCodeInstallationTasks(tasks, t); 218 throw t; 219 } 220 221 postCodeInstallationTasks(tasks, installedCode); 222 223 return installedCode; 224 } catch (Throwable e) { 225 throw debug.handle(e); 226 } 227 } 228 229 private static void failCodeInstallationTasks(CodeInstallationTask[] tasks, Throwable t) { 230 for (CodeInstallationTask task : tasks) { 231 task.installFailed(t); 232 } 233 } 234 235 private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult, InstalledCode predefinedInstalledCode) { 236 for (CodeInstallationTask task : tasks) { 237 task.preProcess(compilationResult, predefinedInstalledCode); 238 } 239 } 240 241 private static void postCodeInstallationTasks(CodeInstallationTask[] tasks, InstalledCode installedCode) { 242 try { 243 for (CodeInstallationTask task : tasks) { 244 task.postProcess(installedCode); 245 } 246 } catch (Throwable t) { 247 installedCode.invalidate(); 248 throw t; 249 } 250 } 251 252 /** 253 * Installs code based on a given compilation result. 254 * 255 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 256 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 257 * @param compilationRequest the request or {@code null} 258 * @param compilationResult the code to be compiled 259 * @return a reference to the compiled and ready-to-run installed code 260 * @throws BailoutException if the code installation failed 261 */ 262 public InstalledCode addInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult) { 263 return createInstalledCode(debug, method, compilationRequest, compilationResult, null, null, false); 264 } 265 266 /** 267 * Installs code based on a given compilation result and sets it as the default code to be used 268 * when {@code method} is invoked. 269 * 270 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 271 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 272 * @param compilationResult the code to be compiled 273 * @return a reference to the compiled and ready-to-run installed code 274 * @throws BailoutException if the code installation failed 275 */ 276 public InstalledCode createDefaultInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationResult compilationResult) { 277 return createInstalledCode(debug, method, compilationResult, null, null, true); 278 } 279 280 /** 281 * Emits the code for a given graph. 282 * 283 * @param installedCodeOwner the method the compiled code will be associated with once 284 * installed. This argument can be null. 285 */ 286 public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner); 287 288 /** 289 * Translates a set of registers from the callee's perspective to the caller's perspective. This 290 * is needed for architectures where input/output registers are renamed during a call (e.g. 291 * register windows on SPARC). Registers which are not visible by the caller are removed. 292 */ 293 public abstract EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters); 294 295 /** 296 * Gets the compilation id for a given {@link ResolvedJavaMethod}. Returns 297 * {@code CompilationIdentifier#INVALID_COMPILATION_ID} in case there is no such id. 298 * 299 * @param resolvedJavaMethod 300 */ 301 public CompilationIdentifier getCompilationIdentifier(ResolvedJavaMethod resolvedJavaMethod) { 302 return CompilationIdentifier.INVALID_COMPILATION_ID; 303 } 304 305 /** 306 * Encapsulates custom tasks done before and after code installation. 307 */ 308 public abstract static class CodeInstallationTask { 309 /** 310 * Task to run before code installation. 311 * 312 * @param compilationResult the code about to be installed 313 * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object that will be 314 * used as a reference to the installed code. May be {@code null}. 315 * 316 */ 317 public void preProcess(CompilationResult compilationResult, InstalledCode predefinedInstalledCode) { 318 } 319 320 /** 321 * Task to run after the code is installed. 322 * 323 * @param installedCode a reference to the installed code 324 */ 325 public void postProcess(InstalledCode installedCode) { 326 } 327 328 /** 329 * Invoked after {@link #preProcess} when code installation fails. 330 * 331 * @param cause the cause of the installation failure 332 */ 333 public void installFailed(Throwable cause) { 334 } 335 } 336 337 /** 338 * Creates code installation tasks. 339 */ 340 public abstract static class CodeInstallationTaskFactory { 341 public abstract CodeInstallationTask create(); 342 } 343 }