Home | History | Annotate | Download | only in x86-atom
      1    /* Copyright (C) 2008 The Android Open Source Project
      2     *
      3     * Licensed under the Apache License, Version 2.0 (the "License");
      4     * you may not use this file except in compliance with the License.
      5     * You may obtain a copy of the License at
      6     *
      7     * http://www.apache.org/licenses/LICENSE-2.0
      8     *
      9     * Unless required by applicable law or agreed to in writing, software
     10     * distributed under the License is distributed on an "AS IS" BASIS,
     11     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12     * See the License for the specific language governing permissions and
     13     * limitations under the License.
     14     */
     15 
     16    /*
     17     * File: footer.S
     18     */
     19 
     20     .text
     21     .align      2
     22 
     23    /*
     24     * Check to see if the thread needs to be suspended or debugger/profiler
     25     * activity has begun.
     26     *
     27     * On entry:
     28     *  %ecx is reentry type, e.g. kInterpEntryInstr
     29     *  %edx is PC adjustment in bytes
     30     */
     31 
     32 common_periodicChecks:
     33     movl        %edx, -8(%esp)          # save pc adjustments
     34     movl        rGLUE, %edx             # %edx<- pMterpGlue
     35     movl        %ebx, -4(%esp)          # save %ebx to the stack
     36     movl        offGlue_pSelfSuspendCount(%edx), %ebx # %ebx<- pSuspendCount (int)
     37 4:
     38     movl        offGlue_pDebuggerActive(%edx), %eax # %eax<- pDebuggerActive
     39     testl       %eax, %eax
     40     je          5f
     41     movzbl        (%eax), %eax            # %eax<- get debuggerActive (boolean)
     42 5:
     43     cmp         $$0, (%ebx)             # check if suspend is pending
     44     jne         2f                      # handle suspend
     45     movl        offGlue_pActiveProfilers(%edx), %ebx # %ebx<- activeProfilers (int)
     46     orl         (%ebx), %eax            # %eax<- merge activeProfilers and debuggerActive
     47     movl        -8(%esp), %edx          # %edx<- restore %edx
     48     jne         3f                      # debugger or profiler active; switch interp
     49     movl        -4(%esp), %ebx          # %ebx<- restore %ebx
     50     ret                                 # return
     51 2:                                      # check suspended
     52     EXPORT_PC
     53     movl        offGlue_self(%edx), %eax # %eax<- glue->self
     54     movl        %eax, -12(%esp)         # push parameter boolean
     55     lea         -12(%esp), %esp
     56     call        dvmCheckSuspendPending  # call: (Thread* self)
     57                                         # return: bool
     58     movl        4(%esp), %edx           # %edx<- restore %edx
     59     movl        8(%esp), %ebx           # %ebx<- restore %ebx
     60     lea         12(%esp), %esp
     61     ret
     62 3:                                      # debugger/profiler enabled, bail out
     63     leal        (rPC, %edx, 2), rPC     # adjust pc to show target
     64     movl        rGLUE, %ecx             # %ecx<- pMterpGlue
     65     movb        $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
     66     movl        $$1, %edx               # switch interpreter
     67     jmp         common_gotoBail         # bail
     68 
     69    /*
     70     * Check to see if the thread needs to be suspended or debugger/profiler
     71     * activity has begun. With this variant, the reentry type is hard coded
     72     * as kInterpEntryInstr.
     73     *
     74     * On entry:
     75     *  %edx is PC adjustment in bytes
     76     */
     77 
     78 common_periodicChecks_backwardBranch:
     79     EXPORT_PC
     80     movl        rGLUE, %ecx             # %ecx<- pMterpGlue
     81     movl        offGlue_pSelfSuspendCount(%ecx), rINST # %ebx<- pSuspendCount (int)
     82 4:
     83     movl        offGlue_pDebuggerActive(%ecx), %eax # %eax<- pDebuggerActive
     84     testl       %eax, %eax              # test for NULL pointer
     85     je          5f
     86     movzbl      (%eax), %eax            # %eax<- get debuggerActive count
     87 5:
     88     cmp         $$0, (rINST)            # check if suspend is pending
     89     jne         2f                      # handle suspend
     90     movl        offGlue_pActiveProfilers(%ecx), rINST # %edx<- activeProfilers (int)
     91     orl          (rINST), %eax           # %eax<- merge activeProfilers and debuggerActive
     92     jne         3f                      # debugger or profiler active; switch interp
     93     FINISH_RB   %edx, %ecx              # jump to next instruction
     94 2:                                      # check suspended
     95     movl        offGlue_self(%ecx), %eax# %eax<- glue->self
     96     movl        %edx, rINST
     97     movl        %eax, -12(%esp)         # push parameter boolean
     98     lea         -12(%esp), %esp
     99     call        dvmCheckSuspendPending  # call: (Thread* self)
    100                                         # return: bool
    101     movl        rINST, %edx             # %edx<- restore %edx
    102     lea         12(%esp), %esp
    103     FINISH_RB   %edx, %ecx
    104 3:                                      # debugger/profiler enabled, bail out
    105     leal        (rPC, %edx, 2), rPC     # adjust pc to show target
    106     movb        $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
    107     movl        $$1, %edx               # switch interpreter
    108     jmp         common_gotoBail         # bail
    109 
    110    /*
    111     * The equivalent of "goto bail", this calls through the "bail handler".
    112     * State registers will be saved to the "glue" area before bailing.
    113     *
    114     * On entry:
    115     *  %edx is "bool changeInterp", indicating if we want to switch to the
    116     *     other interpreter or just bail all the way out
    117     */
    118 
    119 common_gotoBail:
    120     SAVE_PC_FP_TO_GLUE %ecx             # save program counter and frame pointer
    121 
    122    /*
    123     * Inlined dvmMterpStdBail
    124     */
    125 
    126     lea         40(%ebp), %esp
    127     movl        %edx, %eax
    128     movl        24(%ebp), %edi
    129     movl        28(%ebp), %esi
    130     movl        32(%ebp), %ebx
    131     movl        36(%ebp), %ebp
    132     ret
    133 
    134    /*
    135     * Common code for method invocation with range.
    136     *
    137     * On entry:
    138     *  %ecx is "Method* methodToCall", the method we're trying to call
    139     */
    140 
    141 common_invokeMethodRange:
    142 .LinvokeNewRange:
    143 
    144    /*
    145     * prepare to copy args to "outs" area of current frame
    146     */
    147 
    148     SAVEAREA_FROM_FP %eax               # %eax<- &outs; &StackSaveArea
    149     test        rINST, rINST            # test for no args
    150     movl        rINST, sReg0            # sReg0<- AA
    151     jz          .LinvokeArgsDone        # no args; jump to args done
    152     FETCH       2, %edx                 # %edx<- CCCC
    153 
    154    /*
    155     * %ecx=methodToCall, %edx=CCCC, sReg0=count, %eax=&outs (&stackSaveArea)
    156     * (very few methods have > 10 args; could unroll for common cases)
    157     */
    158 
    159     movl        %ebx, sReg1             # sReg1<- save %ebx
    160     lea         (rFP, %edx, 4), %edx    # %edx<- &vCCCC
    161     shll        $$2, sReg0              # sReg0<- offset
    162     subl        sReg0, %eax             # %eax<- update &outs
    163     shrl        $$2, sReg0              # sReg0<- offset
    164 1:
    165     movl        (%edx), %ebx            # %ebx<- vCCCC
    166     lea         4(%edx), %edx           # %edx<- &vCCCC++
    167     subl        $$1, sReg0              # sReg<- sReg--
    168     movl        %ebx, (%eax)            # *outs<- vCCCC
    169     lea         4(%eax), %eax           # outs++
    170     jne         1b                      # loop if count (sReg0) not zero
    171     movl        sReg1, %ebx             # %ebx<- restore %ebx
    172     jmp         .LinvokeArgsDone        # continue
    173 
    174    /*
    175     * %ecx is "Method* methodToCall", the method we're trying to call
    176     * prepare to copy args to "outs" area of current frame
    177     */
    178 
    179 common_invokeMethodNoRange:
    180 .LinvokeNewNoRange:
    181     movl        rINST, sReg0            # sReg0<- BA
    182     shrl        $$4, sReg0              # sReg0<- B
    183     je          .LinvokeArgsDone        # no args; jump to args done
    184     SAVEAREA_FROM_FP %eax               # %eax<- &outs; &StackSaveArea
    185     FETCH       2, %edx                 # %edx<- GFED
    186 
    187    /*
    188     * %ecx=methodToCall, %edx=GFED, sReg0=count, %eax=outs
    189     */
    190 
    191 .LinvokeNonRange:
    192     cmp         $$2, sReg0              # compare sReg0 to 2
    193     movl        %edx, sReg1             # sReg1<- GFED
    194     jl          1f                      # handle 1 arg
    195     je          2f                      # handle 2 args
    196     cmp         $$4, sReg0              # compare sReg0 to 4
    197     jl          3f                      # handle 3 args
    198     je          4f                      # handle 4 args
    199 5:
    200     andl        $$15, rINST             # rINST<- A
    201     lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
    202     movl        (rFP, rINST, 4), %edx   # %edx<- vA
    203     movl        %edx, (%eax)            # *outs<- vA
    204     movl        sReg1, %edx             # %edx<- GFED
    205 4:
    206     shr         $$12, %edx              # %edx<- G
    207     lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
    208     movl        (rFP, %edx, 4), %edx    # %edx<- vG
    209     movl        %edx, (%eax)            # *outs<- vG
    210     movl        sReg1, %edx             # %edx<- GFED
    211 3:
    212     and         $$0x0f00, %edx          # %edx<- 0F00
    213     shr         $$6, %edx               # %edx<- F at correct offset
    214     lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
    215     movl        (rFP, %edx), %edx       # %edx<- vF
    216     movl        %edx, (%eax)            # *outs<- vF
    217     movl        sReg1, %edx             # %edx<- GFED
    218 2:
    219     and         $$0x00f0, %edx          # %edx<- 00E0
    220     shr         $$2, %edx               # %edx<- E at correct offset
    221     lea         -4(%eax), %eax          # %eax<- update &outs; &outs--
    222     movl        (rFP, %edx), %edx       # %edx<- vE
    223     movl        %edx, (%eax)            # *outs<- vE
    224     movl        sReg1, %edx             # %edx<- GFED
    225 1:
    226     and         $$0x000f, %edx          # %edx<- 000D
    227     movl        (rFP, %edx, 4), %edx    # %edx<- vD
    228     movl        %edx, -4(%eax)          # *--outs<- vD
    229 0:
    230 
    231    /*
    232     * %ecx is "Method* methodToCall", the method we're trying to call
    233     * find space for the new stack frame, check for overflow
    234     */
    235 
    236 .LinvokeArgsDone:
    237     movzwl      offMethod_registersSize(%ecx), %eax # %eax<- methodToCall->regsSize
    238     movzwl      offMethod_outsSize(%ecx), %edx # %edx<- methodToCall->outsSize
    239     movl        %ecx, sReg0             # sReg<- methodToCall
    240     shl         $$2, %eax               # %eax<- update offset
    241     SAVEAREA_FROM_FP %ecx               # %ecx<- &outs; &StackSaveArea
    242     subl        %eax, %ecx              # %ecx<- newFP; (old savearea - regsSize)
    243     movl        rGLUE, %eax             # %eax<- pMterpGlue
    244     movl        %ecx, sReg1             # sReg1<- &outs
    245     subl        $$sizeofStackSaveArea, %ecx # %ecx<- newSaveArea (stack save area using newFP)
    246     movl        offGlue_interpStackEnd(%eax), %eax # %eax<- glue->interpStackEnd
    247     movl        %eax, sReg2             # sReg2<- glue->interpStackEnd
    248     shl         $$2, %edx               # %edx<- update offset for outsSize
    249     movl        %ecx, %eax              # %eax<- newSaveArea
    250     sub         %edx, %ecx              # %ecx<- bottom; (newSaveArea - outsSize)
    251     cmp         sReg2, %ecx             # compare interpStackEnd and bottom
    252     movl        sReg0, %ecx             # %ecx<- restore methodToCall
    253     jl          .LstackOverflow         # handle frame overflow
    254 
    255    /*
    256     * set up newSaveArea
    257     */
    258 
    259 #ifdef EASY_GDB
    260     SAVEAREA_FROM_FP %edx               # %edx<- &outs; &StackSaveArea
    261     movl        %edx, offStackSaveArea_prevSave(%eax) # newSaveArea->prevSave<- &outs
    262 #endif
    263     movl        rFP, offStackSaveArea_prevFrame(%eax) # newSaveArea->prevFrame<- rFP
    264     movl        rPC, offStackSaveArea_savedPc(%eax) # newSaveArea->savedPc<- rPC
    265     testl       $$ACC_NATIVE, offMethod_accessFlags(%ecx) # check for native call
    266     movl        %ecx, offStackSaveArea_method(%eax) # newSaveArea->method<- method to call
    267     jne         .LinvokeNative          # handle native call
    268 
    269    /*
    270     * Update "glue" values for the new method
    271     * %ecx=methodToCall, sReg1=newFp
    272     */
    273 
    274     movl        offMethod_clazz(%ecx), %edx # %edx<- method->clazz
    275     movl        rGLUE, %eax             # %eax<- pMterpGlue
    276     movl        %ecx, offGlue_method(%eax) # glue->method<- methodToCall
    277     movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
    278     movl        offMethod_insns(%ecx), rPC # rPC<- methodToCall->insns
    279     movl        %edx, offGlue_methodClassDex(%eax) # glue->methodClassDex<- method->clazz->pDvmDex
    280     movl        offGlue_self(%eax), %ecx # %ecx<- glue->self
    281     movl        sReg1, rFP              # rFP<- newFP
    282     movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
    283     FINISH_A                            # jump to methodToCall->insns
    284 
    285    /*
    286     * Prep for the native call
    287     * %ecx=methodToCall, sReg1=newFP, %eax=newSaveArea
    288     */
    289 
    290 .LinvokeNative:
    291     movl        rGLUE, %edx             # %edx<- pMterpGlue
    292     movl        %ecx, -20(%esp)         # push parameter methodToCall
    293     movl        offGlue_self(%edx), %edx # %edx<- glue->self
    294     movl        offThread_jniLocal_topCookie(%edx), %ecx # %ecx<- glue->self->thread->refNext
    295     movl        %ecx, offStackSaveArea_localRefCookie(%eax) # newSaveArea->localRefCookie<- refNext
    296     movl        %eax, -4(%esp)          # save newSaveArea
    297     movl        sReg1, %eax             # %eax<- newFP
    298     movl        %eax, offThread_curFrame(%edx) # glue->self->curFrame<- newFP
    299     movl        %edx, -8(%esp)          # save glue->self
    300     movl        %edx, -16(%esp)         # push parameter glue->self
    301     movl        rGLUE, %edx             # %edx<- pMterpGlue
    302     movl        -20(%esp), %ecx         # %ecx<- methodToCall
    303     lea         offGlue_retval(%edx), %edx # %edx<- &retval
    304     movl        %edx, -24(%esp)         # push parameter pMterpGlue
    305     movl        %eax, -28(%esp)         # push parameter newFP
    306     lea         -28(%esp), %esp
    307 
    308 #ifdef ASSIST_DEBUGGER
    309     jmp         .Lskip
    310     .type       dalvik_mterp, %function
    311 dalvik_mterp:
    312     MTERP_ENTRY
    313 .Lskip:
    314 #endif
    315     call        *offMethod_nativeFunc(%ecx) # call methodToCall->nativeFunc
    316     lea         28(%esp), %esp
    317     movl        -4(%esp), %edx          # %edx<- newSaveArea
    318     movl        -8(%esp), %ecx          # %ecx<- glue->self
    319     movl        offStackSaveArea_localRefCookie(%edx), %eax  # %eax<- newSaveArea->localRefCookie
    320     FFETCH_ADV  3, %edx                 # %edx<- next instruction hi; fetch, advance
    321     cmp         $$0, offThread_exception(%ecx) # check for exception
    322     movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
    323     movl        %eax, offThread_jniLocal_topCookie(%ecx) # glue->self<- newSaveArea->localRefCookie
    324     jne         common_exceptionThrown  # handle exception
    325     FGETOP_JMP  3, %edx                 # jump to next instruction; getop, jmp
    326 
    327 .LstackOverflow:
    328     movl        %ecx, -4(%esp)          # push method to call
    329     movl        rGLUE, %ecx             # %ecx<- pMterpGlue
    330     movl        offGlue_self(%ecx), %ecx # %ecx<- glue->self
    331     movl        %ecx, -8(%esp)          # push parameter self
    332     lea         -8(%esp), %esp
    333     call        dvmHandleStackOverflow  # call: (Thread* self, Method *meth)
    334                                         # return: void
    335     lea         8(%esp), %esp
    336     jmp         common_exceptionThrown  # handle exception
    337 #ifdef ASSIST_DEBUGGER
    338 #endif
    339 
    340    /*
    341     * Common code for handling a return instruction.
    342     *
    343     * This does not return.
    344     */
    345 
    346 common_returnFromMethod:
    347 .LreturnNew:
    348 
    349    /*
    350     * Inline common periodic checks
    351     */
    352 
    353     movl        rGLUE, rINST            # %ecx<- pMterpGlue
    354     movl        offGlue_pSelfSuspendCount(rINST), %edx # %ebx<- pSuspendCount (int)
    355     movl        offGlue_pDebuggerActive(rINST), %eax # %eax<- pDebuggerActive
    356     movl        (%eax), %eax            # %eax<- get debuggerActive (boolean)
    357     and         $$7, %eax               # %eax<- mask for boolean (just how many bits does it take?)
    358     cmp         $$0, (%edx)             # check if suspend is pending
    359     jne         2f                      # handle suspend
    360     movl        offGlue_pActiveProfilers(rINST), %edx # %edx<- activeProfilers (int)
    361     or          (%edx), %eax            # %eax<- merge activeProfilers and debuggerActive
    362     cmp         $$0, %eax               # check for debuggerActive
    363     jne         3f                      # debugger or profiler active; switch interp
    364     jmp         4f
    365 2:                                      # check suspended
    366     movl        offGlue_self(rINST), %eax# %eax<- glue->self
    367     movl        %eax, -12(%esp)         # push parameter boolean
    368     lea         -12(%esp), %esp
    369     call        dvmCheckSuspendPending  # call: (Thread* self)
    370                                         # return: bool
    371     lea         12(%esp), %esp
    372     jmp         4f
    373 3:                                      # debugger/profiler enabled, bail out
    374     movl        $$kInterpEntryInstr, offGlue_entryPoint(rINST) # glue->entryPoint<- reentry type
    375     movl        $$1, %edx               # switch to interp<- true
    376     jmp         common_gotoBail         # bail
    377 
    378 
    379    /*
    380     * Get save area; rGLUE is %ebx, rFP is %eax
    381     */
    382 4:
    383     SAVEAREA_FROM_FP %ecx               # %ecx<- saveArea(old)
    384     movl        offStackSaveArea_prevFrame(%ecx), rFP # rFP<- saveArea->PrevFrame
    385     movl        (offStackSaveArea_method - sizeofStackSaveArea)(rFP), %edx # %edx<- method we are returning to
    386     cmpl        $$0, %edx               # check for break frame
    387     je          common_gotoBail         # bail if break frame
    388     movl        offStackSaveArea_savedPc(%ecx), rPC # rPC<- saveAreaOld->savedPc
    389     movl        offGlue_self(rINST), %ecx # %eax<- glue->self
    390     movl        %edx, offGlue_method(rINST) # glue->method<- newSave->method
    391     movl        offMethod_clazz(%edx), %edx # %edx<- method->clazz
    392     FFETCH_ADV  3, %eax                 # %ecx<- next instruction hi; fetch, advance
    393     movl        rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
    394     movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
    395     movl        %edx, offGlue_methodClassDex(rINST) # glue->pDvmDex<- method->clazz->pDvmDex
    396     FGETOP_JMP  3, %eax                 # jump to next instruction; getop, jmp
    397 
    398    /*
    399     * Handle thrown an exception. If the exception processing code
    400     * returns to us (instead of falling out of the interpreter),
    401     * continue with whatever the next instruction now happens to be.
    402     * This does not return.
    403     */
    404 
    405 common_exceptionThrown:
    406 .LexceptionNew:
    407     movl        $$kInterpEntryThrow, %ecx # %ecx<- reentry type
    408     movl        $$0, %edx               # %edx<- pc adjustment
    409     call        common_periodicChecks
    410     movl        rGLUE, %eax             # %eax<- pMterpGlue
    411     movl        offGlue_self(%eax), %edx # %edx<- glue->self
    412     movl        offThread_exception(%edx), %ecx # %ecx<- pMterpGlue->self->exception
    413     movl        %edx, -4(%esp)          # push parameter self
    414     movl        %ecx, -8(%esp)          # push parameter obj
    415     lea         -8(%esp), %esp
    416     call        dvmAddTrackedAlloc      # don't allow the exception to be GC'd
    417                                         # call: (Object* obj, Thread* self)
    418                                         # return: void
    419     movl        4(%esp), %edx           # %edx<- glue->self
    420     movl        $$0, offThread_exception(%edx) # glue->self->exception<- NULL
    421 
    422    /*
    423     * set up args and a local for &fp
    424     */
    425 
    426     movl        rFP, -4(%esp)           # move fp to stack
    427     lea         -4(%esp), %esp          # update %esp
    428     movl        %esp, -4(%esp)          # push parameter 4<- &fp
    429     movl        $$0, -8(%esp)           # push parameter 3<- false
    430     movl        4(%esp), %edx
    431     movl        %edx, -12(%esp)         # push parameter 2<- glue->self->exception
    432     movl        rGLUE, %eax             # %eax<- pMterpGlue
    433     movl        offGlue_method(%eax), %edx # %edx<- glue->method
    434     movl        offMethod_insns(%edx), %edx # %edx<- glue->method->insns
    435     movl        rPC, %ecx               # %ecx<- rPC
    436     subl        %edx, %ecx              # %ecx<- pc - glue->method->insns
    437     sar         $$1, %ecx               # %ecx<- adjust %ecx for offset
    438     movl        %ecx, -16(%esp)         # push parameter 1<- glue->method->insns
    439     movl        8(%esp), %edx
    440     movl        %edx, -20(%esp)         # push parameter 0<- glue->self
    441     lea         -20(%esp), %esp
    442 
    443    /*
    444     * call dvmFindCatchBlock, %eax gets catchRelPc (a code-unit offset)
    445     */
    446 
    447     call        dvmFindCatchBlock       # call: (Thread* self, int relPc, Object* exception,
    448                                         #      bool doUnroll, void** newFrame)
    449                                         # return: int
    450     lea         32(%esp), %esp
    451     movl        -12(%esp), rFP          # rFP<- updated rFP
    452     cmp         $$0, %eax               # check for catchRelPc < 0
    453     jl          .LnotCaughtLocally      # handle not caught locally
    454 
    455    /*
    456     * fix stack overflow if necessary
    457     */
    458 
    459     movl        -4(%esp), %ecx          # %ecx<- glue->self
    460     cmp         $$0, offThread_stackOverflowed(%ecx)
    461     je          1f
    462     movl        %eax, -4(%esp)          # save %eax for later
    463     movl        %ecx, -12(%esp)         # push parameter 2 glue->self
    464     lea         -12(%esp), %esp
    465     call        dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
    466                                         # return: void
    467     lea         12(%esp), %esp
    468     movl        -4(%esp), %eax          # %eax<- restore %eax
    469     jmp         2f
    470 1:
    471     movl        %ecx, -12(%esp)         # push parameter 2 glue->self
    472 2:
    473 
    474    /*
    475     * adjust locals to match self->curFrame and updated PC
    476     *
    477     */
    478 
    479     SAVEAREA_FROM_FP %edx               # %edx<- get newSaveArea
    480     movl        rGLUE, %ecx             # %ecx<- pMterpGlue
    481     movl        offStackSaveArea_method(%edx), rPC # rPC<- newMethod
    482     movl        rPC, offGlue_method(%ecx) # glue->method<- newMethod
    483     movl        offMethod_clazz(rPC), %edx # %edx<- method->clazz
    484     movl        offMethod_insns(rPC), rPC # rPC<- method->insns
    485     movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
    486     lea         (rPC, %eax, 2), rPC     # rPC<- method->insns + catchRelPc
    487     movl        %edx, offGlue_methodClassDex(%ecx) # glue->pDvmDex<- method->clazz->pDvmDex
    488     movl        -8(%esp), %eax
    489     movl        %eax, -16(%esp)         # push parameter 1 obj
    490     lea         -16(%esp), %esp
    491     call        dvmReleaseTrackedAlloc  # call: (Object* obj, Thread* self)
    492                                         # return: void
    493     lea         16(%esp), %esp
    494     FINISH_FETCH %eax
    495     cmp         $$OP_MOVE_EXCEPTION, %eax # is it a move exception
    496     jne         1f
    497     movl        -12(%esp), %edx         # %edx<- glue->self
    498     movl        -8(%esp), %ecx          # %ecx<- exception
    499     movl        %ecx, offThread_exception(%edx) # restore the exception
    500 1:
    501     FINISH_JMP  %eax
    502 
    503    /*
    504     * -8(%esp) = exception, -4(%esp) = self
    505     */
    506 
    507 .LnotCaughtLocally:
    508     movl        -4(%esp), %edx          # %edx<- glue->self
    509     movzb       offThread_stackOverflowed(%edx), %eax # %eax<- self->stackOverflowed
    510     cmp         $$0, %eax               # check for stack overflow;
    511                                         # maybe should use cmpb
    512     je          1f                      #
    513     movl        %edx, -12(%esp)         # push parameter 1 glue->self
    514     lea         -12(%esp), %esp
    515     call        dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
    516                                         # return: void
    517     lea         12(%esp), %esp
    518 
    519    /*
    520     * Release the exception
    521     * -8(%esp) = exception, -4(%esp) = self
    522     */
    523 1:
    524     movl        -8(%esp), %ecx          # %ecx<- exception
    525     movl        -4(%esp), %edx          # %edx<- glue->self
    526     movl        %ecx, offThread_exception(%edx) # glue->self<- exception
    527     lea         -8(%esp), %esp
    528     call        dvmReleaseTrackedAlloc  # call: (Object* obj, Thread* self)
    529                                         # return: void
    530     lea         8(%esp), %esp
    531     movl        $$0, %edx               # switch to interp<- false
    532     jmp         common_gotoBail         # bail
    533 
    534    /*
    535     * After returning from a "glued" function, pull out the updated
    536     * values and start executing at the next instruction.
    537     */
    538 
    539 common_resumeAfterGlueCall:
    540     LOAD_PC_FP_FROM_GLUE                # pull rPC and rFP out of glue
    541     FINISH_A                            # jump to next instruction
    542 
    543    /*
    544     * For debugging, cause an immediate fault.
    545     */
    546 
    547 common_abort:
    548     jmp         .LdeadFood
    549 
    550 .LdeadFood:
    551 .int 0xdeadf00d
    552 
    553    /*
    554     * Invalid array index.
    555     */
    556 
    557 common_errArrayIndex:
    558     EXPORT_PC
    559     movl        $$.LstrArrayIndexException, -8(%esp) # push parameter description
    560     movl        $$0, -4(%esp)           # push parameter msg paramter
    561     lea         -8(%esp), %esp
    562     call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
    563                                         # return: void
    564     lea         8(%esp), %esp
    565     jmp         common_exceptionThrown  # handle exception
    566 
    567    /*
    568     * Invalid array value.
    569     */
    570 
    571 common_errArrayStore:
    572     EXPORT_PC
    573     movl        $$.LstrArrayStoreException, -8(%esp) # push parameter description
    574     movl        $$0, -4(%esp)           # push parameter msg paramter
    575     lea         -8(%esp), %esp
    576     call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
    577                                         # return: void
    578     lea         8(%esp), %esp
    579     jmp         common_exceptionThrown  # handle exception
    580 
    581    /*
    582     * Integer divide or mod by zero.
    583     */
    584 
    585 common_errDivideByZero:
    586     EXPORT_PC
    587     movl        $$.LstrArithmeticException, -8(%esp) # push parameter description
    588     movl        $$.LstrDivideByZero, -4(%esp) # push parameter msg paramter
    589     lea         -8(%esp), %esp
    590     call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
    591                                         # return: void
    592     lea         8(%esp), %esp
    593     jmp         common_exceptionThrown  # handle exception
    594 
    595    /*
    596     * Attempt to allocate an array with a negative size.
    597     */
    598 
    599 common_errNegativeArraySize:
    600     EXPORT_PC
    601     movl        $$.LstrNegativeArraySizeException, -8(%esp) # push parameter description
    602     movl        $$0, -4(%esp)           # push parameter msg paramter
    603     lea         -8(%esp), %esp
    604     call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
    605                                         # return: void
    606     lea         8(%esp), %esp
    607     jmp         common_exceptionThrown  # handle exception
    608 
    609    /*
    610     * Invocation of a non-existent method.
    611     */
    612 
    613 common_errNoSuchMethod:
    614     EXPORT_PC
    615     movl        $$.LstrNoSuchMethodError, -8(%esp) # push parameter description
    616     movl        $$0, -4(%esp)           # push parameter msg paramter
    617     lea         -8(%esp), %esp
    618     call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
    619                                         # return: void
    620     lea         8(%esp), %esp
    621     jmp         common_exceptionThrown  # handle exception
    622 
    623    /*
    624     * Unexpected null object.
    625     */
    626 
    627 common_errNullObject:
    628     EXPORT_PC
    629     movl        $$.LstrNullPointerException, -8(%esp) # push parameter description
    630     movl        $$0, -4(%esp)           # push parameter msg paramter
    631     lea         -8(%esp), %esp
    632     call        dvmThrowException       # call: (const char* exceptionDescriptor, const char* msg)
    633                                         # return: void
    634     lea         8(%esp), %esp
    635     jmp         common_exceptionThrown  # handle exception
    636 
    637    /*
    638     * String references
    639     */
    640 
    641     .align 4
    642     .section .rodata
    643 .LstrArithmeticException:
    644     .asciz "Ljava/lang/ArithmeticException;"
    645 .LstrArrayIndexException:
    646     .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
    647 .LstrArrayStoreException:
    648     .asciz "Ljava/lang/ArrayStoreException;"
    649 .LstrDivideByZero:
    650     .asciz "divide by zero"
    651 .LstrInstantiationError:
    652     .asciz "Ljava/lang/InstantiationError;"
    653 .LstrNegativeArraySizeException:
    654     .asciz "Ljava/lang/NegativeArraySizeException;"
    655 .LstrNoSuchMethodError:
    656     .asciz "Ljava/lang/NoSuchMethodError;"
    657 .LstrNullPointerException:
    658     .asciz "Ljava/lang/NullPointerException;"
    659 .LstrExceptionNotCaughtLocally:
    660     .asciz "Exception %s from %s:%d not caught locally\n"
    661