1 /*
   2  * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018, Red Hat Inc. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 
  26 
  27 package org.graalvm.compiler.hotspot.aarch64;
  28 
  29 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
  30 import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
  31 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
  32 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
  33 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
  34 import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
  35 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
  36 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
  37 import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
  38 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
  39 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
  40 
  41 import java.util.function.Function;
  42 
  43 import org.graalvm.compiler.asm.Label;
  44 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
  45 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
  46 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.PrefetchMode;
  47 import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator;
  48 import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator;
  49 import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
  50 import org.graalvm.compiler.core.common.CompressEncoding;
  51 import org.graalvm.compiler.core.common.LIRKind;
  52 import org.graalvm.compiler.core.common.calc.Condition;
  53 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  54 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  55 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  56 import org.graalvm.compiler.debug.GraalError;
  57 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  58 import org.graalvm.compiler.hotspot.HotSpotBackend;
  59 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
  60 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
  61 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
  62 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
  63 import org.graalvm.compiler.hotspot.HotSpotLockStack;
  64 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
  65 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  66 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
  67 import org.graalvm.compiler.hotspot.stubs.Stub;
  68 import org.graalvm.compiler.lir.LIRFrameState;
  69 import org.graalvm.compiler.lir.LIRInstruction;
  70 import org.graalvm.compiler.lir.LabelRef;
  71 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
  72 import org.graalvm.compiler.lir.SwitchStrategy;
  73 import org.graalvm.compiler.lir.Variable;
  74 import org.graalvm.compiler.lir.VirtualStackSlot;
  75 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
  76 import org.graalvm.compiler.lir.aarch64.AArch64CCall;
  77 import org.graalvm.compiler.lir.aarch64.AArch64Call;
  78 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
  79 import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder;
  80 import org.graalvm.compiler.lir.aarch64.AArch64Move;
  81 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
  82 import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp;
  83 import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp;
  84 import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp;
  85 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  86 import org.graalvm.compiler.options.OptionValues;
  87 
  88 import jdk.vm.ci.aarch64.AArch64;
  89 import jdk.vm.ci.aarch64.AArch64Kind;
  90 import jdk.vm.ci.code.CallingConvention;
  91 import jdk.vm.ci.code.Register;
  92 import jdk.vm.ci.code.RegisterValue;
  93 import jdk.vm.ci.code.StackSlot;
  94 import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
  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.SpeculationLog;
 105 import jdk.vm.ci.meta.Value;
 106 
 107 /**
 108  * LIR generator specialized for AArch64 HotSpot.
 109  */
 110 public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements HotSpotLIRGenerator {
 111 
 112     final GraalHotSpotVMConfig config;
 113     private HotSpotDebugInfoBuilder debugInfoBuilder;
 114 
 115     protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
 116         this(new AArch64LIRKindTool(), new AArch64ArithmeticLIRGenerator(null), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes);
 117     }
 118 
 119     protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
 120                     LIRGenerationResult lirGenRes) {
 121         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
 122         this.config = config;
 123     }
 124 
 125     @Override
 126     public HotSpotProviders getProviders() {
 127         return (HotSpotProviders) super.getProviders();
 128     }
 129 
 130     @Override
 131     public boolean needOnlyOopMaps() {
 132         // Stubs only need oop maps
 133         return getResult().getStub() != null;
 134     }
 135 
 136     private LIRFrameState currentRuntimeCallInfo;
 137 
 138     @Override
 139     protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
 140         currentRuntimeCallInfo = info;
 141         if (AArch64Call.isNearCall(linkage)) {
 142             append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label));
 143         } else {
 144             append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label));
 145         }
 146     }
 147 
 148     @Override
 149     public void emitTailcall(Value[] args, Value address) {
 150         throw GraalError.unimplemented();
 151     }
 152 
 153     @Override
 154     public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args) {
 155         Value[] argLocations = new Value[args.length];
 156         getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention);
 157         for (int i = 0; i < args.length; i++) {
 158             Value arg = args[i];
 159             AllocatableValue loc = nativeCallingConvention.getArgument(i);
 160             emitMove(loc, arg);
 161             argLocations[i] = loc;
 162         }
 163         Value ptr = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(address));
 164         append(new AArch64CCall(nativeCallingConvention.getReturn(), ptr, argLocations));
 165     }
 166 
 167     /**
 168      * @param savedRegisters the registers saved by this operation which may be subject to pruning
 169      * @param savedRegisterLocations the slots to which the registers are saved
 170      * @param supportsRemove determines if registers can be pruned
 171      */
 172     protected AArch64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
 173         AArch64SaveRegistersOp save = new AArch64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
 174         append(save);
 175         return save;
 176     }
 177 
 178     /**
 179      * Allocate a stack slot for saving a register.
 180      */
 181     protected VirtualStackSlot allocateSaveRegisterLocation(Register register) {
 182         PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory());
 183         if (kind.getVectorLength() > 1) {
 184             // we don't use vector registers, so there is no need to save them
 185             kind = AArch64Kind.QWORD;
 186         }
 187         return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
 188     }
 189 
 190     /**
 191      * Adds a node to the graph that saves all allocatable registers to the stack.
 192      *
 193      * @param supportsRemove determines if registers can be pruned
 194      * @return the register save node
 195      */
 196     private AArch64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) {
 197         AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
 198         for (int i = 0; i < savedRegisters.length; i++) {
 199             savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]);
 200         }
 201         return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
 202     }
 203 
 204     protected void emitRestoreRegisters(AArch64SaveRegistersOp save) {
 205         append(new AArch64RestoreRegistersOp(save.getSlots().clone(), save));
 206     }
 207 
 208     @Override
 209     public VirtualStackSlot getLockSlot(int lockDepth) {
 210         return getLockStack().makeLockSlot(lockDepth);
 211     }
 212 
 213     private HotSpotLockStack getLockStack() {
 214         assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
 215         return debugInfoBuilder.lockStack();
 216     }
 217 
 218     @Override
 219     public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 220                     double trueDestinationProbability) {
 221         Value localX = x;
 222         Value localY = y;
 223         if (localX instanceof HotSpotObjectConstant) {
 224             localX = load(localX);
 225         }
 226         if (localY instanceof HotSpotObjectConstant) {
 227             localY = load(localY);
 228         }
 229         super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
 230     }
 231 
 232     @Override
 233     protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) {
 234         Value localA = a;
 235         Value localB = b;
 236         if (isConstantValue(a)) {
 237             Constant c = asConstant(a);
 238             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 239                 localA = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD));
 240             } else if (c instanceof HotSpotObjectConstant) {
 241                 localA = load(localA);
 242             }
 243         }
 244         if (isConstantValue(b)) {
 245             Constant c = asConstant(b);
 246             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 247                 localB = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD));
 248             } else if (c instanceof HotSpotObjectConstant) {
 249                 localB = load(localB);
 250             }
 251         }
 252         return super.emitCompare(cmpKind, localA, localB, condition, unorderedIsTrue);
 253     }
 254 
 255     @Override
 256     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 257         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 258         LIRKindTool lirKindTool = getLIRKindTool();
 259         assert inputKind.getPlatformKind() == AArch64Kind.QWORD;
 260         if (inputKind.isReference(0)) {
 261             // oop
 262             Variable result = newVariable(LIRKind.compressedReference(AArch64Kind.DWORD));
 263             append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 264             return result;
 265         } else {
 266             // metaspace pointer
 267             Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
 268             AllocatableValue base = Value.ILLEGAL;
 269             OptionValues options = getResult().getLIR().getOptions();
 270             if (encoding.hasBase() || GeneratePIC.getValue(options)) {
 271                 if (GeneratePIC.getValue(options)) {
 272                     Variable baseAddress = newVariable(lirKindTool.getWordKind());
 273                     AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
 274                     append(move);
 275                     base = baseAddress;
 276                 } else {
 277                     base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
 278                 }
 279             }
 280             append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 281             return result;
 282         }
 283     }
 284 
 285     @Override
 286     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 287         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 288         assert inputKind.getPlatformKind() == AArch64Kind.DWORD;
 289         if (inputKind.isReference(0)) {
 290             // oop
 291             Variable result = newVariable(LIRKind.reference(AArch64Kind.QWORD));
 292             append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 293             return result;
 294         } else {
 295             // metaspace pointer
 296             Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD));
 297             AllocatableValue base = Value.ILLEGAL;
 298             OptionValues options = getResult().getLIR().getOptions();
 299             if (encoding.hasBase() || GeneratePIC.getValue(options)) {
 300                 if (GeneratePIC.getValue(options)) {
 301                     Variable baseAddress = newVariable(LIRKind.value(AArch64Kind.QWORD));
 302                     AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
 303                     append(move);
 304                     base = baseAddress;
 305                 } else {
 306                     base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
 307                 }
 308             }
 309             append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 310             return result;
 311         }
 312     }
 313 
 314     @Override
 315     public void emitNullCheck(Value address, LIRFrameState state) {
 316         if (address.getValueKind().getPlatformKind() == AArch64Kind.DWORD) {
 317             CompressEncoding encoding = config.getOopEncoding();
 318             Value uncompressed = emitUncompress(address, encoding, false);
 319             append(new AArch64Move.NullCheckOp(asAddressValue(uncompressed), state));
 320         } else {
 321             super.emitNullCheck(address, state);
 322         }
 323     }
 324 
 325     @Override
 326     public void emitPrefetchAllocate(Value address) {
 327         append(new AArch64PrefetchOp(asAddressValue(address), PrefetchMode.PSTL1KEEP));
 328     }
 329 
 330     @Override
 331     public void beforeRegisterAllocation() {
 332         super.beforeRegisterAllocation();
 333         boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
 334         if (hasDebugInfo) {
 335             getResult().setDeoptimizationRescueSlot(((AArch64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
 336         }
 337 
 338         getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
 339     }
 340 
 341     private Label label;
 342 
 343     @Override
 344     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
 345         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
 346         boolean destroysRegisters = hotspotLinkage.destroysRegisters();
 347 
 348         AArch64SaveRegistersOp save = null;
 349         Stub stub = getStub();
 350         if (destroysRegisters) {
 351             if (stub != null && stub.preservesRegisters()) {
 352                 Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray();
 353                 save = emitSaveAllRegisters(savedRegisters, true);
 354             }
 355         }
 356 
 357         Variable result;
 358         LIRFrameState debugInfo = null;
 359         if (hotspotLinkage.needsDebugInfo()) {
 360             debugInfo = state;
 361             assert debugInfo != null || getStub() != null;
 362         }
 363 
 364         if (destroysRegisters || hotspotLinkage.needsJavaFrameAnchor()) {
 365             HotSpotRegistersProvider registers = getProviders().getRegisters();
 366             Register thread = registers.getThreadRegister();
 367             Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind()));
 368 
 369             // We need a label for the return address.
 370             label = new Label();
 371 
 372             append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, scratch, label));
 373             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
 374             append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, label));
 375 
 376             // Clear it out so it's not being reused later.
 377             label = null;
 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 void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
 402         Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
 403         Value speculation = emitJavaConstant(getMetaAccess().encodeSpeculation(SpeculationLog.NO_SPECULATION));
 404         moveDeoptValuesToThread(actionAndReason, speculation);
 405         append(new AArch64HotSpotDeoptimizeCallerOp(config));
 406     }
 407 
 408     @Override
 409     public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
 410         moveDeoptValuesToThread(actionAndReason, failedSpeculation);
 411         append(new AArch64HotSpotDeoptimizeOp(state));
 412     }
 413 
 414     private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
 415         moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
 416         moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
 417     }
 418 
 419     private void moveValueToThread(Value value, int offset) {
 420         LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
 421         RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
 422         final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes();
 423         AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, offset, transferSize, AddressingMode.IMMEDIATE_SCALED);
 424         append(new StoreOp((AArch64Kind) value.getPlatformKind(), address, loadReg(value), null));
 425     }
 426 
 427     @Override
 428     public void emitUnwind(Value exception) {
 429         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
 430         CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
 431         assert outgoingCc.getArgumentCount() == 2;
 432         RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0);
 433         emitMove(exceptionParameter, exception);
 434         append(new AArch64HotSpotUnwindOp(config, exceptionParameter));
 435     }
 436 
 437     @Override
 438     public Value emitLoadObjectAddress(Constant constant) {
 439         HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
 440         LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind();
 441         Variable result = newVariable(kind);
 442         append(new AArch64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
 443         return result;
 444     }
 445 
 446     @Override
 447     public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
 448         HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
 449         LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind();
 450         Variable result = newVariable(kind);
 451         append(new AArch64HotSpotLoadAddressOp(result, constant, action));
 452         return result;
 453     }
 454 
 455     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
 456         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall);
 457         append(new AArch64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
 458         AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
 459         return emitMove(result);
 460     }
 461 
 462     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
 463         Constant[] constants = new Constant[]{constant};
 464         Object[] notes = new Object[]{action};
 465         return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState);
 466     }
 467 
 468     @Override
 469     public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) {
 470         AllocatableValue[] constantDescriptions = new AllocatableValue[0];
 471         return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState);
 472     }
 473 
 474     @Override
 475     public Value emitLoadConfigValue(int markId, LIRKind kind) {
 476         Variable result = newVariable(kind);
 477         append(new AArch64HotSpotLoadConfigValueOp(markId, result));
 478         return result;
 479     }
 480 
 481     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) {
 482         AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
 483         return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState);
 484     }
 485 
 486     @Override
 487     public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 488         return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
 489     }
 490 
 491     @Override
 492     public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 493         return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
 494     }
 495 
 496     @Override
 497     public void emitReturn(JavaKind kind, Value input) {
 498         AllocatableValue operand = Value.ILLEGAL;
 499         if (input != null) {
 500             operand = resultOperandFor(kind, input.getValueKind());
 501             emitMove(operand, input);
 502         }
 503         Register thread = getProviders().getRegisters().getThreadRegister();
 504         append(new AArch64HotSpotReturnOp(operand, getStub() != null, config, thread, getResult().requiresReservedStackAccessCheck()));
 505     }
 506 
 507     @Override
 508     public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 509         return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState);
 510     }
 511 
 512     @Override
 513     public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
 514         AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
 515         return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState);
 516     }
 517 
 518     /**
 519      * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
 520      * being generated.
 521      */
 522     public Stub getStub() {
 523         return getResult().getStub();
 524     }
 525 
 526     @Override
 527     public HotSpotLIRGenerationResult getResult() {
 528         return ((HotSpotLIRGenerationResult) super.getResult());
 529     }
 530 
 531     @Override
 532     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue,
 533                     Function<Condition, ConditionFlag> converter) {
 534         return new AArch64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter);
 535     }
 536 
 537     public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
 538         this.debugInfoBuilder = debugInfoBuilder;
 539     }
 540 
 541     @Override
 542     public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
 543         throw GraalError.unimplemented();
 544     }
 545 
 546     @Override
 547     public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
 548         throw GraalError.unimplemented();
 549     }
 550 }