1 /*
   2  * Copyright (c) 2015, 2019, 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.EnumSet;
  42 import java.util.function.Function;
  43 
  44 import org.graalvm.compiler.asm.Label;
  45 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
  46 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
  47 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.PrefetchMode;
  48 import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator;
  49 import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator;
  50 import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
  51 import org.graalvm.compiler.core.common.CompressEncoding;
  52 import org.graalvm.compiler.core.common.GraalOptions;
  53 import org.graalvm.compiler.core.common.LIRKind;
  54 import org.graalvm.compiler.core.common.calc.Condition;
  55 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
  56 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
  57 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  58 import org.graalvm.compiler.debug.GraalError;
  59 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
  60 import org.graalvm.compiler.hotspot.HotSpotBackend;
  61 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder;
  62 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
  63 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
  64 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
  65 import org.graalvm.compiler.hotspot.HotSpotLockStack;
  66 import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
  67 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
  68 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
  69 import org.graalvm.compiler.hotspot.stubs.Stub;
  70 import org.graalvm.compiler.lir.LIRFrameState;
  71 import org.graalvm.compiler.lir.LIRInstruction;
  72 import org.graalvm.compiler.lir.LabelRef;
  73 import org.graalvm.compiler.lir.StandardOp.ZapRegistersOp;
  74 import org.graalvm.compiler.lir.SwitchStrategy;
  75 import org.graalvm.compiler.lir.Variable;
  76 import org.graalvm.compiler.lir.VirtualStackSlot;
  77 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
  78 import org.graalvm.compiler.lir.aarch64.AArch64CCall;
  79 import org.graalvm.compiler.lir.aarch64.AArch64Call;
  80 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
  81 import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder;
  82 import org.graalvm.compiler.lir.aarch64.AArch64Move;
  83 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
  84 import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp;
  85 import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp;
  86 import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp;
  87 import org.graalvm.compiler.lir.aarch64.AArch64ZeroMemoryOp;
  88 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
  89 import org.graalvm.compiler.options.OptionValues;
  90 
  91 import jdk.vm.ci.aarch64.AArch64;
  92 import jdk.vm.ci.aarch64.AArch64Kind;
  93 import jdk.vm.ci.code.CallingConvention;
  94 import jdk.vm.ci.code.Register;
  95 import jdk.vm.ci.code.RegisterValue;
  96 import jdk.vm.ci.code.StackSlot;
  97 import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
  98 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
  99 import jdk.vm.ci.hotspot.HotSpotObjectConstant;
 100 import jdk.vm.ci.meta.AllocatableValue;
 101 import jdk.vm.ci.meta.Constant;
 102 import jdk.vm.ci.meta.DeoptimizationAction;
 103 import jdk.vm.ci.meta.DeoptimizationReason;
 104 import jdk.vm.ci.meta.JavaConstant;
 105 import jdk.vm.ci.meta.JavaKind;
 106 import jdk.vm.ci.meta.PlatformKind;
 107 import jdk.vm.ci.meta.SpeculationLog;
 108 import jdk.vm.ci.meta.Value;
 109 
 110 /**
 111  * LIR generator specialized for AArch64 HotSpot.
 112  */
 113 public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements HotSpotLIRGenerator {
 114 
 115     final GraalHotSpotVMConfig config;
 116     private HotSpotDebugInfoBuilder debugInfoBuilder;
 117 
 118     protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) {
 119         this(new AArch64LIRKindTool(), new AArch64ArithmeticLIRGenerator(null), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes);
 120     }
 121 
 122     protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
 123                     LIRGenerationResult lirGenRes) {
 124         super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes);
 125         this.config = config;
 126     }
 127 
 128     @Override
 129     public HotSpotProviders getProviders() {
 130         return (HotSpotProviders) super.getProviders();
 131     }
 132 
 133     @Override
 134     public boolean needOnlyOopMaps() {
 135         // Stubs only need oop maps
 136         return getResult().getStub() != null;
 137     }
 138 
 139     private LIRFrameState currentRuntimeCallInfo;
 140 
 141     @Override
 142     protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
 143         currentRuntimeCallInfo = info;
 144         if (AArch64Call.isNearCall(linkage)) {
 145             append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label));
 146         } else {
 147             append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label));
 148         }
 149     }
 150 
 151     @Override
 152     public void emitTailcall(Value[] args, Value address) {
 153         throw GraalError.unimplemented();
 154     }
 155 
 156     @Override
 157     public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args) {
 158         Value[] argLocations = new Value[args.length];
 159         getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention);
 160         for (int i = 0; i < args.length; i++) {
 161             Value arg = args[i];
 162             AllocatableValue loc = nativeCallingConvention.getArgument(i);
 163             emitMove(loc, arg);
 164             argLocations[i] = loc;
 165         }
 166         Value ptr = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(address));
 167         append(new AArch64CCall(nativeCallingConvention.getReturn(), ptr, argLocations));
 168     }
 169 
 170     /**
 171      * @param savedRegisters the registers saved by this operation which may be subject to pruning
 172      * @param savedRegisterLocations the slots to which the registers are saved
 173      */
 174     protected AArch64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations) {
 175         AArch64SaveRegistersOp save = new AArch64SaveRegistersOp(savedRegisters, savedRegisterLocations);
 176         append(save);
 177         return save;
 178     }
 179 
 180     /**
 181      * Allocate a stack slot for saving a register.
 182      */
 183     protected VirtualStackSlot allocateSaveRegisterLocation(Register register) {
 184         PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory());
 185         if (kind.getVectorLength() > 1) {
 186             // we don't use vector registers, so there is no need to save them
 187             kind = AArch64Kind.DOUBLE;
 188         }
 189         return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
 190     }
 191 
 192     /**
 193      * Adds a node to the graph that saves all allocatable registers to the stack.
 194      *
 195      * @return the register save node
 196      */
 197     private AArch64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters) {
 198         AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
 199         for (int i = 0; i < savedRegisters.length; i++) {
 200             savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]);
 201         }
 202         return emitSaveRegisters(savedRegisters, savedRegisterLocations);
 203     }
 204 
 205     protected void emitRestoreRegisters(AArch64SaveRegistersOp save) {
 206         append(new AArch64RestoreRegistersOp(save.getSlots().clone(), save));
 207     }
 208 
 209     @Override
 210     public VirtualStackSlot getLockSlot(int lockDepth) {
 211         return getLockStack().makeLockSlot(lockDepth);
 212     }
 213 
 214     private HotSpotLockStack getLockStack() {
 215         assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null;
 216         return debugInfoBuilder.lockStack();
 217     }
 218 
 219     @Override
 220     public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 221                     double trueDestinationProbability) {
 222         Value localX = x;
 223         Value localY = y;
 224         if (localX instanceof HotSpotObjectConstant) {
 225             localX = load(localX);
 226         }
 227         if (localY instanceof HotSpotObjectConstant) {
 228             localY = load(localY);
 229         }
 230         super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability);
 231     }
 232 
 233     @Override
 234     protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) {
 235         Value localA = a;
 236         Value localB = b;
 237         if (isConstantValue(a)) {
 238             Constant c = asConstant(a);
 239             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 240                 localA = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD));
 241             } else if (c instanceof HotSpotObjectConstant) {
 242                 localA = load(localA);
 243             }
 244         }
 245         if (isConstantValue(b)) {
 246             Constant c = asConstant(b);
 247             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 248                 localB = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD));
 249             } else if (c instanceof HotSpotObjectConstant) {
 250                 localB = load(localB);
 251             }
 252         }
 253         return super.emitCompare(cmpKind, localA, localB, condition, unorderedIsTrue);
 254     }
 255 
 256     @Override
 257     public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 258         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 259         LIRKindTool lirKindTool = getLIRKindTool();
 260         assert inputKind.getPlatformKind() == AArch64Kind.QWORD;
 261         if (inputKind.isReference(0)) {
 262             // oop
 263             Variable result = newVariable(LIRKind.compressedReference(AArch64Kind.DWORD));
 264             append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 265             return result;
 266         } else {
 267             // metaspace pointer
 268             Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
 269             AllocatableValue base = Value.ILLEGAL;
 270             OptionValues options = getResult().getLIR().getOptions();
 271             if (encoding.hasBase() || GeneratePIC.getValue(options)) {
 272                 if (GeneratePIC.getValue(options)) {
 273                     Variable baseAddress = newVariable(lirKindTool.getWordKind());
 274                     AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
 275                     append(move);
 276                     base = baseAddress;
 277                 } else {
 278                     base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
 279                 }
 280             }
 281             append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 282             return result;
 283         }
 284     }
 285 
 286     @Override
 287     public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
 288         LIRKind inputKind = pointer.getValueKind(LIRKind.class);
 289         assert inputKind.getPlatformKind() == AArch64Kind.DWORD;
 290         if (inputKind.isReference(0)) {
 291             // oop
 292             Variable result = newVariable(LIRKind.reference(AArch64Kind.QWORD));
 293             append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
 294             return result;
 295         } else {
 296             // metaspace pointer
 297             Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD));
 298             AllocatableValue base = Value.ILLEGAL;
 299             OptionValues options = getResult().getLIR().getOptions();
 300             if (encoding.hasBase() || GeneratePIC.getValue(options)) {
 301                 if (GeneratePIC.getValue(options)) {
 302                     Variable baseAddress = newVariable(LIRKind.value(AArch64Kind.QWORD));
 303                     AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
 304                     append(move);
 305                     base = baseAddress;
 306                 } else {
 307                     base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
 308                 }
 309             }
 310             append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
 311             return result;
 312         }
 313     }
 314 
 315     @Override
 316     public void emitNullCheck(Value address, LIRFrameState state) {
 317         if (address.getValueKind().getPlatformKind() == AArch64Kind.DWORD) {
 318             CompressEncoding encoding = config.getOopEncoding();
 319             Value uncompressed = emitUncompress(address, encoding, false);
 320             append(new AArch64Move.NullCheckOp(asAddressValue(uncompressed), state));
 321         } else {
 322             super.emitNullCheck(address, state);
 323         }
 324     }
 325 
 326     @Override
 327     public void emitPrefetchAllocate(Value address) {
 328         append(new AArch64PrefetchOp(asAddressValue(address), PrefetchMode.PSTL1KEEP));
 329     }
 330 
 331     @Override
 332     public void beforeRegisterAllocation() {
 333         super.beforeRegisterAllocation();
 334         boolean hasDebugInfo = getResult().getLIR().hasDebugInfo();
 335         if (hasDebugInfo) {
 336             getResult().setDeoptimizationRescueSlot(((AArch64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot());
 337         }
 338 
 339         getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize());
 340     }
 341 
 342     private Label label;
 343 
 344     @Override
 345     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
 346         HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
 347         boolean destroysRegisters = hotspotLinkage.destroysRegisters();
 348 
 349         AArch64SaveRegistersOp save = null;
 350         Stub stub = getStub();
 351         if (destroysRegisters && stub != null && stub.shouldSaveRegistersAroundCalls()) {
 352             Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray();
 353             save = emitSaveAllRegisters(savedRegisters);
 354         }
 355 
 356         Variable result;
 357         LIRFrameState debugInfo = null;
 358         if (hotspotLinkage.needsDebugInfo()) {
 359             debugInfo = state;
 360             assert debugInfo != null || getStub() != null;
 361         }
 362 
 363         if (destroysRegisters || hotspotLinkage.needsJavaFrameAnchor()) {
 364             HotSpotRegistersProvider registers = getProviders().getRegisters();
 365             Register thread = registers.getThreadRegister();
 366             Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind()));
 367 
 368             // We need a label for the return address.
 369             label = new Label();
 370 
 371             append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, scratch, label));
 372             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
 373             append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, label));
 374 
 375             // Clear it out so it's not being reused later.
 376             label = null;
 377         } else {
 378             result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
 379         }
 380 
 381         if (save != null) {
 382             HotSpotLIRGenerationResult generationResult = getResult();
 383             LIRFrameState key = currentRuntimeCallInfo;
 384             if (key == null) {
 385                 key = LIRFrameState.NO_STATE;
 386             }
 387             assert !generationResult.getCalleeSaveInfo().containsKey(key);
 388             generationResult.getCalleeSaveInfo().put(key, save);
 389             emitRestoreRegisters(save);
 390         }
 391 
 392         return result;
 393     }
 394 
 395     @Override
 396     public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) {
 397         Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0));
 398         Value speculation = emitJavaConstant(getMetaAccess().encodeSpeculation(SpeculationLog.NO_SPECULATION));
 399         moveDeoptValuesToThread(actionAndReason, speculation);
 400         append(new AArch64HotSpotDeoptimizeCallerOp(config));
 401     }
 402 
 403     @Override
 404     public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) {
 405         moveDeoptValuesToThread(actionAndReason, failedSpeculation);
 406         append(new AArch64HotSpotDeoptimizeOp(state));
 407     }
 408 
 409     private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) {
 410         moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset);
 411         moveValueToThread(speculation, config.pendingFailedSpeculationOffset);
 412     }
 413 
 414     private void moveValueToThread(Value value, int offset) {
 415         LIRKind wordKind = LIRKind.value(target().arch.getWordKind());
 416         RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind);
 417         final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes();
 418         AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, offset, transferSize, AddressingMode.IMMEDIATE_SCALED);
 419         append(new StoreOp((AArch64Kind) value.getPlatformKind(), address, loadReg(value), null));
 420     }
 421 
 422     @Override
 423     public void emitUnwind(Value exception) {
 424         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER);
 425         CallingConvention outgoingCc = linkage.getOutgoingCallingConvention();
 426         assert outgoingCc.getArgumentCount() == 2;
 427         RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0);
 428         emitMove(exceptionParameter, exception);
 429         append(new AArch64HotSpotUnwindOp(config, exceptionParameter));
 430     }
 431 
 432     @Override
 433     public Value emitLoadObjectAddress(Constant constant) {
 434         HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
 435         LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind();
 436         Variable result = newVariable(kind);
 437         append(new AArch64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
 438         return result;
 439     }
 440 
 441     @Override
 442     public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
 443         HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
 444         LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind();
 445         Variable result = newVariable(kind);
 446         append(new AArch64HotSpotLoadAddressOp(result, constant, action));
 447         return result;
 448     }
 449 
 450     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
 451         ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall);
 452         append(new AArch64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
 453         AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
 454         return emitMove(result);
 455     }
 456 
 457     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
 458         Constant[] constants = new Constant[]{constant};
 459         Object[] notes = new Object[]{action};
 460         return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState);
 461     }
 462 
 463     @Override
 464     public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) {
 465         AllocatableValue[] constantDescriptions = new AllocatableValue[0];
 466         return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState);
 467     }
 468 
 469     @Override
 470     public Value emitLoadConfigValue(int markId, LIRKind kind) {
 471         Variable result = newVariable(kind);
 472         append(new AArch64HotSpotLoadConfigValueOp(markId, result));
 473         return result;
 474     }
 475 
 476     private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) {
 477         AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
 478         return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState);
 479     }
 480 
 481     @Override
 482     public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 483         return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
 484     }
 485 
 486     @Override
 487     public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 488         return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
 489     }
 490 
 491     @Override
 492     public void emitReturn(JavaKind kind, Value input) {
 493         AllocatableValue operand = Value.ILLEGAL;
 494         if (input != null) {
 495             operand = resultOperandFor(kind, input.getValueKind());
 496             emitMove(operand, input);
 497         }
 498         Register thread = getProviders().getRegisters().getThreadRegister();
 499         append(new AArch64HotSpotReturnOp(operand, getStub() != null, config, thread, getResult().requiresReservedStackAccessCheck()));
 500     }
 501 
 502     @Override
 503     public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
 504         return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState);
 505     }
 506 
 507     @Override
 508     public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
 509         AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
 510         return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState);
 511     }
 512 
 513     /**
 514      * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
 515      * being generated.
 516      */
 517     public Stub getStub() {
 518         return getResult().getStub();
 519     }
 520 
 521     @Override
 522     public HotSpotLIRGenerationResult getResult() {
 523         return ((HotSpotLIRGenerationResult) super.getResult());
 524     }
 525 
 526     @Override
 527     protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue,
 528                     Function<Condition, ConditionFlag> converter) {
 529         return new AArch64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter);
 530     }
 531 
 532     public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) {
 533         this.debugInfoBuilder = debugInfoBuilder;
 534     }
 535 
 536     @Override
 537     public ZapRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) {
 538         throw GraalError.unimplemented();
 539     }
 540 
 541     @Override
 542     public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
 543         throw GraalError.unimplemented();
 544     }
 545 
 546     @Override
 547     public void emitZeroMemory(Value address, Value length) {
 548         int dczidValue = config.psrInfoDczidValue;
 549         EnumSet<AArch64.Flag> flags = ((AArch64) target().arch).getFlags();
 550 
 551         // ARMv8-A architecture reference manual D12.2.35 Data Cache Zero ID register says:
 552         // * BS, bits [3:0] indicate log2 of the DC ZVA block size in (4-byte) words.
 553         // * DZP, bit [4] of indicates whether use of DC ZVA instruction is prohibited.
 554         int zvaLength = 4 << (dczidValue & 0xF);
 555         boolean isDcZvaProhibited = ((dczidValue & 0x10) != 0);
 556 
 557         // Use DC ZVA if it's not prohibited and AArch64 HotSpot flag UseBlockZeroing is on.
 558         boolean useDcZva = !isDcZvaProhibited && flags.contains(AArch64.Flag.UseBlockZeroing);
 559 
 560         // Set zva length negative (unknown at compile-time) for AOT compilation, since the value
 561         // could be different on different AArch64 CPU implementations.
 562         if (GraalOptions.ImmutableCode.getValue(getResult().getLIR().getOptions())) {
 563             useDcZva = false;
 564         }
 565 
 566         // Value address is 8-byte aligned; Value length is multiple of 8.
 567         append(new AArch64ZeroMemoryOp(asAllocatable(address), asAllocatable(length), useDcZva, zvaLength));
 568     }
 569 }