1 /* 2 * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.hotspot.amd64; 24 25 import static 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, LIRKind kind) { 501 Variable result = newVariable(kind); 502 append(new AMD64HotSpotLoadConfigValueOp(markId, result)); 503 return result; 504 } 505 506 @Override 507 public Value emitRandomSeed() { 508 AMD64ReadTimestampCounter timestamp = new AMD64ReadTimestampCounter(); 509 append(timestamp); 510 return emitMove(timestamp.getLowResult()); 511 } 512 513 @Override 514 public Value emitUncommonTrapCall(Value trapRequest, Value mode, SaveRegistersOp saveRegisterOp) { 515 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(UNCOMMON_TRAP); 516 517 Register thread = getProviders().getRegisters().getThreadRegister(); 518 append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread)); 519 Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(AMD64Kind.QWORD)), trapRequest, mode); 520 append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread)); 521 522 Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = getResult().getCalleeSaveInfo(); 523 assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); 524 calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); 525 526 return result; 527 } 528 529 @Override 530 public Value emitDeoptimizationFetchUnrollInfoCall(Value mode, SaveRegistersOp saveRegisterOp) { 531 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(FETCH_UNROLL_INFO); 532 533 Register thread = getProviders().getRegisters().getThreadRegister(); 534 append(new AMD64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), thread)); 535 Variable result = super.emitForeignCall(linkage, null, thread.asValue(LIRKind.value(AMD64Kind.QWORD)), mode); 536 append(new AMD64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), config.threadLastJavaPcOffset(), thread)); 537 538 Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = getResult().getCalleeSaveInfo(); 539 assert !calleeSaveInfo.containsKey(currentRuntimeCallInfo); 540 calleeSaveInfo.put(currentRuntimeCallInfo, saveRegisterOp); 541 542 return result; 543 } 544 545 @Override 546 public void emitTailcall(Value[] args, Value address) { 547 append(new AMD64TailcallOp(args, address)); 548 } 549 550 @Override 551 public void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args, int numberOfFloatingPointArguments) { 552 Value[] argLocations = new Value[args.length]; 553 getResult().getFrameMapBuilder().callsMethod(nativeCallingConvention); 554 // TODO(mg): in case a native function uses floating point varargs, the ABI requires that 555 // RAX contains the length of the varargs 556 PrimitiveConstant intConst = JavaConstant.forInt(numberOfFloatingPointArguments); 557 AllocatableValue numberOfFloatingPointArgumentsRegister = AMD64.rax.asValue(LIRKind.value(AMD64Kind.DWORD)); 558 emitMoveConstant(numberOfFloatingPointArgumentsRegister, intConst); 559 for (int i = 0; i < args.length; i++) { 560 Value arg = args[i]; 561 AllocatableValue loc = nativeCallingConvention.getArgument(i); 562 emitMove(loc, arg); 563 argLocations[i] = loc; 564 } 565 Value ptr = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(address)); 566 append(new AMD64CCall(nativeCallingConvention.getReturn(), ptr, numberOfFloatingPointArgumentsRegister, argLocations)); 567 } 568 569 @Override 570 public void emitUnwind(Value exception) { 571 ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(HotSpotBackend.UNWIND_EXCEPTION_TO_CALLER); 572 CallingConvention outgoingCc = linkage.getOutgoingCallingConvention(); 573 assert outgoingCc.getArgumentCount() == 2; 574 RegisterValue exceptionParameter = (RegisterValue) outgoingCc.getArgument(0); 575 emitMove(exceptionParameter, exception); 576 append(new AMD64HotSpotUnwindOp(exceptionParameter)); 577 } 578 579 private void moveDeoptValuesToThread(Value actionAndReason, Value speculation) { 580 moveValueToThread(actionAndReason, config.pendingDeoptimizationOffset); 581 moveValueToThread(speculation, config.pendingFailedSpeculationOffset); 582 } 583 584 private void moveValueToThread(Value v, int offset) { 585 LIRKind wordKind = LIRKind.value(target().arch.getWordKind()); 586 RegisterValue thread = getProviders().getRegisters().getThreadRegister().asValue(wordKind); 587 AMD64AddressValue address = new AMD64AddressValue(wordKind, thread, offset); 588 arithmeticLIRGen.emitStore(v.getValueKind(), address, v, null); 589 } 590 591 @Override 592 public void emitDeoptimize(Value actionAndReason, Value speculation, LIRFrameState state) { 593 moveDeoptValuesToThread(actionAndReason, speculation); 594 append(new AMD64DeoptimizeOp(state)); 595 } 596 597 @Override 598 public void emitDeoptimizeCaller(DeoptimizationAction action, DeoptimizationReason reason) { 599 Value actionAndReason = emitJavaConstant(getMetaAccess().encodeDeoptActionAndReason(action, reason, 0)); 600 Value nullValue = emitConstant(LIRKind.reference(AMD64Kind.QWORD), JavaConstant.NULL_POINTER); 601 moveDeoptValuesToThread(actionAndReason, nullValue); 602 append(new AMD64HotSpotDeoptimizeCallerOp()); 603 } 604 605 @Override 606 public void beforeRegisterAllocation() { 607 super.beforeRegisterAllocation(); 608 boolean hasDebugInfo = getResult().getLIR().hasDebugInfo(); 609 AllocatableValue savedRbp = saveRbp.finalize(hasDebugInfo); 610 if (hasDebugInfo) { 611 getResult().setDeoptimizationRescueSlot(((AMD64FrameMapBuilder) getResult().getFrameMapBuilder()).allocateDeoptimizationRescueSlot()); 612 } 613 614 getResult().setMaxInterpreterFrameSize(debugInfoBuilder.maxInterpreterFrameSize()); 615 616 for (AMD64HotSpotRestoreRbpOp op : epilogueOps) { 617 op.setSavedRbp(savedRbp); 618 } 619 if (BenchmarkCounters.enabled) { 620 // ensure that the rescue slot is available 621 LIRInstruction op = getOrInitRescueSlotOp(); 622 // insert dummy instruction into the start block 623 LIR lir = getResult().getLIR(); 624 List<LIRInstruction> instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock()); 625 instructions.add(1, op); 626 Debug.dump(Debug.INFO_LOG_LEVEL, lir, "created rescue dummy op"); 627 } 628 } 629 630 @Override 631 public void emitPushInterpreterFrame(Value frameSize, Value framePc, Value senderSp, Value initialInfo) { 632 Variable frameSizeVariable = load(frameSize); 633 Variable framePcVariable = load(framePc); 634 Variable senderSpVariable = load(senderSp); 635 Variable initialInfoVariable = load(initialInfo); 636 append(new AMD64HotSpotPushInterpreterFrameOp(frameSizeVariable, framePcVariable, senderSpVariable, initialInfoVariable, config)); 637 } 638 639 @Override 640 public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 641 LIRKind inputKind = pointer.getValueKind(LIRKind.class); 642 assert inputKind.getPlatformKind() == AMD64Kind.QWORD; 643 if (inputKind.isReference(0)) { 644 // oop 645 Variable result = newVariable(LIRKind.reference(AMD64Kind.DWORD)); 646 append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 647 return result; 648 } else { 649 // metaspace pointer 650 Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); 651 AllocatableValue base = Value.ILLEGAL; 652 if (encoding.base != 0 || GeneratePIC.getValue()) { 653 if (GeneratePIC.getValue()) { 654 Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD)); 655 AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config); 656 append(move); 657 base = baseAddress; 658 } else { 659 base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.base)); 660 } 661 } 662 append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 663 return result; 664 } 665 } 666 667 @Override 668 public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) { 669 LIRKind inputKind = pointer.getValueKind(LIRKind.class); 670 assert inputKind.getPlatformKind() == AMD64Kind.DWORD; 671 if (inputKind.isReference(0)) { 672 // oop 673 Variable result = newVariable(LIRKind.reference(AMD64Kind.QWORD)); 674 append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull)); 675 return result; 676 } else { 677 // metaspace pointer 678 Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD)); 679 AllocatableValue base = Value.ILLEGAL; 680 if (encoding.base != 0 || GeneratePIC.getValue()) { 681 if (GeneratePIC.getValue()) { 682 Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD)); 683 AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config); 684 append(move); 685 base = baseAddress; 686 } else { 687 base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.base)); 688 } 689 } 690 append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull)); 691 return result; 692 } 693 } 694 695 @Override 696 public void emitNullCheck(Value address, LIRFrameState state) { 697 if (address.getValueKind().getPlatformKind() == AMD64Kind.DWORD) { 698 CompressEncoding encoding = config.getOopEncoding(); 699 Value uncompressed; 700 if (encoding.shift <= 3) { 701 LIRKind wordKind = LIRKind.unknownReference(target().arch.getWordKind()); 702 uncompressed = new AMD64AddressValue(wordKind, getProviders().getRegisters().getHeapBaseRegister().asValue(wordKind), asAllocatable(address), Scale.fromInt(1 << encoding.shift), 0); 703 } else { 704 uncompressed = emitUncompress(address, encoding, false); 705 } 706 append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state)); 707 } else { 708 super.emitNullCheck(address, state); 709 } 710 } 711 712 @Override 713 public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) { 714 if (BenchmarkCounters.enabled) { 715 return new AMD64HotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, getOrInitRescueSlot()); 716 } 717 throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); 718 } 719 720 @Override 721 public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) { 722 if (BenchmarkCounters.enabled) { 723 return new AMD64HotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, getOrInitRescueSlot()); 724 } 725 throw GraalError.shouldNotReachHere("BenchmarkCounters are not enabled!"); 726 } 727 728 @Override 729 public void emitPrefetchAllocate(Value address) { 730 append(new AMD64PrefetchOp(asAddressValue(address), config.allocatePrefetchInstr)); 731 } 732 733 @Override 734 protected StrategySwitchOp createStrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue temp) { 735 return new AMD64HotSpotStrategySwitchOp(strategy, keyTargets, defaultTarget, key, temp); 736 } 737 }