1 /* 2 * Copyright (c) 2009, 2019, 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 25 package org.graalvm.compiler.lir.gen; 26 27 import static jdk.vm.ci.code.ValueUtil.asAllocatableValue; 28 import static jdk.vm.ci.code.ValueUtil.isAllocatableValue; 29 import static jdk.vm.ci.code.ValueUtil.isLegal; 30 import static jdk.vm.ci.code.ValueUtil.isStackSlot; 31 import static org.graalvm.compiler.lir.LIRValueUtil.asConstant; 32 import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue; 33 import static org.graalvm.compiler.lir.LIRValueUtil.isVariable; 34 import static org.graalvm.compiler.lir.LIRValueUtil.isVirtualStackSlot; 35 36 import java.util.ArrayList; 37 import java.util.List; 38 import java.util.Optional; 39 40 import org.graalvm.compiler.asm.Label; 41 import org.graalvm.compiler.core.common.LIRKind; 42 import org.graalvm.compiler.core.common.calc.Condition; 43 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; 44 import org.graalvm.compiler.core.common.spi.CodeGenProviders; 45 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; 46 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; 47 import org.graalvm.compiler.core.common.spi.LIRKindTool; 48 import org.graalvm.compiler.core.common.type.Stamp; 49 import org.graalvm.compiler.debug.DebugCloseable; 50 import org.graalvm.compiler.debug.GraalError; 51 import org.graalvm.compiler.debug.TTY; 52 import org.graalvm.compiler.graph.NodeSourcePosition; 53 import org.graalvm.compiler.lir.ConstantValue; 54 import org.graalvm.compiler.lir.LIR; 55 import org.graalvm.compiler.lir.LIRFrameState; 56 import org.graalvm.compiler.lir.LIRInstruction; 57 import org.graalvm.compiler.lir.LIRVerifier; 58 import org.graalvm.compiler.lir.LabelRef; 59 import org.graalvm.compiler.lir.StandardOp; 60 import org.graalvm.compiler.lir.StandardOp.BlockEndOp; 61 import org.graalvm.compiler.lir.StandardOp.LabelOp; 62 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp; 63 import org.graalvm.compiler.lir.hashing.Hasher; 64 import org.graalvm.compiler.lir.SwitchStrategy; 65 import org.graalvm.compiler.lir.Variable; 66 import org.graalvm.compiler.options.Option; 67 import org.graalvm.compiler.options.OptionKey; 68 import org.graalvm.compiler.options.OptionType; 69 import org.graalvm.compiler.options.OptionValues; 70 71 import jdk.vm.ci.code.CallingConvention; 72 import jdk.vm.ci.code.CodeCacheProvider; 73 import jdk.vm.ci.code.Register; 74 import jdk.vm.ci.code.RegisterAttributes; 75 import jdk.vm.ci.code.RegisterConfig; 76 import jdk.vm.ci.code.StackSlot; 77 import jdk.vm.ci.code.TargetDescription; 78 import jdk.vm.ci.meta.AllocatableValue; 79 import jdk.vm.ci.meta.Constant; 80 import jdk.vm.ci.meta.JavaConstant; 81 import jdk.vm.ci.meta.JavaKind; 82 import jdk.vm.ci.meta.MetaAccessProvider; 83 import jdk.vm.ci.meta.PlatformKind; 84 import jdk.vm.ci.meta.Value; 85 import jdk.vm.ci.meta.ValueKind; 86 87 /** 88 * This class traverses the HIR instructions and generates LIR instructions from them. 89 */ 90 public abstract class LIRGenerator implements LIRGeneratorTool { 91 92 public static class Options { 93 // @formatter:off 94 @Option(help = "Print HIR along side LIR as the latter is generated", type = OptionType.Debug) 95 public static final OptionKey<Boolean> PrintIRWithLIR = new OptionKey<>(false); 96 @Option(help = "The trace level for the LIR generator", type = OptionType.Debug) 97 public static final OptionKey<Integer> TraceLIRGeneratorLevel = new OptionKey<>(0); 98 // @formatter:on 99 } 100 101 private final LIRKindTool lirKindTool; 102 103 private final CodeGenProviders providers; 104 105 private AbstractBlockBase<?> currentBlock; 106 107 private LIRGenerationResult res; 108 109 protected final ArithmeticLIRGenerator arithmeticLIRGen; 110 private final MoveFactory moveFactory; 111 112 private final boolean printIrWithLir; 113 private final int traceLIRGeneratorLevel; 114 LIRGenerator(LIRKindTool lirKindTool, ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, CodeGenProviders providers, LIRGenerationResult res)115 public LIRGenerator(LIRKindTool lirKindTool, ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, CodeGenProviders providers, LIRGenerationResult res) { 116 this.lirKindTool = lirKindTool; 117 this.arithmeticLIRGen = arithmeticLIRGen; 118 this.res = res; 119 this.providers = providers; 120 OptionValues options = res.getLIR().getOptions(); 121 this.printIrWithLir = !TTY.isSuppressed() && Options.PrintIRWithLIR.getValue(options); 122 this.traceLIRGeneratorLevel = TTY.isSuppressed() ? 0 : Options.TraceLIRGeneratorLevel.getValue(options); 123 124 assert arithmeticLIRGen.lirGen == null; 125 arithmeticLIRGen.lirGen = this; 126 this.moveFactory = moveFactory; 127 } 128 129 @Override getArithmetic()130 public ArithmeticLIRGeneratorTool getArithmetic() { 131 return arithmeticLIRGen; 132 } 133 134 @Override getMoveFactory()135 public MoveFactory getMoveFactory() { 136 return moveFactory; 137 } 138 139 private MoveFactory spillMoveFactory; 140 141 @Override getSpillMoveFactory()142 public MoveFactory getSpillMoveFactory() { 143 if (spillMoveFactory == null) { 144 boolean verify = false; 145 assert (verify = true) == true; 146 if (verify) { 147 spillMoveFactory = new VerifyingMoveFactory(moveFactory); 148 } else { 149 spillMoveFactory = moveFactory; 150 } 151 } 152 return spillMoveFactory; 153 } 154 155 @Override getValueKind(JavaKind javaKind)156 public LIRKind getValueKind(JavaKind javaKind) { 157 return LIRKind.fromJavaKind(target().arch, javaKind); 158 } 159 160 @Override target()161 public TargetDescription target() { 162 return getCodeCache().getTarget(); 163 } 164 165 @Override getProviders()166 public CodeGenProviders getProviders() { 167 return providers; 168 } 169 170 @Override getMetaAccess()171 public MetaAccessProvider getMetaAccess() { 172 return providers.getMetaAccess(); 173 } 174 175 @Override getCodeCache()176 public CodeCacheProvider getCodeCache() { 177 return providers.getCodeCache(); 178 } 179 180 @Override getForeignCalls()181 public ForeignCallsProvider getForeignCalls() { 182 return providers.getForeignCalls(); 183 } 184 getLIRKindTool()185 public LIRKindTool getLIRKindTool() { 186 return lirKindTool; 187 } 188 189 /** 190 * Hide {@link #nextVariable()} from other users. 191 */ 192 public abstract static class VariableProvider { 193 private int numVariables; 194 numVariables()195 public int numVariables() { 196 return numVariables; 197 } 198 nextVariable()199 private int nextVariable() { 200 return numVariables++; 201 } 202 } 203 204 @Override newVariable(ValueKind<?> valueKind)205 public Variable newVariable(ValueKind<?> valueKind) { 206 return new Variable(valueKind, ((VariableProvider) res.getLIR()).nextVariable()); 207 } 208 209 @Override getRegisterConfig()210 public RegisterConfig getRegisterConfig() { 211 return res.getRegisterConfig(); 212 } 213 214 @Override attributes(Register register)215 public RegisterAttributes attributes(Register register) { 216 return getRegisterConfig().getAttributesMap()[register.number]; 217 } 218 219 @Override emitMove(Value input)220 public Variable emitMove(Value input) { 221 assert !(input instanceof Variable) : "Creating a copy of a variable via this method is not supported (and potentially a bug): " + input; 222 Variable result = newVariable(input.getValueKind()); 223 emitMove(result, input); 224 return result; 225 } 226 227 @Override emitMove(AllocatableValue dst, Value src)228 public void emitMove(AllocatableValue dst, Value src) { 229 append(moveFactory.createMove(dst, src)); 230 } 231 232 @Override emitMoveConstant(AllocatableValue dst, Constant src)233 public void emitMoveConstant(AllocatableValue dst, Constant src) { 234 append(moveFactory.createLoad(dst, src)); 235 } 236 237 @Override emitConstant(LIRKind kind, Constant constant)238 public Value emitConstant(LIRKind kind, Constant constant) { 239 if (moveFactory.canInlineConstant(constant)) { 240 return new ConstantValue(toRegisterKind(kind), constant); 241 } else { 242 return emitLoadConstant(toRegisterKind(kind), constant); 243 } 244 } 245 246 @Override emitJavaConstant(JavaConstant constant)247 public Value emitJavaConstant(JavaConstant constant) { 248 return emitConstant(getValueKind(constant.getJavaKind()), constant); 249 } 250 251 @Override emitLoadConstant(ValueKind<?> kind, Constant constant)252 public AllocatableValue emitLoadConstant(ValueKind<?> kind, Constant constant) { 253 Variable result = newVariable(kind); 254 emitMoveConstant(result, constant); 255 return result; 256 } 257 258 @Override asAllocatable(Value value)259 public AllocatableValue asAllocatable(Value value) { 260 if (isAllocatableValue(value)) { 261 return asAllocatableValue(value); 262 } else if (isConstantValue(value)) { 263 return emitLoadConstant(value.getValueKind(), asConstant(value)); 264 } else { 265 return emitMove(value); 266 } 267 } 268 269 @Override load(Value value)270 public Variable load(Value value) { 271 if (!isVariable(value)) { 272 return emitMove(value); 273 } 274 return (Variable) value; 275 } 276 277 @Override loadNonConst(Value value)278 public Value loadNonConst(Value value) { 279 if (isConstantValue(value) && !moveFactory.canInlineConstant(asConstant(value))) { 280 return emitMove(value); 281 } 282 return value; 283 } 284 285 /** 286 * Determines if only oop maps are required for the code generated from the LIR. 287 */ 288 @Override needOnlyOopMaps()289 public boolean needOnlyOopMaps() { 290 return false; 291 } 292 293 /** 294 * Gets the ABI specific operand used to return a value of a given kind from a method. 295 * 296 * @param javaKind the kind of value being returned 297 * @param valueKind the backend type of the value being returned 298 * @return the operand representing the ABI defined location used return a value of kind 299 * {@code kind} 300 */ 301 @Override resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind)302 public AllocatableValue resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind) { 303 Register reg = getRegisterConfig().getReturnRegister(javaKind); 304 assert target().arch.canStoreValue(reg.getRegisterCategory(), valueKind.getPlatformKind()) : reg.getRegisterCategory() + " " + valueKind.getPlatformKind(); 305 return reg.asValue(valueKind); 306 } 307 308 NodeSourcePosition currentPosition; 309 310 @Override setSourcePosition(NodeSourcePosition position)311 public void setSourcePosition(NodeSourcePosition position) { 312 currentPosition = position; 313 } 314 315 @Override append(I op)316 public <I extends LIRInstruction> I append(I op) { 317 LIR lir = res.getLIR(); 318 if (printIrWithLir) { 319 TTY.println(op.toStringWithIdPrefix()); 320 TTY.println(); 321 } 322 assert LIRVerifier.verify(op); 323 ArrayList<LIRInstruction> lirForBlock = lir.getLIRforBlock(getCurrentBlock()); 324 op.setPosition(currentPosition); 325 lirForBlock.add(op); 326 return op; 327 } 328 329 @Override hasBlockEnd(AbstractBlockBase<?> block)330 public boolean hasBlockEnd(AbstractBlockBase<?> block) { 331 ArrayList<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block); 332 if (ops.size() == 0) { 333 return false; 334 } 335 return ops.get(ops.size() - 1) instanceof BlockEndOp; 336 } 337 338 private final class BlockScopeImpl extends BlockScope { 339 BlockScopeImpl(AbstractBlockBase<?> block)340 private BlockScopeImpl(AbstractBlockBase<?> block) { 341 currentBlock = block; 342 } 343 doBlockStart()344 private void doBlockStart() { 345 if (printIrWithLir) { 346 TTY.print(currentBlock.toString()); 347 } 348 349 // set up the list of LIR instructions 350 assert res.getLIR().getLIRforBlock(currentBlock) == null : "LIR list already computed for this block"; 351 res.getLIR().setLIRforBlock(currentBlock, new ArrayList<LIRInstruction>()); 352 353 append(new LabelOp(new Label(currentBlock.getId()), currentBlock.isAligned())); 354 355 if (traceLIRGeneratorLevel >= 1) { 356 TTY.println("BEGIN Generating LIR for block B" + currentBlock.getId()); 357 } 358 } 359 doBlockEnd()360 private void doBlockEnd() { 361 if (traceLIRGeneratorLevel >= 1) { 362 TTY.println("END Generating LIR for block B" + currentBlock.getId()); 363 } 364 365 if (printIrWithLir) { 366 TTY.println(); 367 } 368 currentBlock = null; 369 } 370 371 @Override getCurrentBlock()372 public AbstractBlockBase<?> getCurrentBlock() { 373 return currentBlock; 374 } 375 376 @Override close()377 public void close() { 378 doBlockEnd(); 379 } 380 381 } 382 383 @Override getBlockScope(AbstractBlockBase<?> block)384 public final BlockScope getBlockScope(AbstractBlockBase<?> block) { 385 BlockScopeImpl blockScope = new BlockScopeImpl(block); 386 blockScope.doBlockStart(); 387 return blockScope; 388 } 389 390 private final class MatchScope implements DebugCloseable { 391 MatchScope(AbstractBlockBase<?> block)392 private MatchScope(AbstractBlockBase<?> block) { 393 currentBlock = block; 394 } 395 396 @Override close()397 public void close() { 398 currentBlock = null; 399 } 400 401 } 402 getMatchScope(AbstractBlockBase<?> block)403 public final DebugCloseable getMatchScope(AbstractBlockBase<?> block) { 404 MatchScope matchScope = new MatchScope(block); 405 return matchScope; 406 } 407 408 @Override emitIncomingValues(Value[] params)409 public void emitIncomingValues(Value[] params) { 410 ((LabelOp) res.getLIR().getLIRforBlock(getCurrentBlock()).get(0)).setIncomingValues(params); 411 } 412 413 @Override emitJump(LabelRef label)414 public abstract void emitJump(LabelRef label); 415 416 @Override emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability)417 public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, 418 double trueDestinationProbability); 419 420 @Override emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability)421 public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability); 422 423 @Override emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability)424 public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability); 425 426 @Override emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue)427 public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue); 428 429 @Override emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue)430 public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue); 431 432 /** 433 * Emits the single call operation at the heart of generating LIR for a 434 * {@linkplain #emitForeignCall(ForeignCallLinkage, LIRFrameState, Value...) foreign call}. 435 */ emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info)436 protected abstract void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info); 437 438 @Override emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args)439 public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args) { 440 LIRFrameState state = null; 441 if (linkage.needsDebugInfo()) { 442 if (frameState != null) { 443 state = frameState; 444 } else { 445 assert needOnlyOopMaps(); 446 state = new LIRFrameState(null, null, null); 447 } 448 } 449 450 // move the arguments into the correct location 451 CallingConvention linkageCc = linkage.getOutgoingCallingConvention(); 452 res.getFrameMapBuilder().callsMethod(linkageCc); 453 assert linkageCc.getArgumentCount() == args.length : "argument count mismatch"; 454 Value[] argLocations = new Value[args.length]; 455 for (int i = 0; i < args.length; i++) { 456 Value arg = args[i]; 457 AllocatableValue loc = linkageCc.getArgument(i); 458 emitMove(loc, arg); 459 argLocations[i] = loc; 460 } 461 res.setForeignCall(true); 462 emitForeignCallOp(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state); 463 464 if (isLegal(linkageCc.getReturn())) { 465 return emitMove(linkageCc.getReturn()); 466 } else { 467 return null; 468 } 469 } 470 471 @Override emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value)472 public void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) { 473 SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets); 474 475 int keyCount = keyConstants.length; 476 double minDensity = 1 / Math.sqrt(strategy.getAverageEffort()); 477 Optional<Hasher> hasher = hasherFor(keyConstants, minDensity); 478 double hashTableSwitchDensity = hasher.map(h -> keyCount / (double) h.cardinality()).orElse(0d); 479 // The value range computation below may overflow, so compute it as a long. 480 long valueRange = (long) keyConstants[keyCount - 1].asInt() - (long) keyConstants[0].asInt() + 1; 481 double tableSwitchDensity = keyCount / (double) valueRange; 482 483 /* 484 * This heuristic tries to find a compromise between the effort for the best switch strategy 485 * and the density of a tableswitch. If the effort for the strategy is at least 4, then a 486 * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers 487 * gradually with additional effort. 488 */ 489 if (strategy.getAverageEffort() < 4d || (tableSwitchDensity < minDensity && hashTableSwitchDensity < minDensity)) { 490 emitStrategySwitch(strategy, value, keyTargets, defaultTarget); 491 } else { 492 if (hashTableSwitchDensity > tableSwitchDensity) { 493 Hasher h = hasher.get(); 494 int cardinality = h.cardinality(); 495 LabelRef[] targets = new LabelRef[cardinality]; 496 JavaConstant[] keys = new JavaConstant[cardinality]; 497 for (int i = 0; i < cardinality; i++) { 498 keys[i] = JavaConstant.INT_0; 499 targets[i] = defaultTarget; 500 } 501 for (int i = 0; i < keyCount; i++) { 502 int idx = h.hash(keyConstants[i].asInt()); 503 keys[idx] = keyConstants[i]; 504 targets[idx] = keyTargets[i]; 505 } 506 emitHashTableSwitch(h, keys, defaultTarget, targets, value); 507 } else { 508 int minValue = keyConstants[0].asInt(); 509 assert valueRange < Integer.MAX_VALUE; 510 LabelRef[] targets = new LabelRef[(int) valueRange]; 511 for (int i = 0; i < valueRange; i++) { 512 targets[i] = defaultTarget; 513 } 514 for (int i = 0; i < keyCount; i++) { 515 targets[keyConstants[i].asInt() - minValue] = keyTargets[i]; 516 } 517 emitTableSwitch(minValue, defaultTarget, targets, value); 518 } 519 } 520 } 521 522 @Override 523 public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget); 524 525 protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key); 526 527 @SuppressWarnings("unused") 528 protected Optional<Hasher> hasherFor(JavaConstant[] keyConstants, double minDensity) { 529 return Optional.empty(); 530 } 531 532 @SuppressWarnings("unused") 533 protected void emitHashTableSwitch(Hasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value) { 534 throw new UnsupportedOperationException(getClass().getSimpleName() + " doesn't support hash table switches"); 535 } 536 537 @Override 538 public void beforeRegisterAllocation() { 539 } 540 541 /** 542 * Gets a garbage value for a given kind. 543 */ 544 protected abstract JavaConstant zapValueForKind(PlatformKind kind); 545 546 @Override 547 public LIRKind getLIRKind(Stamp stamp) { 548 return stamp.getLIRKind(lirKindTool); 549 } 550 551 protected LIRKind getAddressKind(Value base, long displacement, Value index) { 552 if (LIRKind.isValue(base) && (index.equals(Value.ILLEGAL) || LIRKind.isValue(index))) { 553 return LIRKind.value(target().arch.getWordKind()); 554 } else if (base.getValueKind() instanceof LIRKind && base.getValueKind(LIRKind.class).isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) { 555 return LIRKind.reference(target().arch.getWordKind()); 556 } else { 557 return LIRKind.unknownReference(target().arch.getWordKind()); 558 } 559 } 560 561 @Override 562 public AbstractBlockBase<?> getCurrentBlock() { 563 return currentBlock; 564 } 565 566 @Override 567 public LIRGenerationResult getResult() { 568 return res; 569 } 570 571 @Override 572 public void emitBlackhole(Value operand) { 573 append(new StandardOp.BlackholeOp(operand)); 574 } 575 576 @Override 577 public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) { 578 throw GraalError.unimplemented(); 579 } 580 581 @Override 582 public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) { 583 throw GraalError.unimplemented(); 584 } 585 586 @Override 587 public abstract SaveRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues); 588 589 @Override 590 public SaveRegistersOp createZapRegisters() { 591 Register[] zappedRegisters = getResult().getFrameMap().getRegisterConfig().getAllocatableRegisters().toArray(); 592 JavaConstant[] zapValues = new JavaConstant[zappedRegisters.length]; 593 for (int i = 0; i < zappedRegisters.length; i++) { 594 PlatformKind kind = target().arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory()); 595 zapValues[i] = zapValueForKind(kind); 596 } 597 return createZapRegisters(zappedRegisters, zapValues); 598 } 599 600 @Override 601 public abstract LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues); 602 603 @Override 604 public LIRInstruction zapArgumentSpace() { 605 List<StackSlot> slots = null; 606 for (AllocatableValue arg : res.getCallingConvention().getArguments()) { 607 if (isStackSlot(arg)) { 608 if (slots == null) { 609 slots = new ArrayList<>(); 610 } 611 slots.add((StackSlot) arg); 612 } else { 613 assert !isVirtualStackSlot(arg); 614 } 615 } 616 if (slots == null) { 617 return null; 618 } 619 StackSlot[] zappedStack = slots.toArray(new StackSlot[slots.size()]); 620 JavaConstant[] zapValues = new JavaConstant[zappedStack.length]; 621 for (int i = 0; i < zappedStack.length; i++) { 622 PlatformKind kind = zappedStack[i].getPlatformKind(); 623 zapValues[i] = zapValueForKind(kind); 624 } 625 return createZapArgumentSpace(zappedStack, zapValues); 626 } 627 } 628