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 }