1 /*
   2  * Copyright (c) 2012, 2017, 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 package org.graalvm.compiler.hotspot.amd64;
  24 
  25 import static jdk.vm.ci.amd64.AMD64.rbp;
  26 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  27 import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
  28 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
  29 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
  30 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
  31 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
  32 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
  33 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
  34 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
  35 
  36 import java.util.ArrayList;
  37 import java.util.List;
  38 
  39 import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
  40 import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
  41 import org.graalvm.compiler.core.amd64.AMD64LIRGenerator;
  42 import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
  43 import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
  44 import org.graalvm.compiler.core.common.CompressEncoding;
  45 import org.graalvm.compiler.core.common.LIRKind;
  46 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  47 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  48 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  49 import org.graalvm.compiler.debug.DebugContext;
  50 import org.graalvm.compiler.debug.GraalError;
  51 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  52 import org.graalvm.compiler.hotspot.HotSpotBackend;
  53 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
  54 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
  55 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
  56 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
  57 import org.graalvm.compiler.hotspot.HotSpotLockStack;
  58 import org.graalvm.compiler.hotspot.debug.BenchmarkCounters;
  59 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
  60 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  61 import org.graalvm.compiler.hotspot.stubs.Stub;
  62 import org.graalvm.compiler.lir.LIR;
  63 import org.graalvm.compiler.lir.LIRFrameState;
  64 import org.graalvm.compiler.lir.LIRInstruction;
  65 import org.graalvm.compiler.lir.LIRInstructionClass;
  66 import org.graalvm.compiler.lir.LabelRef;
  67 import org.graalvm.compiler.lir.StandardOp.NoOp;
  68 import org.graalvm.compiler.lir.SwitchStrategy;
  69 import org.graalvm.compiler.lir.Variable;
  70 import org.graalvm.compiler.lir.VirtualStackSlot;
  71 import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
  72 import org.graalvm.compiler.lir.amd64.AMD64CCall;
  73 import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
  74 import org.graalvm.compiler.lir.amd64.AMD64FrameMapBuilder;
  75 import org.graalvm.compiler.lir.amd64.AMD64Move;
  76 import org.graalvm.compiler.lir.amd64.AMD64Move.MoveFromRegOp;
  77 import org.graalvm.compiler.lir.amd64.AMD64PrefetchOp;
  78 import org.graalvm.compiler.lir.amd64.AMD64ReadTimestampCounter;
  79 import org.graalvm.compiler.lir.amd64.AMD64RestoreRegistersOp;
  80 import org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp;
  81 import org.graalvm.compiler.lir.amd64.AMD64VZeroUpper;
  82 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
  83 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
  84 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  85 import org.graalvm.compiler.options.OptionValues;
  86 
  87 import jdk.vm.ci.amd64.AMD64;
  88 import jdk.vm.ci.amd64.AMD64Kind;
  89 import jdk.vm.ci.code.CallingConvention;
  90 import jdk.vm.ci.code.Register;
  91 import jdk.vm.ci.code.RegisterConfig;
  92 import jdk.vm.ci.code.RegisterValue;
  93 import jdk.vm.ci.code.StackSlot;
  94 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
  95 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
  96 import jdk.vm.ci.meta.AllocatableValue;
  97 import jdk.vm.ci.meta.Constant;
  98 import jdk.vm.ci.meta.DeoptimizationAction;
  99 import jdk.vm.ci.meta.DeoptimizationReason;
 100 import jdk.vm.ci.meta.JavaConstant;
 101 import jdk.vm.ci.meta.JavaKind;
 102 import jdk.vm.ci.meta.PlatformKind;
 103 import jdk.vm.ci.meta.PrimitiveConstant;
 104 import jdk.vm.ci.meta.Value;
 105 
 106 /**
 107  * LIR generator specialized for AMD64 HotSpot.
 108  */
 109 public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSpotLIRGenerator {
 110 
 111     final GraalHotSpotVMConfig config;
 112     private HotSpotDebugInfoBuilder debugInfoBuilder;
 113 
 114     protected AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
 115         this(providers, config, lirGenRes, new BackupSlotProvider(lirGenRes.getFrameMapBuilder()));
 116     }
 117 
 118     private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
 119         this(new AMD64LIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
 120     }
 121 
 122     protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
 123                     LIRGenerationResult lirGenRes) {
 124         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
 125         assert config.basicLockSize == 8;
 126         this.config = config;
 127     }
 128 
 129     @Override
 130     public HotSpotProviders getProviders() {
 131         return (HotSpotProviders) super.getProviders();
 132     }
 133 
 134     /**
 135      * Utility for emitting the instruction to save RBP.
 136      */
 137     class SaveRbp {
 138 
 139         final NoOp placeholder;
 140 
 141         /**
 142          * The slot reserved for saving RBP.
 143          */
 144         final StackSlot reservedSlot;
 145 
 146         SaveRbp(NoOp placeholder) {
 147             this.placeholder = placeholder;
 148             AMD64FrameMapBuilder frameMapBuilder = (AMD64FrameMapBuilder) getResult().getFrameMapBuilder();
 149             this.reservedSlot = frameMapBuilder.allocateRBPSpillSlot();
 150         }
 151 
 152         /**
 153          * Replaces this operation with the appropriate move for saving rbp.
 154          *
 155          * @param useStack specifies if rbp must be saved to the stack
 156          */
 157         public AllocatableValue finalize(boolean useStack) {
 158             AllocatableValue dst;
 159             if (useStack) {
 160                 dst = reservedSlot;
 161             } else {
 162                 ((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).freeRBPSpillSlot();
 163                 dst = newVariable(LIRKind.value(AMD64Kind.QWORD));
 164             }
 165 
 166             placeholder.replace(getResult().getLIR(), new MoveFromRegOp(AMD64Kind.QWORD, dst, rbp.asValue(LIRKind.value(AMD64Kind.QWORD))));
 167             return dst;
 168         }
 169     }
 170 
 171     private SaveRbp saveRbp;
 172 
 173     protected void emitSaveRbp() {
 174         NoOp placeholder = new NoOp(getCurrentBlock(), getResult().getLIR().getLIRforBlock(getCurrentBlock()).size());
 175         append(placeholder);
 176         saveRbp = new SaveRbp(placeholder);
 177     }
 178 
 179     protected SaveRbp getSaveRbp() {
 180         return saveRbp;
 181     }
 182 
 183     /**
 184      * Helper instruction to reserve a stack slot for the whole method. Note that the actual users
 185      * of the stack slot might be inserted after stack slot allocation. This dummy instruction
 186      * ensures that the stack slot is alive and gets a real stack slot assigned.
 187      */
 188     private static final class RescueSlotDummyOp extends LIRInstruction {
 189         public static final LIRInstructionClass<RescueSlotDummyOp> TYPE = LIRInstructionClass.create(RescueSlotDummyOp.class);
 190 
 191         @Alive({OperandFlag.STACK, OperandFlag.UNINITIALIZED}) private AllocatableValue slot;
 192 
 193         RescueSlotDummyOp(FrameMapBuilder frameMapBuilder, LIRKind kind) {
 194             super(TYPE);
 195             slot = frameMapBuilder.allocateSpillSlot(kind);
 196         }
 197 
 198         public AllocatableValue getSlot() {
 199             return slot;
 200         }
 201 
 202         @Override
 203         public void emitCode(CompilationResultBuilder crb) {
 204         }
 205     }
 206 
 207     private RescueSlotDummyOp rescueSlotOp;
 208 
 209     private AllocatableValue getOrInitRescueSlot() {
 210         RescueSlotDummyOp op = getOrInitRescueSlotOp();
 211         return op.getSlot();
 212     }
 213 
 214     private RescueSlotDummyOp getOrInitRescueSlotOp() {
 215         if (rescueSlotOp == null) {
 216             // create dummy instruction to keep the rescue slot alive
 217             rescueSlotOp = new RescueSlotDummyOp(getResult().getFrameMapBuilder(), getLIRKindTool().getWordKind());
 218         }
 219         return rescueSlotOp;
 220     }
 221 
 222     /**
 223      * List of epilogue operations that need to restore RBP.
 224      */
 225     List<AMD64HotSpotRestoreRbpOp> epilogueOps = new ArrayList<>(2);
 226 
 227     @Override
 228     public <I extends LIRInstruction> I append(I op) {
 229         I ret = super.append(op);
 230         if (op instanceof AMD64HotSpotRestoreRbpOp) {
 231             epilogueOps.add((AMD64HotSpotRestoreRbpOp) op);
 232         }
 233         return ret;
 234     }
 235 
 236     @Override
 237     public VirtualStackSlot getLockSlot(int lockDepth) {
 238         return getLockStack().makeLockSlot(lockDepth);
 239     }
 240 
 241     private HotSpotLockStack getLockStack() {
 242         assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
 243         return debugInfoBuilder.lockStack();
 244     }
 245 
 246     private Register findPollOnReturnScratchRegister() {
 247         RegisterConfig regConfig = getProviders().getCodeCache().getRegisterConfig();
 248         for (Register r : regConfig.getAllocatableRegisters()) {
 249             if (!r.equals(regConfig.getReturnRegister(JavaKind.Long)) && !r.equals(AMD64.rbp)) {
 250                 return r;
 251             }
 252         }
 253         throw GraalError.shouldNotReachHere();
 254     }
 255 
 256     private Register pollOnReturnScratchRegister;
 257 
 258     @Override
 259     public void emitReturn(JavaKind kind, Value input) {
 260         AllocatableValue operand = Value.ILLEGAL;
 261         if (input != null) {
 262             operand = resultOperandFor(kind, input.getValueKind());
 263             emitMove(operand, input);
 264         }
 265         if (pollOnReturnScratchRegister == null) {
 266             pollOnReturnScratchRegister = findPollOnReturnScratchRegister();
 267         }
 268         append(new AMD64HotSpotReturnOp(operand, getStub() != null, pollOnReturnScratchRegister, config));
 269     }
 270 
 271     @Override
 272     public boolean needOnlyOopMaps() {
 273         // Stubs only need oop maps
 274         return getResult().getStub() != null;
 275     }
 276 
 277     private LIRFrameState currentRuntimeCallInfo;
 278 
 279     @Override
 280     protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
 281         currentRuntimeCallInfo = info;
 282         HotSpotForeignCallLinkage hsLinkage = (HotSpotForeignCallLinkage) linkage;
 283         AMD64 arch = (AMD64) target().arch;
 284         if (arch.getFeatures().contains(AMD64.CPUFeature.AVX) && hsLinkage.mayContainFP() && !hsLinkage.isCompiledStub()) {
 285             /*
 286              * If the target may contain FP ops, and it is not compiled by us, we may have an
 287              * AVX-SSE transition.
 288              *
 289              * We exclude the argument registers from the zeroing LIR instruction since it violates
 290              * the LIR semantics of @Temp that values must not be live. Note that the emitted
 291              * machine instruction actually zeros _all_ XMM registers which is fine since we know
 292              * that their upper half is not used.
 293              */
 294             append(new AMD64VZeroUpper(arguments));
 295         }
 296         super.emitForeignCallOp(linkage, result, arguments, temps, info);
 297     }
 298 
 299     /**
 300      * @param savedRegisters the registers saved by this operation which may be subject to pruning
 301      * @param savedRegisterLocations the slots to which the registers are saved
 302      * @param supportsRemove determines if registers can be pruned
 303      */
 304     protected AMD64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
 305         AMD64SaveRegistersOp save = new AMD64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
 306         append(save);
 307         return save;
 308     }
 309 
 310     /**
 311      * Allocate a stack slot for saving a register.
 312      */
 313     protected VirtualStackSlot allocateSaveRegisterLocation(Register register) {
 314         PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory());
 315         if (kind.getVectorLength() > 1) {
 316             // we don't use vector registers, so there is no need to save them
 317             kind = AMD64Kind.DOUBLE;
 318         }
 319         return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
 320     }
 321 
 322     /**
 323      * Adds a node to the graph that saves all allocatable registers to the stack.
 324      *
 325      * @param supportsRemove determines if registers can be pruned
 326      * @return the register save node
 327      */
 328     private AMD64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) {
 329         AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
 330         for (int i = 0; i < savedRegisters.length; i++) {
 331             savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]);
 332         }
 333         return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
 334     }
 335 
 336     protected void emitRestoreRegisters(AMD64SaveRegistersOp save) {
 337         append(new AMD64RestoreRegistersOp(save.getSlots().clone(), save));
 338     }
 339 
 340     /**
 341      * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
 342      * being generated.
 343      */
 344     public Stub getStub() {
 345         return getResult().getStub();
 346     }
 347 
 348     @Override
 349     public HotSpotLIRGenerationResult getResult() {
 350         return ((HotSpotLIRGenerationResult) super.getResult());
 351     }
 352 
 353     public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
 354         this.debugInfoBuilder = debugInfoBuilder;
 355     }
 356 
 357     @Override
 358     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
 359         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
 360         boolean destroysRegisters = hotspotLinkage.destroysRegisters();
 361 
 362         AMD64SaveRegistersOp save = null;
 363         Stub stub = getStub();
 364         if (destroysRegisters) {
 365             if (stub != null && stub.preservesRegisters()) {
 366                 Register[] savedRegisters = getResult().getFrameMapBuilder().getRegisterConfig().getAllocatableRegisters().toArray();
 367                 save = emitSaveAllRegisters(savedRegisters, true);
 368             }
 369         }
 370 
 371         Variable result;
 372         LIRFrameState debugInfo = null;
 373         if (hotspotLinkage.needsDebugInfo()) {
 374             debugInfo = state;
 375             assert debugInfo != null || stub != null;
 376         }
 377 
 378         if (hotspotLinkage.needsJavaFrameAnchor()) {
 379             Register thread = getProviders().getRegisters().getThreadRegister();
 380             append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread));
 381             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
 382             append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread));
 383         } else {
 384             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
 385         }
 386 
 387         if (destroysRegisters) {
 388             if (stub != null) {
 389                 if (stub.preservesRegisters()) {
 390                     HotSpotLIRGenerationResult generationResult = getResult();
 391                     LIRFrameState key = currentRuntimeCallInfo;
 392                     if (key == null) {
 393                         key = LIRFrameState.NO_STATE;
 394                     }
 395                     assert !generationResult.getCalleeSaveInfo().containsKey(key);
 396                     generationResult.getCalleeSaveInfo().put(key, save);
 397                     emitRestoreRegisters(save);
 398                 }
 399             }
 400         }
 401 
 402         return result;
 403     }
 404 
 405     @Override
 406     public Value emitLoadObjectAddress(Constant constant) {
 407         HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
 408         LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind();
 409         Variable result = newVariable(kind);
 410         append(new AMD64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
 411         return result;
 412     }
 413 
 414     @Override
 415     public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
 416         HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
 417         LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind();
 418         Variable result = newVariable(kind);
 419         append(new AMD64HotSpotLoadAddressOp(result, constant, action));
 420         return result;
 421     }
 422 
 423     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
 424         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall);
 425         append(new AMD64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
 426         AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
 427         return emitMove(result);
 428     }
 429 
 430     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
 431         Constant[] constants = new Constant[]{constant};
 432         Object[] notes = new Object[]{action};
 433         return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState);
 434     }
 435 
 436     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) {
 437         AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
 438         return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState);
 439     }
 440 
 441     @Override
 442     public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 443         return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
 444     }
 445 
 446     @Override
 447     public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 448         return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
 449     }
 450 
 451     @Override
 452     public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 453         return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState);
 454     }
 455 
 456     @Override
 457     public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
 458         AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
 459         return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState);
 460     }
 461 
 462     @Override
 463     public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) {
 464         AllocatableValue[] constantDescriptions = new AllocatableValue[0];
 465         return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState);
 466     }
 467 
 468     @Override
 469     public Value emitLoadConfigValue(int markId, LIRKind kind) {
 470         Variable result = newVariable(kind);
 471         append(new AMD64HotSpotLoadConfigValueOp(markId, result));
 472         return result;
 473     }
 474 
 475     @Override
 476     public Value emitRandomSeed() {
 477         AMD64ReadTimestampCounter timestamp = new AMD64ReadTimestampCounter();
 478         append(timestamp);
 479         return emitMove(timestamp.getLowResult());
 480     }
 481 
 482     @Override
 483     public void emitTailcall(Value[] args, Value address) {
 484         append(new AMD64TailcallOp(args, address));
 485     }
 486 
 487     @Override
 488     public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) {
 489         Value[] argLocations = new Value[args.length];
 490         getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention);
 491         // TODO(mg): in case a native function uses floating point varargs, the ABI requires that
 492         // RAX contains the length of the varargs
 493         PrimitiveConstant intConst = JavaConstant.forInt(numberOfFloatingPointArguments);
 494         AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD));
 495         emitMoveConstant(numberOfFloatingPointArgumentsRegister, intConst);
 496         for (int i = 0; i < args.length; i++) {
 497             Value arg = args[i];
 498             AllocatableValue loc = nativeCallingConvention.getArgument(i);
 499             emitMove(loc, arg);
 500             argLocations[i] = loc;
 501         }
 502         Value ptr = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(address));
 503         append(new AMD64CCall(nativeCallingConvention.getReturn(), ptr, numberOfFloatingPointArgumentsRegister, argLocations));
 504     }
 505 
 506     @Override
 507     public void emitUnwind(Value exception) {
 508         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
 509         CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
 510         assert outgoingCc.getArgumentCount() == 2;
 511         RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0);
 512         emitMove(exceptionParameter, exception);
 513         append(new AMD64HotSpotUnwindOp(exceptionParameter));
 514     }
 515 
 516     private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
 517         moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
 518         moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
 519     }
 520 
 521     private void moveValueToThread(Value v, int offset) {
 522         LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
 523         RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
 524         AMD64AddressValue address = new AMD64AddressValue(wordKind, thread, offset);
 525         arithmeticLIRGen.emitStore(v.getValueKind(), address, v, null);
 526     }
 527 
 528     @Override
 529     public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) {
 530         moveDeoptValuesToThread(actionAndReason, speculation);
 531         append(new AMD64DeoptimizeOp(state));
 532     }
 533 
 534     @Override
 535     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
 536         Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
 537         Value nullValue = emitConstant(LIRKind.reference(AMD64Kind.QWORD), JavaConstant.NULL_POINTER);
 538         moveDeoptValuesToThread(actionAndReason, nullValue);
 539         append(new AMD64HotSpotDeoptimizeCallerOp());
 540     }
 541 
 542     @Override
 543     public void beforeRegisterAllocation() {
 544         super.beforeRegisterAllocation();
 545         boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
 546         AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo);
 547         if (hasDebugInfo) {
 548             getResult().setDeoptimizationRescueSlot(((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
 549         }
 550 
 551         getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
 552 
 553         for (AMD64HotSpotRestoreRbpOp op : epilogueOps) {
 554             op.setSavedRbp(savedRbp);
 555         }
 556         if (BenchmarkCounters.enabled) {
 557             // ensure that the rescue slot is available
 558             LIRInstruction op = getOrInitRescueSlotOp();
 559             // insert dummy instruction into the start block
 560             LIR lir = getResult().getLIR();
 561             ArrayList<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock());
 562             instructions.add(1, op);
 563             lir.getDebug().dump(DebugContext.INFO_LEVEL, lir, "created rescue dummy op");
 564         }
 565     }
 566 
 567     @Override
 568     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 569         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 570         assert inputKind.getPlatformKind() == AMD64Kind.QWORD;
 571         if (inputKind.isReference(0)) {
 572             // oop
 573             Variable result = newVariable(LIRKind.reference(AMD64Kind.DWORD));
 574             append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 575             return result;
 576         } else {
 577             // metaspace pointer
 578             Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
 579             AllocatableValue base = Value.ILLEGAL;
 580             OptionValues options = getResult().getLIR().getOptions();
 581             if (encoding.hasBase() || GeneratePIC.getValue(options)) {
 582                 if (GeneratePIC.getValue(options)) {
 583                     Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
 584                     AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
 585                     append(move);
 586                     base = baseAddress;
 587                 } else {
 588                     base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
 589                 }
 590             }
 591             append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 592             return result;
 593         }
 594     }
 595 
 596     @Override
 597     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 598         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 599         assert inputKind.getPlatformKind() == AMD64Kind.DWORD;
 600         if (inputKind.isReference(0)) {
 601             // oop
 602             Variable result = newVariable(LIRKind.reference(AMD64Kind.QWORD));
 603             append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 604             return result;
 605         } else {
 606             // metaspace pointer
 607             Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD));
 608             AllocatableValue base = Value.ILLEGAL;
 609             OptionValues options = getResult().getLIR().getOptions();
 610             if (encoding.hasBase() || GeneratePIC.getValue(options)) {
 611                 if (GeneratePIC.getValue(options)) {
 612                     Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
 613                     AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
 614                     append(move);
 615                     base = baseAddress;
 616                 } else {
 617                     base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
 618                 }
 619             }
 620             append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 621             return result;
 622         }
 623     }
 624 
 625     @Override
 626     public void emitNullCheck(Value address, LIRFrameState state) {
 627         if (address.getValueKind().getPlatformKind() == AMD64Kind.DWORD) {
 628             CompressEncoding encoding = config.getOopEncoding();
 629             Value uncompressed;
 630             if (encoding.getShift() <= 3) {
 631                 LIRKind wordKind = LIRKind.unknownReference(target().arch.getWordKind());
 632                 uncompressed = new AMD64AddressValue(wordKind, getProviders().getRegisters().getHeapBaseRegister().asValue(wordKind), asAllocatable(address), Scale.fromInt(1 << encoding.getShift()),
 633                                 0);
 634             } else {
 635                 uncompressed = emitUncompress(address, encoding, false);
 636             }
 637             append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state));
 638         } else {
 639             super.emitNullCheck(address, state);
 640         }
 641     }
 642 
 643     @Override
 644     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
 645         if (BenchmarkCounters.enabled) {
 646             return new AMD64HotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, getOrInitRescueSlot());
 647         }
 648         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 649     }
 650 
 651     @Override
 652     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
 653         if (BenchmarkCounters.enabled) {
 654             return new AMD64HotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, getOrInitRescueSlot());
 655         }
 656         throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!");
 657     }
 658 
 659     @Override
 660     public void emitPrefetchAllocate(Value address) {
 661         append(new AMD64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr));
 662     }
 663 
 664     @Override
 665     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) {
 666         return new AMD64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp);
 667     }
 668 }