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.hir2lir;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.classloader.RVMArray;
017    import org.jikesrvm.classloader.RVMClass;
018    import org.jikesrvm.classloader.DynamicTypeCheck;
019    import org.jikesrvm.classloader.RVMMethod;
020    import org.jikesrvm.classloader.RVMType;
021    import org.jikesrvm.classloader.TypeReference;
022    import org.jikesrvm.compilers.opt.OptimizingCompilerException;
023    import org.jikesrvm.compilers.opt.ir.ALoad;
024    import org.jikesrvm.compilers.opt.ir.Binary;
025    import org.jikesrvm.compilers.opt.ir.BooleanCmp;
026    import org.jikesrvm.compilers.opt.ir.Call;
027    import org.jikesrvm.compilers.opt.ir.Goto;
028    import org.jikesrvm.compilers.opt.ir.IfCmp;
029    import org.jikesrvm.compilers.opt.ir.IfCmp2;
030    import org.jikesrvm.compilers.opt.ir.InstanceOf;
031    import org.jikesrvm.compilers.opt.ir.Load;
032    import org.jikesrvm.compilers.opt.ir.Move;
033    import org.jikesrvm.compilers.opt.ir.BasicBlock;
034    import org.jikesrvm.compilers.opt.ir.IR;
035    import org.jikesrvm.compilers.opt.ir.Instruction;
036    import static org.jikesrvm.compilers.opt.ir.Operators.ARRAYLENGTH;
037    import static org.jikesrvm.compilers.opt.ir.Operators.BBEND;
038    import static org.jikesrvm.compilers.opt.ir.Operators.BOOLEAN_CMP_ADDR;
039    import static org.jikesrvm.compilers.opt.ir.Operators.CALL;
040    import static org.jikesrvm.compilers.opt.ir.Operators.GET_ARRAY_ELEMENT_TIB_FROM_TIB;
041    import static org.jikesrvm.compilers.opt.ir.Operators.GET_DOES_IMPLEMENT_FROM_TIB;
042    import static org.jikesrvm.compilers.opt.ir.Operators.GET_SUPERCLASS_IDS_FROM_TIB;
043    import static org.jikesrvm.compilers.opt.ir.Operators.GET_TYPE_FROM_TIB;
044    import static org.jikesrvm.compilers.opt.ir.Operators.GOTO;
045    import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_COMBINE;
046    import static org.jikesrvm.compilers.opt.ir.Operators.GUARD_MOVE;
047    import static org.jikesrvm.compilers.opt.ir.Operators.INT_2ADDRZerExt;
048    import static org.jikesrvm.compilers.opt.ir.Operators.INT_AND;
049    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP;
050    import static org.jikesrvm.compilers.opt.ir.Operators.INT_IFCMP2;
051    import static org.jikesrvm.compilers.opt.ir.Operators.INT_LOAD;
052    import static org.jikesrvm.compilers.opt.ir.Operators.INT_MOVE;
053    import static org.jikesrvm.compilers.opt.ir.Operators.INT_SHL;
054    import static org.jikesrvm.compilers.opt.ir.Operators.REF_IFCMP;
055    import static org.jikesrvm.compilers.opt.ir.Operators.REF_MOVE;
056    import static org.jikesrvm.compilers.opt.ir.Operators.TRAP;
057    import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_ALOAD;
058    import static org.jikesrvm.compilers.opt.ir.Operators.USHORT_LOAD;
059    import org.jikesrvm.compilers.opt.ir.StoreCheck;
060    import org.jikesrvm.compilers.opt.ir.Trap;
061    import org.jikesrvm.compilers.opt.ir.TypeCheck;
062    import org.jikesrvm.compilers.opt.ir.operand.BranchProfileOperand;
063    import org.jikesrvm.compilers.opt.ir.operand.ConditionOperand;
064    import org.jikesrvm.compilers.opt.ir.operand.IntConstantOperand;
065    import org.jikesrvm.compilers.opt.ir.operand.LocationOperand;
066    import org.jikesrvm.compilers.opt.ir.operand.MethodOperand;
067    import org.jikesrvm.compilers.opt.ir.operand.NullConstantOperand;
068    import org.jikesrvm.compilers.opt.ir.operand.Operand;
069    import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
070    import org.jikesrvm.compilers.opt.ir.operand.TrapCodeOperand;
071    import org.jikesrvm.compilers.opt.ir.operand.TrueGuardOperand;
072    import org.jikesrvm.runtime.Entrypoints;
073    import org.vmmagic.unboxed.Address;
074    import org.vmmagic.unboxed.Offset;
075    
076    /**
077     * Expansion of Dynamic Type Checking operations.
078     *
079     * @see DynamicTypeCheck
080     */
081    abstract class DynamicTypeCheckExpansion extends ConvertToLowLevelIR {
082    
083      /**
084       * Expand an instanceof instruction into the LIR sequence that implements
085       * the dynamic type check.  Ref may contain a null ptr at runtime.
086       *
087       * @param s an INSTANCEOF or INSTANCEOF_UNRESOLVED instruction to expand
088       * @param ir the enclosing IR
089       * @return the last Instruction in the generated LIR sequence.
090       */
091      static Instruction instanceOf(Instruction s, IR ir) {
092        RegisterOperand result = InstanceOf.getClearResult(s);
093        TypeReference LHStype = InstanceOf.getType(s).getTypeRef();
094        Operand ref = InstanceOf.getClearRef(s);
095        Instruction next = s.nextInstructionInCodeOrder();
096        if (next.operator() == INT_IFCMP &&
097            IfCmp.getVal1(next) instanceof RegisterOperand &&
098            result.similar(IfCmp.getVal1(next))) {
099          // The result of instanceof is being consumed by a conditional branch.
100          // Optimize this case by generating a branching type check
101          // instead of producing a value.
102          // TODO: This is really not safe: suppose the if is NOT the
103          // only use of the result of the instanceof.
104          // The way to fix this is to add ifInstanceOf and ifNotInstanceOf
105          // operators to the IR and have Simple transform
106          // instanceof, intIfCmp based on the U/D chains.
107          // See defect 2114.
108          Operand val2 = IfCmp.getVal2(next);
109          if (VM.VerifyAssertions) VM._assert(val2.isIntConstant());
110          int ival2 = ((IntConstantOperand) val2).value;
111          ConditionOperand cond = IfCmp.getCond(next);
112          boolean branchCondition =
113              (((ival2 == 0) && (cond.isNOT_EQUAL() || cond.isLESS_EQUAL())) ||
114               ((ival2 == 1) && (cond.isEQUAL() || cond.isGREATER_EQUAL())));
115          BasicBlock branchBB = next.getBranchTarget();
116          RegisterOperand oldGuard = IfCmp.getGuardResult(next);
117          next.remove();
118          BasicBlock fallThroughBB = fallThroughBB(s, ir);
119          BasicBlock falseBranch = branchCondition ? fallThroughBB : branchBB;
120          BasicBlock trueBranch = branchCondition ? branchBB : fallThroughBB;
121          BranchProfileOperand bp = IfCmp.getClearBranchProfile(next);
122          if (branchCondition) bp = bp.flip();
123          Instruction nullComp =
124              IfCmp.create(REF_IFCMP,
125                           oldGuard.copyRO(),
126                           ref.copy(),
127                           new NullConstantOperand(),
128                           ConditionOperand.EQUAL(),
129                           falseBranch.makeJumpTarget(),
130                           BranchProfileOperand.unlikely());
131          s.insertBefore(nullComp);
132          BasicBlock myBlock = s.getBasicBlock();
133          BasicBlock instanceOfBlock = myBlock.splitNodeAt(nullComp, ir);
134          myBlock.insertOut(instanceOfBlock);
135          myBlock.insertOut(falseBranch);
136          ir.cfg.linkInCodeOrder(myBlock, instanceOfBlock);
137          Operand RHStib = getTIB(s, ir, ref, oldGuard.copyRO());
138          return generateBranchingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, trueBranch, falseBranch, oldGuard, bp);
139        } else {
140          // Not a branching pattern
141          RegisterOperand guard = ir.regpool.makeTempValidation();
142          BasicBlock instanceOfBlock = s.getBasicBlock().segregateInstruction(s, ir);
143          BasicBlock prevBB = instanceOfBlock.prevBasicBlockInCodeOrder();
144          BasicBlock nextBB = instanceOfBlock.nextBasicBlockInCodeOrder();
145          BasicBlock nullCaseBB = instanceOfBlock.createSubBlock(s.bcIndex, ir, .01f);
146          prevBB.appendInstruction(IfCmp.create(REF_IFCMP,
147                                                guard,
148                                                ref.copy(),
149                                                new NullConstantOperand(),
150                                                ConditionOperand.EQUAL(),
151                                                nullCaseBB.makeJumpTarget(),
152                                                BranchProfileOperand.unlikely()));
153          nullCaseBB.appendInstruction(Move.create(INT_MOVE, result.copyD2D(), IC(0)));
154          nullCaseBB.appendInstruction(Goto.create(GOTO, nextBB.makeJumpTarget()));
155          // Stitch together the CFG; add nullCaseBB to the end of code array.
156          prevBB.insertOut(nullCaseBB);
157          nullCaseBB.insertOut(nextBB);
158          ir.cfg.addLastInCodeOrder(nullCaseBB);
159          Operand RHStib = getTIB(s, ir, ref, guard.copyD2U());
160          return generateValueProducingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, result);
161        }
162      }
163    
164      /**
165       * Expand an instanceof instruction into the LIR sequence that implements
166       * the dynamic type check.  Ref is known to never contain a null ptr at
167       * runtime.
168       *
169       * @param s an INSTANCEOF_NOTNULL instruction to expand
170       * @param ir the enclosing IR
171       * @return the last Instruction in the generated LIR sequence.
172       */
173      static Instruction instanceOfNotNull(Instruction s, IR ir) {
174        RegisterOperand result = InstanceOf.getClearResult(s);
175        TypeReference LHStype = InstanceOf.getType(s).getTypeRef();
176        Operand ref = InstanceOf.getClearRef(s);
177        Operand guard = InstanceOf.getClearGuard(s);
178        Instruction next = s.nextInstructionInCodeOrder();
179        if (next.operator() == INT_IFCMP &&
180            IfCmp.getVal1(next) instanceof RegisterOperand &&
181            result.similar(IfCmp.getVal1(next))) {
182          // The result of instanceof is being consumed by a conditional branch.
183          // Optimize this case by generating a branching type
184          // check instead of producing a value.
185          Operand val2 = IfCmp.getVal2(next);
186          if (VM.VerifyAssertions) {
187            VM._assert(val2.isIntConstant());
188          }
189          int ival2 = ((IntConstantOperand) val2).value;
190          ConditionOperand cond = IfCmp.getCond(next);
191          boolean branchCondition =
192              (((ival2 == 0) && (cond.isNOT_EQUAL() || cond.isLESS_EQUAL())) ||
193               ((ival2 == 1) && (cond.isEQUAL() || cond.isGREATER_EQUAL())));
194          BasicBlock branchBB = next.getBranchTarget();
195          RegisterOperand oldGuard = IfCmp.getGuardResult(next);
196          next.remove();
197          BasicBlock fallThroughBB = fallThroughBB(s, ir);
198          Operand RHStib = getTIB(s, ir, ref, guard);
199          if (branchCondition) {
200            return generateBranchingTypeCheck(s,
201                                              ir,
202                                              ref.copy(),
203                                              LHStype,
204                                              RHStib,
205                                              branchBB,
206                                              fallThroughBB,
207                                              oldGuard,
208                                              IfCmp.getClearBranchProfile(next).flip());
209          } else {
210            return generateBranchingTypeCheck(s,
211                                              ir,
212                                              ref.copy(),
213                                              LHStype,
214                                              RHStib,
215                                              fallThroughBB,
216                                              branchBB,
217                                              oldGuard,
218                                              IfCmp.getClearBranchProfile(next));
219          }
220        } else {
221          // Not a branching pattern
222          Operand RHStib = getTIB(s, ir, ref, guard);
223          return generateValueProducingTypeCheck(s, ir, ref.copy(), LHStype, RHStib, result);
224        }
225      }
226    
227      /**
228       * Expand a checkcast instruction into the LIR sequence that implements the
229       * dynamic type check, raising a ClassCastException when the type check
230       * fails. Ref may contain a null ptr at runtime.
231       *
232       * @param s a CHECKCAST or CHECKCAST_UNRESOLVED instruction to expand
233       * @param ir the enclosing IR
234       * @return the last Instruction in the generated LIR sequence.
235       */
236      static Instruction checkcast(Instruction s, IR ir) {
237        Operand ref = TypeCheck.getClearRef(s);
238        TypeReference LHStype = TypeCheck.getType(s).getTypeRef();
239        RegisterOperand guard = ir.regpool.makeTempValidation();
240        Instruction nullCond =
241            IfCmp.create(REF_IFCMP,
242                         guard,
243                         ref.copy(),
244                         new NullConstantOperand(),
245                         ConditionOperand.EQUAL(),
246                         null,
247                         // KLUDGE...we haven't created the block yet!
248                         new BranchProfileOperand());
249        s.insertBefore(nullCond);
250        BasicBlock myBlock = s.getBasicBlock();
251        BasicBlock failBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
252        BasicBlock instanceOfBlock = myBlock.splitNodeAt(nullCond, ir);
253        BasicBlock succBlock = instanceOfBlock.splitNodeAt(s, ir);
254        succBlock.firstInstruction().insertAfter(Move.create(REF_MOVE, TypeCheck.getClearResult(s), ref.copy()));
255        IfCmp.setTarget(nullCond, succBlock.makeJumpTarget()); // fixup KLUDGE
256        myBlock.insertOut(instanceOfBlock);
257        myBlock.insertOut(succBlock);
258        instanceOfBlock.insertOut(failBlock);
259        instanceOfBlock.insertOut(succBlock);
260        ir.cfg.linkInCodeOrder(myBlock, instanceOfBlock);
261        ir.cfg.linkInCodeOrder(instanceOfBlock, succBlock);
262        ir.cfg.addLastInCodeOrder(failBlock);
263        Instruction raiseError = Trap.create(TRAP, null, TrapCodeOperand.CheckCast());
264        raiseError.copyPosition(s);
265        failBlock.appendInstruction(raiseError);
266        Operand RHStib = getTIB(s, ir, ref, guard.copyD2U());
267        return generateBranchingTypeCheck(s,
268                                          ir,
269                                          ref.copy(),
270                                          LHStype,
271                                          RHStib,
272                                          succBlock,
273                                          failBlock,
274                                          guard.copyRO(),
275                                          BranchProfileOperand.never());
276      }
277    
278      /**
279       * Expand a checkcast instruction into the LIR sequence that implements the
280       * dynamic type check, raising a ClassCastException when the type check
281       * fails. Ref is known to never contain a null ptr at runtime.
282       *
283       * @param s a CHECKCAST_NOTNULL instruction to expand
284       * @param ir the enclosing IR
285       * @return the last Instruction in the generated LIR sequence.
286       */
287      static Instruction checkcastNotNull(Instruction s, IR ir) {
288        Operand ref = TypeCheck.getClearRef(s);
289        TypeReference LHStype = TypeCheck.getType(s).getTypeRef();
290        Operand guard = TypeCheck.getClearGuard(s);
291        BasicBlock myBlock = s.getBasicBlock();
292        BasicBlock failBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
293        BasicBlock succBlock = myBlock.splitNodeAt(s, ir);
294        succBlock.firstInstruction().insertAfter(Move.create(REF_MOVE, TypeCheck.getClearResult(s), ref.copy()));
295        myBlock.insertOut(failBlock);
296        myBlock.insertOut(succBlock);
297        ir.cfg.linkInCodeOrder(myBlock, succBlock);
298        ir.cfg.addLastInCodeOrder(failBlock);
299        Instruction raiseError = Trap.create(TRAP, null, TrapCodeOperand.CheckCast());
300        raiseError.copyPosition(s);
301        failBlock.appendInstruction(raiseError);
302        Operand RHStib = getTIB(s, ir, ref, guard);
303        return generateBranchingTypeCheck(s,
304                                          ir,
305                                          ref.copy(),
306                                          LHStype,
307                                          RHStib,
308                                          succBlock,
309                                          failBlock,
310                                          ir.regpool.makeTempValidation(),
311                                          BranchProfileOperand.never());
312      }
313    
314      /**
315       * Expand a checkcastInterface instruction into the LIR sequence that
316       * implements the dynamic type check, raising an IncompataibleClassChangeError
317       * if the type check fails.
318       * Ref is known to never contain a null ptr at runtime.
319       *
320       * @param s a MUST_IMPLEMENT_INTERFACE instruction to expand
321       * @param ir the enclosing IR
322       * @return the last Instruction in the generated LIR sequence.
323       */
324      static Instruction mustImplementInterface(Instruction s, IR ir) {
325        Operand ref = TypeCheck.getClearRef(s);
326        RVMClass LHSClass = (RVMClass) TypeCheck.getType(s).getVMType();
327        if (VM.VerifyAssertions) VM._assert(LHSClass != null, "Should be resolvable...");
328        int interfaceIndex = LHSClass.getDoesImplementIndex();
329        int interfaceMask = LHSClass.getDoesImplementBitMask();
330        Operand guard = TypeCheck.getClearGuard(s);
331        BasicBlock myBlock = s.getBasicBlock();
332        BasicBlock failBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
333        BasicBlock succBlock = myBlock.splitNodeAt(s, ir);
334        succBlock.firstInstruction().insertAfter(Move.create(REF_MOVE, TypeCheck.getClearResult(s), ref.copy()));
335        myBlock.insertOut(failBlock);
336        myBlock.insertOut(succBlock);
337        ir.cfg.linkInCodeOrder(myBlock, succBlock);
338        ir.cfg.addLastInCodeOrder(failBlock);
339        Instruction raiseError = Trap.create(TRAP, null, TrapCodeOperand.MustImplement());
340        raiseError.copyPosition(s);
341        failBlock.appendInstruction(raiseError);
342    
343        Operand RHStib = getTIB(s, ir, ref, guard);
344        RegisterOperand doesImpl = InsertUnary(s, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
345    
346        if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
347          RegisterOperand doesImplLength =
348              InsertGuardedUnary(s, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copyD2U(), TG());
349          Instruction lengthCheck =
350              IfCmp.create(INT_IFCMP,
351                  ir.regpool.makeTempValidation(),
352                  doesImplLength,
353                  IC(interfaceIndex),
354                  ConditionOperand.LESS_EQUAL(),
355                  failBlock.makeJumpTarget(),
356                  BranchProfileOperand.never());
357          s.insertBefore(lengthCheck);
358          myBlock.splitNodeWithLinksAt(lengthCheck, ir);
359          myBlock.insertOut(failBlock); // required due to splitNode!
360        }
361        RegisterOperand entry =
362            InsertLoadOffset(s,
363                             ir,
364                             INT_LOAD,
365                             TypeReference.Int,
366                             doesImpl,
367                             Offset.fromIntZeroExtend(interfaceIndex << 2),
368                             new LocationOperand(TypeReference.Int),
369                             TG());
370        RegisterOperand bit = insertBinary(s, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
371        IfCmp.mutate(s,
372                     INT_IFCMP,
373                     ir.regpool.makeTempValidation(),
374                     bit,
375                     IC(0),
376                     ConditionOperand.EQUAL(),
377                     failBlock.makeJumpTarget(),
378                     BranchProfileOperand.never());
379        return s;
380      }
381    
382      /**
383       * Expand an object array store check into the LIR sequence that
384       * implements it.
385       *
386       * @param s an OBJARRAY_STORE_CHECK instruction to expand
387       * @param ir the enclosing IR
388       * @param couldBeNull is it possible that the element being stored is null?
389       * @return the last Instruction in the generated LIR sequence.
390       */
391      static Instruction arrayStoreCheck(Instruction s, IR ir, boolean couldBeNull) {
392        RegisterOperand guardResult = StoreCheck.getGuardResult(s);
393        Operand arrayRef = StoreCheck.getClearRef(s);
394        Operand elemRef = StoreCheck.getClearVal(s);
395        Operand guard = StoreCheck.getClearGuard(s);
396        if (elemRef instanceof NullConstantOperand) {
397          Instruction continueAt = s.prevInstructionInCodeOrder();
398          s.remove();
399          return continueAt;
400        }
401        BasicBlock myBlock = s.getBasicBlock();
402        BasicBlock contBlock = myBlock.splitNodeAt(s, ir);
403        BasicBlock trapBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);
404        BasicBlock curBlock = myBlock;
405        Move.mutate(s, GUARD_MOVE, guardResult, new TrueGuardOperand());
406    
407        // Set up a block with a trap instruction that we can jump to if the
408        // store check fails
409        Instruction trap = Trap.create(TRAP, null, TrapCodeOperand.StoreCheck());
410        trap.copyPosition(s);
411        trapBlock.appendInstruction(trap);
412        ir.cfg.addLastInCodeOrder(trapBlock);
413    
414        Operand rhsGuard = guard;
415        if (couldBeNull) {
416          // if rhs is null, then the checkcast succeeds
417          rhsGuard = ir.regpool.makeTempValidation();
418          contBlock.prependInstruction(Binary.create(GUARD_COMBINE,
419                                                     guardResult.copyRO(),
420                                                     guardResult.copyRO(),
421                                                     rhsGuard.copy()));
422          curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
423                                                  rhsGuard.asRegister(),
424                                                  elemRef,
425                                                  new NullConstantOperand(),
426                                                  ConditionOperand.EQUAL(),
427                                                  contBlock.makeJumpTarget(),
428                                                  new BranchProfileOperand()));
429          curBlock.insertOut(contBlock);
430          curBlock = advanceBlock(s.bcIndex, curBlock, ir);
431        }
432    
433        // Find out what we think the compile time type of the lhs is.
434        // Based on this, we can do one of several things:
435        //  (1) If the compile time element type is a final proper class, then a
436        //      TIB comparision of the runtime elemRef type and the
437        //      compile time element type is definitive.
438        //  (2) If the compile time type is known to be the declared type,
439        //      then inject a short-circuit test to see if the
440        //      runtime lhs type is the same as the compile-time lhs type.
441        //  (3) If the compile time element type is a proper class other than
442        //      java.lang.Object, then a subclass test of the runtime LHS elem type
443        //      and the runtime elemRef type is definitive.  Note: we must exclude
444        //      java.lang.Object because if the compile time element type is
445        //      java.lang.Object, then the runtime-element type might actually be
446        //      an interface (ie not a proper class), and we won't be testing the right thing!
447        // If we think the compile time type is JavaLangObjectType then
448        // we lost type information due to unloaded classes causing
449        // imprecise meets.  This should only happen once in a blue moon,
450        // so don't bother trying anything clever when it does.
451        RVMType compType = arrayRef.getType().peekType();
452        if (compType != null && !compType.isJavaLangObjectType()) {
453          // optionally (1) from above
454          if (compType.getDimensionality() == 1) {
455            RVMClass etc = (RVMClass) compType.asArray().getElementType();
456            if (etc.isResolved() && etc.isFinal()) {
457              if (VM.VerifyAssertions) VM._assert(!etc.isInterface());
458              Operand rhsTIB = getTIB(curBlock.lastInstruction(), ir, elemRef.copy(), rhsGuard.copy());
459              Operand etTIB = getTIB(curBlock.lastInstruction(), ir, etc);
460              curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
461                                                      guardResult.copyRO(),
462                                                      rhsTIB,
463                                                      etTIB,
464                                                      ConditionOperand.NOT_EQUAL(),
465                                                      trapBlock.makeJumpTarget(),
466                                                      BranchProfileOperand.never()));
467              curBlock.insertOut(trapBlock);
468              curBlock.insertOut(contBlock);
469              ir.cfg.linkInCodeOrder(curBlock, contBlock);
470              return curBlock.lastInstruction();
471            }
472          }
473    
474          // optionally (2) from above
475          Operand lhsTIB = getTIB(curBlock.lastInstruction(), ir, arrayRef, guard);
476          if (((arrayRef instanceof RegisterOperand) && ((RegisterOperand) arrayRef).isDeclaredType()) ||
477              compType == RVMType.JavaLangObjectArrayType) {
478            Operand declTIB = getTIB(curBlock.lastInstruction(), ir, compType);
479            curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
480                                                    guardResult.copyRO(),
481                                                    declTIB,
482                                                    lhsTIB,
483                                                    ConditionOperand.EQUAL(),
484                                                    contBlock.makeJumpTarget(),
485                                                    new BranchProfileOperand()));
486            curBlock.insertOut(contBlock);
487            curBlock = advanceBlock(s.bcIndex, curBlock, ir);
488          }
489    
490          // On our way to doing (3) from above attempt another short-circuit.
491          // If lhsElemTIB == rhsTIB, then we are done.
492          Operand rhsTIB = getTIB(curBlock.lastInstruction(), ir, elemRef.copy(), rhsGuard.copy());
493          RegisterOperand lhsElemTIB =
494              InsertUnary(curBlock.lastInstruction(),
495                          ir,
496                          GET_ARRAY_ELEMENT_TIB_FROM_TIB,
497                          TypeReference.TIB,
498                          lhsTIB.copy());
499          curBlock.appendInstruction(IfCmp.create(REF_IFCMP,
500                                                  guardResult.copyRO(),
501                                                  rhsTIB,
502                                                  lhsElemTIB,
503                                                  ConditionOperand.EQUAL(),
504                                                  contBlock.makeJumpTarget(),
505                                                  new BranchProfileOperand()));
506          curBlock.insertOut(contBlock);
507          curBlock = advanceBlock(s.bcIndex, curBlock, ir);
508    
509          // Optionally (3) from above
510          if (compType.getDimensionality() == 1) {
511            RVMClass etc = (RVMClass) compType.asArray().getElementType();
512            if (etc.isResolved() && !etc.isInterface() && !etc.isJavaLangObjectType()) {
513              RegisterOperand lhsElemType =
514                  InsertUnary(curBlock.lastInstruction(),
515                              ir,
516                              GET_TYPE_FROM_TIB,
517                              TypeReference.Type,
518                              lhsElemTIB.copyU2U());
519              RegisterOperand rhsSuperclassIds =
520                  InsertUnary(curBlock.lastInstruction(),
521                              ir,
522                              GET_SUPERCLASS_IDS_FROM_TIB,
523                              TypeReference.ShortArray,
524                              rhsTIB.copy());
525              RegisterOperand lhsElemDepth =
526                  getField(curBlock.lastInstruction(), ir, lhsElemType, Entrypoints.depthField, TG());
527              RegisterOperand rhsSuperclassIdsLength =
528                  InsertGuardedUnary(curBlock.lastInstruction(),
529                                     ir,
530                                     ARRAYLENGTH,
531                                     TypeReference.Int,
532                                     rhsSuperclassIds.copyD2U(),
533                                     TG());
534              curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
535                                                      guardResult.copyRO(),
536                                                      lhsElemDepth,
537                                                      rhsSuperclassIdsLength,
538                                                      ConditionOperand.GREATER_EQUAL(),
539                                                      trapBlock.makeJumpTarget(),
540                                                      BranchProfileOperand.never()));
541              curBlock.insertOut(trapBlock);
542              curBlock = advanceBlock(s.bcIndex, curBlock, ir);
543    
544              RegisterOperand lhsElemId =
545                  getField(curBlock.lastInstruction(), ir, lhsElemType.copyD2U(), Entrypoints.idField, TG());
546              RegisterOperand refCandidate = ir.regpool.makeTemp(TypeReference.Short);
547              LocationOperand loc = new LocationOperand(TypeReference.Short);
548              if (LOWER_ARRAY_ACCESS) {
549                RegisterOperand lhsDepthOffset =
550                    insertBinary(curBlock.lastInstruction(),
551                                 ir,
552                                 INT_SHL,
553                                 TypeReference.Int,
554                                 lhsElemDepth.copyD2U(),
555                                 IC(1));
556                lhsDepthOffset =
557                    InsertUnary(curBlock.lastInstruction(),
558                                ir,
559                                INT_2ADDRZerExt,
560                                TypeReference.Offset,
561                                lhsDepthOffset.copy());
562                curBlock.appendInstruction(Load.create(USHORT_LOAD,
563                                                       refCandidate,
564                                                       rhsSuperclassIds,
565                                                       lhsDepthOffset,
566                                                       loc,
567                                                       TG()));
568              } else {
569                curBlock.appendInstruction(ALoad.create(USHORT_ALOAD,
570                                                        refCandidate,
571                                                        rhsSuperclassIds,
572                                                        lhsElemDepth.copyRO(),
573                                                        loc,
574                                                        TG()));
575              }
576              curBlock.appendInstruction(IfCmp.create(INT_IFCMP,
577                                                      guardResult.copyRO(),
578                                                      refCandidate.copyD2U(),
579                                                      lhsElemId,
580                                                      ConditionOperand.NOT_EQUAL(),
581                                                      trapBlock.makeJumpTarget(),
582                                                      BranchProfileOperand.never()));
583              curBlock.insertOut(trapBlock);
584              curBlock.insertOut(contBlock);
585              ir.cfg.linkInCodeOrder(curBlock, contBlock);
586              return curBlock.lastInstruction();
587            }
588          }
589        }
590    
591        // Call RuntimeEntrypoints.checkstore.
592        RVMMethod target = Entrypoints.checkstoreMethod;
593        Instruction call =
594            Call.create2(CALL,
595                         null,
596                         AC(target.getOffset()),
597                         MethodOperand.STATIC(target),
598                         rhsGuard.copy(),
599                         arrayRef.copy(),
600                         elemRef.copy());
601        call.copyPosition(s);
602        curBlock.appendInstruction(call);
603        curBlock.insertOut(contBlock);
604        ir.cfg.linkInCodeOrder(curBlock, contBlock);
605        return callHelper(call, ir);
606      }
607    
608      /**
609       * Generate a value-producing dynamic type check.
610       * This routine assumes that the CFG and code order are
611       * already correctly established.
612       * This routine must either remove s or mutuate it.
613       *
614       * @param s        The Instruction that is to be replaced by
615       *                  a value producing type check
616       * @param ir       The IR containing the instruction to be expanded.
617       * @param RHSobj   The RegisterOperand containing the rhs object.
618       * @param LHStype  The RVMType to be tested against.
619       * @param RHStib   The Operand containing the TIB of the rhs.
620       * @param result   The RegisterOperand that the result of dynamic
621       *                 type check is to be stored in.
622       * @return the opt instruction immediately before the
623       *         instruction to continue expansion.
624       */
625      private static Instruction generateValueProducingTypeCheck(Instruction s, IR ir, Operand RHSobj,
626                                                                     TypeReference LHStype, Operand RHStib,
627                                                                     RegisterOperand result) {
628        // Is LHStype a class?
629        if (LHStype.isClassType()) {
630          RVMClass LHSclass = (RVMClass) LHStype.peekType();
631          if (LHSclass != null && LHSclass.isResolved()) {
632            // Cases 4, 5, and 6 of DynamicTypeCheck: LHSclass is a
633            // resolved class or interface
634            if (LHSclass.isInterface()) {
635              // A resolved interface (case 4)
636              int interfaceIndex = LHSclass.getDoesImplementIndex();
637              int interfaceMask = LHSclass.getDoesImplementBitMask();
638              RegisterOperand doesImpl =
639                  InsertUnary(s, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
640              RegisterOperand entry =
641                  InsertLoadOffset(s,
642                                   ir,
643                                   INT_LOAD,
644                                   TypeReference.Int,
645                                   doesImpl,
646                                   Offset.fromIntZeroExtend(interfaceIndex << 2),
647                                   new LocationOperand(TypeReference.Int),
648                                   TG());
649              RegisterOperand bit = insertBinary(s, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
650              //save to use the cheaper ADDR version of BOOLEAN_CMP
651              s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
652                                               result,
653                                               bit,
654                                               AC(Address.zero()),
655                                               ConditionOperand.NOT_EQUAL(),
656                                               new BranchProfileOperand()));
657    
658              if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
659                RegisterOperand doesImplLength =
660                    InsertGuardedUnary(s, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copy(), TG());
661                RegisterOperand boundscheck = ir.regpool.makeTempInt();
662                //save to use the cheaper ADDR version of BOOLEAN_CMP
663                s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
664                                                 boundscheck,
665                                                 doesImplLength,
666                                                 AC(Address.fromIntSignExtend(interfaceIndex)),
667                                                 ConditionOperand.GREATER(),
668                                                 new BranchProfileOperand()));
669                s.insertBefore(Binary.create(INT_AND, result.copyD2D(), result.copyD2U(), boundscheck.copyD2U()));
670              }
671              Instruction continueAt = s.prevInstructionInCodeOrder();
672              s.remove();
673              return continueAt;
674            } else {
675              // A resolved class (cases 5 and 6 in DynamicTypeCheck)
676              if (LHSclass.isFinal()) {
677                // For a final class, we can do a PTR compare of
678                // rhsTIB and the TIB of the class
679                Operand classTIB = getTIB(s, ir, LHSclass);
680                BooleanCmp.mutate(s,
681                                  BOOLEAN_CMP_ADDR,
682                                  result,
683                                  RHStib,
684                                  classTIB,
685                                  ConditionOperand.EQUAL(),
686                                  new BranchProfileOperand());
687                return s.prevInstructionInCodeOrder();
688              } else {
689                // Do the full blown case 5 or 6 typecheck.
690                int LHSDepth = LHSclass.getTypeDepth();
691                int LHSId = LHSclass.getId();
692                RegisterOperand superclassIds =
693                    InsertUnary(s, ir, GET_SUPERCLASS_IDS_FROM_TIB, TypeReference.ShortArray, RHStib);
694                RegisterOperand refCandidate =
695                    InsertLoadOffset(s,
696                                     ir,
697                                     USHORT_LOAD,
698                                     TypeReference.Short,
699                                     superclassIds,
700                                     Offset.fromIntZeroExtend(LHSDepth << 1),
701                                     new LocationOperand(TypeReference.Short),
702                                     TG());
703                //save to use the cheaper ADDR version of BOOLEAN_CMP
704                s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
705                                                 result,
706                                                 refCandidate,
707                                                 AC(Address.fromIntZeroExtend(LHSId)),
708                                                 ConditionOperand.EQUAL(),
709                                                 new BranchProfileOperand()));
710                if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) {
711                  RegisterOperand superclassIdsLength =
712                      InsertGuardedUnary(s, ir, ARRAYLENGTH, TypeReference.Int, superclassIds.copyD2U(), TG());
713                  RegisterOperand boundscheck = ir.regpool.makeTempInt();
714                  //save to use the cheaper ADDR version of BOOLEAN_CMP
715                  s.insertBefore(BooleanCmp.create(BOOLEAN_CMP_ADDR,
716                                                   boundscheck,
717                                                   superclassIdsLength,
718                                                   AC(Address.fromIntSignExtend(LHSDepth)),
719                                                   ConditionOperand.GREATER(),
720                                                   new BranchProfileOperand()));
721                  s.insertBefore(Binary.create(INT_AND, result.copyD2D(), result.copyD2U(), boundscheck.copyD2U()));
722                }
723                Instruction continueAt = s.prevInstructionInCodeOrder();
724                s.remove();
725                return continueAt;
726              }
727            }
728          } else {
729            // A non-resolved class or interface.
730            // We expect these to be extremely uncommon in opt code in AOS.
731            // Mutate s into a call to RuntimeEntrypoints.instanceOf
732            RVMMethod target = Entrypoints.instanceOfMethod;
733            Call.mutate2(s,
734                         CALL,
735                         result,
736                         AC(target.getOffset()),
737                         MethodOperand.STATIC(target),
738                         RHSobj,
739                         IC(LHStype.getId()));
740            return callHelper(s, ir);
741          }
742        }
743        if (LHStype.isArrayType()) {
744          // Case 2 of DynamicTypeCheck: LHS is an array.
745          RVMArray LHSArray = (RVMArray) LHStype.peekType();
746          if (LHSArray != null) {
747            RVMType innermostElementType = LHSArray.getInnermostElementType();
748            if (innermostElementType.isPrimitiveType() || innermostElementType.isUnboxedType() ||
749                (innermostElementType.asClass().isResolved() && innermostElementType.asClass().isFinal())) {
750              // [^k of primitive or [^k of final class. Just like final classes,
751              // a PTR compare of rhsTIB and the TIB of the class gives the answer.
752              Operand classTIB = getTIB(s, ir, LHSArray);
753              BooleanCmp.mutate(s,
754                                BOOLEAN_CMP_ADDR,
755                                result,
756                                RHStib,
757                                classTIB,
758                                ConditionOperand.EQUAL(),
759                                new BranchProfileOperand());
760              return s;
761            }
762          }
763          // We're going to have to branch anyways, so reduce to a branching case
764          // and do the real work there.
765          return convertToBranchingTypeCheck(s, ir, RHSobj, LHStype, RHStib, result);
766        }
767        OptimizingCompilerException.UNREACHABLE();
768        return null;
769      }
770    
771      /**
772       * Generate wrapper around branching type check to get a
773       * value producing type check.
774       * @param s        The Instruction that is to be replaced by
775       *                  a value producing type check
776       * @param ir       The IR containing the instruction to be expanded.
777       * @param RHSobj   The RegisterOperand containing the rhs object.
778       * @param LHStype  The TypeReference to be tested against.
779       * @param RHStib   The Operand containing the TIB of the rhs.
780       * @param result   The RegisterOperand that the result of dynamic
781       * @return the opt instruction immediately before the instruction to
782       *         continue expansion.
783       */
784      private static Instruction convertToBranchingTypeCheck(Instruction s, IR ir, Operand RHSobj,
785                                                                 TypeReference LHStype, Operand RHStib,
786                                                                 RegisterOperand result) {
787        BasicBlock myBlock = s.getBasicBlock();
788        BasicBlock contBlock = myBlock.splitNodeAt(s, ir);
789        BasicBlock trueBlock = myBlock.createSubBlock(s.bcIndex, ir);
790        BasicBlock falseBlock = myBlock.createSubBlock(s.bcIndex, ir);
791        myBlock.insertOut(trueBlock);
792        myBlock.insertOut(falseBlock);
793        trueBlock.insertOut(contBlock);
794        falseBlock.insertOut(contBlock);
795        ir.cfg.linkInCodeOrder(myBlock, trueBlock);
796        ir.cfg.linkInCodeOrder(trueBlock, falseBlock);
797        ir.cfg.linkInCodeOrder(falseBlock, contBlock);
798        trueBlock.appendInstruction(Move.create(INT_MOVE, result, IC(1)));
799        trueBlock.appendInstruction(Goto.create(GOTO, contBlock.makeJumpTarget()));
800        falseBlock.appendInstruction(Move.create(INT_MOVE, result.copyD2D(), IC(0)));
801        return generateBranchingTypeCheck(s,
802                                          ir,
803                                          RHSobj,
804                                          LHStype,
805                                          RHStib,
806                                          trueBlock,
807                                          falseBlock,
808                                          ir.regpool.makeTempValidation(),
809                                          new BranchProfileOperand());
810      }
811    
812      /**
813       * Generate a branching dynamic type check.
814       * This routine assumes that the CFG and code order are already
815       * correctly established.
816       * This routine must either remove s or mutuate it.
817       *
818       * @param s          The Instruction that is to be replaced by a
819       *                   branching type check
820       * @param ir         The IR containing the instruction to be expanded.
821       * @param RHSobj     The RegisterOperand containing the rhs object.
822       * @param LHStype    The TypeReference to be tested against.
823       * @param RHStib     The Operand containing the TIB of the rhs.
824       * @param trueBlock  The BasicBlock to continue at if the typecheck
825       *                   evaluates to true
826       * @param falseBlock The BasicBlock to continue at if the typecheck
827       *                   evaluates to false.
828       * @param falseProb   The probability that typecheck will branch to the falseBlock
829       * @return the opt instruction immediately before the instruction to
830       *         continue expansion.
831       */
832      private static Instruction generateBranchingTypeCheck(Instruction s, IR ir, Operand RHSobj,
833                                                                TypeReference LHStype, Operand RHStib,
834                                                                BasicBlock trueBlock, BasicBlock falseBlock,
835                                                                RegisterOperand oldGuard,
836                                                                BranchProfileOperand falseProb) {
837        Instruction continueAt = Goto.create(GOTO, trueBlock.makeJumpTarget());
838        continueAt.copyPosition(s);
839        s.insertBefore(continueAt);
840        s.remove();
841    
842        if (LHStype.isClassType()) {
843          RVMClass LHSclass = (RVMClass) LHStype.peekType();
844          if (LHSclass != null && LHSclass.isResolved()) {
845            // Cases 4, 5, and 6 of DynamicTypeCheck: LHSclass is a resolved
846            // class or interface
847            if (LHSclass.isInterface()) {
848              // A resolved interface (case 4)
849              int interfaceIndex = LHSclass.getDoesImplementIndex();
850              int interfaceMask = LHSclass.getDoesImplementBitMask();
851              RegisterOperand doesImpl =
852                  InsertUnary(continueAt, ir, GET_DOES_IMPLEMENT_FROM_TIB, TypeReference.IntArray, RHStib);
853    
854              if (DynamicTypeCheck.MIN_DOES_IMPLEMENT_SIZE <= interfaceIndex) {
855                RegisterOperand doesImplLength =
856                    InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, doesImpl.copyD2U(), TG());
857                Instruction lengthCheck =
858                    IfCmp.create(INT_IFCMP,
859                                 oldGuard,
860                                 doesImplLength,
861                                 IC(interfaceIndex),
862                                 ConditionOperand.LESS_EQUAL(),
863                                 falseBlock.makeJumpTarget(),
864                                 BranchProfileOperand.unlikely());
865                if (oldGuard != null) {
866                  oldGuard = oldGuard.copyD2D();
867                }
868                continueAt.insertBefore(lengthCheck);
869                BasicBlock oldBlock = continueAt.getBasicBlock();
870                oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
871                oldBlock.insertOut(falseBlock); // required due to splitNode!
872              }
873              RegisterOperand entry =
874                  InsertLoadOffset(continueAt,
875                                   ir,
876                                   INT_LOAD,
877                                   TypeReference.Int,
878                                   doesImpl,
879                                   Offset.fromIntZeroExtend(interfaceIndex << 2),
880                                   new LocationOperand(TypeReference.Int),
881                                   TG());
882              RegisterOperand bit =
883                  insertBinary(continueAt, ir, INT_AND, TypeReference.Int, entry, IC(interfaceMask));
884              continueAt.insertBefore(IfCmp.create(INT_IFCMP,
885                                                   oldGuard,
886                                                   bit,
887                                                   IC(0),
888                                                   ConditionOperand.EQUAL(),
889                                                   falseBlock.makeJumpTarget(),
890                                                   falseProb));
891              return continueAt;
892            } else {
893              // A resolved class (cases 5 and 6 in DynamicTypeCheck)
894              if (LHSclass.isFinal()) {
895                // For a final class, we can do a PTR compare of
896                // rhsTIB and the TIB of the class
897                Operand classTIB = getTIB(continueAt, ir, LHSclass);
898                continueAt.insertBefore(IfCmp.create(REF_IFCMP,
899                                                     oldGuard,
900                                                     RHStib,
901                                                     classTIB,
902                                                     ConditionOperand.NOT_EQUAL(),
903                                                     falseBlock.makeJumpTarget(),
904                                                     falseProb));
905                return continueAt;
906              } else {
907                // Do the full blown case 5 or 6 typecheck.
908                int LHSDepth = LHSclass.getTypeDepth();
909                int LHSId = LHSclass.getId();
910                RegisterOperand superclassIds =
911                    InsertUnary(continueAt, ir, GET_SUPERCLASS_IDS_FROM_TIB, TypeReference.ShortArray, RHStib);
912                if (DynamicTypeCheck.MIN_SUPERCLASS_IDS_SIZE <= LHSDepth) {
913                  RegisterOperand superclassIdsLength =
914                      InsertGuardedUnary(continueAt, ir, ARRAYLENGTH, TypeReference.Int, superclassIds.copyD2U(), TG());
915                  Instruction lengthCheck =
916                      IfCmp.create(INT_IFCMP,
917                                   oldGuard,
918                                   superclassIdsLength,
919                                   IC(LHSDepth),
920                                   ConditionOperand.LESS(),
921                                   falseBlock.makeJumpTarget(),
922                                   BranchProfileOperand.unlikely());
923                  if (oldGuard != null) {
924                    oldGuard = oldGuard.copyD2D();
925                  }
926                  continueAt.insertBefore(lengthCheck);
927                  BasicBlock oldBlock = continueAt.getBasicBlock();
928                  oldBlock.splitNodeWithLinksAt(lengthCheck, ir);
929                  oldBlock.insertOut(falseBlock); // required due to splitNode!
930                }
931                RegisterOperand refCandidate =
932                    InsertLoadOffset(continueAt,
933                                     ir,
934                                     USHORT_LOAD,
935                                     TypeReference.Short,
936                                     superclassIds,
937                                     Offset.fromIntZeroExtend(LHSDepth << 1),
938                                     new LocationOperand(TypeReference.Short),
939                                     TG());
940                continueAt.insertBefore(IfCmp.create(INT_IFCMP,
941                                                     oldGuard,
942                                                     refCandidate,
943                                                     IC(LHSId),
944                                                     ConditionOperand.NOT_EQUAL(),
945                                                     falseBlock.makeJumpTarget(),
946                                                     falseProb));
947                return continueAt;
948              }
949            }
950          } else {
951            // A non-resolved class or interface. Case 3 of DynamicTypeCheck
952            // Branch on the result of a call to
953            // RuntimeEntrypoints.instance
954            RegisterOperand result = ir.regpool.makeTempInt();
955            RVMMethod target = Entrypoints.instanceOfMethod;
956            Instruction call =
957                Call.create2(CALL,
958                             result,
959                             AC(target.getOffset()),
960                             MethodOperand.STATIC(target),
961                             RHSobj,
962                             IC(LHStype.getId()));
963            call.copyPosition(continueAt);
964            continueAt.insertBefore(call);
965            call = callHelper(call, ir);
966            continueAt.insertBefore(IfCmp.create(INT_IFCMP,
967                                                 oldGuard,
968                                                 result.copyD2U(),
969                                                 IC(0),
970                                                 ConditionOperand.EQUAL(),
971                                                 falseBlock.makeJumpTarget(),
972                                                 falseProb));
973            return continueAt;
974          }
975        }
976    
977        if (LHStype.isArrayType()) {
978          // Case 2 of DynamicTypeCheck: LHS is an array.
979          RVMArray LHSArray = (RVMArray) LHStype.peekType();
980          if (LHSArray != null) {
981            Operand classTIB = getTIB(continueAt, ir, LHSArray);
982            RVMType innermostElementType = LHSArray.getInnermostElementType();
983            if (innermostElementType.isPrimitiveType() || innermostElementType.isUnboxedType() ||
984                (innermostElementType.asClass().isResolved() && innermostElementType.asClass().isFinal())) {
985              // [^k of primitive or [^k of final class. Just like final classes,
986              // a PTR compare of rhsTIB and the TIB of the class gives the answer.
987              continueAt.insertBefore(IfCmp.create(REF_IFCMP,
988                                                   oldGuard,
989                                                   RHStib,
990                                                   classTIB,
991                                                   ConditionOperand.NOT_EQUAL(),
992                                                   falseBlock.makeJumpTarget(),
993                                                   falseProb));
994              return continueAt;
995            }
996            // TODO: branch probability calculation is somewhat bogus for this case.
997            Instruction shortcircuit =
998                IfCmp.create(REF_IFCMP,
999                             oldGuard,
1000                             RHStib,
1001                             classTIB,
1002                             ConditionOperand.EQUAL(),
1003                             trueBlock.makeJumpTarget(),
1004                             new BranchProfileOperand());
1005            if (oldGuard != null) {
1006              oldGuard = oldGuard.copyD2D();
1007            }
1008            continueAt.insertBefore(shortcircuit);
1009            BasicBlock myBlock = shortcircuit.getBasicBlock();
1010            BasicBlock mainBlock = myBlock.splitNodeWithLinksAt(shortcircuit, ir);
1011            myBlock.insertOut(trueBlock);       // must come after the splitNodeAt
1012            RegisterOperand rhsType =
1013                InsertUnary(continueAt, ir, GET_TYPE_FROM_TIB, TypeReference.Type, RHStib.copy());
1014            if (innermostElementType.isJavaLangObjectType()) {
1015              IntConstantOperand lhsDimension = IC(LHStype.getDimensionality());
1016              RegisterOperand rhsDimension = getField(continueAt, ir, rhsType, Entrypoints.dimensionField);
1017              Instruction dimTest =
1018                  IfCmp2.create(INT_IFCMP2,
1019                                oldGuard,
1020                                rhsDimension,
1021                                lhsDimension,
1022                                ConditionOperand.GREATER(),
1023                                trueBlock.makeJumpTarget(),
1024                                ((BranchProfileOperand) falseProb.copy()).flip(),
1025                                ConditionOperand.LESS(),
1026                                falseBlock.makeJumpTarget(),
1027                                (BranchProfileOperand) falseProb.copy());
1028              if (oldGuard != null) {
1029                oldGuard = oldGuard.copyD2D();
1030              }
1031              continueAt.insertBefore(dimTest);
1032              //BasicBlock testBlock =
1033              mainBlock.splitNodeWithLinksAt(dimTest, ir);
1034              mainBlock.insertOut(trueBlock);
1035              mainBlock.insertOut(falseBlock);
1036              RegisterOperand rhsInnermostElementTypeDimension =
1037                  getField(continueAt, ir, rhsType.copyU2U(), Entrypoints.innermostElementTypeDimensionField);
1038              continueAt.insertBefore(IfCmp.create(INT_IFCMP,
1039                                                   oldGuard,
1040                                                   rhsInnermostElementTypeDimension,
1041                                                   IC(0),
1042                                                   ConditionOperand.NOT_EQUAL(),
1043                                                   falseBlock.makeJumpTarget(),
1044                                                   falseProb));
1045              return continueAt;
1046            }
1047          }
1048    
1049          // Not a case we want to handle inline
1050          RVMMethod target = Entrypoints.instanceOfMethod;
1051          RegisterOperand callResult = ir.regpool.makeTempInt();
1052          Instruction call =
1053              Call.create2(CALL,
1054                           callResult,
1055                           AC(target.getOffset()),
1056                           MethodOperand.STATIC(target),
1057                           RHSobj,
1058                           IC(LHStype.getId()));
1059          call.copyPosition(continueAt);
1060          continueAt.insertBefore(call);
1061          call = callHelper(call, ir);
1062          continueAt.insertBefore(IfCmp.create(INT_IFCMP,
1063                                               oldGuard,
1064                                               callResult.copyD2U(),
1065                                               IC(0),
1066                                               ConditionOperand.EQUAL(),
1067                                               falseBlock.makeJumpTarget(),
1068                                               falseProb));
1069          return continueAt;
1070        }
1071        OptimizingCompilerException.UNREACHABLE();
1072        return null;
1073      }
1074    
1075      // helper routine.
1076      // s is a conditional branch; Make it the last instruction in its block
1077      // if it isn't already and return the fallthrough block.
1078      private static BasicBlock fallThroughBB(Instruction s, IR ir) {
1079        Instruction next = s.nextInstructionInCodeOrder();
1080        if (next.operator() == BBEND) {
1081          return next.getBasicBlock().nextBasicBlockInCodeOrder();
1082        } else if (next.operator() == GOTO) {
1083          BasicBlock target = next.getBranchTarget();
1084          next.remove();
1085          return target;
1086        } else {
1087          BasicBlock myBlock = s.getBasicBlock();
1088          BasicBlock succBlock = myBlock.splitNodeAt(s, ir);
1089          myBlock.insertOut(succBlock);
1090          ir.cfg.linkInCodeOrder(myBlock, succBlock);
1091          return succBlock;
1092        }
1093      }
1094    
1095      private static BasicBlock advanceBlock(int bcIndex, BasicBlock curBlock, IR ir) {
1096        BasicBlock newBlock = curBlock.createSubBlock(bcIndex, ir);
1097        curBlock.insertOut(newBlock);
1098        ir.cfg.linkInCodeOrder(curBlock, newBlock);
1099        return newBlock;
1100      }
1101    
1102    }