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