Home | History | Annotate | Download | only in x86
      1 /*
      2  * Copyright (C) 2012 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 /*! \file LowerInvoke.cpp
     19     \brief This file lowers the following bytecodes: INVOKE_XXX
     20 */
     21 #include "libdex/DexOpcodes.h"
     22 #include "libdex/DexFile.h"
     23 #include "mterp/Mterp.h"
     24 #include "Lower.h"
     25 #include "NcgAot.h"
     26 #include "enc_wrapper.h"
     27 
     28 char* streamMisPred = NULL;
     29 
     30 /* according to callee, decide the ArgsDoneType*/
     31 ArgsDoneType convertCalleeToType(const Method* calleeMethod) {
     32     if(calleeMethod == NULL)
     33         return ArgsDone_Full;
     34     if(dvmIsNativeMethod(calleeMethod))
     35         return ArgsDone_Native;
     36     return ArgsDone_Normal;
     37 }
     38 int common_invokeMethodRange(ArgsDoneType);
     39 int common_invokeMethodNoRange(ArgsDoneType);
     40 void gen_predicted_chain(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg);
     41 
     42 //inputs to common_invokeMethodRange: %ecx
     43 //          common_errNoSuchMethod: %edx
     44 #define P_GPR_1 PhysicalReg_ESI
     45 #define P_GPR_2 PhysicalReg_EBX
     46 #define P_GPR_3 PhysicalReg_ECX
     47 #define P_SCRATCH_1 PhysicalReg_EDX
     48 #define PP_GPR_1 PhysicalReg_EBX
     49 #define PP_GPR_2 PhysicalReg_ESI
     50 #define PP_GPR_3 PhysicalReg_EAX
     51 #define PP_GPR_4 PhysicalReg_EDX
     52 
     53 #ifdef WITH_JIT_INLINING
     54 /*
     55  * The function here takes care the
     56  * branch over if prediction is correct and the misprediction target for misPredBranchOver.
     57  */
     58 static void genLandingPadForMispredictedCallee(MIR* mir) {
     59     BasicBlock *fallThrough = traceCurrentBB->fallThrough;
     60     /* Bypass the move-result block if there is one */
     61     if (fallThrough->firstMIRInsn) {
     62         assert(fallThrough->firstMIRInsn->OptimizationFlags & MIR_INLINED_PRED);
     63         fallThrough = fallThrough->fallThrough;
     64     }
     65     /* Generate a branch over if the predicted inlining is correct */
     66     jumpToBasicBlock(stream, fallThrough->id);
     67     /* Hook up the target to the verification branch */
     68     int relativeNCG = stream - streamMisPred;
     69     unsigned instSize = encoder_get_inst_size(streamMisPred);
     70     relativeNCG -= instSize; //size of the instruction
     71     updateJumpInst(streamMisPred, OpndSize_8, relativeNCG);
     72 }
     73 #endif
     74 
     75 //! LOWER bytecode INVOKE_VIRTUAL without usage of helper function
     76 
     77 //!
     78 int common_invoke_virtual_nohelper(bool isRange, u2 tmp, u2 vD) {
     79 #ifdef WITH_JIT_INLINING
     80     /*
     81      * If the invoke has non-null misPredBranchOver, we need to generate
     82      * the non-inlined version of the invoke here to handle the
     83      * mispredicted case.
     84      */
     85     if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) {
     86         genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList);
     87     }
     88 #endif
     89     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
     90     export_pc();
     91     constVREndOfBB();
     92     beforeCall("exception"); //dump GG, GL VRs
     93 
     94     get_virtual_reg(vD, OpndSize_32, 5, false);
     95     simpleNullCheck(5, false, vD);
     96 #ifndef PREDICTED_CHAINING
     97     move_mem_to_reg(OpndSize_32, offObject_clazz, 5, false, 6, false); //clazz of "this"
     98     move_mem_to_reg(OpndSize_32, offClassObject_vtable, 6, false, 7, false); //vtable
     99     /* method is already resolved in trace-based JIT */
    100     int methodIndex =
    101                 currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex;
    102     move_mem_to_reg(OpndSize_32, methodIndex*4, 7, false, PhysicalReg_ECX, true);
    103     if(isRange) {
    104         common_invokeMethodRange(ArgsDone_Full);
    105     }
    106     else {
    107         common_invokeMethodNoRange(ArgsDone_Full);
    108     }
    109 #else
    110     int methodIndex =
    111                 currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex;
    112     gen_predicted_chain(isRange, tmp, methodIndex*4, false, 5/*tmp5*/);
    113 #endif
    114     ///////////////////////////////////
    115     return 0;
    116 }
    117 //! wrapper to call either common_invoke_virtual_helper or common_invoke_virtual_nohelper
    118 
    119 //!
    120 int common_invoke_virtual(bool isRange, u2 tmp, u2 vD) {
    121     return common_invoke_virtual_nohelper(isRange, tmp, vD);
    122 }
    123 #undef P_GPR_1
    124 #undef P_GPR_2
    125 #undef P_GPR_3
    126 #undef P_SCRATCH_1
    127 #undef PP_GPR_1
    128 #undef PP_GPR_2
    129 #undef PP_GPR_3
    130 #undef PP_GPR_4
    131 
    132 #define P_GPR_1 PhysicalReg_ESI
    133 #define P_GPR_2 PhysicalReg_EBX
    134 #define P_GPR_3 PhysicalReg_EDX
    135 #define PP_GPR_1 PhysicalReg_EBX
    136 #define PP_GPR_2 PhysicalReg_ESI
    137 #define PP_GPR_3 PhysicalReg_EAX
    138 #define PP_GPR_4 PhysicalReg_EDX
    139 //! common section to lower INVOKE_SUPER
    140 
    141 //! It will use helper function if the switch is on
    142 int common_invoke_super(bool isRange, u2 tmp) {
    143     export_pc();
    144     constVREndOfBB();
    145     beforeCall("exception"); //dump GG, GL VRs
    146     ///////////////////////
    147     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
    148     /* method is already resolved in trace-based JIT */
    149     int mIndex = currentMethod->clazz->pDvmDex->pResMethods[tmp]->methodIndex;
    150     const Method *calleeMethod =
    151         currentMethod->clazz->super->vtable[mIndex];
    152     move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
    153     if(isRange) {
    154         common_invokeMethodRange(convertCalleeToType(calleeMethod));
    155     }
    156     else {
    157         common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
    158     }
    159     ///////////////////////////////
    160     return 0;
    161 }
    162 #undef PP_GPR_1
    163 #undef PP_GPR_2
    164 #undef PP_GPR_3
    165 #undef PP_GPR_4
    166 
    167 //! helper function to handle no such method error
    168 
    169 //!
    170 int invoke_super_nsm() {
    171     insertLabel(".invoke_super_nsm", false);
    172     //NOTE: it seems that the name in %edx is not used in common_errNoSuchMethod
    173     move_mem_to_reg(OpndSize_32, offMethod_name, PhysicalReg_EAX, true, PhysicalReg_EDX, true); //method name
    174     unconditional_jump("common_errNoSuchMethod", false);
    175     return 0;
    176 }
    177 #undef P_GPR_1
    178 #undef P_GPR_2
    179 #undef P_GPR_3
    180 
    181 #define P_GPR_1 PhysicalReg_EBX
    182 #define P_GPR_2 PhysicalReg_ESI
    183 #define P_GPR_3 PhysicalReg_ECX
    184 #define PP_GPR_1 PhysicalReg_EBX
    185 #define PP_GPR_2 PhysicalReg_ESI
    186 #define PP_GPR_3 PhysicalReg_EAX
    187 #define PP_GPR_4 PhysicalReg_EDX
    188 //! common section to lower INVOKE_DIRECT
    189 
    190 //! It will use helper function if the switch is on
    191 int common_invoke_direct(bool isRange, u2 tmp, u2 vD) {
    192     //%ecx can be used as scratch when calling export_pc, get_res_methods and resolve_method
    193     export_pc();
    194     constVREndOfBB();
    195     beforeCall("exception"); //dump GG, GL VRs
    196     ////////////////////////////////////
    197     get_virtual_reg(vD, OpndSize_32, 5, false);
    198     simpleNullCheck(5, false, vD);
    199     /* method is already resolved in trace-based JIT */
    200     const Method *calleeMethod =
    201         currentMethod->clazz->pDvmDex->pResMethods[tmp];
    202     move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
    203     //%ecx passed to common_invokeMethod...
    204     if(isRange) {
    205         common_invokeMethodRange(convertCalleeToType(calleeMethod));
    206     }
    207     else {
    208         common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
    209     }
    210     ////////////////////////////
    211     return 0;
    212 }
    213 #undef P_GPR_1
    214 #undef P_GPR_2
    215 #undef P_GPR_3
    216 #undef PP_GPR_1
    217 #undef PP_GPR_2
    218 #undef PP_GPR_3
    219 #undef PP_GPR_4
    220 
    221 #define P_GPR_1  PhysicalReg_EBX
    222 #define P_GPR_3  PhysicalReg_ECX
    223 #define PP_GPR_1 PhysicalReg_EBX
    224 #define PP_GPR_2 PhysicalReg_ESI
    225 #define PP_GPR_3 PhysicalReg_EAX
    226 #define PP_GPR_4 PhysicalReg_EDX
    227 //! common section to lower INVOKE_STATIC
    228 
    229 //! It will use helper function if the switch is on
    230 int common_invoke_static(bool isRange, u2 tmp) {
    231     //%ecx can be used as scratch when calling export_pc, get_res_methods and resolve_method
    232     export_pc();
    233     constVREndOfBB();
    234     beforeCall("exception"); //dump GG, GL VRs
    235     ////////////////////////////
    236     /* method is already resolved in trace-based JIT */
    237     const Method *calleeMethod =
    238         currentMethod->clazz->pDvmDex->pResMethods[tmp];
    239     move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
    240     //%ecx passed to common_invokeMethod...
    241     if(isRange) {
    242         common_invokeMethodRange(convertCalleeToType(calleeMethod));
    243     }
    244     else {
    245         common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
    246     }
    247     ////////////////////////
    248     return 0;
    249 }
    250 #undef P_GPR_1
    251 #undef PP_GPR_1
    252 #undef PP_GPR_2
    253 #undef PP_GPR_3
    254 #undef PP_GPR_4
    255 
    256 #define P_GPR_1 PhysicalReg_EBX
    257 #define P_GPR_2 PhysicalReg_EAX //scratch
    258 #define P_GPR_3 PhysicalReg_ECX
    259 #define P_SCRATCH_1 PhysicalReg_ESI //clazz of object
    260 #define PP_GPR_1 PhysicalReg_EBX
    261 #define PP_GPR_2 PhysicalReg_ESI
    262 #define PP_GPR_3 PhysicalReg_EAX
    263 #define PP_GPR_4 PhysicalReg_EDX
    264 //! common section to lower INVOKE_INTERFACE
    265 
    266 //! It will use helper function if the switch is on
    267 int common_invoke_interface(bool isRange, u2 tmp, u2 vD) {
    268 #ifdef WITH_JIT_INLINING
    269     /*
    270      * If the invoke has non-null misPredBranchOver, we need to generate
    271      * the non-inlined version of the invoke here to handle the
    272      * mispredicted case.
    273      */
    274     if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) {
    275         genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList);
    276     }
    277 #endif
    278     export_pc(); //use %edx
    279     constVREndOfBB();
    280     beforeCall("exception"); //dump GG, GL VRs
    281     ///////////////////////
    282     scratchRegs[2] = PhysicalReg_Null; scratchRegs[3] = PhysicalReg_Null;
    283     get_virtual_reg(vD, OpndSize_32, 1, false);
    284     simpleNullCheck(1, false, vD);
    285 
    286 #ifndef PREDICTED_CHAINING
    287     load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    288     move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true);
    289     /* for trace-based JIT, pDvmDex is a constant at JIT time
    290        4th argument to dvmFindInterfaceMethodInCache at -4(%esp) */
    291     move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true);
    292     move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 5, false);
    293     /* for trace-based JIT, method is a constant at JIT time
    294        3rd argument to dvmFindInterfaceMethodInCache at 8(%esp) */
    295     move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true);
    296     move_reg_to_mem(OpndSize_32, 5, false, 0, PhysicalReg_ESP, true);
    297     scratchRegs[0] = PhysicalReg_SCRATCH_3; scratchRegs[1] = PhysicalReg_Null;
    298     call_dvmFindInterfaceMethodInCache();
    299     load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    300     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
    301 
    302     conditional_jump_global_API(Condition_E, "common_exceptionThrown", false);
    303     move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
    304     if(isRange) {
    305         common_invokeMethodRange(ArgsDone_Full);
    306     }
    307     else {
    308         common_invokeMethodNoRange(ArgsDone_Full);
    309     }
    310 #else
    311     gen_predicted_chain(isRange, tmp, -1, true /*interface*/, 1/*tmp1*/);
    312 #endif
    313     ///////////////////////
    314     return 0;
    315 }
    316 #undef PP_GPR_1
    317 #undef PP_GPR_2
    318 #undef PP_GPR_3
    319 #undef PP_GPR_4
    320 #undef P_GPR_1
    321 #undef P_GPR_2
    322 #undef P_GPR_3
    323 #undef P_SCRATCH_1
    324 //! lower bytecode INVOKE_VIRTUAL by calling common_invoke_virtual
    325 
    326 //!
    327 int op_invoke_virtual() {
    328 #ifdef WITH_JIT_INLINING
    329     /* An invoke with the MIR_INLINED is effectively a no-op */
    330     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    331         return false;
    332 #endif
    333     //B|A|op CCCC G|F|E|D
    334     //D: the first argument, which is the "this" pointer
    335     //B: argument count
    336     //D,E,F,G,A: arguments
    337     u2 vD = FETCH(2) & 0xf;
    338     u2 tmp = FETCH(1); //method index
    339     int retval = common_invoke_virtual(false/*not range*/, tmp, vD);
    340 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    341     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    342 #endif
    343     rPC += 3;
    344     return retval;
    345 }
    346 //! lower bytecode INVOKE_SUPER by calling common_invoke_super
    347 
    348 //!
    349 int op_invoke_super() {
    350 #ifdef WITH_JIT_INLINING
    351     /* An invoke with the MIR_INLINED is effectively a no-op */
    352     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    353         return false;
    354 #endif
    355     //B|A|op CCCC G|F|E|D
    356     //D: the first argument
    357     //B: argument count
    358     //D,E,F,G,A: arguments
    359     u2 tmp = FETCH(1); //method index
    360     int retval = common_invoke_super(false/*not range*/, tmp);
    361 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    362     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    363 #endif
    364     rPC += 3;
    365     return retval;
    366 }
    367 //! lower bytecode INVOKE_DIRECT by calling common_invoke_direct
    368 
    369 //!
    370 int op_invoke_direct() {
    371 #ifdef WITH_JIT_INLINING
    372     /* An invoke with the MIR_INLINED is effectively a no-op */
    373     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    374         return false;
    375 #endif
    376     //B|A|op CCCC G|F|E|D
    377     //D: the first argument, which is the "this" pointer
    378     //B: argument count
    379     //D,E,F,G,A: arguments
    380     u2 vD = FETCH(2) & 0xf;
    381     u2 tmp = FETCH(1); //method index
    382     int retval = common_invoke_direct(false/*not range*/, tmp, vD);
    383 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    384     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    385 #endif
    386     rPC += 3;
    387     return retval;
    388 }
    389 //! lower bytecode INVOKE_STATIC by calling common_invoke_static
    390 
    391 //!
    392 int op_invoke_static() {
    393 #ifdef WITH_JIT_INLINING
    394     /* An invoke with the MIR_INLINED is effectively a no-op */
    395     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    396         return false;
    397 #endif
    398     //B|A|op CCCC G|F|E|D
    399     //D: the first argument
    400     //B: argument count
    401     //D,E,F,G,A: arguments
    402     u2 tmp = FETCH(1); //method index
    403     int retval = common_invoke_static(false/*not range*/, tmp);
    404 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    405     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    406 #endif
    407     rPC += 3;
    408     return retval;
    409 }
    410 //! lower bytecode INVOKE_INTERFACE by calling common_invoke_interface
    411 
    412 //!
    413 int op_invoke_interface() {
    414 #ifdef WITH_JIT_INLINING
    415     /* An invoke with the MIR_INLINED is effectively a no-op */
    416     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    417         return false;
    418 #endif
    419     //B|A|op CCCC G|F|E|D
    420     //D: the first argument, which is the "this" pointer
    421     //B: argument count
    422     //D,E,F,G,A: arguments
    423     u2 vD = FETCH(2) & 0xf;
    424     u2 tmp = FETCH(1); //method index
    425     int retval = common_invoke_interface(false/*not range*/, tmp, vD);
    426 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    427     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    428 #endif
    429     rPC += 3;
    430     return retval;
    431 }
    432 //! lower bytecode INVOKE_VIRTUAL_RANGE by calling common_invoke_virtual
    433 
    434 //!
    435 int op_invoke_virtual_range() {
    436 #ifdef WITH_JIT_INLINING
    437     /* An invoke with the MIR_INLINED is effectively a no-op */
    438     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    439         return false;
    440 #endif
    441     //AA|op BBBB CCCC
    442     //CCCC: the first argument, which is the "this" pointer
    443     //AA: argument count
    444     u2 tmp = FETCH(1); //BBBB, method index
    445     u2 vD = FETCH(2); //the first argument
    446     int retval = common_invoke_virtual(true/*range*/, tmp, vD);
    447 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    448     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    449 #endif
    450     rPC += 3;
    451     return retval;
    452 }
    453 //! lower bytecode INVOKE_SUPER_RANGE by calling common_invoke_super
    454 
    455 //!
    456 int op_invoke_super_range() {
    457 #ifdef WITH_JIT_INLINING
    458     /* An invoke with the MIR_INLINED is effectively a no-op */
    459     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    460         return false;
    461 #endif
    462     u2 tmp = FETCH(1); //BBBB, method index
    463     int retval = common_invoke_super(true/*range*/, tmp);
    464 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    465     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    466 #endif
    467     rPC += 3;
    468     return retval;
    469 }
    470 //! lower bytecode INVOKE_DIRECT_RANGE by calling common_invoke_direct
    471 
    472 //!
    473 int op_invoke_direct_range() {
    474 #ifdef WITH_JIT_INLINING
    475     /* An invoke with the MIR_INLINED is effectively a no-op */
    476     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    477         return false;
    478 #endif
    479     u2 tmp = FETCH(1); //BBBB, method index
    480     u2 vD = FETCH(2); //the first argument
    481     int retval = common_invoke_direct(true/*range*/, tmp, vD);
    482 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    483     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    484 #endif
    485     rPC += 3;
    486     return retval;
    487 }
    488 //! lower bytecode INVOKE_STATIC_RANGE by calling common_invoke_static
    489 
    490 //!
    491 int op_invoke_static_range() {
    492 #ifdef WITH_JIT_INLINING
    493     /* An invoke with the MIR_INLINED is effectively a no-op */
    494     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    495         return false;
    496 #endif
    497     u2 tmp = FETCH(1); //BBBB, method index
    498     int retval = common_invoke_static(true/*range*/, tmp);
    499 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    500     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    501 #endif
    502     rPC += 3;
    503     return retval;
    504 }
    505 //! lower bytecode INVOKE_INTERFACE_RANGE by calling common_invoke_interface
    506 
    507 //!
    508 int op_invoke_interface_range() {
    509 #ifdef WITH_JIT_INLINING
    510     /* An invoke with the MIR_INLINED is effectively a no-op */
    511     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
    512         return false;
    513 #endif
    514     u2 tmp = FETCH(1); //BBBB, method index
    515     u2 vD = FETCH(2); //the first argument
    516     int retval = common_invoke_interface(true/*range*/, tmp, vD);
    517 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
    518     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
    519 #endif
    520     rPC += 3;
    521     return retval;
    522 }
    523 
    524 //used %ecx, %edi, %esp %ebp
    525 #define P_GPR_1 PhysicalReg_EBX
    526 #define P_SCRATCH_1 PhysicalReg_ESI
    527 #define P_SCRATCH_2 PhysicalReg_EAX
    528 #define P_SCRATCH_3 PhysicalReg_EDX
    529 #define P_SCRATCH_4 PhysicalReg_ESI
    530 #define P_SCRATCH_5 PhysicalReg_EAX
    531 //! pass the arguments for invoking method without range
    532 
    533 //!
    534 int common_invokeMethodNoRange_noJmp() {
    535     u2 count = INST_B(inst);
    536     u2 vD = FETCH(2) & 0xf;
    537     u2 vE = (FETCH(2) >> 4) & 0xf;
    538     u2 vF = (FETCH(2) >> 8) & 0xf;
    539     u2 vG = (FETCH(2) >> 12) & 0xf;
    540     u2 vA = INST_A(inst); //5th argument
    541     int offsetFromSaveArea = -4;
    542     if(count == 5) {
    543         get_virtual_reg(vA, OpndSize_32, 22, false);
    544         move_reg_to_mem(OpndSize_32, 22, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
    545         offsetFromSaveArea -= 4;
    546     }
    547     if(count >= 4) {
    548         get_virtual_reg(vG, OpndSize_32, 23, false);
    549         move_reg_to_mem(OpndSize_32, 23, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
    550         offsetFromSaveArea -= 4;
    551     }
    552     if(count >= 3) {
    553         get_virtual_reg(vF, OpndSize_32, 24, false);
    554         move_reg_to_mem(OpndSize_32, 24, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
    555         offsetFromSaveArea -= 4;
    556     }
    557     if(count >= 2) {
    558         get_virtual_reg(vE, OpndSize_32, 25, false);
    559         move_reg_to_mem(OpndSize_32, 25, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
    560         offsetFromSaveArea -= 4;
    561     }
    562     if(count >= 1) {
    563         get_virtual_reg(vD, OpndSize_32, 26, false);
    564         move_reg_to_mem(OpndSize_32, 26, false, offsetFromSaveArea-sizeofStackSaveArea, PhysicalReg_FP, true);
    565     }
    566     return 0;
    567 }
    568 
    569 int common_invokeMethod_Jmp(ArgsDoneType form) {
    570     nextVersionOfHardReg(PhysicalReg_EDX, 1);
    571     move_imm_to_reg(OpndSize_32, (int)rPC, PhysicalReg_EDX, true);
    572     //arguments needed in ArgsDone:
    573     //    start of HotChainingCell for next bytecode: -4(%esp)
    574     //    start of InvokeSingletonChainingCell for callee: -8(%esp)
    575     load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    576     insertChainingWorklist(traceCurrentBB->fallThrough->id, stream);
    577     move_chain_to_mem(OpndSize_32, traceCurrentBB->fallThrough->id, 4, PhysicalReg_ESP, true);
    578     // for honeycomb: JNI call doesn't need a chaining cell, so the taken branch is null
    579     if(traceCurrentBB->taken)
    580         insertChainingWorklist(traceCurrentBB->taken->id, stream);
    581     int takenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0;
    582     move_chain_to_mem(OpndSize_32, takenId, 0, PhysicalReg_ESP, true);
    583     if(form == ArgsDone_Full)
    584         unconditional_jump_global_API(".invokeArgsDone_jit", false);
    585     else if(form == ArgsDone_Native)
    586         unconditional_jump_global_API(".invokeArgsDone_native", false);
    587     else
    588         unconditional_jump_global_API(".invokeArgsDone_normal", false);
    589     return 0;
    590 }
    591 
    592 int common_invokeMethodNoRange(ArgsDoneType form) {
    593     common_invokeMethodNoRange_noJmp();
    594     common_invokeMethod_Jmp(form);
    595     return 0;
    596 }
    597 
    598 #undef P_GPR_1
    599 #undef P_SCRATCH_1
    600 #undef P_SCRATCH_2
    601 #undef P_SCRATCH_3
    602 #undef P_SCRATCH_4
    603 #undef P_SCRATCH_5
    604 
    605 //input: %ecx (method to call)
    606 #define P_GPR_1 PhysicalReg_EBX
    607 #define P_GPR_2 PhysicalReg_ESI
    608 #define P_GPR_3 PhysicalReg_EDX //not used with P_SCRATCH_2
    609 #define P_SCRATCH_1 PhysicalReg_EAX
    610 #define P_SCRATCH_2 PhysicalReg_EDX
    611 #define P_SCRATCH_3 PhysicalReg_EAX
    612 #define P_SCRATCH_4 PhysicalReg_EDX
    613 #define P_SCRATCH_5 PhysicalReg_EAX
    614 #define P_SCRATCH_6 PhysicalReg_EDX
    615 #define P_SCRATCH_7 PhysicalReg_EAX
    616 #define P_SCRATCH_8 PhysicalReg_EDX
    617 #define P_SCRATCH_9 PhysicalReg_EAX
    618 #define P_SCRATCH_10 PhysicalReg_EDX
    619 //! pass the arguments for invoking method with range
    620 
    621 //! loop is unrolled when count <= 10
    622 int common_invokeMethodRange_noJmp() {
    623     u2 count = INST_AA(inst);
    624     u2 vD = FETCH(2); //the first argument
    625     savearea_from_fp(21, false);
    626     //vD to rFP-4*count-20
    627     //vD+1 to rFP-4*count-20+4 = rFP-20-4*(count-1)
    628     if(count >= 1 && count <= 10) {
    629         get_virtual_reg(vD, OpndSize_32, 22, false);
    630         move_reg_to_mem(OpndSize_32, 22, false, -4*count, 21, false);
    631     }
    632     if(count >= 2 && count <= 10) {
    633         get_virtual_reg(vD+1, OpndSize_32, 23, false);
    634         move_reg_to_mem(OpndSize_32, 23, false, -4*(count-1), 21, false);
    635     }
    636     if(count >= 3 && count <= 10) {
    637         get_virtual_reg(vD+2, OpndSize_32, 24, false);
    638         move_reg_to_mem(OpndSize_32, 24, false, -4*(count-2), 21, false);
    639     }
    640     if(count >= 4 && count <= 10) {
    641         get_virtual_reg(vD+3, OpndSize_32, 25, false);
    642         move_reg_to_mem(OpndSize_32, 25, false, -4*(count-3), 21, false);
    643     }
    644     if(count >= 5 && count <= 10) {
    645         get_virtual_reg(vD+4, OpndSize_32, 26, false);
    646         move_reg_to_mem(OpndSize_32, 26, false, -4*(count-4), 21, false);
    647     }
    648     if(count >= 6 && count <= 10) {
    649         get_virtual_reg(vD+5, OpndSize_32, 27, false);
    650         move_reg_to_mem(OpndSize_32, 27, false, -4*(count-5), 21, false);
    651     }
    652     if(count >= 7 && count <= 10) {
    653         get_virtual_reg(vD+6, OpndSize_32, 28, false);
    654         move_reg_to_mem(OpndSize_32, 28, false, -4*(count-6), 21, false);
    655     }
    656     if(count >= 8 && count <= 10) {
    657         get_virtual_reg(vD+7, OpndSize_32, 29, false);
    658         move_reg_to_mem(OpndSize_32, 29, false, -4*(count-7), 21, false);
    659     }
    660     if(count >= 9 && count <= 10) {
    661         get_virtual_reg(vD+8, OpndSize_32, 30, false);
    662         move_reg_to_mem(OpndSize_32, 30, false, -4*(count-8), 21, false);
    663     }
    664     if(count == 10) {
    665         get_virtual_reg(vD+9, OpndSize_32, 31, false);
    666         move_reg_to_mem(OpndSize_32, 31, false, -4*(count-9), 21, false);
    667     }
    668     if(count > 10) {
    669         //dump to memory first, should we set physicalReg to Null?
    670         //this bytecodes uses a set of virtual registers (update getVirtualInfo)
    671         //this is necessary to correctly insert transfer points
    672         int k;
    673         for(k = 0; k < count; k++) {
    674             spillVirtualReg(vD+k, LowOpndRegType_gp, true); //will update refCount
    675         }
    676         load_effective_addr(4*vD, PhysicalReg_FP, true, 12, false);
    677         alu_binary_imm_reg(OpndSize_32, sub_opc, 4*count, 21, false);
    678         move_imm_to_reg(OpndSize_32, count, 13, false);
    679         insertLabel(".invokeMethod_1", true); //if checkDup: will perform work from ShortWorklist
    680         rememberState(1);
    681         move_mem_to_reg(OpndSize_32, 0, 12, false, 14, false);
    682         move_reg_to_mem(OpndSize_32, 14, false, 0, 21, false);
    683         load_effective_addr(4, 12, false, 12, false);
    684         alu_binary_imm_reg(OpndSize_32, sub_opc, 1, 13, false);
    685         load_effective_addr(4, 21, false, 21, false);
    686         transferToState(1);
    687         conditional_jump(Condition_NE, ".invokeMethod_1", true); //backward branch
    688     }
    689     return 0;
    690 }
    691 
    692 int common_invokeMethodRange(ArgsDoneType form) {
    693     common_invokeMethodRange_noJmp();
    694     common_invokeMethod_Jmp(form);
    695     return 0;
    696 }
    697 #undef P_GPR_1
    698 #undef P_GPR_2
    699 #undef P_GPR_3
    700 #undef P_SCRATCH_1
    701 #undef P_SCRATCH_2
    702 #undef P_SCRATCH_3
    703 #undef P_SCRATCH_4
    704 #undef P_SCRATCH_5
    705 #undef P_SCRATCH_6
    706 #undef P_SCRATCH_7
    707 #undef P_SCRATCH_8
    708 #undef P_SCRATCH_9
    709 #undef P_SCRATCH_10
    710 
    711 #define P_GPR_1 PhysicalReg_EBX
    712 #define P_GPR_3 PhysicalReg_ESI
    713 #define P_SCRATCH_1 PhysicalReg_EAX
    714 #define P_SCRATCH_2 PhysicalReg_EDX
    715 #define P_SCRATCH_3 PhysicalReg_EAX
    716 #define P_SCRATCH_4 PhysicalReg_EDX
    717 #define P_SCRATCH_5 PhysicalReg_EAX
    718 #define P_SCRATCH_6 PhysicalReg_EDX
    719 
    720 //! spill a register to native stack
    721 
    722 //! decrease %esp by 4, then store a register at 0(%esp)
    723 int spill_reg(int reg, bool isPhysical) {
    724     load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    725     move_reg_to_mem(OpndSize_32, reg, isPhysical, 0, PhysicalReg_ESP, true);
    726     return 0;
    727 }
    728 //! get a register from native stack
    729 
    730 //! load a register from 0(%esp), then increase %esp by 4
    731 int unspill_reg(int reg, bool isPhysical) {
    732     move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, reg, isPhysical);
    733     load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    734     return 0;
    735 }
    736 
    737 void generate_invokeNative(bool generateForNcg); //forward declaration
    738 void generate_stackOverflow(); //forward declaration
    739 
    740 //! common code to invoke a method after all arguments are handled
    741 
    742 //!
    743 //takes one argument to generate code
    744 //  for invokeNativeSingle (form == ArgsDone_Native)
    745 //   or invokeNonNativeSingle (form == ArgsDone_Normal) when WITH_JIT is true
    746 //   to dynamically determine which one to choose (form == ArgsDone_Full)
    747 /* common_invokeArgsDone is called at NCG time and
    748      at execution time during relocation
    749    generate invokeArgsDone for NCG if isJitFull is false && form == Full */
    750 int common_invokeArgsDone(ArgsDoneType form, bool isJitFull) {
    751     bool generateForNcg = false;
    752     if(form == ArgsDone_Full) {
    753         if(isJitFull)
    754             insertLabel(".invokeArgsDone_jit", false);
    755         else {
    756             insertLabel(".invokeArgsDone", false);
    757             generateForNcg = true;
    758         }
    759     }
    760     else if(form == ArgsDone_Normal)
    761         insertLabel(".invokeArgsDone_normal", false);
    762     else if(form == ArgsDone_Native)
    763         insertLabel(".invokeArgsDone_native", false);
    764     //%ecx: methodToCall
    765     movez_mem_to_reg(OpndSize_16, offMethod_registersSize, PhysicalReg_ECX, true, P_SCRATCH_1, true); //regSize
    766     scratchRegs[0] = PhysicalReg_EBX; scratchRegs[1] = PhysicalReg_ESI;
    767     scratchRegs[2] = PhysicalReg_EDX; scratchRegs[3] = PhysicalReg_Null;
    768     savearea_from_fp(P_GPR_3, true);
    769     alu_binary_imm_reg(OpndSize_32, shl_opc, 2, P_SCRATCH_1, true);
    770     alu_binary_reg_reg(OpndSize_32, sub_opc, P_SCRATCH_1, true, P_GPR_3, true);
    771     //update newSaveArea->savedPc, here P_GPR_3 is new FP
    772     move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true, offStackSaveArea_savedPc-sizeofStackSaveArea, P_GPR_3, true);
    773     movez_mem_to_reg(OpndSize_16, offMethod_outsSize, PhysicalReg_ECX, true, P_SCRATCH_2, true); //outsSize
    774     move_reg_to_reg(OpndSize_32, P_GPR_3, true, P_GPR_1, true); //new FP
    775     alu_binary_imm_reg(OpndSize_32, sub_opc, sizeofStackSaveArea, P_GPR_3, true);
    776 
    777     alu_binary_imm_reg(OpndSize_32, shl_opc, 2, P_SCRATCH_2, true);
    778     alu_binary_reg_reg(OpndSize_32, sub_opc, P_SCRATCH_2, true, P_GPR_3, true);
    779     get_self_pointer(P_SCRATCH_3, true);
    780     move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offStackSaveArea_prevFrame-sizeofStackSaveArea, P_GPR_1, true); //set stack->prevFrame
    781     compare_mem_reg(OpndSize_32, offsetof(Thread, interpStackEnd), P_SCRATCH_3, true, P_GPR_3, true);
    782     conditional_jump(Condition_L, ".stackOverflow", true);
    783 
    784     if(form == ArgsDone_Full) {
    785         test_imm_mem(OpndSize_32, ACC_NATIVE, offMethod_accessFlags, PhysicalReg_ECX, true);
    786     }
    787     move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, offStackSaveArea_method-sizeofStackSaveArea, P_GPR_1, true); //set stack->method
    788 
    789     if(form == ArgsDone_Native || form == ArgsDone_Full) {
    790         /* to correctly handle code cache reset:
    791            update returnAddr and check returnAddr after done with the native method
    792            if returnAddr is set to NULL during code cache reset,
    793            the execution will correctly continue with interpreter */
    794         //get returnAddr from 4(%esp) and update stack
    795         move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true,
    796                         PhysicalReg_EDX, true);
    797         move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true,
    798                         offStackSaveArea_returnAddr-sizeofStackSaveArea, P_GPR_1, true);
    799     }
    800     if(form == ArgsDone_Native) {
    801         generate_invokeNative(generateForNcg);
    802         return 0;
    803     }
    804     if(form == ArgsDone_Full) {
    805         conditional_jump(Condition_NE, ".invokeNative", true);
    806     }
    807     move_mem_to_reg(OpndSize_32, offMethod_clazz, PhysicalReg_ECX, true, P_SCRATCH_4, true); //get method->claz
    808     move_mem_to_reg(OpndSize_32, offClassObject_pDvmDex, P_SCRATCH_4, true, P_SCRATCH_4, true); //get method->clazz->pDvmDex
    809     move_reg_to_reg(OpndSize_32, P_GPR_1, true, PhysicalReg_FP, true); //update rFP
    810     get_self_pointer(P_GPR_1, true);
    811     move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, offsetof(Thread, interpSave.method), P_GPR_1, true); //glue->method
    812     move_reg_to_mem(OpndSize_32, P_SCRATCH_4, true, offsetof(Thread, interpSave.methodClassDex), P_GPR_1, true); //set_glue_dvmdex
    813     move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, P_GPR_1, true); //set glue->self->frame
    814     if(!generateForNcg) {
    815         /* returnAddr updated already for Full */
    816         //get returnAddr from 4(%esp) and update stack
    817         if(form == ArgsDone_Normal)
    818             move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true,
    819                             PhysicalReg_EDX, true);
    820         //for JIT: starting bytecode in %ebx to invoke JitToInterp
    821         move_mem_to_reg(OpndSize_32, offMethod_insns, PhysicalReg_ECX, true, PhysicalReg_EBX, true);
    822         if(form == ArgsDone_Normal)
    823             move_reg_to_mem(OpndSize_32, PhysicalReg_EDX, true,
    824                             offStackSaveArea_returnAddr-sizeofStackSaveArea, PhysicalReg_FP, true);
    825     }
    826 
    827     insertLabel(".invokeInterp", true);
    828     if(!generateForNcg) {
    829         bool callNoChain = false;
    830 #ifdef PREDICTED_CHAINING
    831         if(form == ArgsDone_Full) callNoChain = true;
    832 #endif
    833         if(callNoChain) {
    834             scratchRegs[0] = PhysicalReg_EAX;
    835             load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    836 #if defined(WITH_JIT_TUNING)
    837             /* Predicted chaining failed. Fall back to interpreter and indicate
    838              * inline cache miss.
    839              */
    840             move_imm_to_reg(OpndSize_32, kInlineCacheMiss, PhysicalReg_EDX, true);
    841 #endif
    842             call_dvmJitToInterpTraceSelectNoChain(); //input: rPC in %ebx
    843         } else {
    844             //jump to the stub at (%esp)
    845             move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true,
    846                             PhysicalReg_EDX, true);
    847             load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    848             unconditional_jump_reg(PhysicalReg_EDX, true);
    849         }
    850     }
    851 
    852     if(form == ArgsDone_Full) generate_invokeNative(generateForNcg);
    853     generate_stackOverflow();
    854     return 0;
    855 }
    856 
    857 /* when WITH_JIT is true,
    858      JIT'ed code invokes native method, after invoke, execution will continue
    859      with the interpreter or with JIT'ed code if chained
    860 */
    861 void generate_invokeNative(bool generateForNcg) {
    862     insertLabel(".invokeNative", true);
    863     //if(!generateForNcg)
    864     //    load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    865     load_effective_addr(-28, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    866     move_reg_to_mem(OpndSize_32, P_GPR_1, true, 0, PhysicalReg_ESP, true);
    867     move_reg_to_mem(OpndSize_32, P_GPR_1, true, 20, PhysicalReg_ESP, true);
    868     scratchRegs[0] = PhysicalReg_EDX;
    869     get_self_pointer(P_SCRATCH_1, true); //glue->self
    870     move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 8, PhysicalReg_ESP, true);
    871     move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, 12, PhysicalReg_ESP, true);
    872     move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, 24, PhysicalReg_ESP, true);
    873     move_mem_to_reg(OpndSize_32, offThread_jniLocal_nextEntry, P_SCRATCH_1, true, P_SCRATCH_2, true); //get self->local_next
    874     scratchRegs[1] = PhysicalReg_EAX;
    875     move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offStackSaveArea_localRefTop-sizeofStackSaveArea, P_GPR_1, true); //update jniLocalRef of stack
    876     move_reg_to_mem(OpndSize_32, P_GPR_1, true, offThread_curFrame, P_SCRATCH_1, true); //set self->curFrame
    877     move_imm_to_mem(OpndSize_32, 0, offThread_inJitCodeCache, P_SCRATCH_1, true); //clear self->inJitCodeCache
    878     load_effective_addr(offsetof(Thread, interpSave.retval), P_SCRATCH_1, true, P_SCRATCH_3, true); //self->retval
    879     move_reg_to_mem(OpndSize_32, P_SCRATCH_3, true, 4, PhysicalReg_ESP, true);
    880     //NOTE: native method checks the interpreted stack for arguments
    881     //      The immediate arguments on native stack: address of return value, new FP, self
    882     call_mem(40, PhysicalReg_ECX, true);//*40(%ecx)
    883     //we can't assume the argument stack is unmodified after the function call
    884     //duplicate newFP & glue->self on stack: newFP (-28 & -8) glue->self (-16 & -4)
    885     move_mem_to_reg(OpndSize_32, 20, PhysicalReg_ESP, true, P_GPR_3, true); //new FP
    886     move_mem_to_reg(OpndSize_32, 24, PhysicalReg_ESP, true, P_GPR_1, true); //glue->self
    887     load_effective_addr(28, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    888     move_mem_to_reg(OpndSize_32, offStackSaveArea_localRefTop-sizeofStackSaveArea, P_GPR_3, true, P_SCRATCH_1, true); //newSaveArea->jniLocal
    889     compare_imm_mem(OpndSize_32, 0, offThread_exception, P_GPR_1, true); //self->exception
    890     if(!generateForNcg)
    891         load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    892     //NOTE: PhysicalReg_FP should be callee-saved register
    893     move_reg_to_mem(OpndSize_32, PhysicalReg_FP, true, offThread_curFrame, P_GPR_1, true); //set self->curFrame
    894     move_reg_to_mem(OpndSize_32, P_SCRATCH_1, true, offThread_jniLocal_nextEntry, P_GPR_1, true); //set self->jniLocal
    895     conditional_jump(Condition_NE, "common_exceptionThrown", false);
    896     if(!generateForNcg) {
    897         //get returnAddr, if it is not NULL,
    898         //    return to JIT'ed returnAddr after executing the native method
    899         /* to correctly handle code cache reset:
    900            update returnAddr and check returnAddr after done with the native method
    901            if returnAddr is set to NULL during code cache reset,
    902            the execution will correctly continue with interpreter */
    903         move_mem_to_reg(OpndSize_32, offStackSaveArea_returnAddr-sizeofStackSaveArea, P_GPR_3, true, P_SCRATCH_2, true);
    904         //set self->inJitCodeCache to returnAddr (P_GPR_1 is in %ebx)
    905         move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offThread_inJitCodeCache, P_GPR_1, true);
    906         move_mem_to_reg(OpndSize_32, offStackSaveArea_savedPc-sizeofStackSaveArea, P_GPR_3, true, PhysicalReg_EBX, true); //savedPc
    907         compare_imm_reg(OpndSize_32, 0, P_SCRATCH_2, true);
    908         conditional_jump(Condition_E, ".nativeToInterp", true);
    909         unconditional_jump_reg(P_SCRATCH_2, true);
    910         //if returnAddr is NULL, return to interpreter after executing the native method
    911         insertLabel(".nativeToInterp", true);
    912         //move rPC by 6 (3 bytecode units for INVOKE)
    913         alu_binary_imm_reg(OpndSize_32, add_opc, 6, PhysicalReg_EBX, true);
    914         scratchRegs[0] = PhysicalReg_EAX;
    915 #if defined(WITH_JIT_TUNING)
    916         /* Return address not in code cache. Indicate that continuing with interpreter
    917          */
    918         move_imm_to_reg(OpndSize_32, kCallsiteInterpreted, PhysicalReg_EDX, true);
    919 #endif
    920         call_dvmJitToInterpTraceSelectNoChain(); //rPC in %ebx
    921     }
    922     return;
    923 }
    924 void generate_stackOverflow() {
    925     insertLabel(".stackOverflow", true);
    926     //load_effective_addr(-8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    927     move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 4, PhysicalReg_ESP, true);
    928     get_self_pointer(P_GPR_1, true); //glue->self
    929     move_reg_to_mem(OpndSize_32, P_GPR_1, true, 0, PhysicalReg_ESP, true);
    930     call_dvmHandleStackOverflow();
    931     load_effective_addr(8, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
    932     unconditional_jump("common_exceptionThrown", false);
    933 }
    934 #undef P_GPR_1
    935 #undef P_GPR_2
    936 #undef P_GPR_3
    937 #undef P_SCRATCH_1
    938 #undef P_SCRATCH_2
    939 #undef P_SCRATCH_3
    940 #undef P_SCRATCH_4
    941 #undef P_SCRATCH_5
    942 #undef P_SCRATCH_6
    943 
    944 /////////////////////////////////////////////
    945 #define P_GPR_1 PhysicalReg_EBX
    946 #define P_GPR_2 PhysicalReg_ECX
    947 #define P_SCRATCH_1 PhysicalReg_ESI
    948 #define P_SCRATCH_2 PhysicalReg_EDX
    949 #define P_SCRATCH_3 PhysicalReg_ESI
    950 #define P_SCRATCH_4 PhysicalReg_EDX
    951 //! lower bytecode EXECUTE_INLINE
    952 
    953 //!
    954 int op_execute_inline(bool isRange) {
    955     //tmp, vC, vD, vE, vF
    956     int num;
    957     if(!isRange) num = INST_B(inst);
    958     else num = INST_AA(inst);
    959     u2 tmp = FETCH(1);
    960     u2 vC, vD, vE, vF;
    961     if(!isRange) {
    962         vC = FETCH(2) & 0xf;
    963         vD = (FETCH(2) >> 4) & 0xf;
    964         vE = (FETCH(2) >> 8) & 0xf;
    965         vF = FETCH(2) >> 12;
    966     } else {
    967         vC = FETCH(2);
    968         vD = vC + 1;
    969         vE = vC + 2;
    970         vF = vC + 3;
    971     }
    972     export_pc();
    973     switch (tmp) {
    974         case INLINE_EMPTYINLINEMETHOD:
    975             return 0;  /* Nop */
    976         case INLINE_STRING_LENGTH:
    977             get_virtual_reg(vC, OpndSize_32, 1, false);
    978             compare_imm_reg(OpndSize_32, 0, 1, false);
    979             conditional_jump(Condition_NE, ".do_inlined_string_length", true);
    980             scratchRegs[0] = PhysicalReg_SCRATCH_1;
    981             jumpToExceptionThrown(1/*exception number*/);
    982             insertLabel(".do_inlined_string_length", true);
    983             move_mem_to_reg(OpndSize_32, 0x14, 1, false, 2, false);
    984             get_self_pointer(3, false);
    985             move_reg_to_mem(OpndSize_32, 2, false, offsetof(Thread, interpSave.retval), 3, false);
    986             return 0;
    987         case INLINE_STRING_IS_EMPTY:
    988             get_virtual_reg(vC, OpndSize_32, 1, false);
    989             compare_imm_reg(OpndSize_32, 0, 1, false);
    990             conditional_jump(Condition_NE, ".do_inlined_string_length", true);
    991             scratchRegs[0] = PhysicalReg_SCRATCH_1;
    992             jumpToExceptionThrown(1/*exception number*/);
    993             insertLabel(".do_inlined_string_length", true);
    994             compare_imm_mem(OpndSize_32, 0, 0x14, 1, false);
    995             conditional_jump(Condition_E, ".inlined_string_length_return_true",
    996                              true);
    997             get_self_pointer(2, false);
    998             move_imm_to_mem(OpndSize_32, 0, offsetof(Thread, interpSave.retval), 2, false);
    999             unconditional_jump(".inlined_string_length_done", true);
   1000             insertLabel(".inlined_string_length_return_true", true);
   1001             get_self_pointer(2, false);
   1002             move_imm_to_mem(OpndSize_32, 1, offsetof(Thread, interpSave.retval), 2, false);
   1003             insertLabel(".inlined_string_length_done", true);
   1004             return 0;
   1005         case INLINE_MATH_ABS_INT:
   1006             get_virtual_reg(vC, OpndSize_32, 1, false);
   1007             move_reg_to_reg(OpndSize_32, 1, false, 2, false);
   1008             alu_binary_imm_reg(OpndSize_32, sar_opc, 0x1f, 2, false);
   1009             alu_binary_reg_reg(OpndSize_32, xor_opc, 2, false, 1, false);
   1010             alu_binary_reg_reg(OpndSize_32, sub_opc, 2, false, 1, false);
   1011             get_self_pointer(3, false);
   1012             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
   1013             return 0;
   1014         case INLINE_MATH_ABS_LONG:
   1015             get_virtual_reg(vD, OpndSize_32, 1, false);
   1016             move_reg_to_reg(OpndSize_32, 1, false, 2, false);
   1017             alu_binary_imm_reg(OpndSize_32, sar_opc, 0x1f, 1, false);
   1018             move_reg_to_reg(OpndSize_32, 1, false, 3, false);
   1019             move_reg_to_reg(OpndSize_32, 1, false, 4, false);
   1020             get_virtual_reg(vC, OpndSize_32, 5, false);
   1021             alu_binary_reg_reg(OpndSize_32, xor_opc, 5, false, 1, false);
   1022             get_self_pointer(6, false);
   1023             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 6, false);
   1024             alu_binary_reg_reg(OpndSize_32, xor_opc, 2, false, 3, false);
   1025             move_reg_to_mem(OpndSize_32, 3, false, 4 + offsetof(Thread, interpSave.retval), 6, false);
   1026             alu_binary_reg_mem(OpndSize_32, sub_opc, 4, false, offsetof(Thread, interpSave.retval), 6, false);
   1027             alu_binary_reg_mem(OpndSize_32, sbb_opc, 4, false, 4 + offsetof(Thread, interpSave.retval), 6, false);
   1028             return 0;
   1029         case INLINE_MATH_MAX_INT:
   1030             get_virtual_reg(vC, OpndSize_32, 1, false);
   1031             get_virtual_reg(vD, OpndSize_32, 2, false);
   1032             compare_reg_reg(1, false, 2, false);
   1033             conditional_move_reg_to_reg(OpndSize_32, Condition_GE, 2,
   1034                                         false/*src*/, 1, false/*dst*/);
   1035             get_self_pointer(3, false);
   1036             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
   1037             return 0;
   1038         case INLINE_MATH_ABS_FLOAT:
   1039             get_virtual_reg(vC, OpndSize_32, 1, false);
   1040             alu_binary_imm_reg(OpndSize_32, and_opc, 0x7fffffff, 1, false);
   1041             get_self_pointer(2, false);
   1042             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false);
   1043             return 0;
   1044         case INLINE_MATH_ABS_DOUBLE:
   1045             get_virtual_reg(vC, OpndSize_32, 1, false);
   1046             get_virtual_reg(vD, OpndSize_32, 2, false);
   1047             alu_binary_imm_reg(OpndSize_32, and_opc, 0x7fffffff, 2, false);
   1048             get_self_pointer(3, false);
   1049             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
   1050             move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false);
   1051             return 0;
   1052         case INLINE_STRING_FASTINDEXOF_II:
   1053 #if defined(USE_GLOBAL_STRING_DEFS)
   1054             break;
   1055 #else
   1056             get_virtual_reg(vC, OpndSize_32, 1, false);
   1057             compare_imm_reg(OpndSize_32, 0, 1, false);
   1058             get_virtual_reg(vD, OpndSize_32, 2, false);
   1059             get_virtual_reg(vE, OpndSize_32, 3, false);
   1060             conditional_jump(Condition_NE, ".do_inlined_string_fastIndexof",
   1061                              true);
   1062             scratchRegs[0] = PhysicalReg_SCRATCH_1;
   1063             jumpToExceptionThrown(1/*exception number*/);
   1064             insertLabel(".do_inlined_string_fastIndexof", true);
   1065             move_mem_to_reg(OpndSize_32, 0x14, 1, false, 4, false);
   1066             move_mem_to_reg(OpndSize_32, 0x8, 1, false, 5, false);
   1067             move_mem_to_reg(OpndSize_32, 0x10, 1, false, 6, false);
   1068             alu_binary_reg_reg(OpndSize_32, xor_opc, 1, false, 1, false);
   1069             compare_imm_reg(OpndSize_32, 0, 3, false);
   1070             conditional_move_reg_to_reg(OpndSize_32, Condition_NS, 3, false, 1,
   1071                                         false);
   1072             compare_reg_reg(4, false, 1, false);
   1073             conditional_jump(Condition_GE,
   1074                              ".do_inlined_string_fastIndexof_exitfalse", true);
   1075             dump_mem_scale_reg(Mnemonic_LEA, OpndSize_32, 5, false, 0xc/*disp*/,
   1076                                6, false, 2, 5, false, LowOpndRegType_gp);
   1077             movez_mem_disp_scale_to_reg(OpndSize_16, 5, false, 0, 1, false, 2,
   1078                                         3, false);
   1079             compare_reg_reg(3, false, 2, false);
   1080             conditional_jump(Condition_E, ".do_inlined_string_fastIndexof_exit",
   1081                              true);
   1082             load_effective_addr(0x1, 1, false, 3, false);
   1083             load_effective_addr_scale(5, false, 3, false, 2, 5, false);
   1084             unconditional_jump(".do_inlined_string_fastIndexof_iter", true);
   1085             insertLabel(".do_inlined_string_fastIndexof_ch_cmp", true);
   1086             if(gDvm.executionMode == kExecutionModeNcgO1) {
   1087                 rememberState(1);
   1088             }
   1089             movez_mem_to_reg(OpndSize_16, 0, 5, false, 6, false);
   1090             load_effective_addr(0x2, 5, false, 5, false);
   1091             compare_reg_reg(6, false, 2, false);
   1092             conditional_jump(Condition_E, ".do_inlined_string_fastIndexof_exit",
   1093                              true);
   1094             load_effective_addr(0x1, 3, false, 3, false);
   1095             insertLabel(".do_inlined_string_fastIndexof_iter", true);
   1096             compare_reg_reg(4, false, 3, false);
   1097             move_reg_to_reg(OpndSize_32, 3, false, 1, false);
   1098             if(gDvm.executionMode == kExecutionModeNcgO1) {
   1099                 transferToState(1);
   1100             }
   1101             conditional_jump(Condition_NE,
   1102                              ".do_inlined_string_fastIndexof_ch_cmp", true);
   1103             insertLabel(".do_inlined_string_fastIndexof_exitfalse", true);
   1104             move_imm_to_reg(OpndSize_32, 0xffffffff, 1,  false);
   1105             insertLabel(".do_inlined_string_fastIndexof_exit", true);
   1106             get_self_pointer(7, false);
   1107             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 7, false);
   1108             return 0;
   1109         case INLINE_FLOAT_TO_RAW_INT_BITS:
   1110             get_virtual_reg(vC, OpndSize_32, 1, false);
   1111             get_self_pointer(2, false);
   1112             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false);
   1113             return 0;
   1114         case INLINE_INT_BITS_TO_FLOAT:
   1115             get_virtual_reg(vC, OpndSize_32, 1, false);
   1116             get_self_pointer(2, false);
   1117             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 2, false);
   1118             return 0;
   1119         case INLINE_DOUBLE_TO_RAW_LONG_BITS:
   1120             get_virtual_reg(vC, OpndSize_32, 1, false);
   1121             get_self_pointer(3, false);
   1122             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
   1123             get_virtual_reg(vD, OpndSize_32, 2, false);
   1124             move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false);
   1125             return 0;
   1126         case INLINE_LONG_BITS_TO_DOUBLE:
   1127             get_virtual_reg(vC, OpndSize_32, 1, false);
   1128             get_virtual_reg(vD, OpndSize_32, 2, false);
   1129             get_self_pointer(3, false);
   1130             move_reg_to_mem(OpndSize_32, 2, false, 4 + offsetof(Thread, interpSave.retval), 3, false);
   1131             move_reg_to_mem(OpndSize_32, 1, false, offsetof(Thread, interpSave.retval), 3, false);
   1132             return 0;
   1133         default:
   1134                 break;
   1135     }
   1136 #endif
   1137     get_self_pointer(PhysicalReg_SCRATCH_1, false);
   1138     load_effective_addr(offsetof(Thread, interpSave.retval), PhysicalReg_SCRATCH_1, false, 1, false);
   1139     load_effective_addr(-24, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1140     move_reg_to_mem(OpndSize_32, 1, false, 16, PhysicalReg_ESP, true);
   1141     if(num >= 1) {
   1142         get_virtual_reg(vC, OpndSize_32, 2, false);
   1143         move_reg_to_mem(OpndSize_32, 2, false, 0, PhysicalReg_ESP, true);
   1144     }
   1145     if(num >= 2) {
   1146         get_virtual_reg(vD, OpndSize_32, 3, false);
   1147         move_reg_to_mem(OpndSize_32, 3, false, 4, PhysicalReg_ESP, true);
   1148     }
   1149     if(num >= 3) {
   1150         get_virtual_reg(vE, OpndSize_32, 4, false);
   1151         move_reg_to_mem(OpndSize_32, 4, false, 8, PhysicalReg_ESP, true);
   1152     }
   1153     if(num >= 4) {
   1154         get_virtual_reg(vF, OpndSize_32, 5, false);
   1155         move_reg_to_mem(OpndSize_32, 5, false, 12, PhysicalReg_ESP, true);
   1156     }
   1157     beforeCall("execute_inline");
   1158     load_imm_global_data_API("gDvmInlineOpsTable", OpndSize_32, 6, false);
   1159     call_mem(16*tmp, 6, false);//
   1160     afterCall("execute_inline");
   1161     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
   1162 
   1163     load_effective_addr(24, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1164     conditional_jump(Condition_NE, ".execute_inline_done", true);
   1165     //jump to dvmJitToExceptionThrown
   1166     scratchRegs[0] = PhysicalReg_SCRATCH_1;
   1167     jumpToExceptionThrown(1/*exception number*/);
   1168     insertLabel(".execute_inline_done", true);
   1169     rPC += 3;
   1170     return 0;
   1171 }
   1172 #undef P_GPR_1
   1173 #undef P_GPR_2
   1174 #undef P_SCRATCH_1
   1175 #undef P_SCRATCH_2
   1176 #undef P_SCRATCH_3
   1177 #undef P_SCRATCH_4
   1178 
   1179 //! lower bytecode INVOKE_OBJECT_INIT_RANGE
   1180 
   1181 //!
   1182 int op_invoke_object_init_range() {
   1183     return -1;
   1184 }
   1185 
   1186 #define P_GPR_1 PhysicalReg_EBX
   1187 #define P_SCRATCH_1 PhysicalReg_ESI
   1188 #define P_SCRATCH_2 PhysicalReg_EDX
   1189 #define PP_GPR_1 PhysicalReg_EBX
   1190 #define PP_GPR_2 PhysicalReg_ESI
   1191 #define PP_GPR_3 PhysicalReg_EAX
   1192 #define PP_GPR_4 PhysicalReg_EDX
   1193 //! common code for INVOKE_VIRTUAL_QUICK
   1194 
   1195 //! It uses helper function if the switch is on
   1196 int common_invoke_virtual_quick(bool hasRange, u2 vD, u2 IMMC) {
   1197 #ifdef WITH_JIT_INLINING
   1198     /* An invoke with the MIR_INLINED is effectively a no-op */
   1199     if (traceCurrentMIR->OptimizationFlags & MIR_INLINED)
   1200         return false;
   1201     /*
   1202      * If the invoke has non-null misPredBranchOver, we need to generate
   1203      * the non-inlined version of the invoke here to handle the
   1204      * mispredicted case.
   1205      */
   1206     if (traceCurrentMIR->meta.callsiteInfo->misPredBranchOver) {
   1207         genLandingPadForMispredictedCallee(); //cUnit, mir, bb, labelList);
   1208     }
   1209 #endif
   1210     export_pc();
   1211     constVREndOfBB();
   1212     beforeCall("exception"); //dump GG, GL VRs
   1213     /////////////////////////////////////////////////
   1214     get_virtual_reg(vD, OpndSize_32, 1, false);
   1215     simpleNullCheck(1, false, vD);
   1216 #ifndef PREDICTED_CHAINING
   1217     move_mem_to_reg(OpndSize_32, 0, 1, false, 2, false);
   1218     move_mem_to_reg(OpndSize_32, offClassObject_vtable, 2, false, 3, false);
   1219     move_mem_to_reg(OpndSize_32, IMMC, 3, false, PhysicalReg_ECX, true);
   1220 
   1221     if(hasRange) {
   1222         common_invokeMethodRange(ArgsDone_Full);
   1223     }
   1224     else {
   1225         common_invokeMethodNoRange(ArgsDone_Full);
   1226     }
   1227 #else
   1228     gen_predicted_chain(hasRange, -1, IMMC, false, 1/*tmp1*/);
   1229 #endif
   1230     ////////////////////////
   1231     return 0;
   1232 }
   1233 #undef P_GPR_1
   1234 #undef P_SCRATCH_1
   1235 #undef P_SCRATCH_2
   1236 #undef PP_GPR_1
   1237 #undef PP_GPR_2
   1238 #undef PP_GPR_3
   1239 #undef PP_GPR_4
   1240 //! lower bytecode INVOKE_VIRTUAL_QUICK by calling common_invoke_virtual_quick
   1241 
   1242 //!
   1243 int op_invoke_virtual_quick() {
   1244     u2 vD = FETCH(2) & 0xf;
   1245     u2 IMMC = 4*FETCH(1);
   1246     int retval = common_invoke_virtual_quick(false, vD, IMMC);
   1247 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
   1248     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
   1249 #endif
   1250     rPC += 3;
   1251     return retval;
   1252 }
   1253 //! lower bytecode INVOKE_VIRTUAL_QUICK_RANGE by calling common_invoke_virtual_quick
   1254 
   1255 //!
   1256 int op_invoke_virtual_quick_range() {
   1257     u2 vD = FETCH(2);
   1258     u2 IMMC = 4*FETCH(1);
   1259     int retval = common_invoke_virtual_quick(true, vD, IMMC);
   1260 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
   1261     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
   1262 #endif
   1263     rPC += 3;
   1264     return retval;
   1265 }
   1266 #define P_GPR_1 PhysicalReg_EBX
   1267 #define P_GPR_2 PhysicalReg_ESI
   1268 #define P_SCRATCH_1 PhysicalReg_EDX
   1269 //! common code to lower INVOKE_SUPER_QUICK
   1270 
   1271 //!
   1272 int common_invoke_super_quick(bool hasRange, u2 vD, u2 IMMC) {
   1273     export_pc();
   1274     constVREndOfBB();
   1275     beforeCall("exception"); //dump GG, GL VRs
   1276     compare_imm_VR(OpndSize_32, 0, vD);
   1277 
   1278     conditional_jump_global_API(Condition_E, "common_errNullObject", false);
   1279     /* for trace-based JIT, callee is already resolved */
   1280     int mIndex = IMMC/4;
   1281     const Method *calleeMethod = currentMethod->clazz->super->vtable[mIndex];
   1282     move_imm_to_reg(OpndSize_32, (int) calleeMethod, PhysicalReg_ECX, true);
   1283     if(hasRange) {
   1284         common_invokeMethodRange(convertCalleeToType(calleeMethod));
   1285     }
   1286     else {
   1287         common_invokeMethodNoRange(convertCalleeToType(calleeMethod));
   1288     }
   1289     return 0;
   1290 }
   1291 #undef P_GPR_1
   1292 #undef P_GPR_2
   1293 #undef P_SCRATCH_1
   1294 //! lower bytecode INVOKE_SUPER_QUICK by calling common_invoke_super_quick
   1295 
   1296 //!
   1297 int op_invoke_super_quick() {
   1298     u2 vD = FETCH(2) & 0xf;
   1299     u2 IMMC = 4*FETCH(1);
   1300     int retval = common_invoke_super_quick(false, vD, IMMC);
   1301 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
   1302     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
   1303 #endif
   1304     rPC += 3;
   1305     return retval;
   1306 }
   1307 //! lower bytecode INVOKE_SUPER_QUICK_RANGE by calling common_invoke_super_quick
   1308 
   1309 //!
   1310 int op_invoke_super_quick_range() {
   1311     u2 vD = FETCH(2);
   1312     u2 IMMC = 4*FETCH(1);
   1313     int retval = common_invoke_super_quick(true, vD, IMMC);
   1314 #if defined(ENABLE_TRACING) && !defined(TRACING_OPTION2)
   1315     insertMapWorklist(offsetPC+3, stream - streamMethodStart, 1); //check when helper switch is on
   1316 #endif
   1317     rPC += 3;
   1318     return retval;
   1319 }
   1320 /////// code to predict the callee method for invoke_virtual & invoke_interface
   1321 #define offChainingCell_clazz 8
   1322 #define offChainingCell_method 12
   1323 #define offChainingCell_counter 16
   1324 #define P_GPR_1 PhysicalReg_EBX
   1325 #define P_GPR_2 PhysicalReg_EAX
   1326 #define P_GPR_3 PhysicalReg_ESI
   1327 #define P_SCRATCH_2 PhysicalReg_EDX
   1328 /* TODO gingerbread: implemented for O1, but not for O0:
   1329    valid input to JitToPatch & use icRechainCount */
   1330 /* update predicted method for invoke interface */
   1331 // 2 inputs: ChainingCell in P_GPR_1, current class object in P_GPR_3
   1332 void predicted_chain_interface_O0(u2 tmp) {
   1333     ALOGI("TODO chain_interface_O0");
   1334 
   1335     /* set up arguments to dvmFindInterfaceMethodInCache */
   1336     load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1337     move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true);
   1338     move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true);
   1339     move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true);
   1340     move_reg_to_mem(OpndSize_32, P_GPR_3, true, 0, PhysicalReg_ESP, true);
   1341     scratchRegs[0] = PhysicalReg_EDX;
   1342     call_dvmFindInterfaceMethodInCache();
   1343     load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1344 
   1345     /* if dvmFindInterfaceMethodInCache returns NULL, throw exception
   1346        otherwise, jump to .find_interface_done */
   1347     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
   1348     conditional_jump(Condition_NE, ".find_interface_done", true);
   1349     scratchRegs[0] = PhysicalReg_EAX;
   1350     jumpToExceptionThrown(1/*exception number*/);
   1351 
   1352     /* the interface method is found */
   1353     insertLabel(".find_interface_done", true);
   1354     /* reduce counter in chaining cell by 1 */
   1355     move_mem_to_reg(OpndSize_32, offChainingCell_counter, P_GPR_1, true, P_SCRATCH_2, true); //counter
   1356     alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, P_SCRATCH_2, true);
   1357     move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, offChainingCell_counter, P_GPR_1, true);
   1358 
   1359     /* if counter is still greater than zero, skip prediction
   1360        if it is zero, update predicted method */
   1361     compare_imm_reg(OpndSize_32, 0, P_SCRATCH_2, true);
   1362     conditional_jump(Condition_G, ".skipPrediction", true);
   1363 
   1364     /* call dvmJitToPatchPredictedChain to update predicted method */
   1365     //%ecx has callee method for virtual, %eax has callee for interface
   1366     /* set up arguments for dvmJitToPatchPredictedChain */
   1367     load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1368     move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true);
   1369     insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1370     move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell
   1371     move_reg_to_mem(OpndSize_32, P_GPR_3, true, 12, PhysicalReg_ESP, true);
   1372     scratchRegs[0] = PhysicalReg_EAX;
   1373     call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
   1374     load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1375     insertLabel(".skipPrediction", true);
   1376     move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
   1377 }
   1378 
   1379 // 2 inputs: ChainingCell in temp 41, current class object in temp 40
   1380 void predicted_chain_interface_O1(u2 tmp) {
   1381 
   1382     /* set up arguments to dvmFindInterfaceMethodInCache */
   1383     load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1384     move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true);
   1385     move_imm_to_mem(OpndSize_32, (int) currentMethod->clazz->pDvmDex, 12, PhysicalReg_ESP, true);
   1386     move_imm_to_mem(OpndSize_32, (int) currentMethod, 8, PhysicalReg_ESP, true);
   1387     move_reg_to_mem(OpndSize_32, 40, false, 0, PhysicalReg_ESP, true);
   1388     scratchRegs[0] = PhysicalReg_SCRATCH_10;
   1389     call_dvmFindInterfaceMethodInCache();
   1390     load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1391 
   1392     /* if dvmFindInterfaceMethodInCache returns NULL, throw exception
   1393        otherwise, jump to .find_interface_done */
   1394     compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true);
   1395     conditional_jump(Condition_NE, ".find_interface_done", true);
   1396     rememberState(3);
   1397     scratchRegs[0] = PhysicalReg_SCRATCH_9;
   1398     jumpToExceptionThrown(1/*exception number*/);
   1399 
   1400     goToState(3);
   1401     /* the interface method is found */
   1402     insertLabel(".find_interface_done", true);
   1403 #if 1 //
   1404     /* for gingerbread, counter is stored in glue structure
   1405        if clazz is not initialized, set icRechainCount to 0, otherwise, reduce it by 1 */
   1406     /* for gingerbread: t43 = 0 t44 = t33 t33-- cmov_ne t43 = t33 cmov_ne t44 = t33 */
   1407     move_mem_to_reg(OpndSize_32, offChainingCell_clazz, 41, false, 45, false);
   1408     move_imm_to_reg(OpndSize_32, 0, 43, false);
   1409     get_self_pointer(PhysicalReg_SCRATCH_7, isScratchPhysical);
   1410     move_mem_to_reg(OpndSize_32, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical, 33, false); //counter
   1411     move_reg_to_reg(OpndSize_32, 33, false, 44, false);
   1412     alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false);
   1413     /* sub_opc will update control flags, so compare_imm_reg must happen after */
   1414     compare_imm_reg(OpndSize_32, 0, 45, false);
   1415     conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 43, false/*dst*/);
   1416     conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 44, false/*dst*/);
   1417     move_reg_to_mem(OpndSize_32, 44, false, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical);
   1418 #else
   1419     /* reduce counter in chaining cell by 1 */
   1420     move_mem_to_reg(OpndSize_32, offChainingCell_counter, 41, false, 33, false); //counter
   1421     alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false);
   1422     move_reg_to_mem(OpndSize_32, 33, false, offChainingCell_counter, 41, false);
   1423 #endif
   1424 
   1425     /* if counter is still greater than zero, skip prediction
   1426        if it is zero, update predicted method */
   1427     compare_imm_reg(OpndSize_32, 0, 43, false);
   1428     conditional_jump(Condition_G, ".skipPrediction", true);
   1429 
   1430     rememberState(4);
   1431     /* call dvmJitToPatchPredictedChain to update predicted method */
   1432     //%ecx has callee method for virtual, %eax has callee for interface
   1433     /* set up arguments for dvmJitToPatchPredictedChain */
   1434     load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1435     move_reg_to_mem(OpndSize_32, PhysicalReg_EAX, true, 0, PhysicalReg_ESP, true);
   1436     move_reg_to_mem(OpndSize_32, PhysicalReg_SCRATCH_7, isScratchPhysical, 4, PhysicalReg_ESP, true);
   1437     insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1438     move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell
   1439     move_reg_to_mem(OpndSize_32, 40, false, 12, PhysicalReg_ESP, true);
   1440     scratchRegs[0] = PhysicalReg_SCRATCH_8;
   1441     call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
   1442     load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1443     transferToState(4);
   1444 
   1445     insertLabel(".skipPrediction", true);
   1446     move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
   1447 }
   1448 
   1449 /* update predicted method for invoke virtual */
   1450 // 2 inputs: ChainingCell in P_GPR_1, current class object in P_GPR_3
   1451 void predicted_chain_virtual_O0(u2 IMMC) {
   1452     ALOGI("TODO chain_virtual_O0");
   1453 
   1454     /* reduce counter in chaining cell by 1 */
   1455     move_mem_to_reg(OpndSize_32, offChainingCell_counter, P_GPR_1, true, P_GPR_2, true); //counter
   1456     move_mem_to_reg(OpndSize_32, offClassObject_vtable, P_GPR_3, true, P_SCRATCH_2, true);
   1457     alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, P_GPR_2, true);
   1458     move_mem_to_reg(OpndSize_32, IMMC, P_SCRATCH_2, true, PhysicalReg_ECX, true);
   1459     move_reg_to_mem(OpndSize_32, P_GPR_2, true, offChainingCell_counter, P_GPR_1, true);
   1460 
   1461     /* if counter is still greater than zero, skip prediction
   1462        if it is zero, update predicted method */
   1463     compare_imm_reg(OpndSize_32, 0, P_GPR_2, true);
   1464     conditional_jump(Condition_G, ".skipPrediction", true);
   1465 
   1466     /* call dvmJitToPatchPredictedChain to update predicted method */
   1467     //%ecx has callee method for virtual, %eax has callee for interface
   1468     /* set up arguments for dvmJitToPatchPredictedChain */
   1469     load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1470     move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 0,  PhysicalReg_ESP, true);
   1471     insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1472     move_chain_to_mem(OpndSize_32, traceCurrentBB->taken->id, 8, PhysicalReg_ESP, true); //predictedChainCell
   1473     move_reg_to_mem(OpndSize_32, P_GPR_3, true, 12, PhysicalReg_ESP, true);
   1474     scratchRegs[0] = PhysicalReg_EAX;
   1475     call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
   1476     load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1477 
   1478     //callee method in %ecx for invoke virtual
   1479     move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
   1480     insertLabel(".skipPrediction", true);
   1481 }
   1482 
   1483 // 2 inputs: ChainingCell in temp 41, current class object in temp 40
   1484 // extra input: predicted clazz in temp 32
   1485 void predicted_chain_virtual_O1(u2 IMMC) {
   1486 
   1487     /* reduce counter in chaining cell by 1 */
   1488     /* for gingerbread: t43 = 0 t44 = t33 t33-- cmov_ne t43 = t33 cmov_ne t44 = t33 */
   1489     get_self_pointer(PhysicalReg_SCRATCH_7, isScratchPhysical);
   1490     move_imm_to_reg(OpndSize_32, 0, 43, false);
   1491     move_mem_to_reg(OpndSize_32, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical, 33, false); //counter
   1492     move_mem_to_reg(OpndSize_32, offClassObject_vtable, 40, false, 34, false);
   1493     move_reg_to_reg(OpndSize_32, 33, false, 44, false);
   1494     alu_binary_imm_reg(OpndSize_32, sub_opc, 0x1, 33, false);
   1495     compare_imm_reg(OpndSize_32, 0, 32, false); // after sub_opc
   1496     move_mem_to_reg(OpndSize_32, IMMC, 34, false, PhysicalReg_ECX, true);
   1497     conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 43, false/*dst*/);
   1498     conditional_move_reg_to_reg(OpndSize_32, Condition_NZ, 33, false/*src*/, 44, false/*dst*/);
   1499     move_reg_to_mem(OpndSize_32, 44, false, offsetof(Thread, icRechainCount), PhysicalReg_SCRATCH_7, isScratchPhysical);
   1500 
   1501     /* if counter is still greater than zero, skip prediction
   1502        if it is zero, update predicted method */
   1503     compare_imm_reg(OpndSize_32, 0, 43, false);
   1504     conditional_jump(Condition_G, ".skipPrediction", true);
   1505 
   1506     rememberState(2);
   1507     /* call dvmJitToPatchPredictedChain to update predicted method */
   1508     //%ecx has callee method for virtual, %eax has callee for interface
   1509     /* set up arguments for dvmJitToPatchPredictedChain */
   1510     load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1511     move_reg_to_mem(OpndSize_32, PhysicalReg_ECX, true, 0, PhysicalReg_ESP, true);
   1512     move_reg_to_mem(OpndSize_32, PhysicalReg_SCRATCH_7, isScratchPhysical, 4, PhysicalReg_ESP, true);
   1513     if(traceCurrentBB->taken)
   1514         insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1515     int traceTakenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0;
   1516     move_chain_to_mem(OpndSize_32, traceTakenId, 8, PhysicalReg_ESP, true); //predictedChainCell
   1517     move_reg_to_mem(OpndSize_32, 40, false, 12, PhysicalReg_ESP, true);
   1518     scratchRegs[0] = PhysicalReg_SCRATCH_10;
   1519     call_dvmJitToPatchPredictedChain(); //inputs: method, unused, predictedChainCell, clazz
   1520     load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1521 
   1522     //callee method in %ecx for invoke virtual
   1523     move_reg_to_reg(OpndSize_32, PhysicalReg_EAX, true, PhysicalReg_ECX, true);
   1524     transferToState(2);
   1525 
   1526     insertLabel(".skipPrediction", true);
   1527 }
   1528 
   1529 static int invokeChain_inst = 0;
   1530 /* object "this" is in %ebx */
   1531 void gen_predicted_chain_O0(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) {
   1532     ALOGI("TODO predicted_chain_O0");
   1533 
   1534     /* get current class object */
   1535     move_mem_to_reg(OpndSize_32, offObject_clazz, PhysicalReg_EBX, true,
   1536              P_GPR_3, true);
   1537 #ifdef DEBUG_CALL_STACK3
   1538     scratchRegs[0] = PhysicalReg_EAX;
   1539     call_debug_dumpSwitch(); //%ebx, %eax, %edx
   1540     move_imm_to_reg(OpndSize_32, 0xdd11, PhysicalReg_EBX, true);
   1541     call_debug_dumpSwitch();
   1542 #endif
   1543 
   1544     /* get predicted clazz
   1545        get predicted method
   1546     */
   1547     insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1548     move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, P_GPR_1, true); //predictedChainCell
   1549     move_mem_to_reg(OpndSize_32, offChainingCell_clazz, P_GPR_1, true, P_SCRATCH_2, true);//predicted clazz
   1550     move_mem_to_reg(OpndSize_32, offChainingCell_method, P_GPR_1, true, PhysicalReg_ECX, true);//predicted method
   1551 
   1552 #ifdef DEBUG_CALL_STACK3
   1553     load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1554     move_reg_to_mem(OpndSize_32, P_GPR_1, true, 8, PhysicalReg_ESP, true);
   1555     move_reg_to_mem(OpndSize_32, P_SCRATCH_2, true, 4, PhysicalReg_ESP, true);
   1556     move_reg_to_mem(OpndSize_32, P_GPR_3, true, 0, PhysicalReg_ESP, true);
   1557 
   1558     move_reg_to_reg(OpndSize_32, P_SCRATCH_2, true, PhysicalReg_EBX, true);
   1559     call_debug_dumpSwitch();
   1560     move_imm_to_reg(OpndSize_32, 0xdd22, PhysicalReg_EBX, true);
   1561     scratchRegs[0] = PhysicalReg_EAX;
   1562     call_debug_dumpSwitch(); //%ebx, %eax, %edx
   1563     move_reg_to_reg(OpndSize_32, P_GPR_3, true, PhysicalReg_EBX, true);
   1564     call_debug_dumpSwitch();
   1565     move_reg_to_reg(OpndSize_32, PhysicalReg_ECX, true, PhysicalReg_EBX, true);
   1566     call_debug_dumpSwitch();
   1567 
   1568     move_mem_to_reg(OpndSize_32, 8, PhysicalReg_ESP, true, P_GPR_1, true);
   1569     move_mem_to_reg(OpndSize_32, 4, PhysicalReg_ESP, true, P_SCRATCH_2, true);
   1570     move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, P_GPR_3, true);
   1571     load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true);
   1572 #endif
   1573 
   1574     /* compare current class object against predicted clazz
   1575        if equal, prediction is still valid, jump to .invokeChain */
   1576     //live registers: P_GPR_1, P_GPR_3, P_SCRATCH_2
   1577     compare_reg_reg(P_GPR_3, true, P_SCRATCH_2, true);
   1578     conditional_jump(Condition_E, ".invokeChain", true);
   1579     invokeChain_inst++;
   1580 
   1581     //get callee method and update predicted method if necessary
   1582     if(isInterface) {
   1583         predicted_chain_interface_O0(tmp);
   1584     } else {
   1585         predicted_chain_virtual_O0(IMMC);
   1586     }
   1587 
   1588 #ifdef DEBUG_CALL_STACK3
   1589     move_imm_to_reg(OpndSize_32, 0xeeee, PhysicalReg_EBX, true);
   1590     scratchRegs[0] = PhysicalReg_EAX;
   1591     call_debug_dumpSwitch(); //%ebx, %eax, %edx
   1592     insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1593     move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, PhysicalReg_EBX, true);
   1594     call_debug_dumpSwitch();
   1595 #endif
   1596 
   1597     if(isRange) {
   1598         common_invokeMethodRange(ArgsDone_Full);
   1599     }
   1600     else {
   1601         common_invokeMethodNoRange(ArgsDone_Full);
   1602     }
   1603 
   1604     insertLabel(".invokeChain", true);
   1605 #ifdef DEBUG_CALL_STACK3
   1606     move_imm_to_reg(OpndSize_32, 0xdddd, PhysicalReg_EBX, true);
   1607     scratchRegs[0] = PhysicalReg_EAX;
   1608     call_debug_dumpSwitch(); //%ebx, %eax, %edx
   1609     insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1610     move_chain_to_reg(OpndSize_32, traceCurrentBB->taken->id, PhysicalReg_EBX, true);
   1611     call_debug_dumpSwitch();
   1612     move_reg_to_reg(OpndSize_32, PhysicalReg_ECX, true, PhysicalReg_EBX, true);
   1613     call_debug_dumpSwitch();
   1614 #endif
   1615 
   1616     if(isRange) {
   1617         common_invokeMethodRange(ArgsDone_Normal);
   1618     }
   1619     else {
   1620         common_invokeMethodNoRange(ArgsDone_Normal);
   1621     }
   1622 }
   1623 
   1624 /* object "this" is in inputReg: 5 for virtual, 1 for interface, 1 for virtual_quick */
   1625 void gen_predicted_chain_O1(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) {
   1626 
   1627     /* get current class object */
   1628     move_mem_to_reg(OpndSize_32, offObject_clazz, inputReg, false,
   1629              40, false);
   1630 
   1631     /* get predicted clazz
   1632        get predicted method
   1633     */
   1634     if(traceCurrentBB->taken)
   1635         insertChainingWorklist(traceCurrentBB->taken->id, stream);
   1636     int traceTakenId = traceCurrentBB->taken ? traceCurrentBB->taken->id : 0;
   1637     move_chain_to_reg(OpndSize_32, traceTakenId, 41, false); //predictedChainCell
   1638     move_mem_to_reg(OpndSize_32, offChainingCell_clazz, 41, false, 32, false);//predicted clazz
   1639     move_mem_to_reg(OpndSize_32, offChainingCell_method, 41, false, PhysicalReg_ECX, true);//predicted method
   1640 
   1641     /* update stack with parameters first, then decide the callee */
   1642     if(isRange) common_invokeMethodRange_noJmp();
   1643     else common_invokeMethodNoRange_noJmp();
   1644 
   1645     /* compare current class object against predicted clazz
   1646        if equal, prediction is still valid, jump to .invokeChain */
   1647     compare_reg_reg(40, false, 32, false);
   1648     conditional_jump(Condition_E, ".invokeChain", true);
   1649     rememberState(1);
   1650     invokeChain_inst++;
   1651 
   1652     //get callee method and update predicted method if necessary
   1653     if(isInterface) {
   1654         predicted_chain_interface_O1(tmp);
   1655     } else {
   1656         predicted_chain_virtual_O1(IMMC);
   1657     }
   1658 
   1659     common_invokeMethod_Jmp(ArgsDone_Full); //will touch %ecx
   1660 
   1661     insertLabel(".invokeChain", true);
   1662     goToState(1);
   1663     common_invokeMethod_Jmp(ArgsDone_Normal);
   1664 }
   1665 
   1666 void gen_predicted_chain(bool isRange, u2 tmp, int IMMC, bool isInterface, int inputReg) {
   1667     return gen_predicted_chain_O1(isRange, tmp, IMMC, isInterface, inputReg);
   1668 }
   1669 #undef P_GPR_1
   1670 #undef P_GPR_2
   1671 #undef P_GPR_3
   1672 #undef P_SCRATCH_2
   1673