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