1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package org.graalvm.compiler.hotspot.aarch64; 25 26 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; 27 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; 28 29 import java.util.function.Function; 30 31 import org.graalvm.compiler.asm.Label; 32 import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode; 33 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; 34 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.PrefetchMode; 35 import org.graalvm.compiler.core.aarch64.AArch64ArithmeticLIRGenerator; 36 import org.graalvm.compiler.core.aarch64.AArch64LIRGenerator; 37 import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool; 38 import org.graalvm.compiler.core.common.CompressEncoding; 39 import org.graalvm.compiler.core.common.LIRKind; 40 import org.graalvm.compiler.core.common.calc.Condition; 41 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 42 import org.graalvm.compiler.core.common.spi.LIRKindTool; 43 import org.graalvm.compiler.debug.GraalError; 44 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; 45 import org.graalvm.compiler.hotspot.HotSpotBackend; 46 import org.graalvm.compiler.hotspot.HotSpotDebugInfoBuilder; 47 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; 48 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult; 49 import org.graalvm.compiler.hotspot.HotSpotLIRGenerator; 50 import org.graalvm.compiler.hotspot.HotSpotLockStack; 51 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 52 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; 53 import org.graalvm.compiler.hotspot.stubs.Stub; 54 import org.graalvm.compiler.lir.LIRFrameState; 55 import org.graalvm.compiler.lir.LIRInstruction; 56 import org.graalvm.compiler.lir.LabelRef; 57 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; 58 import org.graalvm.compiler.lir.SwitchStrategy; 59 import org.graalvm.compiler.lir.Variable; 60 import org.graalvm.compiler.lir.VirtualStackSlot; 61 import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; 62 import org.graalvm.compiler.lir.aarch64.AArch64CCall; 63 import org.graalvm.compiler.lir.aarch64.AArch64Call; 64 import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp; 65 import org.graalvm.compiler.lir.aarch64.AArch64FrameMapBuilder; 66 import org.graalvm.compiler.lir.aarch64.AArch64Move; 67 import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp; 68 import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp; 69 import org.graalvm.compiler.lir.gen.LIRGenerationResult; 70 71 import jdk.vm.ci.aarch64.AArch64; 72 import jdk.vm.ci.aarch64.AArch64Kind; 73 import jdk.vm.ci.code.CallingConvention; 74 import jdk.vm.ci.code.Register; 75 import jdk.vm.ci.code.RegisterValue; 76 import jdk.vm.ci.code.StackSlot; 77 import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; 78 import jdk.vm.ci.hotspot.HotSpotObjectConstant; 79 import jdk.vm.ci.meta.AllocatableValue; 80 import jdk.vm.ci.meta.Constant; 81 import jdk.vm.ci.meta.DeoptimizationAction; 82 import jdk.vm.ci.meta.DeoptimizationReason; 83 import jdk.vm.ci.meta.JavaConstant; 84 import jdk.vm.ci.meta.JavaKind; 85 import jdk.vm.ci.meta.PlatformKind; 86 import jdk.vm.ci.meta.Value; 87 88 /** 89 * LIR generator specialized for AArch64 HotSpot. 90 */ 91 public class AArch64HotSpotLIRGenerator extends AArch64LIRGenerator implements HotSpotLIRGenerator { 92 93 final GraalHotSpotVMConfig config; 94 private HotSpotDebugInfoBuilder debugInfoBuilder; 95 96 protected AArch64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes) { 97 this(new AArch64LIRKindTool(), new AArch64ArithmeticLIRGenerator(), new AArch64HotSpotMoveFactory(), providers, config, lirGenRes); 98 } 99 100 protected AArch64HotSpotLIRGenerator(LIRKindTool lirKindTool, AArch64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config, 101 LIRGenerationResult lirGenRes) { 102 super(lirKindTool, arithmeticLIRGen, moveFactory, providers, lirGenRes); 103 this.config = config; 104 } 105 106 @Override 107 public HotSpotProviders getProviders() { 108 return (HotSpotProviders) super.getProviders(); 109 } 110 111 @Override 112 public boolean needOnlyOopMaps() { 113 // Stubs only need oop maps 114 return getResult().getStub() != null; 115 } 116 117 @SuppressWarnings("unused") private LIRFrameState currentRuntimeCallInfo; 118 119 @Override 120 protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) { 121 currentRuntimeCallInfo = info; 122 if (AArch64Call.isNearCall(linkage)) { 123 append(new AArch64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info, label)); 124 } else { 125 append(new AArch64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info, label)); 126 } 127 } 128 129 @Override 130 public void emitTailcall(Value[] args, Value address) { 131 throw GraalError.unimplemented(); 132 } 133 134 @Override 135 public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args) { 136 Value[] argLocations = new Value[args.length]; 137 getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention); 138 for (int i = 0; i < args.length; i++) { 139 Value arg = args[i]; 140 AllocatableValue loc = nativeCallingConvention.getArgument(i); 141 emitMove(loc, arg); 142 argLocations[i] = loc; 143 } 144 Value ptr = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(address)); 145 append(new AArch64CCall(nativeCallingConvention.getReturn(), ptr, argLocations)); 146 } 147 148 public SaveRegistersOp emitSaveAllRegisters() { 149 throw GraalError.unimplemented(); 150 } 151 152 @Override 153 public VirtualStackSlot getLockSlot(int lockDepth) { 154 return getLockStack().makeLockSlot(lockDepth); 155 } 156 157 private HotSpotLockStack getLockStack() { 158 assert debugInfoBuilder != null && debugInfoBuilder.lockStack() != null; 159 return debugInfoBuilder.lockStack(); 160 } 161 162 @Override 163 public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, 164 double trueDestinationProbability) { 165 Value localX = x; 166 Value localY = y; 167 if (localX instanceof HotSpotObjectConstant) { 168 localX = load(localX); 169 } 170 if (localY instanceof HotSpotObjectConstant) { 171 localY = load(localY); 172 } 173 super.emitCompareBranch(cmpKind, localX, localY, cond, unorderedIsTrue, trueDestination, falseDestination, trueDestinationProbability); 174 } 175 176 @Override 177 protected boolean emitCompare(PlatformKind cmpKind, Value a, Value b, Condition condition, boolean unorderedIsTrue) { 178 Value localA = a; 179 Value localB = b; 180 if (isConstantValue(a)) { 181 Constant c = asConstant(a); 182 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { 183 localA = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD)); 184 } else if (c instanceof HotSpotObjectConstant) { 185 localA = load(localA); 186 } 187 } 188 if (isConstantValue(b)) { 189 Constant c = asConstant(b); 190 if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) { 191 localB = AArch64.zr.asValue(LIRKind.value(AArch64Kind.DWORD)); 192 } else if (c instanceof HotSpotObjectConstant) { 193 localB = load(localB); 194 } 195 } 196 return super.emitCompare(cmpKind, localA, localB, condition, unorderedIsTrue); 197 } 198 199 @Override 200 public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 201 LIRKind inputKind = pointer.getValueKind(LIRKind.class); 202 assert inputKind.getPlatformKind() == AArch64Kind.QWORD; 203 if (inputKind.isReference(0)) { 204 // oop 205 Variable result = newVariable(LIRKind.compressedReference(AArch64Kind.DWORD)); 206 append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 207 return result; 208 } else { 209 // metaspace pointer 210 Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD)); 211 AllocatableValue base = Value.ILLEGAL; 212 if (encoding.hasBase()) { 213 base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); 214 } 215 append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 216 return result; 217 } 218 } 219 220 @Override 221 public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 222 LIRKind inputKind = pointer.getValueKind(LIRKind.class); 223 assert inputKind.getPlatformKind() == AArch64Kind.DWORD; 224 if (inputKind.isReference(0)) { 225 // oop 226 Variable result = newVariable(LIRKind.reference(AArch64Kind.QWORD)); 227 append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 228 return result; 229 } else { 230 // metaspace pointer 231 Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD)); 232 AllocatableValue base = Value.ILLEGAL; 233 if (encoding.hasBase()) { 234 base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase())); 235 } 236 append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 237 return result; 238 } 239 } 240 241 @Override 242 public void emitNullCheck(Value address, LIRFrameState state) { 243 if (address.getValueKind().getPlatformKind() == AArch64Kind.DWORD) { 244 CompressEncoding encoding = config.getOopEncoding(); 245 Value uncompressed = emitUncompress(address, encoding, false); 246 append(new AArch64Move.NullCheckOp(asAddressValue(uncompressed), state)); 247 } else { 248 super.emitNullCheck(address, state); 249 } 250 } 251 252 @Override 253 public void emitPrefetchAllocate(Value address) { 254 append(new AArch64PrefetchOp(asAddressValue(address), PrefetchMode.PSTL1KEEP)); 255 } 256 257 @Override 258 public void beforeRegisterAllocation() { 259 super.beforeRegisterAllocation(); 260 boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); 261 if (hasDebugInfo) { 262 getResult().setDeoptimizationRescueSlot(((AArch64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); 263 } 264 265 getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); 266 } 267 268 private Label label; 269 270 @Override 271 public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) { 272 HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage; 273 Variable result; 274 LIRFrameState debugInfo = null; 275 if (hotspotLinkage.needsDebugInfo()) { 276 debugInfo = state; 277 assert debugInfo != null || getStub() != null; 278 } 279 280 if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) { 281 HotSpotRegistersProvider registers = getProviders().getRegisters(); 282 Register thread = registers.getThreadRegister(); 283 Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind())); 284 285 // We need a label for the return address. 286 label = new Label(); 287 288 append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), thread, scratch, label)); 289 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); 290 append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread)); 291 292 // Clear it out so it's not being reused later. 293 label = null; 294 } else { 295 result = super.emitForeignCall(hotspotLinkage, debugInfo, args); 296 } 297 298 return result; 299 } 300 301 @Override 302 public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { 303 Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); 304 Value nullValue = emitConstant(LIRKind.reference(AArch64Kind.QWORD), JavaConstant.NULL_POINTER); 305 moveDeoptValuesToThread(actionAndReason, nullValue); 306 append(new AArch64HotSpotDeoptimizeCallerOp(config)); 307 } 308 309 @Override 310 public void emitDeoptimize(Value actionAndReason, Value failedSpeculation, LIRFrameState state) { 311 moveDeoptValuesToThread(actionAndReason, failedSpeculation); 312 append(new AArch64HotSpotDeoptimizeOp(state)); 313 } 314 315 private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { 316 moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); 317 moveValueToThread(speculation, config.pendingFailedSpeculationOffset); 318 } 319 320 private void moveValueToThread(Value value, int offset) { 321 LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); 322 RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); 323 final int transferSize = value.getValueKind().getPlatformKind().getSizeInBytes(); 324 AArch64AddressValue address = new AArch64AddressValue(value.getValueKind(), thread, Value.ILLEGAL, offset, transferSize, AddressingMode.IMMEDIATE_SCALED); 325 append(new StoreOp((AArch64Kind) value.getPlatformKind(), address, loadReg(value), null)); 326 } 327 328 @Override 329 public void emitUnwind(Value exception) { 330 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); 331 CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); 332 assert outgoingCc.getArgumentCount() == 2; 333 RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0); 334 emitMove(exceptionParameter, exception); 335 append(new AArch64HotSpotUnwindOp(config, exceptionParameter)); 336 } 337 338 @Override 339 public void emitReturn(JavaKind kind, Value input) { 340 AllocatableValue operand = Value.ILLEGAL; 341 if (input != null) { 342 operand = resultOperandFor(kind, input.getValueKind()); 343 emitMove(operand, input); 344 } 345 Register thread = getProviders().getRegisters().getThreadRegister(); 346 append(new AArch64HotSpotReturnOp(operand, getStub() != null, config, thread)); 347 } 348 349 /** 350 * Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not 351 * being generated. 352 */ 353 public Stub getStub() { 354 return getResult().getStub(); 355 } 356 357 @Override 358 public HotSpotLIRGenerationResult getResult() { 359 return ((HotSpotLIRGenerationResult) super.getResult()); 360 } 361 362 @Override 363 protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue, 364 Function<Condition, ConditionFlag> converter) { 365 return new AArch64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, scratchValue, converter); 366 } 367 368 public void setDebugInfoBuilder(HotSpotDebugInfoBuilder debugInfoBuilder) { 369 this.debugInfoBuilder = debugInfoBuilder; 370 } 371 372 @Override 373 public SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues) { 374 throw GraalError.unimplemented(); 375 } 376 377 @Override 378 public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { 379 throw GraalError.unimplemented(); 380 } 381 }