Home | History | Annotate | Download | only in mips
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * This file contains codegen and support common to all supported
     19  * Mips variants.  It is included by:
     20  *
     21  *        Codegen-$(TARGET_ARCH_VARIANT).c
     22  *
     23  * which combines this common code with specific support found in the
     24  * applicable directory below this one.
     25  */
     26 
     27 /*
     28  * Mark garbage collection card. Skip if the value we're storing is null.
     29  */
     30 static void markCard(CompilationUnit *cUnit, int valReg, int tgtAddrReg)
     31 {
     32     int regCardBase = dvmCompilerAllocTemp(cUnit);
     33     int regCardNo = dvmCompilerAllocTemp(cUnit);
     34     MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBeq, valReg, r_ZERO);
     35     loadWordDisp(cUnit, rSELF, offsetof(Thread, cardTable),
     36                  regCardBase);
     37     opRegRegImm(cUnit, kOpLsr, regCardNo, tgtAddrReg, GC_CARD_SHIFT);
     38     storeBaseIndexed(cUnit, regCardBase, regCardNo, regCardBase, 0,
     39                      kUnsignedByte);
     40     MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
     41     target->defMask = ENCODE_ALL;
     42     branchOver->generic.target = (LIR *)target;
     43     dvmCompilerFreeTemp(cUnit, regCardBase);
     44     dvmCompilerFreeTemp(cUnit, regCardNo);
     45 }
     46 
     47 static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
     48                                      int srcSize, int tgtSize)
     49 {
     50     /*
     51      * Don't optimize the register usage since it calls out to template
     52      * functions
     53      */
     54     RegLocation rlSrc;
     55     RegLocation rlDest;
     56     int srcReg = 0;
     57     int srcRegHi = 0;
     58     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
     59 
     60     if (srcSize == kWord) {
     61         srcReg = r_A0;
     62     } else if (srcSize == kSingle) {
     63 #ifdef __mips_hard_float
     64         srcReg = r_F12;
     65 #else
     66         srcReg = r_A0;
     67 #endif
     68     } else if (srcSize == kLong) {
     69         srcReg = r_ARG0;
     70         srcRegHi = r_ARG1;
     71     } else if (srcSize == kDouble) {
     72 #ifdef __mips_hard_float
     73         srcReg = r_FARG0;
     74         srcRegHi = r_FARG1;
     75 #else
     76         srcReg = r_ARG0;
     77         srcRegHi = r_ARG1;
     78 #endif
     79     }
     80     else {
     81         assert(0);
     82     }
     83 
     84     if (srcSize == kWord || srcSize == kSingle) {
     85         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
     86         loadValueDirectFixed(cUnit, rlSrc, srcReg);
     87     } else {
     88         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
     89         loadValueDirectWideFixed(cUnit, rlSrc, srcReg, srcRegHi);
     90     }
     91     LOAD_FUNC_ADDR(cUnit, r_T9, (int)funct);
     92     opReg(cUnit, kOpBlx, r_T9);
     93     newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
     94     dvmCompilerClobberCallRegs(cUnit);
     95     if (tgtSize == kWord || tgtSize == kSingle) {
     96         RegLocation rlResult;
     97         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
     98 #ifdef __mips_hard_float
     99         if (tgtSize == kSingle)
    100             rlResult = dvmCompilerGetReturnAlt(cUnit);
    101         else
    102             rlResult = dvmCompilerGetReturn(cUnit);
    103 #else
    104         rlResult = dvmCompilerGetReturn(cUnit);
    105 #endif
    106         storeValue(cUnit, rlDest, rlResult);
    107     } else {
    108         RegLocation rlResult;
    109         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
    110 #ifdef __mips_hard_float
    111         if (tgtSize == kDouble)
    112             rlResult = dvmCompilerGetReturnWideAlt(cUnit);
    113         else
    114             rlResult = dvmCompilerGetReturnWide(cUnit);
    115 #else
    116         rlResult = dvmCompilerGetReturnWide(cUnit);
    117 #endif
    118         storeValueWide(cUnit, rlDest, rlResult);
    119     }
    120     return false;
    121 }
    122 
    123 
    124 static bool genArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
    125                                     RegLocation rlDest, RegLocation rlSrc1,
    126                                     RegLocation rlSrc2)
    127 {
    128     RegLocation rlResult;
    129     void* funct;
    130 
    131     switch (mir->dalvikInsn.opcode) {
    132         case OP_ADD_FLOAT_2ADDR:
    133         case OP_ADD_FLOAT:
    134             funct = (void*) __addsf3;
    135             break;
    136         case OP_SUB_FLOAT_2ADDR:
    137         case OP_SUB_FLOAT:
    138             funct = (void*) __subsf3;
    139             break;
    140         case OP_DIV_FLOAT_2ADDR:
    141         case OP_DIV_FLOAT:
    142             funct = (void*) __divsf3;
    143             break;
    144         case OP_MUL_FLOAT_2ADDR:
    145         case OP_MUL_FLOAT:
    146             funct = (void*) __mulsf3;
    147             break;
    148         case OP_REM_FLOAT_2ADDR:
    149         case OP_REM_FLOAT:
    150             funct = (void*) fmodf;
    151             break;
    152         case OP_NEG_FLOAT: {
    153             genNegFloat(cUnit, rlDest, rlSrc1);
    154             return false;
    155         }
    156         default:
    157             return true;
    158     }
    159 
    160     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
    161 #ifdef __mips_hard_float
    162     loadValueDirectFixed(cUnit, rlSrc1, r_F12);
    163     loadValueDirectFixed(cUnit, rlSrc2, r_F14);
    164 #else
    165     loadValueDirectFixed(cUnit, rlSrc1, r_A0);
    166     loadValueDirectFixed(cUnit, rlSrc2, r_A1);
    167 #endif
    168     LOAD_FUNC_ADDR(cUnit, r_T9, (int)funct);
    169     opReg(cUnit, kOpBlx, r_T9);
    170     newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
    171     dvmCompilerClobberCallRegs(cUnit);
    172 #ifdef __mips_hard_float
    173     rlResult = dvmCompilerGetReturnAlt(cUnit);
    174 #else
    175     rlResult = dvmCompilerGetReturn(cUnit);
    176 #endif
    177     storeValue(cUnit, rlDest, rlResult);
    178     return false;
    179 }
    180 
    181 static bool genArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
    182                                      RegLocation rlDest, RegLocation rlSrc1,
    183                                      RegLocation rlSrc2)
    184 {
    185     RegLocation rlResult;
    186     void* funct;
    187 
    188     switch (mir->dalvikInsn.opcode) {
    189         case OP_ADD_DOUBLE_2ADDR:
    190         case OP_ADD_DOUBLE:
    191             funct = (void*) __adddf3;
    192             break;
    193         case OP_SUB_DOUBLE_2ADDR:
    194         case OP_SUB_DOUBLE:
    195             funct = (void*) __subdf3;
    196             break;
    197         case OP_DIV_DOUBLE_2ADDR:
    198         case OP_DIV_DOUBLE:
    199             funct = (void*) __divsf3;
    200             break;
    201         case OP_MUL_DOUBLE_2ADDR:
    202         case OP_MUL_DOUBLE:
    203             funct = (void*) __muldf3;
    204             break;
    205         case OP_REM_DOUBLE_2ADDR:
    206         case OP_REM_DOUBLE:
    207             funct = (void*) (double (*)(double, double)) fmod;
    208             break;
    209         case OP_NEG_DOUBLE: {
    210             genNegDouble(cUnit, rlDest, rlSrc1);
    211             return false;
    212         }
    213         default:
    214             return true;
    215     }
    216     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
    217     LOAD_FUNC_ADDR(cUnit, r_T9, (int)funct);
    218 #ifdef __mips_hard_float
    219     loadValueDirectWideFixed(cUnit, rlSrc1, r_F12, r_F13);
    220     loadValueDirectWideFixed(cUnit, rlSrc2, r_F14, r_F15);
    221 #else
    222     loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
    223     loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
    224 #endif
    225     opReg(cUnit, kOpBlx, r_T9);
    226     newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
    227     dvmCompilerClobberCallRegs(cUnit);
    228 #ifdef __mips_hard_float
    229     rlResult = dvmCompilerGetReturnWideAlt(cUnit);
    230 #else
    231     rlResult = dvmCompilerGetReturnWide(cUnit);
    232 #endif
    233     storeValueWide(cUnit, rlDest, rlResult);
    234 #if defined(WITH_SELF_VERIFICATION)
    235     cUnit->usesLinkRegister = true;
    236 #endif
    237     return false;
    238 }
    239 
    240 static bool genConversionPortable(CompilationUnit *cUnit, MIR *mir)
    241 {
    242     Opcode opcode = mir->dalvikInsn.opcode;
    243 
    244     switch (opcode) {
    245         case OP_INT_TO_FLOAT:
    246             return genConversionCall(cUnit, mir, (void*)__floatsisf, kWord, kSingle);
    247         case OP_FLOAT_TO_INT:
    248             return genConversionCall(cUnit, mir, (void*)__fixsfsi, kSingle, kWord);
    249         case OP_DOUBLE_TO_FLOAT:
    250             return genConversionCall(cUnit, mir, (void*)__truncdfsf2, kDouble, kSingle);
    251         case OP_FLOAT_TO_DOUBLE:
    252             return genConversionCall(cUnit, mir, (void*)__extendsfdf2, kSingle, kDouble);
    253         case OP_INT_TO_DOUBLE:
    254             return genConversionCall(cUnit, mir, (void*)__floatsidf, kWord, kDouble);
    255         case OP_DOUBLE_TO_INT:
    256             return genConversionCall(cUnit, mir, (void*)__fixdfsi, kDouble, kWord);
    257         case OP_FLOAT_TO_LONG:
    258             return genConversionCall(cUnit, mir, (void*)__fixsfdi, kSingle, kLong);
    259         case OP_LONG_TO_FLOAT:
    260             return genConversionCall(cUnit, mir, (void*)__floatdisf, kLong, kSingle);
    261         case OP_DOUBLE_TO_LONG:
    262             return genConversionCall(cUnit, mir, (void*)__fixdfdi, kDouble, kLong);
    263         case OP_LONG_TO_DOUBLE:
    264             return genConversionCall(cUnit, mir, (void*)__floatdidf, kLong, kDouble);
    265         default:
    266             return true;
    267     }
    268     return false;
    269 }
    270 
    271 #if defined(WITH_SELF_VERIFICATION)
    272 static void selfVerificationBranchInsert(LIR *currentLIR, Mipsopcode opcode,
    273                           int dest, int src1)
    274 {
    275 assert(0); /* MIPSTODO port selfVerificationBranchInsert() */
    276      MipsLIR *insn = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
    277      insn->opcode = opcode;
    278      insn->operands[0] = dest;
    279      insn->operands[1] = src1;
    280      setupResourceMasks(insn);
    281      dvmCompilerInsertLIRBefore(currentLIR, (LIR *) insn);
    282 }
    283 
    284 /*
    285  * Example where r14 (LR) is preserved around a heap access under
    286  * self-verification mode in Thumb2:
    287  *
    288  * D/dalvikvm( 1538): 0x59414c5e (0026): ldr     r14, [r15pc, #220] <-hoisted
    289  * D/dalvikvm( 1538): 0x59414c62 (002a): mla     r4, r0, r8, r4
    290  * D/dalvikvm( 1538): 0x59414c66 (002e): adds    r3, r4, r3
    291  * D/dalvikvm( 1538): 0x59414c6a (0032): push    <r5, r14>    ---+
    292  * D/dalvikvm( 1538): 0x59414c6c (0034): blx_1   0x5940f494      |
    293  * D/dalvikvm( 1538): 0x59414c6e (0036): blx_2   see above       <-MEM_OP_DECODE
    294  * D/dalvikvm( 1538): 0x59414c70 (0038): ldr     r10, [r9, #0]   |
    295  * D/dalvikvm( 1538): 0x59414c74 (003c): pop     <r5, r14>    ---+
    296  * D/dalvikvm( 1538): 0x59414c78 (0040): mov     r11, r10
    297  * D/dalvikvm( 1538): 0x59414c7a (0042): asr     r12, r11, #31
    298  * D/dalvikvm( 1538): 0x59414c7e (0046): movs    r0, r2
    299  * D/dalvikvm( 1538): 0x59414c80 (0048): movs    r1, r3
    300  * D/dalvikvm( 1538): 0x59414c82 (004a): str     r2, [r5, #16]
    301  * D/dalvikvm( 1538): 0x59414c84 (004c): mov     r2, r11
    302  * D/dalvikvm( 1538): 0x59414c86 (004e): str     r3, [r5, #20]
    303  * D/dalvikvm( 1538): 0x59414c88 (0050): mov     r3, r12
    304  * D/dalvikvm( 1538): 0x59414c8a (0052): str     r11, [r5, #24]
    305  * D/dalvikvm( 1538): 0x59414c8e (0056): str     r12, [r5, #28]
    306  * D/dalvikvm( 1538): 0x59414c92 (005a): blx     r14             <-use of LR
    307  *
    308  */
    309 static void selfVerificationBranchInsertPass(CompilationUnit *cUnit)
    310 {
    311 assert(0); /* MIPSTODO port selfVerificationBranchInsertPass() */
    312     MipsLIR *thisLIR;
    313     Templateopcode opcode = TEMPLATE_MEM_OP_DECODE;
    314 
    315     for (thisLIR = (MipsLIR *) cUnit->firstLIRInsn;
    316          thisLIR != (MipsLIR *) cUnit->lastLIRInsn;
    317          thisLIR = NEXT_LIR(thisLIR)) {
    318         if (!thisLIR->flags.isNop && thisLIR->flags.insertWrapper) {
    319             /*
    320              * Push r5(FP) and r14(LR) onto stack. We need to make sure that
    321              * SP is 8-byte aligned, and we use r5 as a temp to restore LR
    322              * for Thumb-only target since LR cannot be directly accessed in
    323              * Thumb mode. Another reason to choose r5 here is it is the Dalvik
    324              * frame pointer and cannot be the target of the emulated heap
    325              * load.
    326              */
    327             if (cUnit->usesLinkRegister) {
    328                 genSelfVerificationPreBranch(cUnit, thisLIR);
    329             }
    330 
    331             /* Branch to mem op decode template */
    332             selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx1,
    333                        (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
    334                        (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
    335             selfVerificationBranchInsert((LIR *) thisLIR, kThumbBlx2,
    336                        (int) gDvmJit.codeCache + templateEntryOffsets[opcode],
    337                        (int) gDvmJit.codeCache + templateEntryOffsets[opcode]);
    338 
    339             /* Restore LR */
    340             if (cUnit->usesLinkRegister) {
    341                 genSelfVerificationPostBranch(cUnit, thisLIR);
    342             }
    343         }
    344     }
    345 }
    346 #endif
    347 
    348 /* Generate conditional branch instructions */
    349 static MipsLIR *genConditionalBranchMips(CompilationUnit *cUnit,
    350                                     MipsOpCode opc, int rs, int rt,
    351                                     MipsLIR *target)
    352 {
    353     MipsLIR *branch = opCompareBranch(cUnit, opc, rs, rt);
    354     branch->generic.target = (LIR *) target;
    355     return branch;
    356 }
    357 
    358 /* Generate a unconditional branch to go to the interpreter */
    359 static inline MipsLIR *genTrap(CompilationUnit *cUnit, int dOffset,
    360                                   MipsLIR *pcrLabel)
    361 {
    362     MipsLIR *branch = opNone(cUnit, kOpUncondBr);
    363     return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
    364 }
    365 
    366 /* Load a wide field from an object instance */
    367 static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
    368 {
    369     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
    370     RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
    371     RegLocation rlResult;
    372     rlObj = loadValue(cUnit, rlObj, kCoreReg);
    373     int regPtr = dvmCompilerAllocTemp(cUnit);
    374 
    375     assert(rlDest.wide);
    376 
    377     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
    378                  NULL);/* null object? */
    379     opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
    380     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
    381 
    382     HEAP_ACCESS_SHADOW(true);
    383     loadPair(cUnit, regPtr, rlResult.lowReg, rlResult.highReg);
    384     HEAP_ACCESS_SHADOW(false);
    385 
    386     dvmCompilerFreeTemp(cUnit, regPtr);
    387     storeValueWide(cUnit, rlDest, rlResult);
    388 }
    389 
    390 /* Store a wide field to an object instance */
    391 static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
    392 {
    393     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    394     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 2);
    395     rlObj = loadValue(cUnit, rlObj, kCoreReg);
    396     int regPtr;
    397     rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
    398     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
    399                  NULL);/* null object? */
    400     regPtr = dvmCompilerAllocTemp(cUnit);
    401     opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
    402 
    403     HEAP_ACCESS_SHADOW(true);
    404     storePair(cUnit, regPtr, rlSrc.lowReg, rlSrc.highReg);
    405     HEAP_ACCESS_SHADOW(false);
    406 
    407     dvmCompilerFreeTemp(cUnit, regPtr);
    408 }
    409 
    410 /*
    411  * Load a field from an object instance
    412  *
    413  */
    414 static void genIGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
    415                     int fieldOffset, bool isVolatile)
    416 {
    417     RegLocation rlResult;
    418     RegisterClass regClass = dvmCompilerRegClassBySize(size);
    419     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
    420     RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
    421     rlObj = loadValue(cUnit, rlObj, kCoreReg);
    422     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
    423     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
    424                  NULL);/* null object? */
    425 
    426     HEAP_ACCESS_SHADOW(true);
    427     loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
    428                  size, rlObj.sRegLow);
    429     HEAP_ACCESS_SHADOW(false);
    430     if (isVolatile) {
    431         dvmCompilerGenMemBarrier(cUnit, 0);
    432     }
    433 
    434     storeValue(cUnit, rlDest, rlResult);
    435 }
    436 
    437 /*
    438  * Store a field to an object instance
    439  *
    440  */
    441 static void genIPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
    442                     int fieldOffset, bool isObject, bool isVolatile)
    443 {
    444     RegisterClass regClass = dvmCompilerRegClassBySize(size);
    445     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
    446     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 1);
    447     rlObj = loadValue(cUnit, rlObj, kCoreReg);
    448     rlSrc = loadValue(cUnit, rlSrc, regClass);
    449     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
    450                  NULL);/* null object? */
    451 
    452     if (isVolatile) {
    453         dvmCompilerGenMemBarrier(cUnit, 0);
    454     }
    455     HEAP_ACCESS_SHADOW(true);
    456     storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
    457     HEAP_ACCESS_SHADOW(false);
    458     if (isVolatile) {
    459         dvmCompilerGenMemBarrier(cUnit, 0);
    460     }
    461     if (isObject) {
    462         /* NOTE: marking card based on object head */
    463         markCard(cUnit, rlSrc.lowReg, rlObj.lowReg);
    464     }
    465 }
    466 
    467 
    468 /*
    469  * Generate array load
    470  */
    471 static void genArrayGet(CompilationUnit *cUnit, MIR *mir, OpSize size,
    472                         RegLocation rlArray, RegLocation rlIndex,
    473                         RegLocation rlDest, int scale)
    474 {
    475     RegisterClass regClass = dvmCompilerRegClassBySize(size);
    476     int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
    477     int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
    478     RegLocation rlResult;
    479     rlArray = loadValue(cUnit, rlArray, kCoreReg);
    480     rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
    481     int regPtr;
    482 
    483     /* null object? */
    484     MipsLIR * pcrLabel = NULL;
    485 
    486     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
    487         pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
    488                                 rlArray.lowReg, mir->offset, NULL);
    489     }
    490 
    491     regPtr = dvmCompilerAllocTemp(cUnit);
    492 
    493     assert(IS_SIMM16(dataOffset));
    494     if (scale) {
    495         opRegRegImm(cUnit, kOpLsl, regPtr, rlIndex.lowReg, scale);
    496     }
    497 
    498     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
    499         int regLen = dvmCompilerAllocTemp(cUnit);
    500         /* Get len */
    501         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
    502         genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
    503                        pcrLabel);
    504         dvmCompilerFreeTemp(cUnit, regLen);
    505     }
    506 
    507     if (scale) {
    508         opRegReg(cUnit, kOpAdd, regPtr, rlArray.lowReg);
    509     } else {
    510         opRegRegReg(cUnit, kOpAdd, regPtr, rlArray.lowReg, rlIndex.lowReg);
    511     }
    512 
    513     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, regClass, true);
    514     if ((size == kLong) || (size == kDouble)) {
    515         HEAP_ACCESS_SHADOW(true);
    516         loadBaseDispWide(cUnit, mir, regPtr, dataOffset, rlResult.lowReg,
    517                          rlResult.highReg, INVALID_SREG);
    518         HEAP_ACCESS_SHADOW(false);
    519         dvmCompilerFreeTemp(cUnit, regPtr);
    520         storeValueWide(cUnit, rlDest, rlResult);
    521     } else {
    522         HEAP_ACCESS_SHADOW(true);
    523         loadBaseDisp(cUnit, mir, regPtr, dataOffset, rlResult.lowReg,
    524                      size, INVALID_SREG);
    525         HEAP_ACCESS_SHADOW(false);
    526         dvmCompilerFreeTemp(cUnit, regPtr);
    527         storeValue(cUnit, rlDest, rlResult);
    528     }
    529 }
    530 
    531 /*
    532  * Generate array store
    533  *
    534  */
    535 static void genArrayPut(CompilationUnit *cUnit, MIR *mir, OpSize size,
    536                         RegLocation rlArray, RegLocation rlIndex,
    537                         RegLocation rlSrc, int scale)
    538 {
    539     RegisterClass regClass = dvmCompilerRegClassBySize(size);
    540     int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
    541     int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
    542 
    543     int regPtr;
    544     rlArray = loadValue(cUnit, rlArray, kCoreReg);
    545     rlIndex = loadValue(cUnit, rlIndex, kCoreReg);
    546 
    547     if (dvmCompilerIsTemp(cUnit, rlArray.lowReg)) {
    548         dvmCompilerClobber(cUnit, rlArray.lowReg);
    549         regPtr = rlArray.lowReg;
    550     } else {
    551         regPtr = dvmCompilerAllocTemp(cUnit);
    552         genRegCopy(cUnit, regPtr, rlArray.lowReg);
    553     }
    554 
    555     /* null object? */
    556     MipsLIR * pcrLabel = NULL;
    557 
    558     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
    559         pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
    560                                 mir->offset, NULL);
    561     }
    562 
    563     assert(IS_SIMM16(dataOffset));
    564     int tReg = dvmCompilerAllocTemp(cUnit);
    565     if (scale) {
    566         opRegRegImm(cUnit, kOpLsl, tReg, rlIndex.lowReg, scale);
    567     }
    568 
    569     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
    570         int regLen = dvmCompilerAllocTemp(cUnit);
    571         //NOTE: max live temps(4) here.
    572         /* Get len */
    573         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
    574         genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
    575                        pcrLabel);
    576         dvmCompilerFreeTemp(cUnit, regLen);
    577     }
    578 
    579     if (scale) {
    580         opRegReg(cUnit, kOpAdd, tReg, rlArray.lowReg);
    581     } else {
    582         opRegRegReg(cUnit, kOpAdd, tReg, rlArray.lowReg, rlIndex.lowReg);
    583     }
    584 
    585     /* at this point, tReg points to array, 2 live temps */
    586     if ((size == kLong) || (size == kDouble)) {
    587         rlSrc = loadValueWide(cUnit, rlSrc, regClass);
    588         HEAP_ACCESS_SHADOW(true);
    589         storeBaseDispWide(cUnit, tReg, dataOffset, rlSrc.lowReg, rlSrc.highReg)
    590         HEAP_ACCESS_SHADOW(false);
    591         dvmCompilerFreeTemp(cUnit, tReg);
    592         dvmCompilerFreeTemp(cUnit, regPtr);
    593     } else {
    594         rlSrc = loadValue(cUnit, rlSrc, regClass);
    595         HEAP_ACCESS_SHADOW(true);
    596         storeBaseDisp(cUnit, tReg, dataOffset, rlSrc.lowReg, size);
    597         dvmCompilerFreeTemp(cUnit, tReg);
    598         HEAP_ACCESS_SHADOW(false);
    599     }
    600 }
    601 
    602 /*
    603  * Generate array object store
    604  * Must use explicit register allocation here because of
    605  * call-out to dvmCanPutArrayElement
    606  */
    607 static void genArrayObjectPut(CompilationUnit *cUnit, MIR *mir,
    608                               RegLocation rlArray, RegLocation rlIndex,
    609                               RegLocation rlSrc, int scale)
    610 {
    611     int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
    612     int dataOffset = OFFSETOF_MEMBER(ArrayObject, contents);
    613 
    614     int regLen = r_A0;
    615     int regPtr = r_S0;  /* Preserved across call */
    616     int regArray = r_A1;
    617     int regIndex = r_S4;  /* Preserved across call */
    618 
    619     dvmCompilerFlushAllRegs(cUnit);
    620     // moved lock for r_S0 and r_S4 here from below since genBoundsCheck
    621     // allocates a temporary that can result in clobbering either of them
    622     dvmCompilerLockTemp(cUnit, regPtr);   // r_S0
    623     dvmCompilerLockTemp(cUnit, regIndex); // r_S4
    624 
    625     loadValueDirectFixed(cUnit, rlArray, regArray);
    626     loadValueDirectFixed(cUnit, rlIndex, regIndex);
    627 
    628     /* null object? */
    629     MipsLIR * pcrLabel = NULL;
    630 
    631     if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
    632         pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, regArray,
    633                                 mir->offset, NULL);
    634     }
    635 
    636     if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
    637         /* Get len */
    638         loadWordDisp(cUnit, regArray, lenOffset, regLen);
    639         /* regPtr -> array data */
    640         opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
    641         genBoundsCheck(cUnit, regIndex, regLen, mir->offset,
    642                        pcrLabel);
    643     } else {
    644         /* regPtr -> array data */
    645         opRegRegImm(cUnit, kOpAdd, regPtr, regArray, dataOffset);
    646     }
    647 
    648     /* Get object to store */
    649     loadValueDirectFixed(cUnit, rlSrc, r_A0);
    650     LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmCanPutArrayElement);
    651 
    652     /* Are we storing null?  If so, avoid check */
    653     MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBeqz, r_A0, -1);
    654 
    655     /* Make sure the types are compatible */
    656     loadWordDisp(cUnit, regArray, offsetof(Object, clazz), r_A1);
    657     loadWordDisp(cUnit, r_A0, offsetof(Object, clazz), r_A0);
    658     opReg(cUnit, kOpBlx, r_T9);
    659     newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
    660     dvmCompilerClobberCallRegs(cUnit);
    661 
    662     /*
    663      * Using fixed registers here, and counting on r_S0 and r_S4 being
    664      * preserved across the above call.  Tell the register allocation
    665      * utilities about the regs we are using directly
    666      */
    667     dvmCompilerLockTemp(cUnit, r_A0);
    668     dvmCompilerLockTemp(cUnit, r_A1);
    669 
    670     /* Bad? - roll back and re-execute if so */
    671     genRegImmCheck(cUnit, kMipsCondEq, r_V0, 0, mir->offset, pcrLabel);
    672 
    673     /* Resume here - must reload element & array, regPtr & index preserved */
    674     loadValueDirectFixed(cUnit, rlSrc, r_A0);
    675     loadValueDirectFixed(cUnit, rlArray, r_A1);
    676 
    677     MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
    678     target->defMask = ENCODE_ALL;
    679     branchOver->generic.target = (LIR *) target;
    680 
    681     HEAP_ACCESS_SHADOW(true);
    682     storeBaseIndexed(cUnit, regPtr, regIndex, r_A0,
    683                      scale, kWord);
    684     HEAP_ACCESS_SHADOW(false);
    685 
    686     dvmCompilerFreeTemp(cUnit, regPtr);
    687     dvmCompilerFreeTemp(cUnit, regIndex);
    688 
    689     /* NOTE: marking card here based on object head */
    690     markCard(cUnit, r_A0, r_A1);
    691 }
    692 
    693 static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir,
    694                            RegLocation rlDest, RegLocation rlSrc1,
    695                            RegLocation rlShift)
    696 {
    697     /*
    698      * Don't mess with the regsiters here as there is a particular calling
    699      * convention to the out-of-line handler.
    700      */
    701     RegLocation rlResult;
    702 
    703     loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
    704     loadValueDirect(cUnit, rlShift, r_A2);
    705     switch( mir->dalvikInsn.opcode) {
    706         case OP_SHL_LONG:
    707         case OP_SHL_LONG_2ADDR:
    708             genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
    709             break;
    710         case OP_SHR_LONG:
    711         case OP_SHR_LONG_2ADDR:
    712             genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
    713             break;
    714         case OP_USHR_LONG:
    715         case OP_USHR_LONG_2ADDR:
    716             genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
    717             break;
    718         default:
    719             return true;
    720     }
    721     rlResult = dvmCompilerGetReturnWide(cUnit);
    722     storeValueWide(cUnit, rlDest, rlResult);
    723     return false;
    724 }
    725 
    726 static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir,
    727                            RegLocation rlDest, RegLocation rlSrc1,
    728                            RegLocation rlSrc2)
    729 {
    730     RegLocation rlResult;
    731     OpKind firstOp = kOpBkpt;
    732     OpKind secondOp = kOpBkpt;
    733     bool callOut = false;
    734     void *callTgt;
    735 
    736     switch (mir->dalvikInsn.opcode) {
    737         case OP_NOT_LONG:
    738             rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
    739             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
    740             opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
    741             opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
    742             storeValueWide(cUnit, rlDest, rlResult);
    743             return false;
    744             break;
    745         case OP_ADD_LONG:
    746         case OP_ADD_LONG_2ADDR:
    747             firstOp = kOpAdd;
    748             secondOp = kOpAdc;
    749             break;
    750         case OP_SUB_LONG:
    751         case OP_SUB_LONG_2ADDR:
    752             firstOp = kOpSub;
    753             secondOp = kOpSbc;
    754             break;
    755         case OP_MUL_LONG:
    756         case OP_MUL_LONG_2ADDR:
    757             genMulLong(cUnit, rlDest, rlSrc1, rlSrc2);
    758             return false;
    759         case OP_DIV_LONG:
    760         case OP_DIV_LONG_2ADDR:
    761             callOut = true;
    762             callTgt = (void*)__divdi3;
    763             break;
    764         case OP_REM_LONG:
    765         case OP_REM_LONG_2ADDR:
    766             callOut = true;
    767             callTgt = (void*)__moddi3;
    768             break;
    769         case OP_AND_LONG_2ADDR:
    770         case OP_AND_LONG:
    771             firstOp = kOpAnd;
    772             secondOp = kOpAnd;
    773             break;
    774         case OP_OR_LONG:
    775         case OP_OR_LONG_2ADDR:
    776             firstOp = kOpOr;
    777             secondOp = kOpOr;
    778             break;
    779         case OP_XOR_LONG:
    780         case OP_XOR_LONG_2ADDR:
    781             firstOp = kOpXor;
    782             secondOp = kOpXor;
    783             break;
    784         case OP_NEG_LONG: {
    785             int tReg = dvmCompilerAllocTemp(cUnit);
    786             rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
    787             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
    788             newLIR3(cUnit, kMipsSubu, rlResult.lowReg, r_ZERO, rlSrc2.lowReg);
    789             newLIR3(cUnit, kMipsSubu, tReg, r_ZERO, rlSrc2.highReg);
    790             newLIR3(cUnit, kMipsSltu, rlResult.highReg, r_ZERO, rlResult.lowReg);
    791             newLIR3(cUnit, kMipsSubu, rlResult.highReg, tReg, rlResult.highReg);
    792             dvmCompilerFreeTemp(cUnit, tReg);
    793             storeValueWide(cUnit, rlDest, rlResult);
    794             return false;
    795             break;
    796         }
    797         default:
    798             ALOGE("Invalid long arith op");
    799             dvmCompilerAbort(cUnit);
    800     }
    801     if (!callOut) {
    802         genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
    803     } else {
    804         dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
    805         loadValueDirectWideFixed(cUnit, rlSrc1, r_ARG0, r_ARG1);
    806         LOAD_FUNC_ADDR(cUnit, r_T9, (int) callTgt);
    807         loadValueDirectWideFixed(cUnit, rlSrc2, r_ARG2, r_ARG3);
    808         opReg(cUnit, kOpBlx, r_T9);
    809         newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
    810         dvmCompilerClobberCallRegs(cUnit);
    811         rlResult = dvmCompilerGetReturnWide(cUnit);
    812         storeValueWide(cUnit, rlDest, rlResult);
    813 #if defined(WITH_SELF_VERIFICATION)
    814         cUnit->usesLinkRegister = true;
    815 #endif
    816     }
    817     return false;
    818 }
    819 
    820 static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir,
    821                           RegLocation rlDest, RegLocation rlSrc1,
    822                           RegLocation rlSrc2)
    823 {
    824     OpKind op = kOpBkpt;
    825     bool checkZero = false;
    826     bool unary = false;
    827     RegLocation rlResult;
    828     bool shiftOp = false;
    829     int isDivRem = false;
    830     MipsOpCode opc;
    831     int divReg;
    832 
    833     switch (mir->dalvikInsn.opcode) {
    834         case OP_NEG_INT:
    835             op = kOpNeg;
    836             unary = true;
    837             break;
    838         case OP_NOT_INT:
    839             op = kOpMvn;
    840             unary = true;
    841             break;
    842         case OP_ADD_INT:
    843         case OP_ADD_INT_2ADDR:
    844             op = kOpAdd;
    845             break;
    846         case OP_SUB_INT:
    847         case OP_SUB_INT_2ADDR:
    848             op = kOpSub;
    849             break;
    850         case OP_MUL_INT:
    851         case OP_MUL_INT_2ADDR:
    852             op = kOpMul;
    853             break;
    854         case OP_DIV_INT:
    855         case OP_DIV_INT_2ADDR:
    856             isDivRem = true;
    857             checkZero = true;
    858             opc = kMipsMflo;
    859             divReg = r_LO;
    860             break;
    861         case OP_REM_INT:
    862         case OP_REM_INT_2ADDR:
    863             isDivRem = true;
    864             checkZero = true;
    865             opc = kMipsMfhi;
    866             divReg = r_HI;
    867             break;
    868         case OP_AND_INT:
    869         case OP_AND_INT_2ADDR:
    870             op = kOpAnd;
    871             break;
    872         case OP_OR_INT:
    873         case OP_OR_INT_2ADDR:
    874             op = kOpOr;
    875             break;
    876         case OP_XOR_INT:
    877         case OP_XOR_INT_2ADDR:
    878             op = kOpXor;
    879             break;
    880         case OP_SHL_INT:
    881         case OP_SHL_INT_2ADDR:
    882             shiftOp = true;
    883             op = kOpLsl;
    884             break;
    885         case OP_SHR_INT:
    886         case OP_SHR_INT_2ADDR:
    887             shiftOp = true;
    888             op = kOpAsr;
    889             break;
    890         case OP_USHR_INT:
    891         case OP_USHR_INT_2ADDR:
    892             shiftOp = true;
    893             op = kOpLsr;
    894             break;
    895         default:
    896             ALOGE("Invalid word arith op: %#x(%d)",
    897                  mir->dalvikInsn.opcode, mir->dalvikInsn.opcode);
    898             dvmCompilerAbort(cUnit);
    899     }
    900 
    901     rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
    902     if (unary) {
    903         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
    904         opRegReg(cUnit, op, rlResult.lowReg,
    905                  rlSrc1.lowReg);
    906     } else if (isDivRem) {
    907         rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
    908         if (checkZero) {
    909             genNullCheck(cUnit, rlSrc2.sRegLow, rlSrc2.lowReg, mir->offset, NULL);
    910         }
    911         newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc1.lowReg, rlSrc2.lowReg);
    912         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
    913         newLIR2(cUnit, opc, rlResult.lowReg, divReg);
    914     } else {
    915         rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
    916         if (shiftOp) {
    917             int tReg = dvmCompilerAllocTemp(cUnit);
    918             opRegRegImm(cUnit, kOpAnd, tReg, rlSrc2.lowReg, 31);
    919             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
    920             opRegRegReg(cUnit, op, rlResult.lowReg,
    921                         rlSrc1.lowReg, tReg);
    922             dvmCompilerFreeTemp(cUnit, tReg);
    923         } else {
    924             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
    925             opRegRegReg(cUnit, op, rlResult.lowReg,
    926                         rlSrc1.lowReg, rlSrc2.lowReg);
    927         }
    928     }
    929     storeValue(cUnit, rlDest, rlResult);
    930 
    931     return false;
    932 }
    933 
    934 static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
    935 {
    936     Opcode opcode = mir->dalvikInsn.opcode;
    937     RegLocation rlDest;
    938     RegLocation rlSrc1;
    939     RegLocation rlSrc2;
    940     /* Deduce sizes of operands */
    941     if (mir->ssaRep->numUses == 2) {
    942         rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
    943         rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
    944     } else if (mir->ssaRep->numUses == 3) {
    945         rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    946         rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
    947     } else {
    948         rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
    949         rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
    950         assert(mir->ssaRep->numUses == 4);
    951     }
    952     if (mir->ssaRep->numDefs == 1) {
    953         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
    954     } else {
    955         assert(mir->ssaRep->numDefs == 2);
    956         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
    957     }
    958 
    959     if ((opcode >= OP_ADD_LONG_2ADDR) && (opcode <= OP_XOR_LONG_2ADDR)) {
    960         return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    961     }
    962     if ((opcode >= OP_ADD_LONG) && (opcode <= OP_XOR_LONG)) {
    963         return genArithOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    964     }
    965     if ((opcode >= OP_SHL_LONG_2ADDR) && (opcode <= OP_USHR_LONG_2ADDR)) {
    966         return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    967     }
    968     if ((opcode >= OP_SHL_LONG) && (opcode <= OP_USHR_LONG)) {
    969         return genShiftOpLong(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    970     }
    971     if ((opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_USHR_INT_2ADDR)) {
    972         return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    973     }
    974     if ((opcode >= OP_ADD_INT) && (opcode <= OP_USHR_INT)) {
    975         return genArithOpInt(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    976     }
    977     if ((opcode >= OP_ADD_FLOAT_2ADDR) && (opcode <= OP_REM_FLOAT_2ADDR)) {
    978         return genArithOpFloat(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    979     }
    980     if ((opcode >= OP_ADD_FLOAT) && (opcode <= OP_REM_FLOAT)) {
    981         return genArithOpFloat(cUnit, mir, rlDest, rlSrc1, rlSrc2);
    982     }
    983     if ((opcode >= OP_ADD_DOUBLE_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
    984         return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    985     }
    986     if ((opcode >= OP_ADD_DOUBLE) && (opcode <= OP_REM_DOUBLE)) {
    987         return genArithOpDouble(cUnit,mir, rlDest, rlSrc1, rlSrc2);
    988     }
    989     return true;
    990 }
    991 
    992 /* Generate unconditional branch instructions */
    993 static MipsLIR *genUnconditionalBranch(CompilationUnit *cUnit, MipsLIR *target)
    994 {
    995     MipsLIR *branch = opNone(cUnit, kOpUncondBr);
    996     branch->generic.target = (LIR *) target;
    997     return branch;
    998 }
    999 
   1000 /* Perform the actual operation for OP_RETURN_* */
   1001 void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
   1002 {
   1003     genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
   1004                          TEMPLATE_RETURN_PROF : TEMPLATE_RETURN);
   1005 #if defined(WITH_JIT_TUNING)
   1006     gDvmJit.returnOp++;
   1007 #endif
   1008     int dPC = (int) (cUnit->method->insns + mir->offset);
   1009     /* Insert branch, but defer setting of target */
   1010     MipsLIR *branch = genUnconditionalBranch(cUnit, NULL);
   1011     /* Set up the place holder to reconstruct this Dalvik PC */
   1012     MipsLIR *pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
   1013     pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
   1014     pcrLabel->operands[0] = dPC;
   1015     pcrLabel->operands[1] = mir->offset;
   1016     /* Insert the place holder to the growable list */
   1017     dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
   1018     /* Branch to the PC reconstruction code */
   1019     branch->generic.target = (LIR *) pcrLabel;
   1020 }
   1021 
   1022 static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
   1023                                   DecodedInstruction *dInsn,
   1024                                   MipsLIR **pcrLabel)
   1025 {
   1026     unsigned int i;
   1027     unsigned int regMask = 0;
   1028     RegLocation rlArg;
   1029     int numDone = 0;
   1030 
   1031     /*
   1032      * Load arguments to r_A0..r_T0.  Note that these registers may contain
   1033      * live values, so we clobber them immediately after loading to prevent
   1034      * them from being used as sources for subsequent loads.
   1035      */
   1036     dvmCompilerLockAllTemps(cUnit);
   1037     for (i = 0; i < dInsn->vA; i++) {
   1038         regMask |= 1 << i;
   1039         rlArg = dvmCompilerGetSrc(cUnit, mir, numDone++);
   1040         loadValueDirectFixed(cUnit, rlArg, i+r_A0); /* r_A0 thru r_T0 */
   1041     }
   1042     if (regMask) {
   1043         /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
   1044         opRegRegImm(cUnit, kOpSub, r_S4, rFP,
   1045                     sizeof(StackSaveArea) + (dInsn->vA << 2));
   1046         /* generate null check */
   1047         if (pcrLabel) {
   1048             *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r_A0,
   1049                                      mir->offset, NULL);
   1050         }
   1051         storeMultiple(cUnit, r_S4, regMask);
   1052     }
   1053 }
   1054 
   1055 static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
   1056                                 DecodedInstruction *dInsn,
   1057                                 MipsLIR **pcrLabel)
   1058 {
   1059     int srcOffset = dInsn->vC << 2;
   1060     int numArgs = dInsn->vA;
   1061     int regMask;
   1062 
   1063     /*
   1064      * Note: here, all promoted registers will have been flushed
   1065      * back to the Dalvik base locations, so register usage restrictins
   1066      * are lifted.  All parms loaded from original Dalvik register
   1067      * region - even though some might conceivably have valid copies
   1068      * cached in a preserved register.
   1069      */
   1070     dvmCompilerLockAllTemps(cUnit);
   1071 
   1072     /*
   1073      * r4PC     : &rFP[vC]
   1074      * r_S4: &newFP[0]
   1075      */
   1076     opRegRegImm(cUnit, kOpAdd, r4PC, rFP, srcOffset);
   1077     /* load [r_A0 up to r_A3)] */
   1078     regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
   1079     /*
   1080      * Protect the loadMultiple instruction from being reordered with other
   1081      * Dalvik stack accesses.
   1082      */
   1083     if (numArgs != 0) loadMultiple(cUnit, r4PC, regMask);
   1084 
   1085     opRegRegImm(cUnit, kOpSub, r_S4, rFP,
   1086                 sizeof(StackSaveArea) + (numArgs << 2));
   1087     /* generate null check */
   1088     if (pcrLabel) {
   1089         *pcrLabel = genNullCheck(cUnit, dvmCompilerSSASrc(mir, 0), r_A0,
   1090                                  mir->offset, NULL);
   1091     }
   1092 
   1093     /*
   1094      * Handle remaining 4n arguments:
   1095      * store previously loaded 4 values and load the next 4 values
   1096      */
   1097     if (numArgs >= 8) {
   1098         MipsLIR *loopLabel = NULL;
   1099         /*
   1100          * r_A0 contains "this" and it will be used later, so push it to the stack
   1101          * first. Pushing r_S1 (rFP) is just for stack alignment purposes.
   1102          */
   1103 
   1104         newLIR2(cUnit, kMipsMove, r_T0, r_A0);
   1105         newLIR2(cUnit, kMipsMove, r_T1, r_S1);
   1106 
   1107         /* No need to generate the loop structure if numArgs <= 11 */
   1108         if (numArgs > 11) {
   1109             loadConstant(cUnit, rFP, ((numArgs - 4) >> 2) << 2);
   1110             loopLabel = newLIR0(cUnit, kMipsPseudoTargetLabel);
   1111             loopLabel->defMask = ENCODE_ALL;
   1112         }
   1113         storeMultiple(cUnit, r_S4, regMask);
   1114         /*
   1115          * Protect the loadMultiple instruction from being reordered with other
   1116          * Dalvik stack accesses.
   1117          */
   1118         loadMultiple(cUnit, r4PC, regMask);
   1119         /* No need to generate the loop structure if numArgs <= 11 */
   1120         if (numArgs > 11) {
   1121             opRegImm(cUnit, kOpSub, rFP, 4);
   1122             genConditionalBranchMips(cUnit, kMipsBne, rFP, r_ZERO, loopLabel);
   1123         }
   1124     }
   1125 
   1126     /* Save the last batch of loaded values */
   1127     if (numArgs != 0) storeMultiple(cUnit, r_S4, regMask);
   1128 
   1129     /* Generate the loop epilogue - don't use r_A0 */
   1130     if ((numArgs > 4) && (numArgs % 4)) {
   1131         regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
   1132         /*
   1133          * Protect the loadMultiple instruction from being reordered with other
   1134          * Dalvik stack accesses.
   1135          */
   1136         loadMultiple(cUnit, r4PC, regMask);
   1137     }
   1138     if (numArgs >= 8) {
   1139         newLIR2(cUnit, kMipsMove, r_A0, r_T0);
   1140         newLIR2(cUnit, kMipsMove, r_S1, r_T1);
   1141     }
   1142 
   1143     /* Save the modulo 4 arguments */
   1144     if ((numArgs > 4) && (numArgs % 4)) {
   1145         storeMultiple(cUnit, r_S4, regMask);
   1146     }
   1147 }
   1148 
   1149 /*
   1150  * Generate code to setup the call stack then jump to the chaining cell if it
   1151  * is not a native method.
   1152  */
   1153 static void genInvokeSingletonCommon(CompilationUnit *cUnit, MIR *mir,
   1154                                      BasicBlock *bb, MipsLIR *labelList,
   1155                                      MipsLIR *pcrLabel,
   1156                                      const Method *calleeMethod)
   1157 {
   1158     /*
   1159      * Note: all Dalvik register state should be flushed to
   1160      * memory by the point, so register usage restrictions no
   1161      * longer apply.  All temp & preserved registers may be used.
   1162      */
   1163     dvmCompilerLockAllTemps(cUnit);
   1164     MipsLIR *retChainingCell = &labelList[bb->fallThrough->id];
   1165 
   1166     /* r_A1 = &retChainingCell */
   1167     dvmCompilerLockTemp(cUnit, r_A1);
   1168     MipsLIR *addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
   1169     addrRetChain->generic.target = (LIR *) retChainingCell;
   1170     addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
   1171     addrRetChain->generic.target = (LIR *) retChainingCell;
   1172 
   1173     /* r4PC = dalvikCallsite */
   1174     loadConstant(cUnit, r4PC,
   1175                  (int) (cUnit->method->insns + mir->offset));
   1176     /*
   1177      * r_A0 = calleeMethod (loaded upon calling genInvokeSingletonCommon)
   1178      * r_A1 = &ChainingCell
   1179      * r4PC = callsiteDPC
   1180      */
   1181     if (dvmIsNativeMethod(calleeMethod)) {
   1182         genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
   1183             TEMPLATE_INVOKE_METHOD_NATIVE_PROF :
   1184             TEMPLATE_INVOKE_METHOD_NATIVE);
   1185 #if defined(WITH_JIT_TUNING)
   1186         gDvmJit.invokeNative++;
   1187 #endif
   1188     } else {
   1189         genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
   1190             TEMPLATE_INVOKE_METHOD_CHAIN_PROF :
   1191             TEMPLATE_INVOKE_METHOD_CHAIN);
   1192 #if defined(WITH_JIT_TUNING)
   1193         gDvmJit.invokeMonomorphic++;
   1194 #endif
   1195         /* Branch to the chaining cell */
   1196         genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
   1197     }
   1198     /* Handle exceptions using the interpreter */
   1199     genTrap(cUnit, mir->offset, pcrLabel);
   1200 }
   1201 
   1202 /*
   1203  * Generate code to check the validity of a predicted chain and take actions
   1204  * based on the result.
   1205  *
   1206  * 0x2f1304c4 :  lui      s0,0x2d22(11554)            # s0 <- dalvikPC
   1207  * 0x2f1304c8 :  ori      s0,s0,0x2d22848c(757236876)
   1208  * 0x2f1304cc :  lahi/lui a1,0x2f13(12051)            # a1 <- &retChainingCell
   1209  * 0x2f1304d0 :  lalo/ori a1,a1,0x2f13055c(789775708)
   1210  * 0x2f1304d4 :  lahi/lui a2,0x2f13(12051)            # a2 <- &predictedChainingCell
   1211  * 0x2f1304d8 :  lalo/ori a2,a2,0x2f13056c(789775724)
   1212  * 0x2f1304dc :  jal      0x2f12d1ec(789762540)       # call TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
   1213  * 0x2f1304e0 :  nop
   1214  * 0x2f1304e4 :  b        0x2f13056c (L0x11ec10)      # off to the predicted chain
   1215  * 0x2f1304e8 :  nop
   1216  * 0x2f1304ec :  b        0x2f13054c (L0x11fc80)      # punt to the interpreter
   1217  * 0x2f1304f0 :  lui      a0,0x2d22(11554)
   1218  * 0x2f1304f4 :  lw       a0,156(s4)                  # a0 <- this->class->vtable[methodIdx]
   1219  * 0x2f1304f8 :  bgtz     a1,0x2f13051c (L0x11fa40)   # if >0 don't rechain
   1220  * 0x2f1304fc :  nop
   1221  * 0x2f130500 :  lui      t9,0x2aba(10938)
   1222  * 0x2f130504 :  ori      t9,t9,0x2abae3f8(716891128)
   1223  * 0x2f130508 :  move     a1,s2
   1224  * 0x2f13050c :  jalr     ra,t9                       # call dvmJitToPatchPredictedChain
   1225  * 0x2f130510 :  nop
   1226  * 0x2f130514 :  lw       gp,84(sp)
   1227  * 0x2f130518 :  move     a0,v0
   1228  * 0x2f13051c :  lahi/lui a1,0x2f13(12051)            # a1 <- &retChainingCell
   1229  * 0x2f130520 :  lalo/ori a1,a1,0x2f13055c(789775708)
   1230  * 0x2f130524 :  jal      0x2f12d0c4(789762244)       # call TEMPLATE_INVOKE_METHOD_NO_OPT
   1231  * 0x2f130528 :  nop
   1232  */
   1233 static void genInvokeVirtualCommon(CompilationUnit *cUnit, MIR *mir,
   1234                                    int methodIndex,
   1235                                    MipsLIR *retChainingCell,
   1236                                    MipsLIR *predChainingCell,
   1237                                    MipsLIR *pcrLabel)
   1238 {
   1239     /*
   1240      * Note: all Dalvik register state should be flushed to
   1241      * memory by the point, so register usage restrictions no
   1242      * longer apply.  Lock temps to prevent them from being
   1243      * allocated by utility routines.
   1244      */
   1245     dvmCompilerLockAllTemps(cUnit);
   1246 
   1247     /*
   1248      * For verbose printing, store the method pointer in operands[1] first as
   1249      * operands[0] will be clobbered in dvmCompilerMIR2LIR.
   1250      */
   1251     predChainingCell->operands[1] = (int) mir->meta.callsiteInfo->method;
   1252 
   1253     /* "this" is already left in r_A0 by genProcessArgs* */
   1254 
   1255     /* r4PC = dalvikCallsite */
   1256     loadConstant(cUnit, r4PC,
   1257                  (int) (cUnit->method->insns + mir->offset));
   1258 
   1259     /* r_A1 = &retChainingCell */
   1260     MipsLIR *addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
   1261     addrRetChain->generic.target = (LIR *) retChainingCell;
   1262     addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
   1263     addrRetChain->generic.target = (LIR *) retChainingCell;
   1264 
   1265     /* r_A2 = &predictedChainingCell */
   1266     MipsLIR *predictedChainingCell = newLIR2(cUnit, kMipsLahi, r_A2, 0);
   1267     predictedChainingCell->generic.target = (LIR *) predChainingCell;
   1268     predictedChainingCell = newLIR3(cUnit, kMipsLalo, r_A2, r_A2, 0);
   1269     predictedChainingCell->generic.target = (LIR *) predChainingCell;
   1270 
   1271     genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
   1272         TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
   1273         TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
   1274 
   1275     /* return through ra - jump to the chaining cell */
   1276     genUnconditionalBranch(cUnit, predChainingCell);
   1277 
   1278     /*
   1279      * null-check on "this" may have been eliminated, but we still need a PC-
   1280      * reconstruction label for stack overflow bailout.
   1281      */
   1282     if (pcrLabel == NULL) {
   1283         int dPC = (int) (cUnit->method->insns + mir->offset);
   1284         pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
   1285         pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
   1286         pcrLabel->operands[0] = dPC;
   1287         pcrLabel->operands[1] = mir->offset;
   1288         /* Insert the place holder to the growable list */
   1289         dvmInsertGrowableList(&cUnit->pcReconstructionList,
   1290                               (intptr_t) pcrLabel);
   1291     }
   1292 
   1293     /* return through ra+8 - punt to the interpreter */
   1294     genUnconditionalBranch(cUnit, pcrLabel);
   1295 
   1296     /*
   1297      * return through ra+16 - fully resolve the callee method.
   1298      * r_A1 <- count
   1299      * r_A2 <- &predictedChainCell
   1300      * r_A3 <- this->class
   1301      * r4 <- dPC
   1302      * r_S4 <- this->class->vtable
   1303      */
   1304 
   1305     /* r_A0 <- calleeMethod */
   1306     loadWordDisp(cUnit, r_S4, methodIndex * 4, r_A0);
   1307 
   1308     /* Check if rechain limit is reached */
   1309     MipsLIR *bypassRechaining = opCompareBranch(cUnit, kMipsBgtz, r_A1, -1);
   1310 
   1311     LOAD_FUNC_ADDR(cUnit, r_T9, (int) dvmJitToPatchPredictedChain);
   1312 
   1313     genRegCopy(cUnit, r_A1, rSELF);
   1314 
   1315     /*
   1316      * r_A0 = calleeMethod
   1317      * r_A2 = &predictedChainingCell
   1318      * r_A3 = class
   1319      *
   1320      * &returnChainingCell has been loaded into r_A1 but is not needed
   1321      * when patching the chaining cell and will be clobbered upon
   1322      * returning so it will be reconstructed again.
   1323      */
   1324     opReg(cUnit, kOpBlx, r_T9);
   1325     newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   1326     newLIR2(cUnit, kMipsMove, r_A0, r_V0);
   1327 
   1328     /* r_A1 = &retChainingCell */
   1329     addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
   1330     addrRetChain->generic.target = (LIR *) retChainingCell;
   1331     bypassRechaining->generic.target = (LIR *) addrRetChain;
   1332     addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
   1333     addrRetChain->generic.target = (LIR *) retChainingCell;
   1334 
   1335     /*
   1336      * r_A0 = calleeMethod,
   1337      * r_A1 = &ChainingCell,
   1338      * r4PC = callsiteDPC,
   1339      */
   1340     genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
   1341         TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
   1342         TEMPLATE_INVOKE_METHOD_NO_OPT);
   1343 #if defined(WITH_JIT_TUNING)
   1344     gDvmJit.invokePolymorphic++;
   1345 #endif
   1346     /* Handle exceptions using the interpreter */
   1347     genTrap(cUnit, mir->offset, pcrLabel);
   1348 }
   1349 
   1350 /* "this" pointer is already in r0 */
   1351 static void genInvokeVirtualWholeMethod(CompilationUnit *cUnit,
   1352                                         MIR *mir,
   1353                                         void *calleeAddr,
   1354                                         MipsLIR *retChainingCell)
   1355 {
   1356     CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
   1357     dvmCompilerLockAllTemps(cUnit);
   1358 
   1359     loadClassPointer(cUnit, r_A1, (int) callsiteInfo);
   1360 
   1361     loadWordDisp(cUnit, r_A0, offsetof(Object, clazz), r_A2);
   1362     /*
   1363      * Set the misPredBranchOver target so that it will be generated when the
   1364      * code for the non-optimized invoke is generated.
   1365      */
   1366     /* Branch to the slow path if classes are not equal */
   1367     MipsLIR *classCheck = opCompareBranch(cUnit, kMipsBne, r_A1, r_A2);
   1368 
   1369     /* a0 = the Dalvik PC of the callsite */
   1370     loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
   1371 
   1372     newLIR1(cUnit, kMipsJal, (int) calleeAddr);
   1373     genUnconditionalBranch(cUnit, retChainingCell);
   1374 
   1375     /* Target of slow path */
   1376     MipsLIR *slowPathLabel = newLIR0(cUnit, kMipsPseudoTargetLabel);
   1377 
   1378     slowPathLabel->defMask = ENCODE_ALL;
   1379     classCheck->generic.target = (LIR *) slowPathLabel;
   1380 
   1381     // FIXME
   1382     cUnit->printMe = true;
   1383 }
   1384 
   1385 static void genInvokeSingletonWholeMethod(CompilationUnit *cUnit,
   1386                                           MIR *mir,
   1387                                           void *calleeAddr,
   1388                                           MipsLIR *retChainingCell)
   1389 {
   1390     /* a0 = the Dalvik PC of the callsite */
   1391     loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
   1392 
   1393     newLIR1(cUnit, kMipsJal, (int) calleeAddr);
   1394     genUnconditionalBranch(cUnit, retChainingCell);
   1395 
   1396     // FIXME
   1397     cUnit->printMe = true;
   1398 }
   1399 
   1400 /* Geneate a branch to go back to the interpreter */
   1401 static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
   1402 {
   1403     /* a0 = dalvik pc */
   1404     dvmCompilerFlushAllRegs(cUnit);
   1405     loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + offset));
   1406 #if 0 /* MIPSTODO tempoary workaround unaligned access on sigma hardware
   1407              this can removed when we're not punting to genInterpSingleStep
   1408              for opcodes that haven't been activated yet */
   1409     loadWordDisp(cUnit, r_A0, offsetof(Object, clazz), r_A3);
   1410 #endif
   1411     loadWordDisp(cUnit, rSELF, offsetof(Thread,
   1412                  jitToInterpEntries.dvmJitToInterpPunt), r_A1);
   1413 
   1414     opReg(cUnit, kOpBlx, r_A1);
   1415 }
   1416 
   1417 /*
   1418  * Attempt to single step one instruction using the interpreter and return
   1419  * to the compiled code for the next Dalvik instruction
   1420  */
   1421 static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
   1422 {
   1423     int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
   1424     int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn;
   1425 
   1426     // Single stepping is considered loop mode breaker
   1427     if (cUnit->jitMode == kJitLoop) {
   1428         cUnit->quitLoopMode = true;
   1429         return;
   1430     }
   1431 
   1432     //If already optimized out, just ignore
   1433     if (mir->dalvikInsn.opcode == OP_NOP)
   1434         return;
   1435 
   1436     //Ugly, but necessary.  Flush all Dalvik regs so Interp can find them
   1437     dvmCompilerFlushAllRegs(cUnit);
   1438 
   1439     if ((mir->next == NULL) || (flags & flagsToCheck)) {
   1440        genPuntToInterp(cUnit, mir->offset);
   1441        return;
   1442     }
   1443     int entryAddr = offsetof(Thread,
   1444                              jitToInterpEntries.dvmJitToInterpSingleStep);
   1445     loadWordDisp(cUnit, rSELF, entryAddr, r_A2);
   1446     /* a0 = dalvik pc */
   1447     loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
   1448     /* a1 = dalvik pc of following instruction */
   1449     loadConstant(cUnit, r_A1, (int) (cUnit->method->insns + mir->next->offset));
   1450     opReg(cUnit, kOpBlx, r_A2);
   1451 }
   1452 
   1453 /*
   1454  * To prevent a thread in a monitor wait from blocking the Jit from
   1455  * resetting the code cache, heavyweight monitor lock will not
   1456  * be allowed to return to an existing translation.  Instead, we will
   1457  * handle them by branching to a handler, which will in turn call the
   1458  * runtime lock routine and then branch directly back to the
   1459  * interpreter main loop.  Given the high cost of the heavyweight
   1460  * lock operation, this additional cost should be slight (especially when
   1461  * considering that we expect the vast majority of lock operations to
   1462  * use the fast-path thin lock bypass).
   1463  */
   1464 static void genMonitorPortable(CompilationUnit *cUnit, MIR *mir)
   1465 {
   1466     bool isEnter = (mir->dalvikInsn.opcode == OP_MONITOR_ENTER);
   1467     genExportPC(cUnit, mir);
   1468     dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
   1469     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   1470     loadValueDirectFixed(cUnit, rlSrc, r_A1);
   1471     genRegCopy(cUnit, r_A0, rSELF);
   1472     genNullCheck(cUnit, rlSrc.sRegLow, r_A1, mir->offset, NULL);
   1473     if (isEnter) {
   1474         /* Get dPC of next insn */
   1475         loadConstant(cUnit, r4PC, (int)(cUnit->method->insns + mir->offset +
   1476                  dexGetWidthFromOpcode(OP_MONITOR_ENTER)));
   1477         genDispatchToHandler(cUnit, TEMPLATE_MONITOR_ENTER);
   1478     } else {
   1479         LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmUnlockObject);
   1480         /* Do the call */
   1481         opReg(cUnit, kOpBlx, r_T9);
   1482         newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   1483         /* Did we throw? */
   1484         MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
   1485         loadConstant(cUnit, r_A0,
   1486                      (int) (cUnit->method->insns + mir->offset +
   1487                      dexGetWidthFromOpcode(OP_MONITOR_EXIT)));
   1488         genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
   1489         MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   1490         target->defMask = ENCODE_ALL;
   1491         branchOver->generic.target = (LIR *) target;
   1492         dvmCompilerClobberCallRegs(cUnit);
   1493     }
   1494 }
   1495 /*#endif*/
   1496 
   1497 /*
   1498  * Fetch *self->info.breakFlags. If the breakFlags are non-zero,
   1499  * punt to the interpreter.
   1500  */
   1501 static void genSuspendPoll(CompilationUnit *cUnit, MIR *mir)
   1502 {
   1503     int rTemp = dvmCompilerAllocTemp(cUnit);
   1504     MipsLIR *ld;
   1505     ld = loadBaseDisp(cUnit, NULL, rSELF,
   1506                       offsetof(Thread, interpBreak.ctl.breakFlags),
   1507                       rTemp, kUnsignedByte, INVALID_SREG);
   1508     setMemRefType(ld, true /* isLoad */, kMustNotAlias);
   1509     genRegImmCheck(cUnit, kMipsCondNe, rTemp, 0, mir->offset, NULL);
   1510 }
   1511 
   1512 /*
   1513  * The following are the first-level codegen routines that analyze the format
   1514  * of each bytecode then either dispatch special purpose codegen routines
   1515  * or produce corresponding Thumb instructions directly.
   1516  */
   1517 
   1518 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
   1519                                        BasicBlock *bb, MipsLIR *labelList)
   1520 {
   1521     /* backward branch? */
   1522     bool backwardBranch = (bb->taken->startOffset <= mir->offset);
   1523 
   1524     if (backwardBranch &&
   1525         (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
   1526         genSuspendPoll(cUnit, mir);
   1527     }
   1528 
   1529     int numPredecessors = dvmCountSetBits(bb->taken->predecessors);
   1530     /*
   1531      * Things could be hoisted out of the taken block into the predecessor, so
   1532      * make sure it is dominated by the predecessor.
   1533      */
   1534     if (numPredecessors == 1 && bb->taken->visited == false &&
   1535         bb->taken->blockType == kDalvikByteCode) {
   1536         cUnit->nextCodegenBlock = bb->taken;
   1537     } else {
   1538         /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
   1539         genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
   1540     }
   1541     return false;
   1542 }
   1543 
   1544 static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir)
   1545 {
   1546     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   1547     if ((dalvikOpcode >= OP_UNUSED_3E) && (dalvikOpcode <= OP_UNUSED_43)) {
   1548         ALOGE("Codegen: got unused opcode %#x",dalvikOpcode);
   1549         return true;
   1550     }
   1551     switch (dalvikOpcode) {
   1552         case OP_RETURN_VOID_BARRIER:
   1553             dvmCompilerGenMemBarrier(cUnit, 0);
   1554             // Intentional fallthrough
   1555         case OP_RETURN_VOID:
   1556             genReturnCommon(cUnit,mir);
   1557             break;
   1558         case OP_UNUSED_73:
   1559         case OP_UNUSED_79:
   1560         case OP_UNUSED_7A:
   1561         case OP_UNUSED_FF:
   1562             ALOGE("Codegen: got unused opcode %#x",dalvikOpcode);
   1563             return true;
   1564         case OP_NOP:
   1565             break;
   1566         default:
   1567             return true;
   1568     }
   1569     return false;
   1570 }
   1571 
   1572 static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
   1573 {
   1574     RegLocation rlDest;
   1575     RegLocation rlResult;
   1576     if (mir->ssaRep->numDefs == 2) {
   1577         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   1578     } else {
   1579         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1580     }
   1581 
   1582     switch (mir->dalvikInsn.opcode) {
   1583         case OP_CONST:
   1584         case OP_CONST_4: {
   1585             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
   1586             loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
   1587             storeValue(cUnit, rlDest, rlResult);
   1588             break;
   1589         }
   1590         case OP_CONST_WIDE_32: {
   1591             //TUNING: single routine to load constant pair for support doubles
   1592             //TUNING: load 0/-1 separately to avoid load dependency
   1593             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   1594             loadConstantNoClobber(cUnit, rlResult.lowReg, mir->dalvikInsn.vB);
   1595             opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
   1596                         rlResult.lowReg, 31);
   1597             storeValueWide(cUnit, rlDest, rlResult);
   1598             break;
   1599         }
   1600         default:
   1601             return true;
   1602     }
   1603     return false;
   1604 }
   1605 
   1606 static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
   1607 {
   1608     RegLocation rlDest;
   1609     RegLocation rlResult;
   1610     if (mir->ssaRep->numDefs == 2) {
   1611         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   1612     } else {
   1613         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1614     }
   1615     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
   1616 
   1617     switch (mir->dalvikInsn.opcode) {
   1618         case OP_CONST_HIGH16: {
   1619             loadConstantNoClobber(cUnit, rlResult.lowReg,
   1620                                   mir->dalvikInsn.vB << 16);
   1621             storeValue(cUnit, rlDest, rlResult);
   1622             break;
   1623         }
   1624         case OP_CONST_WIDE_HIGH16: {
   1625             loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
   1626                                   0, mir->dalvikInsn.vB << 16);
   1627             storeValueWide(cUnit, rlDest, rlResult);
   1628             break;
   1629         }
   1630         default:
   1631             return true;
   1632     }
   1633     return false;
   1634 }
   1635 
   1636 static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
   1637 {
   1638     /* For OP_THROW_VERIFICATION_ERROR */
   1639     genInterpSingleStep(cUnit, mir);
   1640     return false;
   1641 }
   1642 
   1643 static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
   1644 {
   1645     RegLocation rlResult;
   1646     RegLocation rlDest;
   1647     RegLocation rlSrc;
   1648 
   1649     switch (mir->dalvikInsn.opcode) {
   1650         case OP_CONST_STRING_JUMBO:
   1651         case OP_CONST_STRING: {
   1652             void *strPtr = (void*)
   1653               (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
   1654 
   1655             if (strPtr == NULL) {
   1656                 BAIL_LOOP_COMPILATION();
   1657                 ALOGE("Unexpected null string");
   1658                 dvmAbort();
   1659             }
   1660 
   1661             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1662             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   1663             loadConstantNoClobber(cUnit, rlResult.lowReg, (int) strPtr );
   1664             storeValue(cUnit, rlDest, rlResult);
   1665             break;
   1666         }
   1667         case OP_CONST_CLASS: {
   1668             void *classPtr = (void*)
   1669               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
   1670 
   1671             if (classPtr == NULL) {
   1672                 BAIL_LOOP_COMPILATION();
   1673                 ALOGE("Unexpected null class");
   1674                 dvmAbort();
   1675             }
   1676 
   1677             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1678             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   1679             loadConstantNoClobber(cUnit, rlResult.lowReg, (int) classPtr );
   1680             storeValue(cUnit, rlDest, rlResult);
   1681             break;
   1682         }
   1683         case OP_SGET:
   1684         case OP_SGET_VOLATILE:
   1685         case OP_SGET_OBJECT:
   1686         case OP_SGET_OBJECT_VOLATILE:
   1687         case OP_SGET_BOOLEAN:
   1688         case OP_SGET_CHAR:
   1689         case OP_SGET_BYTE:
   1690         case OP_SGET_SHORT: {
   1691             int valOffset = OFFSETOF_MEMBER(StaticField, value);
   1692             int tReg = dvmCompilerAllocTemp(cUnit);
   1693             bool isVolatile;
   1694             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
   1695                 mir->meta.calleeMethod : cUnit->method;
   1696             void *fieldPtr = (void*)
   1697               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
   1698 
   1699             if (fieldPtr == NULL) {
   1700                 BAIL_LOOP_COMPILATION();
   1701                 ALOGE("Unexpected null static field");
   1702                 dvmAbort();
   1703             }
   1704 
   1705             /*
   1706              * On SMP systems, Dalvik opcodes found to be referencing
   1707              * volatile fields are rewritten to their _VOLATILE variant.
   1708              * However, this does not happen on non-SMP systems. The JIT
   1709              * still needs to know about volatility to avoid unsafe
   1710              * optimizations so we determine volatility based on either
   1711              * the opcode or the field access flags.
   1712              */
   1713 #if ANDROID_SMP != 0
   1714             Opcode opcode = mir->dalvikInsn.opcode;
   1715             isVolatile = (opcode == OP_SGET_VOLATILE) ||
   1716                          (opcode == OP_SGET_OBJECT_VOLATILE);
   1717             assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
   1718 #else
   1719             isVolatile = dvmIsVolatileField((Field *) fieldPtr);
   1720 #endif
   1721 
   1722             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1723             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
   1724             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
   1725 
   1726             if (isVolatile) {
   1727                 dvmCompilerGenMemBarrier(cUnit, 0);
   1728             }
   1729             HEAP_ACCESS_SHADOW(true);
   1730             loadWordDisp(cUnit, tReg, 0, rlResult.lowReg);
   1731             HEAP_ACCESS_SHADOW(false);
   1732 
   1733             storeValue(cUnit, rlDest, rlResult);
   1734             break;
   1735         }
   1736         case OP_SGET_WIDE: {
   1737             int valOffset = OFFSETOF_MEMBER(StaticField, value);
   1738             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
   1739                 mir->meta.calleeMethod : cUnit->method;
   1740             void *fieldPtr = (void*)
   1741               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
   1742 
   1743             if (fieldPtr == NULL) {
   1744                 BAIL_LOOP_COMPILATION();
   1745                 ALOGE("Unexpected null static field");
   1746                 dvmAbort();
   1747             }
   1748 
   1749             int tReg = dvmCompilerAllocTemp(cUnit);
   1750             rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   1751             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
   1752             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
   1753 
   1754             HEAP_ACCESS_SHADOW(true);
   1755             loadPair(cUnit, tReg, rlResult.lowReg, rlResult.highReg);
   1756             HEAP_ACCESS_SHADOW(false);
   1757 
   1758             storeValueWide(cUnit, rlDest, rlResult);
   1759             break;
   1760         }
   1761         case OP_SPUT:
   1762         case OP_SPUT_VOLATILE:
   1763         case OP_SPUT_OBJECT:
   1764         case OP_SPUT_OBJECT_VOLATILE:
   1765         case OP_SPUT_BOOLEAN:
   1766         case OP_SPUT_CHAR:
   1767         case OP_SPUT_BYTE:
   1768         case OP_SPUT_SHORT: {
   1769             int valOffset = OFFSETOF_MEMBER(StaticField, value);
   1770             int tReg = dvmCompilerAllocTemp(cUnit);
   1771             int objHead = 0;
   1772             bool isVolatile;
   1773             bool isSputObject;
   1774             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
   1775                 mir->meta.calleeMethod : cUnit->method;
   1776             void *fieldPtr = (void*)
   1777               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
   1778             Opcode opcode = mir->dalvikInsn.opcode;
   1779 
   1780             if (fieldPtr == NULL) {
   1781                 BAIL_LOOP_COMPILATION();
   1782                 ALOGE("Unexpected null static field");
   1783                 dvmAbort();
   1784             }
   1785 
   1786 #if ANDROID_SMP != 0
   1787             isVolatile = (opcode == OP_SPUT_VOLATILE) ||
   1788                          (opcode == OP_SPUT_OBJECT_VOLATILE);
   1789             assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
   1790 #else
   1791             isVolatile = dvmIsVolatileField((Field *) fieldPtr);
   1792 #endif
   1793 
   1794             isSputObject = (opcode == OP_SPUT_OBJECT) ||
   1795                            (opcode == OP_SPUT_OBJECT_VOLATILE);
   1796 
   1797             rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   1798             rlSrc = loadValue(cUnit, rlSrc, kAnyReg);
   1799             loadConstant(cUnit, tReg,  (int) fieldPtr);
   1800             if (isSputObject) {
   1801                 objHead = dvmCompilerAllocTemp(cUnit);
   1802                 loadWordDisp(cUnit, tReg, OFFSETOF_MEMBER(Field, clazz), objHead);
   1803             }
   1804             if (isVolatile) {
   1805                 dvmCompilerGenMemBarrier(cUnit, 0);
   1806             }
   1807             HEAP_ACCESS_SHADOW(true);
   1808             storeWordDisp(cUnit, tReg, valOffset ,rlSrc.lowReg);
   1809             dvmCompilerFreeTemp(cUnit, tReg);
   1810             HEAP_ACCESS_SHADOW(false);
   1811             if (isVolatile) {
   1812                 dvmCompilerGenMemBarrier(cUnit, 0);
   1813             }
   1814             if (isSputObject) {
   1815                 /* NOTE: marking card based sfield->clazz */
   1816                 markCard(cUnit, rlSrc.lowReg, objHead);
   1817                 dvmCompilerFreeTemp(cUnit, objHead);
   1818             }
   1819 
   1820             break;
   1821         }
   1822         case OP_SPUT_WIDE: {
   1823             int tReg = dvmCompilerAllocTemp(cUnit);
   1824             int valOffset = OFFSETOF_MEMBER(StaticField, value);
   1825             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
   1826                 mir->meta.calleeMethod : cUnit->method;
   1827             void *fieldPtr = (void*)
   1828               (method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
   1829 
   1830             if (fieldPtr == NULL) {
   1831                 BAIL_LOOP_COMPILATION();
   1832                 ALOGE("Unexpected null static field");
   1833                 dvmAbort();
   1834             }
   1835 
   1836             rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
   1837             rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
   1838             loadConstant(cUnit, tReg,  (int) fieldPtr + valOffset);
   1839 
   1840             HEAP_ACCESS_SHADOW(true);
   1841             storePair(cUnit, tReg, rlSrc.lowReg, rlSrc.highReg);
   1842             HEAP_ACCESS_SHADOW(false);
   1843             break;
   1844         }
   1845         case OP_NEW_INSTANCE: {
   1846             /*
   1847              * Obey the calling convention and don't mess with the register
   1848              * usage.
   1849              */
   1850             ClassObject *classPtr = (ClassObject *)
   1851               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
   1852 
   1853             if (classPtr == NULL) {
   1854                 BAIL_LOOP_COMPILATION();
   1855                 ALOGE("Unexpected null class");
   1856                 dvmAbort();
   1857             }
   1858 
   1859             /*
   1860              * If it is going to throw, it should not make to the trace to begin
   1861              * with.  However, Alloc might throw, so we need to genExportPC()
   1862              */
   1863             assert((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) == 0);
   1864             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
   1865             genExportPC(cUnit, mir);
   1866             LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmAllocObject);
   1867             loadConstant(cUnit, r_A0, (int) classPtr);
   1868             loadConstant(cUnit, r_A1, ALLOC_DONT_TRACK);
   1869             opReg(cUnit, kOpBlx, r_T9);
   1870             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   1871             dvmCompilerClobberCallRegs(cUnit);
   1872             /* generate a branch over if allocation is successful */
   1873             MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
   1874 
   1875             /*
   1876              * OOM exception needs to be thrown here and cannot re-execute
   1877              */
   1878             loadConstant(cUnit, r_A0,
   1879                          (int) (cUnit->method->insns + mir->offset));
   1880             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
   1881             /* noreturn */
   1882 
   1883             MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   1884             target->defMask = ENCODE_ALL;
   1885             branchOver->generic.target = (LIR *) target;
   1886             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1887             rlResult = dvmCompilerGetReturn(cUnit);
   1888             storeValue(cUnit, rlDest, rlResult);
   1889             break;
   1890         }
   1891         case OP_CHECK_CAST: {
   1892             /*
   1893              * Obey the calling convention and don't mess with the register
   1894              * usage.
   1895              */
   1896             ClassObject *classPtr =
   1897               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
   1898             /*
   1899              * Note: It is possible that classPtr is NULL at this point,
   1900              * even though this instruction has been successfully interpreted.
   1901              * If the previous interpretation had a null source, the
   1902              * interpreter would not have bothered to resolve the clazz.
   1903              * Bail out to the interpreter in this case, and log it
   1904              * so that we can tell if it happens frequently.
   1905              */
   1906             if (classPtr == NULL) {
   1907                 BAIL_LOOP_COMPILATION();
   1908                 LOGVV("null clazz in OP_CHECK_CAST, single-stepping");
   1909                 genInterpSingleStep(cUnit, mir);
   1910                 return false;
   1911             }
   1912             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
   1913             loadConstant(cUnit, r_A1, (int) classPtr );
   1914             rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   1915             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   1916             MipsLIR *branch1 = opCompareBranch(cUnit, kMipsBeqz, rlSrc.lowReg, -1);
   1917             /*
   1918              *  rlSrc.lowReg now contains object->clazz.  Note that
   1919              *  it could have been allocated r_A0, but we're okay so long
   1920              *  as we don't do anything desctructive until r_A0 is loaded
   1921              *  with clazz.
   1922              */
   1923             /* r_A0 now contains object->clazz */
   1924             loadWordDisp(cUnit, rlSrc.lowReg, offsetof(Object, clazz), r_A0);
   1925             LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmInstanceofNonTrivial);
   1926             MipsLIR *branch2 = opCompareBranch(cUnit, kMipsBeq, r_A0, r_A1);
   1927             opReg(cUnit, kOpBlx, r_T9);
   1928             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   1929             dvmCompilerClobberCallRegs(cUnit);
   1930             /*
   1931              * If null, check cast failed - punt to the interpreter.  Because
   1932              * interpreter will be the one throwing, we don't need to
   1933              * genExportPC() here.
   1934              */
   1935             genRegCopy(cUnit, r_A0, r_V0);
   1936             genZeroCheck(cUnit, r_V0, mir->offset, NULL);
   1937             /* check cast passed - branch target here */
   1938             MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   1939             target->defMask = ENCODE_ALL;
   1940             branch1->generic.target = (LIR *)target;
   1941             branch2->generic.target = (LIR *)target;
   1942             break;
   1943         }
   1944         case OP_SGET_WIDE_VOLATILE:
   1945         case OP_SPUT_WIDE_VOLATILE:
   1946             genInterpSingleStep(cUnit, mir);
   1947             break;
   1948         default:
   1949             return true;
   1950     }
   1951     return false;
   1952 }
   1953 
   1954 static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
   1955 {
   1956     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   1957     RegLocation rlResult;
   1958     switch (dalvikOpcode) {
   1959         case OP_MOVE_EXCEPTION: {
   1960             int exOffset = offsetof(Thread, exception);
   1961             int resetReg = dvmCompilerAllocTemp(cUnit);
   1962             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1963             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   1964             loadWordDisp(cUnit, rSELF, exOffset, rlResult.lowReg);
   1965             loadConstant(cUnit, resetReg, 0);
   1966             storeWordDisp(cUnit, rSELF, exOffset, resetReg);
   1967             storeValue(cUnit, rlDest, rlResult);
   1968            break;
   1969         }
   1970         case OP_MOVE_RESULT:
   1971         case OP_MOVE_RESULT_OBJECT: {
   1972             /* An inlined move result is effectively no-op */
   1973             if (mir->OptimizationFlags & MIR_INLINED)
   1974                 break;
   1975             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   1976             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL;
   1977             rlSrc.fp = rlDest.fp;
   1978             storeValue(cUnit, rlDest, rlSrc);
   1979             break;
   1980         }
   1981         case OP_MOVE_RESULT_WIDE: {
   1982             /* An inlined move result is effectively no-op */
   1983             if (mir->OptimizationFlags & MIR_INLINED)
   1984                 break;
   1985             RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   1986             RegLocation rlSrc = LOC_DALVIK_RETURN_VAL_WIDE;
   1987             rlSrc.fp = rlDest.fp;
   1988             storeValueWide(cUnit, rlDest, rlSrc);
   1989             break;
   1990         }
   1991         case OP_RETURN_WIDE: {
   1992             RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
   1993             RegLocation rlDest = LOC_DALVIK_RETURN_VAL_WIDE;
   1994             rlDest.fp = rlSrc.fp;
   1995             storeValueWide(cUnit, rlDest, rlSrc);
   1996             genReturnCommon(cUnit,mir);
   1997             break;
   1998         }
   1999         case OP_RETURN:
   2000         case OP_RETURN_OBJECT: {
   2001             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   2002             RegLocation rlDest = LOC_DALVIK_RETURN_VAL;
   2003             rlDest.fp = rlSrc.fp;
   2004             storeValue(cUnit, rlDest, rlSrc);
   2005             genReturnCommon(cUnit, mir);
   2006             break;
   2007         }
   2008         case OP_MONITOR_EXIT:
   2009         case OP_MONITOR_ENTER:
   2010             genMonitor(cUnit, mir);
   2011             break;
   2012         case OP_THROW:
   2013             genInterpSingleStep(cUnit, mir);
   2014             break;
   2015         default:
   2016             return true;
   2017     }
   2018     return false;
   2019 }
   2020 
   2021 static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
   2022 {
   2023     Opcode opcode = mir->dalvikInsn.opcode;
   2024     RegLocation rlDest;
   2025     RegLocation rlSrc;
   2026     RegLocation rlResult;
   2027 
   2028     if ( (opcode >= OP_ADD_INT_2ADDR) && (opcode <= OP_REM_DOUBLE_2ADDR)) {
   2029         return genArithOp( cUnit, mir );
   2030     }
   2031 
   2032     if (mir->ssaRep->numUses == 2)
   2033         rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
   2034     else
   2035         rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   2036     if (mir->ssaRep->numDefs == 2)
   2037         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   2038     else
   2039         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   2040 
   2041     switch (opcode) {
   2042         case OP_DOUBLE_TO_INT:
   2043         case OP_INT_TO_FLOAT:
   2044         case OP_FLOAT_TO_INT:
   2045         case OP_DOUBLE_TO_FLOAT:
   2046         case OP_FLOAT_TO_DOUBLE:
   2047         case OP_INT_TO_DOUBLE:
   2048         case OP_FLOAT_TO_LONG:
   2049         case OP_LONG_TO_FLOAT:
   2050         case OP_DOUBLE_TO_LONG:
   2051         case OP_LONG_TO_DOUBLE:
   2052             return genConversion(cUnit, mir);
   2053         case OP_NEG_INT:
   2054         case OP_NOT_INT:
   2055             return genArithOpInt(cUnit, mir, rlDest, rlSrc, rlSrc);
   2056         case OP_NEG_LONG:
   2057         case OP_NOT_LONG:
   2058             return genArithOpLong(cUnit, mir, rlDest, rlSrc, rlSrc);
   2059         case OP_NEG_FLOAT:
   2060             return genArithOpFloat(cUnit, mir, rlDest, rlSrc, rlSrc);
   2061         case OP_NEG_DOUBLE:
   2062             return genArithOpDouble(cUnit, mir, rlDest, rlSrc, rlSrc);
   2063         case OP_MOVE_WIDE:
   2064             storeValueWide(cUnit, rlDest, rlSrc);
   2065             break;
   2066         case OP_INT_TO_LONG:
   2067             rlSrc = dvmCompilerUpdateLoc(cUnit, rlSrc);
   2068             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2069             //TUNING: shouldn't loadValueDirect already check for phys reg?
   2070             if (rlSrc.location == kLocPhysReg) {
   2071                 genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
   2072             } else {
   2073                 loadValueDirect(cUnit, rlSrc, rlResult.lowReg);
   2074             }
   2075             opRegRegImm(cUnit, kOpAsr, rlResult.highReg,
   2076                         rlResult.lowReg, 31);
   2077             storeValueWide(cUnit, rlDest, rlResult);
   2078             break;
   2079         case OP_LONG_TO_INT:
   2080             rlSrc = dvmCompilerUpdateLocWide(cUnit, rlSrc);
   2081             rlSrc = dvmCompilerWideToNarrow(cUnit, rlSrc);
   2082             // Intentional fallthrough
   2083         case OP_MOVE:
   2084         case OP_MOVE_OBJECT:
   2085             storeValue(cUnit, rlDest, rlSrc);
   2086             break;
   2087         case OP_INT_TO_BYTE:
   2088             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2089             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2090             opRegReg(cUnit, kOp2Byte, rlResult.lowReg, rlSrc.lowReg);
   2091             storeValue(cUnit, rlDest, rlResult);
   2092             break;
   2093         case OP_INT_TO_SHORT:
   2094             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2095             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2096             opRegReg(cUnit, kOp2Short, rlResult.lowReg, rlSrc.lowReg);
   2097             storeValue(cUnit, rlDest, rlResult);
   2098             break;
   2099         case OP_INT_TO_CHAR:
   2100             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2101             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2102             opRegReg(cUnit, kOp2Char, rlResult.lowReg, rlSrc.lowReg);
   2103             storeValue(cUnit, rlDest, rlResult);
   2104             break;
   2105         case OP_ARRAY_LENGTH: {
   2106             int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
   2107             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2108             genNullCheck(cUnit, rlSrc.sRegLow, rlSrc.lowReg,
   2109                          mir->offset, NULL);
   2110             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2111             loadWordDisp(cUnit, rlSrc.lowReg, lenOffset,
   2112                          rlResult.lowReg);
   2113             storeValue(cUnit, rlDest, rlResult);
   2114             break;
   2115         }
   2116         default:
   2117             return true;
   2118     }
   2119     return false;
   2120 }
   2121 
   2122 static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
   2123 {
   2124     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   2125     RegLocation rlDest;
   2126     RegLocation rlResult;
   2127     int BBBB = mir->dalvikInsn.vB;
   2128     if (dalvikOpcode == OP_CONST_WIDE_16) {
   2129         rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   2130         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2131         loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
   2132         //TUNING: do high separately to avoid load dependency
   2133         opRegRegImm(cUnit, kOpAsr, rlResult.highReg, rlResult.lowReg, 31);
   2134         storeValueWide(cUnit, rlDest, rlResult);
   2135     } else if (dalvikOpcode == OP_CONST_16) {
   2136         rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   2137         rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kAnyReg, true);
   2138         loadConstantNoClobber(cUnit, rlResult.lowReg, BBBB);
   2139         storeValue(cUnit, rlDest, rlResult);
   2140     } else
   2141         return true;
   2142     return false;
   2143 }
   2144 
   2145 /* Compare agaist zero */
   2146 static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
   2147                          MipsLIR *labelList)
   2148 {
   2149     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   2150     MipsOpCode opc = kMipsNop;
   2151     int rt = -1;
   2152     /* backward branch? */
   2153     bool backwardBranch = (bb->taken->startOffset <= mir->offset);
   2154 
   2155     if (backwardBranch &&
   2156         (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
   2157         genSuspendPoll(cUnit, mir);
   2158     }
   2159 
   2160     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   2161     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2162 
   2163     switch (dalvikOpcode) {
   2164         case OP_IF_EQZ:
   2165             opc = kMipsBeqz;
   2166             break;
   2167         case OP_IF_NEZ:
   2168             opc = kMipsBne;
   2169             rt = r_ZERO;
   2170             break;
   2171         case OP_IF_LTZ:
   2172             opc = kMipsBltz;
   2173             break;
   2174         case OP_IF_GEZ:
   2175             opc = kMipsBgez;
   2176             break;
   2177         case OP_IF_GTZ:
   2178             opc = kMipsBgtz;
   2179             break;
   2180         case OP_IF_LEZ:
   2181             opc = kMipsBlez;
   2182             break;
   2183         default:
   2184             ALOGE("Unexpected opcode (%d) for Fmt21t", dalvikOpcode);
   2185             dvmCompilerAbort(cUnit);
   2186     }
   2187     genConditionalBranchMips(cUnit, opc, rlSrc.lowReg, rt, &labelList[bb->taken->id]);
   2188     /* This mostly likely will be optimized away in a later phase */
   2189     genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
   2190     return false;
   2191 }
   2192 
   2193 static bool isPowerOfTwo(int x)
   2194 {
   2195     return (x & (x - 1)) == 0;
   2196 }
   2197 
   2198 // Returns true if no more than two bits are set in 'x'.
   2199 static bool isPopCountLE2(unsigned int x)
   2200 {
   2201     x &= x - 1;
   2202     return (x & (x - 1)) == 0;
   2203 }
   2204 
   2205 // Returns the index of the lowest set bit in 'x'.
   2206 static int lowestSetBit(unsigned int x) {
   2207     int bit_posn = 0;
   2208     while ((x & 0xf) == 0) {
   2209         bit_posn += 4;
   2210         x >>= 4;
   2211     }
   2212     while ((x & 1) == 0) {
   2213         bit_posn++;
   2214         x >>= 1;
   2215     }
   2216     return bit_posn;
   2217 }
   2218 
   2219 // Returns true if it added instructions to 'cUnit' to divide 'rlSrc' by 'lit'
   2220 // and store the result in 'rlDest'.
   2221 static bool handleEasyDivide(CompilationUnit *cUnit, Opcode dalvikOpcode,
   2222                              RegLocation rlSrc, RegLocation rlDest, int lit)
   2223 {
   2224     if (lit < 2 || !isPowerOfTwo(lit)) {
   2225         return false;
   2226     }
   2227     int k = lowestSetBit(lit);
   2228     if (k >= 30) {
   2229         // Avoid special cases.
   2230         return false;
   2231     }
   2232     bool div = (dalvikOpcode == OP_DIV_INT_LIT8 || dalvikOpcode == OP_DIV_INT_LIT16);
   2233     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2234     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2235     if (div) {
   2236         int tReg = dvmCompilerAllocTemp(cUnit);
   2237         if (lit == 2) {
   2238             // Division by 2 is by far the most common division by constant.
   2239             opRegRegImm(cUnit, kOpLsr, tReg, rlSrc.lowReg, 32 - k);
   2240             opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
   2241             opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
   2242         } else {
   2243             opRegRegImm(cUnit, kOpAsr, tReg, rlSrc.lowReg, 31);
   2244             opRegRegImm(cUnit, kOpLsr, tReg, tReg, 32 - k);
   2245             opRegRegReg(cUnit, kOpAdd, tReg, tReg, rlSrc.lowReg);
   2246             opRegRegImm(cUnit, kOpAsr, rlResult.lowReg, tReg, k);
   2247         }
   2248     } else {
   2249         int cReg = dvmCompilerAllocTemp(cUnit);
   2250         loadConstant(cUnit, cReg, lit - 1);
   2251         int tReg1 = dvmCompilerAllocTemp(cUnit);
   2252         int tReg2 = dvmCompilerAllocTemp(cUnit);
   2253         if (lit == 2) {
   2254             opRegRegImm(cUnit, kOpLsr, tReg1, rlSrc.lowReg, 32 - k);
   2255             opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
   2256             opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
   2257             opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
   2258         } else {
   2259             opRegRegImm(cUnit, kOpAsr, tReg1, rlSrc.lowReg, 31);
   2260             opRegRegImm(cUnit, kOpLsr, tReg1, tReg1, 32 - k);
   2261             opRegRegReg(cUnit, kOpAdd, tReg2, tReg1, rlSrc.lowReg);
   2262             opRegRegReg(cUnit, kOpAnd, tReg2, tReg2, cReg);
   2263             opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg2, tReg1);
   2264         }
   2265     }
   2266     storeValue(cUnit, rlDest, rlResult);
   2267     return true;
   2268 }
   2269 
   2270 // Returns true if it added instructions to 'cUnit' to multiply 'rlSrc' by 'lit'
   2271 // and store the result in 'rlDest'.
   2272 static bool handleEasyMultiply(CompilationUnit *cUnit,
   2273                                RegLocation rlSrc, RegLocation rlDest, int lit)
   2274 {
   2275     // Can we simplify this multiplication?
   2276     bool powerOfTwo = false;
   2277     bool popCountLE2 = false;
   2278     bool powerOfTwoMinusOne = false;
   2279     if (lit < 2) {
   2280         // Avoid special cases.
   2281         return false;
   2282     } else if (isPowerOfTwo(lit)) {
   2283         powerOfTwo = true;
   2284     } else if (isPopCountLE2(lit)) {
   2285         popCountLE2 = true;
   2286     } else if (isPowerOfTwo(lit + 1)) {
   2287         powerOfTwoMinusOne = true;
   2288     } else {
   2289         return false;
   2290     }
   2291     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2292     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2293     if (powerOfTwo) {
   2294         // Shift.
   2295         opRegRegImm(cUnit, kOpLsl, rlResult.lowReg, rlSrc.lowReg,
   2296                     lowestSetBit(lit));
   2297     } else if (popCountLE2) {
   2298         // Shift and add and shift.
   2299         int firstBit = lowestSetBit(lit);
   2300         int secondBit = lowestSetBit(lit ^ (1 << firstBit));
   2301         genMultiplyByTwoBitMultiplier(cUnit, rlSrc, rlResult, lit,
   2302                                       firstBit, secondBit);
   2303     } else {
   2304         // Reverse subtract: (src << (shift + 1)) - src.
   2305         assert(powerOfTwoMinusOne);
   2306         // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
   2307         int tReg = dvmCompilerAllocTemp(cUnit);
   2308         opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
   2309         opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
   2310     }
   2311     storeValue(cUnit, rlDest, rlResult);
   2312     return true;
   2313 }
   2314 
   2315 static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
   2316 {
   2317     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   2318     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   2319     RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   2320     RegLocation rlResult;
   2321     int lit = mir->dalvikInsn.vC;
   2322     OpKind op = (OpKind)0;      /* Make gcc happy */
   2323     int shiftOp = false;
   2324 
   2325     switch (dalvikOpcode) {
   2326         case OP_RSUB_INT_LIT8:
   2327         case OP_RSUB_INT: {
   2328             int tReg;
   2329             //TUNING: add support for use of Arm rsub op
   2330             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2331             tReg = dvmCompilerAllocTemp(cUnit);
   2332             loadConstant(cUnit, tReg, lit);
   2333             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2334             opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
   2335                         tReg, rlSrc.lowReg);
   2336             storeValue(cUnit, rlDest, rlResult);
   2337             return false;
   2338             break;
   2339         }
   2340 
   2341         case OP_ADD_INT_LIT8:
   2342         case OP_ADD_INT_LIT16:
   2343             op = kOpAdd;
   2344             break;
   2345         case OP_MUL_INT_LIT8:
   2346         case OP_MUL_INT_LIT16: {
   2347             if (handleEasyMultiply(cUnit, rlSrc, rlDest, lit)) {
   2348                 return false;
   2349             }
   2350             op = kOpMul;
   2351             break;
   2352         }
   2353         case OP_AND_INT_LIT8:
   2354         case OP_AND_INT_LIT16:
   2355             op = kOpAnd;
   2356             break;
   2357         case OP_OR_INT_LIT8:
   2358         case OP_OR_INT_LIT16:
   2359             op = kOpOr;
   2360             break;
   2361         case OP_XOR_INT_LIT8:
   2362         case OP_XOR_INT_LIT16:
   2363             op = kOpXor;
   2364             break;
   2365         case OP_SHL_INT_LIT8:
   2366             lit &= 31;
   2367             shiftOp = true;
   2368             op = kOpLsl;
   2369             break;
   2370         case OP_SHR_INT_LIT8:
   2371             lit &= 31;
   2372             shiftOp = true;
   2373             op = kOpAsr;
   2374             break;
   2375         case OP_USHR_INT_LIT8:
   2376             lit &= 31;
   2377             shiftOp = true;
   2378             op = kOpLsr;
   2379             break;
   2380 
   2381         case OP_DIV_INT_LIT8:
   2382         case OP_DIV_INT_LIT16:
   2383         case OP_REM_INT_LIT8:
   2384         case OP_REM_INT_LIT16: {
   2385             if (lit == 0) {
   2386                 /* Let the interpreter deal with div by 0 */
   2387                 genInterpSingleStep(cUnit, mir);
   2388                 return false;
   2389             }
   2390             if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
   2391                 return false;
   2392             }
   2393 
   2394             MipsOpCode opc;
   2395             int divReg;
   2396 
   2397             if ((dalvikOpcode == OP_DIV_INT_LIT8) ||
   2398                 (dalvikOpcode == OP_DIV_INT_LIT16)) {
   2399                 opc = kMipsMflo;
   2400                 divReg = r_LO;
   2401             } else {
   2402                 opc = kMipsMfhi;
   2403                 divReg = r_HI;
   2404             }
   2405 
   2406             rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2407             int tReg = dvmCompilerAllocTemp(cUnit);
   2408             newLIR3(cUnit, kMipsAddiu, tReg, r_ZERO, lit);
   2409             newLIR4(cUnit, kMipsDiv, r_HI, r_LO, rlSrc.lowReg, tReg);
   2410             rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2411             newLIR2(cUnit, opc, rlResult.lowReg, divReg);
   2412             dvmCompilerFreeTemp(cUnit, tReg);
   2413             storeValue(cUnit, rlDest, rlResult);
   2414             return false;
   2415             break;
   2416         }
   2417         default:
   2418             return true;
   2419     }
   2420     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   2421     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   2422     // Avoid shifts by literal 0 - no support in Thumb.  Change to copy
   2423     if (shiftOp && (lit == 0)) {
   2424         genRegCopy(cUnit, rlResult.lowReg, rlSrc.lowReg);
   2425     } else {
   2426         opRegRegImm(cUnit, op, rlResult.lowReg, rlSrc.lowReg, lit);
   2427     }
   2428     storeValue(cUnit, rlDest, rlResult);
   2429     return false;
   2430 }
   2431 
   2432 static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
   2433 {
   2434     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   2435     int fieldOffset = -1;
   2436     bool isVolatile = false;
   2437     switch (dalvikOpcode) {
   2438         /*
   2439          * Wide volatiles currently handled via single step.
   2440          * Add them here if generating in-line code.
   2441          *     case OP_IGET_WIDE_VOLATILE:
   2442          *     case OP_IPUT_WIDE_VOLATILE:
   2443          */
   2444         case OP_IGET_VOLATILE:
   2445         case OP_IGET_OBJECT_VOLATILE:
   2446         case OP_IPUT_VOLATILE:
   2447         case OP_IPUT_OBJECT_VOLATILE:
   2448 #if ANDROID_SMP != 0
   2449             isVolatile = true;
   2450         // NOTE: intentional fallthrough
   2451 #endif
   2452         case OP_IGET:
   2453         case OP_IGET_WIDE:
   2454         case OP_IGET_OBJECT:
   2455         case OP_IGET_BOOLEAN:
   2456         case OP_IGET_BYTE:
   2457         case OP_IGET_CHAR:
   2458         case OP_IGET_SHORT:
   2459         case OP_IPUT:
   2460         case OP_IPUT_WIDE:
   2461         case OP_IPUT_OBJECT:
   2462         case OP_IPUT_BOOLEAN:
   2463         case OP_IPUT_BYTE:
   2464         case OP_IPUT_CHAR:
   2465         case OP_IPUT_SHORT: {
   2466             const Method *method = (mir->OptimizationFlags & MIR_CALLEE) ?
   2467                 mir->meta.calleeMethod : cUnit->method;
   2468             Field *fieldPtr =
   2469                 method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
   2470 
   2471             if (fieldPtr == NULL) {
   2472                 BAIL_LOOP_COMPILATION();
   2473                 ALOGE("Unexpected null instance field");
   2474                 dvmAbort();
   2475             }
   2476 #if ANDROID_SMP != 0
   2477             assert(isVolatile == dvmIsVolatileField((Field *) fieldPtr));
   2478 #else
   2479             isVolatile = dvmIsVolatileField((Field *) fieldPtr);
   2480 #endif
   2481             fieldOffset = ((InstField *)fieldPtr)->byteOffset;
   2482             break;
   2483         }
   2484         default:
   2485             break;
   2486     }
   2487 
   2488     switch (dalvikOpcode) {
   2489         case OP_NEW_ARRAY: {
   2490 #if 0 /* 080 triggers assert in Interp.c:1290 for out of memory exception.
   2491              i think the assert is in error and should be disabled. With
   2492              asserts disabled, 080 passes. */
   2493 genInterpSingleStep(cUnit, mir);
   2494 return false;
   2495 #endif
   2496             // Generates a call - use explicit registers
   2497             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   2498             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   2499             RegLocation rlResult;
   2500             void *classPtr = (void*)
   2501               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
   2502 
   2503             if (classPtr == NULL) {
   2504                 BAIL_LOOP_COMPILATION();
   2505                 ALOGE("Unexpected null class");
   2506                 dvmAbort();
   2507             }
   2508 
   2509             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
   2510             genExportPC(cUnit, mir);
   2511             loadValueDirectFixed(cUnit, rlSrc, r_A1);   /* Len */
   2512             loadConstant(cUnit, r_A0, (int) classPtr );
   2513             LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmAllocArrayByClass);
   2514             /*
   2515              * "len < 0": bail to the interpreter to re-execute the
   2516              * instruction
   2517              */
   2518             genRegImmCheck(cUnit, kMipsCondMi, r_A1, 0, mir->offset, NULL);
   2519             loadConstant(cUnit, r_A2, ALLOC_DONT_TRACK);
   2520             opReg(cUnit, kOpBlx, r_T9);
   2521             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   2522             dvmCompilerClobberCallRegs(cUnit);
   2523             /* generate a branch over if allocation is successful */
   2524             MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
   2525             /*
   2526              * OOM exception needs to be thrown here and cannot re-execute
   2527              */
   2528             loadConstant(cUnit, r_A0,
   2529                          (int) (cUnit->method->insns + mir->offset));
   2530             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
   2531             /* noreturn */
   2532 
   2533             MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   2534             target->defMask = ENCODE_ALL;
   2535             branchOver->generic.target = (LIR *) target;
   2536             rlResult = dvmCompilerGetReturn(cUnit);
   2537             storeValue(cUnit, rlDest, rlResult);
   2538             break;
   2539         }
   2540         case OP_INSTANCE_OF: {
   2541             // May generate a call - use explicit registers
   2542             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   2543             RegLocation rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   2544             RegLocation rlResult;
   2545             ClassObject *classPtr =
   2546               (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
   2547             /*
   2548              * Note: It is possible that classPtr is NULL at this point,
   2549              * even though this instruction has been successfully interpreted.
   2550              * If the previous interpretation had a null source, the
   2551              * interpreter would not have bothered to resolve the clazz.
   2552              * Bail out to the interpreter in this case, and log it
   2553              * so that we can tell if it happens frequently.
   2554              */
   2555             if (classPtr == NULL) {
   2556                 BAIL_LOOP_COMPILATION();
   2557                 ALOGD("null clazz in OP_INSTANCE_OF, single-stepping");
   2558                 genInterpSingleStep(cUnit, mir);
   2559                 break;
   2560             }
   2561             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
   2562             loadValueDirectFixed(cUnit, rlSrc, r_V0);  /* Ref */
   2563             loadConstant(cUnit, r_A2, (int) classPtr );
   2564             /* When taken r_V0 has NULL which can be used for store directly */
   2565             MipsLIR *branch1 = opCompareBranch(cUnit, kMipsBeqz, r_V0, -1);
   2566             /* r_A1 now contains object->clazz */
   2567             loadWordDisp(cUnit, r_V0, offsetof(Object, clazz), r_A1);
   2568             /* r_A1 now contains object->clazz */
   2569             LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmInstanceofNonTrivial);
   2570             loadConstant(cUnit, r_V0, 1);                /* Assume true */
   2571             MipsLIR *branch2 = opCompareBranch(cUnit, kMipsBeq, r_A1, r_A2);
   2572             genRegCopy(cUnit, r_A0, r_A1);
   2573             genRegCopy(cUnit, r_A1, r_A2);
   2574             opReg(cUnit, kOpBlx, r_T9);
   2575             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   2576             dvmCompilerClobberCallRegs(cUnit);
   2577             /* branch target here */
   2578             MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   2579             target->defMask = ENCODE_ALL;
   2580             rlResult = dvmCompilerGetReturn(cUnit);
   2581             storeValue(cUnit, rlDest, rlResult);
   2582             branch1->generic.target = (LIR *)target;
   2583             branch2->generic.target = (LIR *)target;
   2584             break;
   2585         }
   2586         case OP_IGET_WIDE:
   2587             genIGetWide(cUnit, mir, fieldOffset);
   2588             break;
   2589         case OP_IGET_VOLATILE:
   2590         case OP_IGET_OBJECT_VOLATILE:
   2591         case OP_IGET:
   2592         case OP_IGET_OBJECT:
   2593         case OP_IGET_BOOLEAN:
   2594         case OP_IGET_BYTE:
   2595         case OP_IGET_CHAR:
   2596         case OP_IGET_SHORT:
   2597             genIGet(cUnit, mir, kWord, fieldOffset, isVolatile);
   2598             break;
   2599         case OP_IPUT_WIDE:
   2600             genIPutWide(cUnit, mir, fieldOffset);
   2601             break;
   2602         case OP_IPUT_VOLATILE:
   2603         case OP_IPUT:
   2604         case OP_IPUT_BOOLEAN:
   2605         case OP_IPUT_BYTE:
   2606         case OP_IPUT_CHAR:
   2607         case OP_IPUT_SHORT:
   2608             genIPut(cUnit, mir, kWord, fieldOffset, false, isVolatile);
   2609             break;
   2610         case OP_IPUT_OBJECT_VOLATILE:
   2611         case OP_IPUT_OBJECT:
   2612             genIPut(cUnit, mir, kWord, fieldOffset, true, isVolatile);
   2613             break;
   2614         case OP_IGET_WIDE_VOLATILE:
   2615         case OP_IPUT_WIDE_VOLATILE:
   2616             genInterpSingleStep(cUnit, mir);
   2617             break;
   2618         default:
   2619             return true;
   2620     }
   2621     return false;
   2622 }
   2623 
   2624 static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
   2625 {
   2626     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   2627     int fieldOffset =  mir->dalvikInsn.vC;
   2628     switch (dalvikOpcode) {
   2629         case OP_IGET_QUICK:
   2630         case OP_IGET_OBJECT_QUICK:
   2631             genIGet(cUnit, mir, kWord, fieldOffset, false);
   2632             break;
   2633         case OP_IPUT_QUICK:
   2634             genIPut(cUnit, mir, kWord, fieldOffset, false, false);
   2635             break;
   2636         case OP_IPUT_OBJECT_QUICK:
   2637             genIPut(cUnit, mir, kWord, fieldOffset, true, false);
   2638             break;
   2639         case OP_IGET_WIDE_QUICK:
   2640             genIGetWide(cUnit, mir, fieldOffset);
   2641             break;
   2642         case OP_IPUT_WIDE_QUICK:
   2643             genIPutWide(cUnit, mir, fieldOffset);
   2644             break;
   2645         default:
   2646             return true;
   2647     }
   2648     return false;
   2649 
   2650 }
   2651 
   2652 /* Compare against zero */
   2653 static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
   2654                          MipsLIR *labelList)
   2655 {
   2656     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   2657     MipsConditionCode cond;
   2658     MipsOpCode opc = kMipsNop;
   2659     MipsLIR * test = NULL;
   2660     /* backward branch? */
   2661     bool backwardBranch = (bb->taken->startOffset <= mir->offset);
   2662 
   2663     if (backwardBranch &&
   2664         (gDvmJit.genSuspendPoll || cUnit->jitMode == kJitLoop)) {
   2665         genSuspendPoll(cUnit, mir);
   2666     }
   2667 
   2668     RegLocation rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
   2669     RegLocation rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
   2670     rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
   2671     rlSrc2 = loadValue(cUnit, rlSrc2, kCoreReg);
   2672     int reg1 = rlSrc1.lowReg;
   2673     int reg2 = rlSrc2.lowReg;
   2674     int tReg;
   2675 
   2676     switch (dalvikOpcode) {
   2677         case OP_IF_EQ:
   2678             opc = kMipsBeq;
   2679             break;
   2680         case OP_IF_NE:
   2681             opc = kMipsBne;
   2682             break;
   2683         case OP_IF_LT:
   2684             opc = kMipsBne;
   2685             tReg = dvmCompilerAllocTemp(cUnit);
   2686             test = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
   2687             reg1 = tReg;
   2688             reg2 = r_ZERO;
   2689             break;
   2690         case OP_IF_LE:
   2691             opc = kMipsBeqz;
   2692             tReg = dvmCompilerAllocTemp(cUnit);
   2693             test = newLIR3(cUnit, kMipsSlt, tReg, reg2, reg1);
   2694             reg1 = tReg;
   2695             reg2 = -1;
   2696             break;
   2697         case OP_IF_GT:
   2698             opc = kMipsBne;
   2699             tReg = dvmCompilerAllocTemp(cUnit);
   2700             test = newLIR3(cUnit, kMipsSlt, tReg, reg2, reg1);
   2701             reg1 = tReg;
   2702             reg2 = r_ZERO;
   2703             break;
   2704         case OP_IF_GE:
   2705             opc = kMipsBeqz;
   2706             tReg = dvmCompilerAllocTemp(cUnit);
   2707             test = newLIR3(cUnit, kMipsSlt, tReg, reg1, reg2);
   2708             reg1 = tReg;
   2709             reg2 = -1;
   2710             break;
   2711         default:
   2712             cond = (MipsConditionCode)0;
   2713             ALOGE("Unexpected opcode (%d) for Fmt22t", dalvikOpcode);
   2714             dvmCompilerAbort(cUnit);
   2715     }
   2716 
   2717     genConditionalBranchMips(cUnit, opc, reg1, reg2, &labelList[bb->taken->id]);
   2718     /* This mostly likely will be optimized away in a later phase */
   2719     genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
   2720     return false;
   2721 }
   2722 
   2723 static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
   2724 {
   2725     Opcode opcode = mir->dalvikInsn.opcode;
   2726 
   2727     switch (opcode) {
   2728         case OP_MOVE_16:
   2729         case OP_MOVE_OBJECT_16:
   2730         case OP_MOVE_FROM16:
   2731         case OP_MOVE_OBJECT_FROM16: {
   2732             storeValue(cUnit, dvmCompilerGetDest(cUnit, mir, 0),
   2733                        dvmCompilerGetSrc(cUnit, mir, 0));
   2734             break;
   2735         }
   2736         case OP_MOVE_WIDE_16:
   2737         case OP_MOVE_WIDE_FROM16: {
   2738             storeValueWide(cUnit, dvmCompilerGetDestWide(cUnit, mir, 0, 1),
   2739                            dvmCompilerGetSrcWide(cUnit, mir, 0, 1));
   2740             break;
   2741         }
   2742         default:
   2743             return true;
   2744     }
   2745     return false;
   2746 }
   2747 
   2748 static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
   2749 {
   2750     Opcode opcode = mir->dalvikInsn.opcode;
   2751     RegLocation rlSrc1;
   2752     RegLocation rlSrc2;
   2753     RegLocation rlDest;
   2754 
   2755     if ((opcode >= OP_ADD_INT) && (opcode <= OP_REM_DOUBLE)) {
   2756         return genArithOp( cUnit, mir );
   2757     }
   2758 
   2759     /* APUTs have 3 sources and no targets */
   2760     if (mir->ssaRep->numDefs == 0) {
   2761         if (mir->ssaRep->numUses == 3) {
   2762             rlDest = dvmCompilerGetSrc(cUnit, mir, 0);
   2763             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 1);
   2764             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 2);
   2765         } else {
   2766             assert(mir->ssaRep->numUses == 4);
   2767             rlDest = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
   2768             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 2);
   2769             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 3);
   2770         }
   2771     } else {
   2772         /* Two sources and 1 dest.  Deduce the operand sizes */
   2773         if (mir->ssaRep->numUses == 4) {
   2774             rlSrc1 = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
   2775             rlSrc2 = dvmCompilerGetSrcWide(cUnit, mir, 2, 3);
   2776         } else {
   2777             assert(mir->ssaRep->numUses == 2);
   2778             rlSrc1 = dvmCompilerGetSrc(cUnit, mir, 0);
   2779             rlSrc2 = dvmCompilerGetSrc(cUnit, mir, 1);
   2780         }
   2781         if (mir->ssaRep->numDefs == 2) {
   2782             rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   2783         } else {
   2784             assert(mir->ssaRep->numDefs == 1);
   2785             rlDest = dvmCompilerGetDest(cUnit, mir, 0);
   2786         }
   2787     }
   2788 
   2789     switch (opcode) {
   2790         case OP_CMPL_FLOAT:
   2791         case OP_CMPG_FLOAT:
   2792         case OP_CMPL_DOUBLE:
   2793         case OP_CMPG_DOUBLE:
   2794             return genCmpFP(cUnit, mir, rlDest, rlSrc1, rlSrc2);
   2795         case OP_CMP_LONG:
   2796             genCmpLong(cUnit, mir, rlDest, rlSrc1, rlSrc2);
   2797             break;
   2798         case OP_AGET_WIDE:
   2799             genArrayGet(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
   2800             break;
   2801         case OP_AGET:
   2802         case OP_AGET_OBJECT:
   2803             genArrayGet(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
   2804             break;
   2805         case OP_AGET_BOOLEAN:
   2806             genArrayGet(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
   2807             break;
   2808         case OP_AGET_BYTE:
   2809             genArrayGet(cUnit, mir, kSignedByte, rlSrc1, rlSrc2, rlDest, 0);
   2810             break;
   2811         case OP_AGET_CHAR:
   2812             genArrayGet(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
   2813             break;
   2814         case OP_AGET_SHORT:
   2815             genArrayGet(cUnit, mir, kSignedHalf, rlSrc1, rlSrc2, rlDest, 1);
   2816             break;
   2817         case OP_APUT_WIDE:
   2818             genArrayPut(cUnit, mir, kLong, rlSrc1, rlSrc2, rlDest, 3);
   2819             break;
   2820         case OP_APUT:
   2821             genArrayPut(cUnit, mir, kWord, rlSrc1, rlSrc2, rlDest, 2);
   2822             break;
   2823         case OP_APUT_OBJECT:
   2824             genArrayObjectPut(cUnit, mir, rlSrc1, rlSrc2, rlDest, 2);
   2825             break;
   2826         case OP_APUT_SHORT:
   2827         case OP_APUT_CHAR:
   2828             genArrayPut(cUnit, mir, kUnsignedHalf, rlSrc1, rlSrc2, rlDest, 1);
   2829             break;
   2830         case OP_APUT_BYTE:
   2831         case OP_APUT_BOOLEAN:
   2832             genArrayPut(cUnit, mir, kUnsignedByte, rlSrc1, rlSrc2, rlDest, 0);
   2833             break;
   2834         default:
   2835             return true;
   2836     }
   2837     return false;
   2838 }
   2839 
   2840 /*
   2841  * Find the matching case.
   2842  *
   2843  * return values:
   2844  * r_RESULT0 (low 32-bit): pc of the chaining cell corresponding to the resolved case,
   2845  *    including default which is placed at MIN(size, MAX_CHAINED_SWITCH_CASES).
   2846  * r_RESULT1 (high 32-bit): the branch offset of the matching case (only for indexes
   2847  *    above MAX_CHAINED_SWITCH_CASES).
   2848  *
   2849  * Instructions around the call are:
   2850  *
   2851  * jalr &findPackedSwitchIndex
   2852  * nop
   2853  * lw gp, 84(sp) |
   2854  * addu          | 20 bytes for these 5 instructions
   2855  * move          | (NOTE: if this sequence is shortened or lengthened, then
   2856  * jr            |  the 20 byte offset added below in 3 places must be changed
   2857  * nop           |  accordingly.)
   2858  * chaining cell for case 0 [16 bytes]
   2859  * chaining cell for case 1 [16 bytes]
   2860  *               :
   2861  * chaining cell for case MIN(size, MAX_CHAINED_SWITCH_CASES)-1 [16 bytes]
   2862  * chaining cell for case default [16 bytes]
   2863  * noChain exit
   2864  */
   2865 static u8 findPackedSwitchIndex(const u2* switchData, int testVal)
   2866 {
   2867     int size;
   2868     int firstKey;
   2869     const int *entries;
   2870     int index;
   2871     int jumpIndex;
   2872     uintptr_t caseDPCOffset = 0;
   2873 
   2874     /*
   2875      * Packed switch data format:
   2876      *  ushort ident = 0x0100   magic value
   2877      *  ushort size             number of entries in the table
   2878      *  int first_key           first (and lowest) switch case value
   2879      *  int targets[size]       branch targets, relative to switch opcode
   2880      *
   2881      * Total size is (4+size*2) 16-bit code units.
   2882      */
   2883     size = switchData[1];
   2884     assert(size > 0);
   2885 
   2886     firstKey = switchData[2];
   2887     firstKey |= switchData[3] << 16;
   2888 
   2889 
   2890     /* The entries are guaranteed to be aligned on a 32-bit boundary;
   2891      * we can treat them as a native int array.
   2892      */
   2893     entries = (const int*) &switchData[4];
   2894     assert(((u4)entries & 0x3) == 0);
   2895 
   2896     index = testVal - firstKey;
   2897 
   2898     /* Jump to the default cell */
   2899     if (index < 0 || index >= size) {
   2900         jumpIndex = MIN(size, MAX_CHAINED_SWITCH_CASES);
   2901     /* Jump to the non-chaining exit point */
   2902     } else if (index >= MAX_CHAINED_SWITCH_CASES) {
   2903         jumpIndex = MAX_CHAINED_SWITCH_CASES + 1;
   2904 #ifdef HAVE_LITTLE_ENDIAN
   2905         caseDPCOffset = entries[index];
   2906 #else
   2907         caseDPCOffset = (unsigned int)entries[index] >> 16 | entries[index] << 16;
   2908 #endif
   2909     /* Jump to the inline chaining cell */
   2910     } else {
   2911         jumpIndex = index;
   2912     }
   2913 
   2914     return (((u8) caseDPCOffset) << 32) | (u8) (jumpIndex * CHAIN_CELL_NORMAL_SIZE + 20);
   2915 }
   2916 
   2917 /* See comments for findPackedSwitchIndex */
   2918 static u8 findSparseSwitchIndex(const u2* switchData, int testVal)
   2919 {
   2920     int size;
   2921     const int *keys;
   2922     const int *entries;
   2923     /* In Thumb mode pc is 4 ahead of the "mov r2, pc" instruction */
   2924     int i;
   2925 
   2926     /*
   2927      * Sparse switch data format:
   2928      *  ushort ident = 0x0200   magic value
   2929      *  ushort size             number of entries in the table; > 0
   2930      *  int keys[size]          keys, sorted low-to-high; 32-bit aligned
   2931      *  int targets[size]       branch targets, relative to switch opcode
   2932      *
   2933      * Total size is (2+size*4) 16-bit code units.
   2934      */
   2935 
   2936     size = switchData[1];
   2937     assert(size > 0);
   2938 
   2939     /* The keys are guaranteed to be aligned on a 32-bit boundary;
   2940      * we can treat them as a native int array.
   2941      */
   2942     keys = (const int*) &switchData[2];
   2943     assert(((u4)keys & 0x3) == 0);
   2944 
   2945     /* The entries are guaranteed to be aligned on a 32-bit boundary;
   2946      * we can treat them as a native int array.
   2947      */
   2948     entries = keys + size;
   2949     assert(((u4)entries & 0x3) == 0);
   2950 
   2951     /*
   2952      * Run through the list of keys, which are guaranteed to
   2953      * be sorted low-to-high.
   2954      *
   2955      * Most tables have 3-4 entries.  Few have more than 10.  A binary
   2956      * search here is probably not useful.
   2957      */
   2958     for (i = 0; i < size; i++) {
   2959 #ifdef HAVE_LITTLE_ENDIAN
   2960         int k = keys[i];
   2961         if (k == testVal) {
   2962             /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
   2963             int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
   2964                            i : MAX_CHAINED_SWITCH_CASES + 1;
   2965             return (((u8) entries[i]) << 32) | (u8) (jumpIndex * CHAIN_CELL_NORMAL_SIZE + 20);
   2966 #else
   2967         int k = (unsigned int)keys[i] >> 16 | keys[i] << 16;
   2968         if (k == testVal) {
   2969             /* MAX_CHAINED_SWITCH_CASES + 1 is the start of the overflow case */
   2970             int jumpIndex = (i < MAX_CHAINED_SWITCH_CASES) ?
   2971                            i : MAX_CHAINED_SWITCH_CASES + 1;
   2972             int temp = (unsigned int)entries[i] >> 16 | entries[i] << 16;
   2973             return (((u8) temp) << 32) | (u8) (jumpIndex * CHAIN_CELL_NORMAL_SIZE + 20);
   2974 #endif
   2975         } else if (k > testVal) {
   2976             break;
   2977         }
   2978     }
   2979     return MIN(size, MAX_CHAINED_SWITCH_CASES) * CHAIN_CELL_NORMAL_SIZE + 20;
   2980 }
   2981 
   2982 static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
   2983 {
   2984     Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   2985     switch (dalvikOpcode) {
   2986         case OP_FILL_ARRAY_DATA: {
   2987             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   2988             // Making a call - use explicit registers
   2989             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
   2990             genExportPC(cUnit, mir);
   2991             loadValueDirectFixed(cUnit, rlSrc, r_A0);
   2992             LOAD_FUNC_ADDR(cUnit, r_T9, (int)dvmInterpHandleFillArrayData);
   2993             loadConstant(cUnit, r_A1,
   2994                (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
   2995             opReg(cUnit, kOpBlx, r_T9);
   2996             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   2997             dvmCompilerClobberCallRegs(cUnit);
   2998             /* generate a branch over if successful */
   2999             MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
   3000             loadConstant(cUnit, r_A0,
   3001                          (int) (cUnit->method->insns + mir->offset));
   3002             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
   3003             MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   3004             target->defMask = ENCODE_ALL;
   3005             branchOver->generic.target = (LIR *) target;
   3006             break;
   3007         }
   3008         /*
   3009          * Compute the goto target of up to
   3010          * MIN(switchSize, MAX_CHAINED_SWITCH_CASES) + 1 chaining cells.
   3011          * See the comment before findPackedSwitchIndex for the code layout.
   3012          */
   3013         case OP_PACKED_SWITCH:
   3014         case OP_SPARSE_SWITCH: {
   3015             RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   3016             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
   3017             loadValueDirectFixed(cUnit, rlSrc, r_A1);
   3018             dvmCompilerLockAllTemps(cUnit);
   3019 
   3020             if (dalvikOpcode == OP_PACKED_SWITCH) {
   3021                 LOAD_FUNC_ADDR(cUnit, r_T9, (int)findPackedSwitchIndex);
   3022             } else {
   3023                 LOAD_FUNC_ADDR(cUnit, r_T9, (int)findSparseSwitchIndex);
   3024             }
   3025             /* r_A0 <- Addr of the switch data */
   3026             loadConstant(cUnit, r_A0,
   3027                (int) (cUnit->method->insns + mir->offset + mir->dalvikInsn.vB));
   3028             opReg(cUnit, kOpBlx, r_T9);
   3029             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   3030             dvmCompilerClobberCallRegs(cUnit);
   3031             /* pc <- computed goto target using value in RA */
   3032             newLIR3(cUnit, kMipsAddu, r_A0, r_RA, r_RESULT0);
   3033             newLIR2(cUnit, kMipsMove, r_A1, r_RESULT1);
   3034             newLIR1(cUnit, kMipsJr, r_A0);
   3035             newLIR0(cUnit, kMipsNop); /* for maintaining 20 byte offset */
   3036             break;
   3037         }
   3038         default:
   3039             return true;
   3040     }
   3041     return false;
   3042 }
   3043 
   3044 /*
   3045  * See the example of predicted inlining listed before the
   3046  * genValidationForPredictedInline function. The function here takes care the
   3047  * branch over at 0x4858de78 and the misprediction target at 0x4858de7a.
   3048  */
   3049 static void genLandingPadForMispredictedCallee(CompilationUnit *cUnit, MIR *mir,
   3050                                                BasicBlock *bb,
   3051                                                MipsLIR *labelList)
   3052 {
   3053     BasicBlock *fallThrough = bb->fallThrough;
   3054 
   3055     /* Bypass the move-result block if there is one */
   3056     if (fallThrough->firstMIRInsn) {
   3057         assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
   3058         fallThrough = fallThrough->fallThrough;
   3059     }
   3060     /* Generate a branch over if the predicted inlining is correct */
   3061     genUnconditionalBranch(cUnit, &labelList[fallThrough->id]);
   3062 
   3063     /* Reset the register state */
   3064     dvmCompilerResetRegPool(cUnit);
   3065     dvmCompilerClobberAllRegs(cUnit);
   3066     dvmCompilerResetNullCheck(cUnit);
   3067 
   3068     /* Target for the slow invoke path */
   3069     MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   3070     target->defMask = ENCODE_ALL;
   3071     /* Hook up the target to the verification branch */
   3072     mir->meta.callsiteInfo->misPredBranchOver->target = (LIR *) target;
   3073 }
   3074 
   3075 static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir,
   3076                              BasicBlock *bb, MipsLIR *labelList)
   3077 {
   3078     MipsLIR *retChainingCell = NULL;
   3079     MipsLIR *pcrLabel = NULL;
   3080 
   3081     /* An invoke with the MIR_INLINED is effectively a no-op */
   3082     if (mir->OptimizationFlags & MIR_INLINED)
   3083         return false;
   3084 
   3085     if (bb->fallThrough != NULL)
   3086         retChainingCell = &labelList[bb->fallThrough->id];
   3087 
   3088     DecodedInstruction *dInsn = &mir->dalvikInsn;
   3089     switch (mir->dalvikInsn.opcode) {
   3090         /*
   3091          * calleeMethod = this->clazz->vtable[
   3092          *     method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
   3093          * ]
   3094          */
   3095         case OP_INVOKE_VIRTUAL:
   3096         case OP_INVOKE_VIRTUAL_RANGE: {
   3097             MipsLIR *predChainingCell = &labelList[bb->taken->id];
   3098             int methodIndex =
   3099                 cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
   3100                 methodIndex;
   3101 
   3102             /*
   3103              * If the invoke has non-null misPredBranchOver, we need to generate
   3104              * the non-inlined version of the invoke here to handle the
   3105              * mispredicted case.
   3106              */
   3107             if (mir->meta.callsiteInfo->misPredBranchOver) {
   3108                 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
   3109             }
   3110 
   3111             if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
   3112                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
   3113             else
   3114                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
   3115 
   3116             genInvokeVirtualCommon(cUnit, mir, methodIndex,
   3117                                    retChainingCell,
   3118                                    predChainingCell,
   3119                                    pcrLabel);
   3120             break;
   3121         }
   3122         /*
   3123          * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
   3124          *                ->pResMethods[BBBB]->methodIndex]
   3125          */
   3126         case OP_INVOKE_SUPER:
   3127         case OP_INVOKE_SUPER_RANGE: {
   3128             /* Grab the method ptr directly from what the interpreter sees */
   3129             const Method *calleeMethod = mir->meta.callsiteInfo->method;
   3130             assert(calleeMethod == cUnit->method->clazz->super->vtable[
   3131                                      cUnit->method->clazz->pDvmDex->
   3132                                        pResMethods[dInsn->vB]->methodIndex]);
   3133 
   3134             if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER)
   3135                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
   3136             else
   3137                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
   3138 
   3139             if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
   3140                 const Method *calleeMethod = mir->meta.callsiteInfo->method;
   3141                 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
   3142                 assert(calleeAddr);
   3143                 genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
   3144                                               retChainingCell);
   3145             } else {
   3146                 /* r_A0 = calleeMethod */
   3147                 loadConstant(cUnit, r_A0, (int) calleeMethod);
   3148 
   3149                 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
   3150                                          calleeMethod);
   3151             }
   3152             break;
   3153         }
   3154         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
   3155         case OP_INVOKE_DIRECT:
   3156         case OP_INVOKE_DIRECT_RANGE: {
   3157             /* Grab the method ptr directly from what the interpreter sees */
   3158             const Method *calleeMethod = mir->meta.callsiteInfo->method;
   3159             assert(calleeMethod ==
   3160                    cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
   3161 
   3162             if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
   3163                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
   3164             else
   3165                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
   3166 
   3167             /* r_A0 = calleeMethod */
   3168             loadConstant(cUnit, r_A0, (int) calleeMethod);
   3169 
   3170             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
   3171                                      calleeMethod);
   3172             break;
   3173         }
   3174         /* calleeMethod = method->clazz->pDvmDex->pResMethods[BBBB] */
   3175         case OP_INVOKE_STATIC:
   3176         case OP_INVOKE_STATIC_RANGE: {
   3177             /* Grab the method ptr directly from what the interpreter sees */
   3178             const Method *calleeMethod = mir->meta.callsiteInfo->method;
   3179             assert(calleeMethod ==
   3180                    cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]);
   3181 
   3182             if (mir->dalvikInsn.opcode == OP_INVOKE_STATIC)
   3183                 genProcessArgsNoRange(cUnit, mir, dInsn,
   3184                                       NULL /* no null check */);
   3185             else
   3186                 genProcessArgsRange(cUnit, mir, dInsn,
   3187                                     NULL /* no null check */);
   3188 
   3189             if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
   3190                 const Method *calleeMethod = mir->meta.callsiteInfo->method;
   3191                 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
   3192                 assert(calleeAddr);
   3193                 genInvokeSingletonWholeMethod(cUnit, mir, calleeAddr,
   3194                                               retChainingCell);
   3195             } else {
   3196                 /* r_A0 = calleeMethod */
   3197                 loadConstant(cUnit, r_A0, (int) calleeMethod);
   3198 
   3199                 genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
   3200                                          calleeMethod);
   3201             }
   3202             break;
   3203         }
   3204 
   3205         /*
   3206          * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
   3207          *                    BBBB, method, method->clazz->pDvmDex)
   3208          *
   3209          * The following is an example of generated code for
   3210          *      "invoke-interface v0"
   3211          *
   3212          * -------- dalvik offset: 0x000f @ invoke-interface (PI) v2
   3213          * 0x2f140c54 : lw       a0,8(s1)                    # genProcessArgsNoRange
   3214          * 0x2f140c58 : addiu    s4,s1,0xffffffe8(-24)
   3215          * 0x2f140c5c : beqz     a0,0x2f140d5c (L0x11f864)
   3216          * 0x2f140c60 : pref     1,0(s4)
   3217          * -------- BARRIER
   3218          * 0x2f140c64 : sw       a0,0(s4)
   3219          * 0x2f140c68 : addiu    s4,s4,0x0004(4)
   3220          * -------- BARRIER
   3221          * 0x2f140c6c : lui      s0,0x2d23(11555)            # dalvikPC
   3222          * 0x2f140c70 : ori      s0,s0,0x2d2365a6(757294502)
   3223          * 0x2f140c74 : lahi/lui a1,0x2f14(12052)            # a1 <- &retChainingCell
   3224          * 0x2f140c78 : lalo/ori a1,a1,0x2f140d38(789843256)
   3225          * 0x2f140c7c : lahi/lui a2,0x2f14(12052)            # a2 <- &predictedChainingCell
   3226          * 0x2f140c80 : lalo/ori a2,a2,0x2f140d80(789843328)
   3227          * 0x2f140c84 : jal      0x2f1311ec(789778924)       # call TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
   3228          * 0x2f140c88 : nop
   3229          * 0x2f140c8c : b        0x2f140d80 (L0x11efc0)      # off to the predicted chain
   3230          * 0x2f140c90 : nop
   3231          * 0x2f140c94 : b        0x2f140d60 (L0x12457c)      # punt to the interpreter
   3232          * 0x2f140c98 : lui      a0,0x2d23(11555)
   3233          * 0x2f140c9c : move     s5,a1                       # prepare for dvmFindInterfaceMethodInCache
   3234          * 0x2f140ca0 : move     s6,a2
   3235          * 0x2f140ca4 : move     s7,a3
   3236          * 0x2f140ca8 : move     a0,a3
   3237          * 0x2f140cac : ori      a1,zero,0x2b42(11074)
   3238          * 0x2f140cb0 : lui      a2,0x2c92(11410)
   3239          * 0x2f140cb4 : ori      a2,a2,0x2c92adf8(747810296)
   3240          * 0x2f140cb8 : lui      a3,0x0009(9)
   3241          * 0x2f140cbc : ori      a3,a3,0x924b8(599224)
   3242          * 0x2f140cc0 : lui      t9,0x2ab2(10930)
   3243          * 0x2f140cc4 : ori      t9,t9,0x2ab2a48c(716350604)
   3244          * 0x2f140cc8 : jalr     ra,t9                       # call dvmFindInterfaceMethodInCache
   3245          * 0x2f140ccc : nop
   3246          * 0x2f140cd0 : lw       gp,84(sp)
   3247          * 0x2f140cd4 : move     a0,v0
   3248          * 0x2f140cd8 : bne      v0,zero,0x2f140cf0 (L0x120064)
   3249          * 0x2f140cdc : nop
   3250          * 0x2f140ce0 : lui      a0,0x2d23(11555)            # a0 <- dalvikPC
   3251          * 0x2f140ce4 : ori      a0,a0,0x2d2365a6(757294502)
   3252          * 0x2f140ce8 : jal      0x2f131720(789780256)       # call TEMPLATE_THROW_EXCEPTION_COMMON
   3253          * 0x2f140cec : nop
   3254          * 0x2f140cf0 : move     a1,s5                       # a1 <- &retChainingCell
   3255          * 0x2f140cf4 : bgtz     s5,0x2f140d20 (L0x120324)   # >0? don't rechain
   3256          * 0x2f140cf8 : nop
   3257          * 0x2f140cfc : lui      t9,0x2aba(10938)            # prepare for dvmJitToPatchPredictedChain
   3258          * 0x2f140d00 : ori      t9,t9,0x2abae3c4(716891076)
   3259          * 0x2f140d04 : move     a1,s2
   3260          * 0x2f140d08 : move     a2,s6
   3261          * 0x2f140d0c : move     a3,s7
   3262          * 0x2f140d10 : jalr     ra,t9                       # call dvmJitToPatchPredictedChain
   3263          * 0x2f140d14 : nop
   3264          * 0x2f140d18 : lw       gp,84(sp)
   3265          * 0x2f140d1c : move     a0,v0
   3266          * 0x2f140d20 : lahi/lui a1,0x2f14(12052)
   3267          * 0x2f140d24 : lalo/ori a1,a1,0x2f140d38(789843256) # a1 <- &retChainingCell
   3268          * 0x2f140d28 : jal      0x2f1310c4(789778628)       # call TEMPLATE_INVOKE_METHOD_NO_OPT
   3269          * 0x2f140d2c : nop
   3270          * 0x2f140d30 : b        0x2f140d60 (L0x12457c)
   3271          * 0x2f140d34 : lui      a0,0x2d23(11555)
   3272          * 0x2f140d38 : .align4
   3273          * -------- dalvik offset: 0x0012 @ move-result (PI) v1, (#0), (#0)
   3274          * 0x2f140d38 : lw       a2,16(s2)
   3275          * 0x2f140d3c : sw       a2,4(s1)
   3276          * 0x2f140d40 : b        0x2f140d74 (L0x1246fc)
   3277          * 0x2f140d44 : lw       a0,116(s2)
   3278          * 0x2f140d48 : undefined
   3279          * -------- reconstruct dalvik PC : 0x2d2365a6 @ +0x000f
   3280          * 0x2f140d4c : lui      a0,0x2d23(11555)
   3281          * 0x2f140d50 : ori      a0,a0,0x2d2365a6(757294502)
   3282          * 0x2f140d54 : b        0x2f140d68 (L0x12463c)
   3283          * 0x2f140d58 : lw       a1,108(s2)
   3284          * -------- reconstruct dalvik PC : 0x2d2365a6 @ +0x000f
   3285          * 0x2f140d5c : lui      a0,0x2d23(11555)
   3286          * 0x2f140d60 : ori      a0,a0,0x2d2365a6(757294502)
   3287          * Exception_Handling:
   3288          * 0x2f140d64 : lw       a1,108(s2)
   3289          * 0x2f140d68 : jalr     ra,a1
   3290          * 0x2f140d6c : nop
   3291          * 0x2f140d70 : .align4
   3292          * -------- chaining cell (hot): 0x0013
   3293          * 0x2f140d70 : lw       a0,116(s2)
   3294          * 0x2f140d74 : jalr     ra,a0
   3295          * 0x2f140d78 : nop
   3296          * 0x2f140d7c : data     0x2d2365ae(757294510)
   3297          * 0x2f140d80 : .align4
   3298          * -------- chaining cell (predicted): N/A
   3299          * 0x2f140d80 : data     0xe7fe(59390)
   3300          * 0x2f140d84 : data     0x0000(0)
   3301          * 0x2f140d88 : data     0x0000(0)
   3302          * 0x2f140d8c : data     0x0000(0)
   3303          * 0x2f140d90 : data     0x0000(0)
   3304          * -------- end of chaining cells (0x0190)
   3305          */
   3306         case OP_INVOKE_INTERFACE:
   3307         case OP_INVOKE_INTERFACE_RANGE: {
   3308             MipsLIR *predChainingCell = &labelList[bb->taken->id];
   3309 
   3310             /*
   3311              * If the invoke has non-null misPredBranchOver, we need to generate
   3312              * the non-inlined version of the invoke here to handle the
   3313              * mispredicted case.
   3314              */
   3315             if (mir->meta.callsiteInfo->misPredBranchOver) {
   3316                 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
   3317             }
   3318 
   3319             if (mir->dalvikInsn.opcode == OP_INVOKE_INTERFACE)
   3320                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
   3321             else
   3322                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
   3323 
   3324             /* "this" is already left in r_A0 by genProcessArgs* */
   3325 
   3326             /* r4PC = dalvikCallsite */
   3327             loadConstant(cUnit, r4PC,
   3328                          (int) (cUnit->method->insns + mir->offset));
   3329 
   3330             /* r_A1 = &retChainingCell */
   3331             MipsLIR *addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
   3332             addrRetChain->generic.target = (LIR *) retChainingCell;
   3333             addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
   3334             addrRetChain->generic.target = (LIR *) retChainingCell;
   3335 
   3336 
   3337             /* r_A2 = &predictedChainingCell */
   3338             MipsLIR *predictedChainingCell = newLIR2(cUnit, kMipsLahi, r_A2, 0);
   3339             predictedChainingCell->generic.target = (LIR *) predChainingCell;
   3340             predictedChainingCell = newLIR3(cUnit, kMipsLalo, r_A2, r_A2, 0);
   3341             predictedChainingCell->generic.target = (LIR *) predChainingCell;
   3342 
   3343             genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
   3344                 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF :
   3345                 TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN);
   3346 
   3347             /* return through ra - jump to the chaining cell */
   3348             genUnconditionalBranch(cUnit, predChainingCell);
   3349 
   3350             /*
   3351              * null-check on "this" may have been eliminated, but we still need
   3352              * a PC-reconstruction label for stack overflow bailout.
   3353              */
   3354             if (pcrLabel == NULL) {
   3355                 int dPC = (int) (cUnit->method->insns + mir->offset);
   3356                 pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
   3357                 pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
   3358                 pcrLabel->operands[0] = dPC;
   3359                 pcrLabel->operands[1] = mir->offset;
   3360                 /* Insert the place holder to the growable list */
   3361                 dvmInsertGrowableList(&cUnit->pcReconstructionList,
   3362                                       (intptr_t) pcrLabel);
   3363             }
   3364 
   3365             /* return through ra+8 - punt to the interpreter */
   3366             genUnconditionalBranch(cUnit, pcrLabel);
   3367 
   3368             /*
   3369              * return through ra+16 - fully resolve the callee method.
   3370              * r_A1 <- count
   3371              * r_A2 <- &predictedChainCell
   3372              * r_A3 <- this->class
   3373              * r4 <- dPC
   3374              * r_S4 <- this->class->vtable
   3375              */
   3376 
   3377             /* Save count, &predictedChainCell, and class to high regs first */
   3378             genRegCopy(cUnit, r_S5, r_A1);
   3379             genRegCopy(cUnit, r_S6, r_A2);
   3380             genRegCopy(cUnit, r_S7, r_A3);
   3381 
   3382             /* r_A0 now contains this->clazz */
   3383             genRegCopy(cUnit, r_A0, r_A3);
   3384 
   3385             /* r_A1 = BBBB */
   3386             loadConstant(cUnit, r_A1, dInsn->vB);
   3387 
   3388             /* r_A2 = method (caller) */
   3389             loadConstant(cUnit, r_A2, (int) cUnit->method);
   3390 
   3391             /* r_A3 = pDvmDex */
   3392             loadConstant(cUnit, r_A3, (int) cUnit->method->clazz->pDvmDex);
   3393 
   3394             LOAD_FUNC_ADDR(cUnit, r_T9,
   3395                            (intptr_t) dvmFindInterfaceMethodInCache);
   3396             opReg(cUnit, kOpBlx, r_T9);
   3397             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   3398             /* r_V0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
   3399             genRegCopy(cUnit, r_A0, r_V0);
   3400 
   3401             dvmCompilerClobberCallRegs(cUnit);
   3402             /* generate a branch over if the interface method is resolved */
   3403             MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
   3404             /*
   3405              * calleeMethod == NULL -> throw
   3406              */
   3407             loadConstant(cUnit, r_A0,
   3408                          (int) (cUnit->method->insns + mir->offset));
   3409             genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
   3410             /* noreturn */
   3411 
   3412             MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   3413             target->defMask = ENCODE_ALL;
   3414             branchOver->generic.target = (LIR *) target;
   3415 
   3416             genRegCopy(cUnit, r_A1, r_S5);
   3417 
   3418             /* Check if rechain limit is reached */
   3419             MipsLIR *bypassRechaining = opCompareBranch(cUnit, kMipsBgtz, r_S5, -1);
   3420 
   3421             LOAD_FUNC_ADDR(cUnit, r_T9, (int) dvmJitToPatchPredictedChain);
   3422 
   3423             genRegCopy(cUnit, r_A1, rSELF);
   3424             genRegCopy(cUnit, r_A2, r_S6);
   3425             genRegCopy(cUnit, r_A3, r_S7);
   3426 
   3427             /*
   3428              * r_A0 = calleeMethod
   3429              * r_A2 = &predictedChainingCell
   3430              * r_A3 = class
   3431              *
   3432              * &returnChainingCell has been loaded into r_A1 but is not needed
   3433              * when patching the chaining cell and will be clobbered upon
   3434              * returning so it will be reconstructed again.
   3435              */
   3436             opReg(cUnit, kOpBlx, r_T9);
   3437             newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   3438             genRegCopy(cUnit, r_A0, r_V0);
   3439 
   3440             /* r_A1 = &retChainingCell */
   3441             addrRetChain = newLIR2(cUnit, kMipsLahi, r_A1, 0);
   3442             addrRetChain->generic.target = (LIR *) retChainingCell;
   3443             bypassRechaining->generic.target = (LIR *) addrRetChain;
   3444             addrRetChain = newLIR3(cUnit, kMipsLalo, r_A1, r_A1, 0);
   3445             addrRetChain->generic.target = (LIR *) retChainingCell;
   3446 
   3447 
   3448             /*
   3449              * r_A0 = this, r_A1 = calleeMethod,
   3450              * r_A1 = &ChainingCell,
   3451              * r4PC = callsiteDPC,
   3452              */
   3453             genDispatchToHandler(cUnit, gDvmJit.methodTraceSupport ?
   3454                 TEMPLATE_INVOKE_METHOD_NO_OPT_PROF :
   3455                 TEMPLATE_INVOKE_METHOD_NO_OPT);
   3456 
   3457 #if defined(WITH_JIT_TUNING)
   3458             gDvmJit.invokePolymorphic++;
   3459 #endif
   3460             /* Handle exceptions using the interpreter */
   3461             genTrap(cUnit, mir->offset, pcrLabel);
   3462             break;
   3463         }
   3464         case OP_INVOKE_OBJECT_INIT_RANGE:
   3465         case OP_FILLED_NEW_ARRAY:
   3466         case OP_FILLED_NEW_ARRAY_RANGE: {
   3467             /* Just let the interpreter deal with these */
   3468             genInterpSingleStep(cUnit, mir);
   3469             break;
   3470         }
   3471         default:
   3472             return true;
   3473     }
   3474     return false;
   3475 }
   3476 
   3477 static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
   3478                                BasicBlock *bb, MipsLIR *labelList)
   3479 {
   3480     MipsLIR *pcrLabel = NULL;
   3481 
   3482     /* An invoke with the MIR_INLINED is effectively a no-op */
   3483     if (mir->OptimizationFlags & MIR_INLINED)
   3484         return false;
   3485 
   3486     DecodedInstruction *dInsn = &mir->dalvikInsn;
   3487     switch (mir->dalvikInsn.opcode) {
   3488         /* calleeMethod = this->clazz->vtable[BBBB] */
   3489         case OP_INVOKE_VIRTUAL_QUICK_RANGE:
   3490         case OP_INVOKE_VIRTUAL_QUICK: {
   3491             int methodIndex = dInsn->vB;
   3492             MipsLIR *retChainingCell = &labelList[bb->fallThrough->id];
   3493             MipsLIR *predChainingCell = &labelList[bb->taken->id];
   3494 
   3495             /*
   3496              * If the invoke has non-null misPredBranchOver, we need to generate
   3497              * the non-inlined version of the invoke here to handle the
   3498              * mispredicted case.
   3499              */
   3500             if (mir->meta.callsiteInfo->misPredBranchOver) {
   3501                 genLandingPadForMispredictedCallee(cUnit, mir, bb, labelList);
   3502             }
   3503 
   3504             if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL_QUICK)
   3505                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
   3506             else
   3507                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
   3508 
   3509             if (mir->OptimizationFlags & MIR_INVOKE_METHOD_JIT) {
   3510                 const Method *calleeMethod = mir->meta.callsiteInfo->method;
   3511                 void *calleeAddr = dvmJitGetMethodAddr(calleeMethod->insns);
   3512                 assert(calleeAddr);
   3513                 genInvokeVirtualWholeMethod(cUnit, mir, calleeAddr,
   3514                                             retChainingCell);
   3515             }
   3516 
   3517             genInvokeVirtualCommon(cUnit, mir, methodIndex,
   3518                                    retChainingCell,
   3519                                    predChainingCell,
   3520                                    pcrLabel);
   3521             break;
   3522         }
   3523         /* calleeMethod = method->clazz->super->vtable[BBBB] */
   3524         case OP_INVOKE_SUPER_QUICK:
   3525         case OP_INVOKE_SUPER_QUICK_RANGE: {
   3526             /* Grab the method ptr directly from what the interpreter sees */
   3527             const Method *calleeMethod = mir->meta.callsiteInfo->method;
   3528             assert(calleeMethod ==
   3529                    cUnit->method->clazz->super->vtable[dInsn->vB]);
   3530 
   3531             if (mir->dalvikInsn.opcode == OP_INVOKE_SUPER_QUICK)
   3532                 genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
   3533             else
   3534                 genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
   3535 
   3536             /* r_A0 = calleeMethod */
   3537             loadConstant(cUnit, r_A0, (int) calleeMethod);
   3538 
   3539             genInvokeSingletonCommon(cUnit, mir, bb, labelList, pcrLabel,
   3540                                      calleeMethod);
   3541             break;
   3542         }
   3543         default:
   3544             return true;
   3545     }
   3546     return false;
   3547 }
   3548 
   3549 /*
   3550  * This operation is complex enough that we'll do it partly inline
   3551  * and partly with a handler.  NOTE: the handler uses hardcoded
   3552  * values for string object offsets and must be revisitied if the
   3553  * layout changes.
   3554  */
   3555 static bool genInlinedCompareTo(CompilationUnit *cUnit, MIR *mir)
   3556 {
   3557 #if defined(USE_GLOBAL_STRING_DEFS)
   3558     return handleExecuteInlineC(cUnit, mir);
   3559 #else
   3560     MipsLIR *rollback;
   3561     RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
   3562     RegLocation rlComp = dvmCompilerGetSrc(cUnit, mir, 1);
   3563 
   3564     loadValueDirectFixed(cUnit, rlThis, r_A0);
   3565     loadValueDirectFixed(cUnit, rlComp, r_A1);
   3566     /* Test objects for NULL */
   3567     rollback = genNullCheck(cUnit, rlThis.sRegLow, r_A0, mir->offset, NULL);
   3568     genNullCheck(cUnit, rlComp.sRegLow, r_A1, mir->offset, rollback);
   3569     /*
   3570      * TUNING: we could check for object pointer equality before invoking
   3571      * handler. Unclear whether the gain would be worth the added code size
   3572      * expansion.
   3573      */
   3574     genDispatchToHandler(cUnit, TEMPLATE_STRING_COMPARETO);
   3575     storeValue(cUnit, inlinedTarget(cUnit, mir, false),
   3576                dvmCompilerGetReturn(cUnit));
   3577     return false;
   3578 #endif
   3579 }
   3580 
   3581 static bool genInlinedFastIndexOf(CompilationUnit *cUnit, MIR *mir)
   3582 {
   3583 #if defined(USE_GLOBAL_STRING_DEFS)
   3584     return handleExecuteInlineC(cUnit, mir);
   3585 #else
   3586     RegLocation rlThis = dvmCompilerGetSrc(cUnit, mir, 0);
   3587     RegLocation rlChar = dvmCompilerGetSrc(cUnit, mir, 1);
   3588 
   3589     loadValueDirectFixed(cUnit, rlThis, r_A0);
   3590     loadValueDirectFixed(cUnit, rlChar, r_A1);
   3591 
   3592     RegLocation rlStart = dvmCompilerGetSrc(cUnit, mir, 2);
   3593     loadValueDirectFixed(cUnit, rlStart, r_A2);
   3594 
   3595     /* Test objects for NULL */
   3596     genNullCheck(cUnit, rlThis.sRegLow, r_A0, mir->offset, NULL);
   3597     genDispatchToHandler(cUnit, TEMPLATE_STRING_INDEXOF);
   3598     storeValue(cUnit, inlinedTarget(cUnit, mir, false),
   3599                dvmCompilerGetReturn(cUnit));
   3600     return false;
   3601 #endif
   3602 }
   3603 
   3604 // Generates an inlined String.isEmpty or String.length.
   3605 static bool genInlinedStringIsEmptyOrLength(CompilationUnit *cUnit, MIR *mir,
   3606                                             bool isEmpty)
   3607 {
   3608     // dst = src.length();
   3609     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
   3610     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
   3611     rlObj = loadValue(cUnit, rlObj, kCoreReg);
   3612     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   3613     genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset, NULL);
   3614     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count,
   3615                  rlResult.lowReg);
   3616     if (isEmpty) {
   3617         // dst = (dst == 0);
   3618         int tReg = dvmCompilerAllocTemp(cUnit);
   3619         newLIR3(cUnit, kMipsSltu, tReg, r_ZERO, rlResult.lowReg);
   3620         opRegRegImm(cUnit, kOpXor, rlResult.lowReg, tReg, 1);
   3621     }
   3622     storeValue(cUnit, rlDest, rlResult);
   3623     return false;
   3624 }
   3625 
   3626 static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
   3627 {
   3628     return genInlinedStringIsEmptyOrLength(cUnit, mir, false);
   3629 }
   3630 
   3631 static bool genInlinedStringIsEmpty(CompilationUnit *cUnit, MIR *mir)
   3632 {
   3633     return genInlinedStringIsEmptyOrLength(cUnit, mir, true);
   3634 }
   3635 
   3636 static bool genInlinedStringCharAt(CompilationUnit *cUnit, MIR *mir)
   3637 {
   3638     int contents = OFFSETOF_MEMBER(ArrayObject, contents);
   3639     RegLocation rlObj = dvmCompilerGetSrc(cUnit, mir, 0);
   3640     RegLocation rlIdx = dvmCompilerGetSrc(cUnit, mir, 1);
   3641     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
   3642     RegLocation rlResult;
   3643     rlObj = loadValue(cUnit, rlObj, kCoreReg);
   3644     rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
   3645     int regMax = dvmCompilerAllocTemp(cUnit);
   3646     int regOff = dvmCompilerAllocTemp(cUnit);
   3647     int regPtr = dvmCompilerAllocTemp(cUnit);
   3648     MipsLIR *pcrLabel = genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg,
   3649                                     mir->offset, NULL);
   3650     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_count, regMax);
   3651     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_offset, regOff);
   3652     loadWordDisp(cUnit, rlObj.lowReg, gDvm.offJavaLangString_value, regPtr);
   3653     genBoundsCheck(cUnit, rlIdx.lowReg, regMax, mir->offset, pcrLabel);
   3654     dvmCompilerFreeTemp(cUnit, regMax);
   3655     opRegImm(cUnit, kOpAdd, regPtr, contents);
   3656     opRegReg(cUnit, kOpAdd, regOff, rlIdx.lowReg);
   3657     rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   3658     loadBaseIndexed(cUnit, regPtr, regOff, rlResult.lowReg, 1, kUnsignedHalf);
   3659     storeValue(cUnit, rlDest, rlResult);
   3660     return false;
   3661 }
   3662 
   3663 static bool genInlinedAbsInt(CompilationUnit *cUnit, MIR *mir)
   3664 {
   3665     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   3666     rlSrc = loadValue(cUnit, rlSrc, kCoreReg);
   3667     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
   3668     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   3669     int signReg = dvmCompilerAllocTemp(cUnit);
   3670     /*
   3671      * abs(x) = y<=x>>31, (x+y)^y.
   3672      * Thumb2's IT block also yields 3 instructions, but imposes
   3673      * scheduling constraints.
   3674      */
   3675     opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.lowReg, 31);
   3676     opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
   3677     opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
   3678     storeValue(cUnit, rlDest, rlResult);
   3679     return false;
   3680 }
   3681 
   3682 static bool genInlinedAbsLong(CompilationUnit *cUnit, MIR *mir)
   3683 {
   3684     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
   3685     RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
   3686     rlSrc = loadValueWide(cUnit, rlSrc, kCoreReg);
   3687     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   3688     int signReg = dvmCompilerAllocTemp(cUnit);
   3689     int tReg = dvmCompilerAllocTemp(cUnit);
   3690     /*
   3691      * abs(x) = y<=x>>31, (x+y)^y.
   3692      * Thumb2 IT block allows slightly shorter sequence,
   3693      * but introduces a scheduling barrier.  Stick with this
   3694      * mechanism for now.
   3695      */
   3696     opRegRegImm(cUnit, kOpAsr, signReg, rlSrc.highReg, 31);
   3697     opRegRegReg(cUnit, kOpAdd, rlResult.lowReg, rlSrc.lowReg, signReg);
   3698     newLIR3(cUnit, kMipsSltu, tReg, rlResult.lowReg, signReg);
   3699     opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlSrc.highReg, signReg);
   3700     opRegRegReg(cUnit, kOpAdd, rlResult.highReg, rlResult.highReg, tReg);
   3701     opRegReg(cUnit, kOpXor, rlResult.lowReg, signReg);
   3702     opRegReg(cUnit, kOpXor, rlResult.highReg, signReg);
   3703     dvmCompilerFreeTemp(cUnit, signReg);
   3704     dvmCompilerFreeTemp(cUnit, tReg);
   3705     storeValueWide(cUnit, rlDest, rlResult);
   3706     return false;
   3707 }
   3708 
   3709 static bool genInlinedIntFloatConversion(CompilationUnit *cUnit, MIR *mir)
   3710 {
   3711     // Just move from source to destination...
   3712     RegLocation rlSrc = dvmCompilerGetSrc(cUnit, mir, 0);
   3713     RegLocation rlDest = inlinedTarget(cUnit, mir, false);
   3714     storeValue(cUnit, rlDest, rlSrc);
   3715     return false;
   3716 }
   3717 
   3718 static bool genInlinedLongDoubleConversion(CompilationUnit *cUnit, MIR *mir)
   3719 {
   3720     // Just move from source to destination...
   3721     RegLocation rlSrc = dvmCompilerGetSrcWide(cUnit, mir, 0, 1);
   3722     RegLocation rlDest = inlinedTargetWide(cUnit, mir, false);
   3723     storeValueWide(cUnit, rlDest, rlSrc);
   3724     return false;
   3725 }
   3726 /*
   3727  * JITs a call to a C function.
   3728  * TODO: use this for faster native method invocation for simple native
   3729  * methods (http://b/3069458).
   3730  */
   3731 static bool handleExecuteInlineC(CompilationUnit *cUnit, MIR *mir)
   3732 {
   3733     DecodedInstruction *dInsn = &mir->dalvikInsn;
   3734     int operation = dInsn->vB;
   3735     unsigned int i;
   3736     const InlineOperation* inLineTable = dvmGetInlineOpsTable();
   3737     uintptr_t fn = (int) inLineTable[operation].func;
   3738     if (fn == 0) {
   3739         dvmCompilerAbort(cUnit);
   3740     }
   3741     dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
   3742     dvmCompilerClobberCallRegs(cUnit);
   3743     dvmCompilerClobber(cUnit, r4PC);
   3744     dvmCompilerClobber(cUnit, rINST);
   3745     int offset = offsetof(Thread, interpSave.retval);
   3746     opRegRegImm(cUnit, kOpAdd, r4PC, rSELF, offset);
   3747     newLIR3(cUnit, kMipsSw, r4PC, 16, r_SP); /* sp has plenty of space */
   3748     genExportPC(cUnit, mir);
   3749     assert(dInsn->vA <= 4);
   3750     for (i=0; i < dInsn->vA; i++) {
   3751         loadValueDirect(cUnit, dvmCompilerGetSrc(cUnit, mir, i), i+r_A0);
   3752     }
   3753     LOAD_FUNC_ADDR(cUnit, r_T9, fn);
   3754     opReg(cUnit, kOpBlx, r_T9);
   3755     newLIR3(cUnit, kMipsLw, r_GP, STACK_OFFSET_GP, r_SP);
   3756     /* NULL? */
   3757     MipsLIR *branchOver = opCompareBranch(cUnit, kMipsBne, r_V0, r_ZERO);
   3758     loadConstant(cUnit, r_A0, (int) (cUnit->method->insns + mir->offset));
   3759     genDispatchToHandler(cUnit, TEMPLATE_THROW_EXCEPTION_COMMON);
   3760     MipsLIR *target = newLIR0(cUnit, kMipsPseudoTargetLabel);
   3761     target->defMask = ENCODE_ALL;
   3762     branchOver->generic.target = (LIR *) target;
   3763     return false;
   3764 }
   3765 
   3766 /*
   3767  * NOTE: Handles both range and non-range versions (arguments
   3768  * have already been normalized by this point).
   3769  */
   3770 static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir)
   3771 {
   3772     DecodedInstruction *dInsn = &mir->dalvikInsn;
   3773     assert(dInsn->opcode == OP_EXECUTE_INLINE_RANGE ||
   3774            dInsn->opcode == OP_EXECUTE_INLINE);
   3775     switch (dInsn->vB) {
   3776         case INLINE_EMPTYINLINEMETHOD:
   3777             return false;  /* Nop */
   3778 
   3779         /* These ones we potentially JIT inline. */
   3780 
   3781         case INLINE_STRING_CHARAT:
   3782             return genInlinedStringCharAt(cUnit, mir);
   3783         case INLINE_STRING_LENGTH:
   3784             return genInlinedStringLength(cUnit, mir);
   3785         case INLINE_STRING_IS_EMPTY:
   3786             return genInlinedStringIsEmpty(cUnit, mir);
   3787         case INLINE_STRING_COMPARETO:
   3788             return genInlinedCompareTo(cUnit, mir);
   3789         case INLINE_STRING_FASTINDEXOF_II:
   3790             return genInlinedFastIndexOf(cUnit, mir);
   3791 
   3792         case INLINE_MATH_ABS_INT:
   3793         case INLINE_STRICT_MATH_ABS_INT:
   3794             return genInlinedAbsInt(cUnit, mir);
   3795         case INLINE_MATH_ABS_LONG:
   3796         case INLINE_STRICT_MATH_ABS_LONG:
   3797             return genInlinedAbsLong(cUnit, mir);
   3798         case INLINE_MATH_MIN_INT:
   3799         case INLINE_STRICT_MATH_MIN_INT:
   3800             return genInlinedMinMaxInt(cUnit, mir, true);
   3801         case INLINE_MATH_MAX_INT:
   3802         case INLINE_STRICT_MATH_MAX_INT:
   3803             return genInlinedMinMaxInt(cUnit, mir, false);
   3804         case INLINE_MATH_SQRT:
   3805         case INLINE_STRICT_MATH_SQRT:
   3806             return genInlineSqrt(cUnit, mir);
   3807         case INLINE_MATH_ABS_FLOAT:
   3808         case INLINE_STRICT_MATH_ABS_FLOAT:
   3809             return genInlinedAbsFloat(cUnit, mir);
   3810         case INLINE_MATH_ABS_DOUBLE:
   3811         case INLINE_STRICT_MATH_ABS_DOUBLE:
   3812             return genInlinedAbsDouble(cUnit, mir);
   3813 
   3814         case INLINE_FLOAT_TO_RAW_INT_BITS:
   3815         case INLINE_INT_BITS_TO_FLOAT:
   3816             return genInlinedIntFloatConversion(cUnit, mir);
   3817         case INLINE_DOUBLE_TO_RAW_LONG_BITS:
   3818         case INLINE_LONG_BITS_TO_DOUBLE:
   3819             return genInlinedLongDoubleConversion(cUnit, mir);
   3820 
   3821         /*
   3822          * These ones we just JIT a call to a C function for.
   3823          * TODO: special-case these in the other "invoke" call paths.
   3824          */
   3825         case INLINE_STRING_EQUALS:
   3826         case INLINE_MATH_COS:
   3827         case INLINE_MATH_SIN:
   3828         case INLINE_FLOAT_TO_INT_BITS:
   3829         case INLINE_DOUBLE_TO_LONG_BITS:
   3830             return handleExecuteInlineC(cUnit, mir);
   3831     }
   3832     dvmCompilerAbort(cUnit);
   3833     return false; // Not reachable; keeps compiler happy.
   3834 }
   3835 
   3836 static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
   3837 {
   3838     //TUNING: We're using core regs here - not optimal when target is a double
   3839     RegLocation rlDest = dvmCompilerGetDestWide(cUnit, mir, 0, 1);
   3840     RegLocation rlResult = dvmCompilerEvalLoc(cUnit, rlDest, kCoreReg, true);
   3841     loadConstantNoClobber(cUnit, rlResult.lowReg,
   3842                           mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
   3843     loadConstantNoClobber(cUnit, rlResult.highReg,
   3844                           (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
   3845     storeValueWide(cUnit, rlDest, rlResult);
   3846     return false;
   3847 }
   3848 
   3849 /*
   3850  * The following are special processing routines that handle transfer of
   3851  * controls between compiled code and the interpreter. Certain VM states like
   3852  * Dalvik PC and special-purpose registers are reconstructed here.
   3853  */
   3854 
   3855 /* Chaining cell for code that may need warmup. */
   3856 static void handleNormalChainingCell(CompilationUnit *cUnit,
   3857                                      unsigned int offset)
   3858 {
   3859     newLIR3(cUnit, kMipsLw, r_A0,
   3860         offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal),
   3861         rSELF);
   3862     newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
   3863     addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
   3864 }
   3865 
   3866 /*
   3867  * Chaining cell for instructions that immediately following already translated
   3868  * code.
   3869  */
   3870 static void handleHotChainingCell(CompilationUnit *cUnit,
   3871                                   unsigned int offset)
   3872 {
   3873     newLIR3(cUnit, kMipsLw, r_A0,
   3874         offsetof(Thread, jitToInterpEntries.dvmJitToInterpTraceSelect),
   3875         rSELF);
   3876     newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
   3877     addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
   3878 }
   3879 
   3880 /* Chaining cell for branches that branch back into the same basic block */
   3881 static void handleBackwardBranchChainingCell(CompilationUnit *cUnit,
   3882                                              unsigned int offset)
   3883 {
   3884     /*
   3885      * Use raw instruction constructors to guarantee that the generated
   3886      * instructions fit the predefined cell size.
   3887      */
   3888 #if defined(WITH_SELF_VERIFICATION)
   3889     newLIR3(cUnit, kMipsLw, r_A0,
   3890         offsetof(Thread, jitToInterpEntries.dvmJitToInterpBackwardBranch),
   3891         rSELF);
   3892 #else
   3893     newLIR3(cUnit, kMipsLw, r_A0,
   3894         offsetof(Thread, jitToInterpEntries.dvmJitToInterpNormal),
   3895         rSELF);
   3896 #endif
   3897     newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
   3898     addWordData(cUnit, NULL, (int) (cUnit->method->insns + offset));
   3899 }
   3900 
   3901 /* Chaining cell for monomorphic method invocations. */
   3902 static void handleInvokeSingletonChainingCell(CompilationUnit *cUnit,
   3903                                               const Method *callee)
   3904 {
   3905     newLIR3(cUnit, kMipsLw, r_A0,
   3906         offsetof(Thread, jitToInterpEntries.dvmJitToInterpTraceSelect),
   3907         rSELF);
   3908     newLIR2(cUnit, kMipsJalr, r_RA, r_A0);
   3909     addWordData(cUnit, NULL, (int) (callee->insns));
   3910 }
   3911 
   3912 /* Chaining cell for monomorphic method invocations. */
   3913 static void handleInvokePredictedChainingCell(CompilationUnit *cUnit)
   3914 {
   3915     /* Should not be executed in the initial state */
   3916     addWordData(cUnit, NULL, PREDICTED_CHAIN_BX_PAIR_INIT);
   3917     /* branch delay slot nop */
   3918     addWordData(cUnit, NULL, PREDICTED_CHAIN_DELAY_SLOT_INIT);
   3919     /* To be filled: class */
   3920     addWordData(cUnit, NULL, PREDICTED_CHAIN_CLAZZ_INIT);
   3921     /* To be filled: method */
   3922     addWordData(cUnit, NULL, PREDICTED_CHAIN_METHOD_INIT);
   3923     /*
   3924      * Rechain count. The initial value of 0 here will trigger chaining upon
   3925      * the first invocation of this callsite.
   3926      */
   3927     addWordData(cUnit, NULL, PREDICTED_CHAIN_COUNTER_INIT);
   3928 }
   3929 
   3930 /* Load the Dalvik PC into a0 and jump to the specified target */
   3931 static void handlePCReconstruction(CompilationUnit *cUnit,
   3932                                    MipsLIR *targetLabel)
   3933 {
   3934     MipsLIR **pcrLabel =
   3935         (MipsLIR **) cUnit->pcReconstructionList.elemList;
   3936     int numElems = cUnit->pcReconstructionList.numUsed;
   3937     int i;
   3938 
   3939     /*
   3940      * We should never reach here through fall-through code, so insert
   3941      * a bomb to signal troubles immediately.
   3942      */
   3943     if (numElems) {
   3944         newLIR0(cUnit, kMipsUndefined);
   3945     }
   3946 
   3947     for (i = 0; i < numElems; i++) {
   3948         dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
   3949         /* a0 = dalvik PC */
   3950         loadConstant(cUnit, r_A0, pcrLabel[i]->operands[0]);
   3951         genUnconditionalBranch(cUnit, targetLabel);
   3952     }
   3953 }
   3954 
   3955 static const char *extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
   3956     "kMirOpPhi",
   3957     "kMirOpNullNRangeUpCheck",
   3958     "kMirOpNullNRangeDownCheck",
   3959     "kMirOpLowerBound",
   3960     "kMirOpPunt",
   3961     "kMirOpCheckInlinePrediction",
   3962 };
   3963 
   3964 /*
   3965  * vA = arrayReg;
   3966  * vB = idxReg;
   3967  * vC = endConditionReg;
   3968  * arg[0] = maxC
   3969  * arg[1] = minC
   3970  * arg[2] = loopBranchConditionCode
   3971  */
   3972 static void genHoistedChecksForCountUpLoop(CompilationUnit *cUnit, MIR *mir)
   3973 {
   3974     /*
   3975      * NOTE: these synthesized blocks don't have ssa names assigned
   3976      * for Dalvik registers.  However, because they dominate the following
   3977      * blocks we can simply use the Dalvik name w/ subscript 0 as the
   3978      * ssa name.
   3979      */
   3980     DecodedInstruction *dInsn = &mir->dalvikInsn;
   3981     const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
   3982     const int maxC = dInsn->arg[0];
   3983     int regLength;
   3984     RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
   3985     RegLocation rlIdxEnd = cUnit->regLocation[mir->dalvikInsn.vC];
   3986 
   3987     /* regArray <- arrayRef */
   3988     rlArray = loadValue(cUnit, rlArray, kCoreReg);
   3989     rlIdxEnd = loadValue(cUnit, rlIdxEnd, kCoreReg);
   3990     genRegImmCheck(cUnit, kMipsCondEq, rlArray.lowReg, 0, 0,
   3991                    (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
   3992 
   3993     /* regLength <- len(arrayRef) */
   3994     regLength = dvmCompilerAllocTemp(cUnit);
   3995     loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
   3996 
   3997     int delta = maxC;
   3998     /*
   3999      * If the loop end condition is ">=" instead of ">", then the largest value
   4000      * of the index is "endCondition - 1".
   4001      */
   4002     if (dInsn->arg[2] == OP_IF_GE) {
   4003         delta--;
   4004     }
   4005 
   4006     if (delta) {
   4007         int tReg = dvmCompilerAllocTemp(cUnit);
   4008         opRegRegImm(cUnit, kOpAdd, tReg, rlIdxEnd.lowReg, delta);
   4009         rlIdxEnd.lowReg = tReg;
   4010         dvmCompilerFreeTemp(cUnit, tReg);
   4011     }
   4012     /* Punt if "regIdxEnd < len(Array)" is false */
   4013     genRegRegCheck(cUnit, kMipsCondGe, rlIdxEnd.lowReg, regLength, 0,
   4014                    (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
   4015 }
   4016 
   4017 /*
   4018  * vA = arrayReg;
   4019  * vB = idxReg;
   4020  * vC = endConditionReg;
   4021  * arg[0] = maxC
   4022  * arg[1] = minC
   4023  * arg[2] = loopBranchConditionCode
   4024  */
   4025 static void genHoistedChecksForCountDownLoop(CompilationUnit *cUnit, MIR *mir)
   4026 {
   4027     DecodedInstruction *dInsn = &mir->dalvikInsn;
   4028     const int lenOffset = OFFSETOF_MEMBER(ArrayObject, length);
   4029     const int regLength = dvmCompilerAllocTemp(cUnit);
   4030     const int maxC = dInsn->arg[0];
   4031     RegLocation rlArray = cUnit->regLocation[mir->dalvikInsn.vA];
   4032     RegLocation rlIdxInit = cUnit->regLocation[mir->dalvikInsn.vB];
   4033 
   4034     /* regArray <- arrayRef */
   4035     rlArray = loadValue(cUnit, rlArray, kCoreReg);
   4036     rlIdxInit = loadValue(cUnit, rlIdxInit, kCoreReg);
   4037     genRegImmCheck(cUnit, kMipsCondEq, rlArray.lowReg, 0, 0,
   4038                    (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
   4039 
   4040     /* regLength <- len(arrayRef) */
   4041     loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLength);
   4042 
   4043     if (maxC) {
   4044         int tReg = dvmCompilerAllocTemp(cUnit);
   4045         opRegRegImm(cUnit, kOpAdd, tReg, rlIdxInit.lowReg, maxC);
   4046         rlIdxInit.lowReg = tReg;
   4047         dvmCompilerFreeTemp(cUnit, tReg);
   4048     }
   4049 
   4050     /* Punt if "regIdxInit < len(Array)" is false */
   4051     genRegRegCheck(cUnit, kMipsCondGe, rlIdxInit.lowReg, regLength, 0,
   4052                    (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
   4053 }
   4054 
   4055 /*
   4056  * vA = idxReg;
   4057  * vB = minC;
   4058  */
   4059 static void genHoistedLowerBoundCheck(CompilationUnit *cUnit, MIR *mir)
   4060 {
   4061     DecodedInstruction *dInsn = &mir->dalvikInsn;
   4062     const int minC = dInsn->vB;
   4063     RegLocation rlIdx = cUnit->regLocation[mir->dalvikInsn.vA];
   4064 
   4065     /* regIdx <- initial index value */
   4066     rlIdx = loadValue(cUnit, rlIdx, kCoreReg);
   4067 
   4068     /* Punt if "regIdxInit + minC >= 0" is false */
   4069     genRegImmCheck(cUnit, kMipsCondLt, rlIdx.lowReg, -minC, 0,
   4070                    (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
   4071 }
   4072 
   4073 /*
   4074  * vC = this
   4075  *
   4076  * A predicted inlining target looks like the following, where instructions
   4077  * between 0x2f130d24 and 0x2f130d40 are checking if the predicted class
   4078  * matches "this", and the verificaion code is generated by this routine.
   4079  *
   4080  * (C) means the instruction is inlined from the callee, and (PI) means the
   4081  * instruction is the predicted inlined invoke, whose corresponding
   4082  * instructions are still generated to handle the mispredicted case.
   4083  *
   4084  * D/dalvikvm( 2377): -------- kMirOpCheckInlinePrediction
   4085  * D/dalvikvm( 2377): 0x2f130d24 (0020):  lw       v0,16(s1)
   4086  * D/dalvikvm( 2377): 0x2f130d28 (0024):  lui      v1,0x0011(17)
   4087  * D/dalvikvm( 2377): 0x2f130d2c (0028):  ori      v1,v1,0x11e418(1172504)
   4088  * D/dalvikvm( 2377): 0x2f130d30 (002c):  beqz     v0,0x2f130df0 (L0x11f1f0)
   4089  * D/dalvikvm( 2377): 0x2f130d34 (0030):  pref     0,0(v0)
   4090  * D/dalvikvm( 2377): 0x2f130d38 (0034):  lw       a0,0(v0)
   4091  * D/dalvikvm( 2377): 0x2f130d3c (0038):  bne      v1,a0,0x2f130d54 (L0x11f518)
   4092  * D/dalvikvm( 2377): 0x2f130d40 (003c):  pref     0,8(v0)
   4093  * D/dalvikvm( 2377): -------- dalvik offset: 0x000a @ +iget-object-quick (C) v3, v4, (#8)
   4094  * D/dalvikvm( 2377): 0x2f130d44 (0040):  lw       a1,8(v0)
   4095  * D/dalvikvm( 2377): -------- dalvik offset: 0x000a @ +invoke-virtual-quick (PI) v4
   4096  * D/dalvikvm( 2377): 0x2f130d48 (0044):  sw       a1,12(s1)
   4097  * D/dalvikvm( 2377): 0x2f130d4c (0048):  b        0x2f130e18 (L0x120150)
   4098  * D/dalvikvm( 2377): 0x2f130d50 (004c):  lw       a0,116(s2)
   4099  * D/dalvikvm( 2377): L0x11f518:
   4100  * D/dalvikvm( 2377): 0x2f130d54 (0050):  lw       a0,16(s1)
   4101  * D/dalvikvm( 2377): 0x2f130d58 (0054):  addiu    s4,s1,0xffffffe8(-24)
   4102  * D/dalvikvm( 2377): 0x2f130d5c (0058):  beqz     a0,0x2f130e00 (L0x11f618)
   4103  * D/dalvikvm( 2377): 0x2f130d60 (005c):  pref     1,0(s4)
   4104  * D/dalvikvm( 2377): -------- BARRIER
   4105  * D/dalvikvm( 2377): 0x2f130d64 (0060):  sw       a0,0(s4)
   4106  * D/dalvikvm( 2377): 0x2f130d68 (0064):  addiu    s4,s4,0x0004(4)
   4107  * D/dalvikvm( 2377): -------- BARRIER
   4108  * D/dalvikvm( 2377): 0x2f130d6c (0068):  lui      s0,0x2d22(11554)
   4109  * D/dalvikvm( 2377): 0x2f130d70 (006c):  ori      s0,s0,0x2d228464(757236836)
   4110  * D/dalvikvm( 2377): 0x2f130d74 (0070):  lahi/lui a1,0x2f13(12051)
   4111  * D/dalvikvm( 2377): 0x2f130d78 (0074):  lalo/ori a1,a1,0x2f130ddc(789777884)
   4112  * D/dalvikvm( 2377): 0x2f130d7c (0078):  lahi/lui a2,0x2f13(12051)
   4113  * D/dalvikvm( 2377): 0x2f130d80 (007c):  lalo/ori a2,a2,0x2f130e24(789777956)
   4114  * D/dalvikvm( 2377): 0x2f130d84 (0080):  jal      0x2f12d1ec(789762540)
   4115  * D/dalvikvm( 2377): 0x2f130d88 (0084):  nop
   4116  * D/dalvikvm( 2377): 0x2f130d8c (0088):  b        0x2f130e24 (L0x11ed6c)
   4117  * D/dalvikvm( 2377): 0x2f130d90 (008c):  nop
   4118  * D/dalvikvm( 2377): 0x2f130d94 (0090):  b        0x2f130e04 (L0x11ffd0)
   4119  * D/dalvikvm( 2377): 0x2f130d98 (0094):  lui      a0,0x2d22(11554)
   4120  * D/dalvikvm( 2377): 0x2f130d9c (0098):  lw       a0,44(s4)
   4121  * D/dalvikvm( 2377): 0x2f130da0 (009c):  bgtz     a1,0x2f130dc4 (L0x11fb98)
   4122  * D/dalvikvm( 2377): 0x2f130da4 (00a0):  nop
   4123  * D/dalvikvm( 2377): 0x2f130da8 (00a4):  lui      t9,0x2aba(10938)
   4124  * D/dalvikvm( 2377): 0x2f130dac (00a8):  ori      t9,t9,0x2abae3f8(716891128)
   4125  * D/dalvikvm( 2377): 0x2f130db0 (00ac):  move     a1,s2
   4126  * D/dalvikvm( 2377): 0x2f130db4 (00b0):  jalr     ra,t9
   4127  * D/dalvikvm( 2377): 0x2f130db8 (00b4):  nop
   4128  * D/dalvikvm( 2377): 0x2f130dbc (00b8):  lw       gp,84(sp)
   4129  * D/dalvikvm( 2377): 0x2f130dc0 (00bc):  move     a0,v0
   4130  * D/dalvikvm( 2377): 0x2f130dc4 (00c0):  lahi/lui a1,0x2f13(12051)
   4131  * D/dalvikvm( 2377): 0x2f130dc8 (00c4):  lalo/ori a1,a1,0x2f130ddc(789777884)
   4132  * D/dalvikvm( 2377): 0x2f130dcc (00c8):  jal      0x2f12d0c4(789762244)
   4133  * D/dalvikvm( 2377): 0x2f130dd0 (00cc):  nop
   4134  * D/dalvikvm( 2377): 0x2f130dd4 (00d0):  b        0x2f130e04 (L0x11ffd0)
   4135  * D/dalvikvm( 2377): 0x2f130dd8 (00d4):  lui      a0,0x2d22(11554)
   4136  * D/dalvikvm( 2377): 0x2f130ddc (00d8): .align4
   4137  * D/dalvikvm( 2377): L0x11ed2c:
   4138  * D/dalvikvm( 2377): -------- dalvik offset: 0x000d @ move-result-object (PI) v3, (#0), (#0)
   4139  * D/dalvikvm( 2377): 0x2f130ddc (00d8):  lw       a2,16(s2)
   4140  * D/dalvikvm( 2377): 0x2f130de0 (00dc):  sw       a2,12(s1)
   4141  * D/dalvikvm( 2377): 0x2f130de4 (00e0):  b        0x2f130e18 (L0x120150)
   4142  * D/dalvikvm( 2377): 0x2f130de8 (00e4):  lw       a0,116(s2)
   4143  * D/dalvikvm( 2377): 0x2f130dec (00e8):  undefined
   4144  * D/dalvikvm( 2377): L0x11f1f0:
   4145  * D/dalvikvm( 2377): -------- reconstruct dalvik PC : 0x2d228464 @ +0x000a
   4146  * D/dalvikvm( 2377): 0x2f130df0 (00ec):  lui      a0,0x2d22(11554)
   4147  * D/dalvikvm( 2377): 0x2f130df4 (00f0):  ori      a0,a0,0x2d228464(757236836)
   4148  * D/dalvikvm( 2377): 0x2f130df8 (00f4):  b        0x2f130e0c (L0x120090)
   4149  * D/dalvikvm( 2377): 0x2f130dfc (00f8):  lw       a1,108(s2)
   4150  * D/dalvikvm( 2377): L0x11f618:
   4151  * D/dalvikvm( 2377): -------- reconstruct dalvik PC : 0x2d228464 @ +0x000a
   4152  * D/dalvikvm( 2377): 0x2f130e00 (00fc):  lui      a0,0x2d22(11554)
   4153  * D/dalvikvm( 2377): 0x2f130e04 (0100):  ori      a0,a0,0x2d228464(757236836)
   4154  * D/dalvikvm( 2377): Exception_Handling:
   4155  * D/dalvikvm( 2377): 0x2f130e08 (0104):  lw       a1,108(s2)
   4156  * D/dalvikvm( 2377): 0x2f130e0c (0108):  jalr     ra,a1
   4157  * D/dalvikvm( 2377): 0x2f130e10 (010c):  nop
   4158  * D/dalvikvm( 2377): 0x2f130e14 (0110): .align4
   4159  * D/dalvikvm( 2377): L0x11edac:
   4160  * D/dalvikvm( 2377): -------- chaining cell (hot): 0x000e
   4161  * D/dalvikvm( 2377): 0x2f130e14 (0110):  lw       a0,116(s2)
   4162  * D/dalvikvm( 2377): 0x2f130e18 (0114):  jalr     ra,a0
   4163  * D/dalvikvm( 2377): 0x2f130e1c (0118):  nop
   4164  * D/dalvikvm( 2377): 0x2f130e20 (011c):  data     0x2d22846c(757236844)
   4165  * D/dalvikvm( 2377): 0x2f130e24 (0120): .align4
   4166  * D/dalvikvm( 2377): L0x11ed6c:
   4167  * D/dalvikvm( 2377): -------- chaining cell (predicted)
   4168  * D/dalvikvm( 2377): 0x2f130e24 (0120):  data     0xe7fe(59390)
   4169  * D/dalvikvm( 2377): 0x2f130e28 (0124):  data     0x0000(0)
   4170  * D/dalvikvm( 2377): 0x2f130e2c (0128):  data     0x0000(0)
   4171  * D/dalvikvm( 2377): 0x2f130e30 (012c):  data     0x0000(0)
   4172  * D/dalvikvm( 2377): 0x2f130e34 (0130):  data     0x0000(0)
   4173  */
   4174 static void genValidationForPredictedInline(CompilationUnit *cUnit, MIR *mir)
   4175 {
   4176     CallsiteInfo *callsiteInfo = mir->meta.callsiteInfo;
   4177     RegLocation rlThis = cUnit->regLocation[mir->dalvikInsn.vC];
   4178 
   4179     rlThis = loadValue(cUnit, rlThis, kCoreReg);
   4180     int regPredictedClass = dvmCompilerAllocTemp(cUnit);
   4181     loadClassPointer(cUnit, regPredictedClass, (int) callsiteInfo);
   4182     genNullCheck(cUnit, rlThis.sRegLow, rlThis.lowReg, mir->offset,
   4183                  NULL);/* null object? */
   4184     int regActualClass = dvmCompilerAllocTemp(cUnit);
   4185     loadWordDisp(cUnit, rlThis.lowReg, offsetof(Object, clazz), regActualClass);
   4186 //    opRegReg(cUnit, kOpCmp, regPredictedClass, regActualClass);
   4187     /*
   4188      * Set the misPredBranchOver target so that it will be generated when the
   4189      * code for the non-optimized invoke is generated.
   4190      */
   4191     callsiteInfo->misPredBranchOver = (LIR *) opCompareBranch(cUnit, kMipsBne, regPredictedClass, regActualClass);
   4192 }
   4193 
   4194 /* Extended MIR instructions like PHI */
   4195 static void handleExtendedMIR(CompilationUnit *cUnit, MIR *mir)
   4196 {
   4197     int opOffset = mir->dalvikInsn.opcode - kMirOpFirst;
   4198     char *msg = (char *)dvmCompilerNew(strlen(extendedMIROpNames[opOffset]) + 1,
   4199                                        false);
   4200     strcpy(msg, extendedMIROpNames[opOffset]);
   4201     newLIR1(cUnit, kMipsPseudoExtended, (int) msg);
   4202 
   4203     switch ((ExtendedMIROpcode)mir->dalvikInsn.opcode) {
   4204         case kMirOpPhi: {
   4205             char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
   4206             newLIR1(cUnit, kMipsPseudoSSARep, (int) ssaString);
   4207             break;
   4208         }
   4209         case kMirOpNullNRangeUpCheck: {
   4210             genHoistedChecksForCountUpLoop(cUnit, mir);
   4211             break;
   4212         }
   4213         case kMirOpNullNRangeDownCheck: {
   4214             genHoistedChecksForCountDownLoop(cUnit, mir);
   4215             break;
   4216         }
   4217         case kMirOpLowerBound: {
   4218             genHoistedLowerBoundCheck(cUnit, mir);
   4219             break;
   4220         }
   4221         case kMirOpPunt: {
   4222             genUnconditionalBranch(cUnit,
   4223                                    (MipsLIR *) cUnit->loopAnalysis->branchToPCR);
   4224             break;
   4225         }
   4226         case kMirOpCheckInlinePrediction: {
   4227             genValidationForPredictedInline(cUnit, mir);
   4228             break;
   4229         }
   4230         default:
   4231             break;
   4232     }
   4233 }
   4234 
   4235 /*
   4236  * Create a PC-reconstruction cell for the starting offset of this trace.
   4237  * Since the PCR cell is placed near the end of the compiled code which is
   4238  * usually out of range for a conditional branch, we put two branches (one
   4239  * branch over to the loop body and one layover branch to the actual PCR) at the
   4240  * end of the entry block.
   4241  */
   4242 static void setupLoopEntryBlock(CompilationUnit *cUnit, BasicBlock *entry,
   4243                                 MipsLIR *bodyLabel)
   4244 {
   4245     /* Set up the place holder to reconstruct this Dalvik PC */
   4246     MipsLIR *pcrLabel = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
   4247     pcrLabel->opcode = kMipsPseudoPCReconstructionCell;
   4248     pcrLabel->operands[0] =
   4249         (int) (cUnit->method->insns + entry->startOffset);
   4250     pcrLabel->operands[1] = entry->startOffset;
   4251     /* Insert the place holder to the growable list */
   4252     dvmInsertGrowableList(&cUnit->pcReconstructionList, (intptr_t) pcrLabel);
   4253 
   4254     /*
   4255      * Next, create two branches - one branch over to the loop body and the
   4256      * other branch to the PCR cell to punt.
   4257      */
   4258     MipsLIR *branchToBody = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
   4259     branchToBody->opcode = kMipsB;
   4260     branchToBody->generic.target = (LIR *) bodyLabel;
   4261     setupResourceMasks(branchToBody);
   4262     cUnit->loopAnalysis->branchToBody = (LIR *) branchToBody;
   4263 
   4264     MipsLIR *branchToPCR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
   4265     branchToPCR->opcode = kMipsB;
   4266     branchToPCR->generic.target = (LIR *) pcrLabel;
   4267     setupResourceMasks(branchToPCR);
   4268     cUnit->loopAnalysis->branchToPCR = (LIR *) branchToPCR;
   4269 }
   4270 
   4271 #if defined(WITH_SELF_VERIFICATION)
   4272 static bool selfVerificationPuntOps(MIR *mir)
   4273 {
   4274 assert(0); /* MIPSTODO port selfVerificationPuntOps() */
   4275     DecodedInstruction *decInsn = &mir->dalvikInsn;
   4276 
   4277     /*
   4278      * All opcodes that can throw exceptions and use the
   4279      * TEMPLATE_THROW_EXCEPTION_COMMON template should be excluded in the trace
   4280      * under self-verification mode.
   4281      */
   4282     switch (decInsn->opcode) {
   4283         case OP_MONITOR_ENTER:
   4284         case OP_MONITOR_EXIT:
   4285         case OP_NEW_INSTANCE:
   4286         case OP_NEW_ARRAY:
   4287         case OP_CHECK_CAST:
   4288         case OP_MOVE_EXCEPTION:
   4289         case OP_FILL_ARRAY_DATA:
   4290         case OP_EXECUTE_INLINE:
   4291         case OP_EXECUTE_INLINE_RANGE:
   4292             return true;
   4293         default:
   4294             return false;
   4295     }
   4296 }
   4297 #endif
   4298 
   4299 void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
   4300 {
   4301     /* Used to hold the labels of each block */
   4302     MipsLIR *labelList =
   4303         (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR) * cUnit->numBlocks, true);
   4304     MipsLIR *headLIR = NULL;
   4305     GrowableList chainingListByType[kChainingCellGap];
   4306     int i;
   4307 
   4308     /*
   4309      * Initialize various types chaining lists.
   4310      */
   4311     for (i = 0; i < kChainingCellGap; i++) {
   4312         dvmInitGrowableList(&chainingListByType[i], 2);
   4313     }
   4314 
   4315     /* Clear the visited flag for each block */
   4316     dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerClearVisitedFlag,
   4317                                           kAllNodes, false /* isIterative */);
   4318 
   4319     GrowableListIterator iterator;
   4320     dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
   4321 
   4322     /* Traces start with a profiling entry point.  Generate it here */
   4323     cUnit->profileCodeSize = genTraceProfileEntry(cUnit);
   4324 
   4325     /* Handle the content in each basic block */
   4326     for (i = 0; ; i++) {
   4327         MIR *mir;
   4328         BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
   4329         if (bb == NULL) break;
   4330         if (bb->visited == true) continue;
   4331 
   4332         labelList[i].operands[0] = bb->startOffset;
   4333 
   4334         if (bb->blockType >= kChainingCellGap) {
   4335             if (bb->isFallThroughFromInvoke == true) {
   4336                 /* Align this block first since it is a return chaining cell */
   4337                 newLIR0(cUnit, kMipsPseudoPseudoAlign4);
   4338             }
   4339             /*
   4340              * Append the label pseudo LIR first. Chaining cells will be handled
   4341              * separately afterwards.
   4342              */
   4343             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
   4344         }
   4345 
   4346         if (bb->blockType == kEntryBlock) {
   4347             labelList[i].opcode = kMipsPseudoEntryBlock;
   4348             if (bb->firstMIRInsn == NULL) {
   4349                 continue;
   4350             } else {
   4351               setupLoopEntryBlock(cUnit, bb,
   4352                                   &labelList[bb->fallThrough->id]);
   4353             }
   4354         } else if (bb->blockType == kExitBlock) {
   4355             labelList[i].opcode = kMipsPseudoExitBlock;
   4356             goto gen_fallthrough;
   4357         } else if (bb->blockType == kDalvikByteCode) {
   4358             if (bb->hidden == true) continue;
   4359             labelList[i].opcode = kMipsPseudoNormalBlockLabel;
   4360             /* Reset the register state */
   4361             dvmCompilerResetRegPool(cUnit);
   4362             dvmCompilerClobberAllRegs(cUnit);
   4363             dvmCompilerResetNullCheck(cUnit);
   4364         } else {
   4365             switch (bb->blockType) {
   4366                 case kChainingCellNormal:
   4367                     labelList[i].opcode = kMipsPseudoChainingCellNormal;
   4368                     /* handle the codegen later */
   4369                     dvmInsertGrowableList(
   4370                         &chainingListByType[kChainingCellNormal], i);
   4371                     break;
   4372                 case kChainingCellInvokeSingleton:
   4373                     labelList[i].opcode =
   4374                         kMipsPseudoChainingCellInvokeSingleton;
   4375                     labelList[i].operands[0] =
   4376                         (int) bb->containingMethod;
   4377                     /* handle the codegen later */
   4378                     dvmInsertGrowableList(
   4379                         &chainingListByType[kChainingCellInvokeSingleton], i);
   4380                     break;
   4381                 case kChainingCellInvokePredicted:
   4382                     labelList[i].opcode =
   4383                         kMipsPseudoChainingCellInvokePredicted;
   4384                     /*
   4385                      * Move the cached method pointer from operand 1 to 0.
   4386                      * Operand 0 was clobbered earlier in this routine to store
   4387                      * the block starting offset, which is not applicable to
   4388                      * predicted chaining cell.
   4389                      */
   4390                     labelList[i].operands[0] = labelList[i].operands[1];
   4391                     /* handle the codegen later */
   4392                     dvmInsertGrowableList(
   4393                         &chainingListByType[kChainingCellInvokePredicted], i);
   4394                     break;
   4395                 case kChainingCellHot:
   4396                     labelList[i].opcode =
   4397                         kMipsPseudoChainingCellHot;
   4398                     /* handle the codegen later */
   4399                     dvmInsertGrowableList(
   4400                         &chainingListByType[kChainingCellHot], i);
   4401                     break;
   4402                 case kPCReconstruction:
   4403                     /* Make sure exception handling block is next */
   4404                     labelList[i].opcode =
   4405                         kMipsPseudoPCReconstructionBlockLabel;
   4406                     handlePCReconstruction(cUnit,
   4407                                            &labelList[cUnit->puntBlock->id]);
   4408                     break;
   4409                 case kExceptionHandling:
   4410                     labelList[i].opcode = kMipsPseudoEHBlockLabel;
   4411                     if (cUnit->pcReconstructionList.numUsed) {
   4412                         loadWordDisp(cUnit, rSELF, offsetof(Thread,
   4413                                      jitToInterpEntries.dvmJitToInterpPunt),
   4414                                      r_A1);
   4415                         opReg(cUnit, kOpBlx, r_A1);
   4416                     }
   4417                     break;
   4418                 case kChainingCellBackwardBranch:
   4419                     labelList[i].opcode =
   4420                         kMipsPseudoChainingCellBackwardBranch;
   4421                     /* handle the codegen later */
   4422                     dvmInsertGrowableList(
   4423                         &chainingListByType[kChainingCellBackwardBranch],
   4424                         i);
   4425                     break;
   4426                 default:
   4427                     break;
   4428             }
   4429             continue;
   4430         }
   4431 
   4432         /*
   4433          * Try to build a longer optimization unit. Currently if the previous
   4434          * block ends with a goto, we continue adding instructions and don't
   4435          * reset the register allocation pool.
   4436          */
   4437         for (BasicBlock *nextBB = bb; nextBB != NULL; nextBB = cUnit->nextCodegenBlock) {
   4438             bb = nextBB;
   4439             bb->visited = true;
   4440             cUnit->nextCodegenBlock = NULL;
   4441 
   4442             for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
   4443 
   4444                 dvmCompilerResetRegPool(cUnit);
   4445                 if (gDvmJit.disableOpt & (1 << kTrackLiveTemps)) {
   4446                     dvmCompilerClobberAllRegs(cUnit);
   4447                 }
   4448 
   4449                 if (gDvmJit.disableOpt & (1 << kSuppressLoads)) {
   4450                     dvmCompilerResetDefTracking(cUnit);
   4451                 }
   4452 
   4453                 if ((int)mir->dalvikInsn.opcode >= (int)kMirOpFirst) {
   4454                     handleExtendedMIR(cUnit, mir);
   4455                     continue;
   4456                 }
   4457 
   4458                 Opcode dalvikOpcode = mir->dalvikInsn.opcode;
   4459                 InstructionFormat dalvikFormat =
   4460                     dexGetFormatFromOpcode(dalvikOpcode);
   4461                 const char *note;
   4462                 if (mir->OptimizationFlags & MIR_INLINED) {
   4463                     note = " (I)";
   4464                 } else if (mir->OptimizationFlags & MIR_INLINED_PRED) {
   4465                     note = " (PI)";
   4466                 } else if (mir->OptimizationFlags & MIR_CALLEE) {
   4467                     note = " (C)";
   4468                 } else {
   4469                     note = NULL;
   4470                 }
   4471 
   4472                 MipsLIR *boundaryLIR =
   4473                     newLIR2(cUnit, kMipsPseudoDalvikByteCodeBoundary,
   4474                             mir->offset,
   4475                             (int) dvmCompilerGetDalvikDisassembly(&mir->dalvikInsn,
   4476                                                                   note));
   4477                 if (mir->ssaRep) {
   4478                     char *ssaString = dvmCompilerGetSSAString(cUnit, mir->ssaRep);
   4479                     newLIR1(cUnit, kMipsPseudoSSARep, (int) ssaString);
   4480                 }
   4481 
   4482                 /* Remember the first LIR for this block */
   4483                 if (headLIR == NULL) {
   4484                     headLIR = boundaryLIR;
   4485                     /* Set the first boundaryLIR as a scheduling barrier */
   4486                     headLIR->defMask = ENCODE_ALL;
   4487                 }
   4488 
   4489                 bool notHandled;
   4490                 /*
   4491                  * Debugging: screen the opcode first to see if it is in the
   4492                  * do[-not]-compile list
   4493                  */
   4494                 bool singleStepMe = SINGLE_STEP_OP(dalvikOpcode);
   4495 #if defined(WITH_SELF_VERIFICATION)
   4496               if (singleStepMe == false) {
   4497                   singleStepMe = selfVerificationPuntOps(mir);
   4498               }
   4499 #endif
   4500                 if (singleStepMe || cUnit->allSingleStep) {
   4501                     notHandled = false;
   4502                     genInterpSingleStep(cUnit, mir);
   4503                 } else {
   4504                     opcodeCoverage[dalvikOpcode]++;
   4505                     switch (dalvikFormat) {
   4506                         case kFmt10t:
   4507                         case kFmt20t:
   4508                         case kFmt30t:
   4509                             notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
   4510                                       mir, bb, labelList);
   4511                             break;
   4512                         case kFmt10x:
   4513                             notHandled = handleFmt10x(cUnit, mir);
   4514                             break;
   4515                         case kFmt11n:
   4516                         case kFmt31i:
   4517                             notHandled = handleFmt11n_Fmt31i(cUnit, mir);
   4518                             break;
   4519                         case kFmt11x:
   4520                             notHandled = handleFmt11x(cUnit, mir);
   4521                             break;
   4522                         case kFmt12x:
   4523                             notHandled = handleFmt12x(cUnit, mir);
   4524                             break;
   4525                         case kFmt20bc:
   4526                             notHandled = handleFmt20bc(cUnit, mir);
   4527                             break;
   4528                         case kFmt21c:
   4529                         case kFmt31c:
   4530                             notHandled = handleFmt21c_Fmt31c(cUnit, mir);
   4531                             break;
   4532                         case kFmt21h:
   4533                             notHandled = handleFmt21h(cUnit, mir);
   4534                             break;
   4535                         case kFmt21s:
   4536                             notHandled = handleFmt21s(cUnit, mir);
   4537                             break;
   4538                         case kFmt21t:
   4539                             notHandled = handleFmt21t(cUnit, mir, bb,
   4540                                                       labelList);
   4541                             break;
   4542                         case kFmt22b:
   4543                         case kFmt22s:
   4544                             notHandled = handleFmt22b_Fmt22s(cUnit, mir);
   4545                             break;
   4546                         case kFmt22c:
   4547                             notHandled = handleFmt22c(cUnit, mir);
   4548                             break;
   4549                         case kFmt22cs:
   4550                             notHandled = handleFmt22cs(cUnit, mir);
   4551                             break;
   4552                         case kFmt22t:
   4553                             notHandled = handleFmt22t(cUnit, mir, bb,
   4554                                                       labelList);
   4555                             break;
   4556                         case kFmt22x:
   4557                         case kFmt32x:
   4558                             notHandled = handleFmt22x_Fmt32x(cUnit, mir);
   4559                             break;
   4560                         case kFmt23x:
   4561                             notHandled = handleFmt23x(cUnit, mir);
   4562                             break;
   4563                         case kFmt31t:
   4564                             notHandled = handleFmt31t(cUnit, mir);
   4565                             break;
   4566                         case kFmt3rc:
   4567                         case kFmt35c:
   4568                             notHandled = handleFmt35c_3rc(cUnit, mir, bb,
   4569                                                           labelList);
   4570                             break;
   4571                         case kFmt3rms:
   4572                         case kFmt35ms:
   4573                             notHandled = handleFmt35ms_3rms(cUnit, mir,bb,
   4574                                                             labelList);
   4575                             break;
   4576                         case kFmt35mi:
   4577                         case kFmt3rmi:
   4578                             notHandled = handleExecuteInline(cUnit, mir);
   4579                             break;
   4580                         case kFmt51l:
   4581                             notHandled = handleFmt51l(cUnit, mir);
   4582                             break;
   4583                         default:
   4584                             notHandled = true;
   4585                             break;
   4586                     }
   4587                 }
   4588                 if (notHandled) {
   4589                     ALOGE("%#06x: Opcode %#x (%s) / Fmt %d not handled",
   4590                          mir->offset,
   4591                          dalvikOpcode, dexGetOpcodeName(dalvikOpcode),
   4592                          dalvikFormat);
   4593                     dvmCompilerAbort(cUnit);
   4594                     break;
   4595                 }
   4596             }
   4597         }
   4598 
   4599         if (bb->blockType == kEntryBlock) {
   4600             dvmCompilerAppendLIR(cUnit,
   4601                                  (LIR *) cUnit->loopAnalysis->branchToBody);
   4602             dvmCompilerAppendLIR(cUnit,
   4603                                  (LIR *) cUnit->loopAnalysis->branchToPCR);
   4604         }
   4605 
   4606         if (headLIR) {
   4607             /*
   4608              * Eliminate redundant loads/stores and delay stores into later
   4609              * slots
   4610              */
   4611             dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
   4612                                                cUnit->lastLIRInsn);
   4613             /* Reset headLIR which is also the optimization boundary */
   4614             headLIR = NULL;
   4615         }
   4616 
   4617 gen_fallthrough:
   4618         /*
   4619          * Check if the block is terminated due to trace length constraint -
   4620          * insert an unconditional branch to the chaining cell.
   4621          */
   4622         if (bb->needFallThroughBranch) {
   4623             genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
   4624         }
   4625     }
   4626 
   4627     /* Handle the chaining cells in predefined order */
   4628     for (i = 0; i < kChainingCellGap; i++) {
   4629         size_t j;
   4630         int *blockIdList = (int *) chainingListByType[i].elemList;
   4631 
   4632         cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
   4633 
   4634         /* No chaining cells of this type */
   4635         if (cUnit->numChainingCells[i] == 0)
   4636             continue;
   4637 
   4638         /* Record the first LIR for a new type of chaining cell */
   4639         cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
   4640 
   4641         for (j = 0; j < chainingListByType[i].numUsed; j++) {
   4642             int blockId = blockIdList[j];
   4643             BasicBlock *chainingBlock =
   4644                 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
   4645                                                          blockId);
   4646 
   4647             /* Align this chaining cell first */
   4648             newLIR0(cUnit, kMipsPseudoPseudoAlign4);
   4649 
   4650             /* Insert the pseudo chaining instruction */
   4651             dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
   4652 
   4653 
   4654             switch (chainingBlock->blockType) {
   4655                 case kChainingCellNormal:
   4656                     handleNormalChainingCell(cUnit, chainingBlock->startOffset);
   4657                     break;
   4658                 case kChainingCellInvokeSingleton:
   4659                     handleInvokeSingletonChainingCell(cUnit,
   4660                         chainingBlock->containingMethod);
   4661                     break;
   4662                 case kChainingCellInvokePredicted:
   4663                     handleInvokePredictedChainingCell(cUnit);
   4664                     break;
   4665                 case kChainingCellHot:
   4666                     handleHotChainingCell(cUnit, chainingBlock->startOffset);
   4667                     break;
   4668                 case kChainingCellBackwardBranch:
   4669                     handleBackwardBranchChainingCell(cUnit,
   4670                         chainingBlock->startOffset);
   4671                     break;
   4672                 default:
   4673                     ALOGE("Bad blocktype %d", chainingBlock->blockType);
   4674                     dvmCompilerAbort(cUnit);
   4675             }
   4676         }
   4677     }
   4678 
   4679     /* Mark the bottom of chaining cells */
   4680     cUnit->chainingCellBottom = (LIR *) newLIR0(cUnit, kMipsChainingCellBottom);
   4681 
   4682     /*
   4683      * Generate the branch to the dvmJitToInterpNoChain entry point at the end
   4684      * of all chaining cells for the overflow cases.
   4685      */
   4686     if (cUnit->switchOverflowPad) {
   4687         loadConstant(cUnit, r_A0, (int) cUnit->switchOverflowPad);
   4688         loadWordDisp(cUnit, rSELF, offsetof(Thread,
   4689                      jitToInterpEntries.dvmJitToInterpNoChain), r_A2);
   4690         opRegReg(cUnit, kOpAdd, r_A1, r_A1);
   4691         opRegRegReg(cUnit, kOpAdd, r4PC, r_A0, r_A1);
   4692 #if defined(WITH_JIT_TUNING)
   4693         loadConstant(cUnit, r_A0, kSwitchOverflow);
   4694 #endif
   4695         opReg(cUnit, kOpBlx, r_A2);
   4696     }
   4697 
   4698     dvmCompilerApplyGlobalOptimizations(cUnit);
   4699 
   4700 #if defined(WITH_SELF_VERIFICATION)
   4701     selfVerificationBranchInsertPass(cUnit);
   4702 #endif
   4703 }
   4704 
   4705 /*
   4706  * Accept the work and start compiling.  Returns true if compilation
   4707  * is attempted.
   4708  */
   4709 bool dvmCompilerDoWork(CompilerWorkOrder *work)
   4710 {
   4711     JitTraceDescription *desc;
   4712     bool isCompile;
   4713     bool success = true;
   4714 
   4715     if (gDvmJit.codeCacheFull) {
   4716         return false;
   4717     }
   4718 
   4719     switch (work->kind) {
   4720         case kWorkOrderTrace:
   4721             isCompile = true;
   4722             /* Start compilation with maximally allowed trace length */
   4723             desc = (JitTraceDescription *)work->info;
   4724             success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
   4725                                         work->bailPtr, 0 /* no hints */);
   4726             break;
   4727         case kWorkOrderTraceDebug: {
   4728             bool oldPrintMe = gDvmJit.printMe;
   4729             gDvmJit.printMe = true;
   4730             isCompile = true;
   4731             /* Start compilation with maximally allowed trace length */
   4732             desc = (JitTraceDescription *)work->info;
   4733             success = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result,
   4734                                         work->bailPtr, 0 /* no hints */);
   4735             gDvmJit.printMe = oldPrintMe;
   4736             break;
   4737         }
   4738         case kWorkOrderProfileMode:
   4739             dvmJitChangeProfileMode((TraceProfilingModes)(int)work->info);
   4740             isCompile = false;
   4741             break;
   4742         default:
   4743             isCompile = false;
   4744             ALOGE("Jit: unknown work order type");
   4745             assert(0);  // Bail if debug build, discard otherwise
   4746     }
   4747     if (!success)
   4748         work->result.codeAddress = NULL;
   4749     return isCompile;
   4750 }
   4751 
   4752 /* Architectural-specific debugging helpers go here */
   4753 void dvmCompilerArchDump(void)
   4754 {
   4755     /* Print compiled opcode in this VM instance */
   4756     int i, start, streak;
   4757     char buf[1024];
   4758 
   4759     streak = i = 0;
   4760     buf[0] = 0;
   4761     while (opcodeCoverage[i] == 0 && i < 256) {
   4762         i++;
   4763     }
   4764     if (i == 256) {
   4765         return;
   4766     }
   4767     for (start = i++, streak = 1; i < 256; i++) {
   4768         if (opcodeCoverage[i]) {
   4769             streak++;
   4770         } else {
   4771             if (streak == 1) {
   4772                 sprintf(buf+strlen(buf), "%x,", start);
   4773             } else {
   4774                 sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
   4775             }
   4776             streak = 0;
   4777             while (opcodeCoverage[i] == 0 && i < 256) {
   4778                 i++;
   4779             }
   4780             if (i < 256) {
   4781                 streak = 1;
   4782                 start = i;
   4783             }
   4784         }
   4785     }
   4786     if (streak) {
   4787         if (streak == 1) {
   4788             sprintf(buf+strlen(buf), "%x", start);
   4789         } else {
   4790             sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
   4791         }
   4792     }
   4793     if (strlen(buf)) {
   4794         ALOGD("dalvik.vm.jit.op = %s", buf);
   4795     }
   4796 }
   4797 
   4798 /* Common initialization routine for an architecture family */
   4799 bool dvmCompilerArchInit()
   4800 {
   4801     int i;
   4802 
   4803     for (i = 0; i < kMipsLast; i++) {
   4804         if (EncodingMap[i].opcode != i) {
   4805             ALOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
   4806                  EncodingMap[i].name, i, EncodingMap[i].opcode);
   4807             dvmAbort();  // OK to dvmAbort - build error
   4808         }
   4809     }
   4810 
   4811     return dvmCompilerArchVariantInit();
   4812 }
   4813 
   4814 void *dvmCompilerGetInterpretTemplate()
   4815 {
   4816       return (void*) ((int)gDvmJit.codeCache +
   4817                       templateEntryOffsets[TEMPLATE_INTERPRET]);
   4818 }
   4819 
   4820 JitInstructionSetType dvmCompilerGetInterpretTemplateSet()
   4821 {
   4822     return DALVIK_JIT_MIPS;
   4823 }
   4824 
   4825 /* Needed by the Assembler */
   4826 void dvmCompilerSetupResourceMasks(MipsLIR *lir)
   4827 {
   4828     setupResourceMasks(lir);
   4829 }
   4830 
   4831 /* Needed by the ld/st optmizatons */
   4832 MipsLIR* dvmCompilerRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
   4833 {
   4834     return genRegCopyNoInsert(cUnit, rDest, rSrc);
   4835 }
   4836 
   4837 /* Needed by the register allocator */
   4838 MipsLIR* dvmCompilerRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
   4839 {
   4840     return genRegCopy(cUnit, rDest, rSrc);
   4841 }
   4842 
   4843 /* Needed by the register allocator */
   4844 void dvmCompilerRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
   4845                             int srcLo, int srcHi)
   4846 {
   4847     genRegCopyWide(cUnit, destLo, destHi, srcLo, srcHi);
   4848 }
   4849 
   4850 void dvmCompilerFlushRegImpl(CompilationUnit *cUnit, int rBase,
   4851                              int displacement, int rSrc, OpSize size)
   4852 {
   4853     storeBaseDisp(cUnit, rBase, displacement, rSrc, size);
   4854 }
   4855 
   4856 void dvmCompilerFlushRegWideImpl(CompilationUnit *cUnit, int rBase,
   4857                                  int displacement, int rSrcLo, int rSrcHi)
   4858 {
   4859     storeBaseDispWide(cUnit, rBase, displacement, rSrcLo, rSrcHi);
   4860 }
   4861