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.ZapRegistersOp;
  63 import org.graalvm.compiler.lir.SwitchStrategy;
  64 import org.graalvm.compiler.lir.Variable;
  65 import org.graalvm.compiler.lir.hashing.Hasher;
  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 
 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
 130     public ArithmeticLIRGeneratorTool getArithmetic() {
 131         return arithmeticLIRGen;
 132     }
 133 
 134     @Override
 135     public MoveFactory getMoveFactory() {
 136         return moveFactory;
 137     }
 138 
 139     private MoveFactory spillMoveFactory;
 140 
 141     @Override
 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
 156     public LIRKind getValueKind(JavaKind javaKind) {
 157         return LIRKind.fromJavaKind(target().arch, javaKind);
 158     }
 159 
 160     @Override
 161     public TargetDescription target() {
 162         return getCodeCache().getTarget();
 163     }
 164 
 165     @Override
 166     public CodeGenProviders getProviders() {
 167         return providers;
 168     }
 169 
 170     @Override
 171     public MetaAccessProvider getMetaAccess() {
 172         return providers.getMetaAccess();
 173     }
 174 
 175     @Override
 176     public CodeCacheProvider getCodeCache() {
 177         return providers.getCodeCache();
 178     }
 179 
 180     @Override
 181     public ForeignCallsProvider getForeignCalls() {
 182         return providers.getForeignCalls();
 183     }
 184 
 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 
 195         public int numVariables() {
 196             return numVariables;
 197         }
 198 
 199         private int nextVariable() {
 200             return numVariables++;
 201         }
 202     }
 203 
 204     @Override
 205     public Variable newVariable(ValueKind<?> valueKind) {
 206         return new Variable(valueKind, ((VariableProvider) res.getLIR()).nextVariable());
 207     }
 208 
 209     @Override
 210     public RegisterConfig getRegisterConfig() {
 211         return res.getRegisterConfig();
 212     }
 213 
 214     @Override
 215     public RegisterAttributes attributes(Register register) {
 216         return getRegisterConfig().getAttributesMap()[register.number];
 217     }
 218 
 219     @Override
 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
 228     public void emitMove(AllocatableValue dst, Value src) {
 229         append(moveFactory.createMove(dst, src));
 230     }
 231 
 232     @Override
 233     public Variable emitReadRegister(Register register, ValueKind<?> kind) {
 234         return emitMove(register.asValue(kind));
 235     }
 236 
 237     @Override
 238     public void emitWriteRegister(Register dst, Value src, ValueKind<?> kind) {
 239         emitMove(dst.asValue(kind), src);
 240     }
 241 
 242     @Override
 243     public void emitMoveConstant(AllocatableValue dst, Constant src) {
 244         append(moveFactory.createLoad(dst, src));
 245     }
 246 
 247     @Override
 248     public boolean canInlineConstant(Constant constant) {
 249         return moveFactory.canInlineConstant(constant);
 250     }
 251 
 252     @Override
 253     public boolean mayEmbedConstantLoad(Constant constant) {
 254         return moveFactory.mayEmbedConstantLoad(constant);
 255     }
 256 
 257     @Override
 258     public Value emitConstant(LIRKind kind, Constant constant) {
 259         if (moveFactory.canInlineConstant(constant)) {
 260             return new ConstantValue(toRegisterKind(kind), constant);
 261         } else {
 262             return emitLoadConstant(toRegisterKind(kind), constant);
 263         }
 264     }
 265 
 266     @Override
 267     public Value emitJavaConstant(JavaConstant constant) {
 268         return emitConstant(getValueKind(constant.getJavaKind()), constant);
 269     }
 270 
 271     @Override
 272     public AllocatableValue emitLoadConstant(ValueKind<?> kind, Constant constant) {
 273         Variable result = newVariable(kind);
 274         emitMoveConstant(result, constant);
 275         return result;
 276     }
 277 
 278     @Override
 279     public AllocatableValue asAllocatable(Value value) {
 280         if (isAllocatableValue(value)) {
 281             return asAllocatableValue(value);
 282         } else if (isConstantValue(value)) {
 283             return emitLoadConstant(value.getValueKind(), asConstant(value));
 284         } else {
 285             return emitMove(value);
 286         }
 287     }
 288 
 289     @Override
 290     public Variable load(Value value) {
 291         if (!isVariable(value)) {
 292             return emitMove(value);
 293         }
 294         return (Variable) value;
 295     }
 296 
 297     @Override
 298     public Value loadNonConst(Value value) {
 299         if (isConstantValue(value) && !moveFactory.canInlineConstant(asConstant(value))) {
 300             return emitMove(value);
 301         }
 302         return value;
 303     }
 304 
 305     /**
 306      * Determines if only oop maps are required for the code generated from the LIR.
 307      */
 308     @Override
 309     public boolean needOnlyOopMaps() {
 310         return false;
 311     }
 312 
 313     /**
 314      * Gets the ABI specific operand used to return a value of a given kind from a method.
 315      *
 316      * @param javaKind the kind of value being returned
 317      * @param valueKind the backend type of the value being returned
 318      * @return the operand representing the ABI defined location used return a value of kind
 319      *         {@code kind}
 320      */
 321     @Override
 322     public AllocatableValue resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind) {
 323         Register reg = getRegisterConfig().getReturnRegister(javaKind);
 324         assert target().arch.canStoreValue(reg.getRegisterCategory(), valueKind.getPlatformKind()) : reg.getRegisterCategory() + " " + valueKind.getPlatformKind();
 325         return reg.asValue(valueKind);
 326     }
 327 
 328     NodeSourcePosition currentPosition;
 329 
 330     @Override
 331     public void setSourcePosition(NodeSourcePosition position) {
 332         currentPosition = position;
 333     }
 334 
 335     @Override
 336     public <I extends LIRInstruction> I append(I op) {
 337         LIR lir = res.getLIR();
 338         if (printIrWithLir) {
 339             TTY.println(op.toStringWithIdPrefix());
 340             TTY.println();
 341         }
 342         assert LIRVerifier.verify(op);
 343         ArrayList<LIRInstruction> lirForBlock = lir.getLIRforBlock(getCurrentBlock());
 344         op.setPosition(currentPosition);
 345         lirForBlock.add(op);
 346         return op;
 347     }
 348 
 349     @Override
 350     public boolean hasBlockEnd(AbstractBlockBase<?> block) {
 351         ArrayList<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
 352         if (ops.size() == 0) {
 353             return false;
 354         }
 355         return ops.get(ops.size() - 1) instanceof BlockEndOp;
 356     }
 357 
 358     private final class BlockScopeImpl extends BlockScope {
 359 
 360         private BlockScopeImpl(AbstractBlockBase<?> block) {
 361             currentBlock = block;
 362         }
 363 
 364         private void doBlockStart() {
 365             if (printIrWithLir) {
 366                 TTY.print(currentBlock.toString());
 367             }
 368 
 369             // set up the list of LIR instructions
 370             assert res.getLIR().getLIRforBlock(currentBlock) == null : "LIR list already computed for this block";
 371             res.getLIR().setLIRforBlock(currentBlock, new ArrayList<LIRInstruction>());
 372 
 373             append(new LabelOp(new Label(currentBlock.getId()), currentBlock.isAligned()));
 374 
 375             if (traceLIRGeneratorLevel >= 1) {
 376                 TTY.println("BEGIN Generating LIR for block B" + currentBlock.getId());
 377             }
 378         }
 379 
 380         private void doBlockEnd() {
 381             if (traceLIRGeneratorLevel >= 1) {
 382                 TTY.println("END Generating LIR for block B" + currentBlock.getId());
 383             }
 384 
 385             if (printIrWithLir) {
 386                 TTY.println();
 387             }
 388             currentBlock = null;
 389         }
 390 
 391         @Override
 392         public AbstractBlockBase<?> getCurrentBlock() {
 393             return currentBlock;
 394         }
 395 
 396         @Override
 397         public void close() {
 398             doBlockEnd();
 399         }
 400 
 401     }
 402 
 403     @Override
 404     public final BlockScope getBlockScope(AbstractBlockBase<?> block) {
 405         BlockScopeImpl blockScope = new BlockScopeImpl(block);
 406         blockScope.doBlockStart();
 407         return blockScope;
 408     }
 409 
 410     private final class MatchScope implements DebugCloseable {
 411 
 412         private MatchScope(AbstractBlockBase<?> block) {
 413             currentBlock = block;
 414         }
 415 
 416         @Override
 417         public void close() {
 418             currentBlock = null;
 419         }
 420 
 421     }
 422 
 423     public final DebugCloseable getMatchScope(AbstractBlockBase<?> block) {
 424         MatchScope matchScope = new MatchScope(block);
 425         return matchScope;
 426     }
 427 
 428     @Override
 429     public void emitIncomingValues(Value[] params) {
 430         ((LabelOp) res.getLIR().getLIRforBlock(getCurrentBlock()).get(0)).setIncomingValues(params);
 431     }
 432 
 433     @Override
 434     public abstract void emitJump(LabelRef label);
 435 
 436     @Override
 437     public abstract void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
 438                     double trueDestinationProbability);
 439 
 440     @Override
 441     public abstract void emitOverflowCheckBranch(LabelRef overflow, LabelRef noOverflow, LIRKind cmpKind, double overflowProbability);
 442 
 443     @Override
 444     public abstract void emitIntegerTestBranch(Value left, Value right, LabelRef trueDestination, LabelRef falseDestination, double trueSuccessorProbability);
 445 
 446     @Override
 447     public abstract Variable emitConditionalMove(PlatformKind cmpKind, Value leftVal, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue);
 448 
 449     @Override
 450     public abstract Variable emitIntegerTestMove(Value leftVal, Value right, Value trueValue, Value falseValue);
 451 
 452     /**
 453      * Emits the single call operation at the heart of generating LIR for a
 454      * {@linkplain #emitForeignCall(ForeignCallLinkage, LIRFrameState, Value...) foreign call}.
 455      */
 456     protected abstract void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info);
 457 
 458     @Override
 459     public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState frameState, Value... args) {
 460         LIRFrameState state = null;
 461         if (linkage.needsDebugInfo()) {
 462             if (frameState != null) {
 463                 state = frameState;
 464             } else {
 465                 assert needOnlyOopMaps();
 466                 state = new LIRFrameState(null, null, null);
 467             }
 468         }
 469 
 470         // move the arguments into the correct location
 471         CallingConvention linkageCc = linkage.getOutgoingCallingConvention();
 472         res.getFrameMapBuilder().callsMethod(linkageCc);
 473         assert linkageCc.getArgumentCount() == args.length : "argument count mismatch";
 474         Value[] argLocations = new Value[args.length];
 475         for (int i = 0; i < args.length; i++) {
 476             Value arg = args[i];
 477             AllocatableValue loc = linkageCc.getArgument(i);
 478             emitMove(loc, arg);
 479             argLocations[i] = loc;
 480         }
 481         res.setForeignCall(true);
 482         emitForeignCallOp(linkage, linkageCc.getReturn(), argLocations, linkage.getTemporaries(), state);
 483 
 484         if (isLegal(linkageCc.getReturn())) {
 485             return emitMove(linkageCc.getReturn());
 486         } else {
 487             return null;
 488         }
 489     }
 490 
 491     @Override
 492     public void emitStrategySwitch(JavaConstant[] keyConstants, double[] keyProbabilities, LabelRef[] keyTargets, LabelRef defaultTarget, Variable value) {
 493         SwitchStrategy strategy = SwitchStrategy.getBestStrategy(keyProbabilities, keyConstants, keyTargets);
 494 
 495         int keyCount = keyConstants.length;
 496         double minDensity = 1 / Math.sqrt(strategy.getAverageEffort());
 497         Optional<Hasher> hasher = hasherFor(keyConstants, minDensity);
 498         double hashTableSwitchDensity = hasher.map(h -> keyCount / (double) h.cardinality()).orElse(0d);
 499         // The value range computation below may overflow, so compute it as a long.
 500         long valueRange = (long) keyConstants[keyCount - 1].asInt() - (long) keyConstants[0].asInt() + 1;
 501         double tableSwitchDensity = keyCount / (double) valueRange;
 502 
 503         /*
 504          * This heuristic tries to find a compromise between the effort for the best switch strategy
 505          * and the density of a tableswitch. If the effort for the strategy is at least 4, then a
 506          * tableswitch is preferred if better than a certain value that starts at 0.5 and lowers
 507          * gradually with additional effort.
 508          */
 509         if (strategy.getAverageEffort() < 4d || (tableSwitchDensity < minDensity && hashTableSwitchDensity < minDensity)) {
 510             emitStrategySwitch(strategy, value, keyTargets, defaultTarget);
 511         } else {
 512             if (hashTableSwitchDensity > tableSwitchDensity) {
 513                 Hasher h = hasher.get();
 514                 int cardinality = h.cardinality();
 515                 LabelRef[] targets = new LabelRef[cardinality];
 516                 JavaConstant[] keys = new JavaConstant[cardinality];
 517                 for (int i = 0; i < cardinality; i++) {
 518                     keys[i] = JavaConstant.INT_0;
 519                     targets[i] = defaultTarget;
 520                 }
 521                 for (int i = 0; i < keyCount; i++) {
 522                     int idx = h.hash(keyConstants[i].asInt());
 523                     keys[idx] = keyConstants[i];
 524                     targets[idx] = keyTargets[i];
 525                 }
 526                 emitHashTableSwitch(h, keys, defaultTarget, targets, value);
 527             } else {
 528                 int minValue = keyConstants[0].asInt();
 529                 assert valueRange < Integer.MAX_VALUE;
 530                 LabelRef[] targets = new LabelRef[(int) valueRange];
 531                 for (int i = 0; i < valueRange; i++) {
 532                     targets[i] = defaultTarget;
 533                 }
 534                 for (int i = 0; i < keyCount; i++) {
 535                     targets[keyConstants[i].asInt() - minValue] = keyTargets[i];
 536                 }
 537                 emitTableSwitch(minValue, defaultTarget, targets, value);
 538             }
 539         }
 540     }
 541 
 542     @Override
 543     public abstract void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget);
 544 
 545     protected abstract void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key);
 546 
 547     @SuppressWarnings("unused")
 548     protected Optional<Hasher> hasherFor(JavaConstant[] keyConstants, double minDensity) {
 549         return Optional.empty();
 550     }
 551 
 552     @SuppressWarnings("unused")
 553     protected void emitHashTableSwitch(Hasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value) {
 554         throw new UnsupportedOperationException(getClass().getSimpleName() + " doesn't support hash table switches");
 555     }
 556 
 557     @Override
 558     public void beforeRegisterAllocation() {
 559     }
 560 
 561     /**
 562      * Gets a garbage value for a given kind.
 563      */
 564     protected abstract JavaConstant zapValueForKind(PlatformKind kind);
 565 
 566     @Override
 567     public LIRKind getLIRKind(Stamp stamp) {
 568         return stamp.getLIRKind(lirKindTool);
 569     }
 570 
 571     protected LIRKind getAddressKind(Value base, long displacement, Value index) {
 572         if (LIRKind.isValue(base) && (index.equals(Value.ILLEGAL) || LIRKind.isValue(index))) {
 573             return LIRKind.value(target().arch.getWordKind());
 574         } else if (base.getValueKind() instanceof LIRKind && base.getValueKind(LIRKind.class).isReference(0) && displacement == 0L && index.equals(Value.ILLEGAL)) {
 575             return LIRKind.reference(target().arch.getWordKind());
 576         } else {
 577             return LIRKind.unknownReference(target().arch.getWordKind());
 578         }
 579     }
 580 
 581     @Override
 582     public AbstractBlockBase<?> getCurrentBlock() {
 583         return currentBlock;
 584     }
 585 
 586     @Override
 587     public LIRGenerationResult getResult() {
 588         return res;
 589     }
 590 
 591     @Override
 592     public void emitBlackhole(Value operand) {
 593         append(new StandardOp.BlackholeOp(operand));
 594     }
 595 
 596     @Override
 597     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
 598         throw GraalError.unimplemented();
 599     }
 600 
 601     @Override
 602     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
 603         throw GraalError.unimplemented();
 604     }
 605 
 606     @Override
 607     public abstract ZapRegistersOp createZapRegisters(Register[] zappedRegisters, JavaConstant[] zapValues);
 608 
 609     @Override
 610     public ZapRegistersOp createZapRegisters() {
 611         Register[] zappedRegisters = getResult().getFrameMap().getRegisterConfig().getAllocatableRegisters().toArray();
 612         return createZapRegisters(zappedRegisters);
 613     }
 614 
 615     @Override
 616     public ZapRegistersOp createZapRegisters(Register[] zappedRegisters) {
 617         JavaConstant[] zapValues = new JavaConstant[zappedRegisters.length];
 618         for (int i = 0; i < zappedRegisters.length; i++) {
 619             PlatformKind kind = target().arch.getLargestStorableKind(zappedRegisters[i].getRegisterCategory());
 620             zapValues[i] = zapValueForKind(kind);
 621         }
 622         return createZapRegisters(zappedRegisters, zapValues);
 623     }
 624 
 625     @Override
 626     public abstract LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues);
 627 
 628     @Override
 629     public LIRInstruction zapArgumentSpace() {
 630         List<StackSlot> slots = null;
 631         for (AllocatableValue arg : res.getCallingConvention().getArguments()) {
 632             if (isStackSlot(arg)) {
 633                 if (slots == null) {
 634                     slots = new ArrayList<>();
 635                 }
 636                 slots.add((StackSlot) arg);
 637             } else {
 638                 assert !isVirtualStackSlot(arg);
 639             }
 640         }
 641         if (slots == null) {
 642             return null;
 643         }
 644         StackSlot[] zappedStack = slots.toArray(new StackSlot[slots.size()]);
 645         JavaConstant[] zapValues = new JavaConstant[zappedStack.length];
 646         for (int i = 0; i < zappedStack.length; i++) {
 647             PlatformKind kind = zappedStack[i].getPlatformKind();
 648             zapValues[i] = zapValueForKind(kind);
 649         }
 650         return createZapArgumentSpace(zappedStack, zapValues);
 651     }
 652 }