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