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