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.target; 24 25 import org.graalvm.compiler.asm.Assembler; 26 import org.graalvm.compiler.code.CompilationResult; 27 import org.graalvm.compiler.core.common.CompilationIdentifier; 28 import org.graalvm.compiler.core.common.LIRKind; 29 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; 30 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 31 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; 32 import org.graalvm.compiler.debug.Debug; 33 import org.graalvm.compiler.debug.Debug.Scope; 34 import org.graalvm.compiler.lir.LIR; 35 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 36 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 37 import org.graalvm.compiler.lir.framemap.FrameMap; 38 import org.graalvm.compiler.lir.framemap.FrameMapBuilder; 39 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 40 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 41 import org.graalvm.compiler.nodes.StructuredGraph; 42 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 43 import org.graalvm.compiler.phases.tiers.SuitesProvider; 44 import org.graalvm.compiler.phases.tiers.TargetProvider; 45 import org.graalvm.compiler.phases.util.Providers; 46 import org.graalvm.util.EconomicSet; 47 48 import jdk.vm.ci.code.BailoutException; 49 import jdk.vm.ci.code.CodeCacheProvider; 50 import jdk.vm.ci.code.CompilationRequest; 51 import jdk.vm.ci.code.CompiledCode; 52 import jdk.vm.ci.code.InstalledCode; 53 import jdk.vm.ci.code.Register; 54 import jdk.vm.ci.code.RegisterConfig; 55 import jdk.vm.ci.code.TargetDescription; 56 import jdk.vm.ci.code.ValueKindFactory; 57 import jdk.vm.ci.meta.ConstantReflectionProvider; 58 import jdk.vm.ci.meta.JavaKind; 59 import jdk.vm.ci.meta.MetaAccessProvider; 60 import jdk.vm.ci.meta.ResolvedJavaMethod; 61 import jdk.vm.ci.meta.SpeculationLog; 62 63 import java.util.ArrayList; 64 65 /** 66 * Represents a compiler backend for Graal. 67 */ 68 public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKind> { 69 70 private final Providers providers; 71 private final ArrayList<CodeInstallationTaskFactory> codeInstallationTaskFactories; 72 73 public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class); 74 public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class); 75 76 protected Backend(Providers providers) { 77 this.providers = providers; 78 this.codeInstallationTaskFactories = new ArrayList<>(); 79 } 80 81 public synchronized void addCodeInstallationTask(CodeInstallationTaskFactory factory) { 82 this.codeInstallationTaskFactories.add(factory); 83 } 84 138 public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen); 139 140 /** 141 * Creates the assembler used to emit the machine code. 142 */ 143 protected abstract Assembler createAssembler(FrameMap frameMap); 144 145 /** 146 * Creates the object used to fill in the details of a given compilation result. 147 */ 148 public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult, 149 CompilationResultBuilderFactory factory); 150 151 /** 152 * Turns a Graal {@link CompilationResult} into a {@link CompiledCode} object that can be passed 153 * to the VM for code installation. 154 */ 155 protected abstract CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult); 156 157 /** 158 * @see #createInstalledCode(ResolvedJavaMethod, CompilationRequest, CompilationResult, 159 * SpeculationLog, InstalledCode, boolean) 160 */ 161 public InstalledCode createInstalledCode(ResolvedJavaMethod method, CompilationResult compilationResult, 162 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { 163 return createInstalledCode(method, null, compilationResult, speculationLog, predefinedInstalledCode, isDefault); 164 } 165 166 /** 167 * @see #createInstalledCode(ResolvedJavaMethod, CompilationRequest, CompilationResult, 168 * SpeculationLog, InstalledCode, boolean, Object[]) 169 */ 170 @SuppressWarnings("try") 171 public InstalledCode createInstalledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, 172 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { 173 return createInstalledCode(method, compilationRequest, compilationResult, speculationLog, predefinedInstalledCode, isDefault, null); 174 } 175 176 /** 177 * Installs code based on a given compilation result. 178 * 179 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 180 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 181 * @param compilationRequest the compilation request or {@code null} 182 * @param compilationResult the code to be compiled 183 * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a 184 * reference to the installed code. If {@code null}, a new {@link InstalledCode} 185 * object will be created. 186 * @param speculationLog the speculation log to be used 187 * @param isDefault specifies if the installed code should be made the default implementation of 188 * {@code compRequest.getMethod()}. The default implementation for a method is the 189 * code executed for standard calls to the method. This argument is ignored if 190 * {@code compRequest == null}. 191 * @param context a custom debug context to use for the code installation. 192 * @return a reference to the compiled and ready-to-run installed code 193 * @throws BailoutException if the code installation failed 194 */ 195 @SuppressWarnings("try") 196 public InstalledCode createInstalledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, 197 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault, Object[] context) { 198 Object[] debugContext = context != null ? context : new Object[]{getProviders().getCodeCache(), method, compilationResult}; 199 CodeInstallationTask[] tasks = new CodeInstallationTask[codeInstallationTaskFactories.size()]; 200 for (int i = 0; i < codeInstallationTaskFactories.size(); i++) { 201 tasks[i] = codeInstallationTaskFactories.get(i).create(); 202 } 203 try (Scope s = Debug.scope("CodeInstall", debugContext)) { 204 for (CodeInstallationTask task : tasks) { 205 task.preProcess(compilationResult); 206 } 207 208 CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); 209 InstalledCode installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); 210 211 // Run post-code installation tasks. 212 try { 213 for (CodeInstallationTask task : tasks) { 214 task.postProcess(installedCode); 215 } 216 for (CodeInstallationTask task : tasks) { 217 task.releaseInstallation(installedCode); 218 } 219 } catch (Throwable t) { 220 installedCode.invalidate(); 221 throw t; 222 } 223 return installedCode; 224 } catch (Throwable e) { 225 throw Debug.handle(e); 226 } 227 } 228 229 /** 230 * Installs code based on a given compilation result. 231 * 232 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 233 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 234 * @param compilationRequest the request or {@code null} 235 * @param compilationResult the code to be compiled 236 * @return a reference to the compiled and ready-to-run installed code 237 * @throws BailoutException if the code installation failed 238 */ 239 public InstalledCode addInstalledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult) { 240 return createInstalledCode(method, compilationRequest, compilationResult, null, null, false); 241 } 242 243 /** 244 * Installs code based on a given compilation result and sets it as the default code to be used 245 * when {@code method} is invoked. 246 * 247 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 248 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 249 * @param compilationResult the code to be compiled 250 * @return a reference to the compiled and ready-to-run installed code 251 * @throws BailoutException if the code installation failed 252 */ 253 public InstalledCode createDefaultInstalledCode(ResolvedJavaMethod method, CompilationResult compilationResult) { 254 return createInstalledCode(method, compilationResult, null, null, true); 255 } 256 257 /** 258 * Emits the code for a given graph. 259 * 260 * @param installedCodeOwner the method the compiled code will be associated with once 261 * installed. This argument can be null. 262 */ 263 public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner); 264 265 /** 266 * Translates a set of registers from the callee's perspective to the caller's perspective. This 267 * is needed for architectures where input/output registers are renamed during a call (e.g. 268 * register windows on SPARC). Registers which are not visible by the caller are removed. 269 */ 270 public abstract EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters); 271 272 /** 273 * Gets the compilation id for a given {@link ResolvedJavaMethod}. Returns 274 * {@code CompilationIdentifier#INVALID_COMPILATION_ID} in case there is no such id. | 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.target; 24 25 import java.util.ArrayList; 26 27 import org.graalvm.compiler.asm.Assembler; 28 import org.graalvm.compiler.code.CompilationResult; 29 import org.graalvm.compiler.core.common.CompilationIdentifier; 30 import org.graalvm.compiler.core.common.LIRKind; 31 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig; 32 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 33 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; 34 import org.graalvm.compiler.debug.DebugContext; 35 import org.graalvm.compiler.lir.LIR; 36 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 37 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 38 import org.graalvm.compiler.lir.framemap.FrameMap; 39 import org.graalvm.compiler.lir.framemap.FrameMapBuilder; 40 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 41 import org.graalvm.compiler.lir.gen.LIRGeneratorTool; 42 import org.graalvm.compiler.nodes.StructuredGraph; 43 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; 44 import org.graalvm.compiler.phases.tiers.SuitesProvider; 45 import org.graalvm.compiler.phases.tiers.TargetProvider; 46 import org.graalvm.compiler.phases.util.Providers; 47 import org.graalvm.util.EconomicSet; 48 49 import jdk.vm.ci.code.BailoutException; 50 import jdk.vm.ci.code.CodeCacheProvider; 51 import jdk.vm.ci.code.CompilationRequest; 52 import jdk.vm.ci.code.CompiledCode; 53 import jdk.vm.ci.code.InstalledCode; 54 import jdk.vm.ci.code.Register; 55 import jdk.vm.ci.code.RegisterConfig; 56 import jdk.vm.ci.code.TargetDescription; 57 import jdk.vm.ci.code.ValueKindFactory; 58 import jdk.vm.ci.meta.ConstantReflectionProvider; 59 import jdk.vm.ci.meta.JavaKind; 60 import jdk.vm.ci.meta.MetaAccessProvider; 61 import jdk.vm.ci.meta.ResolvedJavaMethod; 62 import jdk.vm.ci.meta.SpeculationLog; 63 64 /** 65 * Represents a compiler backend for Graal. 66 */ 67 public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKind> { 68 69 private final Providers providers; 70 private final ArrayList<CodeInstallationTaskFactory> codeInstallationTaskFactories; 71 72 public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class); 73 public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class); 74 75 protected Backend(Providers providers) { 76 this.providers = providers; 77 this.codeInstallationTaskFactories = new ArrayList<>(); 78 } 79 80 public synchronized void addCodeInstallationTask(CodeInstallationTaskFactory factory) { 81 this.codeInstallationTaskFactories.add(factory); 82 } 83 137 public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen); 138 139 /** 140 * Creates the assembler used to emit the machine code. 141 */ 142 protected abstract Assembler createAssembler(FrameMap frameMap); 143 144 /** 145 * Creates the object used to fill in the details of a given compilation result. 146 */ 147 public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult, 148 CompilationResultBuilderFactory factory); 149 150 /** 151 * Turns a Graal {@link CompilationResult} into a {@link CompiledCode} object that can be passed 152 * to the VM for code installation. 153 */ 154 protected abstract CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult); 155 156 /** 157 * @see #createInstalledCode(DebugContext, ResolvedJavaMethod, CompilationRequest, 158 * CompilationResult, SpeculationLog, InstalledCode, boolean, Object[]) 159 */ 160 public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationResult compilationResult, 161 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { 162 return createInstalledCode(debug, method, null, compilationResult, speculationLog, predefinedInstalledCode, isDefault, null); 163 } 164 165 /** 166 * @see #createInstalledCode(DebugContext, ResolvedJavaMethod, CompilationRequest, 167 * CompilationResult, SpeculationLog, InstalledCode, boolean, Object[]) 168 */ 169 @SuppressWarnings("try") 170 public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, 171 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault) { 172 return createInstalledCode(debug, method, compilationRequest, compilationResult, speculationLog, predefinedInstalledCode, isDefault, null); 173 } 174 175 /** 176 * Installs code based on a given compilation result. 177 * 178 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 179 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 180 * @param compilationRequest the compilation request or {@code null} 181 * @param compilationResult the code to be compiled 182 * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a 183 * reference to the installed code. If {@code null}, a new {@link InstalledCode} 184 * object will be created. 185 * @param speculationLog the speculation log to be used 186 * @param isDefault specifies if the installed code should be made the default implementation of 187 * {@code compRequest.getMethod()}. The default implementation for a method is the 188 * code executed for standard calls to the method. This argument is ignored if 189 * {@code compRequest == null}. 190 * @param context a custom debug context to use for the code installation 191 * @return a reference to the compiled and ready-to-run installed code 192 * @throws BailoutException if the code installation failed 193 */ 194 @SuppressWarnings("try") 195 public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, 196 SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault, Object[] context) { 197 Object[] debugContext = context != null ? context : new Object[]{getProviders().getCodeCache(), method, compilationResult}; 198 CodeInstallationTask[] tasks = new CodeInstallationTask[codeInstallationTaskFactories.size()]; 199 for (int i = 0; i < codeInstallationTaskFactories.size(); i++) { 200 tasks[i] = codeInstallationTaskFactories.get(i).create(); 201 } 202 try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext); 203 DebugContext.Activation a = debug.activate()) { 204 for (CodeInstallationTask task : tasks) { 205 task.preProcess(compilationResult); 206 } 207 208 CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); 209 InstalledCode installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); 210 211 // Run post-code installation tasks. 212 try { 213 for (CodeInstallationTask task : tasks) { 214 task.postProcess(installedCode); 215 } 216 for (CodeInstallationTask task : tasks) { 217 task.releaseInstallation(installedCode); 218 } 219 } catch (Throwable t) { 220 installedCode.invalidate(); 221 throw t; 222 } 223 return installedCode; 224 } catch (Throwable e) { 225 throw debug.handle(e); 226 } 227 } 228 229 /** 230 * Installs code based on a given compilation result. 231 * 232 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 233 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 234 * @param compilationRequest the request or {@code null} 235 * @param compilationResult the code to be compiled 236 * @return a reference to the compiled and ready-to-run installed code 237 * @throws BailoutException if the code installation failed 238 */ 239 public InstalledCode addInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult) { 240 return createInstalledCode(debug, method, compilationRequest, compilationResult, null, null, false); 241 } 242 243 /** 244 * Installs code based on a given compilation result and sets it as the default code to be used 245 * when {@code method} is invoked. 246 * 247 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the 248 * input to {@code compResult} was not a {@link ResolvedJavaMethod} 249 * @param compilationResult the code to be compiled 250 * @return a reference to the compiled and ready-to-run installed code 251 * @throws BailoutException if the code installation failed 252 */ 253 public InstalledCode createDefaultInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationResult compilationResult) { 254 return createInstalledCode(debug, method, compilationResult, null, null, true); 255 } 256 257 /** 258 * Emits the code for a given graph. 259 * 260 * @param installedCodeOwner the method the compiled code will be associated with once 261 * installed. This argument can be null. 262 */ 263 public abstract void emitCode(CompilationResultBuilder crb, LIR lir, ResolvedJavaMethod installedCodeOwner); 264 265 /** 266 * Translates a set of registers from the callee's perspective to the caller's perspective. This 267 * is needed for architectures where input/output registers are renamed during a call (e.g. 268 * register windows on SPARC). Registers which are not visible by the caller are removed. 269 */ 270 public abstract EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters); 271 272 /** 273 * Gets the compilation id for a given {@link ResolvedJavaMethod}. Returns 274 * {@code CompilationIdentifier#INVALID_COMPILATION_ID} in case there is no such id. |