1 /* 2 * Copyright (c) 2012, 2019, 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.hotspot; 26 27 import static org.graalvm.compiler.replacements.arraycopy.ArrayCopyForeignCalls.UNSAFE_ARRAYCOPY; 28 29 import java.util.EnumSet; 30 31 import jdk.internal.vm.compiler.collections.EconomicMap; 32 import jdk.internal.vm.compiler.collections.EconomicSet; 33 import jdk.internal.vm.compiler.collections.Equivalence; 34 import jdk.internal.vm.compiler.collections.MapCursor; 35 import org.graalvm.compiler.code.CompilationResult; 36 import org.graalvm.compiler.core.common.CompilationIdentifier; 37 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 38 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; 39 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 40 import org.graalvm.compiler.core.target.Backend; 41 import org.graalvm.compiler.graph.Node.ConstantNodeParameter; 42 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 43 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 44 import org.graalvm.compiler.hotspot.nodes.VMErrorNode; 45 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; 46 import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions; 47 import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions; 48 import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions; 49 import org.graalvm.compiler.hotspot.replacements.DigestBaseSubstitutions; 50 import org.graalvm.compiler.hotspot.replacements.SHA2Substitutions; 51 import org.graalvm.compiler.hotspot.replacements.SHA5Substitutions; 52 import org.graalvm.compiler.hotspot.replacements.SHASubstitutions; 53 import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub; 54 import org.graalvm.compiler.hotspot.stubs.Stub; 55 import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub; 56 import org.graalvm.compiler.hotspot.word.KlassPointer; 57 import org.graalvm.compiler.hotspot.word.MethodCountersPointer; 58 import org.graalvm.compiler.lir.LIR; 59 import org.graalvm.compiler.lir.LIRFrameState; 60 import org.graalvm.compiler.lir.LIRInstruction; 61 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag; 62 import org.graalvm.compiler.lir.LIRInstruction.OperandMode; 63 import org.graalvm.compiler.lir.StandardOp.LabelOp; 64 import org.graalvm.compiler.lir.StandardOp.RestoreRegistersOp; 65 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; 66 import org.graalvm.compiler.lir.ValueConsumer; 67 import org.graalvm.compiler.lir.asm.CompilationResultBuilder; 68 import org.graalvm.compiler.lir.framemap.FrameMap; 69 import org.graalvm.compiler.nodes.UnwindNode; 70 import org.graalvm.compiler.nodes.extended.ForeignCallNode; 71 import org.graalvm.compiler.options.Option; 72 import org.graalvm.compiler.options.OptionKey; 73 import org.graalvm.compiler.options.OptionType; 74 import org.graalvm.compiler.options.OptionValues; 75 import org.graalvm.compiler.phases.tiers.SuitesProvider; 76 import org.graalvm.compiler.serviceprovider.JavaVersionUtil; 77 import org.graalvm.compiler.word.Word; 78 import jdk.internal.vm.compiler.word.Pointer; 79 80 import jdk.vm.ci.code.CallingConvention; 81 import jdk.vm.ci.code.CompilationRequest; 82 import jdk.vm.ci.code.CompiledCode; 83 import jdk.vm.ci.code.Register; 84 import jdk.vm.ci.code.StackSlot; 85 import jdk.vm.ci.code.ValueUtil; 86 import jdk.vm.ci.hotspot.HotSpotCompilationRequest; 87 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; 88 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 89 import jdk.vm.ci.meta.AllocatableValue; 90 import jdk.vm.ci.meta.ResolvedJavaMethod; 91 import jdk.vm.ci.meta.Value; 92 import jdk.vm.ci.runtime.JVMCICompiler; 93 94 /** 95 * HotSpot specific backend. 96 */ 97 public abstract class HotSpotBackend extends Backend implements FrameMap.ReferenceMapBuilderFactory { 98 99 public static class Options { 100 // @formatter:off 101 @Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible") 102 public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(JavaVersionUtil.JAVA_SPEC >= 9); 103 @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." + 104 " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug) 105 public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null); 106 // @formatter:on 107 } 108 109 /** 110 * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the 111 * {@linkplain GraalHotSpotVMConfig#MARKID_EXCEPTION_HANDLER_ENTRY exception handler} in a 112 * compiled method. 113 */ 114 public static final ForeignCallDescriptor EXCEPTION_HANDLER = new ForeignCallDescriptor("exceptionHandler", void.class, Object.class, Word.class); 115 116 /** 117 * Descriptor for SharedRuntime::get_ic_miss_stub(). 118 */ 119 public static final ForeignCallDescriptor IC_MISS_HANDLER = new ForeignCallDescriptor("icMissHandler", void.class); 120 121 /** 122 * Descriptor for SharedRuntime::get_handle_wrong_method_stub(). 123 */ 124 public static final ForeignCallDescriptor WRONG_METHOD_HANDLER = new ForeignCallDescriptor("wrongMethodHandler", void.class); 125 126 /** 127 * Descriptor for {@link UnwindExceptionToCallerStub}. This stub is called by code generated 128 * from {@link UnwindNode}. 129 */ 130 public static final ForeignCallDescriptor UNWIND_EXCEPTION_TO_CALLER = new ForeignCallDescriptor("unwindExceptionToCaller", void.class, Object.class, Word.class); 131 132 /** 133 * Descriptor for the arguments when unwinding to an exception handler in a caller. 134 */ 135 public static final ForeignCallDescriptor EXCEPTION_HANDLER_IN_CALLER = new ForeignCallDescriptor("exceptionHandlerInCaller", void.class, Object.class, Word.class); 136 137 private final HotSpotGraalRuntimeProvider runtime; 138 139 /** 140 * @see AESCryptSubstitutions#encryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) 141 */ 142 public static final ForeignCallDescriptor ENCRYPT_BLOCK = new ForeignCallDescriptor("encrypt_block", void.class, Word.class, Word.class, Pointer.class); 143 144 /** 145 * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) 146 */ 147 public static final ForeignCallDescriptor DECRYPT_BLOCK = new ForeignCallDescriptor("decrypt_block", void.class, Word.class, Word.class, Pointer.class); 148 149 /** 150 * @see AESCryptSubstitutions#decryptBlockStub(ForeignCallDescriptor, Word, Word, Pointer) 151 */ 152 public static final ForeignCallDescriptor DECRYPT_BLOCK_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_block_with_original_key", void.class, Word.class, Word.class, Pointer.class, 153 Pointer.class); 154 155 /** 156 * @see CipherBlockChainingSubstitutions#crypt 157 */ 158 public static final ForeignCallDescriptor ENCRYPT = new ForeignCallDescriptor("encrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); 159 160 /** 161 * @see CipherBlockChainingSubstitutions#crypt 162 */ 163 public static final ForeignCallDescriptor DECRYPT = new ForeignCallDescriptor("decrypt", void.class, Word.class, Word.class, Pointer.class, Pointer.class, int.class); 164 165 /** 166 * @see CipherBlockChainingSubstitutions#crypt 167 */ 168 public static final ForeignCallDescriptor DECRYPT_WITH_ORIGINAL_KEY = new ForeignCallDescriptor("decrypt_with_original_key", void.class, Word.class, Word.class, Pointer.class, Pointer.class, 169 int.class, Pointer.class); 170 171 /** 172 * @see BigIntegerSubstitutions#multiplyToLen 173 */ 174 public static final ForeignCallDescriptor MULTIPLY_TO_LEN = new ForeignCallDescriptor("multiplyToLen", void.class, Word.class, int.class, Word.class, int.class, Word.class, int.class); 175 176 public static void multiplyToLenStub(Word xAddr, int xlen, Word yAddr, int ylen, Word zAddr, int zLen) { 177 multiplyToLenStub(HotSpotBackend.MULTIPLY_TO_LEN, xAddr, xlen, yAddr, ylen, zAddr, zLen); 178 } 179 180 @NodeIntrinsic(ForeignCallNode.class) 181 private static native void multiplyToLenStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xIn, int xLen, Word yIn, int yLen, Word zIn, int zLen); 182 183 /** 184 * @see BigIntegerSubstitutions#mulAdd 185 */ 186 public static final ForeignCallDescriptor MUL_ADD = new ForeignCallDescriptor("mulAdd", int.class, Word.class, Word.class, int.class, int.class, int.class); 187 188 public static int mulAddStub(Word inAddr, Word outAddr, int newOffset, int len, int k) { 189 return mulAddStub(HotSpotBackend.MUL_ADD, inAddr, outAddr, newOffset, len, k); 190 } 191 192 @NodeIntrinsic(ForeignCallNode.class) 193 private static native int mulAddStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word inAddr, Word outAddr, int newOffset, int len, int k); 194 195 /** 196 * @see BigIntegerSubstitutions#implMontgomeryMultiply 197 */ 198 public static final ForeignCallDescriptor MONTGOMERY_MULTIPLY = new ForeignCallDescriptor("implMontgomeryMultiply", void.class, Word.class, Word.class, Word.class, int.class, long.class, 199 Word.class); 200 201 public static void implMontgomeryMultiply(Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr) { 202 implMontgomeryMultiply(HotSpotBackend.MONTGOMERY_MULTIPLY, aAddr, bAddr, nAddr, len, inv, productAddr); 203 } 204 205 @NodeIntrinsic(ForeignCallNode.class) 206 private static native void implMontgomeryMultiply(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word bAddr, Word nAddr, int len, long inv, Word productAddr); 207 208 /** 209 * @see BigIntegerSubstitutions#implMontgomerySquare 210 */ 211 public static final ForeignCallDescriptor MONTGOMERY_SQUARE = new ForeignCallDescriptor("implMontgomerySquare", void.class, Word.class, Word.class, int.class, long.class, Word.class); 212 213 public static void implMontgomerySquare(Word aAddr, Word nAddr, int len, long inv, Word productAddr) { 214 implMontgomerySquare(HotSpotBackend.MONTGOMERY_SQUARE, aAddr, nAddr, len, inv, productAddr); 215 } 216 217 @NodeIntrinsic(ForeignCallNode.class) 218 private static native void implMontgomerySquare(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word nAddr, int len, long inv, Word productAddr); 219 220 /** 221 * @see BigIntegerSubstitutions#implSquareToLen 222 */ 223 public static final ForeignCallDescriptor SQUARE_TO_LEN = new ForeignCallDescriptor("implSquareToLen", void.class, Word.class, int.class, Word.class, int.class); 224 225 public static void implSquareToLen(Word xAddr, int len, Word zAddr, int zLen) { 226 implSquareToLen(SQUARE_TO_LEN, xAddr, len, zAddr, zLen); 227 } 228 229 @NodeIntrinsic(ForeignCallNode.class) 230 private static native void implSquareToLen(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word xAddr, int len, Word zAddr, int zLen); 231 232 /** 233 * @see SHASubstitutions#implCompress0 234 */ 235 public static final ForeignCallDescriptor SHA_IMPL_COMPRESS = new ForeignCallDescriptor("shaImplCompress", void.class, Word.class, Object.class); 236 237 public static void shaImplCompressStub(Word bufAddr, Object state) { 238 shaImplCompressStub(HotSpotBackend.SHA_IMPL_COMPRESS, bufAddr, state); 239 } 240 241 @NodeIntrinsic(ForeignCallNode.class) 242 private static native void shaImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); 243 244 /** 245 * @see SHA2Substitutions#implCompress0 246 */ 247 public static final ForeignCallDescriptor SHA2_IMPL_COMPRESS = new ForeignCallDescriptor("sha2ImplCompress", void.class, Word.class, Object.class); 248 249 public static void sha2ImplCompressStub(Word bufAddr, Object state) { 250 sha2ImplCompressStub(HotSpotBackend.SHA2_IMPL_COMPRESS, bufAddr, state); 251 } 252 253 @NodeIntrinsic(ForeignCallNode.class) 254 private static native void sha2ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); 255 256 /** 257 * @see SHA5Substitutions#implCompress0 258 */ 259 public static final ForeignCallDescriptor SHA5_IMPL_COMPRESS = new ForeignCallDescriptor("sha5ImplCompress", void.class, Word.class, Object.class); 260 261 public static void sha5ImplCompressStub(Word bufAddr, Object state) { 262 sha5ImplCompressStub(HotSpotBackend.SHA5_IMPL_COMPRESS, bufAddr, state); 263 } 264 265 @NodeIntrinsic(ForeignCallNode.class) 266 private static native void sha5ImplCompressStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state); 267 268 /** 269 * @see DigestBaseSubstitutions#implCompressMultiBlock0 270 */ 271 public static final ForeignCallDescriptor SHA_IMPL_COMPRESS_MB = new ForeignCallDescriptor("shaImplCompressMB", int.class, Word.class, Object.class, int.class, int.class); 272 273 public static int shaImplCompressMBStub(Word bufAddr, Object stateAddr, int ofs, int limit) { 274 return shaImplCompressMBStub(HotSpotBackend.SHA_IMPL_COMPRESS_MB, bufAddr, stateAddr, ofs, limit); 275 } 276 277 @NodeIntrinsic(ForeignCallNode.class) 278 private static native int shaImplCompressMBStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state, int ofs, int limit); 279 280 public static final ForeignCallDescriptor SHA2_IMPL_COMPRESS_MB = new ForeignCallDescriptor("sha2ImplCompressMB", int.class, Word.class, Object.class, int.class, int.class); 281 282 public static int sha2ImplCompressMBStub(Word bufAddr, Object stateAddr, int ofs, int limit) { 283 return sha2ImplCompressMBStub(HotSpotBackend.SHA2_IMPL_COMPRESS_MB, bufAddr, stateAddr, ofs, limit); 284 } 285 286 @NodeIntrinsic(ForeignCallNode.class) 287 private static native int sha2ImplCompressMBStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state, int ofs, int limit); 288 289 public static final ForeignCallDescriptor SHA5_IMPL_COMPRESS_MB = new ForeignCallDescriptor("sha5ImplCompressMB", int.class, Word.class, Object.class, int.class, int.class); 290 291 public static int sha5ImplCompressMBStub(Word bufAddr, Object stateAddr, int ofs, int limit) { 292 return sha5ImplCompressMBStub(HotSpotBackend.SHA5_IMPL_COMPRESS_MB, bufAddr, stateAddr, ofs, limit); 293 } 294 295 @NodeIntrinsic(ForeignCallNode.class) 296 private static native int sha5ImplCompressMBStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word bufAddr, Object state, int ofs, int limit); 297 298 public static void unsafeArraycopy(Word srcAddr, Word dstAddr, Word size) { 299 unsafeArraycopyStub(UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size); 300 } 301 302 @NodeIntrinsic(ForeignCallNode.class) 303 private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size); 304 305 /** 306 * Descriptor for {@code StubRoutines::_ghash_processBlocks}. 307 */ 308 public static final ForeignCallDescriptor GHASH_PROCESS_BLOCKS = new ForeignCallDescriptor("ghashProcessBlocks", void.class, Word.class, Word.class, Word.class, int.class); 309 310 /** 311 * Descriptor for {@code StubRoutines::_base64_encodeBlock}. 312 */ 313 public static final ForeignCallDescriptor BASE64_ENCODE_BLOCK = new ForeignCallDescriptor("base64EncodeBlock", void.class, Word.class, int.class, int.class, Word.class, int.class, boolean.class); 314 315 /** 316 * Descriptor for {@code StubRoutines::_counterMode_AESCrypt}. 317 */ 318 public static final ForeignCallDescriptor COUNTERMODE_IMPL_CRYPT = new ForeignCallDescriptor("counterModeAESCrypt", int.class, Word.class, Word.class, Word.class, Word.class, int.class, 319 Word.class, Word.class); 320 321 public static int counterModeAESCrypt(Word srcAddr, Word dstAddr, Word kPtr, Word cntPtr, int len, Word encCntPtr, Word used) { 322 return counterModeAESCrypt(COUNTERMODE_IMPL_CRYPT, srcAddr, dstAddr, kPtr, cntPtr, len, encCntPtr, used); 323 } 324 325 @NodeIntrinsic(ForeignCallNode.class) 326 private static native int counterModeAESCrypt(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word kPtr, Word cntPtr, int len, Word encCntPtr, 327 Word used); 328 329 /** 330 * Descriptor for {@code StubRoutines::_vectorizedMismatch}. 331 */ 332 public static final ForeignCallDescriptor VECTORIZED_MISMATCHED = new ForeignCallDescriptor("vectorizedMismatch", int.class, Word.class, Word.class, int.class, int.class); 333 334 public static int vectorizedMismatch(Word aAddr, Word bAddr, int length, int log2ArrayIndexScale) { 335 return vectorizedMismatchStub(VECTORIZED_MISMATCHED, aAddr, bAddr, length, log2ArrayIndexScale); 336 } 337 338 @NodeIntrinsic(ForeignCallNode.class) 339 private static native int vectorizedMismatchStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word aAddr, Word bAddr, int length, int log2ArrayIndexScale); 340 341 /** 342 * @see VMErrorNode 343 */ 344 public static final ForeignCallDescriptor VM_ERROR = new ForeignCallDescriptor("vm_error", void.class, Object.class, Object.class, long.class); 345 346 /** 347 * New multi array stub that throws an {@link OutOfMemoryError} on allocation failure. 348 */ 349 public static final ForeignCallDescriptor NEW_MULTI_ARRAY = new ForeignCallDescriptor("new_multi_array", Object.class, KlassPointer.class, int.class, Word.class); 350 351 /** 352 * New multi array stub that will return null on allocation failure. 353 */ 354 public static final ForeignCallDescriptor NEW_MULTI_ARRAY_OR_NULL = new ForeignCallDescriptor("new_multi_array_or_null", Object.class, KlassPointer.class, int.class, Word.class); 355 356 /** 357 * New array stub that throws an {@link OutOfMemoryError} on allocation failure. 358 */ 359 public static final ForeignCallDescriptor NEW_ARRAY = new ForeignCallDescriptor("new_array", Object.class, KlassPointer.class, int.class); 360 361 /** 362 * New array stub that will return null on allocation failure. 363 */ 364 public static final ForeignCallDescriptor NEW_ARRAY_OR_NULL = new ForeignCallDescriptor("new_array_or_null", Object.class, KlassPointer.class, int.class); 365 366 /** 367 * New instance stub that throws an {@link OutOfMemoryError} on allocation failure. 368 */ 369 public static final ForeignCallDescriptor NEW_INSTANCE = new ForeignCallDescriptor("new_instance", Object.class, KlassPointer.class); 370 371 /** 372 * New instance stub that will return null on allocation failure. 373 */ 374 public static final ForeignCallDescriptor NEW_INSTANCE_OR_NULL = new ForeignCallDescriptor("new_instance_or_null", Object.class, KlassPointer.class); 375 376 /** 377 * @see ResolveConstantStubCall 378 */ 379 public static final ForeignCallDescriptor RESOLVE_STRING_BY_SYMBOL = new ForeignCallDescriptor("resolve_string_by_symbol", Object.class, Word.class, Word.class); 380 381 /** 382 * @see ResolveConstantStubCall 383 */ 384 public static final ForeignCallDescriptor RESOLVE_DYNAMIC_INVOKE = new ForeignCallDescriptor("resolve_dynamic_invoke", Object.class, Word.class); 385 386 /** 387 * @see ResolveConstantStubCall 388 */ 389 public static final ForeignCallDescriptor RESOLVE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("resolve_klass_by_symbol", Word.class, Word.class, Word.class); 390 391 /** 392 * @see ResolveConstantStubCall 393 */ 394 public static final ForeignCallDescriptor INITIALIZE_KLASS_BY_SYMBOL = new ForeignCallDescriptor("initialize_klass_by_symbol", Word.class, Word.class, Word.class); 395 396 /** 397 * @see ResolveConstantStubCall 398 */ 399 public static final ForeignCallDescriptor RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS = new ForeignCallDescriptor("resolve_method_by_symbol_and_load_counters", Word.class, Word.class, Word.class, 400 Word.class); 401 402 /** 403 * Tiered support. 404 */ 405 public static final ForeignCallDescriptor INVOCATION_EVENT = new ForeignCallDescriptor("invocation_event", void.class, MethodCountersPointer.class); 406 public static final ForeignCallDescriptor BACKEDGE_EVENT = new ForeignCallDescriptor("backedge_event", void.class, MethodCountersPointer.class, int.class, int.class); 407 408 public HotSpotBackend(HotSpotGraalRuntimeProvider runtime, HotSpotProviders providers) { 409 super(providers); 410 this.runtime = runtime; 411 } 412 413 public HotSpotGraalRuntimeProvider getRuntime() { 414 return runtime; 415 } 416 417 /** 418 * Performs any remaining initialization that was deferred until the {@linkplain #getRuntime() 419 * runtime} object was initialized and this backend was registered with it. 420 * 421 * @param jvmciRuntime 422 * @param options 423 */ 424 public void completeInitialization(HotSpotJVMCIRuntime jvmciRuntime, OptionValues options) { 425 } 426 427 /** 428 * Finds all the registers that are defined by some given LIR. 429 * 430 * @param gen the result to examine 431 * @return the registers that are defined by or used as temps for any instruction in {@code lir} 432 */ 433 private EconomicSet<Register> gatherDestroyedCallerRegisters(HotSpotLIRGenerationResult gen) { 434 LIR lir = gen.getLIR(); 435 final EconomicSet<Register> preservedRegisters = EconomicSet.create(Equivalence.IDENTITY); 436 final EconomicSet<Register> destroyedRegisters = EconomicSet.create(Equivalence.IDENTITY); 437 ValueConsumer defConsumer = new ValueConsumer() { 438 439 @Override 440 public void visitValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) { 441 if (ValueUtil.isRegister(value)) { 442 final Register reg = ValueUtil.asRegister(value); 443 if (!preservedRegisters.contains(reg)) { 444 destroyedRegisters.add(reg); 445 } 446 } 447 } 448 }; 449 boolean sawSaveRegisters = false; 450 for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) { 451 if (block == null) { 452 continue; 453 } 454 // Ignore the effects of instructions bracketed by save/restore 455 SaveRegistersOp save = null; 456 for (LIRInstruction op : lir.getLIRforBlock(block)) { 457 if (op instanceof LabelOp) { 458 // Don't consider this as a definition 459 } else if (op instanceof SaveRegistersOp) { 460 save = (SaveRegistersOp) op; 461 sawSaveRegisters = true; 462 preservedRegisters.addAll(save.getSaveableRegisters()); 463 } else if (op instanceof RestoreRegistersOp) { 464 save = null; 465 preservedRegisters.clear(); 466 } else { 467 op.visitEachTemp(defConsumer); 468 op.visitEachOutput(defConsumer); 469 } 470 } 471 assert save == null : "missing RestoreRegistersOp"; 472 } 473 474 if (sawSaveRegisters) { 475 // The return value must be killed so it can be propagated out 476 CallingConvention cc = gen.getCallingConvention(); 477 AllocatableValue returnValue = cc.getReturn(); 478 if (returnValue != null) { 479 if (ValueUtil.isRegister(returnValue)) { 480 destroyedRegisters.add(ValueUtil.asRegister(returnValue)); 481 } 482 } 483 } 484 return translateToCallerRegisters(destroyedRegisters); 485 } 486 487 /** 488 * Translates a set of registers from the callee's perspective to the caller's perspective. This 489 * is needed for architectures where input/output registers are renamed during a call (e.g. 490 * register windows on SPARC). Registers which are not visible by the caller are removed. 491 */ 492 protected abstract EconomicSet<Register> translateToCallerRegisters(EconomicSet<Register> calleeRegisters); 493 494 /** 495 * Updates a given stub with respect to the registers it destroys by 496 * {@link #gatherDestroyedCallerRegisters(HotSpotLIRGenerationResult) computing the destroyed 497 * registers} and removing those registers from the {@linkplain SaveRegistersOp SaveRegistersOp} 498 * as these registers are declared as temporaries in the stub's {@linkplain ForeignCallLinkage 499 * linkage} (and thus will be saved by the stub's caller). 500 * 501 * @param stub the stub to update 502 * @param gen the HotSpotLIRGenerationResult being emitted 503 * @param frameMap used to {@linkplain FrameMap#offsetForStackSlot(StackSlot) convert} a virtual 504 */ 505 protected void updateStub(Stub stub, HotSpotLIRGenerationResult gen, FrameMap frameMap) { 506 EconomicSet<Register> destroyedRegisters = gatherDestroyedCallerRegisters(gen); 507 EconomicMap<LIRFrameState, SaveRegistersOp> calleeSaveInfo = gen.getCalleeSaveInfo(); 508 509 if (stub.getLinkage().needsDebugInfo() && calleeSaveInfo.isEmpty()) { 510 // This call is a safepoint but no register saving was done so we must ensure that all 511 // registers appear to be killed. The Native ABI may allow caller save registers but 512 // for HotSpot they must be described in a RegisterMap so they are accessible. 513 for (Register r : frameMap.getRegisterConfig().getCallerSaveRegisters()) { 514 destroyedRegisters.add(r); 515 } 516 } 517 518 stub.initDestroyedCallerRegisters(destroyedRegisters); 519 520 MapCursor<LIRFrameState, SaveRegistersOp> cursor = calleeSaveInfo.getEntries(); 521 while (cursor.advance()) { 522 SaveRegistersOp save = cursor.getValue(); 523 save.remove(destroyedRegisters); 524 if (cursor.getKey() != LIRFrameState.NO_STATE) { 525 cursor.getKey().debugInfo().setCalleeSaveInfo(save.getMap(frameMap)); 526 } 527 } 528 } 529 530 @Override 531 public HotSpotProviders getProviders() { 532 return (HotSpotProviders) super.getProviders(); 533 } 534 535 @Override 536 public SuitesProvider getSuites() { 537 return getProviders().getSuites(); 538 } 539 540 protected void profileInstructions(LIR lir, CompilationResultBuilder crb) { 541 if (HotSpotBackend.Options.ASMInstructionProfiling.getValue(lir.getOptions()) != null) { 542 HotSpotInstructionProfiling.countInstructions(lir, crb.asm); 543 } 544 } 545 546 @Override 547 public CompiledCode createCompiledCode(ResolvedJavaMethod method, 548 CompilationRequest compilationRequest, 549 CompilationResult compResult, 550 boolean isDefault, 551 OptionValues options) { 552 assert !isDefault || compResult.getName() == null : "a default nmethod should have a null name since it is associated with a Method*"; 553 HotSpotCompilationRequest compRequest = compilationRequest instanceof HotSpotCompilationRequest ? (HotSpotCompilationRequest) compilationRequest : null; 554 return HotSpotCompiledCodeBuilder.createCompiledCode(getCodeCache(), method, compRequest, compResult, options); 555 } 556 557 @Override 558 public CompilationIdentifier getCompilationIdentifier(ResolvedJavaMethod resolvedJavaMethod) { 559 if (resolvedJavaMethod instanceof HotSpotResolvedJavaMethod) { 560 HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) resolvedJavaMethod, JVMCICompiler.INVOCATION_ENTRY_BCI, 0L); 561 return new HotSpotCompilationIdentifier(request); 562 } 563 return super.getCompilationIdentifier(resolvedJavaMethod); 564 } 565 }