lhsElemDepth, loc, TG()));
lhsElemDepth.copyRO(), loc, TG()));
  static OPT_Instruction arrayStoreCheck(OPT_Instruction s, OPT_IR ir, boolean couldBeNull) {    OPT_RegisterOperand guardResult = StoreCheck.getClearGuardResult(s);    OPT_Operand arrayRef = StoreCheck.getClearRef(s);    OPT_Operand elemRef = StoreCheck.getClearVal(s);    OPT_Operand guard = StoreCheck.getClearGuard(s);    if (elemRef instanceof OPT_NullConstantOperand) {      OPT_Instruction continueAt = s.prevInstructionInCodeOrder();      s.remove();      return continueAt;    }    OPT_BasicBlock myBlock = s.getBasicBlock();    OPT_BasicBlock contBlock = myBlock.splitNodeAt(s, ir);    OPT_BasicBlock trapBlock = myBlock.createSubBlock(s.bcIndex, ir, .0001f);    OPT_BasicBlock curBlock = myBlock;    s.remove();      // Set up a block with a trap instruction that we can jump to if the       // store check fails    OPT_Instruction trap = Trap.create(TRAP, null, OPT_TrapCodeOperand.StoreCheck());    trap.copyPosition(s);    trapBlock.appendInstruction(trap);    ir.cfg.addLastInCodeOrder(trapBlock);    OPT_Operand rhsGuard = guard;    if (couldBeNull) {      // if rhs is null, then the checkcast succeeds      rhsGuard = ir.regpool.makeTempValidation();      contBlock.prependInstruction(Binary.create(GUARD_COMBINE,                                                  guardResult,                                                  guardResult.copyRO(),                                                  rhsGuard.copy()));      curBlock.appendInstruction(IfCmp.create(REF_IFCMP, rhsGuard.asRegister(),                                               elemRef,                                               new OPT_NullConstantOperand(),                                              OPT_ConditionOperand.EQUAL(),                                               contBlock.makeJumpTarget(),                                               new OPT_BranchProfileOperand()));      curBlock.insertOut(contBlock);      curBlock = advanceBlock(s.bcIndex, curBlock, ir);    }              // Find out what we think the compile time type of the lhs is.    // Based on this, we can do one of several things:    //  (1) If the compile time element type is a final proper class, then a     //      TIB comparision of the runtime elemRef type and the     //      compile time element type is definitive.    //  (2) If the compile time type is known to be the declared type,    //      then inject a short-circuit test to see if the     //      runtime lhs type is the same as the compile-time lhs type.    //  (3) If the compile time element type is a proper class other than     //      java.lang.Object, then a subclass test of the runtime LHS elem type     //      and the runtime elemRef type is definitive.  Note: we must exclude    //      java.lang.Object because if the compile time element type is     //      java.lang.Object, then the runtime-element type might actually be     //      an interface (ie not a proper class), and we won't be testing the right thing!    // If we think the compile time type is JavaLangObjectType then    // we lost type information due to unloaded classes causing    // imprecise meets.  This should only happen once in a blue moon,    // so don't bother trying anything clever when it does.    VM_Type compType = arrayRef.getType().peekResolvedType();    if (compType != null && !compType.isJavaLangObjectType()) {      // optionally (1) from above      if (compType.getDimensionality() == 1) {        VM_Class etc = (VM_Class)compType.asArray().getElementType();        if (etc.isResolved() && etc.isFinal()) {          if (VM.VerifyAssertions) VM._assert(!etc.isInterface());          OPT_RegisterOperand rhsTIB = getTIB(curBlock.lastInstruction(), ir, elemRef.copy(), rhsGuard.copy());          OPT_Operand etTIB = getTIB(curBlock.lastInstruction(), ir, etc);          curBlock.appendInstruction(IfCmp.create(REF_IFCMP, guardResult.copyRO(),                                                   rhsTIB, etTIB,                                                  OPT_ConditionOperand.NOT_EQUAL(),                                                   trapBlock.makeJumpTarget(),                                                  OPT_BranchProfileOperand.never()));          curBlock.insertOut(trapBlock);          curBlock.insertOut(contBlock);          ir.cfg.linkInCodeOrder(curBlock, contBlock);          return curBlock.lastInstruction();        }      }      // optionally (2) from above      OPT_RegisterOperand lhsTIB = getTIB(curBlock.lastInstruction(), ir, arrayRef, guard);      if (((arrayRef instanceof OPT_RegisterOperand)&&((OPT_RegisterOperand)arrayRef).isDeclaredType()) || compType == VM_Type.JavaLangObjectArrayType) {        OPT_Operand declTIB = getTIB(curBlock.lastInstruction(), ir, compType);        curBlock.appendInstruction(IfCmp.create(REF_IFCMP, guardResult.copyRO(),                                                 declTIB, lhsTIB,                                                OPT_ConditionOperand.EQUAL(),                                                 contBlock.makeJumpTarget(),                                                new OPT_BranchProfileOperand()));        curBlock.insertOut(contBlock);        curBlock = advanceBlock(s.bcIndex, curBlock, ir);      }      // On our way to doing (3) from above attempt another short-circuit.      // If lhsElemTIB == rhsTIB, then we are done.      OPT_RegisterOperand rhsTIB = getTIB(curBlock.lastInstruction(), ir, elemRef.copy(), rhsGuard.copy());      OPT_RegisterOperand lhsElemTIB =         InsertUnary(curBlock.lastInstruction(), ir, GET_ARRAY_ELEMENT_TIB_FROM_TIB,                     VM_TypeReference.JavaLangObjectArray,                     lhsTIB.copyRO());      curBlock.appendInstruction(IfCmp.create(REF_IFCMP, guardResult.copyRO(),                                               rhsTIB, lhsElemTIB,                                              OPT_ConditionOperand.EQUAL(),                                               contBlock.makeJumpTarget(),                                              new OPT_BranchProfileOperand()));      curBlock.insertOut(contBlock);      curBlock = advanceBlock(s.bcIndex, curBlock, ir);      // Optionally (3) from above       if (compType.getDimensionality() == 1) {        VM_Class etc = (VM_Class)compType.asArray().getElementType();        if (etc.isResolved() && !etc.isInterface() && !etc.isJavaLangObjectType()) {          OPT_RegisterOperand lhsElemType =             InsertUnary(curBlock.lastInstruction(), ir,                         GET_TYPE_FROM_TIB, VM_TypeReference.VM_Type,                         lhsElemTIB.copyU2U());          OPT_RegisterOperand rhsSuperclassIds =             InsertUnary(curBlock.lastInstruction(), ir, GET_SUPERCLASS_IDS_FROM_TIB,                         VM_TypeReference.ShortArray, rhsTIB.copyD2U());          OPT_RegisterOperand lhsElemDepth =             getField(curBlock.lastInstruction(), ir, lhsElemType, VM_Entrypoints.depthField, TG());          OPT_RegisterOperand rhsSuperclassIdsLength =             InsertGuardedUnary(curBlock.lastInstruction(), ir,                                ARRAYLENGTH, VM_TypeReference.Int,                               rhsSuperclassIds.copyD2U(), TG());          curBlock.appendInstruction(IfCmp.create(INT_IFCMP, guardResult.copyRO(),                                                   lhsElemDepth,                                                   rhsSuperclassIdsLength,                                                  OPT_ConditionOperand.GREATER_EQUAL(),                                                   trapBlock.makeJumpTarget(),                                                  OPT_BranchProfileOperand.never()));          curBlock.insertOut(trapBlock);          curBlock = advanceBlock(s.bcIndex, curBlock, ir);          OPT_RegisterOperand lhsElemId =             getField(curBlock.lastInstruction(), ir, lhsElemType.copyD2U(), VM_Entrypoints.idField, TG());          OPT_RegisterOperand refCandidate = ir.regpool.makeTemp(VM_TypeReference.Short);          OPT_LocationOperand loc = new OPT_LocationOperand(VM_TypeReference.Short);          if (LOWER_ARRAY_ACCESS) {            OPT_RegisterOperand lhsDepthOffset =               InsertBinary(curBlock.lastInstruction(), ir, INT_SHL, VM_TypeReference.Int,                           lhsElemDepth.copyD2U(), IC(1));            lhsDepthOffset = InsertUnary(curBlock.lastInstruction(), ir, INT_2ADDRZerExt, VM_TypeReference.Offset, lhsDepthOffset.copy());            curBlock.appendInstruction(Load.create(USHORT_LOAD, refCandidate,                                                    rhsSuperclassIds,                                                    lhsDepthOffset, loc, TG()));          } else {            curBlock.appendInstruction(ALoad.create(USHORT_ALOAD, refCandidate,                                                     rhsSuperclassIds,                                                     lhsElemDepth, loc, TG()));          }          curBlock.appendInstruction(IfCmp.create(INT_IFCMP, guardResult.copyRO(),                                                  refCandidate.copyD2U(),                                                   lhsElemId,                                                  OPT_ConditionOperand.NOT_EQUAL(),                                                   trapBlock.makeJumpTarget(),                                                  OPT_BranchProfileOperand.never()));          curBlock.insertOut(trapBlock);          curBlock.insertOut(contBlock);          ir.cfg.linkInCodeOrder(curBlock, contBlock);          return curBlock.lastInstruction();        }      }    }    // Call VM_Runtime.checkstore.    VM_Method target = VM_Entrypoints.checkstoreMethod;    OPT_Instruction call = Call.create2(CALL, null, AC(target.getOffset()),                                        OPT_MethodOperand.STATIC(target),                                        rhsGuard.copy(), arrayRef.copy(), elemRef.copy());    call.copyPosition(s);    curBlock.appendInstruction(call);    curBlock.insertOut(contBlock);    ir.cfg.linkInCodeOrder(curBlock, contBlock);    return callHelper(call, ir);  }