Home | History | Annotate | Download | only in x86
      1 /*
      2  * Copyright (C) 2008 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  * Common subroutines and data.
     18  */
     19 
     20 #if defined(WITH_JIT)
     21 /*
     22  * JIT-related re-entries into the interpreter.  In general, if the
     23  * exit from a translation can at some point be chained, the entry
     24  * here requires that control arrived via a call, and that the "rp"
     25  * on TOS is actually a pointer to a 32-bit cell containing the Dalvik PC
     26  * of the next insn to handle.  If no chaining will happen, the entry
     27  * should be reached via a direct jump and rPC set beforehand.
     28  */
     29 
     30     .global dvmJitToInterpPunt
     31 /*
     32  * The compiler will generate a jump to this entry point when it is
     33  * having difficulty translating a Dalvik instruction.  We must skip
     34  * the code cache lookup & prevent chaining to avoid bouncing between
     35  * the interpreter and code cache. rPC must be set on entry.
     36  */
     37 dvmJitToInterpPunt:
     38 #if defined(WITH_JIT_TUNING)
     39     movl   rPC, OUT_ARG0(%esp)
     40     call   dvmBumpPunt
     41 #endif
     42     movl   rSELF, %ecx
     43     movl   offThread_curHandlerTable(%ecx),rIBASE
     44     FETCH_INST_R %ecx
     45     GOTO_NEXT_R %ecx
     46 
     47     .global dvmJitToInterpSingleStep
     48 /*
     49  * Return to the interpreter to handle a single instruction.
     50  * Should be reached via a call.
     51  * On entry:
     52  *   0(%esp)          <= native return address within trace
     53  *   rPC              <= Dalvik PC of this instruction
     54  *   OUT_ARG0+4(%esp) <= Dalvik PC of next instruction
     55  */
     56 dvmJitToInterpSingleStep:
     57 /* TODO */
     58     call     dvmAbort
     59 #if 0
     60     pop    %eax
     61     movl   rSELF, %ecx
     62     movl   OUT_ARG0(%esp), %edx
     63     movl   %eax,offThread_jitResumeNPC(%ecx)
     64     movl   %edx,offThread_jitResumeDPC(%ecx)
     65     movl   $$kInterpEntryInstr,offThread_entryPoint(%ecx)
     66     movl   $$1,rINST     # changeInterp <= true
     67     jmp    common_gotoBail
     68 #endif
     69 
     70     .global dvmJitToInterpNoChainNoProfile
     71 /*
     72  * Return from the translation cache to the interpreter to do method
     73  * invocation.  Check if the translation exists for the callee, but don't
     74  * chain to it. rPC must be set on entry.
     75  */
     76 dvmJitToInterpNoChainNoProfile:
     77 #if defined(WITH_JIT_TUNING)
     78     call   dvmBumpNoChain
     79 #endif
     80     movl   rSELF, %eax
     81     movl   rPC,OUT_ARG0(%esp)
     82     movl   %eax,OUT_ARG1(%esp)
     83     call   dvmJitGetTraceAddrThread        # (pc, self)
     84     movl   rSELF,%ecx                # ecx <- self
     85     movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
     86     cmpl   $$0, %eax
     87     jz     1f
     88     call   *%eax                     # exec translation if we've got one
     89     # won't return
     90 1:
     91     movl   rSELF, %ecx
     92     movl   offThread_curHandlerTable(%ecx),rIBASE
     93     FETCH_INST_R %ecx
     94     GOTO_NEXT_R %ecx
     95 
     96 /*
     97  * Return from the translation cache and immediately request a
     98  * translation fro the exit target, but don't attempt to chain.
     99  * rPC set on entry.
    100  */
    101     .global dvmJitToInterpTraceSelectNoChain
    102 dvmJitToInterpTraceSelectNoChain:
    103 #if defined(WITH_JIT_TUNING)
    104     call   dvmBumpNoChain
    105 #endif
    106     movl   rSELF, %eax
    107     movl   rPC,OUT_ARG0(%esp)
    108     movl   %eax,OUT_ARG1(%esp)
    109     call   dvmJitGetTraceAddrThread # (pc, self)
    110     movl   rSELF,%ecx
    111     cmpl   $$0,%eax
    112     movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
    113     jz     1f
    114     call   *%eax              # jump to tranlation
    115     # won't return
    116 
    117 /* No Translation - request one */
    118 1:
    119     GET_JIT_PROF_TABLE %ecx %eax
    120     cmpl   $$0, %eax          # JIT enabled?
    121     jnz    2f                 # Request one if so
    122     movl   rSELF, %ecx
    123     movl   offThread_curHandlerTable(%ecx),rIBASE
    124     FETCH_INST_R %ecx         # Continue interpreting if not
    125     GOTO_NEXT_R %ecx
    126 2:
    127     movl   $$kJitTSelectRequestHot,rINST  # ask for trace select
    128     jmp    common_selectTrace
    129 
    130 /*
    131  * Return from the translation cache and immediately request a
    132  * translation for the exit target.  Reached via a call, and
    133  * (TOS)->rPC.
    134  */
    135     .global dvmJitToInterpTraceSelect
    136 dvmJitToInterpTraceSelect:
    137     pop    rINST           # save chain cell address in callee save reg
    138     movl   (rINST),rPC
    139     movl   rSELF, %eax
    140     movl   rPC,OUT_ARG0(%esp)
    141     movl   %eax,OUT_ARG1(%esp)
    142     call   dvmJitGetTraceAddrThread # (pc, self)
    143     cmpl   $$0,%eax
    144     jz     1b                 # no - ask for one
    145     movl   %eax,OUT_ARG0(%esp)
    146 # TODO - need to adjust rINST to beginning of sequence
    147     movl   rINST,OUT_ARG1(%esp)
    148     call   dvmJitChain        # Attempt dvmJitChain(codeAddr,chainAddr)
    149     cmpl   $$0,%eax           # Success?
    150     jz     toInterpreter      # didn't chain - interpret
    151     call   *%eax
    152     # won't return
    153 
    154 /*
    155  * Placeholder entries for x86 JIT
    156  */
    157     .global dvmJitToInterpBackwardBranch
    158 dvmJitToInterpBackwardBranch:
    159     .global dvmJitToInterpNormal
    160 dvmJitToInterpNormal:
    161     .global dvmJitToInterpNoChain
    162 dvmJitToInterpNoChain:
    163 toInterpreter:
    164     jmp  common_abort
    165 
    166 common_updateProfile:
    167     # quick & dirty hash
    168     movl   rPC, %eax
    169     shrl   $$12, %eax
    170     xorl   rPC, %eax
    171     andl   $$((1<<JIT_PROF_SIZE_LOG_2)-1),%eax
    172     decb   (%edx,%eax)
    173     jz     2f
    174 1:
    175     GOTO_NEXT
    176 2:
    177 /*
    178  * Here, we switch to the debug interpreter to request
    179  * trace selection.  First, though, check to see if there
    180  * is already a native translation in place (and, if so,
    181  * jump to it now.
    182  */
    183     GET_JIT_THRESHOLD %ecx rINST  # leaves rSELF in %ecx
    184     EXPORT_PC
    185     movb   rINSTbl,(%edx,%eax)   # reset counter
    186     movl   %ecx,rINST            # preserve rSELF
    187     movl   rSELF, %eax
    188     movl   rPC,OUT_ARG0(%esp)
    189     movl   %eax,OUT_ARG1(%esp)
    190     call   dvmJitGetTraceAddr  # (pc, self)
    191     movl   %eax,offThread_inJitCodeCache(rINST)   # set the inJitCodeCache flag
    192     cmpl   $$0,%eax
    193     jz     1f
    194     call   *%eax        # TODO: decide call vs/ jmp!.  No return either way
    195 1:
    196     movl   $$kJitTSelectRequest,%eax
    197     # On entry, eax<- jitState, rPC valid
    198 common_selectTrace:
    199 /* TODO */
    200     call   dvmAbort
    201 #if 0
    202     movl   rSELF,%ecx
    203     movl   %eax,offThread_jitState(%ecx)
    204     movl   $$kInterpEntryInstr,offThread_entryPoint(%ecx)
    205     movl   $$1,rINST
    206     jmp    common_gotoBail
    207 #endif
    208 #endif
    209 
    210 
    211 
    212 /*
    213  * Common code for method invocation with range.
    214  *
    215  * On entry:
    216  *   eax = Method* methodToCall
    217  *   rINSTw trashed, must reload
    218  *   rIBASE trashed, must reload before resuming interpreter
    219  */
    220 
    221 common_invokeMethodRange:
    222 .LinvokeNewRange:
    223 
    224    /*
    225     * prepare to copy args to "outs" area of current frame
    226     */
    227 
    228     movzbl      1(rPC),rINST       # rINST<- AA
    229     movzwl      4(rPC), %ecx            # %ecx<- CCCC
    230     SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
    231     test        rINST, rINST
    232     movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
    233     jz          .LinvokeArgsDone        # no args; jump to args done
    234 
    235 
    236    /*
    237     * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count,
    238     * %edx=&outs (&stackSaveArea).  (very few methods have > 10 args;
    239     * could unroll for common cases)
    240     */
    241 
    242 .LinvokeRangeArgs:
    243     movl        %ebx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- save %ebx
    244     lea         (rFP, %ecx, 4), %ecx    # %ecx<- &vCCCC
    245     shll        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
    246     subl        LOCAL0_OFFSET(%ebp), %edx       # %edx<- update &outs
    247     shrl        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
    248 1:
    249     movl        (%ecx), %ebx            # %ebx<- vCCCC
    250     lea         4(%ecx), %ecx           # %ecx<- &vCCCC++
    251     subl        $$1, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET<- LOCAL0_OFFSET--
    252     movl        %ebx, (%edx)            # *outs<- vCCCC
    253     lea         4(%edx), %edx           # outs++
    254     jne         1b                      # loop if count (LOCAL0_OFFSET(%ebp)) not zero
    255     movl        LOCAL1_OFFSET(%ebp), %ebx       # %ebx<- restore %ebx
    256     jmp         .LinvokeArgsDone        # continue
    257 
    258    /*
    259     * %eax is "Method* methodToCall", the method we're trying to call
    260     * prepare to copy args to "outs" area of current frame
    261     * rIBASE trashed, must reload before resuming interpreter
    262     */
    263 
    264 common_invokeMethodNoRange:
    265 .LinvokeNewNoRange:
    266     movzbl      1(rPC),rINST       # rINST<- BA
    267     movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
    268     shrl        $$4, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- B
    269     je          .LinvokeArgsDone        # no args; jump to args done
    270     movzwl      4(rPC), %ecx            # %ecx<- GFED
    271     SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
    272 
    273    /*
    274     * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
    275     */
    276 
    277 .LinvokeNonRange:
    278     cmp         $$2, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 2
    279     movl        %ecx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- GFED
    280     jl          1f                      # handle 1 arg
    281     je          2f                      # handle 2 args
    282     cmp         $$4, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 4
    283     jl          3f                      # handle 3 args
    284     je          4f                      # handle 4 args
    285 5:
    286     andl        $$15, rINST             # rINSTw<- A
    287     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    288     movl        (rFP, rINST, 4), %ecx   # %ecx<- vA
    289     movl        %ecx, (%edx)            # *outs<- vA
    290     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    291 4:
    292     shr         $$12, %ecx              # %ecx<- G
    293     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    294     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vG
    295     movl        %ecx, (%edx)            # *outs<- vG
    296     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    297 3:
    298     and         $$0x0f00, %ecx          # %ecx<- 0F00
    299     shr         $$8, %ecx               # %ecx<- F
    300     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    301     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vF
    302     movl        %ecx, (%edx)            # *outs<- vF
    303     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    304 2:
    305     and         $$0x00f0, %ecx          # %ecx<- 00E0
    306     shr         $$4, %ecx               # %ecx<- E
    307     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    308     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vE
    309     movl        %ecx, (%edx)            # *outs<- vE
    310     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    311 1:
    312     and         $$0x000f, %ecx          # %ecx<- 000D
    313     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vD
    314     movl        %ecx, -4(%edx)          # *--outs<- vD
    315 0:
    316 
    317    /*
    318     * %eax is "Method* methodToCall", the method we're trying to call
    319     * find space for the new stack frame, check for overflow
    320     */
    321 
    322 .LinvokeArgsDone:
    323     movzwl      offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
    324     movzwl      offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
    325     movl        %eax, LOCAL0_OFFSET(%ebp)       # LOCAL0_OFFSET<- methodToCall
    326     shl         $$2, %edx               # %edx<- update offset
    327     SAVEAREA_FROM_FP %eax               # %eax<- &StackSaveArea
    328     subl        %edx, %eax              # %eax<- newFP; (old savearea - regsSize)
    329     movl        rSELF,%edx              # %edx<- pthread
    330     movl        %eax, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- &outs
    331     subl        $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
    332     movl        offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd
    333     movl        %edx, TMP_SPILL1(%ebp)  # spill self->interpStackEnd
    334     shl         $$2, %ecx               # %ecx<- update offset for outsSize
    335     movl        %eax, %edx              # %edx<- newSaveArea
    336     sub         %ecx, %eax              # %eax<- bottom; (newSaveArea - outsSize)
    337     cmp         TMP_SPILL1(%ebp), %eax  # compare interpStackEnd and bottom
    338     movl        LOCAL0_OFFSET(%ebp), %eax       # %eax<- restore methodToCall
    339     jl          .LstackOverflow         # handle frame overflow
    340 
    341    /*
    342     * set up newSaveArea
    343     */
    344 
    345 #ifdef EASY_GDB
    346     SAVEAREA_FROM_FP %ecx               # %ecx<- &StackSaveArea
    347     movl        %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
    348 #endif
    349     movl        rSELF,%ecx              # %ecx<- pthread
    350     movl        rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
    351     movl        rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
    352 
    353     /* Any special actions to take? */
    354     cmpw        $$0, offThread_subMode(%ecx)
    355     jne         2f                     # Yes - handle them
    356 1:
    357     testl       $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
    358     movl        %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
    359     jne         .LinvokeNative          # handle native call
    360 
    361    /*
    362     * Update "self" values for the new method
    363     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
    364     */
    365     movl        offMethod_clazz(%eax), %edx # %edx<- method->clazz
    366     movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
    367     movl        %eax, offThread_method(%ecx) # self->method<- methodToCall
    368     movl        %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex
    369     movl        offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
    370     movl        $$1, offThread_debugIsMethodEntry(%ecx)
    371     movl        LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
    372     movl        rFP, offThread_curFrame(%ecx) # curFrame<-newFP
    373     movl        offThread_curHandlerTable(%ecx),rIBASE
    374     FETCH_INST
    375     GOTO_NEXT                           # jump to methodToCall->insns
    376 
    377 2:
    378     /*
    379      * On entry, preserve all:
    380      *  %eax: method
    381      *  %ecx: self
    382      *  %edx: new save area
    383      */
    384     SPILL_TMP1(%eax)                   # preserve methodToCall
    385     SPILL_TMP2(%edx)                   # preserve newSaveArea
    386     movl        rPC, offThread_pc(%ecx) # update interpSave.pc
    387     movl        %ecx, OUT_ARG0(%esp)
    388     movl        %eax, OUT_ARG1(%esp)
    389     call        dvmReportInvoke        # (self, method)
    390     UNSPILL_TMP1(%eax)
    391     UNSPILL_TMP2(%edx)
    392     movl        rSELF,%ecx             # restore rSELF
    393     jmp         1b
    394 
    395    /*
    396     * Prep for the native call
    397     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
    398     */
    399 
    400 .LinvokeNative:
    401     movl        offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->...
    402     movl        rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
    403     movl        %edx, LOCAL2_OFFSET(%ebp)  # save newSaveArea
    404     movl        LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP
    405     movl        rINST, offThread_curFrame(%ecx)  # curFrame<- newFP
    406     cmpw        $$0, offThread_subMode(%ecx)  # Anything special going on?
    407     jne         11f                     # yes - handle it
    408     movl        %ecx, OUT_ARG3(%esp)    # push parameter self
    409     movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
    410     lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
    411     movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
    412     movl        rINST, OUT_ARG0(%esp)    # push parameter newFP
    413     call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
    414 7:
    415     movl        LOCAL2_OFFSET(%ebp), %ecx    # %ecx<- newSaveArea
    416     movl        rSELF, %eax             # %eax<- self
    417     movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
    418     cmp         $$0, offThread_exception(%eax) # check for exception
    419     movl        rFP, offThread_curFrame(%eax) # curFrame<- rFP
    420     movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
    421     jne         common_exceptionThrown  # handle exception
    422     movl        offThread_curHandlerTable(%eax),rIBASE
    423     FETCH_INST_OPCODE 3 %ecx
    424     ADVANCE_PC 3
    425     GOTO_NEXT_R %ecx                    # jump to next instruction
    426 
    427 11:
    428     /*
    429      * Handle any special subMode actions
    430      * %eax=methodToCall, rINST=newFP, %ecx=self
    431      */
    432     SPILL_TMP1(%eax)                    # save methodTocall
    433     movl        rPC, offThread_pc(%ecx)
    434     movl        %eax, OUT_ARG0(%esp)
    435     movl        %ecx, OUT_ARG1(%esp)
    436     movl        rFP, OUT_ARG2(%esp)
    437     call        dvmReportPreNativeInvoke # (methodToCall, self, fp)
    438     UNSPILL_TMP1(%eax)                  # restore methodToCall
    439     movl        rSELF,%ecx              # restore self
    440 
    441     /* Do the native call */
    442     movl        %ecx, OUT_ARG3(%esp)    # push parameter self
    443     lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
    444     movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
    445     movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
    446     movl        rINST, OUT_ARG0(%esp)   # push parameter newFP
    447     call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
    448 
    449     UNSPILL_TMP1(%eax)                  # restore methodToCall
    450     movl        rSELF, %ecx
    451     movl        %eax, OUT_ARG0(%esp)
    452     movl        %ecx, OUT_ARG1(%esp)
    453     movl        rFP, OUT_ARG2(%esp)
    454     call        dvmReportPostNativeInvoke # (methodToCall, self, fp)
    455     jmp         7b                      # rejoin
    456 
    457 .LstackOverflow:    # eax=methodToCall
    458     movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
    459     movl        rSELF,%eax              # %eax<- self
    460     movl        %eax, OUT_ARG0(%esp)    # push parameter self
    461     call        dvmHandleStackOverflow  # call: (Thread* self, Method* meth)
    462     jmp         common_exceptionThrown  # handle exception
    463 
    464 
    465 /*
    466  * Common code for handling a return instruction
    467  */
    468 common_returnFromMethod:
    469     movl    rSELF,%ecx
    470     SAVEAREA_FROM_FP %eax                         # eax<- saveArea (old)
    471     cmpw    $$0, offThread_subMode(%ecx)          # special action needed?
    472     jne     19f                                   # go if so
    473 14:
    474     movl    offStackSaveArea_prevFrame(%eax),rFP  # rFP<- prevFrame
    475     movl    (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
    476     cmpl    $$0,rINST                             # break?
    477     je      common_gotoBail    # break frame, bail out completely
    478 
    479     movl    offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
    480     movl    rINST,offThread_method(%ecx)       # self->method = newSave->meethod
    481     movl    rFP,offThread_curFrame(%ecx)       # curFrame = fp
    482     movl    offMethod_clazz(rINST),%eax        # eax<- method->clazz
    483     movl    offThread_curHandlerTable(%ecx),rIBASE
    484     movl    offClassObject_pDvmDex(%eax),rINST # rINST<- method->clazz->pDvmDex
    485     FETCH_INST_OPCODE 3 %eax
    486     movl    rINST,offThread_methodClassDex(%ecx)
    487     ADVANCE_PC 3
    488     GOTO_NEXT_R %eax
    489 
    490 19:
    491     /*
    492      * Handle special subMode actions
    493      * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
    494      */
    495     movl     rFP, offThread_curFrame(%ecx)    # update interpSave.curFrame
    496     movl     rPC, offThread_pc(%ecx)          # update interpSave.pc
    497     movl     %ecx, OUT_ARG0(%esp)             # parameter self
    498     call     dvmReportReturn                  # (self)
    499     movl     rSELF, %ecx                      # restore self
    500     SAVEAREA_FROM_FP %eax                     # restore saveArea
    501     jmp      14b
    502 
    503 
    504 /*
    505  * Prepare to strip the current frame and "longjump" back to caller of
    506  * dvmMterpStdRun.
    507  *
    508  * on entry:
    509  *    rINST holds changeInterp
    510  *    ecx holds self pointer
    511  *
    512  * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
    513  */
    514 common_gotoBail:
    515     movl   rPC,offThread_pc(%ecx)     # export state to self
    516     movl   rFP,offThread_curFrame(%ecx)
    517     movl   %ecx,OUT_ARG0(%esp)      # self in arg0
    518     movl   rINST,OUT_ARG1(%esp)     # changeInterp in arg1
    519     call   dvmMterpStdBail          # bail out....
    520 
    521 
    522 /*
    523  * After returning from a "selfd" function, pull out the updated values
    524  * and start executing at the next instruction.
    525  */
    526  common_resumeAfterGlueCall:
    527      movl  rSELF, %eax
    528      movl  offThread_pc(%eax),rPC
    529      movl  offThread_curFrame(%eax),rFP
    530      movl  offThread_curHandlerTable(%eax),rIBASE
    531      FETCH_INST
    532      GOTO_NEXT
    533 
    534 /*
    535  * Integer divide or mod by zero
    536  */
    537 common_errDivideByZero:
    538     EXPORT_PC
    539     movl    $$.LstrDivideByZero,%eax
    540     movl    %eax,OUT_ARG0(%esp)
    541     call    dvmThrowArithmeticException
    542     jmp     common_exceptionThrown
    543 
    544 /*
    545  * Attempt to allocate an array with a negative size.
    546  * On entry, len in eax
    547  */
    548 common_errNegativeArraySize:
    549     EXPORT_PC
    550     movl    %eax,OUT_ARG0(%esp)                  # arg0<- len
    551     call    dvmThrowNegativeArraySizeException   # (len)
    552     jmp     common_exceptionThrown
    553 
    554 /*
    555  * Attempt to allocate an array with a negative size.
    556  * On entry, method name in eax
    557  */
    558 common_errNoSuchMethod:
    559 
    560     EXPORT_PC
    561     movl    %eax,OUT_ARG0(%esp)
    562     call    dvmThrowNoSuchMethodError
    563     jmp     common_exceptionThrown
    564 
    565 /*
    566  * Hit a null object when we weren't expecting one.  Export the PC, throw a
    567  * NullPointerException and goto the exception processing code.
    568  */
    569 common_errNullObject:
    570     EXPORT_PC
    571     xorl    %eax,%eax
    572     movl    %eax,OUT_ARG0(%esp)
    573     call    dvmThrowNullPointerException
    574     jmp     common_exceptionThrown
    575 
    576 /*
    577  * Array index exceeds max.
    578  * On entry:
    579  *    eax <- array object
    580  *    ecx <- index
    581  */
    582 common_errArrayIndex:
    583     EXPORT_PC
    584     movl    offArrayObject_length(%eax), %eax
    585     movl    %eax,OUT_ARG0(%esp)
    586     movl    %ecx,OUT_ARG1(%esp)
    587     call    dvmThrowArrayIndexOutOfBoundsException   # args (length, index)
    588     jmp     common_exceptionThrown
    589 
    590 /*
    591  * Somebody has thrown an exception.  Handle it.
    592  *
    593  * If the exception processing code returns to us (instead of falling
    594  * out of the interpreter), continue with whatever the next instruction
    595  * now happens to be.
    596  *
    597  * NOTE: special subMode handling done in dvmMterp_exceptionThrown
    598  *
    599  * This does not return.
    600  */
    601 common_exceptionThrown:
    602     movl    rSELF,%ecx
    603     movl    rPC,offThread_pc(%ecx)
    604     movl    rFP,offThread_curFrame(%ecx)
    605     movl    %ecx,OUT_ARG0(%esp)
    606     call    dvmMterp_exceptionThrown
    607     jmp     common_resumeAfterGlueCall
    608 
    609 common_abort:
    610     movl    $$0xdeadf00d,%eax
    611     call     *%eax
    612 
    613 
    614 /*
    615  * Strings
    616  */
    617 
    618     .section     .rodata
    619 .LstrDivideByZero:
    620     .asciz  "divide by zero"
    621 .LstrFilledNewArrayNotImplA:
    622     .asciz  "filled-new-array only implemented for 'int'"
    623