001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.opt.bc2ir;
014
015import static org.jikesrvm.classloader.BytecodeConstants.*;
016import static org.jikesrvm.classloader.ClassLoaderConstants.*;
017import static org.jikesrvm.compilers.opt.OptimizingCompilerException.opt_assert;
018import static org.jikesrvm.compilers.opt.bc2ir.IRGenOptions.*;
019import static org.jikesrvm.compilers.opt.driver.OptConstants.NO;
020import static org.jikesrvm.compilers.opt.driver.OptConstants.RUNTIME_SERVICES_BCI;
021import static org.jikesrvm.compilers.opt.driver.OptConstants.YES;
022import static org.jikesrvm.compilers.opt.ir.Operators.*;
023import static org.jikesrvm.osr.OSRConstants.*;
024
025import java.util.ArrayList;
026import java.util.Enumeration;
027
028import org.jikesrvm.VM;
029import org.jikesrvm.adaptive.controller.Controller;
030import org.jikesrvm.classloader.BytecodeStream;
031import org.jikesrvm.classloader.FieldReference;
032import org.jikesrvm.classloader.MethodReference;
033import org.jikesrvm.classloader.RVMClass;
034import org.jikesrvm.classloader.RVMField;
035import org.jikesrvm.classloader.RVMMethod;
036import org.jikesrvm.classloader.RVMType;
037import org.jikesrvm.classloader.TypeReference;
038import org.jikesrvm.compilers.baseline.SwitchBranchProfile;
039import org.jikesrvm.compilers.common.CompiledMethod;
040import org.jikesrvm.compilers.common.CompiledMethods;
041import org.jikesrvm.compilers.opt.ClassLoaderProxy;
042import org.jikesrvm.compilers.opt.FieldAnalysis;
043import org.jikesrvm.compilers.opt.OptimizingCompilerException;
044import org.jikesrvm.compilers.opt.Simplifier;
045import org.jikesrvm.compilers.opt.StaticFieldReader;
046import org.jikesrvm.compilers.opt.driver.OptimizingCompiler;
047import org.jikesrvm.compilers.opt.inlining.CompilationState;
048import org.jikesrvm.compilers.opt.inlining.InlineDecision;
049import org.jikesrvm.compilers.opt.inlining.InlineSequence;
050import org.jikesrvm.compilers.opt.inlining.Inliner;
051import org.jikesrvm.compilers.opt.ir.ALoad;
052import org.jikesrvm.compilers.opt.ir.AStore;
053import org.jikesrvm.compilers.opt.ir.Athrow;
054import org.jikesrvm.compilers.opt.ir.BasicBlock;
055import org.jikesrvm.compilers.opt.ir.Binary;
056import org.jikesrvm.compilers.opt.ir.BoundsCheck;
057import org.jikesrvm.compilers.opt.ir.CacheOp;
058import org.jikesrvm.compilers.opt.ir.Call;
059import org.jikesrvm.compilers.opt.ir.Empty;
060import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock;
061import org.jikesrvm.compilers.opt.ir.GetField;
062import org.jikesrvm.compilers.opt.ir.GetStatic;
063import org.jikesrvm.compilers.opt.ir.Goto;
064import org.jikesrvm.compilers.opt.ir.GuardedBinary;
065import org.jikesrvm.compilers.opt.ir.GuardedUnary;
066import org.jikesrvm.compilers.opt.ir.IRTools;
067import org.jikesrvm.compilers.opt.ir.IfCmp;
068import org.jikesrvm.compilers.opt.ir.InstanceOf;
069import org.jikesrvm.compilers.opt.ir.Instruction;
070import org.jikesrvm.compilers.opt.ir.LookupSwitch;
071import org.jikesrvm.compilers.opt.ir.MonitorOp;
072import org.jikesrvm.compilers.opt.ir.Move;
073import org.jikesrvm.compilers.opt.ir.Multianewarray;
074import org.jikesrvm.compilers.opt.ir.New;
075import org.jikesrvm.compilers.opt.ir.NewArray;
076import org.jikesrvm.compilers.opt.ir.NullCheck;
077import org.jikesrvm.compilers.opt.ir.Operator;
078import org.jikesrvm.compilers.opt.ir.OsrBarrier;
079import org.jikesrvm.compilers.opt.ir.OsrPoint;
080import org.jikesrvm.compilers.opt.ir.PutField;
081import org.jikesrvm.compilers.opt.ir.PutStatic;
082import org.jikesrvm.compilers.opt.ir.Register;
083import org.jikesrvm.compilers.opt.ir.ResultCarrier;
084import org.jikesrvm.compilers.opt.ir.StoreCheck;
085import org.jikesrvm.compilers.opt.ir.TableSwitch;
086import org.jikesrvm.compilers.opt.ir.Trap;
087import org.jikesrvm.compilers.opt.ir.TypeCheck;
088import org.jikesrvm.compilers.opt.ir.Unary;
089import org.jikesrvm.compilers.opt.ir.ZeroCheck;
090import org.jikesrvm.compilers.opt.ir.operand.AddressConstantOperand;
091import org.jikesrvm.compilers.opt.ir.operand.BranchOperand;
092import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
093import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
094import org.jikesrvm.compilers.opt.ir.operand.ConstantOperand;
095import org.jikesrvm.compilers.opt.ir.operand.DoubleConstantOperand;
096import org.jikesrvm.compilers.opt.ir.operand.FloatConstantOperand;
097import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
098import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
099import org.jikesrvm.compilers.opt.ir.operand.LongConstantOperand;
100import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
101import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand;
102import org.jikesrvm.compilers.opt.ir.operand.Operand;
103import org.jikesrvm.compilers.opt.ir.operand.OsrTypeInfoOperand;
104import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
105import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
106import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
107import org.jikesrvm.compilers.opt.ir.operand.TypeOperand;
108import org.jikesrvm.osr.ObjectHolder;
109import org.jikesrvm.osr.bytecodes.InvokeStatic;
110import org.jikesrvm.runtime.Entrypoints;
111import org.jikesrvm.runtime.Magic;
112import org.vmmagic.pragma.NoInline;
113import org.vmmagic.unboxed.Address;
114import org.vmmagic.unboxed.Offset;
115
116/**
117 * This class translates from bytecode to HIR.
118 * <p>
119 * The only public entry point is BC2IR.generateHIR.
120 * generateHIR is passed an argument GenerationContext.
121 * The context is assumed to be "empty" but "initialized." Invoking
122 * generateHIR on a context results in it being "filled in" with the HIR
123 * for the method (and for any inlined methods) as specified by the
124 * state of the context.
125 * <p>
126 * The basic idea is to abstractly interpret the bytecode stream,
127 * translating it into a register-based IR along the way.  At each program
128 * point BC2IR has an abstract stack and an abstract local variable array.
129 * Based on this, and on the bytecode, it can generate instructions.
130 * It also does a number of forward flow-sensitive dataflow analyses and
131 * optimistic optimizations in the process. There's lots of details in
132 * John Whaley's master thesis from MIT.  However, one needs to be careful
133 * because this code has substantial diverged from the system described in
134 * his thesis.
135 * Some optimizations/features described in Johns's thesis are not implemented
136 * here. Some optimizations/features implemented here are not described
137 * in John's thesis.
138 * In particular this code takes a different approach to JSRs (inlining them),
139 * and has more advanced and effective implementation of the inlining
140 * transformation.
141 *
142 *
143 * @see IRGenOptions
144 * @see GenerationContext
145 * @see ConvertBCtoHIR
146 */
147public final class BC2IR {
148  /**
149   * Dummy slot.
150   * Used to deal with the fact the longs/doubles take
151   * two words of stack space/local space to represent.
152   * This field needs to be accessed by several of the IR classes,
153   * but is not intended to be referenced by general client code.
154   */
155  public static final DummyStackSlot DUMMY = new DummyStackSlot();
156
157  /**
158   * Generate HIR as specified by the argument GenerationContext.
159   * As a result of calling this method, the cfg field of the generation
160   * context is populated with basic blocks and instructions.
161   * Additionally, other fields of the generation context will be modified
162   * to summarize what happened during IR generation.
163   * <p>
164   * This is the only external entry point to BC2IR.
165   * <p>
166   * Note: most clients should be calling methods in
167   * ConvertBCtoHIR or in Inliner rather than invoking
168   * BC2IR.generateHIR directly.
169   *
170   * @param context the generation context
171   */
172  public static void generateHIR(GenerationContext context) {
173    new BC2IR(context).generateHIR();
174  }
175
176  //////////////////////////////////////////
177  // vvv Implementation details below vvv //
178  //////////////////////////////////////////
179  /**
180   * The generation context.
181   */
182  private GenerationContext gc;
183
184  /**
185   * Bytecodes for the method being generated.
186   */
187  private BytecodeStream bcodes;
188
189  // Fields to support generation of instructions/blocks
190  /**
191   * The set of BasicBlockLEs we are generating
192   */
193  private BBSet blocks;
194
195  /**
196   * Bytecode index of current instruction.
197   */
198  private int instrIndex;
199
200  // OSR field
201  private boolean osrGuardedInline = false;
202
203  /**
204   * OSR field: TODO rework this mechanism!
205   * adjustment of bcIndex of instructions because of
206   * specialized bytecode.
207   */
208  private int bciAdjustment;
209
210  /**
211   * Last instruction generated (for ELIM_COPY_LOCALS)
212   */
213  private Instruction lastInstr;
214
215  /**
216   * Does basic block end here?
217   */
218  private boolean endOfBasicBlock;
219
220  /**
221   * Do we fall through to the next basic block?
222   */
223  private boolean fallThrough;
224
225  /**
226   * Current BBLE.
227   */
228  private BasicBlockLE currentBBLE;
229
230  /**
231   * Current simulated stack state.
232   */
233  private OperandStack stack;
234
235  /**
236   * Current state of local variables.
237   */
238  private Operand[] _localState;
239
240  /**
241   * Index of next basic block.
242   */
243  private int runoff;
244
245  private Operand currentGuard;
246
247  /**
248   * Was something inlined?
249   */
250  private boolean inlinedSomething;
251
252  /**
253   * OSR: used for PSEUDO_InvokeStatic to recover the type info
254   */
255  private int param1, param2;
256
257  /**
258   * osr barrier needs type information of locals and stacks,
259   * it has to be created before a _callHelper.
260   * only when the call site is going to be inlined, the instruction
261   * is inserted before the call site.
262   */
263  private Instruction lastOsrBarrier = null;
264
265  /**
266   *  Debugging with method_to_print. Switch following 2
267   *  to both be non-final. Set {@link #DBG_SELECTIVE} to true.
268   *  {@link #DBG_SELECTED} will then be {@code true} when the method matches.
269   *  You must also uncomment the assignment to DBG_SELECTIVE in
270   *  {@link #start(GenerationContext)}.
271   */
272  private static final boolean DBG_SELECTIVE = false;
273  static final boolean DBG_SELECTED = false;
274
275  //////////
276  // End of field declarations
277  //////////
278
279  /**
280   * Construct the BC2IR object for the generation context.
281   * After the constructor completes, we're ready to start generating
282   * HIR from bytecode 0 of context.method.
283   *
284   * @param context the context to generate HIR into
285   */
286  private BC2IR(GenerationContext context) {
287    start(context);
288    for (int argIdx = 0, localIdx = 0; argIdx < context.getArguments().length;) {
289      TypeReference argType = context.getArguments()[argIdx].getType();
290      _localState[localIdx++] = context.getArguments()[argIdx++];
291      if (argType.isLongType() || argType.isDoubleType()) {
292        _localState[localIdx++] = DUMMY;
293      }
294    }
295    finish(context);
296  }
297
298  @NoInline
299  private void start(GenerationContext context) {
300    gc = context;
301    // To use the following you need to change the declarations
302    // above the constructor
303    if (DBG_SELECTIVE) {
304      VM.sysWrite("Whoops! you need to uncomment the assignment to DBG_SELECTED");
305//      DBG_SELECTED = gc.methodIsSelectedForDebuggingWithMethodToPrint();
306    }
307
308    if (context.getMethod().isForOsrSpecialization()) {
309      bcodes = context.getMethod().getOsrSynthesizedBytecodes();
310    } else {
311      bcodes = context.getMethod().getBytecodes();
312    }
313
314    // initialize the local state from context.arguments
315    _localState = new Operand[context.getMethod().getLocalWords()];
316
317    if (context.getMethod().isForOsrSpecialization()) {
318      this.bciAdjustment = context.getMethod().getOsrPrologueLength();
319    } else {
320      this.bciAdjustment = 0;
321    }
322
323    this.osrGuardedInline = VM.runningVM &&
324       context.getOptions().OSR_GUARDED_INLINING &&
325       !context.getMethod().isForOsrSpecialization() &&
326       OptimizingCompiler.getAppStarted() &&
327       (Controller.options != null) &&
328       Controller.options.ENABLE_RECOMPILATION;
329  }
330
331  private void finish(GenerationContext context) {
332    // Initialize simulated stack.
333    stack = new OperandStack(context.getMethod().getOperandWords());
334    // Initialize BBSet.
335    blocks = new BBSet(context, bcodes, _localState);
336    // Finish preparing to generate from bytecode 0
337    currentBBLE = blocks.getEntry();
338    gc.getPrologue().insertOut(currentBBLE.block);
339    if (DBG_CFG || DBG_SELECTED) {
340      db("Added CFG edge from " + gc.getPrologue() + " to " + currentBBLE.block);
341    }
342    runoff = currentBBLE.max;
343  }
344
345  /**
346   * Main generation loop.
347   */
348  private void generateHIR() {
349    // Constructor initialized generation state to start
350    // generating from bytecode 0, so get the ball rolling.
351    if (DBG_BB || DBG_SELECTED) db("bbl: " + printBlocks());
352    generateFrom(0);
353    // While there are more blocks that need it, pick one and generate it.
354    for (currentBBLE = blocks.getNextEmptyBlock(currentBBLE); currentBBLE != null; currentBBLE =
355        blocks.getNextEmptyBlock(currentBBLE)) {
356      // Found a block. Set the generation state appropriately.
357      currentBBLE.clearSelfRegen();
358      runoff = Math.min(blocks.getNextBlockBytecodeIndex(currentBBLE), currentBBLE.max);
359      if (currentBBLE.stackState == null) {
360        stack.clear();
361      } else {
362        stack = currentBBLE.stackState.deepCopy();
363      }
364      _localState = currentBBLE.copyLocalState();
365      if (DBG_BB || DBG_SELECTED) db("bbl: " + printBlocks());
366      // Generate it!
367      generateFrom(currentBBLE.low);
368    }
369    // Construct initial code order, commit to recursive inlines,
370    // insert any synthetic blocks.
371    if (DBG_BB || DBG_SELECTED) db("doing final pass over basic blocks: " + printBlocks());
372    blocks.finalPass(inlinedSomething);
373  }
374
375  // pops the length off the stack
376  //
377  public Instruction generateAnewarray(TypeReference arrayTypeRef, TypeReference elementTypeRef) {
378    if (arrayTypeRef == null) {
379      if (VM.VerifyAssertions) opt_assert(elementTypeRef != null);
380      arrayTypeRef = elementTypeRef.getArrayTypeForElementType();
381    }
382    if (elementTypeRef == null) {
383      elementTypeRef = arrayTypeRef.getArrayElementType();
384    }
385
386    RegisterOperand t = gc.getTemps().makeTemp(arrayTypeRef);
387    t.setPreciseType();
388    markGuardlessNonNull(t);
389    // We can do early resolution of the array type if the element type
390    // is already initialized.
391    RVMType arrayType = arrayTypeRef.peekType();
392    Operator op;
393    TypeOperand arrayOp;
394
395    if ((arrayType != null) && (arrayType.isInitialized() || arrayType.isInBootImage())) {
396      op = NEWARRAY;
397      arrayOp = makeTypeOperand(arrayType);
398      t.setExtant();
399    } else {
400      RVMType elementType = elementTypeRef.peekType();
401      if ((elementType != null) && (elementType.isInitialized() || elementType.isInBootImage())) {
402        arrayType = arrayTypeRef.resolve();
403        arrayType.resolve();
404        arrayType.instantiate();
405        op = NEWARRAY;
406        arrayOp = makeTypeOperand(arrayType);
407        t.setExtant();
408      } else {
409        op = NEWARRAY_UNRESOLVED;
410        arrayOp = makeTypeOperand(arrayTypeRef);
411      }
412    }
413    Instruction s = NewArray.create(op, t, arrayOp, popInt());
414    push(t.copyD2U());
415    rectifyStateWithErrorHandler();
416    rectifyStateWithExceptionHandler(TypeReference.JavaLangNegativeArraySizeException);
417    return s;
418  }
419
420  /**
421   * Generate instructions for a basic block.
422   * May discover other basic blocks that need to be generated along the way.
423   *
424   * @param fromIndex bytecode index to start from
425   */
426  private void generateFrom(int fromIndex) {
427    if (DBG_BB || DBG_SELECTED) {
428      db("generating code into " + currentBBLE + " with runoff " + runoff);
429    }
430    currentBBLE.setGenerated();
431    endOfBasicBlock = fallThrough = false;
432    lastInstr = null;
433    bcodes.reset(fromIndex);
434    while (true) {
435      // Must keep currentBBLE.high up-to-date in case we try to jump into
436      // the middle of the block we're currently generating.  Simply updating
437      // high once endsBasicBlock is true doesn't enable us to catch this case.
438      currentBBLE.high = instrIndex = bcodes.index();
439      int code = bcodes.nextInstruction();
440      if (DBG_BCPARSE) {
441        db("parsing " +
442           instrIndex +
443           " " +
444           code +
445           " : 0x" +
446           Integer.toHexString(code) +
447           " " +
448           JBC_name(code));
449      }
450      Instruction s = null;
451
452      lastOsrBarrier = null;
453
454      switch (code) {
455        case JBC_nop:
456          break;
457
458        case JBC_aconst_null:
459          push(new NullConstantOperand());
460          break;
461
462        case JBC_iconst_m1:
463        case JBC_iconst_0:
464        case JBC_iconst_1:
465        case JBC_iconst_2:
466        case JBC_iconst_3:
467        case JBC_iconst_4:
468        case JBC_iconst_5:
469          push(new IntConstantOperand(code - JBC_iconst_0));
470          break;
471
472        case JBC_lconst_0:
473        case JBC_lconst_1:
474          pushDual(new LongConstantOperand(code - JBC_lconst_0));
475          break;
476
477        case JBC_fconst_0:
478          push(new FloatConstantOperand(0.f));
479          break;
480
481        case JBC_fconst_1:
482          push(new FloatConstantOperand(1.f));
483          break;
484
485        case JBC_fconst_2:
486          push(new FloatConstantOperand(2.f));
487          break;
488
489        case JBC_dconst_0:
490          pushDual(new DoubleConstantOperand(0.));
491          break;
492
493        case JBC_dconst_1:
494          pushDual(new DoubleConstantOperand(1.));
495          break;
496
497        case JBC_bipush:
498          push(new IntConstantOperand(bcodes.getByteValue()));
499          break;
500
501        case JBC_sipush:
502          push(new IntConstantOperand(bcodes.getShortValue()));
503          break;
504
505        case JBC_ldc:
506          push(getConstantOperand(bcodes.getConstantIndex()));
507          break;
508
509        case JBC_ldc_w:
510          push(getConstantOperand(bcodes.getWideConstantIndex()));
511          break;
512
513        case JBC_ldc2_w:
514          pushDual(getConstantOperand(bcodes.getWideConstantIndex()));
515          break;
516
517        case JBC_iload:
518          s = do_iload(bcodes.getLocalNumber());
519          break;
520
521        case JBC_lload:
522          s = do_lload(bcodes.getLocalNumber());
523          break;
524
525        case JBC_fload:
526          s = do_fload(bcodes.getLocalNumber());
527          break;
528
529        case JBC_dload:
530          s = do_dload(bcodes.getLocalNumber());
531          break;
532
533        case JBC_aload:
534          s = do_aload(bcodes.getLocalNumber());
535          break;
536
537        case JBC_iload_0:
538        case JBC_iload_1:
539        case JBC_iload_2:
540        case JBC_iload_3:
541          s = do_iload(code - JBC_iload_0);
542          break;
543
544        case JBC_lload_0:
545        case JBC_lload_1:
546        case JBC_lload_2:
547        case JBC_lload_3:
548          s = do_lload(code - JBC_lload_0);
549          break;
550
551        case JBC_fload_0:
552        case JBC_fload_1:
553        case JBC_fload_2:
554        case JBC_fload_3:
555          s = do_fload(code - JBC_fload_0);
556          break;
557
558        case JBC_dload_0:
559        case JBC_dload_1:
560        case JBC_dload_2:
561        case JBC_dload_3:
562          s = do_dload(code - JBC_dload_0);
563          break;
564
565        case JBC_aload_0:
566        case JBC_aload_1:
567        case JBC_aload_2:
568        case JBC_aload_3:
569          s = do_aload(code - JBC_aload_0);
570          break;
571
572        case JBC_iaload: {
573          Operand index = popInt();
574          Operand ref = pop();
575          clearCurrentGuard();
576          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
577            break;
578          }
579          if (VM.VerifyAssertions) {
580            assertIsType(ref, TypeReference.IntArray);
581          }
582          s = _aloadHelper(INT_ALOAD, ref, index, TypeReference.Int);
583        }
584        break;
585
586        case JBC_laload: {
587          Operand index = popInt();
588          Operand ref = pop();
589          clearCurrentGuard();
590          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
591            break;
592          }
593          if (VM.VerifyAssertions) {
594            assertIsType(ref, TypeReference.LongArray);
595          }
596          s = _aloadHelper(LONG_ALOAD, ref, index, TypeReference.Long);
597        }
598        break;
599
600        case JBC_faload: {
601          Operand index = popInt();
602          Operand ref = pop();
603          clearCurrentGuard();
604          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
605            break;
606          }
607          if (VM.VerifyAssertions) {
608            assertIsType(ref, TypeReference.FloatArray);
609          }
610          s = _aloadHelper(FLOAT_ALOAD, ref, index, TypeReference.Float);
611        }
612        break;
613
614        case JBC_daload: {
615          Operand index = popInt();
616          Operand ref = pop();
617          clearCurrentGuard();
618          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
619            break;
620          }
621          if (VM.VerifyAssertions) {
622            assertIsType(ref, TypeReference.DoubleArray);
623          }
624          s = _aloadHelper(DOUBLE_ALOAD, ref, index, TypeReference.Double);
625        }
626        break;
627
628        case JBC_aaload: {
629          Operand index = popInt();
630          Operand ref = pop();
631          clearCurrentGuard();
632          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
633            break;
634          }
635          TypeReference type = getRefTypeOf(ref).getArrayElementType();
636          if (VM.VerifyAssertions) opt_assert(type.isReferenceType());
637          s = _aloadHelper(REF_ALOAD, ref, index, type);
638        }
639        break;
640
641        case JBC_baload: {
642          Operand index = popInt();
643          Operand ref = pop();
644          clearCurrentGuard();
645          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
646            break;
647          }
648          TypeReference type = getArrayTypeOf(ref);
649          if (VM.VerifyAssertions) {
650            opt_assert(type == TypeReference.ByteArray || type == TypeReference.BooleanArray);
651          }
652          if (type == TypeReference.ByteArray) {
653            s = _aloadHelper(BYTE_ALOAD, ref, index, TypeReference.Byte);
654          } else {
655            s = _aloadHelper(UBYTE_ALOAD, ref, index, TypeReference.Boolean);
656          }
657        }
658        break;
659
660        case JBC_caload: {
661          Operand index = popInt();
662          Operand ref = pop();
663          clearCurrentGuard();
664          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
665            break;
666          }
667          if (VM.VerifyAssertions) {
668            assertIsType(ref, TypeReference.CharArray);
669          }
670          s = _aloadHelper(USHORT_ALOAD, ref, index, TypeReference.Char);
671        }
672        break;
673
674        case JBC_saload: {
675          Operand index = popInt();
676          Operand ref = pop();
677          clearCurrentGuard();
678          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
679            break;
680          }
681          if (VM.VerifyAssertions) {
682            assertIsType(ref, TypeReference.ShortArray);
683          }
684          s = _aloadHelper(SHORT_ALOAD, ref, index, TypeReference.Short);
685        }
686        break;
687
688        case JBC_istore:
689          s = do_store(bcodes.getLocalNumber(), popInt());
690          break;
691
692        case JBC_lstore:
693          s = do_store(bcodes.getLocalNumber(), popLong());
694          break;
695
696        case JBC_fstore:
697          s = do_store(bcodes.getLocalNumber(), popFloat());
698          break;
699
700        case JBC_dstore:
701          s = do_store(bcodes.getLocalNumber(), popDouble());
702          break;
703
704        case JBC_astore:
705          s = do_astore(bcodes.getLocalNumber());
706          break;
707
708        case JBC_istore_0:
709        case JBC_istore_1:
710        case JBC_istore_2:
711        case JBC_istore_3:
712          s = do_store(code - JBC_istore_0, popInt());
713          break;
714
715        case JBC_lstore_0:
716        case JBC_lstore_1:
717        case JBC_lstore_2:
718        case JBC_lstore_3:
719          s = do_store(code - JBC_lstore_0, popLong());
720          break;
721
722        case JBC_fstore_0:
723        case JBC_fstore_1:
724        case JBC_fstore_2:
725        case JBC_fstore_3:
726          s = do_store(code - JBC_fstore_0, popFloat());
727          break;
728
729        case JBC_dstore_0:
730        case JBC_dstore_1:
731        case JBC_dstore_2:
732        case JBC_dstore_3:
733          s = do_store(code - JBC_dstore_0, popDouble());
734          break;
735
736        case JBC_astore_0:
737        case JBC_astore_1:
738        case JBC_astore_2:
739        case JBC_astore_3:
740          s = do_astore(code - JBC_astore_0);
741          break;
742
743        case JBC_iastore: {
744          Operand val = popInt();
745          Operand index = popInt();
746          Operand ref = pop();
747          clearCurrentGuard();
748          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
749            break;
750          }
751          if (VM.VerifyAssertions) {
752            assertIsType(ref, TypeReference.IntArray);
753          }
754          s =
755              AStore.create(INT_ASTORE,
756                            val,
757                            ref,
758                            index,
759                            new LocationOperand(TypeReference.Int),
760                            getCurrentGuard());
761        }
762        break;
763
764        case JBC_lastore: {
765          Operand val = popLong();
766          Operand index = popInt();
767          Operand ref = pop();
768          clearCurrentGuard();
769          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
770            break;
771          }
772          if (VM.VerifyAssertions) {
773            assertIsType(ref, TypeReference.LongArray);
774          }
775          s =
776              AStore.create(LONG_ASTORE,
777                            val,
778                            ref,
779                            index,
780                            new LocationOperand(TypeReference.Long),
781                            getCurrentGuard());
782        }
783        break;
784
785        case JBC_fastore: {
786          Operand val = popFloat();
787          Operand index = popInt();
788          Operand ref = pop();
789          clearCurrentGuard();
790          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
791            break;
792          }
793          if (VM.VerifyAssertions) {
794            assertIsType(ref, TypeReference.FloatArray);
795          }
796          s =
797              AStore.create(FLOAT_ASTORE,
798                            val,
799                            ref,
800                            index,
801                            new LocationOperand(TypeReference.Float),
802                            getCurrentGuard());
803        }
804        break;
805
806        case JBC_dastore: {
807          Operand val = popDouble();
808          Operand index = popInt();
809          Operand ref = pop();
810          clearCurrentGuard();
811          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
812            break;
813          }
814          if (VM.VerifyAssertions) {
815            assertIsType(ref, TypeReference.DoubleArray);
816          }
817          s =
818              AStore.create(DOUBLE_ASTORE,
819                            val,
820                            ref,
821                            index,
822                            new LocationOperand(TypeReference.Double),
823                            getCurrentGuard());
824        }
825        break;
826
827        case JBC_aastore: {
828          Operand val = pop();
829          Operand index = popInt();
830          Operand ref = pop();
831          clearCurrentGuard();
832          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
833            break;
834          }
835          TypeReference type = getRefTypeOf(ref).getArrayElementType();
836          if (VM.VerifyAssertions) opt_assert(type.isReferenceType());
837          if (do_CheckStore(ref, val, type)) {
838            break;
839          }
840          s = AStore.create(REF_ASTORE, val, ref, index, new LocationOperand(type), getCurrentGuard());
841        }
842        break;
843
844        case JBC_bastore: {
845          Operand val = popInt();
846          Operand index = popInt();
847          Operand ref = pop();
848          clearCurrentGuard();
849          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
850            break;
851          }
852          TypeReference type = getArrayTypeOf(ref);
853          if (VM.VerifyAssertions) {
854            opt_assert(type == TypeReference.ByteArray || type == TypeReference.BooleanArray);
855          }
856          if (type == TypeReference.ByteArray) {
857            type = TypeReference.Byte;
858          } else {
859            type = TypeReference.Boolean;
860          }
861          s = AStore.create(BYTE_ASTORE, val, ref, index, new LocationOperand(type), getCurrentGuard());
862        }
863        break;
864
865        case JBC_castore: {
866          Operand val = popInt();
867          Operand index = popInt();
868          Operand ref = pop();
869          clearCurrentGuard();
870          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
871            break;
872          }
873          if (VM.VerifyAssertions) {
874            assertIsType(ref, TypeReference.CharArray);
875          }
876          s =
877              AStore.create(SHORT_ASTORE,
878                            val,
879                            ref,
880                            index,
881                            new LocationOperand(TypeReference.Char),
882                            getCurrentGuard());
883        }
884        break;
885
886        case JBC_sastore: {
887          Operand val = popInt();
888          Operand index = popInt();
889          Operand ref = pop();
890          clearCurrentGuard();
891          if (do_NullCheck(ref) || do_BoundsCheck(ref, index)) {
892            break;
893          }
894          if (VM.VerifyAssertions) {
895            assertIsType(ref, TypeReference.ShortArray);
896          }
897          s =
898              AStore.create(SHORT_ASTORE,
899                            val,
900                            ref,
901                            index,
902                            new LocationOperand(TypeReference.Short),
903                            getCurrentGuard());
904        }
905        break;
906
907        case JBC_pop:
908          stack.pop();
909          break;
910
911        case JBC_pop2:
912          stack.pop2();
913          break;
914
915        case JBC_dup: {
916          Operand op1 = stack.pop();
917          stack.push(op1);
918          s = pushCopy(op1);
919        }
920        break;
921
922        case JBC_dup_x1: {
923          Operand op1 = stack.pop();
924          Operand op2 = stack.pop();
925          stack.push(op1);
926          stack.push(op2);
927          s = pushCopy(op1);
928        }
929        break;
930
931        case JBC_dup_x2: {
932          Operand op1 = stack.pop();
933          Operand op2 = stack.pop();
934          Operand op3 = stack.pop();
935          stack.push(op1);
936          stack.push(op3);
937          stack.push(op2);
938          s = pushCopy(op1);
939        }
940        break;
941
942        case JBC_dup2: {
943          Operand op1 = stack.pop();
944          Operand op2 = stack.pop();
945          stack.push(op2);
946          stack.push(op1);
947          s = pushCopy(op2);
948          if (s != null) {
949            appendInstruction(s);
950            s = null;
951          }
952          s = pushCopy(op1);
953        }
954        break;
955
956        case JBC_dup2_x1: {
957          Operand op1 = stack.pop();
958          Operand op2 = stack.pop();
959          Operand op3 = stack.pop();
960          stack.push(op2);
961          stack.push(op1);
962          stack.push(op3);
963          s = pushCopy(op2);
964          if (s != null) {
965            appendInstruction(s);
966            s = null;
967          }
968          s = pushCopy(op1);
969        }
970        break;
971
972        case JBC_dup2_x2: {
973          Operand op1 = stack.pop();
974          Operand op2 = stack.pop();
975          Operand op3 = stack.pop();
976          Operand op4 = stack.pop();
977          stack.push(op2);
978          stack.push(op1);
979          stack.push(op4);
980          stack.push(op3);
981          s = pushCopy(op2);
982          if (s != null) {
983            appendInstruction(s);
984            s = null;
985          }
986          s = pushCopy(op1);
987        }
988        break;
989
990        case JBC_swap: {
991          stack.swap();
992        }
993        break;
994
995        case JBC_iadd: {
996          Operand op2 = popInt();
997          Operand op1 = popInt();
998          s = _binaryHelper(INT_ADD, op1, op2, TypeReference.Int);
999        }
1000        break;
1001
1002        case JBC_ladd: {
1003          Operand op2 = popLong();
1004          Operand op1 = popLong();
1005          s = _binaryDualHelper(LONG_ADD, op1, op2, TypeReference.Long);
1006        }
1007        break;
1008
1009        case JBC_fadd: {
1010          Operand op2 = popFloat();
1011          Operand op1 = popFloat();
1012          s = _binaryHelper(FLOAT_ADD, op1, op2, TypeReference.Float);
1013        }
1014        break;
1015
1016        case JBC_dadd: {
1017          Operand op2 = popDouble();
1018          Operand op1 = popDouble();
1019          s = _binaryDualHelper(DOUBLE_ADD, op1, op2, TypeReference.Double);
1020        }
1021        break;
1022
1023        case JBC_isub: {
1024          Operand op2 = popInt();
1025          Operand op1 = popInt();
1026          s = _binaryHelper(INT_SUB, op1, op2, TypeReference.Int);
1027        }
1028        break;
1029
1030        case JBC_lsub: {
1031          Operand op2 = popLong();
1032          Operand op1 = popLong();
1033          s = _binaryDualHelper(LONG_SUB, op1, op2, TypeReference.Long);
1034        }
1035        break;
1036
1037        case JBC_fsub: {
1038          Operand op2 = popFloat();
1039          Operand op1 = popFloat();
1040          s = _binaryHelper(FLOAT_SUB, op1, op2, TypeReference.Float);
1041        }
1042        break;
1043
1044        case JBC_dsub: {
1045          Operand op2 = popDouble();
1046          Operand op1 = popDouble();
1047          s = _binaryDualHelper(DOUBLE_SUB, op1, op2, TypeReference.Double);
1048        }
1049        break;
1050
1051        case JBC_imul: {
1052          Operand op2 = popInt();
1053          Operand op1 = popInt();
1054          s = _binaryHelper(INT_MUL, op1, op2, TypeReference.Int);
1055        }
1056        break;
1057
1058        case JBC_lmul: {
1059          Operand op2 = popLong();
1060          Operand op1 = popLong();
1061          s = _binaryDualHelper(LONG_MUL, op1, op2, TypeReference.Long);
1062        }
1063        break;
1064
1065        case JBC_fmul: {
1066          Operand op2 = popFloat();
1067          Operand op1 = popFloat();
1068          s = _binaryHelper(FLOAT_MUL, op1, op2, TypeReference.Float);
1069        }
1070        break;
1071
1072        case JBC_dmul: {
1073          Operand op2 = popDouble();
1074          Operand op1 = popDouble();
1075          s = _binaryDualHelper(DOUBLE_MUL, op1, op2, TypeReference.Double);
1076        }
1077        break;
1078
1079        case JBC_idiv: {
1080          clearCurrentGuard();
1081          Operand op2 = popInt();
1082          Operand op1 = popInt();
1083          if (do_IntZeroCheck(op2)) {
1084            break;
1085          }
1086          s = _guardedBinaryHelper(INT_DIV, op1, op2, getCurrentGuard(), TypeReference.Int);
1087        }
1088        break;
1089
1090        case JBC_ldiv: {
1091          clearCurrentGuard();
1092          Operand op2 = popLong();
1093          Operand op1 = popLong();
1094          if (do_LongZeroCheck(op2)) {
1095            break;
1096          }
1097          s = _guardedBinaryDualHelper(LONG_DIV, op1, op2, getCurrentGuard(), TypeReference.Long);
1098        }
1099        break;
1100
1101        case JBC_fdiv: {
1102          Operand op2 = popFloat();
1103          Operand op1 = popFloat();
1104          s = _binaryHelper(FLOAT_DIV, op1, op2, TypeReference.Float);
1105        }
1106        break;
1107
1108        case JBC_ddiv: {
1109          Operand op2 = popDouble();
1110          Operand op1 = popDouble();
1111          s = _binaryDualHelper(DOUBLE_DIV, op1, op2, TypeReference.Double);
1112        }
1113        break;
1114
1115        case JBC_irem: {
1116          clearCurrentGuard();
1117          Operand op2 = popInt();
1118          Operand op1 = popInt();
1119          if (do_IntZeroCheck(op2)) {
1120            break;
1121          }
1122          s = _guardedBinaryHelper(INT_REM, op1, op2, getCurrentGuard(), TypeReference.Int);
1123        }
1124        break;
1125
1126        case JBC_lrem: {
1127          clearCurrentGuard();
1128          Operand op2 = popLong();
1129          Operand op1 = popLong();
1130          if (do_LongZeroCheck(op2)) {
1131            break;
1132          }
1133          s = _guardedBinaryDualHelper(LONG_REM, op1, op2, getCurrentGuard(), TypeReference.Long);
1134        }
1135        break;
1136
1137        case JBC_frem: {
1138          Operand op2 = popFloat();
1139          Operand op1 = popFloat();
1140          s = _binaryHelper(FLOAT_REM, op1, op2, TypeReference.Float);
1141        }
1142        break;
1143
1144        case JBC_drem: {
1145          Operand op2 = popDouble();
1146          Operand op1 = popDouble();
1147          s = _binaryDualHelper(DOUBLE_REM, op1, op2, TypeReference.Double);
1148        }
1149        break;
1150
1151        case JBC_ineg:
1152          s = _unaryHelper(INT_NEG, popInt(), TypeReference.Int);
1153          break;
1154
1155        case JBC_lneg:
1156          s = _unaryDualHelper(LONG_NEG, popLong(), TypeReference.Long);
1157          break;
1158
1159        case JBC_fneg:
1160          s = _unaryHelper(FLOAT_NEG, popFloat(), TypeReference.Float);
1161          break;
1162
1163        case JBC_dneg:
1164          s = _unaryDualHelper(DOUBLE_NEG, popDouble(), TypeReference.Double);
1165          break;
1166
1167        case JBC_ishl: {
1168          Operand op2 = popShiftInt(false);
1169          Operand op1 = popInt();
1170          s = _binaryHelper(INT_SHL, op1, op2, TypeReference.Int);
1171        }
1172        break;
1173
1174        case JBC_lshl: {
1175          Operand op2 = popShiftInt(true);
1176          Operand op1 = popLong();
1177          s = _binaryDualHelper(LONG_SHL, op1, op2, TypeReference.Long);
1178        }
1179        break;
1180
1181        case JBC_ishr: {
1182          Operand op2 = popShiftInt(false);
1183          Operand op1 = popInt();
1184          s = _binaryHelper(INT_SHR, op1, op2, TypeReference.Int);
1185        }
1186        break;
1187
1188        case JBC_lshr: {
1189          Operand op2 = popShiftInt(true);
1190          Operand op1 = popLong();
1191          s = _binaryDualHelper(LONG_SHR, op1, op2, TypeReference.Long);
1192        }
1193        break;
1194
1195        case JBC_iushr: {
1196          Operand op2 = popShiftInt(false);
1197          Operand op1 = popInt();
1198          s = _binaryHelper(INT_USHR, op1, op2, TypeReference.Int);
1199        }
1200        break;
1201
1202        case JBC_lushr: {
1203          Operand op2 = popShiftInt(true);
1204          Operand op1 = popLong();
1205          s = _binaryDualHelper(LONG_USHR, op1, op2, TypeReference.Long);
1206        }
1207        break;
1208
1209        case JBC_iand: {
1210          Operand op2 = popInt();
1211          Operand op1 = popInt();
1212          s = _binaryHelper(INT_AND, op1, op2, TypeReference.Int);
1213        }
1214        break;
1215
1216        case JBC_land: {
1217          Operand op2 = popLong();
1218          Operand op1 = popLong();
1219          s = _binaryDualHelper(LONG_AND, op1, op2, TypeReference.Long);
1220        }
1221        break;
1222
1223        case JBC_ior: {
1224          Operand op2 = popInt();
1225          Operand op1 = popInt();
1226          s = _binaryHelper(INT_OR, op1, op2, TypeReference.Int);
1227        }
1228        break;
1229
1230        case JBC_lor: {
1231          Operand op2 = popLong();
1232          Operand op1 = popLong();
1233          s = _binaryDualHelper(LONG_OR, op1, op2, TypeReference.Long);
1234        }
1235        break;
1236
1237        case JBC_ixor: {
1238          Operand op2 = popInt();
1239          Operand op1 = popInt();
1240          s = _binaryHelper(INT_XOR, op1, op2, TypeReference.Int);
1241        }
1242        break;
1243
1244        case JBC_lxor: {
1245          Operand op2 = popLong();
1246          Operand op1 = popLong();
1247          s = _binaryDualHelper(LONG_XOR, op1, op2, TypeReference.Long);
1248        }
1249        break;
1250
1251        case JBC_iinc: {
1252          int index = bcodes.getLocalNumber();
1253          s = do_iinc(index, bcodes.getIncrement());
1254        }
1255        break;
1256
1257        case JBC_i2l:
1258          s = _unaryDualHelper(INT_2LONG, popInt(), TypeReference.Long);
1259          break;
1260
1261        case JBC_i2f:
1262          s = _unaryHelper(INT_2FLOAT, popInt(), TypeReference.Float);
1263          break;
1264
1265        case JBC_i2d:
1266          s = _unaryDualHelper(INT_2DOUBLE, popInt(), TypeReference.Double);
1267          break;
1268
1269        case JBC_l2i:
1270          s = _unaryHelper(LONG_2INT, popLong(), TypeReference.Int);
1271          break;
1272
1273        case JBC_l2f:
1274          s = _unaryHelper(LONG_2FLOAT, popLong(), TypeReference.Float);
1275          break;
1276
1277        case JBC_l2d:
1278          s = _unaryDualHelper(LONG_2DOUBLE, popLong(), TypeReference.Double);
1279          break;
1280
1281        case JBC_f2i:
1282          s = _unaryHelper(FLOAT_2INT, popFloat(), TypeReference.Int);
1283          break;
1284
1285        case JBC_f2l:
1286          s = _unaryDualHelper(FLOAT_2LONG, popFloat(), TypeReference.Long);
1287          break;
1288
1289        case JBC_f2d:
1290          s = _unaryDualHelper(FLOAT_2DOUBLE, popFloat(), TypeReference.Double);
1291          break;
1292
1293        case JBC_d2i:
1294          s = _unaryHelper(DOUBLE_2INT, popDouble(), TypeReference.Int);
1295          break;
1296
1297        case JBC_d2l:
1298          s = _unaryDualHelper(DOUBLE_2LONG, popDouble(), TypeReference.Long);
1299          break;
1300
1301        case JBC_d2f:
1302          s = _unaryHelper(DOUBLE_2FLOAT, popDouble(), TypeReference.Float);
1303          break;
1304
1305        case JBC_int2byte:
1306          s = _unaryHelper(INT_2BYTE, popInt(), TypeReference.Byte);
1307          break;
1308
1309        case JBC_int2char:
1310          s = _unaryHelper(INT_2USHORT, popInt(), TypeReference.Char);
1311          break;
1312
1313        case JBC_int2short:
1314          s = _unaryHelper(INT_2SHORT, popInt(), TypeReference.Short);
1315          break;
1316
1317        case JBC_lcmp: {
1318          Operand op2 = popLong();
1319          Operand op1 = popLong();
1320          s = _binaryHelper(LONG_CMP, op1, op2, TypeReference.Int);
1321        }
1322        break;
1323
1324        case JBC_fcmpl: {
1325          Operand op2 = popFloat();
1326          Operand op1 = popFloat();
1327          s = _binaryHelper(FLOAT_CMPL, op1, op2, TypeReference.Int);
1328        }
1329        break;
1330
1331        case JBC_fcmpg: {
1332          Operand op2 = popFloat();
1333          Operand op1 = popFloat();
1334          s = _binaryHelper(FLOAT_CMPG, op1, op2, TypeReference.Int);
1335        }
1336        break;
1337
1338        case JBC_dcmpl: {
1339          Operand op2 = popDouble();
1340          Operand op1 = popDouble();
1341          s = _binaryHelper(DOUBLE_CMPL, op1, op2, TypeReference.Int);
1342        }
1343        break;
1344
1345        case JBC_dcmpg: {
1346          Operand op2 = popDouble();
1347          Operand op1 = popDouble();
1348          s = _binaryHelper(DOUBLE_CMPG, op1, op2, TypeReference.Int);
1349        }
1350        break;
1351
1352        case JBC_ifeq:
1353          s = _intIfHelper(ConditionOperand.EQUAL());
1354          break;
1355
1356        case JBC_ifne:
1357          s = _intIfHelper(ConditionOperand.NOT_EQUAL());
1358          break;
1359
1360        case JBC_iflt:
1361          s = _intIfHelper(ConditionOperand.LESS());
1362          break;
1363
1364        case JBC_ifge:
1365          s = _intIfHelper(ConditionOperand.GREATER_EQUAL());
1366          break;
1367
1368        case JBC_ifgt:
1369          s = _intIfHelper(ConditionOperand.GREATER());
1370          break;
1371
1372        case JBC_ifle:
1373          s = _intIfHelper(ConditionOperand.LESS_EQUAL());
1374          break;
1375
1376        case JBC_if_icmpeq:
1377          s = _intIfCmpHelper(ConditionOperand.EQUAL());
1378          break;
1379
1380        case JBC_if_icmpne:
1381          s = _intIfCmpHelper(ConditionOperand.NOT_EQUAL());
1382          break;
1383
1384        case JBC_if_icmplt:
1385          s = _intIfCmpHelper(ConditionOperand.LESS());
1386          break;
1387
1388        case JBC_if_icmpge:
1389          s = _intIfCmpHelper(ConditionOperand.GREATER_EQUAL());
1390          break;
1391
1392        case JBC_if_icmpgt:
1393          s = _intIfCmpHelper(ConditionOperand.GREATER());
1394          break;
1395
1396        case JBC_if_icmple:
1397          s = _intIfCmpHelper(ConditionOperand.LESS_EQUAL());
1398          break;
1399
1400        case JBC_if_acmpeq:
1401          s = _refIfCmpHelper(ConditionOperand.EQUAL());
1402          break;
1403
1404        case JBC_if_acmpne:
1405          s = _refIfCmpHelper(ConditionOperand.NOT_EQUAL());
1406          break;
1407
1408        case JBC_goto: {
1409          int offset = bcodes.getBranchOffset();
1410          if (offset != 3) {
1411            // skip generating frivolous goto's
1412            s = _gotoHelper(offset);
1413          }
1414        }
1415        break;
1416
1417        case JBC_jsr:
1418          s = _jsrHelper(bcodes.getBranchOffset());
1419          break;
1420
1421        case JBC_ret:
1422          s = _retHelper(bcodes.getLocalNumber());
1423          break;
1424
1425        case JBC_tableswitch: {
1426          bcodes.alignSwitch();
1427          Operand op0 = popInt();
1428          int defaultoff = bcodes.getDefaultSwitchOffset();
1429          int low = bcodes.getLowSwitchValue();
1430          int high = bcodes.getHighSwitchValue();
1431          int number = high - low + 1;
1432          if (CF_TABLESWITCH && op0 instanceof IntConstantOperand) {
1433            int v1 = ((IntConstantOperand) op0).value;
1434            int match = bcodes.computeTableSwitchOffset(v1, low, high);
1435            int offset = match == 0 ? defaultoff : match;
1436            bcodes.skipTableSwitchOffsets(number);
1437            if (DBG_CF) {
1438              db("changed tableswitch to goto because index (" + v1 + ") is constant");
1439            }
1440            s = _gotoHelper(offset);
1441            break;
1442          }
1443          s =
1444              TableSwitch.create(TABLESWITCH,
1445                                 op0,
1446                                 null,
1447                                 null,
1448                                 new IntConstantOperand(low),
1449                                 new IntConstantOperand(high),
1450                                 generateTarget(defaultoff),
1451                                 null,
1452                                 number * 2);
1453          for (int i = 0; i < number; ++i) {
1454            TableSwitch.setTarget(s, i, generateTarget(bcodes.getTableSwitchOffset(i)));
1455          }
1456          bcodes.skipTableSwitchOffsets(number);
1457
1458          // Set branch probabilities
1459          SwitchBranchProfile sp = gc.getSwitchProfile(instrIndex - bciAdjustment);
1460          if (sp == null) {
1461            float approxProb = 1.0f / (number + 1); // number targets + default
1462            TableSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(approxProb));
1463            for (int i = 0; i < number; ++i) {
1464              TableSwitch.setBranchProfile(s, i, new BranchProfileOperand(approxProb));
1465            }
1466          } else {
1467            TableSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(sp.getDefaultProbability()));
1468            for (int i = 0; i < number; ++i) {
1469              TableSwitch.setBranchProfile(s, i, new BranchProfileOperand(sp.getCaseProbability(i)));
1470            }
1471          }
1472        }
1473        break;
1474
1475        case JBC_lookupswitch: {
1476          bcodes.alignSwitch();
1477          Operand op0 = popInt();
1478          int defaultoff = bcodes.getDefaultSwitchOffset();
1479          int numpairs = bcodes.getSwitchLength();
1480          if (numpairs == 0) {
1481            s = _gotoHelper(defaultoff);
1482            break;
1483          }
1484          if (CF_LOOKUPSWITCH && op0 instanceof IntConstantOperand) {
1485            int v1 = ((IntConstantOperand) op0).value;
1486            int match = bcodes.computeLookupSwitchOffset(v1, numpairs);
1487            int offset = match == 0 ? defaultoff : match;
1488            bcodes.skipLookupSwitchPairs(numpairs);
1489            if (DBG_CF) {
1490              db("changed lookupswitch to goto because index (" + v1 + ") is constant");
1491            }
1492            s = _gotoHelper(offset);
1493            break;
1494          }
1495
1496          // Construct switch
1497          s = LookupSwitch.create(LOOKUPSWITCH, op0, null, null, generateTarget(defaultoff), null, numpairs * 3);
1498          for (int i = 0; i < numpairs; ++i) {
1499            LookupSwitch.setMatch(s, i, new IntConstantOperand(bcodes.getLookupSwitchValue(i)));
1500            LookupSwitch.setTarget(s, i, generateTarget(bcodes.getLookupSwitchOffset(i)));
1501          }
1502          bcodes.skipLookupSwitchPairs(numpairs);
1503
1504          // Set branch probabilities
1505          SwitchBranchProfile sp = gc.getSwitchProfile(instrIndex - bciAdjustment);
1506          if (sp == null) {
1507            float approxProb = 1.0f / (numpairs + 1); // num targets + default
1508            LookupSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(approxProb));
1509            for (int i = 0; i < numpairs; ++i) {
1510              LookupSwitch.setBranchProfile(s, i, new BranchProfileOperand(approxProb));
1511            }
1512          } else {
1513            LookupSwitch.setDefaultBranchProfile(s, new BranchProfileOperand(sp.getDefaultProbability()));
1514            for (int i = 0; i < numpairs; ++i) {
1515              LookupSwitch.setBranchProfile(s, i, new BranchProfileOperand(sp.getCaseProbability(i)));
1516            }
1517          }
1518        }
1519        break;
1520
1521        case JBC_ireturn:
1522          _returnHelper(INT_MOVE, popInt());
1523          break;
1524
1525        case JBC_lreturn:
1526          _returnHelper(LONG_MOVE, popLong());
1527          break;
1528
1529        case JBC_freturn:
1530          _returnHelper(FLOAT_MOVE, popFloat());
1531          break;
1532
1533        case JBC_dreturn:
1534          _returnHelper(DOUBLE_MOVE, popDouble());
1535          break;
1536
1537        case JBC_areturn: {
1538          Operand op0 = popRef();
1539          if (VM.VerifyAssertions && !op0.isDefinitelyNull()) {
1540            TypeReference retType = op0.getType();
1541            assertIsAssignable(gc.getMethod().getReturnType(), retType);
1542          }
1543          _returnHelper(REF_MOVE, op0);
1544        }
1545        break;
1546
1547        case JBC_return:
1548          _returnHelper(null, null);
1549          break;
1550
1551        case JBC_getstatic: {
1552          // field resolution
1553          FieldReference ref = bcodes.getFieldReference();
1554          boolean unresolved = ref.needsDynamicLink(bcodes.getMethod());
1555          LocationOperand fieldOp = makeStaticFieldRef(ref);
1556          Operand offsetOp;
1557          TypeReference fieldType = ref.getFieldContentsType();
1558          RegisterOperand t = gc.getTemps().makeTemp(fieldType);
1559          if (unresolved) {
1560            RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1561            appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy()));
1562            offsetOp = offsetrop;
1563            rectifyStateWithErrorHandler();
1564          } else {
1565            RVMField field = ref.peekResolvedField();
1566            offsetOp = new AddressConstantOperand(field.getOffset());
1567
1568            // use results of field analysis to refine type of result
1569            RVMType ft = fieldType.peekType();
1570            if (ft != null && ft.isClassType()) {
1571              TypeReference concreteType = FieldAnalysis.getConcreteType(field);
1572              if (concreteType != null) {
1573                if (concreteType == fieldType) {
1574                  t.setDeclaredType();
1575                  t.setPreciseType();
1576                } else {
1577                  fieldType = concreteType;
1578                  t.setPreciseType(concreteType);
1579                }
1580              }
1581            }
1582
1583            // optimization: if the field is final and either
1584            // initialized or we're writing the bootimage and the field
1585            // is from a suitable class, then get the value at compile
1586            // time.
1587            if (gc.getOptions().SIMPLIFY_CHASE_FINAL_FIELDS && field.isFinal()) {
1588              RVMClass declaringClass = field.getDeclaringClass();
1589
1590              boolean initializedClassAtRuntime = VM.runningVM & declaringClass.isInitialized();
1591              boolean fieldFromRVMInternalClassInBootImage = declaringClass.isInBootImage() &&
1592                  declaringClass.getDescriptor().isRVMDescriptor();
1593              // We cannot assume that non-public fields from the host JVM's class library are present in
1594              // the class library used by Jikes RVM: only public fields are part of the API.
1595              boolean publicFieldInBootImage = declaringClass.isInBootImage() &&
1596                  field.isPublic();
1597
1598              if (initializedClassAtRuntime || fieldFromRVMInternalClassInBootImage ||
1599                  publicFieldInBootImage) {
1600                try {
1601                  ConstantOperand rhs = StaticFieldReader.getStaticFieldValue(field);
1602                  // VM.sysWrite("Replaced getstatic of "+field+" with "+rhs+"\n");
1603                  push(rhs, fieldType);
1604                  break;
1605                } catch (NoSuchFieldException e) {
1606                  if (VM.runningVM) {
1607                    throw new Error("Unexpected exception", e);
1608                  } else {
1609                    // Field not found during bootstrap due to chasing a field
1610                    // only valid in the bootstrap JVM.
1611
1612                    // Although we try to avoid most cases where this could happen, we cannot
1613                    // avoid all. For example, a NoSuchFieldException can occur when we're trying
1614                    // to optimize a public field from Jikes RVM's class library that's not present
1615                    // in the host JVM's class library (example: a field from an internal
1616                    // helper class).
1617                  }
1618                }
1619              }
1620            } else if (field.isRuntimeFinal()) {
1621              if (VM.VerifyAssertions) opt_assert(fieldType.isBooleanType());
1622              boolean rhsBool = field.getRuntimeFinalValue();
1623              push(new IntConstantOperand(rhsBool ? 1 : 0));
1624              break;
1625            }
1626          }
1627
1628          s = GetStatic.create(GETSTATIC, t, offsetOp, fieldOp);
1629          if (fieldOp.mayBeVolatile()) {
1630              appendInstruction(s);
1631              s = Empty.create(READ_CEILING);
1632          }
1633
1634          push(t.copyD2U(), fieldType);
1635        }
1636        break;
1637
1638        case JBC_putstatic: {
1639          // field resolution
1640          FieldReference ref = bcodes.getFieldReference();
1641          boolean unresolved = ref.needsDynamicLink(bcodes.getMethod());
1642          LocationOperand fieldOp = makeStaticFieldRef(ref);
1643          Operand offsetOp;
1644          if (unresolved) {
1645            RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1646            appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy()));
1647            offsetOp = offsetrop;
1648            rectifyStateWithErrorHandler();
1649          } else {
1650            RVMField field = ref.peekResolvedField();
1651            offsetOp = new AddressConstantOperand(field.getOffset());
1652          }
1653
1654          TypeReference fieldType = ref.getFieldContentsType();
1655          Operand r = pop(fieldType);
1656          if (fieldOp.mayBeVolatile()) {
1657              appendInstruction(Empty.create(WRITE_FLOOR));
1658          }
1659          s = PutStatic.create(PUTSTATIC, r, offsetOp, fieldOp);
1660          if (fieldOp.mayBeVolatile()) {
1661            appendInstruction(s);
1662            s = Empty.create(FENCE);
1663          }
1664        }
1665        break;
1666
1667        case JBC_getfield: {
1668          // field resolution
1669          FieldReference ref = bcodes.getFieldReference();
1670          boolean unresolved = ref.needsDynamicLink(bcodes.getMethod());
1671          LocationOperand fieldOp = makeInstanceFieldRef(ref);
1672          Operand offsetOp;
1673          TypeReference fieldType = ref.getFieldContentsType();
1674          RVMField field = null;
1675          RegisterOperand t = gc.getTemps().makeTemp(fieldType);
1676          if (unresolved) {
1677            RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1678            appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy()));
1679            offsetOp = offsetrop;
1680            rectifyStateWithErrorHandler();
1681          } else {
1682            field = ref.peekResolvedField();
1683            offsetOp = new AddressConstantOperand(field.getOffset());
1684
1685            // use results of field analysis to refine type.
1686            RVMType ft = fieldType.peekType();
1687            if (ft != null && ft.isClassType()) {
1688              TypeReference concreteType = FieldAnalysis.getConcreteType(field);
1689              if (concreteType != null) {
1690                if (concreteType == fieldType) {
1691                  t.setDeclaredType();
1692                  t.setPreciseType();
1693                } else {
1694                  fieldType = concreteType;
1695                  t.setType(concreteType);
1696                  t.setPreciseType();
1697                }
1698              }
1699            }
1700          }
1701
1702          Operand op1 = pop();
1703          clearCurrentGuard();
1704          if (do_NullCheck(op1)) {
1705            break;
1706          }
1707
1708          // optimization: if the field is final and referenced by a
1709          // constant reference then get the value at compile time.
1710          // NB avoid String fields
1711          if (op1.isConstant() && field.isFinal()) {
1712            try {
1713              ConstantOperand rhs =
1714                  StaticFieldReader.getFieldValueAsConstant(field, op1.asObjectConstant().value);
1715              push(rhs, fieldType);
1716              break;
1717            } catch (NoSuchFieldException e) {
1718              if (VM.runningVM) { // this is unexpected
1719                throw new Error("Unexpected exception", e);
1720              } else {
1721                // Field not found during bootstrap due to chasing a field
1722                // only valid in the bootstrap JVM
1723              }
1724            }
1725          }
1726
1727          s = GetField.create(GETFIELD, t, op1, offsetOp, fieldOp, getCurrentGuard());
1728          if (fieldOp.mayBeVolatile()) {
1729              appendInstruction(s);
1730              s = Empty.create(READ_CEILING);
1731          }
1732
1733          push(t.copyD2U(), fieldType);
1734        }
1735        break;
1736
1737        case JBC_putfield: {
1738          // field resolution
1739          FieldReference ref = bcodes.getFieldReference();
1740          boolean unresolved = ref.needsDynamicLink(bcodes.getMethod());
1741          LocationOperand fieldOp = makeInstanceFieldRef(ref);
1742          TypeReference fieldType = ref.getFieldContentsType();
1743          Operand offsetOp;
1744          if (unresolved) {
1745            RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1746            appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), fieldOp.copy()));
1747            offsetOp = offsetrop;
1748            rectifyStateWithErrorHandler();
1749          } else {
1750            RVMField field = ref.peekResolvedField();
1751            offsetOp = new AddressConstantOperand(field.getOffset());
1752          }
1753
1754          Operand val = pop(fieldType);
1755          Operand obj = popRef();
1756          clearCurrentGuard();
1757          if (do_NullCheck(obj)) {
1758            break;
1759          }
1760
1761          if (fieldOp.mayBeVolatile()) {
1762              appendInstruction(Empty.create(WRITE_FLOOR));
1763          }
1764          s = PutField.create(PUTFIELD, val, obj, offsetOp, fieldOp, getCurrentGuard());
1765          if (fieldOp.mayBeVolatile()) {
1766            appendInstruction(s);
1767            s = Empty.create(FENCE);
1768          }
1769        }
1770        break;
1771
1772        case JBC_invokevirtual: {
1773          MethodReference ref = bcodes.getMethodReference();
1774
1775          // See if this is a magic method (Address, Word, etc.)
1776          // If it is, generate the inline code and we are done.
1777          if (ref.isMagic()) {
1778            boolean generated = GenerateMagic.generateMagic(this, gc, ref);
1779            if (generated) break; // all done.
1780          }
1781
1782          /* just create an osr barrier right before _callHelper
1783           * changes the states of locals and stacks.
1784           */
1785          if (this.osrGuardedInline) {
1786            lastOsrBarrier = _createOsrBarrier();
1787          }
1788
1789          if (ref.isMiranda()) {
1790            // An invokevirtual that is really an invokeinterface.
1791            s = _callHelper(ref, MethodOperand.INTERFACE(ref, null));
1792            if (s == null)
1793              break;
1794            Operand receiver = Call.getParam(s, 0);
1795            RVMClass receiverType = (RVMClass) receiver.getType().peekType();
1796            // null check on this parameter of call
1797            clearCurrentGuard();
1798            if (do_NullCheck(receiver)) {
1799              // call will always raise null pointer exception
1800              s = null;
1801              break;
1802            }
1803            Call.setGuard(s, getCurrentGuard());
1804
1805            // Attempt to resolve the interface call to a particular virtual method.
1806            // This is independent of whether or not the static type of the receiver is
1807            // known to implement the interface and it is not that case that being able
1808            // to prove one implies the other.
1809            RVMMethod vmeth = null;
1810            if (receiverType != null && receiverType.isInitialized() && !receiverType.isInterface()) {
1811              vmeth = ClassLoaderProxy.lookupMethod(receiverType, ref);
1812            }
1813            if (vmeth != null) {
1814              MethodReference vmethRef = vmeth.getMemberRef().asMethodReference();
1815              MethodOperand mop = MethodOperand.VIRTUAL(vmethRef, vmeth);
1816              if (receiver.isConstant() || (receiver.isRegister() && receiver.asRegister().isPreciseType())) {
1817                mop.refine(vmeth, true);
1818              }
1819              Call.setMethod(s, mop);
1820              boolean unresolved = vmethRef.needsDynamicLink(bcodes.getMethod());
1821              if (unresolved) {
1822                RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1823                appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy()));
1824                Call.setAddress(s, offsetrop);
1825                rectifyStateWithErrorHandler();
1826              } else {
1827                Call.setAddress(s, new AddressConstantOperand(vmeth.getOffset()));
1828              }
1829
1830              // Attempt to inline virtualized call.
1831              if (maybeInlineMethod(shouldInline(s,
1832                                                 receiver.isConstant() ||
1833                                                 (receiver.isRegister() && receiver.asRegister().isExtant()),
1834                                                 instrIndex - bciAdjustment), s)) {
1835                return;
1836              }
1837            }
1838
1839          } else {
1840            // A normal invokevirtual.  Create call instruction.
1841            boolean unresolved = ref.needsDynamicLink(bcodes.getMethod());
1842            RVMMethod target = ref.peekResolvedMethod();
1843            MethodOperand methOp = MethodOperand.VIRTUAL(ref, target);
1844
1845            s = _callHelper(ref, methOp);
1846            if (s == null)
1847              break;
1848
1849            // Handle possibility of dynamic linking.
1850            // Must be done before null_check!
1851            if (unresolved) {
1852              RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1853              appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy()));
1854              Call.setAddress(s, offsetrop);
1855              rectifyStateWithErrorHandler();
1856            } else {
1857              if (VM.VerifyAssertions) opt_assert(target != null);
1858              Call.setAddress(s, new AddressConstantOperand(target.getOffset()));
1859            }
1860
1861            // null check receiver
1862            Operand receiver = Call.getParam(s, 0);
1863            clearCurrentGuard();
1864            if (do_NullCheck(receiver)) {
1865              // call will always raise null pointer exception
1866              s = null;
1867              break;
1868            }
1869            Call.setGuard(s, getCurrentGuard());
1870
1871            // Use compile time type of receiver to try reduce the number
1872            // of targets.
1873            // If we succeed, we'll update meth and s's method operand.
1874            boolean isExtant = false;
1875            boolean isPreciseType = false;
1876            TypeReference tr = null;
1877            if (receiver.isRegister()) {
1878              RegisterOperand rop = receiver.asRegister();
1879              isExtant = rop.isExtant();
1880              isPreciseType = rop.isPreciseType();
1881              tr = rop.getType();
1882            } else {
1883              isExtant = true;
1884              isPreciseType = true;
1885              tr = receiver.getType();
1886            }
1887            RVMType type = tr.peekType();
1888            if (type != null && type.isResolved()) {
1889              if (type.isClassType()) {
1890                RVMMethod vmeth = target;
1891                if (target == null || type != target.getDeclaringClass()) {
1892                  vmeth = ClassLoaderProxy.lookupMethod(type.asClass(), ref);
1893                }
1894                if (vmeth != null) {
1895                  methOp.refine(vmeth, isPreciseType || type.asClass().isFinal());
1896                }
1897              } else {
1898                // Array: will always be calling the method defined in java.lang.Object
1899                if (VM.VerifyAssertions) opt_assert(target != null, "Huh?  Target method must already be resolved if receiver is array");
1900                methOp.refine(target, true);
1901              }
1902            }
1903
1904            // Consider inlining it.
1905            if (maybeInlineMethod(shouldInline(s, isExtant, instrIndex - bciAdjustment), s)) {
1906              return;
1907            }
1908          }
1909
1910          // noninlined CALL must be treated as potential throw of anything
1911          rectifyStateWithExceptionHandlers();
1912        }
1913        break;
1914
1915        case JBC_invokespecial: {
1916          MethodReference ref = bcodes.getMethodReference();
1917          RVMMethod target = ref.resolveInvokeSpecial();
1918
1919          /* just create an osr barrier right before _callHelper
1920           * changes the states of locals and stacks.
1921           */
1922          if (this.osrGuardedInline) {
1923            lastOsrBarrier = _createOsrBarrier();
1924          }
1925
1926          s = _callHelper(ref, MethodOperand.SPECIAL(ref, target));
1927          if (s == null)
1928            break;
1929
1930          // Handle possibility of dynamic linking. Must be done before null_check!
1931          // NOTE: different definition of unresolved due to semantics of invokespecial.
1932          if (target == null) {
1933            RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1934            appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy()));
1935            Call.setAddress(s, offsetrop);
1936            rectifyStateWithErrorHandler();
1937          } else {
1938            Call.setAddress(s, new AddressConstantOperand(target.getOffset()));
1939          }
1940
1941          // null check receiver
1942          Operand receiver = Call.getParam(s, 0);
1943          clearCurrentGuard();
1944          if (do_NullCheck(receiver)) {
1945            // call will always raise null pointer exception
1946            s = null;
1947            break;
1948          }
1949          Call.setGuard(s, getCurrentGuard());
1950
1951          // Consider inlining it.
1952          if (maybeInlineMethod(shouldInline(s, false, instrIndex - bciAdjustment), s)) {
1953            return;
1954          }
1955
1956          // noninlined CALL must be treated as potential throw of anything
1957          rectifyStateWithExceptionHandlers();
1958        }
1959        break;
1960
1961        case JBC_invokestatic: {
1962          MethodReference ref = bcodes.getMethodReference();
1963
1964          // See if this is a magic method (Magic, Address, Word, etc.)
1965          // If it is, generate the inline code and we are done.
1966          if (ref.isMagic()) {
1967            boolean generated = GenerateMagic.generateMagic(this, gc, ref);
1968            if (generated) break;
1969          }
1970
1971          // A non-magical invokestatic.  Create call instruction.
1972          boolean unresolved = ref.needsDynamicLink(bcodes.getMethod());
1973          RVMMethod target = ref.peekResolvedMethod();
1974
1975          /* just create an osr barrier right before _callHelper
1976          * changes the states of locals and stacks.
1977          */
1978          if (this.osrGuardedInline) {
1979            lastOsrBarrier = _createOsrBarrier();
1980          }
1981
1982          s = _callHelper(ref, MethodOperand.STATIC(ref, target));
1983          if (s == null)
1984            break;
1985
1986          if (Call.conforms(s)) {
1987            MethodOperand methOp = Call.getMethod(s);
1988            if (methOp.getTarget() == target) {
1989              // Handle possibility of dynamic linking.
1990              if (unresolved) {
1991                RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
1992                appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy()));
1993                Call.setAddress(s, offsetrop);
1994                rectifyStateWithErrorHandler();
1995              } else {
1996                Call.setAddress(s, new AddressConstantOperand(target.getOffset()));
1997              }
1998
1999              // Consider inlining it.
2000              if (maybeInlineMethod(shouldInline(s, false, instrIndex - bciAdjustment), s)) {
2001                return;
2002              }
2003            }
2004          }
2005          // noninlined CALL must be treated as potential throw of anything
2006          rectifyStateWithExceptionHandlers();
2007        }
2008        break;
2009
2010        case JBC_invokeinterface: {
2011          MethodReference ref = bcodes.getMethodReference();
2012          bcodes.alignInvokeInterface();
2013          RVMMethod resolvedMethod = null;
2014          resolvedMethod = ref.peekInterfaceMethod();
2015
2016          /* just create an osr barrier right before _callHelper
2017           * changes the states of locals and stacks.
2018           */
2019          if (this.osrGuardedInline) {
2020            lastOsrBarrier = _createOsrBarrier();
2021          }
2022
2023          s = _callHelper(ref, MethodOperand.INTERFACE(ref, resolvedMethod));
2024          if (s == null)
2025            break;
2026
2027          Operand receiver = Call.getParam(s, 0);
2028          RVMClass receiverType = (RVMClass) receiver.getType().peekType();
2029          boolean requiresImplementsTest = VM.BuildForIMTInterfaceInvocation;
2030
2031          // Invokeinterface requires a dynamic type check
2032          // to ensure that the receiver object actually
2033          // implements the interface.  This is necessary
2034          // because the verifier does not detect incompatible class changes.
2035          // Depending on the implementation of interface dispatching
2036          // we are using, we may have to make this test explicit
2037          // in the calling sequence if we can't prove at compile time
2038          // that it is not needed.
2039          if (requiresImplementsTest && resolvedMethod == null) {
2040            // Sigh.  Can't even resolve the reference to figure out what interface
2041            // method we are trying to call. Therefore we must make generate a call
2042            // to an out-of-line typechecking routine to handle it at runtime.
2043            RVMMethod target = Entrypoints.unresolvedInvokeinterfaceImplementsTestMethod;
2044            Instruction callCheck =
2045              Call.create2(CALL,
2046                           null,
2047                           new AddressConstantOperand(target.getOffset()),
2048                           MethodOperand.STATIC(target),
2049                           new IntConstantOperand(ref.getId()),
2050                           receiver.copy());
2051            if (gc.getOptions().H2L_NO_CALLEE_EXCEPTIONS) {
2052              callCheck.markAsNonPEI();
2053            }
2054
2055            appendInstruction(callCheck);
2056            callCheck.bcIndex = RUNTIME_SERVICES_BCI;
2057
2058            requiresImplementsTest = false; // the above call subsumes the test
2059            rectifyStateWithErrorHandler(); // Can raise incompatible class change error.
2060          }
2061
2062          // null check on this parameter of call. Must be done after dynamic linking!
2063          clearCurrentGuard();
2064          if (do_NullCheck(receiver)) {
2065            // call will always raise null pointer exception
2066            s = null;
2067            break;
2068          }
2069          Call.setGuard(s, getCurrentGuard());
2070
2071          if (requiresImplementsTest) {
2072            // We know what interface method the program wants to invoke.
2073            // Attempt to avoid inserting the type check by seeing if the
2074            // known static type of the receiver implements the desired interface.
2075            RVMType interfaceType = resolvedMethod.getDeclaringClass();
2076            if (receiverType != null && receiverType.isResolved() && !receiverType.isInterface()) {
2077              byte doesImplement =
2078                ClassLoaderProxy.includesType(interfaceType.getTypeRef(), receiverType.getTypeRef());
2079              requiresImplementsTest = doesImplement != YES;
2080            }
2081          }
2082
2083          // Attempt to resolve the interface call to a particular virtual method.
2084          // This is independent of whether or not the static type of the receiver is
2085          // known to implement the interface and it is not that case that being able
2086          // to prove one implies the other.
2087          RVMMethod vmeth = null;
2088          if (receiverType != null && receiverType.isInitialized() && !receiverType.isInterface()) {
2089            vmeth = ClassLoaderProxy.lookupMethod(receiverType, ref);
2090          }
2091          if (vmeth != null) {
2092            MethodReference vmethRef = vmeth.getMemberRef().asMethodReference();
2093            // We're going to virtualize the call.  Must inject the
2094            // DTC to ensure the receiver implements the interface if
2095            // requiresImplementsTest is still true.
2096            // Note that at this point requiresImplementsTest => resolvedMethod != null
2097            if (requiresImplementsTest) {
2098              RegisterOperand checkedReceiver = gc.getTemps().makeTemp(receiver);
2099              appendInstruction(TypeCheck.create(MUST_IMPLEMENT_INTERFACE,
2100                  checkedReceiver,
2101                  receiver.copy(),
2102                  makeTypeOperand(resolvedMethod.getDeclaringClass()),
2103                  getCurrentGuard()));
2104              checkedReceiver.refine(resolvedMethod.getDeclaringClass().getTypeRef());
2105              Call.setParam(s, 0, checkedReceiver.copyRO());
2106              receiver = checkedReceiver;
2107              rectifyStateWithErrorHandler(); // Can raise incompatible class change error.
2108            }
2109            MethodOperand mop = MethodOperand.VIRTUAL(vmethRef, vmeth);
2110            if (receiver.isConstant() || receiver.asRegister().isPreciseType()) {
2111              mop.refine(vmeth, true);
2112            }
2113            Call.setMethod(s, mop);
2114            boolean unresolved = vmethRef.needsDynamicLink(bcodes.getMethod());
2115            if (unresolved) {
2116              RegisterOperand offsetrop = gc.getTemps().makeTempOffset();
2117              appendInstruction(Unary.create(RESOLVE_MEMBER, offsetrop.copyRO(), Call.getMethod(s).copy()));
2118              Call.setAddress(s, offsetrop);
2119              rectifyStateWithErrorHandler();
2120            } else {
2121              Call.setAddress(s, new AddressConstantOperand(vmeth.getOffset()));
2122            }
2123
2124            // Attempt to inline virtualized call.
2125            if (maybeInlineMethod(shouldInline(s,
2126                receiver.isConstant() || receiver.asRegister().isExtant(),
2127                instrIndex - bciAdjustment), s)) {
2128              return;
2129            }
2130          } else {
2131            // We can't virtualize the call;
2132            // try to inline a predicted target for the interface invocation
2133            // inline code will include DTC to ensure receiver implements the interface.
2134            if (resolvedMethod != null &&
2135                maybeInlineMethod(shouldInline(s, false, instrIndex - bciAdjustment), s)) {
2136              return;
2137            } else {
2138              if (requiresImplementsTest) {
2139                RegisterOperand checkedReceiver = gc.getTemps().makeTemp(receiver);
2140                appendInstruction(TypeCheck.create(MUST_IMPLEMENT_INTERFACE,
2141                    checkedReceiver,
2142                    receiver.copy(),
2143                    makeTypeOperand(resolvedMethod.getDeclaringClass()),
2144                    getCurrentGuard()));
2145                checkedReceiver.refine(resolvedMethod.getDeclaringClass().getTypeRef());
2146                Call.setParam(s, 0, checkedReceiver.copyRO());
2147                // don't have to rectify with error handlers; rectify call below subsumes.
2148              }
2149            }
2150          }
2151
2152          // CALL must be treated as potential throw of anything
2153          rectifyStateWithExceptionHandlers();
2154        }
2155        break;
2156
2157        case JBC_invokedynamic:
2158          OptimizingCompilerException.UNREACHABLE();
2159          break;
2160
2161        case JBC_new: {
2162          TypeReference klass = bcodes.getTypeReference();
2163          RegisterOperand t = gc.getTemps().makeTemp(klass);
2164          t.setPreciseType();
2165          markGuardlessNonNull(t);
2166          Operator operator;
2167          TypeOperand klassOp;
2168          RVMClass klassType = (RVMClass) klass.peekType();
2169          if (klassType != null && (klassType.isInitialized() || klassType.isInBootImage())) {
2170            klassOp = makeTypeOperand(klassType);
2171            operator = NEW;
2172            t.setExtant();
2173          } else {
2174            operator = NEW_UNRESOLVED;
2175            klassOp = makeTypeOperand(klass);
2176          }
2177          s = New.create(operator, t, klassOp);
2178          push(t.copyD2U());
2179          rectifyStateWithErrorHandler();
2180        }
2181        break;
2182
2183        case JBC_newarray: {
2184          RVMType array = bcodes.getPrimitiveArrayType();
2185          TypeOperand arrayOp = makeTypeOperand(array);
2186          RegisterOperand t = gc.getTemps().makeTemp(array.getTypeRef());
2187          t.setPreciseType();
2188          t.setExtant();
2189          markGuardlessNonNull(t);
2190          s = NewArray.create(NEWARRAY, t, arrayOp, popInt());
2191          push(t.copyD2U());
2192          rectifyStateWithExceptionHandler(TypeReference.JavaLangNegativeArraySizeException);
2193        }
2194        break;
2195
2196        case JBC_anewarray: {
2197          TypeReference elementTypeRef = bcodes.getTypeReference();
2198          s = generateAnewarray(null, elementTypeRef);
2199        }
2200        break;
2201
2202        case JBC_arraylength: {
2203          Operand op1 = pop();
2204          clearCurrentGuard();
2205          if (do_NullCheck(op1)) {
2206            break;
2207          }
2208          if (VM.VerifyAssertions) {
2209            opt_assert(getArrayTypeOf(op1).isArrayType());
2210          }
2211          RegisterOperand t = gc.getTemps().makeTempInt();
2212          s = GuardedUnary.create(ARRAYLENGTH, t, op1, getCurrentGuard());
2213          push(t.copyD2U());
2214        }
2215        break;
2216
2217        case JBC_athrow: {
2218          Operand op0 = pop();
2219          clearCurrentGuard();
2220          if (do_NullCheck(op0)) {
2221            break;
2222          }
2223          TypeReference type = getRefTypeOf(op0);
2224          if (VM.VerifyAssertions) assertIsAssignable(TypeReference.JavaLangThrowable, type);
2225          if (!gc.getMethod().isInterruptible()) {
2226            // prevent code motion in or out of uninterruptible code sequence
2227            appendInstruction(Empty.create(UNINT_END));
2228          }
2229          endOfBasicBlock = true;
2230          BasicBlock definiteTarget = rectifyStateWithExceptionHandler(type, true);
2231          if (definiteTarget != null) {
2232            appendInstruction(CacheOp.create(SET_CAUGHT_EXCEPTION, op0));
2233            s = Goto.create(GOTO, definiteTarget.makeJumpTarget());
2234            definiteTarget.setExceptionHandlerWithNormalIn();
2235          } else {
2236            s = Athrow.create(ATHROW, op0);
2237          }
2238        }
2239        break;
2240
2241        case JBC_checkcast: {
2242          TypeReference typeRef = bcodes.getTypeReference();
2243          boolean classLoading = couldCauseClassLoading(typeRef);
2244          Operand op2 = pop();
2245          if (typeRef.isWordLikeType()) {
2246            op2 = op2.copy();
2247            if (op2 instanceof RegisterOperand) {
2248              ((RegisterOperand) op2).setType(typeRef);
2249            }
2250            push(op2);
2251            if (DBG_CF) db("skipped gen of checkcast to word type " + typeRef);
2252            break;
2253          }
2254          if (VM.VerifyAssertions) opt_assert(op2.isRef());
2255          if (CF_CHECKCAST && !classLoading) {
2256            if (op2.isDefinitelyNull()) {
2257              push(op2);
2258              if (DBG_CF) db("skipped gen of null checkcast");
2259              break;
2260            }
2261            TypeReference type = getRefTypeOf(op2);  // non-null, null case above
2262            byte typeTestResult = ClassLoaderProxy.includesType(typeRef, type);
2263            if (typeTestResult == YES) {
2264              push(op2);
2265              if (DBG_CF) {
2266                db("skipped gen of checkcast of " + op2 + " from " + typeRef + " to " + type);
2267              }
2268              break;
2269            }
2270            if (typeTestResult == NO) {
2271              if (isNonNull(op2)) {
2272                // Definite class cast exception
2273                endOfBasicBlock = true;
2274                appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.CheckCast()));
2275                rectifyStateWithExceptionHandler(TypeReference.JavaLangClassCastException);
2276                if (DBG_CF) db("Converted checkcast into unconditional trap");
2277                break;
2278              } else {
2279                // At runtime either it is null and the checkcast succeeds or it is non-null
2280                // and a class cast exception is raised
2281                RegisterOperand refinedOp2 = gc.getTemps().makeTemp(op2);
2282                s = TypeCheck.create(CHECKCAST, refinedOp2, op2.copy(), makeTypeOperand(typeRef.peekType()));
2283                refinedOp2.refine(TypeReference.NULL_TYPE);
2284                push(refinedOp2.copyRO());
2285                rectifyStateWithExceptionHandler(TypeReference.JavaLangClassCastException);
2286                if (DBG_CF) db("Narrowed type downstream of checkcast to NULL");
2287                break;
2288              }
2289            }
2290          }
2291
2292          RegisterOperand refinedOp2 = gc.getTemps().makeTemp(op2);
2293          if (classLoading) {
2294            s = TypeCheck.create(CHECKCAST_UNRESOLVED, refinedOp2, op2.copy(), makeTypeOperand(typeRef));
2295          } else {
2296            TypeOperand typeOp = makeTypeOperand(typeRef.peekType());
2297            if (isNonNull(op2)) {
2298              s = TypeCheck.create(CHECKCAST_NOTNULL, refinedOp2, op2.copy(), typeOp, copyGuardFromOperand(op2));
2299            } else {
2300              s = TypeCheck.create(CHECKCAST, refinedOp2, op2.copy(), typeOp);
2301            }
2302          }
2303          refinedOp2.refine(typeRef);
2304          push(refinedOp2.copyRO());
2305          rectifyStateWithExceptionHandler(TypeReference.JavaLangClassCastException);
2306          if (classLoading) rectifyStateWithErrorHandler();
2307        }
2308        break;
2309
2310        case JBC_instanceof: {
2311          TypeReference typeRef = bcodes.getTypeReference();
2312          boolean classLoading = couldCauseClassLoading(typeRef);
2313          Operand op2 = pop();
2314          if (VM.VerifyAssertions) opt_assert(op2.isRef());
2315          if (CF_INSTANCEOF && !classLoading) {
2316            if (op2.isDefinitelyNull()) {
2317              push(new IntConstantOperand(0));
2318              if (DBG_CF) db("skipped gen of null instanceof");
2319              break;
2320            }
2321            TypeReference type = getRefTypeOf(op2);                 // non-null
2322            int answer = ClassLoaderProxy.includesType(typeRef, type);
2323            if (answer == YES && isNonNull(op2)) {
2324              push(new IntConstantOperand(1));
2325              if (DBG_CF) {
2326                db(op2 + " instanceof " + typeRef + " is always true ");
2327              }
2328              break;
2329            } else if (answer == NO) {
2330              if (DBG_CF) {
2331                db(op2 + " instanceof " + typeRef + " is always false ");
2332              }
2333              push(new IntConstantOperand(0));
2334              break;
2335            }
2336          }
2337
2338          RegisterOperand t = gc.getTemps().makeTempInt();
2339          if (classLoading) {
2340            s = InstanceOf.create(INSTANCEOF_UNRESOLVED, t, makeTypeOperand(typeRef), op2);
2341          } else {
2342            TypeOperand typeOp = makeTypeOperand(typeRef.peekType());
2343            if (isNonNull(op2)) {
2344              s = InstanceOf.create(INSTANCEOF_NOTNULL, t, typeOp, op2, copyGuardFromOperand(op2));
2345            } else {
2346              s = InstanceOf.create(INSTANCEOF, t, typeOp, op2);
2347            }
2348          }
2349
2350          push(t.copyD2U());
2351          if (classLoading) rectifyStateWithErrorHandler();
2352        }
2353        break;
2354
2355        case JBC_monitorenter: {
2356          Operand op0 = pop();
2357          clearCurrentGuard();
2358          if (do_NullCheck(op0)) {
2359            break;
2360          }
2361          if (VM.VerifyAssertions) opt_assert(op0.isRef());
2362          s = MonitorOp.create(MONITORENTER, op0, getCurrentGuard());
2363        }
2364        break;
2365
2366        case JBC_monitorexit: {
2367          Operand op0 = pop();
2368          clearCurrentGuard();
2369          if (do_NullCheck(op0)) {
2370            break;
2371          }
2372          s = MonitorOp.create(MONITOREXIT, op0, getCurrentGuard());
2373          rectifyStateWithExceptionHandler(TypeReference.JavaLangIllegalMonitorStateException);
2374        }
2375        break;
2376
2377        case JBC_wide: {
2378          int widecode = bcodes.getWideOpcode();
2379          int index = bcodes.getWideLocalNumber();
2380          switch (widecode) {
2381            case JBC_iload:
2382              s = do_iload(index);
2383              break;
2384
2385            case JBC_lload:
2386              s = do_lload(index);
2387              break;
2388
2389            case JBC_fload:
2390              s = do_fload(index);
2391              break;
2392
2393            case JBC_dload:
2394              s = do_dload(index);
2395              break;
2396
2397            case JBC_aload:
2398              s = do_aload(index);
2399              break;
2400
2401            case JBC_istore:
2402              s = do_store(index, popInt());
2403              break;
2404
2405            case JBC_lstore:
2406              s = do_store(index, popLong());
2407              break;
2408
2409            case JBC_fstore:
2410              s = do_store(index, popFloat());
2411              break;
2412
2413            case JBC_dstore:
2414              s = do_store(index, popDouble());
2415              break;
2416
2417            case JBC_astore:
2418              s = do_astore(index);
2419              break;
2420
2421            case JBC_iinc:
2422              s = do_iinc(index, bcodes.getWideIncrement());
2423              break;
2424
2425            case JBC_ret:
2426              s = _retHelper(index);
2427              break;
2428
2429            default:
2430              OptimizingCompilerException.UNREACHABLE();
2431              break;
2432          }
2433        }
2434        break;
2435
2436        case JBC_multianewarray: {
2437          TypeReference arrayType = bcodes.getTypeReference();
2438          int dimensions = bcodes.getArrayDimension();
2439
2440          if (dimensions == 1) {
2441            s = generateAnewarray(arrayType, null);
2442          } else {
2443            TypeOperand typeOp = makeTypeOperand(arrayType);
2444            RegisterOperand result = gc.getTemps().makeTemp(arrayType);
2445            markGuardlessNonNull(result);
2446            result.setPreciseType();
2447            TypeReference innermostElementTypeRef = arrayType.getInnermostElementType();
2448            RVMType innermostElementType = innermostElementTypeRef.peekType();
2449            if (innermostElementType != null && (innermostElementType.isInitialized() || innermostElementType.isInBootImage())) {
2450              result.setExtant();
2451            }
2452            s = Multianewarray.create(NEWOBJMULTIARRAY, result, typeOp, dimensions);
2453            for (int i = 0; i < dimensions; i++) {
2454              Multianewarray.setDimension(s, dimensions - i - 1, popInt());
2455            }
2456            push(result.copyD2U());
2457            rectifyStateWithErrorHandler();
2458            rectifyStateWithExceptionHandler(TypeReference.JavaLangNegativeArraySizeException);
2459          }
2460        }
2461        break;
2462
2463        case JBC_ifnull:
2464          s = _refIfNullHelper(ConditionOperand.EQUAL());
2465          break;
2466
2467        case JBC_ifnonnull:
2468          s = _refIfNullHelper(ConditionOperand.NOT_EQUAL());
2469          break;
2470
2471        case JBC_goto_w: {
2472          int offset = bcodes.getWideBranchOffset();
2473          if (offset != 5) {
2474            // skip generating frivolous goto's
2475            s = _gotoHelper(offset);
2476          }
2477        }
2478        break;
2479
2480        case JBC_jsr_w:
2481          s = _jsrHelper(bcodes.getWideBranchOffset());
2482          break;
2483
2484        case JBC_impdep1: {
2485          if (VM.BuildForAdaptiveSystem) {
2486          int pseudo_opcode = bcodes.nextPseudoInstruction();
2487          switch (pseudo_opcode) {
2488            case PSEUDO_LoadIntConst: {
2489              int value = bcodes.readIntConst();
2490
2491              if (VM.TraceOnStackReplacement) {
2492                VM.sysWriteln("PSEUDO_LoadIntConst " + value);
2493              }
2494
2495              push(new IntConstantOperand(value));
2496
2497              // used for PSEUDO_InvokeStatic to recover the type info
2498              param1 = param2;
2499              param2 = value;
2500
2501              break;
2502            }
2503            case PSEUDO_LoadLongConst: {
2504              long value = bcodes.readLongConst();
2505
2506              if (VM.TraceOnStackReplacement) {
2507                VM.sysWriteln("PSEUDO_LoadLongConst " + value);
2508              }
2509
2510              pushDual(new LongConstantOperand(value));
2511              break;
2512            }
2513            case PSEUDO_LoadWordConst: {
2514              Address a =
2515                  (VM.BuildFor32Addr) ? Address.fromIntSignExtend(bcodes.readIntConst()) : Address.fromLong(bcodes.readLongConst());
2516
2517              push(new AddressConstantOperand(a));
2518
2519              if (VM.TraceOnStackReplacement) {
2520                VM.sysWrite("PSEUDO_LoadWordConst 0x");
2521              }
2522              VM.sysWrite(a);
2523              VM.sysWriteln();
2524
2525              break;
2526            }
2527            case PSEUDO_LoadFloatConst: {
2528              int ibits = bcodes.readIntConst();
2529              float value = Float.intBitsToFloat(ibits);
2530
2531              if (VM.TraceOnStackReplacement) {
2532                VM.sysWriteln("PSEUDO_LoadFloatConst " + value);
2533              }
2534
2535              push(new FloatConstantOperand(value, Offset.zero()));
2536              break;
2537            }
2538
2539            case PSEUDO_LoadDoubleConst: {
2540              long lbits = bcodes.readLongConst();
2541
2542              double value = Magic.longBitsAsDouble(lbits);
2543
2544              if (VM.TraceOnStackReplacement) {
2545                VM.sysWriteln("PSEUDO_LoadDoubleConst " + lbits);
2546              }
2547
2548              pushDual(new DoubleConstantOperand(value, Offset.zero()));
2549              break;
2550            }
2551
2552            case PSEUDO_LoadRetAddrConst: {
2553              int value = bcodes.readIntConst();
2554
2555              if (VM.TraceOnStackReplacement) {
2556                VM.sysWriteln("PSEUDO_LoadRetAddrConst " + value);
2557              }
2558
2559              push(new ReturnAddressOperand(value));
2560              break;
2561            }
2562            case PSEUDO_InvokeStatic: {
2563              /* pseudo invoke static for getRefAt and cleanRefAt, both must be resolved already */
2564              int targetidx = bcodes.readIntConst();
2565              RVMMethod meth = InvokeStatic.targetMethod(targetidx);
2566
2567              if (VM.TraceOnStackReplacement) {
2568                VM.sysWriteln("PSEUDO_Invoke " + meth + "\n");
2569              }
2570
2571              s = _callHelper(meth.getMemberRef().asMethodReference(), MethodOperand.STATIC(meth));
2572              if (s == null)
2573                break;
2574              Call.setAddress(s, new AddressConstantOperand(meth.getOffset()));
2575
2576              /* try to set the type of return register */
2577              if (targetidx == GETREFAT) {
2578                Object realObj = ObjectHolder.getRefAt(param1, param2);
2579
2580                if (VM.VerifyAssertions) opt_assert(realObj != null);
2581
2582                TypeReference klass = Magic.getObjectType(realObj).getTypeRef();
2583
2584                RegisterOperand op0 = gc.getTemps().makeTemp(klass);
2585                Call.setResult(s, op0);
2586                pop();    // pop the old one and push the new return type.
2587                push(op0.copyD2U(), klass);
2588              }
2589
2590              // CALL must be treated as potential throw of anything
2591              rectifyStateWithExceptionHandlers();
2592              break;
2593            }
2594            case PSEUDO_InvokeCompiledMethod: {
2595              int cmid = bcodes.readIntConst();
2596              int origBCIdx = bcodes.readIntConst(); // skip it
2597              CompiledMethod cm = CompiledMethods.getCompiledMethod(cmid);
2598              RVMMethod meth = cm.getMethod();
2599
2600              if (VM.TraceOnStackReplacement) {
2601                VM.sysWriteln("PSEUDO_InvokeCompiledMethod " + meth + "\n");
2602              }
2603
2604              /* the bcIndex should be adjusted to the original */
2605              s = _callHelper(meth.getMemberRef().asMethodReference(),
2606                              MethodOperand.COMPILED(meth, cm.getOsrJTOCoffset()));
2607              if (s == null)
2608                break;
2609
2610              // adjust the bcindex of s to the original bytecode's index
2611              // it should be able to give the correct exception handling
2612              s.bcIndex = origBCIdx + bciAdjustment;
2613
2614              rectifyStateWithExceptionHandlers();
2615              break;
2616            }
2617            case PSEUDO_ParamInitEnd: {
2618              // indicates the place to insert method prologue and stack
2619              // overflow checks.
2620              // opt compiler should consider this too
2621
2622              break;
2623            }
2624            default:
2625              if (VM.TraceOnStackReplacement) {
2626                VM.sysWriteln("OSR Error, no such pseudo opcode : " + pseudo_opcode);
2627              }
2628
2629              OptimizingCompilerException.UNREACHABLE();
2630              break;
2631          }
2632            break;
2633          } else {
2634            OptimizingCompilerException.UNREACHABLE();
2635          }
2636        }
2637        default:
2638          OptimizingCompilerException.UNREACHABLE();
2639          break;
2640      }
2641
2642      if (s != null && !currentBBLE.isSelfRegen()) {
2643        appendInstruction(s);
2644      }
2645
2646      // check runoff
2647      if (VM.VerifyAssertions) opt_assert(bcodes.index() <= runoff);
2648      if (!endOfBasicBlock && bcodes.index() == runoff) {
2649        if (DBG_BB || DBG_SELECTED) {
2650          db("runoff occurred! current basic block: " + currentBBLE + ", runoff = " + runoff);
2651        }
2652        endOfBasicBlock = fallThrough = true;
2653      }
2654      if (endOfBasicBlock) {
2655        if (currentBBLE.isSelfRegen()) {
2656          // This block ended in a goto that jumped into the middle of it.
2657          // Through away all out edges from this block, they're out of date
2658          // because we're going to have to regenerate this block.
2659          currentBBLE.block.deleteOut();
2660          if (DBG_CFG || DBG_SELECTED) {
2661            db("Deleted all out edges of " + currentBBLE.block);
2662          }
2663          return;
2664        }
2665        if (fallThrough) {
2666          if (VM.VerifyAssertions) opt_assert(bcodes.index() < bcodes.length());
2667          // Get/Create fallthrough BBLE and record it as
2668          // currentBBLE's fallThrough.
2669          currentBBLE.fallThrough = getOrCreateBlock(bcodes.index());
2670          currentBBLE.block.insertOut(currentBBLE.fallThrough.block);
2671        }
2672        return;
2673      }
2674    }
2675  }
2676
2677  Instruction _unaryHelper(Operator operator, Operand val, TypeReference type) {
2678    RegisterOperand t = gc.getTemps().makeTemp(type);
2679    Instruction s = Unary.create(operator, t, val);
2680    Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
2681    if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
2682      gc.getTemps().release(t);
2683      push(Move.getClearVal(s));
2684      return null;
2685    } else {
2686      push(t.copyD2U());
2687      return s;
2688    }
2689  }
2690
2691  Instruction _unaryDualHelper(Operator operator, Operand val, TypeReference type) {
2692    RegisterOperand t = gc.getTemps().makeTemp(type);
2693    Instruction s = Unary.create(operator, t, val);
2694    Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
2695    if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
2696      gc.getTemps().release(t);
2697      pushDual(Move.getClearVal(s));
2698      return null;
2699    } else {
2700      pushDual(t.copyD2U());
2701      return s;
2702    }
2703  }
2704
2705  public Instruction _binaryHelper(Operator operator, Operand op1, Operand op2,
2706                                        TypeReference type) {
2707    RegisterOperand t = gc.getTemps().makeTemp(type);
2708    Instruction s = Binary.create(operator, t, op1, op2);
2709    Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
2710    if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
2711      gc.getTemps().release(t);
2712      push(Move.getClearVal(s));
2713      return null;
2714    } else {
2715      push(t.copyD2U());
2716      return s;
2717    }
2718  }
2719
2720  private Instruction _guardedBinaryHelper(Operator operator, Operand op1, Operand op2,
2721                                               Operand guard, TypeReference type) {
2722    RegisterOperand t = gc.getTemps().makeTemp(type);
2723    Instruction s = GuardedBinary.create(operator, t, op1, op2, guard);
2724    Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
2725    if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
2726      gc.getTemps().release(t);
2727      push(Move.getClearVal(s));
2728      return null;
2729    } else {
2730      push(t.copyD2U());
2731      return s;
2732    }
2733  }
2734
2735  private Instruction _binaryDualHelper(Operator operator, Operand op1, Operand op2,
2736                                            TypeReference type) {
2737    RegisterOperand t = gc.getTemps().makeTemp(type);
2738    Instruction s = Binary.create(operator, t, op1, op2);
2739    Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
2740    if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
2741      gc.getTemps().release(t);
2742      pushDual(Move.getClearVal(s));
2743      return null;
2744    } else {
2745      pushDual(t.copyD2U());
2746      return s;
2747    }
2748  }
2749
2750  private Instruction _guardedBinaryDualHelper(Operator operator, Operand op1, Operand op2,
2751                                                   Operand guard, TypeReference type) {
2752    RegisterOperand t = gc.getTemps().makeTemp(type);
2753    Instruction s = GuardedBinary.create(operator, t, op1, op2, guard);
2754    Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
2755    if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
2756      gc.getTemps().release(t);
2757      pushDual(Move.getClearVal(s));
2758      return null;
2759    } else {
2760      pushDual(t.copyD2U());
2761      return s;
2762    }
2763  }
2764
2765  Instruction _moveHelper(Operator operator, Operand val, TypeReference type) {
2766    RegisterOperand t = gc.getTemps().makeTemp(type);
2767    push(t.copyD2U());
2768    Instruction s = Move.create(operator, t, val);
2769    s.position = gc.getInlineSequence();
2770    s.bcIndex = instrIndex;
2771    return s;
2772  }
2773
2774  private Instruction _moveDualHelper(Operator operator, Operand val, TypeReference type) {
2775    RegisterOperand t = gc.getTemps().makeTemp(type);
2776    pushDual(t.copyD2U());
2777    Instruction s = Move.create(operator, t, val);
2778    s.position = gc.getInlineSequence();
2779    s.bcIndex = instrIndex;
2780    return s;
2781  }
2782
2783  public Instruction _aloadHelper(Operator operator, Operand ref, Operand index,
2784                                      TypeReference type) {
2785    RegisterOperand t = gc.getTemps().makeTemp(type);
2786    t.setDeclaredType();
2787    LocationOperand loc = new LocationOperand(type);
2788    Instruction s = ALoad.create(operator, t, ref, index, loc, getCurrentGuard());
2789    t = t.copyD2U();
2790    if (type.isLongType() || type.isDoubleType()) {
2791      pushDual(t);
2792    } else {
2793      push(t);
2794    }
2795    return s;
2796  }
2797
2798  /**
2799   * Pop method parameters off the expression stack.
2800   * If a non-void return, then create a result operand and push it
2801   * on the stack.
2802   * Create the call instruction and initialize all its operands.
2803   *
2804   * @param meth the method to call
2805   * @param methOp data about the method
2806   *
2807   * @return the newly created call instruction
2808   */
2809  private Instruction _callHelper(MethodReference meth, MethodOperand methOp) {
2810    int numHiddenParams = methOp.isStatic() ? 0 : 1;
2811    TypeReference[] params = meth.getParameterTypes();
2812    Instruction s = Call.create(CALL, null, null, null, null, params.length + numHiddenParams);
2813    if (gc.getOptions().H2L_NO_CALLEE_EXCEPTIONS) {
2814      s.markAsNonPEI();
2815    }
2816    for (int i = params.length - 1; i >= 0; i--) {
2817      try {
2818        Call.setParam(s, i + numHiddenParams, pop(params[i]));
2819      } catch (OptimizingCompilerException.IllegalUpcast e) {
2820        throw new Error("Illegal upcast creating call to " + meth + " from " + gc.getMethod() + " argument " + i, e);
2821      }
2822    }
2823    if (numHiddenParams != 0) {
2824      Operand ref = pop();
2825      Call.setParam(s, 0, ref);
2826    }
2827    Call.setMethod(s, methOp);
2828
2829    // need to set it up early because the inlining oracle use it
2830    s.position = gc.getInlineSequence();
2831    // no longer used by the inline oracle as it is incorrectly adjusted by OSR,
2832    // can't adjust it here as it will effect the exception handler maps
2833    s.bcIndex = instrIndex;
2834
2835    TypeReference rtype = meth.getReturnType();
2836    if (rtype.isVoidType()) {
2837      return s;
2838    } else {
2839      RegisterOperand t = gc.getTemps().makeTemp(rtype);
2840      Call.setResult(s, t);
2841      Simplifier.DefUseEffect simp = Simplifier.simplify(true, gc.getTemps(), gc.getOptions(), s);
2842      if ((simp == Simplifier.DefUseEffect.MOVE_FOLDED) || (simp == Simplifier.DefUseEffect.MOVE_REDUCED)) {
2843        gc.getTemps().release(t);
2844        push(Move.getClearVal(s), rtype);
2845        return null;
2846      } else {
2847        push(t.copyD2U(), rtype);
2848        return s;
2849      }
2850    }
2851  }
2852
2853  private void _returnHelper(Operator operator, Operand val) {
2854    if (gc.getResultReg() != null) {
2855      TypeReference returnType = val.getType();
2856      RegisterOperand ret = new RegisterOperand(gc.getResultReg(), returnType);
2857      boolean returningRegister = false;
2858      if (val.isRegister()) {
2859        returningRegister = true;
2860        ret.setInheritableFlags(val.asRegister());
2861        setGuardForRegOp(ret, copyGuardFromOperand(val));
2862      }
2863      appendInstruction(Move.create(operator, ret, val));
2864      // pass analysis facts about val back to our caller
2865      if (gc.getResult() == null) {
2866        if (returningRegister) {
2867          gc.setResult(ret.copyD2U());
2868        } else {
2869          gc.setResult(val.copy());
2870        }
2871      } else {
2872        Operand meet = Operand.meet(gc.getResult(), val, gc.getResultReg());
2873        // Return value can't be forced to bottom...violation of Java spec.
2874        if (VM.VerifyAssertions) opt_assert(meet != null);
2875        gc.setResult(meet);
2876      }
2877    }
2878    if (gc.getMethod().isObjectInitializer() && gc.getMethod().getDeclaringClass().declaresFinalInstanceField()) {
2879      /* JMM Compliance.  Must insert StoreStore barrier before returning from constructor of class with final instance fields */
2880      appendInstruction(Empty.create(WRITE_FLOOR));
2881    }
2882    appendInstruction(gc.getEpilogue().makeGOTO());
2883    currentBBLE.block.insertOut(gc.getEpilogue());
2884    if (DBG_CFG || DBG_SELECTED) {
2885      db("Added CFG edge from " + currentBBLE.block + " to " + gc.getEpilogue());
2886    }
2887    endOfBasicBlock = true;
2888  }
2889
2890  //// APPEND INSTRUCTION.
2891  /**
2892   * Append an instruction to the current basic block.
2893   *
2894   * @param s instruction to append
2895   */
2896  public void appendInstruction(Instruction s) {
2897    currentBBLE.block.appendInstruction(s);
2898    s.position = gc.getInlineSequence();
2899    s.bcIndex = instrIndex;
2900    lastInstr = s;
2901    if (DBG_INSTR || DBG_SELECTED) db("-> " + s.bcIndex + ":\t" + s);
2902  }
2903
2904  //// MAKE A FIELD REFERENCE.
2905  /**
2906   * Make a field reference operand referring to the given field with the
2907   * given type.
2908   *
2909   * @param f desired field
2910   * @return a new location operand
2911   */
2912  private LocationOperand makeStaticFieldRef(FieldReference f) {
2913    return new LocationOperand(f);
2914  }
2915
2916  private LocationOperand makeInstanceFieldRef(FieldReference f) {
2917    return new LocationOperand(f);
2918  }
2919
2920  //// MAKE A TYPE REFERENCE.
2921  /**
2922   * Make a type operand that refers to the given type.
2923   *
2924   * @param type desired type
2925   * @return a new type operand
2926   */
2927  private TypeOperand makeTypeOperand(TypeReference type) {
2928    if (VM.VerifyAssertions) opt_assert(type != null);
2929    return new TypeOperand(type);
2930  }
2931
2932  /**
2933   * Make a type operand that refers to the given type.
2934   *
2935   * @param type desired type
2936   * @return a new type operand
2937   */
2938  private TypeOperand makeTypeOperand(RVMType type) {
2939    if (VM.VerifyAssertions) opt_assert(type != null);
2940    return new TypeOperand(type);
2941  }
2942
2943  private boolean couldCauseClassLoading(TypeReference typeRef) {
2944    RVMType type = typeRef.peekType();
2945    if (type == null) return true;
2946    if (type.isInitialized()) return false;
2947    if (type.isArrayType()) return !type.isResolved();
2948    if (type.isClassType() && type.asClass().isInBootImage()) return false;
2949    return true;
2950  }
2951
2952  /**
2953   * Fetch the value of the next operand, a constant, from the bytecode
2954   * stream.
2955   * @param index constant pool index
2956   * @return the value of a literal constant from the bytecode stream,
2957   * encoding as a constant IR operand
2958   */
2959  public Operand getConstantOperand(int index) {
2960    byte desc = bcodes.getConstantType(index);
2961    RVMClass declaringClass = bcodes.getDeclaringClass();
2962    switch (desc) {
2963      case CP_INT:
2964        return ClassLoaderProxy.getIntFromConstantPool(declaringClass, index);
2965      case CP_FLOAT:
2966        return ClassLoaderProxy.getFloatFromConstantPool(declaringClass, index);
2967      case CP_STRING:
2968        return ClassLoaderProxy.getStringFromConstantPool(declaringClass, index);
2969      case CP_LONG:
2970        return ClassLoaderProxy.getLongFromConstantPool(declaringClass, index);
2971      case CP_DOUBLE:
2972        return ClassLoaderProxy.getDoubleFromConstantPool(declaringClass, index);
2973      case CP_CLASS:
2974        return ClassLoaderProxy.getClassFromConstantPool(declaringClass, index);
2975      default:
2976        if (VM.VerifyAssertions) {
2977          String msg = "invalid literal type: 0x" + Integer.toHexString(desc);
2978          opt_assert(VM.NOT_REACHED, msg);
2979        }
2980        return null;
2981    }
2982  }
2983
2984  //// LOAD LOCAL VARIABLE ONTO STACK.
2985  /**
2986   * Simulates a load from a given local variable of an int.
2987   *
2988   * @param index local variable number
2989   * @return {@code null} if no instruction is necessary, a move instruction
2990   *  otherwise
2991   */
2992  private Instruction do_iload(int index) {
2993    Operand r = getLocal(index);
2994    if (VM.VerifyAssertions) opt_assert(r.isIntLike());
2995    if (LOCALS_ON_STACK) {
2996      push(r);
2997      return null;
2998    } else {
2999      return _moveHelper(INT_MOVE, r, TypeReference.Int);
3000    }
3001  }
3002
3003  /**
3004   * Simulates a load from a given local variable of a float.
3005   *
3006   * @param index local variable number
3007   * @return {@code null} if no instruction is necessary, a move instruction
3008   *  otherwise
3009   */
3010  private Instruction do_fload(int index) {
3011    Operand r = getLocal(index);
3012    if (VM.VerifyAssertions) opt_assert(r.isFloat());
3013    if (LOCALS_ON_STACK) {
3014      push(r);
3015      return null;
3016    } else {
3017      return _moveHelper(FLOAT_MOVE, r, TypeReference.Float);
3018    }
3019  }
3020
3021  /**
3022   * Simulates a load from a given local variable of a reference.
3023   *
3024   * @param index local variable number
3025   * @return {@code null} if no instruction is necessary, a move instruction
3026   *  otherwise
3027   */
3028  private Instruction do_aload(int index) {
3029    Operand r = getLocal(index);
3030    if (VM.VerifyAssertions && !(r.isRef() || r.isAddress())) {
3031      String msg = r + " not ref, but a " + r.getType();
3032      opt_assert(VM.NOT_REACHED, msg);
3033    }
3034    if (LOCALS_ON_STACK) {
3035      push(r);
3036      return null;
3037    } else {
3038      return _moveHelper(REF_MOVE, r, r.getType());
3039    }
3040  }
3041
3042  /**
3043   * Simulates a load from a given local variable of a long.
3044   *
3045   * @param index local variable number
3046   * @return {@code null} if no instruction is necessary, a move instruction
3047   *  otherwise
3048   */
3049  private Instruction do_lload(int index) {
3050    Operand r = getLocalDual(index);
3051    if (VM.VerifyAssertions) opt_assert(r.isLong());
3052    if (LOCALS_ON_STACK) {
3053      pushDual(r);
3054      return null;
3055    } else {
3056      return _moveDualHelper(LONG_MOVE, r, TypeReference.Long);
3057    }
3058  }
3059
3060  /**
3061   * Simulates a load from a given local variable of a double.
3062   *
3063   * @param index local variable number
3064   * @return {@code null} if no instruction is necessary, a move instruction
3065   *  otherwise
3066   */
3067  private Instruction do_dload(int index) {
3068    Operand r = getLocalDual(index);
3069    if (VM.VerifyAssertions) opt_assert(r.isDouble());
3070    if (LOCALS_ON_STACK) {
3071      pushDual(r);
3072      return null;
3073    } else {
3074      return _moveDualHelper(DOUBLE_MOVE, r, TypeReference.Double);
3075    }
3076  }
3077
3078  //// INCREMENT A LOCAL VARIABLE.
3079  /**
3080   * Simulates the incrementing of a given int local variable.
3081   *
3082   * @param index local variable number
3083   * @param amount amount to increment by
3084   * @return the generated instruction, never {@code null}
3085   */
3086  private Instruction do_iinc(int index, int amount) {
3087    Operand r = getLocal(index);
3088    if (VM.VerifyAssertions) opt_assert(r.isIntLike());
3089    if (LOCALS_ON_STACK) {
3090      replaceLocalsOnStack(index, TypeReference.Int);
3091    }
3092    RegisterOperand op0 = gc.makeLocal(index, TypeReference.Int);
3093    if (r instanceof IntConstantOperand) {
3094      // do constant folding.
3095      int res = amount + ((IntConstantOperand) r).value;
3096      IntConstantOperand val = new IntConstantOperand(res);
3097      if (CP_IN_LOCALS) {
3098        setLocal(index, val);
3099      } else {
3100        setLocal(index, op0);
3101      }
3102      Instruction s = Move.create(INT_MOVE, op0, val);
3103      s.position = gc.getInlineSequence();
3104      s.bcIndex = instrIndex;
3105      return s;
3106    }
3107    setLocal(index, op0);
3108    return Binary.create(INT_ADD, op0, r, new IntConstantOperand(amount));
3109  }
3110
3111  //// POP FROM STACK AND STORE INTO LOCAL VARIABLE.
3112  /**
3113   * Simulates a store into a given local variable of an int/long/double/float
3114   *
3115   * @param index local variable number
3116   * @param op1 the value to store
3117   * @return {@code null} if no instruction is necessary, the generated
3118   *  instruction otherwise
3119   */
3120  private Instruction do_store(int index, Operand op1) {
3121    TypeReference type = op1.getType();
3122    boolean Dual = (type.isLongType() || type.isDoubleType());
3123    if (LOCALS_ON_STACK) {
3124      replaceLocalsOnStack(index, type);
3125    }
3126    if (ELIM_COPY_LOCALS) {
3127      if (op1 instanceof RegisterOperand) {
3128        RegisterOperand rop1 = (RegisterOperand) op1;
3129        Register r1 = rop1.getRegister();
3130        if (lastInstr != null &&
3131            ResultCarrier.conforms(lastInstr) &&
3132            ResultCarrier.hasResult(lastInstr) &&
3133            !r1.isLocal() &&
3134            r1 == ResultCarrier.getResult(lastInstr).getRegister()) {
3135          if (DBG_ELIMCOPY) db("eliminated copy " + op1 + " to" + index);
3136          RegisterOperand newop0 = gc.makeLocal(index, rop1);
3137          ResultCarrier.setResult(lastInstr, newop0);
3138          if (Dual) {
3139            setLocalDual(index, newop0);
3140          } else {
3141            setLocal(index, newop0);
3142          }
3143          gc.getTemps().release(rop1);
3144          return null;
3145        }
3146      }
3147    }
3148    RegisterOperand op0 =
3149        (op1 instanceof RegisterOperand) ? gc.makeLocal(index, (RegisterOperand) op1) : gc.makeLocal(index,
3150                                                                                                             type);
3151    Operand set = op0;
3152    if (CP_IN_LOCALS) {
3153      set = (op1 instanceof RegisterOperand) ? op0 : op1;
3154    }
3155    if (Dual) {
3156      setLocalDual(index, set);
3157    } else {
3158      setLocal(index, set);
3159    }
3160    Instruction s = Move.create(IRTools.getMoveOp(type), op0, op1);
3161    s.position = gc.getInlineSequence();
3162    s.bcIndex = instrIndex;
3163    return s;
3164  }
3165
3166  /**
3167   * Simulates a store into a given local variable of an object ref.
3168   *
3169   * @param index local variable number
3170   * @return {@code null} if no instruction is necessary, the generated
3171   *  instruction otherwise
3172   */
3173  private Instruction do_astore(int index) {
3174    Operand op1 = pop();
3175    if (op1 instanceof ReturnAddressOperand) {
3176      setLocal(index, op1);
3177      return null;
3178    }
3179    boolean doConstantProp = false;
3180    if ((op1 instanceof NullConstantOperand) || (op1 instanceof AddressConstantOperand)) {
3181      doConstantProp = true;
3182    }
3183    TypeReference type = op1.getType();
3184    if (LOCALS_ON_STACK) {
3185      replaceLocalsOnStack(index, type);
3186    }
3187    if (ELIM_COPY_LOCALS) {
3188      if (op1 instanceof RegisterOperand) {
3189        RegisterOperand rop1 = (RegisterOperand) op1;
3190        Register r1 = rop1.getRegister();
3191        if (lastInstr != null &&
3192            ResultCarrier.conforms(lastInstr) &&
3193            ResultCarrier.hasResult(lastInstr) &&
3194            !r1.isLocal() &&
3195            r1 == ResultCarrier.getResult(lastInstr).getRegister()) {
3196          if (DBG_ELIMCOPY) {
3197            db("eliminated copy " + op1 + " to " + index);
3198          }
3199          RegisterOperand newop0 = gc.makeLocal(index, rop1);
3200          ResultCarrier.setResult(lastInstr, newop0);
3201          setLocal(index, newop0);
3202          gc.getTemps().release(rop1);
3203          return null;
3204        }
3205      }
3206    }
3207    RegisterOperand op0;
3208    if (op1 instanceof RegisterOperand) {
3209      RegisterOperand rop1 = (RegisterOperand) op1;
3210      op0 = gc.makeLocal(index, rop1);
3211      if (hasGuard(rop1)) {
3212        RegisterOperand g0 = gc.makeNullCheckGuard(op0.getRegister());
3213        appendInstruction(Move.create(GUARD_MOVE, g0.copyRO(), copyGuardFromOperand(rop1)));
3214        setGuardForRegOp(op0, g0);
3215      }
3216    } else {
3217      op0 = gc.makeLocal(index, type);
3218    }
3219    if (CP_IN_LOCALS) {
3220      setLocal(index, doConstantProp ? op1 : op0);
3221    } else {
3222      setLocal(index, op0);
3223    }
3224    Instruction s = Move.create(REF_MOVE, op0, op1);
3225    s.position = gc.getInlineSequence();
3226    s.bcIndex = instrIndex;
3227    return s;
3228  }
3229
3230  //// PUSH OPERAND ONTO THE STACK.
3231  /**
3232   * Push a single width operand (int, float, ref, ...) on the simulated stack.
3233   *
3234   * @param r operand to push
3235   */
3236  public void push(Operand r) {
3237    if (VM.VerifyAssertions) opt_assert(r.instruction == null);
3238    stack.push(r);
3239  }
3240
3241  /**
3242   * Push a double width operand (long, double) on the simulated stack.
3243   *
3244   * @param r operand to push
3245   */
3246  void pushDual(Operand r) {
3247    if (VM.VerifyAssertions) opt_assert(r.instruction == null);
3248    stack.push(DUMMY);
3249    stack.push(r);
3250  }
3251
3252  /**
3253   * Push an operand of the specified type on the simulated stack.
3254   *
3255   * @param r operand to push
3256   * @param type data type of operand
3257   */
3258  void push(Operand r, TypeReference type) {
3259    if (VM.VerifyAssertions) opt_assert(r.instruction == null);
3260    if (type.isVoidType()) {
3261      return;
3262    }
3263    if (type.isLongType() || type.isDoubleType()) {
3264      pushDual(r);
3265    } else {
3266      push(r);
3267    }
3268  }
3269
3270  /**
3271   * Pushes a copy of the given operand onto simulated stack.
3272   *
3273   * @param op1 operand to push
3274   * @return always {@code null}
3275   */
3276  private Instruction pushCopy(Operand op1) {
3277    if (VM.VerifyAssertions) opt_assert(op1.instruction == null);
3278    if (op1 instanceof RegisterOperand) {
3279      RegisterOperand reg = (RegisterOperand) op1;
3280      if (!reg.getRegister().isLocal()) {
3281        lastInstr = null;       // to prevent eliminating this temporary.
3282      }
3283      stack.push(reg.copy());
3284    } else {
3285      stack.push(op1.copy());
3286    }
3287    return null;
3288  }
3289
3290  //// POP OPERAND FROM THE STACK.
3291  /**
3292   * Pops an operand from the stack. No type checking is performed.
3293   * @return the popped operand
3294   */
3295  Operand pop() {
3296    return stack.pop();
3297  }
3298
3299  /**
3300   * Pops an int operand from the stack.
3301   * @return the popped operand
3302   */
3303  public Operand popInt() {
3304    Operand r = pop();
3305    if (VM.VerifyAssertions) opt_assert(r.isIntLike());
3306    return r;
3307  }
3308
3309  /**
3310   * Pops a float operand from the stack.
3311   * @return the popped operand
3312   */
3313  Operand popFloat() {
3314    Operand r = pop();
3315    if (VM.VerifyAssertions) opt_assert(r.isFloat());
3316    return r;
3317  }
3318
3319  /**
3320   * Pops a ref operand from the stack.
3321   * @return the popped operand
3322   */
3323  public Operand popRef() {
3324    Operand r = pop();
3325    if (VM.VerifyAssertions) opt_assert(r.isRef() || r.isAddress());
3326    return r;
3327  }
3328
3329  /**
3330   * Pops an address operand from the stack.
3331   * @return the popped operand
3332   */
3333  public Operand popAddress() {
3334    Operand r = pop();
3335    if (VM.VerifyAssertions) opt_assert(r.isAddress());
3336    return r;
3337  }
3338
3339  /**
3340   * Pops a long operand from the stack.
3341   * @return the popped operand
3342   */
3343  Operand popLong() {
3344    Operand r = pop();
3345    if (VM.VerifyAssertions) opt_assert(r.isLong());
3346    popDummy();
3347    return r;
3348  }
3349
3350  /**
3351   * Pops a double operand from the stack.
3352   * @return the popped operand
3353   */
3354  Operand popDouble() {
3355    Operand r = pop();
3356    if (VM.VerifyAssertions) opt_assert(r.isDouble());
3357    popDummy();
3358    return r;
3359  }
3360
3361  /**
3362   * Pops a dummy operand from the stack.
3363   */
3364  void popDummy() {
3365    Operand r = pop();
3366    if (VM.VerifyAssertions) opt_assert(r == DUMMY);
3367  }
3368
3369  /**
3370   * Pops an operand of the given type from the stack.
3371   * @param type the expected type of the operand
3372   * @return the popped operand
3373   */
3374  Operand pop(TypeReference type) {
3375    Operand r = pop();
3376    // Can't assert the following due to approximations by
3377    // ClassLoaderProxy.findCommonSuperclass
3378    // if (VM.VerifyAssertions) assertIsType(r, type);
3379    // Avoid upcasts of magic types to regular j.l.Objects
3380//    if (VM.VerifyAssertions && (type == TypeReference.JavaLangObject))
3381//      opt_assert(!r.getType().isMagicType());
3382    if (VM.VerifyAssertions) {
3383      if ((type == TypeReference.JavaLangObject) &&
3384          (r.getType().isMagicType()) &&
3385          !gc.getMethod().getDeclaringClass().getTypeRef().isMagicType()) {
3386        throw new OptimizingCompilerException.IllegalUpcast(r.getType());
3387      }
3388    }
3389    if (type.isLongType() || type.isDoubleType()) {
3390      popDummy();
3391    }
3392    return r;
3393  }
3394
3395  /**
3396   * Pop an int from the stack to be used in a shift. A shift only uses the
3397   * bottom 5 or 6 bits of an int so the upper bits must be masked to conform
3398   * with the semantics of xx_SHx. NB the opt compiler shift operators allow that
3399   * {@code (x << 16) << 16 == x << 32}, which isn't true in the bytecode
3400   * @param longShift is this a shift of a long
3401   * @return the operand containing the amount to shift by
3402   */
3403  private Operand popShiftInt(boolean longShift) {
3404    Operand op = popInt();
3405    if (op instanceof IntConstantOperand) {
3406      int val = op.asIntConstant().value;
3407      if (!longShift) {
3408        if ((val > 0) && (val <= 31)) {
3409          return op;
3410        } else {
3411          return new IntConstantOperand(val & 0x1F);
3412        }
3413      } else {
3414        if ((val > 0) && (val <= 63)) {
3415          return op;
3416        } else {
3417          return new IntConstantOperand(val & 0x3F);
3418        }
3419      }
3420    } else {
3421      Instruction s =
3422          _binaryHelper(INT_AND, op, new IntConstantOperand(longShift ? 0x3F : 0x1f), TypeReference.Int);
3423      if (s != null && !currentBBLE.isSelfRegen()) {
3424        appendInstruction(s);
3425      }
3426      return popInt();
3427    }
3428  }
3429
3430  //// SUBROUTINES.
3431  private Instruction _jsrHelper(int offset) {
3432    // (1) notify the BBSet that we have reached a JSR bytecode.
3433    //     This enables the more complex JSR-aware implementation of
3434    //     BBSet.getOrCreateBlock.
3435    blocks.seenJSR();
3436
3437    // (2) push return address on expression stack
3438    push(new ReturnAddressOperand(bcodes.index()));
3439
3440    // (3) generate GOTO to subroutine body.
3441    BranchOperand branch = generateTarget(offset);
3442    return Goto.create(GOTO, branch);
3443  }
3444
3445  private Instruction _retHelper(int var) {
3446    // (1) consume the return address from the specified local variable
3447    Operand local = getLocal(var);
3448    ReturnAddressOperand ra = (ReturnAddressOperand) local;
3449    setLocal(var, null); // must set local null before calling getOrCreateBlock!!
3450    BasicBlockLE rb = getOrCreateBlock(ra.retIndex);
3451
3452    // (2) generate a GOTO to the return site.
3453    currentBBLE.block.insertOut(rb.block);
3454    endOfBasicBlock = true;
3455    if (DBG_CFG || DBG_SELECTED) db("Added CFG edge from " + currentBBLE.block + " to " + rb.block);
3456    return Goto.create(GOTO, rb.block.makeJumpTarget());
3457  }
3458
3459  //// GET TYPE OF AN OPERAND.
3460  /**
3461   * Returns the data type of the given operand, assuming that the operand is
3462   * an array reference. (and not a {@code null} constant.)
3463   *
3464   * @param op operand to get type of
3465   * @return operand's data type
3466   */
3467  public TypeReference getArrayTypeOf(Operand op) {
3468    if (VM.VerifyAssertions) opt_assert(!op.isDefinitelyNull());
3469    return op.getType();
3470  }
3471
3472  /**
3473   * Returns the data type of the given operand, assuming that the operand is
3474   * a reference. (and not a {@code null} constant.)
3475   *
3476   * @param op operand to get type of
3477   * @return operand's data type
3478   */
3479  private TypeReference getRefTypeOf(Operand op) {
3480    if (VM.VerifyAssertions) opt_assert(!op.isDefinitelyNull());
3481    return op.getType();
3482  }
3483
3484  //// HELPER FUNCTIONS FOR ASSERTION VERIFICATION
3485  /**
3486   * Assert that the given operand is of the given type, or of
3487   * a subclass of the given type.
3488   *
3489   * @param op operand to check
3490   * @param type expected type of operand
3491   */
3492  public void assertIsType(Operand op, TypeReference type) {
3493    if (VM.VerifyAssertions) {
3494      if (op.isDefinitelyNull()) {
3495        opt_assert(type.isReferenceType());
3496      } else if (op.isIntLike()) {
3497        opt_assert(type.isIntLikeType());
3498      } else {
3499        TypeReference type1 = op.getType();
3500        if (ClassLoaderProxy.includesType(type, type1) == NO) {
3501          String msg = op + ": " + type + " is not assignable with " + type1;
3502          opt_assert(VM.NOT_REACHED, msg);
3503        }
3504      }
3505    }
3506  }
3507
3508  /**
3509   * Assert that the given child type is a subclass of the given parent type.
3510   *
3511   * @param parentType parent type
3512   * @param childType child type
3513   */
3514  private void assertIsAssignable(TypeReference parentType, TypeReference childType) {
3515    if (VM.VerifyAssertions) {
3516      if (childType.isUnboxedType()) {
3517        //TODO: This should be opt_assert(gc.method.getReturnType() == retType.isUnboxedType());
3518        // but all word types are converted into addresses and thus the assertion fails. This should be fixed.
3519        opt_assert(parentType.isUnboxedType());
3520      } else {
3521        // fudge to deal with conservative approximation
3522        // in ClassLoaderProxy.findCommonSuperclass
3523        if (childType != TypeReference.JavaLangObject) {
3524          if (ClassLoaderProxy.includesType(parentType, childType) == NO) {
3525            VM.sysWriteln("type reference equality " + (parentType == childType));
3526            Enumeration<InlineSequence> callHierarchy = gc.getInlineSequence().enumerateFromRoot();
3527            while (callHierarchy.hasMoreElements()) {
3528              VM.sysWriteln(callHierarchy.nextElement().toString());
3529            }
3530            String msg = parentType + " not assignable with " + childType;
3531            opt_assert(VM.NOT_REACHED, msg);
3532          }
3533        }
3534      }
3535    }
3536  }
3537
3538  //// DEBUGGING.
3539  /**
3540   * Print a debug string to the sysWrite stream
3541   *
3542   * @param val string to print
3543   */
3544  private void db(String val) {
3545    VM.sysWrite("IRGEN " + bcodes.getDeclaringClass() + "." + gc.getMethod().getName() + ":" + val + "\n");
3546  }
3547
3548  /**
3549   * @return a string representation of the current basic block set.
3550   */
3551  private String printBlocks() {
3552    StringBuilder res = new StringBuilder();
3553    for (Enumeration<BasicBlockLE> e = blocks.contents(); e.hasMoreElements();) {
3554      BasicBlockLE b = e.nextElement();
3555      if (b == currentBBLE) {
3556        res.append("*");
3557      }
3558      res.append(b.toString());
3559      res.append(" ");
3560    }
3561    return res.toString();
3562  }
3563
3564  //// GENERATE CHECK INSTRUCTIONS.
3565  public static boolean isNonNull(Operand op) {
3566    if (op instanceof RegisterOperand) {
3567      RegisterOperand rop = (RegisterOperand) op;
3568      if (VM.VerifyAssertions) {
3569        opt_assert((rop.getGuard() == null) ||
3570                   (rop.getGuard() instanceof RegisterOperand) ||
3571                   (rop.getGuard() instanceof TrueGuardOperand));
3572      }
3573      return rop.getGuard() != null;
3574    } else {
3575      return op.isConstant();
3576    }
3577  }
3578
3579  public static boolean hasGuard(RegisterOperand rop) {
3580    return rop.getGuard() != null;
3581  }
3582
3583  public static boolean hasLessConservativeGuard(RegisterOperand rop1, RegisterOperand rop2) {
3584    if (rop1.getGuard() == rop2.getGuard()) {
3585      return false;
3586    }
3587    if (rop1.getGuard() instanceof Operand) {
3588      if (rop2.getGuard() instanceof Operand) {
3589        Operand op1 = rop1.getGuard();
3590        Operand op2 = rop2.getGuard();
3591        if (op2 instanceof TrueGuardOperand) {
3592          // rop2 is top therefore rop1 can't be less conservative!
3593          return false;
3594        } else {
3595          return !(op1.similar(op2));
3596        }
3597      } else {
3598        return true;
3599      }
3600    } else {
3601      // rop1 is bottom, therefore is most conservative guard possible
3602      return false;
3603    }
3604  }
3605
3606  public void markGuardlessNonNull(RegisterOperand rop) {
3607    RegisterOperand g = gc.makeNullCheckGuard(rop.getRegister());
3608    appendInstruction(Move.create(GUARD_MOVE, g, new TrueGuardOperand()));
3609    rop.setGuard(g.copy());
3610  }
3611
3612  public static Operand copyGuardFromOperand(Operand op) {
3613    if (op instanceof RegisterOperand) {
3614      RegisterOperand rop = (RegisterOperand) op;
3615      if (VM.VerifyAssertions) {
3616        opt_assert((rop.getGuard() == null) ||
3617                   (rop.getGuard() instanceof RegisterOperand) ||
3618                   (rop.getGuard() instanceof TrueGuardOperand));
3619      }
3620      if (rop.getGuard() == null) {
3621        return null;
3622      } else {
3623        return rop.getGuard().copy();
3624      }
3625    }
3626    if (VM.VerifyAssertions) {
3627      opt_assert(op.isConstant());
3628    }
3629    return new TrueGuardOperand();
3630  }
3631
3632  public static void setGuardForRegOp(RegisterOperand rop, Operand guard) {
3633    rop.setGuard(guard);
3634  }
3635
3636  private void setCurrentGuard(Operand guard) {
3637    if (currentGuard instanceof RegisterOperand) {
3638      if (VM.VerifyAssertions) {
3639        opt_assert(!(guard instanceof TrueGuardOperand));
3640      }
3641      // shouldn't happen given current generation --dave.
3642      RegisterOperand combined = gc.getTemps().makeTempValidation();
3643      appendInstruction(Binary.create(GUARD_COMBINE, combined, getCurrentGuard(), guard.copy()));
3644      currentGuard = combined;
3645    } else {
3646      currentGuard = guard;
3647    }
3648  }
3649
3650  public void clearCurrentGuard() {
3651    currentGuard = null;
3652  }
3653
3654  public Operand getCurrentGuard() {
3655    // This check is needed for when guards are (unsafely) turned off
3656    if (currentGuard != null) {
3657      return currentGuard.copy();
3658    }
3659    return null;
3660  }
3661
3662  /**
3663   * Generates a null-check instruction for the given operand.
3664   * @param ref the reference to check for null
3665   * @return {@code true} if an unconditional throw is generated, {@code false} otherwise
3666   */
3667  public boolean do_NullCheck(Operand ref) {
3668    if (gc.noNullChecks()) {
3669      setCurrentGuard(new TrueGuardOperand());
3670      return false;
3671    }
3672    if (ref.isDefinitelyNull()) {
3673      if (DBG_CF) db("generating definite exception: null_check of definitely null");
3674      endOfBasicBlock = true;
3675      rectifyStateWithNullPtrExceptionHandler();
3676      appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.NullPtr()));
3677      return true;
3678    }
3679    if (ref instanceof RegisterOperand) {
3680      RegisterOperand rop = (RegisterOperand) ref;
3681      if (hasGuard(rop)) {
3682        Operand guard = copyGuardFromOperand(rop);
3683        setCurrentGuard(guard);
3684        if (DBG_ELIMNULL) {
3685          db("null check of " + ref + " is not necessary; guarded by " + guard);
3686        }
3687        return false;
3688      }
3689      // rop is possibly null, insert the null check,
3690      // rectify with exception handler, update the guard state.
3691      RegisterOperand guard = gc.makeNullCheckGuard(rop.getRegister());
3692      appendInstruction(NullCheck.create(NULL_CHECK, guard, ref.copy()));
3693      rectifyStateWithNullPtrExceptionHandler();
3694      setCurrentGuard(guard);
3695      setGuardForRegOp(rop, guard);
3696      if (DBG_ELIMNULL) db(rop + " is guarded by " + guard);
3697      // Now, try to leverage this null check by updating
3698      // other unguarded (and thus potentially null)
3699      // RegisterOperands representing the same Register.
3700      if (rop.getRegister().isLocal()) {
3701        // We want to learn that downstream of this nullcheck, other
3702        // uses of this local variable will also be non-null.
3703        // BUT, we MUST NOT just directly set the guard of the appropriate
3704        // element of our locals array (operands in the local array
3705        // may appear in previously generated instructions).
3706        // Therefore we call getLocal (which internally makes a copy),
3707        // mark the copy with the new guard
3708        // and finally store the copy back into the local state.
3709        int number = gc.getLocalNumberFor(rop.getRegister(), rop.getType());
3710        if (number != -1) {
3711          Operand loc = getLocal(number);
3712          if (loc instanceof RegisterOperand) {
3713            if (DBG_ELIMNULL) {
3714              db("setting local #" + number + "(" + loc + ") to non-null");
3715            }
3716            setGuardForRegOp((RegisterOperand) loc, guard);
3717          }
3718          setLocal(number, loc);
3719        }
3720      }
3721      // At least within this basic block we know that all subsequent uses
3722      // of ref will be non null, since they are guarded by the null check
3723      // instruction we just inserted.  Update all RegisterOperands with
3724      // this register currently on the expression stack appropriately.
3725      // Stack rectification will ensure that we don't propagate this
3726      // non-nullness to a use that is not dominated by the null check in
3727      // the current basic block.
3728      for (int i = stack.getSize() - 1; i >= 0; --i) {
3729        Operand sop = stack.getFromTop(i);
3730        if (sop instanceof RegisterOperand) {
3731          RegisterOperand sreg = (RegisterOperand) sop;
3732          if (sreg.getRegister() == rop.getRegister()) {
3733            if (hasGuard(sreg)) {
3734              if (DBG_ELIMNULL) {
3735                db(sreg + " on stack already with guard " + copyGuardFromOperand(sreg));
3736              }
3737            } else {
3738              if (DBG_ELIMNULL) {
3739                db("setting " + sreg + " on stack to be guarded by " + guard);
3740              }
3741              setGuardForRegOp(sreg, guard);
3742            }
3743          }
3744        }
3745      }
3746      return false;
3747    } else {
3748      // cannot be null becuase it's not in a register.
3749      if (DBG_ELIMNULL) {
3750        db("skipped generation of a null-check instruction for non-register " + ref);
3751      }
3752      setCurrentGuard(new TrueGuardOperand());
3753      return false;
3754    }
3755  }
3756
3757  /**
3758   * Generates a boundscheck instruction for the given operand and index.
3759   * @param ref the array reference
3760   * @param index the array index
3761   * @return {@code true} if an unconditional throw is generated, {@code false} otherwise
3762   */
3763  public boolean do_BoundsCheck(Operand ref, Operand index) {
3764    // Unsafely eliminate all bounds checks
3765    if (gc.noBoundsChecks()) {
3766      return false;
3767    }
3768    RegisterOperand guard = gc.getTemps().makeTempValidation();
3769    appendInstruction(BoundsCheck.create(BOUNDS_CHECK, guard, ref.copy(), index.copy(), getCurrentGuard()));
3770    setCurrentGuard(guard);
3771    rectifyStateWithArrayBoundsExceptionHandler();
3772    return false;
3773  }
3774
3775  /**
3776   * Generates a check for 0 for the given operand
3777   * @param div the value to check
3778   * @return {@code true} if an unconditional trap is generated, {@code false} otherwise
3779   */
3780  private boolean do_IntZeroCheck(Operand div) {
3781    if (div instanceof IntConstantOperand) {
3782      if (((IntConstantOperand) div).value == 0) {
3783        endOfBasicBlock = true;
3784        rectifyStateWithArithmeticExceptionHandler();
3785        appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.DivByZero()));
3786        return true;
3787      } else {
3788        if (DBG_CF) {
3789          db("skipped gen of int_zero_check of " + div.asIntConstant().value);
3790        }
3791        setCurrentGuard(new TrueGuardOperand());
3792        return false;
3793      }
3794    }
3795    RegisterOperand guard = gc.getTemps().makeTempValidation();
3796    appendInstruction(ZeroCheck.create(INT_ZERO_CHECK, guard, div.copy()));
3797    setCurrentGuard(guard);
3798    rectifyStateWithArithmeticExceptionHandler();
3799    return false;
3800  }
3801
3802  /**
3803   * Generates a checks for 0 for the given operand
3804   * @param div the value to check
3805   * @return {@code true} if an unconditional trap is generated, {@code false} otherwise
3806   */
3807  private boolean do_LongZeroCheck(Operand div) {
3808    if (div instanceof LongConstantOperand) {
3809      if (((LongConstantOperand) div).value == 0) {
3810        endOfBasicBlock = true;
3811        rectifyStateWithArithmeticExceptionHandler();
3812        appendInstruction(Trap.create(TRAP, gc.getTemps().makeTempValidation(), TrapCodeOperand.DivByZero()));
3813        return true;
3814      } else {
3815        if (DBG_CF) {
3816          db("skipped gen of long_zero_check of " + div.asLongConstant().value);
3817        }
3818        setCurrentGuard(new TrueGuardOperand());
3819        return false;
3820      }
3821    }
3822    RegisterOperand guard = gc.getTemps().makeTempValidation();
3823    appendInstruction(ZeroCheck.create(LONG_ZERO_CHECK, guard, div.copy()));
3824    setCurrentGuard(guard);
3825    rectifyStateWithArithmeticExceptionHandler();
3826    return false;
3827  }
3828
3829  /**
3830   * Generate a storecheck for the given array and elem
3831   * @param ref the array reference
3832   * @param elem the element to be written to the array
3833   * @param elemType the type of the array references elements
3834   * @return {@code true} if an unconditional throw is generated, {@code false} otherwise
3835   */
3836  private boolean do_CheckStore(Operand ref, Operand elem, TypeReference elemType) {
3837    if (gc.noCheckStoreChecks()) return false;
3838
3839    if (CF_CHECKSTORE) {
3840      // NOTE: BE WARY OF ADDITIONAL OPTIMZATIONS.
3841      // ARRAY SUBTYPING IS SUBTLE (see JLS 10.10) --dave
3842      if (elem.isDefinitelyNull()) {
3843        if (DBG_TYPE) db("skipping checkstore of null constant");
3844        return false;
3845      }
3846      if (elemType.isArrayType()) {
3847        TypeReference elemType2 = elemType;
3848        do {
3849          elemType2 = elemType2.getArrayElementType();
3850        } while (elemType2.isArrayType());
3851        RVMType et2 = elemType2.peekType();
3852        if (et2 != null) {
3853          if (et2.isPrimitiveType() || et2.isUnboxedType() || ((RVMClass) et2).isFinal()) {
3854            TypeReference myElemType = getRefTypeOf(elem);
3855            if (myElemType == elemType) {
3856              if (DBG_TYPE) {
3857                db("eliminating checkstore to an array with a final element type " + elemType);
3858              }
3859              return false;
3860            } else {
3861              // run time check is still necessary
3862            }
3863          }
3864        }
3865      } else {
3866        // elemType is class
3867        RVMType et = elemType.peekType();
3868        if (et != null && ((RVMClass) et).isFinal()) {
3869          if (getRefTypeOf(elem) == elemType) {
3870            if (DBG_TYPE) {
3871              db("eliminating checkstore to an array with a final element type " + elemType);
3872            }
3873            return false;
3874          } else {
3875            // run time check is still necessary
3876          }
3877        }
3878      }
3879    }
3880
3881    RegisterOperand guard = gc.getTemps().makeTempValidation();
3882    if (isNonNull(elem)) {
3883      RegisterOperand newGuard = gc.getTemps().makeTempValidation();
3884      appendInstruction(Binary.create(GUARD_COMBINE, newGuard, copyGuardFromOperand(elem), getCurrentGuard()));
3885      appendInstruction(StoreCheck.create(OBJARRAY_STORE_CHECK_NOTNULL,
3886                                          guard,
3887                                          ref.copy(),
3888                                          elem.copy(),
3889                                          newGuard.copy()));
3890    } else {
3891      appendInstruction(StoreCheck.create(OBJARRAY_STORE_CHECK, guard, ref.copy(), elem.copy(), getCurrentGuard()));
3892    }
3893    setCurrentGuard(guard);
3894    rectifyStateWithArrayStoreExceptionHandler();
3895    return false;
3896  }
3897
3898  //// GENERATE BRANCHING INSTRUCTIONS.
3899  /**
3900   * Gets or creates a block at the specified target.
3901   * Rectifies current state with target state.
3902   * Instructions to rectify state are appended to currentBBLE.
3903   * If the target is between bcodes.index() and runoff, runoff is
3904   * updated to be target.
3905   *
3906   * @param target target index
3907   * @return a block, never {@code null}
3908   */
3909  private BasicBlockLE getOrCreateBlock(int target) {
3910    return getOrCreateBlock(target, currentBBLE, stack, _localState);
3911  }
3912
3913  /**
3914   * Get or create a block at the specified target.
3915   * If simStack is non-{@code null}, rectifies stack state with target stack state.
3916   * If simLocals is non-{@code null}, rectifies local state with target local state.
3917   * Any instructions needed to rectify stack/local state are appended to from.
3918   * If the target is between bcodes.index() and runoff, runoff is
3919   * updated to be target.
3920   *
3921   * @param target target index
3922   * @param from the block from which control is being transfered
3923   *                  and to which stack rectification instructions are added.
3924   * @param simStack stack state to rectify, or {@code null}
3925   * @param simLocals local state to rectify, or {@code null}
3926   * @return a block, never {@code null}
3927   */
3928  private BasicBlockLE getOrCreateBlock(int target, BasicBlockLE from, OperandStack simStack, Operand[] simLocals) {
3929    if ((target > bcodes.index()) && (target < runoff)) {
3930      if (DBG_BB || DBG_SELECTED) db("updating runoff from " + runoff + " to " + target);
3931      runoff = target;
3932    }
3933    return blocks.getOrCreateBlock(target, from, simStack, simLocals);
3934  }
3935
3936  private BranchOperand generateTarget(int offset) {
3937    BasicBlockLE targetbble = getOrCreateBlock(offset + instrIndex);
3938    currentBBLE.block.insertOut(targetbble.block);
3939    endOfBasicBlock = true;
3940    if (DBG_CFG || DBG_SELECTED) {
3941      db("Added CFG edge from " + currentBBLE.block + " to " + targetbble.block);
3942    }
3943    return targetbble.block.makeJumpTarget();
3944  }
3945
3946  // GOTO
3947  private Instruction _gotoHelper(int offset) {
3948    return Goto.create(GOTO, generateTarget(offset));
3949  }
3950
3951  // helper function for if?? bytecodes
3952  private Instruction _intIfHelper(ConditionOperand cond) {
3953    int offset = bcodes.getBranchOffset();
3954    Operand op0 = popInt();
3955    if (offset == 3) {
3956      return null;             // remove frivolous IFs
3957    }
3958    if (CF_INTIF && op0 instanceof IntConstantOperand) {
3959      int c = cond.evaluate(((IntConstantOperand) op0).value, 0);
3960      if (c == ConditionOperand.TRUE) {
3961        if (DBG_CF) {
3962          db(cond + ": changed branch to goto because predicate (" + op0 + ") is constant true");
3963        }
3964        return _gotoHelper(offset);
3965      } else if (c == ConditionOperand.FALSE) {
3966        if (DBG_CF) {
3967          db(cond + ": eliminated branch because predicate (" + op0 + ") is constant false");
3968        }
3969        return null;
3970      }
3971    }
3972    fallThrough = true;
3973    if (!(op0 instanceof RegisterOperand)) {
3974      if (DBG_CF) db("generated int_ifcmp of " + op0 + " with 0");
3975      RegisterOperand guard = gc.getTemps().makeTempValidation();
3976      return IfCmp.create(INT_IFCMP,
3977                          guard,
3978                          op0,
3979                          new IntConstantOperand(0),
3980                          cond,
3981                          generateTarget(offset),
3982                          gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
3983    }
3984    RegisterOperand val = (RegisterOperand) op0;
3985    BranchOperand branch = null;
3986    if (lastInstr != null) {
3987      switch (lastInstr.getOpcode()) {
3988        case INSTANCEOF_opcode:
3989        case INSTANCEOF_UNRESOLVED_opcode: {
3990          if (DBG_TYPE) db("last instruction was instanceof");
3991          RegisterOperand res = InstanceOf.getResult(lastInstr);
3992          if (DBG_TYPE) db("result was in " + res + ", we are checking " + val);
3993          if (val.getRegister() != res.getRegister()) {
3994            break;            // not our value
3995          }
3996          Operand ref = InstanceOf.getRef(lastInstr);
3997          // should've been constant folded anyway
3998          if (!(ref instanceof RegisterOperand)) {
3999            break;
4000          }
4001          RegisterOperand guard = null;
4002          // Propagate types and non-nullness along the CFG edge where we
4003          // know that refReg is an instanceof type2
4004          RegisterOperand refReg = (RegisterOperand) ref;
4005          TypeReference type2 = InstanceOf.getType(lastInstr).getTypeRef();
4006          if (cond.isNOT_EQUAL()) {
4007            // IS an instance of on the branch-taken edge
4008            boolean generated = false;
4009            if (refReg.getRegister().isLocal()) {
4010              int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType());
4011              if (locNum != -1) {
4012                Operand loc = getLocal(locNum);
4013                if (loc instanceof RegisterOperand) {
4014                  if (DBG_TYPE) {
4015                    db(val +
4016                       " is from instanceof test, propagating new type of " +
4017                       refReg +
4018                       " (" +
4019                       type2 +
4020                       ") to basic block at " +
4021                       offset);
4022                  }
4023                  RegisterOperand locr = (RegisterOperand) loc;
4024                  RegisterOperand tlocr = locr.copyU2U();
4025                  guard = gc.makeNullCheckGuard(tlocr.getRegister());
4026                  setGuardForRegOp(tlocr, guard.copyD2U());
4027                  tlocr.clearDeclaredType();
4028                  tlocr.clearPreciseType();
4029                  tlocr.setType(type2);
4030                  setLocal(locNum, tlocr);
4031                  branch = generateTarget(offset);
4032                  generated = true;
4033                  setLocal(locNum, locr);
4034                }
4035              }
4036            }
4037            if (!generated) {
4038              branch = generateTarget(offset);
4039            }
4040          } else if (cond.isEQUAL()) {
4041            // IS an instance of on the fallthrough edge.
4042            branch = generateTarget(offset);
4043            if (refReg.getRegister().isLocal()) {
4044              int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType());
4045              if (locNum != -1) {
4046                Operand loc = getLocal(locNum);
4047                if (loc instanceof RegisterOperand) {
4048                  if (DBG_TYPE) {
4049                    db(val +
4050                       " is from instanceof test, propagating new type of " +
4051                       refReg +
4052                       " (" +
4053                       type2 +
4054                       ") along fallthrough edge");
4055                  }
4056                  RegisterOperand locr = (RegisterOperand) loc;
4057                  guard = gc.makeNullCheckGuard(locr.getRegister());
4058                  setGuardForRegOp(locr, guard.copyD2U());
4059                  locr.clearDeclaredType();
4060                  locr.clearPreciseType();
4061                  locr.setType(type2);
4062                  setLocal(locNum, loc);
4063                }
4064              }
4065            }
4066          }
4067          if (guard == null) {
4068            guard = gc.getTemps().makeTempValidation();
4069          }
4070          return IfCmp.create(INT_IFCMP,
4071                              guard,
4072                              val,
4073                              new IntConstantOperand(0),
4074                              cond,
4075                              branch,
4076                              gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
4077        }
4078        case INSTANCEOF_NOTNULL_opcode: {
4079          if (DBG_TYPE) db("last instruction was instanceof");
4080          RegisterOperand res = InstanceOf.getResult(lastInstr);
4081          if (DBG_TYPE) {
4082            db("result was in " + res + ", we are checking " + val);
4083          }
4084          if (val.getRegister() != res.getRegister()) {
4085            break;            // not our value
4086          }
4087          Operand ref = InstanceOf.getRef(lastInstr);
4088          // should've been constant folded anyway
4089          if (!(ref instanceof RegisterOperand)) {
4090            break;
4091          }
4092          // Propagate types along the CFG edge where we know that
4093          // refReg is an instanceof type2
4094          RegisterOperand refReg = (RegisterOperand) ref;
4095          TypeReference type2 = InstanceOf.getType(lastInstr).getTypeRef();
4096          if (cond.isNOT_EQUAL()) {
4097            // IS an instance of on the branch-taken edge
4098            boolean generated = false;
4099            if (refReg.getRegister().isLocal()) {
4100              int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType());
4101              if (locNum != -1) {
4102                Operand loc = getLocal(locNum);
4103                if (loc instanceof RegisterOperand) {
4104                  if (DBG_TYPE) {
4105                    db(val +
4106                       " is from instanceof test, propagating new type of " +
4107                       refReg +
4108                       " (" +
4109                       type2 +
4110                       ") to basic block at " +
4111                       offset);
4112                  }
4113                  RegisterOperand locr = (RegisterOperand) loc;
4114                  RegisterOperand tlocr = locr.copyU2U();
4115                  tlocr.clearDeclaredType();
4116                  tlocr.clearPreciseType();
4117                  tlocr.setType(type2);
4118                  setLocal(locNum, tlocr);
4119                  branch = generateTarget(offset);
4120                  generated = true;
4121                  setLocal(locNum, locr);
4122                }
4123              }
4124            }
4125            if (!generated) {
4126              branch = generateTarget(offset);
4127            }
4128          } else if (cond.isEQUAL()) {
4129            // IS an instance of on the fallthrough edge.
4130            branch = generateTarget(offset);
4131            if (refReg.getRegister().isLocal()) {
4132              int locNum = gc.getLocalNumberFor(refReg.getRegister(), refReg.getType());
4133              if (locNum != -1) {
4134                Operand loc = getLocal(locNum);
4135                if (loc instanceof RegisterOperand) {
4136                  if (DBG_TYPE) {
4137                    db(val +
4138                       " is from instanceof test, propagating new type of " +
4139                       refReg +
4140                       " (" +
4141                       type2 +
4142                       ") along fallthrough edge");
4143                  }
4144                  RegisterOperand locr = (RegisterOperand) loc;
4145                  locr.setType(type2);
4146                  locr.clearDeclaredType();
4147                  setLocal(locNum, loc);
4148                }
4149              }
4150            }
4151          }
4152          RegisterOperand guard = gc.getTemps().makeTempValidation();
4153          return IfCmp.create(INT_IFCMP,
4154                              guard,
4155                              val,
4156                              new IntConstantOperand(0),
4157                              cond,
4158                              branch,
4159                              gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
4160        }
4161        case DOUBLE_CMPG_opcode:
4162        case DOUBLE_CMPL_opcode:
4163        case FLOAT_CMPG_opcode:
4164        case FLOAT_CMPL_opcode:
4165        case LONG_CMP_opcode: {
4166          RegisterOperand res = Binary.getResult(lastInstr);
4167          if (val.getRegister() != res.getRegister()) {
4168            break;            // not our value
4169          }
4170          Operator operator = null;
4171          switch (lastInstr.getOpcode()) {
4172            case DOUBLE_CMPG_opcode:
4173              cond.translateCMPG();
4174              operator = DOUBLE_IFCMP;
4175              break;
4176            case DOUBLE_CMPL_opcode:
4177              cond.translateCMPL();
4178              operator = DOUBLE_IFCMP;
4179              break;
4180            case FLOAT_CMPG_opcode:
4181              cond.translateCMPG();
4182              operator = FLOAT_IFCMP;
4183              break;
4184            case FLOAT_CMPL_opcode:
4185              cond.translateCMPL();
4186              operator = FLOAT_IFCMP;
4187              break;
4188            case LONG_CMP_opcode:
4189              operator = LONG_IFCMP;
4190              break;
4191            default:
4192              OptimizingCompilerException.UNREACHABLE();
4193              break;
4194          }
4195          Operand val1 = Binary.getClearVal1(lastInstr);
4196          Operand val2 = Binary.getClearVal2(lastInstr);
4197          if (!(val1 instanceof RegisterOperand)) {
4198            // swap operands
4199            Operand temp = val1;
4200            val1 = val2;
4201            val2 = temp;
4202            cond = cond.flipOperands();
4203          }
4204          lastInstr.remove();
4205          lastInstr = null;
4206          branch = generateTarget(offset);
4207          RegisterOperand guard = gc.getTemps().makeTempValidation();
4208          return IfCmp.create(operator,
4209                              guard,
4210                              val1,
4211                              val2,
4212                              cond,
4213                              branch,
4214                              gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
4215        }
4216        default:
4217          // Fall through and Insert INT_IFCMP
4218          break;
4219      }
4220    }
4221    branch = generateTarget(offset);
4222    RegisterOperand guard = gc.getTemps().makeTempValidation();
4223    return IfCmp.create(INT_IFCMP,
4224                        guard,
4225                        val,
4226                        new IntConstantOperand(0),
4227                        cond,
4228                        branch,
4229                        gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
4230  }
4231
4232  // helper function for if_icmp?? bytecodes
4233  private Instruction _intIfCmpHelper(ConditionOperand cond) {
4234    int offset = bcodes.getBranchOffset();
4235    Operand op1 = popInt();
4236    Operand op0 = popInt();
4237    if (offset == 3) {
4238      return null;             // remove frivolous INF_IFCMPs
4239    }
4240    if (!(op0 instanceof RegisterOperand)) {
4241      // swap operands
4242      Operand temp = op0;
4243      op0 = op1;
4244      op1 = temp;
4245      cond = cond.flipOperands();
4246    }
4247    if (CF_INTIFCMP && (op0 instanceof IntConstantOperand) && (op1 instanceof IntConstantOperand)) {
4248      int c = cond.evaluate(((IntConstantOperand) op0).value, ((IntConstantOperand) op1).value);
4249      if (c == ConditionOperand.TRUE) {
4250        if (DBG_CF) {
4251          db(cond + ": changed branch to goto because predicate (" + op0 + ", " + op1 + ") is constant true");
4252        }
4253        return _gotoHelper(offset);
4254      } else if (c == ConditionOperand.FALSE) {
4255        if (DBG_CF) {
4256          db(cond + ": eliminated branch because predicate (" + op0 + "," + op1 + ") is constant false");
4257        }
4258        return null;
4259      }
4260    }
4261    fallThrough = true;
4262    RegisterOperand guard = gc.getTemps().makeTempValidation();
4263    return IfCmp.create(INT_IFCMP,
4264                        guard,
4265                        op0,
4266                        op1,
4267                        cond,
4268                        generateTarget(offset),
4269                        gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
4270  }
4271
4272  // helper function for ifnull/ifnonnull bytecodes
4273  private Instruction _refIfNullHelper(ConditionOperand cond) {
4274    if (VM.VerifyAssertions) opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL());
4275    int offset = bcodes.getBranchOffset();
4276    Operand op0 = popRef();
4277    if (offset == 3) {
4278      return null;             // remove frivolous REF_IFs
4279    }
4280    if (CF_REFIF) {
4281      if (op0.isDefinitelyNull()) {
4282        if (cond.isEQUAL()) {
4283          if (DBG_CF) {
4284            db(cond + ": changed branch to goto because predicate is true");
4285          }
4286          return _gotoHelper(offset);
4287        } else {
4288          if (DBG_CF) {
4289            db(cond + ": eliminated branch because predicate is false");
4290          }
4291          return null;
4292        }
4293      }
4294      if (isNonNull(op0)) {
4295        if (cond.isNOT_EQUAL()) {
4296          if (DBG_CF) {
4297            db(cond + ": changed branch to goto because predicate is true");
4298          }
4299          return _gotoHelper(offset);
4300        } else {
4301          if (DBG_CF) {
4302            db(cond + ": eliminated branch because predicate is false");
4303          }
4304          return null;
4305        }
4306      }
4307    }
4308    RegisterOperand ref = (RegisterOperand) op0;
4309    BranchOperand branch = null;
4310    RegisterOperand guard = null;
4311
4312    // Check for incorrect null checks on unboxed types
4313    if (ref.getType().isUnboxedType()) {
4314      throw new OptimizingCompilerException("Detected incorrect null check of unboxed type in " +
4315          gc.getMethod() + " at bytecode index " + instrIndex + " from class " +
4316          gc.getMethod().getDeclaringClass() +
4317          " . Use the methods provided on the unboxed types to do null checks!");
4318    }
4319
4320    if (cond.isEQUAL()) {
4321      branch = generateTarget(offset);
4322      if (ref.getRegister().isLocal()) {
4323        int locNum = gc.getLocalNumberFor(ref.getRegister(), ref.getType());
4324        if (locNum != -1) {
4325          Operand loc = getLocal(locNum);
4326          if (loc instanceof RegisterOperand) {
4327            RegisterOperand locr = (RegisterOperand) loc;
4328            guard = gc.makeNullCheckGuard(locr.getRegister());
4329            setGuardForRegOp(locr, guard.copyD2U());
4330            setLocal(locNum, loc);
4331          }
4332        }
4333      }
4334    } else {
4335      boolean generated = false;
4336      if (ref.getRegister().isLocal()) {
4337        int locNum = gc.getLocalNumberFor(ref.getRegister(), ref.getType());
4338        if (locNum != -1) {
4339          Operand loc = getLocal(locNum);
4340          if (loc instanceof RegisterOperand) {
4341            RegisterOperand locr = (RegisterOperand) loc;
4342            RegisterOperand tlocr = locr.copyU2U();
4343            guard = gc.makeNullCheckGuard(locr.getRegister());
4344            setGuardForRegOp(tlocr, guard.copyD2U());
4345            setLocal(locNum, tlocr);
4346            branch = generateTarget(offset);
4347            generated = true;
4348            setLocal(locNum, locr);
4349          }
4350        }
4351      }
4352      if (!generated) {
4353        branch = generateTarget(offset);
4354      }
4355    }
4356    fallThrough = true;
4357    if (guard == null) {
4358      guard = gc.getTemps().makeTempValidation();
4359    }
4360    return IfCmp.create(REF_IFCMP,
4361                        guard,
4362                        ref,
4363                        new NullConstantOperand(),
4364                        cond,
4365                        branch,
4366                        gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
4367  }
4368
4369  // helper function for if_acmp?? bytecodes
4370  private Instruction _refIfCmpHelper(ConditionOperand cond) {
4371    if (VM.VerifyAssertions) opt_assert(cond.isEQUAL() || cond.isNOT_EQUAL());
4372    int offset = bcodes.getBranchOffset();
4373    Operand op1 = popRef();
4374    Operand op0 = popRef();
4375    if (offset == 3) {
4376      return null;             // remove frivolous REF_IFCMPs
4377    }
4378    if (!(op0 instanceof RegisterOperand)) {
4379      // swap operands
4380      Operand temp = op0;
4381      op0 = op1;
4382      op1 = temp;
4383      cond = cond.flipOperands();
4384    }
4385    if (CF_REFIFCMP && op0.isDefinitelyNull() && op1.isDefinitelyNull()) {
4386      if (cond.isEQUAL()) {
4387        if (DBG_CF) {
4388          db(cond + ": changed branch to goto because predicate is true");
4389        }
4390        return _gotoHelper(offset);
4391      } else {
4392        if (DBG_CF) {
4393          db(cond + ": eliminated branch because predicate is false");
4394        }
4395        return null;
4396      }
4397    }
4398
4399    // Check for incorrect comparison operators on unboxed types
4400    if (op0.isRegister()) {
4401      RegisterOperand op0Reg = op0.asRegister();
4402      if (op0Reg.getType().isUnboxedType()) {
4403        throw new OptimizingCompilerException("Detected incorrect comparison of unboxed types in " +
4404            gc.getMethod() + " at bytecode index " + instrIndex + " from class " +
4405            gc.getMethod().getDeclaringClass() +
4406            " . Use the methods provided on the unboxed types to do comparisons!");
4407      }
4408    }
4409    if (op1.isRegister()) {
4410      RegisterOperand op1Reg = op1.asRegister();
4411      if (op1Reg.getType().isUnboxedType()) {
4412        throw new OptimizingCompilerException("Detected incorrect comparison of unboxed types in " +
4413            gc.getMethod() + " at bytecode index " + instrIndex + " from class " +
4414            gc.getMethod().getDeclaringClass() +
4415            " . Use the methods provided on the unboxed types to do comparisons!");
4416      }
4417    }
4418
4419    fallThrough = true;
4420    RegisterOperand guard = gc.getTemps().makeTempValidation();
4421    return IfCmp.create(REF_IFCMP,
4422                        guard,
4423                        op0,
4424                        op1,
4425                        cond,
4426                        generateTarget(offset),
4427                        gc.getConditionalBranchProfileOperand(instrIndex - bciAdjustment, offset < 0));
4428  }
4429
4430////REPLACE LOCALS ON STACK.
4431  //
4432
4433
4434
4435  /**
4436   * Replaces copies of local {@code <#index,type>} with
4437   * newly-generated temporaries, and generates the necessary move instructions.
4438   * @param index the local's index
4439   * @param type the local's type
4440   */
4441  private void replaceLocalsOnStack(int index, TypeReference type) {
4442    int i;
4443    int size = stack.getSize();
4444    for (i = 0; i < size; ++i) {
4445      Operand op = stack.getFromTop(i);
4446      if (gc.isLocal(op, index, type)) {
4447        RegisterOperand lop = (RegisterOperand) op;
4448        RegisterOperand t = gc.getTemps().makeTemp(lop);
4449        Instruction s = Move.create(IRTools.getMoveOp(t.getType()), t, op);
4450        stack.replaceFromTop(i, t.copyD2U());
4451        s.position = gc.getInlineSequence();
4452        s.bcIndex = instrIndex;
4453        if (DBG_LOCAL || DBG_SELECTED) {
4454          db("replacing local " + index + " at " + i + " from tos with " + t);
4455        }
4456        appendInstruction(s);
4457      }
4458    }
4459  }
4460
4461  //////////
4462  // EXCEPTION HANDLERS.
4463
4464  //////////
4465  // Some common cases to make the code more readable...
4466
4467  private BasicBlock rectifyStateWithNullPtrExceptionHandler() {
4468    return rectifyStateWithNullPtrExceptionHandler(false);
4469  }
4470
4471  private BasicBlock rectifyStateWithArrayBoundsExceptionHandler() {
4472    return rectifyStateWithArrayBoundsExceptionHandler(false);
4473  }
4474
4475  private BasicBlock rectifyStateWithArithmeticExceptionHandler() {
4476    return rectifyStateWithArithmeticExceptionHandler(false);
4477  }
4478
4479  private BasicBlock rectifyStateWithArrayStoreExceptionHandler() {
4480    return rectifyStateWithArrayStoreExceptionHandler(false);
4481  }
4482
4483  private BasicBlock rectifyStateWithErrorHandler() {
4484    return rectifyStateWithErrorHandler(false);
4485  }
4486
4487  public void rectifyStateWithExceptionHandlers() {
4488    rectifyStateWithExceptionHandlers(false);
4489  }
4490
4491  public BasicBlock rectifyStateWithExceptionHandler(TypeReference exceptionType) {
4492    return rectifyStateWithExceptionHandler(exceptionType, false);
4493  }
4494
4495  private BasicBlock rectifyStateWithNullPtrExceptionHandler(boolean linkToExitIfUncaught) {
4496    TypeReference et = TypeReference.JavaLangNullPointerException;
4497    return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught);
4498  }
4499
4500  private BasicBlock rectifyStateWithArrayBoundsExceptionHandler(boolean linkToExitIfUncaught) {
4501    TypeReference et = TypeReference.JavaLangArrayIndexOutOfBoundsException;
4502    return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught);
4503  }
4504
4505  private BasicBlock rectifyStateWithArithmeticExceptionHandler(boolean linkToExitIfUncaught) {
4506    TypeReference et = TypeReference.JavaLangArithmeticException;
4507    return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught);
4508  }
4509
4510  private BasicBlock rectifyStateWithArrayStoreExceptionHandler(boolean linkToExitIfUncaught) {
4511    TypeReference et = TypeReference.JavaLangArrayStoreException;
4512    return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught);
4513  }
4514
4515  private BasicBlock rectifyStateWithErrorHandler(boolean linkToExitIfUncaught) {
4516    TypeReference et = TypeReference.JavaLangError;
4517    return rectifyStateWithExceptionHandler(et, linkToExitIfUncaught);
4518  }
4519
4520  // If exactly 1 catch block is guarenteed to catch the exception,
4521  // then we return it.
4522  // Returning null means that no such block was found.
4523  private BasicBlock rectifyStateWithExceptionHandler(TypeReference exceptionType,
4524                                                          boolean linkToExitIfUncaught) {
4525    currentBBLE.block.setCanThrowExceptions();
4526    int catchTargets = 0;
4527    if (DBG_EX) db("\tchecking exceptions of " + currentBBLE.block);
4528    if (currentBBLE.handlers != null) {
4529      for (HandlerBlockLE xbble : currentBBLE.handlers) {
4530        if (DBG_EX) db("\texception block " + xbble.entryBlock);
4531        byte mustCatch = xbble.mustCatchException(exceptionType);
4532        if (mustCatch != NO || xbble.mayCatchException(exceptionType) != NO) {
4533          if (DBG_EX) {
4534            db("PEI of type " + exceptionType + " could be caught by " + xbble + " rectifying locals");
4535          }
4536          catchTargets++;
4537          blocks.rectifyLocals(_localState, xbble);
4538          currentBBLE.block.insertOut(xbble.entryBlock);
4539          if (DBG_CFG || DBG_SELECTED) {
4540            db("Added CFG edge from " + currentBBLE.block + " to " + xbble.entryBlock);
4541          }
4542        }
4543        if (mustCatch == YES) {
4544          if (DBG_EX) {
4545            db("\t" + xbble + " will defintely catch exceptions of type " + exceptionType);
4546          }
4547          if (DBG_EX && catchTargets == 1) {
4548            db("\t  and it is the only target");
4549          }
4550          return (catchTargets == 1) ? xbble.entryBlock : null;
4551        }
4552      }
4553    }
4554    // Now, consider the enclosing exception context.
4555    // NOTE: Because the locals of the current method can't
4556    // possibly matter to the locals of the enclosing method, it is
4557    // sufficient to add a CFG edge (no need to rectify locals).
4558    // It is the responsibility of the BC2IR object generating the
4559    // caller method to ensure that the exposed handler blocks are
4560    // generated if they are reachable from a callee.
4561    // See maybeInlineMethod.
4562    if (gc.getEnclosingHandlers() != null) {
4563      for (Enumeration<BasicBlock> e = gc.getEnclosingHandlers().enumerator(); e.hasMoreElements();) {
4564        ExceptionHandlerBasicBlock xbb = (ExceptionHandlerBasicBlock) e.nextElement();
4565        byte mustCatch = xbb.mustCatchException(exceptionType);
4566        if (mustCatch != NO || xbb.mayCatchException(exceptionType) != NO) {
4567          if (DBG_EX) {
4568            db("PEI of type " + exceptionType + " could be caught by enclosing handler " + xbb);
4569          }
4570          catchTargets++;
4571          currentBBLE.block.insertOut(xbb);
4572          if (DBG_CFG || DBG_SELECTED) {
4573            db("Added CFG edge from " + currentBBLE.block + " to " + xbb);
4574          }
4575        }
4576        if (mustCatch == YES) {
4577          if (DBG_EX) {
4578            db("\t" + xbb + " will defintely catch exceptions of type " + exceptionType);
4579          }
4580          if (DBG_EX && catchTargets == 1) {
4581            db("\t  and it is the only target");
4582          }
4583          return (catchTargets == 1) ? xbb : null;
4584        }
4585      }
4586    }
4587    // If we get to here, then we didn't find a handler block that
4588    // is guarenteed to catch the exception. Therefore deal with the
4589    // possibly uncaught exception.
4590    currentBBLE.block.setMayThrowUncaughtException();
4591    if (linkToExitIfUncaught) {
4592      if (DBG_EX) {
4593        db("added explicit edge from " + currentBBLE + " to outermost exit");
4594      }
4595      currentBBLE.block.insertOut(gc.getExit());
4596      if (DBG_CFG || DBG_SELECTED) {
4597        db("Added CFG edge from " + currentBBLE.block + " to exit");
4598      }
4599    }
4600    return null;
4601  }
4602
4603  /*
4604   * Very similar to the above, but since we aren't told what might be thrown,
4605   * we are forced to connect to every in scope handler and can't
4606   * identify a definite target.
4607   *
4608   */
4609  private void rectifyStateWithExceptionHandlers(boolean linkToExitIfUncaught) {
4610    currentBBLE.block.setCanThrowExceptions();
4611    currentBBLE.block.setMayThrowUncaughtException();
4612    if (linkToExitIfUncaught) {
4613      if (DBG_EX) {
4614        db("PEI of unknown type caused edge from " + currentBBLE + " to outermost exit");
4615      }
4616      currentBBLE.block.insertOut(gc.getExit());
4617      if (DBG_CFG || DBG_SELECTED) {
4618        db("Added CFG edge from " + currentBBLE.block + " to exit");
4619      }
4620    }
4621    if (currentBBLE.handlers != null) {
4622      for (HandlerBlockLE xbble : currentBBLE.handlers) {
4623        if (DBG_EX) {
4624          db("PEI of unknown type could be caught by " + xbble + " rectifying locals");
4625        }
4626        blocks.rectifyLocals(_localState, xbble);
4627        currentBBLE.block.insertOut(xbble.entryBlock);
4628        if (DBG_CFG || DBG_SELECTED) {
4629          db("Added CFG edge from " + currentBBLE.block + " to " + xbble.entryBlock);
4630        }
4631      }
4632    }
4633    // Now, consider the enclosing exception context; ditto NOTE above.
4634    if (gc.getEnclosingHandlers() != null) {
4635      for (Enumeration<BasicBlock> e = gc.getEnclosingHandlers().enumerator(); e.hasMoreElements();) {
4636        ExceptionHandlerBasicBlock xbb = (ExceptionHandlerBasicBlock) e.nextElement();
4637        if (DBG_EX) {
4638          db("PEI of unknown type could be caught by enclosing handler " + xbb);
4639        }
4640        currentBBLE.block.insertOut(xbb);
4641        if (DBG_CFG || DBG_SELECTED) {
4642          db("Added CFG edge from " + currentBBLE.block + " to " + xbb);
4643        }
4644      }
4645    }
4646  }
4647
4648  //////////
4649  // INLINING support
4650  //////////
4651  /**
4652   * Should we inline a call site?
4653   *
4654   * @param call the call instruction being considered for inlining
4655   * @param isExtant is the receiver of a virtual method an extant object?
4656   * @param realBCI the real bytecode index of the call instruction, not adjusted because of OSR
4657   * @return the inline decision (which cannot be {@code null})
4658   */
4659  private InlineDecision shouldInline(Instruction call, boolean isExtant, int realBCI) {
4660    if (Call.getMethod(call).getTarget() == null) {
4661      return InlineDecision.NO("Target method is null");
4662    }
4663    CompilationState state = new CompilationState(call, isExtant, gc.getOptions(), gc.getOriginalCompiledMethod(), realBCI);
4664    InlineDecision d = gc.getInlinePlan().shouldInline(state);
4665    return d;
4666  }
4667
4668  /**
4669   * Attempt to inline a method. This may fail.
4670   *
4671   * @param inlDec the inline decision for this call site
4672   * @param callSite the call instruction we are attempting to inline
4673   * @return {@code true} if inlining succeeded, {@code false} otherwise
4674   */
4675  private boolean maybeInlineMethod(InlineDecision inlDec, Instruction callSite) {
4676    if (inlDec.isNO()) {
4677      return false;
4678    }
4679
4680    // Insert OsrBarrier point before the callsite which is going to be
4681    // inlined. The callee can find this barrier via its generation context.
4682
4683    // verify it
4684    if (this.osrGuardedInline) {
4685      if (VM.VerifyAssertions) opt_assert(lastOsrBarrier != null);
4686      gc.saveOSRBarrierForInst(lastOsrBarrier, callSite);
4687    }
4688
4689    // Execute the inline decision.
4690    // NOTE: It is tempting to wrap the call to Inliner.execute in
4691    // a try/catch block that suppresses MagicNotImplemented failures
4692    // by "backing out" the attempted inlining of a method that contained
4693    // an unimplemented magic.  Unfortunately, this is somewhat hard to do
4694    // cleanly, since exceptional control flow can inject control flow graph
4695    // edges from inlinedContext to blocks in the enclosing caller CFG.
4696    // These are not easy to find and remove because inlinedContext is not
4697    // well-formed (the exception was thrown while generating the IR, in
4698    // particular before calling finalPass, therefore the inlined CFG
4699    // is not formed and finding all of its member blocks is somewhat awkward).
4700    // We could write code to deal with this, but since in practice the
4701    // opt compiler implements all but a few fringe magics, it is just fine
4702    // to completely give up rather than take heroic measures here.
4703    // In a few cases we do care about, we use NoInlinePragma to
4704    // prevent the opt compiler from inlining a method that contains an
4705    // unimplemented magic.
4706    GenerationContext inlinedContext =
4707        Inliner.execute(inlDec, gc, currentBBLE.block.exceptionHandlers, callSite);
4708
4709    inlinedSomething = true;
4710    // TODO: We're currently not keeping track if any of the
4711    // enclosing exception handlers are actually reachable from
4712    // this inlined callee.
4713    // Therefore we simply force all of them to be generated wrt
4714    // the state of the local variables in currentBBLE.
4715    // This can result in generating unreachable handlers
4716    // (if no PEI can reach them) and in generating suboptimal
4717    // catch blocks (by merging in currentBBLE's local state
4718    // into catch blocks that can't actually be reached from the inlined CFG).
4719    // I strongly suspect it's not worth worrying about this.....
4720    // dead code elimination should zap the unreachable handlers,
4721    // and we shouldn't care too  much about the
4722    // optimization possibilities lost by the extra local rectification.
4723    // Especially since the odds of currentBBLE actually having
4724    // unreachable handler blocks is darn close to zero. --dave 9/21/99.
4725    // NOTE: No need to add CFG edges (they were added as needed
4726    // during generation of the callee)
4727    if (currentBBLE.handlers != null) {
4728      for (HandlerBlockLE handler : currentBBLE.handlers) {
4729        blocks.rectifyLocals(_localState, handler);
4730      }
4731    }
4732    if (inlinedContext.getEpilogue() != null) {
4733      // Wrap a synthetic BBLE around GenerationContext.epilogue and
4734      // pass it as from to getOrCreateBlock.
4735      // This causes any compensation code inserted by getOrCreateBlock
4736      // into the epilogue of the inlined method (see inlineTest7)
4737      BasicBlockLE epilogueBBLE = new BasicBlockLE(0);
4738      epilogueBBLE.block = inlinedContext.getEpilogue();
4739      if (inlinedContext.getResult() != null) {
4740        // If the call has a result, _callHelper allocated a new
4741        // temp for it and pushed it onto the expression stack.
4742        // But, since we successfully inlined the call and
4743        // inlinedContext.epilogue != null,
4744        // we can use inlinedContext.result to obtain better
4745        // downstream information about the inlined callee's return value.
4746        // Therefore we'll pop the old callSite.result off the stack
4747        // and push result instead.
4748        // NOTE: It's critical that we pop callSite.result
4749        // _before_ we copy the stack state into epilogueBBLE!
4750        // Otherwise we'll end up with bogus code in the inlined
4751        // method's prologue due to stack saving!!!!
4752        TypeReference resultType = Call.getResult(callSite).getType();
4753        pop(resultType);        // throw away callSite.result
4754      }
4755      blocks.rectifyStacks(currentBBLE.block, stack, epilogueBBLE);
4756      if (inlinedContext.getResult() != null) {
4757        TypeReference resultType = Call.getResult(callSite).getType();
4758        push(inlinedContext.getResult(), resultType);
4759      }
4760      epilogueBBLE.copyIntoLocalState(_localState);
4761      BasicBlockLE afterBBLE = blocks.getOrCreateBlock(bcodes.index(), epilogueBBLE, stack, _localState);
4762      // Create the InliningBlockLE and initialize fallThrough links.
4763      InliningBlockLE inlinedCallee = new InliningBlockLE(inlinedContext, epilogueBBLE);
4764      currentBBLE.fallThrough = inlinedCallee;
4765      currentBBLE.block.insertOut(inlinedCallee.gc.getCfg().firstInCodeOrder());
4766      epilogueBBLE.fallThrough = afterBBLE;
4767      epilogueBBLE.block.insertOut(epilogueBBLE.fallThrough.block);
4768    } else {
4769      // All exits from the callee were via throws.
4770      // Therefore the next basic block is unreachable (unless
4771      // there is a branch to it from somewhere else in the current method,
4772      // which will naturally be handled when we generate the branch).
4773      InliningBlockLE inlinedCallee = new InliningBlockLE(inlinedContext, null);
4774      currentBBLE.fallThrough = inlinedCallee;
4775      currentBBLE.block.insertOut(inlinedCallee.gc.getCfg().firstInCodeOrder());
4776    }
4777    endOfBasicBlock = true;
4778    return true;
4779  }
4780
4781  /* create an OSR Barrier instruction at the current position.
4782   */
4783  private Instruction _createOsrBarrier() {
4784    ArrayList<Operand> livevars = new ArrayList<Operand>();
4785
4786    /* for local variables, we have to use helper to make a register. */
4787    /* ltypes and stypes should be the full length
4788     * WARNING: what's the order of DUMMY and LONG?
4789     */
4790    int localnum = _localState.length;
4791    byte[] ltypes = new byte[localnum];
4792
4793    int num_llocals = 0;
4794    for (int i = 0, n = _localState.length; i < n; i++) {
4795      Operand op = _localState[i];
4796
4797      if ((op != null) && (op != DUMMY)) {
4798        livevars.add(_loadLocalForOSR(op));
4799        num_llocals++;
4800
4801        if (op instanceof ReturnAddressOperand) {
4802          ltypes[i] = ReturnAddressTypeCode;
4803        } else {
4804          TypeReference typ = op.getType();
4805          if (typ.isWordLikeType() || (typ == TypeReference.NULL_TYPE)) {
4806            ltypes[i] = WordTypeCode;
4807          } else {
4808            ltypes[i] = typ.getName().parseForTypeCode();
4809          }
4810        }
4811
4812      } else {
4813        ltypes[i] = VoidTypeCode;
4814      }
4815    }
4816    int stacknum = stack.getSize();
4817    byte[] stypes = new byte[stacknum];
4818
4819    /* the variable on stack can be used directly ? */
4820    int num_lstacks = 0;
4821    for (int i = 0, n = stack.getSize(); i < n; i++) {
4822      Operand op = stack.getFromBottom(i);
4823
4824      if ((op != null) && (op != DUMMY)) {
4825
4826        if (op.isRegister()) {
4827          livevars.add(op.asRegister().copyU2U());
4828        } else {
4829          livevars.add(op.copy());
4830        }
4831
4832        num_lstacks++;
4833
4834        if (op instanceof ReturnAddressOperand) {
4835          stypes[i] = ReturnAddressTypeCode;
4836        } else {
4837          TypeReference typ = op.getType();
4838          if (typ.isWordLikeType() || (typ == TypeReference.NULL_TYPE)) {
4839            stypes[i] = WordTypeCode;
4840          } else {
4841            /* for stack operand, reverse the order for long and double */
4842            byte tcode = typ.getName().parseForTypeCode();
4843            if ((tcode == LongTypeCode) || (tcode == DoubleTypeCode)) {
4844              stypes[i - 1] = tcode;
4845              stypes[i] = VoidTypeCode;
4846            } else {
4847              stypes[i] = tcode;
4848            }
4849          }
4850        }
4851
4852      } else {
4853        stypes[i] = VoidTypeCode;
4854      }
4855    }
4856
4857    Instruction barrier = OsrBarrier.create(OSR_BARRIER, null, // temporarily
4858                                                num_llocals + num_lstacks);
4859
4860    for (int i = 0, n = livevars.size(); i < n; i++) {
4861      Operand op = livevars.get(i);
4862      if (op instanceof ReturnAddressOperand) {
4863        int tgtpc = ((ReturnAddressOperand) op).retIndex - gc.getMethod().getOsrPrologueLength();
4864        op = new IntConstantOperand(tgtpc);
4865      } else if (op instanceof LongConstantOperand) {
4866        op = _prepareLongConstant(op);
4867      } else if (op instanceof DoubleConstantOperand) {
4868        op = _prepareDoubleConstant(op);
4869      }
4870
4871      if (VM.VerifyAssertions) opt_assert(op != null);
4872
4873      OsrBarrier.setElement(barrier, i, op);
4874    }
4875
4876    // patch type info operand
4877    OsrTypeInfoOperand typeinfo = new OsrTypeInfoOperand(ltypes, stypes);
4878
4879    OsrBarrier.setTypeInfo(barrier, typeinfo);
4880
4881    /* if the current method is for specialization, the bcIndex
4882     * has to be adjusted at "OsrPointConstructor".
4883     */
4884    barrier.position = gc.getInlineSequence();
4885    barrier.bcIndex = instrIndex;
4886
4887    return barrier;
4888  }
4889
4890  /**
4891   * special process for long/double constants
4892   * @param op a long constant
4893   * @return a new operand
4894   */
4895  private Operand _prepareLongConstant(Operand op) {
4896    /* for long and double constants, always move them to a register,
4897     * therefor, BURS will split it in two registers.
4898     */
4899    RegisterOperand t = gc.getTemps().makeTemp(op.getType());
4900    appendInstruction(Move.create(LONG_MOVE, t, op));
4901
4902    return t.copyD2U();
4903  }
4904
4905  /**
4906   * special process for long/double constants
4907   * @param op a double constant
4908   * @return a new operand
4909   */
4910  private Operand _prepareDoubleConstant(Operand op) {
4911    /* for long and double constants, always move them to a register,
4912     * therefor, BURS will split it in two registers.
4913     */
4914    RegisterOperand t = gc.getTemps().makeTemp(op.getType());
4915    appendInstruction(Move.create(DOUBLE_MOVE, t, op));
4916
4917    return t.copyD2U();
4918  }
4919
4920  /**
4921   * make a temporary register, and create a move instruction
4922   * @param op the local variable.
4923   * @return operand marked as use.
4924   */
4925  private Operand _loadLocalForOSR(Operand op) {
4926
4927    /* return address is processed specially */
4928    if (op instanceof ReturnAddressOperand) {
4929      return op;
4930    }
4931
4932    RegisterOperand t = gc.getTemps().makeTemp(op.getType());
4933
4934    byte tcode = op.getType().getName().parseForTypeCode();
4935
4936    Operator operator = null;
4937
4938    switch (tcode) {
4939      case ClassTypeCode:
4940      case ArrayTypeCode:
4941        operator = REF_MOVE;
4942        break;
4943      case BooleanTypeCode:
4944      case ByteTypeCode:
4945      case ShortTypeCode:
4946      case CharTypeCode:
4947      case IntTypeCode:
4948        operator = INT_MOVE;
4949        break;
4950      case LongTypeCode:
4951        operator = LONG_MOVE;
4952        break;
4953      case FloatTypeCode:
4954        operator = FLOAT_MOVE;
4955        break;
4956      case DoubleTypeCode:
4957        operator = DOUBLE_MOVE;
4958        break;
4959      case VoidTypeCode:
4960        return null;
4961    }
4962
4963    appendInstruction(Move.create(operator, t, op.copy()));
4964    return t.copyD2U();
4965  }
4966
4967  /**
4968   * Creates an OSR point instruction with its dependent OsrBarrier
4969   * which provides type and variable information.
4970   * The OsrPoint instruction is going to be refilled immediately
4971   * after BC2IR, before any other optimizations.
4972   *
4973   * @param barrier the OSR barrier instruction
4974   * @param gc context that has information about OSR
4975   * @return the osr point instruction
4976   */
4977  public static Instruction _osrHelper(Instruction barrier, GenerationContext gc) {
4978    Instruction inst = OsrPoint.create(YIELDPOINT_OSR, null,  // currently unknown
4979                                           0);    // currently unknown
4980    gc.saveOSRBarrierForInst(barrier, inst);
4981    return inst;
4982  }
4983
4984  //// LOCAL STATE.
4985  /**
4986   * Gets the specified local variable. This can return an RegisterOperand
4987   * which refers to the given local, or some other kind of operand (if the
4988   * local variable is assumed to contain a particular value.)
4989   *
4990   * @param i local variable number
4991   * @return a copy of the local variable
4992   */
4993  private Operand getLocal(int i) {
4994    Operand local = _localState[i];
4995    if (DBG_LOCAL || DBG_SELECTED) db("getting local " + i + " for use: " + local);
4996    return local.copy();
4997  }
4998
4999  /**
5000   * Gets the specified local variable (long, double). This can return an
5001   * RegisterOperand which refers to the given local, or some other kind
5002   * of operand (if the local variable is assumed to contain a given value.)
5003   *
5004   * @param i local variable number
5005   * @return a copy of the local variable
5006   */
5007  private Operand getLocalDual(int i) {
5008    if (VM.VerifyAssertions) opt_assert(_localState[i + 1] == DUMMY);
5009    Operand local = _localState[i];
5010    if (DBG_LOCAL || DBG_SELECTED) db("getting local " + i + " for use: " + local);
5011    return local.copy();
5012  }
5013
5014  /**
5015   * Set the specified local variable
5016   *
5017   * @param i local variable number
5018   * @param op Operand to store in the local
5019   */
5020  private void setLocal(int i, Operand op) {
5021    if (DBG_LOCAL || DBG_SELECTED) db("setting local " + i + " with " + op);
5022    _localState[i] = op;
5023  }
5024
5025  /**
5026   * Set the specified local variable
5027   *
5028   * @param i local variable number
5029   * @param op Operand to store in the local
5030   */
5031  private void setLocalDual(int i, Operand op) {
5032    if (DBG_LOCAL || DBG_SELECTED) db("setting dual local " + i + " with " + op);
5033    _localState[i] = op;
5034    _localState[i + 1] = DUMMY;
5035  }
5036
5037  /**
5038   * Dummy stack slot
5039   * @see BC2IR#DUMMY
5040   */
5041  private static final class DummyStackSlot extends Operand {
5042    @Override
5043    public Operand copy() {
5044      return this;
5045    }
5046
5047    @Override
5048    public boolean similar(Operand op) {
5049      return (op instanceof DummyStackSlot);
5050    }
5051
5052    @Override
5053    public String toString() {
5054      return "<DUMMY>";
5055    }
5056  }
5057}