Home | History | Annotate | Download | only in armv5te
      1 /*
      2  * ===========================================================================
      3  *  Common subroutines and data
      4  * ===========================================================================
      5  */
      6 
      7     .text
      8     .align  2
      9 
     10 #if defined(WITH_JIT)
     11 
     12 #if defined(WITH_SELF_VERIFICATION)
     13 /*
     14  * "longjmp" to a translation after single-stepping.  Before returning
     15  * to translation, must save state for self-verification.
     16  */
     17     .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
     18 dvmJitResumeTranslation:
     19     mov    rSELF, r0                             @ restore self
     20     mov    rPC, r1                               @ restore Dalvik pc
     21     mov    rFP, r2                               @ restore Dalvik fp
     22     ldr    r10, [rSELF,#offThread_jitResumeNPC]  @ resume address
     23     mov    r2, #0
     24     str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
     25     ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
     26     b      jitSVShadowRunStart                   @ resume as if cache hit
     27                                                  @ expects resume addr in r10
     28 
     29     .global dvmJitToInterpPunt
     30 dvmJitToInterpPunt:
     31     mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
     32     mov    r3, #0
     33     str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
     34     b      jitSVShadowRunEnd            @ doesn't return
     35 
     36     .global dvmJitToInterpSingleStep
     37 dvmJitToInterpSingleStep:
     38     mov    rPC, r0              @ set up dalvik pc
     39     EXPORT_PC()
     40     str    lr, [rSELF,#offThread_jitResumeNPC]
     41     str    sp, [rSELF,#offThread_jitResumeNSP]
     42     str    r1, [rSELF,#offThread_jitResumeDPC]
     43     mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
     44     b      jitSVShadowRunEnd            @ doesn't return
     45 
     46 
     47     .global dvmJitToInterpNoChainNoProfile
     48 dvmJitToInterpNoChainNoProfile:
     49     mov    r0,rPC                       @ pass our target PC
     50     mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
     51     mov    r3, #0                       @ 0 means !inJitCodeCache
     52     str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
     53     b      jitSVShadowRunEnd            @ doesn't return
     54 
     55     .global dvmJitToInterpTraceSelectNoChain
     56 dvmJitToInterpTraceSelectNoChain:
     57     mov    r0,rPC                       @ pass our target PC
     58     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
     59     mov    r3, #0                       @ 0 means !inJitCodeCache
     60     str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
     61     b      jitSVShadowRunEnd            @ doesn't return
     62 
     63     .global dvmJitToInterpTraceSelect
     64 dvmJitToInterpTraceSelect:
     65     ldr    r0,[lr, #-1]                 @ pass our target PC
     66     mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
     67     mov    r3, #0                       @ 0 means !inJitCodeCache
     68     str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
     69     b      jitSVShadowRunEnd            @ doesn't return
     70 
     71     .global dvmJitToInterpBackwardBranch
     72 dvmJitToInterpBackwardBranch:
     73     ldr    r0,[lr, #-1]                 @ pass our target PC
     74     mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
     75     mov    r3, #0                       @ 0 means !inJitCodeCache
     76     str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
     77     b      jitSVShadowRunEnd            @ doesn't return
     78 
     79     .global dvmJitToInterpNormal
     80 dvmJitToInterpNormal:
     81     ldr    r0,[lr, #-1]                 @ pass our target PC
     82     mov    r2,#kSVSNormal               @ r2<- interpreter entry point
     83     mov    r3, #0                       @ 0 means !inJitCodeCache
     84     str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
     85     b      jitSVShadowRunEnd            @ doesn't return
     86 
     87     .global dvmJitToInterpNoChain
     88 dvmJitToInterpNoChain:
     89     mov    r0,rPC                       @ pass our target PC
     90     mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
     91     mov    r3, #0                       @ 0 means !inJitCodeCache
     92     str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
     93     b      jitSVShadowRunEnd            @ doesn't return
     94 #else
     95 
     96 /*
     97  * "longjmp" to a translation after single-stepping.
     98  */
     99     .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
    100 dvmJitResumeTranslation:
    101     mov    rSELF, r0                             @ restore self
    102     mov    rPC, r1                               @ restore Dalvik pc
    103     mov    rFP, r2                               @ restore Dalvik fp
    104     ldr    r0, [rSELF,#offThread_jitResumeNPC]
    105     mov    r2, #0
    106     str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
    107     ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
    108     bx     r0                                    @ resume translation
    109 
    110 /*
    111  * Return from the translation cache to the interpreter when the compiler is
    112  * having issues translating/executing a Dalvik instruction. We have to skip
    113  * the code cache lookup otherwise it is possible to indefinitely bouce
    114  * between the interpreter and the code cache if the instruction that fails
    115  * to be compiled happens to be at a trace start.
    116  */
    117     .global dvmJitToInterpPunt
    118 dvmJitToInterpPunt:
    119     mov    rPC, r0
    120 #if defined(WITH_JIT_TUNING)
    121     mov    r0,lr
    122     bl     dvmBumpPunt;
    123 #endif
    124     EXPORT_PC()
    125     mov    r0, #0
    126     str    r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
    127     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
    128     FETCH_INST()
    129     GET_INST_OPCODE(ip)
    130     GOTO_OPCODE(ip)
    131 
    132 /*
    133  * Return to the interpreter to handle a single instruction.
    134  * We'll use the normal single-stepping mechanism via interpBreak,
    135  * but also save the native pc of the resume point in the translation
    136  * and the native sp so that we can later do the equivalent of a
    137  * longjmp() to resume.
    138  * On entry:
    139  *    dPC <= Dalvik PC of instrucion to interpret
    140  *    lr <= resume point in translation
    141  *    r1 <= Dalvik PC of next instruction
    142  */
    143     .global dvmJitToInterpSingleStep
    144 dvmJitToInterpSingleStep:
    145     mov    rPC, r0              @ set up dalvik pc
    146     EXPORT_PC()
    147     str    lr, [rSELF,#offThread_jitResumeNPC]
    148     str    sp, [rSELF,#offThread_jitResumeNSP]
    149     str    r1, [rSELF,#offThread_jitResumeDPC]
    150     mov    r1, #1
    151     str    r1, [rSELF,#offThread_singleStepCount]  @ just step once
    152     mov    r0, rSELF
    153     mov    r1, #kSubModeCountedStep
    154     bl     dvmEnableSubMode     @ (self, newMode)
    155     ldr    rIBASE, [rSELF,#offThread_curHandlerTable]
    156     FETCH_INST()
    157     GET_INST_OPCODE(ip)
    158     GOTO_OPCODE(ip)
    159 
    160 /*
    161  * Return from the translation cache and immediately request
    162  * a translation for the exit target.  Commonly used for callees.
    163  */
    164     .global dvmJitToInterpTraceSelectNoChain
    165 dvmJitToInterpTraceSelectNoChain:
    166 #if defined(WITH_JIT_TUNING)
    167     bl     dvmBumpNoChain
    168 #endif
    169     mov    r0,rPC
    170     mov    r1,rSELF
    171     bl     dvmJitGetTraceAddrThread @ (pc, self)
    172     str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
    173     mov    r1, rPC                  @ arg1 of translation may need this
    174     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
    175     cmp    r0,#0                    @ !0 means translation exists
    176     bxne   r0                       @ continue native execution if so
    177     b      2f                       @ branch over to use the interpreter
    178 
    179 /*
    180  * Return from the translation cache and immediately request
    181  * a translation for the exit target.  Commonly used following
    182  * invokes.
    183  */
    184     .global dvmJitToInterpTraceSelect
    185 dvmJitToInterpTraceSelect:
    186     ldr    rPC,[lr, #-1]           @ get our target PC
    187     add    rINST,lr,#-5            @ save start of chain branch
    188     add    rINST, #-4              @  .. which is 9 bytes back
    189     mov    r0,rPC
    190     mov    r1,rSELF
    191     bl     dvmJitGetTraceAddrThread @ (pc, self)
    192     str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
    193     cmp    r0,#0
    194     beq    2f
    195     mov    r1,rINST
    196     bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
    197     mov    r1, rPC                  @ arg1 of translation may need this
    198     mov    lr, #0                   @ in case target is HANDLER_INTERPRET
    199     cmp    r0,#0                    @ successful chain?
    200     bxne   r0                       @ continue native execution
    201     b      toInterpreter            @ didn't chain - resume with interpreter
    202 
    203 /* No translation, so request one if profiling isn't disabled*/
    204 2:
    205     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
    206     ldr    r0, [rSELF, #offThread_pJitProfTable]
    207     FETCH_INST()
    208     cmp    r0, #0
    209     movne  r2,#kJitTSelectRequestHot   @ ask for trace selection
    210     bne    common_selectTrace
    211     GET_INST_OPCODE(ip)
    212     GOTO_OPCODE(ip)
    213 
    214 /*
    215  * Return from the translation cache to the interpreter.
    216  * The return was done with a BLX from thumb mode, and
    217  * the following 32-bit word contains the target rPC value.
    218  * Note that lr (r14) will have its low-order bit set to denote
    219  * its thumb-mode origin.
    220  *
    221  * We'll need to stash our lr origin away, recover the new
    222  * target and then check to see if there is a translation available
    223  * for our new target.  If so, we do a translation chain and
    224  * go back to native execution.  Otherwise, it's back to the
    225  * interpreter (after treating this entry as a potential
    226  * trace start).
    227  */
    228     .global dvmJitToInterpNormal
    229 dvmJitToInterpNormal:
    230     ldr    rPC,[lr, #-1]           @ get our target PC
    231     add    rINST,lr,#-5            @ save start of chain branch
    232     add    rINST,#-4               @ .. which is 9 bytes back
    233 #if defined(WITH_JIT_TUNING)
    234     bl     dvmBumpNormal
    235 #endif
    236     mov    r0,rPC
    237     mov    r1,rSELF
    238     bl     dvmJitGetTraceAddrThread @ (pc, self)
    239     str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
    240     cmp    r0,#0
    241     beq    toInterpreter            @ go if not, otherwise do chain
    242     mov    r1,rINST
    243     bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
    244     mov    r1, rPC                  @ arg1 of translation may need this
    245     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
    246     cmp    r0,#0                    @ successful chain?
    247     bxne   r0                       @ continue native execution
    248     b      toInterpreter            @ didn't chain - resume with interpreter
    249 
    250 /*
    251  * Return from the translation cache to the interpreter to do method invocation.
    252  * Check if translation exists for the callee, but don't chain to it.
    253  */
    254     .global dvmJitToInterpNoChainNoProfile
    255 dvmJitToInterpNoChainNoProfile:
    256 #if defined(WITH_JIT_TUNING)
    257     bl     dvmBumpNoChain
    258 #endif
    259     mov    r0,rPC
    260     mov    r1,rSELF
    261     bl     dvmJitGetTraceAddrThread @ (pc, self)
    262     str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
    263     mov    r1, rPC                  @ arg1 of translation may need this
    264     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
    265     cmp    r0,#0
    266     bxne   r0                       @ continue native execution if so
    267     EXPORT_PC()
    268     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
    269     FETCH_INST()
    270     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    271     GOTO_OPCODE(ip)                     @ jump to next instruction
    272 
    273 /*
    274  * Return from the translation cache to the interpreter to do method invocation.
    275  * Check if translation exists for the callee, but don't chain to it.
    276  */
    277     .global dvmJitToInterpNoChain
    278 dvmJitToInterpNoChain:
    279 #if defined(WITH_JIT_TUNING)
    280     bl     dvmBumpNoChain
    281 #endif
    282     mov    r0,rPC
    283     mov    r1,rSELF
    284     bl     dvmJitGetTraceAddrThread @ (pc, self)
    285     str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
    286     mov    r1, rPC                  @ arg1 of translation may need this
    287     mov    lr, #0                   @  in case target is HANDLER_INTERPRET
    288     cmp    r0,#0
    289     bxne   r0                       @ continue native execution if so
    290 #endif
    291 
    292 /*
    293  * No translation, restore interpreter regs and start interpreting.
    294  * rSELF & rFP were preserved in the translated code, and rPC has
    295  * already been restored by the time we get here.  We'll need to set
    296  * up rIBASE & rINST, and load the address of the JitTable into r0.
    297  */
    298 toInterpreter:
    299     EXPORT_PC()
    300     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
    301     FETCH_INST()
    302     ldr    r0, [rSELF, #offThread_pJitProfTable]
    303     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
    304     @ NOTE: intended fallthrough
    305 
    306 /*
    307  * Similar to common_updateProfile, but tests for null pJitProfTable
    308  * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
    309  * rIBASE has been recently refreshed.
    310  */
    311 common_testUpdateProfile:
    312     cmp     r0, #0               @ JIT switched off?
    313     beq     4f                   @ return to interp if so
    314 
    315 /*
    316  * Common code to update potential trace start counter, and initiate
    317  * a trace-build if appropriate.
    318  * On entry here:
    319  *    r0    <= pJitProfTable (verified non-NULL)
    320  *    rPC   <= Dalvik PC
    321  *    rINST <= next instruction
    322  */
    323 common_updateProfile:
    324     eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
    325     lsl     r3,r3,#(32 - JIT_PROF_SIZE_LOG_2)          @ shift out excess bits
    326     ldrb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
    327     GET_INST_OPCODE(ip)
    328     subs    r1,r1,#1           @ decrement counter
    329     strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
    330     GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
    331 
    332     /* Looks good, reset the counter */
    333     ldr     r1, [rSELF, #offThread_jitThreshold]
    334     strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
    335     EXPORT_PC()
    336     mov     r0,rPC
    337     mov     r1,rSELF
    338     bl      dvmJitGetTraceAddrThread    @ (pc, self)
    339     str     r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
    340     mov     r1, rPC                     @ arg1 of translation may need this
    341     mov     lr, #0                      @  in case target is HANDLER_INTERPRET
    342     cmp     r0,#0
    343 #if !defined(WITH_SELF_VERIFICATION)
    344     bxne    r0                          @ jump to the translation
    345     mov     r2,#kJitTSelectRequest      @ ask for trace selection
    346     @ fall-through to common_selectTrace
    347 #else
    348     moveq   r2,#kJitTSelectRequest      @ ask for trace selection
    349     beq     common_selectTrace
    350     /*
    351      * At this point, we have a target translation.  However, if
    352      * that translation is actually the interpret-only pseudo-translation
    353      * we want to treat it the same as no translation.
    354      */
    355     mov     r10, r0                     @ save target
    356     bl      dvmCompilerGetInterpretTemplate
    357     cmp     r0, r10                     @ special case?
    358     bne     jitSVShadowRunStart         @ set up self verification shadow space
    359     @ Need to clear the inJitCodeCache flag
    360     mov    r3, #0                       @ 0 means not in the JIT code cache
    361     str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
    362     GET_INST_OPCODE(ip)
    363     GOTO_OPCODE(ip)
    364     /* no return */
    365 #endif
    366 
    367 /*
    368  * On entry:
    369  *  r2 is jit state.
    370  */
    371 common_selectTrace:
    372     ldrh    r0,[rSELF,#offThread_subMode]
    373     ands    r0, #(kSubModeJitTraceBuild | kSubModeJitSV)
    374     bne     3f                         @ already doing JIT work, continue
    375     str     r2,[rSELF,#offThread_jitState]
    376     mov     r0, rSELF
    377 /*
    378  * Call out to validate trace-building request.  If successful,
    379  * rIBASE will be swapped to to send us into single-stepping trace
    380  * building mode, so we need to refresh before we continue.
    381  */
    382     EXPORT_PC()
    383     SAVE_PC_FP_TO_SELF()                 @ copy of pc/fp to Thread
    384     bl      dvmJitCheckTraceRequest
    385 3:
    386     FETCH_INST()
    387     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
    388 4:
    389     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    390     GOTO_OPCODE(ip)
    391     /* no return */
    392 #endif
    393 
    394 #if defined(WITH_SELF_VERIFICATION)
    395 /*
    396  * Save PC and registers to shadow memory for self verification mode
    397  * before jumping to native translation.
    398  * On entry:
    399  *    rPC, rFP, rSELF: the values that they should contain
    400  *    r10: the address of the target translation.
    401  */
    402 jitSVShadowRunStart:
    403     mov     r0,rPC                      @ r0<- program counter
    404     mov     r1,rFP                      @ r1<- frame pointer
    405     mov     r2,rSELF                    @ r2<- self (Thread) pointer
    406     mov     r3,r10                      @ r3<- target translation
    407     bl      dvmSelfVerificationSaveState @ save registers to shadow space
    408     ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
    409     bx      r10                         @ jump to the translation
    410 
    411 /*
    412  * Restore PC, registers, and interpreter state to original values
    413  * before jumping back to the interpreter.
    414  * On entry:
    415  *   r0:  dPC
    416  *   r2:  self verification state
    417  */
    418 jitSVShadowRunEnd:
    419     mov    r1,rFP                        @ pass ending fp
    420     mov    r3,rSELF                      @ pass self ptr for convenience
    421     bl     dvmSelfVerificationRestoreState @ restore pc and fp values
    422     LOAD_PC_FP_FROM_SELF()               @ restore pc, fp
    423     ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
    424     cmp    r1,#0                         @ check for punt condition
    425     beq    1f
    426     @ Set up SV single-stepping
    427     mov    r0, rSELF
    428     mov    r1, #kSubModeJitSV
    429     bl     dvmEnableSubMode              @ (self, subMode)
    430     mov    r2,#kJitSelfVerification      @ ask for self verification
    431     str    r2,[rSELF,#offThread_jitState]
    432     @ intentional fallthrough
    433 1:                                       @ exit to interpreter without check
    434     EXPORT_PC()
    435     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
    436     FETCH_INST()
    437     GET_INST_OPCODE(ip)
    438     GOTO_OPCODE(ip)
    439 #endif
    440 
    441 /*
    442  * The equivalent of "goto bail", this calls through the "bail handler".
    443  * It will end this interpreter activation, and return to the caller
    444  * of dvmMterpStdRun.
    445  *
    446  * State registers will be saved to the "thread" area before bailing
    447  * debugging purposes
    448  */
    449 common_gotoBail:
    450     SAVE_PC_FP_TO_SELF()                @ export state to "thread"
    451     mov     r0, rSELF                   @ r0<- self ptr
    452     b       dvmMterpStdBail             @ call(self, changeInterp)
    453 
    454 /*
    455  * The JIT's invoke method needs to remember the callsite class and
    456  * target pair.  Save them here so that they are available to
    457  * dvmCheckJit following the interpretation of this invoke.
    458  */
    459 #if defined(WITH_JIT)
    460 save_callsiteinfo:
    461     cmp     r9, #0
    462     ldrne   r9, [r9, #offObject_clazz]
    463     str     r0, [rSELF, #offThread_methodToCall]
    464     str     r9, [rSELF, #offThread_callsiteClass]
    465     bx      lr
    466 #endif
    467 
    468 /*
    469  * Common code for method invocation with range.
    470  *
    471  * On entry:
    472  *  r0 is "Method* methodToCall", r9 is "this"
    473  */
    474 common_invokeMethodRange:
    475 .LinvokeNewRange:
    476 #if defined(WITH_JIT)
    477     ldrh    r1, [rSELF, #offThread_subMode]
    478     ands    r1, #kSubModeJitTraceBuild
    479     blne    save_callsiteinfo
    480 #endif
    481     @ prepare to copy args to "outs" area of current frame
    482     movs    r2, rINST, lsr #8           @ r2<- AA (arg count) -- test for zero
    483     SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
    484     beq     .LinvokeArgsDone            @ if no args, skip the rest
    485     FETCH(r1, 2)                        @ r1<- CCCC
    486 
    487 .LinvokeRangeArgs:
    488     @ r0=methodToCall, r1=CCCC, r2=count, r10=outs
    489     @ (very few methods have > 10 args; could unroll for common cases)
    490     add     r3, rFP, r1, lsl #2         @ r3<- &fp[CCCC]
    491     sub     r10, r10, r2, lsl #2        @ r10<- "outs" area, for call args
    492 1:  ldr     r1, [r3], #4                @ val = *fp++
    493     subs    r2, r2, #1                  @ count--
    494     str     r1, [r10], #4               @ *outs++ = val
    495     bne     1b                          @ ...while count != 0
    496     b       .LinvokeArgsDone
    497 
    498 /*
    499  * Common code for method invocation without range.
    500  *
    501  * On entry:
    502  *  r0 is "Method* methodToCall", r9 is "this"
    503  */
    504 common_invokeMethodNoRange:
    505 .LinvokeNewNoRange:
    506 #if defined(WITH_JIT)
    507     ldrh    r1, [rSELF, #offThread_subMode]
    508     ands    r1, #kSubModeJitTraceBuild
    509     blne    save_callsiteinfo
    510 #endif
    511     @ prepare to copy args to "outs" area of current frame
    512     movs    r2, rINST, lsr #12          @ r2<- B (arg count) -- test for zero
    513     SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
    514     FETCH(r1, 2)                        @ r1<- GFED (load here to hide latency)
    515     beq     .LinvokeArgsDone
    516 
    517     @ r0=methodToCall, r1=GFED, r2=count, r10=outs
    518 .LinvokeNonRange:
    519     rsb     r2, r2, #5                  @ r2<- 5-r2
    520     add     pc, pc, r2, lsl #4          @ computed goto, 4 instrs each
    521     bl      common_abort                @ (skipped due to ARM prefetch)
    522 5:  and     ip, rINST, #0x0f00          @ isolate A
    523     ldr     r2, [rFP, ip, lsr #6]       @ r2<- vA (shift right 8, left 2)
    524     mov     r0, r0                      @ nop
    525     str     r2, [r10, #-4]!             @ *--outs = vA
    526 4:  and     ip, r1, #0xf000             @ isolate G
    527     ldr     r2, [rFP, ip, lsr #10]      @ r2<- vG (shift right 12, left 2)
    528     mov     r0, r0                      @ nop
    529     str     r2, [r10, #-4]!             @ *--outs = vG
    530 3:  and     ip, r1, #0x0f00             @ isolate F
    531     ldr     r2, [rFP, ip, lsr #6]       @ r2<- vF
    532     mov     r0, r0                      @ nop
    533     str     r2, [r10, #-4]!             @ *--outs = vF
    534 2:  and     ip, r1, #0x00f0             @ isolate E
    535     ldr     r2, [rFP, ip, lsr #2]       @ r2<- vE
    536     mov     r0, r0                      @ nop
    537     str     r2, [r10, #-4]!             @ *--outs = vE
    538 1:  and     ip, r1, #0x000f             @ isolate D
    539     ldr     r2, [rFP, ip, lsl #2]       @ r2<- vD
    540     mov     r0, r0                      @ nop
    541     str     r2, [r10, #-4]!             @ *--outs = vD
    542 0:  @ fall through to .LinvokeArgsDone
    543 
    544 .LinvokeArgsDone: @ r0=methodToCall
    545     ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
    546     ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
    547     ldr     r2, [r0, #offMethod_insns]  @ r2<- method->insns
    548     ldr     rINST, [r0, #offMethod_clazz]  @ rINST<- method->clazz
    549     @ find space for the new stack frame, check for overflow
    550     SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
    551     sub     r1, r1, r9, lsl #2          @ r1<- newFp (old savearea - regsSize)
    552     SAVEAREA_FROM_FP(r10, r1)           @ r10<- newSaveArea
    553 @    bl      common_dumpRegs
    554     ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
    555     sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
    556     cmp     r3, r9                      @ bottom < interpStackEnd?
    557     ldrh    lr, [rSELF, #offThread_subMode]
    558     ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
    559     blo     .LstackOverflow             @ yes, this frame will overflow stack
    560 
    561     @ set up newSaveArea
    562 #ifdef EASY_GDB
    563     SAVEAREA_FROM_FP(ip, rFP)           @ ip<- stack save area
    564     str     ip, [r10, #offStackSaveArea_prevSave]
    565 #endif
    566     str     rFP, [r10, #offStackSaveArea_prevFrame]
    567     str     rPC, [r10, #offStackSaveArea_savedPc]
    568 #if defined(WITH_JIT)
    569     mov     r9, #0
    570     str     r9, [r10, #offStackSaveArea_returnAddr]
    571 #endif
    572     str     r0, [r10, #offStackSaveArea_method]
    573 
    574     @ Profiling?
    575     cmp     lr, #0                      @ any special modes happening?
    576     bne     2f                          @ go if so
    577 1:
    578     tst     r3, #ACC_NATIVE
    579     bne     .LinvokeNative
    580 
    581     /*
    582     stmfd   sp!, {r0-r3}
    583     bl      common_printNewline
    584     mov     r0, rFP
    585     mov     r1, #0
    586     bl      dvmDumpFp
    587     ldmfd   sp!, {r0-r3}
    588     stmfd   sp!, {r0-r3}
    589     mov     r0, r1
    590     mov     r1, r10
    591     bl      dvmDumpFp
    592     bl      common_printNewline
    593     ldmfd   sp!, {r0-r3}
    594     */
    595 
    596     ldrh    r9, [r2]                        @ r9 <- load INST from new PC
    597     ldr     r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
    598     mov     rPC, r2                         @ publish new rPC
    599 
    600     @ Update state values for the new method
    601     @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST
    602     str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
    603     str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
    604     mov     r2, #1
    605     str     r2, [rSELF, #offThread_debugIsMethodEntry]
    606 #if defined(WITH_JIT)
    607     ldr     r0, [rSELF, #offThread_pJitProfTable]
    608     mov     rFP, r1                         @ fp = newFp
    609     GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
    610     mov     rINST, r9                       @ publish new rINST
    611     str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
    612     cmp     r0,#0
    613     bne     common_updateProfile
    614     GOTO_OPCODE(ip)                         @ jump to next instruction
    615 #else
    616     mov     rFP, r1                         @ fp = newFp
    617     GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
    618     mov     rINST, r9                       @ publish new rINST
    619     str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
    620     GOTO_OPCODE(ip)                         @ jump to next instruction
    621 #endif
    622 
    623 2:
    624     @ Profiling - record method entry.  r0: methodToCall
    625     stmfd   sp!, {r0-r3}                @ preserve r0-r3
    626     str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
    627     mov     r1, r0
    628     mov     r0, rSELF
    629     bl      dvmReportInvoke             @ (self, method)
    630     ldmfd   sp!, {r0-r3}                @ restore r0-r3
    631     b       1b
    632 
    633 .LinvokeNative:
    634     @ Prep for the native call
    635     @ r0=methodToCall, r1=newFp, r10=newSaveArea
    636     ldrh    lr, [rSELF, #offThread_subMode]
    637     ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
    638     str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
    639     str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
    640     mov     r2, r0                      @ r2<- methodToCall
    641     mov     r0, r1                      @ r0<- newFp (points to args)
    642     add     r1, rSELF, #offThread_retval  @ r1<- &retval
    643     mov     r3, rSELF                   @ arg3<- self
    644 
    645 #ifdef ASSIST_DEBUGGER
    646     /* insert fake function header to help gdb find the stack frame */
    647     b       .Lskip
    648     .type   dalvik_mterp, %function
    649 dalvik_mterp:
    650     .fnstart
    651     MTERP_ENTRY1
    652     MTERP_ENTRY2
    653 .Lskip:
    654 #endif
    655 
    656     cmp     lr, #0                      @ any special SubModes active?
    657     bne     11f                         @ go handle them if so
    658     ldr     ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
    659     blx     ip
    660 7:
    661 
    662     @ native return; r10=newSaveArea
    663     @ equivalent to dvmPopJniLocals
    664     ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
    665     ldr     r1, [rSELF, #offThread_exception] @ check for exception
    666     str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
    667     cmp     r1, #0                      @ null?
    668     str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
    669     bne     common_exceptionThrown      @ no, handle exception
    670 
    671     FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
    672     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    673     GOTO_OPCODE(ip)                     @ jump to next instruction
    674 
    675 11:
    676     @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes
    677     stmfd   sp!, {r0-r3}                @ save all but subModes
    678     mov     r0, r2                      @ r0<- methodToCall
    679     mov     r1, rSELF
    680     mov     r2, rFP
    681     bl      dvmReportPreNativeInvoke    @ (methodToCall, self, fp)
    682     ldmfd   sp, {r0-r3}                 @ refresh.  NOTE: no sp autoincrement
    683 
    684     @ Call the native method
    685     ldr     ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
    686     blx     ip
    687 
    688     @ Restore the pre-call arguments
    689     ldmfd   sp!, {r0-r3}                @ r2<- methodToCall (others unneeded)
    690 
    691     @ Finish up any post-invoke subMode requirements
    692     mov     r0, r2                      @ r0<- methodToCall
    693     mov     r1, rSELF
    694     mov     r2, rFP
    695     bl      dvmReportPostNativeInvoke   @ (methodToCall, self, fp)
    696     b       7b                          @ resume
    697 
    698 .LstackOverflow:    @ r0=methodToCall
    699     mov     r1, r0                      @ r1<- methodToCall
    700     mov     r0, rSELF                   @ r0<- self
    701     bl      dvmHandleStackOverflow
    702     b       common_exceptionThrown
    703 #ifdef ASSIST_DEBUGGER
    704     .fnend
    705     .size   dalvik_mterp, .-dalvik_mterp
    706 #endif
    707 
    708 
    709     /*
    710      * Common code for method invocation, calling through "glue code".
    711      *
    712      * TODO: now that we have range and non-range invoke handlers, this
    713      *       needs to be split into two.  Maybe just create entry points
    714      *       that set r9 and jump here?
    715      *
    716      * On entry:
    717      *  r0 is "Method* methodToCall", the method we're trying to call
    718      *  r9 is "bool methodCallRange", indicating if this is a /range variant
    719      */
    720      .if    0
    721 .LinvokeOld:
    722     sub     sp, sp, #8                  @ space for args + pad
    723     FETCH(ip, 2)                        @ ip<- FEDC or CCCC
    724     mov     r2, r0                      @ A2<- methodToCall
    725     mov     r0, rSELF                   @ A0<- self
    726     SAVE_PC_FP_TO_SELF()                @ export state to "self"
    727     mov     r1, r9                      @ A1<- methodCallRange
    728     mov     r3, rINST, lsr #8           @ A3<- AA
    729     str     ip, [sp, #0]                @ A4<- ip
    730     bl      dvmMterp_invokeMethod       @ call the C invokeMethod
    731     add     sp, sp, #8                  @ remove arg area
    732     b       common_resumeAfterGlueCall  @ continue to next instruction
    733     .endif
    734 
    735 
    736 
    737 /*
    738  * Common code for handling a return instruction.
    739  *
    740  * This does not return.
    741  */
    742 common_returnFromMethod:
    743 .LreturnNew:
    744     ldrh    lr, [rSELF, #offThread_subMode]
    745     SAVEAREA_FROM_FP(r0, rFP)
    746     ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
    747     cmp     lr, #0                      @ any special subMode handling needed?
    748     bne     19f
    749 14:
    750     ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
    751     ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
    752                                         @ r2<- method we're returning to
    753     cmp     r2, #0                      @ is this a break frame?
    754 #if defined(WORKAROUND_CORTEX_A9_745320)
    755     /* Don't use conditional loads if the HW defect exists */
    756     beq     15f
    757     ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
    758 15:
    759 #else
    760     ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
    761 #endif
    762     beq     common_gotoBail             @ break frame, bail out completely
    763 
    764     ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
    765     PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
    766     str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
    767     ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
    768     str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
    769 #if defined(WITH_JIT)
    770     ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
    771     mov     rPC, r9                     @ publish new rPC
    772     str     r1, [rSELF, #offThread_methodClassDex]
    773     str     r10, [rSELF, #offThread_inJitCodeCache]  @ may return to JIT'ed land
    774     cmp     r10, #0                      @ caller is compiled code
    775     blxne   r10
    776     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    777     GOTO_OPCODE(ip)                     @ jump to next instruction
    778 #else
    779     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    780     mov     rPC, r9                     @ publish new rPC
    781     str     r1, [rSELF, #offThread_methodClassDex]
    782     GOTO_OPCODE(ip)                     @ jump to next instruction
    783 #endif
    784 
    785 19:
    786     @ Handle special actions
    787     @ On entry, r0: StackSaveArea
    788     ldr     r1, [r0, #offStackSaveArea_prevFrame]  @ r2<- prevFP
    789     str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
    790     str     r1, [rSELF, #offThread_curFrame]   @ update interpSave.curFrame
    791     mov     r0, rSELF
    792     bl      dvmReportReturn             @ (self)
    793     SAVEAREA_FROM_FP(r0, rFP)           @ restore StackSaveArea
    794     b       14b                         @ continue
    795 
    796     /*
    797      * Return handling, calls through "glue code".
    798      */
    799      .if    0
    800 .LreturnOld:
    801     SAVE_PC_FP_TO_SELF()                @ export state
    802     mov     r0, rSELF                   @ arg to function
    803     bl      dvmMterp_returnFromMethod
    804     b       common_resumeAfterGlueCall
    805     .endif
    806 
    807 
    808 /*
    809  * Somebody has thrown an exception.  Handle it.
    810  *
    811  * If the exception processing code returns to us (instead of falling
    812  * out of the interpreter), continue with whatever the next instruction
    813  * now happens to be.
    814  *
    815  * This does not return.
    816  */
    817      .global dvmMterpCommonExceptionThrown
    818 dvmMterpCommonExceptionThrown:
    819 common_exceptionThrown:
    820 .LexceptionNew:
    821 
    822     EXPORT_PC()
    823 
    824     mov     r0, rSELF
    825     bl      dvmCheckSuspendPending
    826 
    827     ldr     r9, [rSELF, #offThread_exception] @ r9<- self->exception
    828     mov     r1, rSELF                   @ r1<- self
    829     mov     r0, r9                      @ r0<- exception
    830     bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
    831     ldrh    r2, [rSELF, #offThread_subMode]  @ get subMode flags
    832     mov     r3, #0                      @ r3<- NULL
    833     str     r3, [rSELF, #offThread_exception] @ self->exception = NULL
    834 
    835     @ Special subMode?
    836     cmp     r2, #0                      @ any special subMode handling needed?
    837     bne     7f                          @ go if so
    838 8:
    839     /* set up args and a local for "&fp" */
    840     /* (str sp, [sp, #-4]!  would be perfect here, but is discouraged) */
    841     str     rFP, [sp, #-4]!             @ *--sp = fp
    842     mov     ip, sp                      @ ip<- &fp
    843     mov     r3, #0                      @ r3<- false
    844     str     ip, [sp, #-4]!              @ *--sp = &fp
    845     ldr     r1, [rSELF, #offThread_method] @ r1<- self->method
    846     mov     r0, rSELF                   @ r0<- self
    847     ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
    848     mov     r2, r9                      @ r2<- exception
    849     sub     r1, rPC, r1                 @ r1<- pc - method->insns
    850     mov     r1, r1, asr #1              @ r1<- offset in code units
    851 
    852     /* call, r0 gets catchRelPc (a code-unit offset) */
    853     bl      dvmFindCatchBlock           @ call(self, relPc, exc, scan?, &fp)
    854 
    855     /* fix earlier stack overflow if necessary; may trash rFP */
    856     ldrb    r1, [rSELF, #offThread_stackOverflowed]
    857     cmp     r1, #0                      @ did we overflow earlier?
    858     beq     1f                          @ no, skip ahead
    859     mov     rFP, r0                     @ save relPc result in rFP
    860     mov     r0, rSELF                   @ r0<- self
    861     mov     r1, r9                      @ r1<- exception
    862     bl      dvmCleanupStackOverflow     @ call(self)
    863     mov     r0, rFP                     @ restore result
    864 1:
    865 
    866     /* update frame pointer and check result from dvmFindCatchBlock */
    867     ldr     rFP, [sp, #4]               @ retrieve the updated rFP
    868     cmp     r0, #0                      @ is catchRelPc < 0?
    869     add     sp, sp, #8                  @ restore stack
    870     bmi     .LnotCaughtLocally
    871 
    872     /* adjust locals to match self->interpSave.curFrame and updated PC */
    873     SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
    874     ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
    875     str     r1, [rSELF, #offThread_method]  @ self->method = new method
    876     ldr     r2, [r1, #offMethod_clazz]      @ r2<- method->clazz
    877     ldr     r3, [r1, #offMethod_insns]      @ r3<- method->insns
    878     ldr     r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
    879     add     rPC, r3, r0, asl #1             @ rPC<- method->insns + catchRelPc
    880     str     r2, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
    881 
    882     /* release the tracked alloc on the exception */
    883     mov     r0, r9                      @ r0<- exception
    884     mov     r1, rSELF                   @ r1<- self
    885     bl      dvmReleaseTrackedAlloc      @ release the exception
    886 
    887     /* restore the exception if the handler wants it */
    888     ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
    889     FETCH_INST()                        @ load rINST from rPC
    890     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    891     cmp     ip, #OP_MOVE_EXCEPTION      @ is it "move-exception"?
    892     streq   r9, [rSELF, #offThread_exception] @ yes, restore the exception
    893     GOTO_OPCODE(ip)                     @ jump to next instruction
    894 
    895     @ Manage debugger bookkeeping
    896 7:
    897     str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
    898     str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
    899     mov     r0, rSELF                       @ arg0<- self
    900     mov     r1, r9                          @ arg1<- exception
    901     bl      dvmReportExceptionThrow         @ (self, exception)
    902     b       8b                              @ resume with normal handling
    903 
    904 .LnotCaughtLocally: @ r9=exception
    905     /* fix stack overflow if necessary */
    906     ldrb    r1, [rSELF, #offThread_stackOverflowed]
    907     cmp     r1, #0                      @ did we overflow earlier?
    908     movne   r0, rSELF                   @ if yes: r0<- self
    909     movne   r1, r9                      @ if yes: r1<- exception
    910     blne    dvmCleanupStackOverflow     @ if yes: call(self)
    911 
    912     @ may want to show "not caught locally" debug messages here
    913 #if DVM_SHOW_EXCEPTION >= 2
    914     /* call __android_log_print(prio, tag, format, ...) */
    915     /* "Exception %s from %s:%d not caught locally" */
    916     @ dvmLineNumFromPC(method, pc - method->insns)
    917     ldr     r0, [rSELF, #offThread_method]
    918     ldr     r1, [r0, #offMethod_insns]
    919     sub     r1, rPC, r1
    920     asr     r1, r1, #1
    921     bl      dvmLineNumFromPC
    922     str     r0, [sp, #-4]!
    923     @ dvmGetMethodSourceFile(method)
    924     ldr     r0, [rSELF, #offThread_method]
    925     bl      dvmGetMethodSourceFile
    926     str     r0, [sp, #-4]!
    927     @ exception->clazz->descriptor
    928     ldr     r3, [r9, #offObject_clazz]
    929     ldr     r3, [r3, #offClassObject_descriptor]
    930     @
    931     ldr     r2, strExceptionNotCaughtLocally
    932 0:  add     r2, pc
    933     ldr     r1, strLogTag
    934 1:  add     r1, pc
    935     mov     r0, #3                      @ LOG_DEBUG
    936     bl      __android_log_print
    937 #endif
    938     str     r9, [rSELF, #offThread_exception] @ restore exception
    939     mov     r0, r9                      @ r0<- exception
    940     mov     r1, rSELF                   @ r1<- self
    941     bl      dvmReleaseTrackedAlloc      @ release the exception
    942     b       common_gotoBail             @ bail out
    943 
    944 strExceptionNotCaughtLocally:
    945     .word   PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
    946 strLogTag:
    947     .word   PCREL_REF(.LstrLogTag,1b)
    948 
    949     /*
    950      * Exception handling, calls through "glue code".
    951      */
    952     .if     0
    953 .LexceptionOld:
    954     SAVE_PC_FP_TO_SELF()                @ export state
    955     mov     r0, rSELF                   @ arg to function
    956     bl      dvmMterp_exceptionThrown
    957     b       common_resumeAfterGlueCall
    958     .endif
    959 
    960 #if defined(WITH_JIT)
    961     /*
    962      * If the JIT is actively building a trace we need to make sure
    963      * that the field is fully resolved before including the current
    964      * instruction.
    965      *
    966      * On entry:
    967      *     r10: &dvmDex->pResFields[field]
    968      *     r0:  field pointer (must preserve)
    969      */
    970 common_verifyField:
    971     ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
    972     ands    r3, #kSubModeJitTraceBuild
    973     bxeq    lr                          @ Not building trace, continue
    974     ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
    975     cmp     r1, #0                      @ resolution complete?
    976     bxne    lr                          @ yes, continue
    977     stmfd   sp!, {r0-r2,lr}             @ save regs
    978     mov     r0, rSELF
    979     mov     r1, rPC
    980     bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
    981     ldmfd   sp!, {r0-r2, lr}
    982     bx      lr                          @ return
    983 #endif
    984 
    985 /*
    986  * After returning from a "glued" function, pull out the updated
    987  * values and start executing at the next instruction.
    988  */
    989 common_resumeAfterGlueCall:
    990     LOAD_PC_FP_FROM_SELF()              @ pull rPC and rFP out of thread
    991     ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
    992     FETCH_INST()                        @ load rINST from rPC
    993     GET_INST_OPCODE(ip)                 @ extract opcode from rINST
    994     GOTO_OPCODE(ip)                     @ jump to next instruction
    995 
    996 /*
    997  * Invalid array index. Note that our calling convention is strange; we use r1
    998  * and r3 because those just happen to be the registers all our callers are
    999  * using. We move r3 before calling the C function, but r1 happens to match.
   1000  * r1: index
   1001  * r3: size
   1002  */
   1003 common_errArrayIndex:
   1004     EXPORT_PC()
   1005     mov     r0, r3
   1006     bl      dvmThrowArrayIndexOutOfBoundsException
   1007     b       common_exceptionThrown
   1008 
   1009 /*
   1010  * Integer divide or mod by zero.
   1011  */
   1012 common_errDivideByZero:
   1013     EXPORT_PC()
   1014     ldr     r0, strDivideByZero
   1015 0:  add     r0, pc
   1016     bl      dvmThrowArithmeticException
   1017     b       common_exceptionThrown
   1018 
   1019 strDivideByZero:
   1020     .word   PCREL_REF(.LstrDivideByZero,0b)
   1021 
   1022 /*
   1023  * Attempt to allocate an array with a negative size.
   1024  * On entry: length in r1
   1025  */
   1026 common_errNegativeArraySize:
   1027     EXPORT_PC()
   1028     mov     r0, r1                                @ arg0 <- len
   1029     bl      dvmThrowNegativeArraySizeException    @ (len)
   1030     b       common_exceptionThrown
   1031 
   1032 /*
   1033  * Invocation of a non-existent method.
   1034  * On entry: method name in r1
   1035  */
   1036 common_errNoSuchMethod:
   1037     EXPORT_PC()
   1038     mov     r0, r1
   1039     bl      dvmThrowNoSuchMethodError
   1040     b       common_exceptionThrown
   1041 
   1042 /*
   1043  * We encountered a null object when we weren't expecting one.  We
   1044  * export the PC, throw a NullPointerException, and goto the exception
   1045  * processing code.
   1046  */
   1047 common_errNullObject:
   1048     EXPORT_PC()
   1049     mov     r0, #0
   1050     bl      dvmThrowNullPointerException
   1051     b       common_exceptionThrown
   1052 
   1053 /*
   1054  * For debugging, cause an immediate fault.  The source address will
   1055  * be in lr (use a bl instruction to jump here).
   1056  */
   1057 common_abort:
   1058     ldr     pc, .LdeadFood
   1059 .LdeadFood:
   1060     .word   0xdeadf00d
   1061 
   1062 /*
   1063  * Spit out a "we were here", preserving all registers.  (The attempt
   1064  * to save ip won't work, but we need to save an even number of
   1065  * registers for EABI 64-bit stack alignment.)
   1066  */
   1067     .macro  SQUEAK num
   1068 common_squeak\num:
   1069     stmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1070     ldr     r0, strSqueak\num
   1071 0:  add     r0, pc
   1072     mov     r1, #\num
   1073     bl      printf
   1074     ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1075     bx      lr
   1076 
   1077 strSqueak\num:
   1078     .word   PCREL_REF(.LstrSqueak,0b)
   1079     .endm
   1080 
   1081     SQUEAK  0
   1082     SQUEAK  1
   1083     SQUEAK  2
   1084     SQUEAK  3
   1085     SQUEAK  4
   1086     SQUEAK  5
   1087 
   1088 /*
   1089  * Spit out the number in r0, preserving registers.
   1090  */
   1091 common_printNum:
   1092     stmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1093     mov     r1, r0
   1094     ldr     r0, strSqueak
   1095 0:  add     r0, pc
   1096     bl      printf
   1097     ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1098     bx      lr
   1099 
   1100 strSqueak:
   1101     .word   PCREL_REF(.LstrSqueak,0b)
   1102 
   1103 /*
   1104  * Print a newline, preserving registers.
   1105  */
   1106 common_printNewline:
   1107     stmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1108     ldr     r0, strNewline
   1109 0:  add     r0, pc
   1110     bl      printf
   1111     ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1112     bx      lr
   1113 
   1114 strNewline:
   1115     .word   PCREL_REF(.LstrNewline,0b)
   1116 
   1117     /*
   1118      * Print the 32-bit quantity in r0 as a hex value, preserving registers.
   1119      */
   1120 common_printHex:
   1121     stmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1122     mov     r1, r0
   1123     ldr     r0, strPrintHex
   1124 0:  add     r0, pc
   1125     bl      printf
   1126     ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1127     bx      lr
   1128 
   1129 strPrintHex:
   1130     .word   PCREL_REF(.LstrPrintHex,0b)
   1131 
   1132 /*
   1133  * Print the 64-bit quantity in r0-r1, preserving registers.
   1134  */
   1135 common_printLong:
   1136     stmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1137     mov     r3, r1
   1138     mov     r2, r0
   1139     ldr     r0, strPrintLong
   1140 0:  add     r0, pc
   1141     bl      printf
   1142     ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1143     bx      lr
   1144 
   1145 strPrintLong:
   1146     .word   PCREL_REF(.LstrPrintLong,0b)
   1147 
   1148 /*
   1149  * Print full method info.  Pass the Method* in r0.  Preserves regs.
   1150  */
   1151 common_printMethod:
   1152     stmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1153     bl      dvmMterpPrintMethod
   1154     ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1155     bx      lr
   1156 
   1157 /*
   1158  * Call a C helper function that dumps regs and possibly some
   1159  * additional info.  Requires the C function to be compiled in.
   1160  */
   1161     .if     0
   1162 common_dumpRegs:
   1163     stmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1164     bl      dvmMterpDumpArmRegs
   1165     ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
   1166     bx      lr
   1167     .endif
   1168 
   1169 #if 0
   1170 /*
   1171  * Experiment on VFP mode.
   1172  *
   1173  * uint32_t setFPSCR(uint32_t val, uint32_t mask)
   1174  *
   1175  * Updates the bits specified by "mask", setting them to the values in "val".
   1176  */
   1177 setFPSCR:
   1178     and     r0, r0, r1                  @ make sure no stray bits are set
   1179     fmrx    r2, fpscr                   @ get VFP reg
   1180     mvn     r1, r1                      @ bit-invert mask
   1181     and     r2, r2, r1                  @ clear masked bits
   1182     orr     r2, r2, r0                  @ set specified bits
   1183     fmxr    fpscr, r2                   @ set VFP reg
   1184     mov     r0, r2                      @ return new value
   1185     bx      lr
   1186 
   1187     .align  2
   1188     .global dvmConfigureFP
   1189     .type   dvmConfigureFP, %function
   1190 dvmConfigureFP:
   1191     stmfd   sp!, {ip, lr}
   1192     /* 0x03000000 sets DN/FZ */
   1193     /* 0x00009f00 clears the six exception enable flags */
   1194     bl      common_squeak0
   1195     mov     r0, #0x03000000             @ r0<- 0x03000000
   1196     add     r1, r0, #0x9f00             @ r1<- 0x03009f00
   1197     bl      setFPSCR
   1198     ldmfd   sp!, {ip, pc}
   1199 #endif
   1200 
   1201 
   1202 
   1203 /*
   1204  * Zero-terminated ASCII string data.
   1205  *
   1206  * On ARM we have two choices: do like gcc does, and LDR from a .word
   1207  * with the address, or use an ADR pseudo-op to get the address
   1208  * directly.  ADR saves 4 bytes and an indirection, but it's using a
   1209  * PC-relative addressing mode and hence has a limited range, which
   1210  * makes it not work well with mergeable string sections.
   1211  */
   1212     .section .rodata.str1.4,"aMS",%progbits,1
   1213 
   1214 .LstrBadEntryPoint:
   1215     .asciz  "Bad entry point %d\n"
   1216 .LstrFilledNewArrayNotImpl:
   1217     .asciz  "filled-new-array only implemented for objects and 'int'"
   1218 .LstrDivideByZero:
   1219     .asciz  "divide by zero"
   1220 .LstrLogTag:
   1221     .asciz  "mterp"
   1222 .LstrExceptionNotCaughtLocally:
   1223     .asciz  "Exception %s from %s:%d not caught locally\n"
   1224 
   1225 .LstrNewline:
   1226     .asciz  "\n"
   1227 .LstrSqueak:
   1228     .asciz  "<%d>"
   1229 .LstrPrintHex:
   1230     .asciz  "<%#x>"
   1231 .LstrPrintLong:
   1232     .asciz  "<%lld>"
   1233