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