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 /*
     21  * Common code when a backwards branch is taken
     22  *
     23  * On entry:
     24  *   ebx (a.k.a. rINST_FULL) -> PC adjustment in 16-bit words
     25  */
     26 common_backwardBranch:
     27     GET_GLUE(%ecx)
     28     call   common_periodicChecks  # Note: expects rPC to be preserved
     29     ADVANCE_PC_INDEXED(rINST_FULL)
     30     FETCH_INST()
     31     GOTO_NEXT
     32 
     33 
     34 
     35 /*
     36  * Common code for method invocation with range.
     37  *
     38  * On entry:
     39  *   eax = Method* methodToCall
     40  *   rINST trashed, must reload
     41  */
     42 
     43 common_invokeMethodRange:
     44 .LinvokeNewRange:
     45 
     46    /*
     47     * prepare to copy args to "outs" area of current frame
     48     */
     49 
     50     movzbl      1(rPC),rINST_FULL       # rINST_FULL<- AA
     51     movzwl      4(rPC), %ecx            # %ecx<- CCCC
     52     SPILL(rPC)
     53     SAVEAREA_FROM_FP(%edx,rFP)          # %edx<- &StackSaveArea
     54     test        rINST_FULL, rINST_FULL
     55     movl        rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
     56     jz          .LinvokeArgsDone        # no args; jump to args done
     57 
     58 
     59    /*
     60     * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, %edx=&outs (&stackSaveArea)
     61     * (very few methods have > 10 args; could unroll for common cases)
     62     */
     63 
     64     movl        %ebx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- save %ebx
     65     lea         (rFP, %ecx, 4), %ecx    # %ecx<- &vCCCC
     66     shll        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
     67     subl        LOCAL0_OFFSET(%ebp), %edx       # %edx<- update &outs
     68     shrl        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
     69 1:
     70     movl        (%ecx), %ebx            # %ebx<- vCCCC
     71     lea         4(%ecx), %ecx           # %ecx<- &vCCCC++
     72     subl        $$1, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET<- LOCAL0_OFFSET--
     73     movl        %ebx, (%edx)            # *outs<- vCCCC
     74     lea         4(%edx), %edx           # outs++
     75     jne         1b                      # loop if count (LOCAL0_OFFSET(%ebp)) not zero
     76     movl        LOCAL1_OFFSET(%ebp), %ebx       # %ebx<- restore %ebx
     77     jmp         .LinvokeArgsDone        # continue
     78 
     79    /*
     80     * %eax is "Method* methodToCall", the method we're trying to call
     81     * prepare to copy args to "outs" area of current frame
     82     */
     83 
     84 common_invokeMethodNoRange:
     85 .LinvokeNewNoRange:
     86     movzbl      1(rPC),rINST_FULL       # rINST_FULL<- BA
     87     SPILL(rPC)
     88     movl        rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
     89     shrl        $$4, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- B
     90     je          .LinvokeArgsDone        # no args; jump to args done
     91     movzwl      4(rPC), %ecx            # %ecx<- GFED
     92     SAVEAREA_FROM_FP(%edx,rFP)          # %edx<- &StackSaveArea
     93 
     94    /*
     95     * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
     96     */
     97 
     98 .LinvokeNonRange:
     99     cmp         $$2, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 2
    100     movl        %ecx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- GFED
    101     jl          1f                      # handle 1 arg
    102     je          2f                      # handle 2 args
    103     cmp         $$4, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 4
    104     jl          3f                      # handle 3 args
    105     je          4f                      # handle 4 args
    106 5:
    107     andl        $$15, rINST_FULL        # rINST<- A
    108     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    109     movl        (rFP, rINST_FULL, 4), %ecx # %ecx<- vA
    110     movl        %ecx, (%edx)            # *outs<- vA
    111     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    112 4:
    113     shr         $$12, %ecx              # %ecx<- G
    114     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    115     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vG
    116     movl        %ecx, (%edx)            # *outs<- vG
    117     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    118 3:
    119     and         $$0x0f00, %ecx          # %ecx<- 0F00
    120     shr         $$8, %ecx               # %ecx<- F
    121     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    122     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vF
    123     movl        %ecx, (%edx)            # *outs<- vF
    124     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    125 2:
    126     and         $$0x00f0, %ecx          # %ecx<- 00E0
    127     shr         $$4, %ecx               # %ecx<- E
    128     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
    129     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vE
    130     movl        %ecx, (%edx)            # *outs<- vE
    131     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
    132 1:
    133     and         $$0x000f, %ecx          # %ecx<- 000D
    134     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vD
    135     movl        %ecx, -4(%edx)          # *--outs<- vD
    136 0:
    137 
    138    /*
    139     * %eax is "Method* methodToCall", the method we're trying to call
    140     * find space for the new stack frame, check for overflow
    141     */
    142 
    143 .LinvokeArgsDone:
    144     movzwl      offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
    145     movzwl      offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
    146     movl        %eax, LOCAL0_OFFSET(%ebp)       # LOCAL0_OFFSET<- methodToCall
    147     shl         $$2, %edx               # %edx<- update offset
    148     SAVEAREA_FROM_FP(%eax,rFP)          # %eax<- &StackSaveArea
    149     subl        %edx, %eax              # %eax<- newFP; (old savearea - regsSize)
    150     GET_GLUE(%edx)                      # %edx<- pMterpGlue
    151     movl        %eax, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- &outs
    152     subl        $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
    153     movl        offGlue_interpStackEnd(%edx), %edx # %edx<- glue->interpStackEnd
    154     movl        %edx, LOCAL2_OFFSET(%ebp)       # LOCAL2_OFFSET<- glue->interpStackEnd
    155     shl         $$2, %ecx               # %ecx<- update offset for outsSize
    156     movl        %eax, %edx              # %edx<- newSaveArea
    157     sub         %ecx, %eax              # %eax<- bottom; (newSaveArea - outsSize)
    158     cmp         LOCAL2_OFFSET(%ebp), %eax       # compare interpStackEnd and bottom
    159     movl        LOCAL0_OFFSET(%ebp), %eax       # %eax<- restore methodToCall
    160     jl          .LstackOverflow         # handle frame overflow
    161 
    162    /*
    163     * set up newSaveArea
    164     */
    165 
    166 #ifdef EASY_GDB
    167     SAVEAREA_FROM_FP(%ecx,rFP)          # %ecx<- &StackSaveArea
    168     movl        %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
    169 #endif
    170     movl        rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
    171     movl        rPC_SPILL(%ebp), %ecx
    172     movl        %ecx, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
    173     testl       $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
    174     movl        %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
    175     jne         .LinvokeNative          # handle native call
    176 
    177    /*
    178     * Update "glue" values for the new method
    179     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
    180     */
    181 
    182     movl        offMethod_clazz(%eax), %edx # %edx<- method->clazz
    183     GET_GLUE(%ecx)                      # %ecx<- pMterpGlue
    184     movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
    185     movl        %eax, offGlue_method(%ecx) # glue->method<- methodToCall
    186     movl        %edx, offGlue_methodClassDex(%ecx) # glue->methodClassDex<- method->clazz->pDvmDex
    187     movl        offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
    188     movl        offGlue_self(%ecx), %eax # %eax<- glue->self
    189     movl        LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
    190     movl        rFP, offThread_curFrame(%eax) # glue->self->curFrame<- newFP
    191     FETCH_INST()
    192     GOTO_NEXT                           # jump to methodToCall->insns
    193 
    194    /*
    195     * Prep for the native call
    196     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea
    197     */
    198 
    199 .LinvokeNative:
    200     GET_GLUE(%ecx)                      # %ecx<- pMterpGlue
    201     movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
    202     movl        offGlue_self(%ecx), %ecx        # %ecx<- glue->self
    203     movl        offThread_jniLocal_topCookie(%ecx), %eax # %eax<- self->localRef->...
    204     movl        %eax, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
    205     movl        %edx, OUT_ARG4(%esp)    # save newSaveArea
    206     movl        LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
    207     movl        %edx, offThread_curFrame(%ecx)  # glue->self->curFrame<- newFP
    208     movl        %ecx, OUT_ARG3(%esp)    # save glue->self
    209     movl        %ecx, OUT_ARG2(%esp)    # push parameter glue->self
    210     GET_GLUE(%ecx)                      # %ecx<- pMterpGlue
    211     movl        OUT_ARG1(%esp), %eax    # %eax<- methodToCall
    212     lea         offGlue_retval(%ecx), %ecx # %ecx<- &retval
    213     movl        %ecx, OUT_ARG0(%esp)    # push parameter pMterpGlue
    214     push        %edx                    # push parameter newFP
    215 
    216     call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
    217     lea         4(%esp), %esp
    218     movl        OUT_ARG4(%esp), %ecx    # %ecx<- newSaveArea
    219     movl        OUT_ARG3(%esp), %eax    # %eax<- glue->self
    220     movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
    221     cmp         $$0, offThread_exception(%eax) # check for exception
    222     movl        rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
    223     movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
    224     UNSPILL(rPC)
    225     jne         common_exceptionThrown  # handle exception
    226     FETCH_INST_WORD(3)
    227     ADVANCE_PC(3)
    228     GOTO_NEXT                           # jump to next instruction
    229 
    230 .LstackOverflow:    # eax=methodToCall
    231     movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
    232     GET_GLUE(%eax)                      # %eax<- pMterpGlue
    233     movl        offGlue_self(%eax), %eax # %eax<- glue->self
    234     movl        %eax, OUT_ARG0(%esp)    # push parameter self
    235     call        dvmHandleStackOverflow  # call: (Thread* self, Method* meth)
    236     UNSPILL(rPC)                        # return: void
    237     jmp         common_exceptionThrown  # handle exception
    238 
    239 
    240 /*
    241  * Common invoke code (old-style).
    242  * TUNING:  Rewrite along lines of new armv5 code?
    243  *
    244  * On entry:
    245  *   eax = Method* methodToCall
    246  *   ecx = bool methodCallRange
    247  *   rINST trashed, must reload
    248  */
    249 common_invokeOld:
    250     movl     %ecx,OUT_ARG1(%esp)     # arg1<- methodCallRange
    251     GET_GLUE(%ecx)
    252     movzwl  (rPC),rINST_FULL         # recover rINST
    253     movl     %eax,OUT_ARG2(%esp)     # arg2<- method
    254     movzwl   4(rPC),%eax             # eax<- GFED or CCCC
    255     SAVE_PC_TO_GLUE(%ecx)
    256     SAVE_FP_TO_GLUE(%ecx)
    257     movzbl   rINST_HI,rINST_FULL
    258     movl     rINST_FULL,OUT_ARG3(%esp)# arg3<- AA
    259     movl     %ecx,OUT_ARG0(%esp)     # arg0<- GLUE
    260     movl     %eax,OUT_ARG4(%esp)     # arg4<- GFED/CCCC
    261     call     dvmMterp_invokeMethod
    262     jmp      common_resumeAfterGlueCall
    263 
    264 
    265 /*
    266  * Do we need the thread to be suspended or have debugger/profiling activity?
    267  *
    268  * On entry:
    269  *   ebx  -> PC adjustment in 16-bit words (must be preserved)
    270  *   ecx  -> GLUE pointer
    271  *
    272  * Note: A call will normally kill %eax, rPC/%edx and %ecx.  To
    273  *       streamline the normal case, this routine will preserve rPC and
    274  *       %ecx in addition to the normal caller save regs.  The save/restore
    275  *       is a bit ugly, but will happen in the relatively uncommon path.
    276  * TUNING: Might be worthwhile to inline this.
    277  * TODO: Basic-block style Jit will need a hook here as well.  Fold it into
    278  *       the suspendCount check so we can get both in 1 shot.
    279  */
    280 common_periodicChecks:
    281     movl    offGlue_pSelfSuspendCount(%ecx),%eax    # eax <- &suspendCount
    282     cmpl    $$0,(%eax)
    283     jne     1f
    284 
    285 #if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
    286 #if defined(WITH_DEBUGGER)
    287     movl   offGlue_pDebuggerActive(%ecx),%eax      # eax <- &DebuggerActive
    288 #endif
    289 #if defined(WITH_PROFILER)
    290     movl   offGlue_pActiveProfilers(%ecx),%ecx     # ecx <- &ActiveProfilers
    291 #endif
    292 #if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
    293     movzbl (%eax),%eax             # eax <- debuggerActive (boolean)
    294     orl    (%ecx),%eax             # eax <- debuggerActive || activeProfilers
    295 #elif defined(WITH_DEBUGGER)
    296     movzbl (%eax),%eax             # eax <- debuggerActive (boolean)
    297 #elif defined(WITH_PROFILER)
    298     movl   (%ecx),%eax             # eax <= activeProfilers
    299 #endif
    300     GET_GLUE(%ecx)                 # restore rGLUE
    301     testl  %eax,%eax
    302     jne    3f                      # one or both active - switch interp
    303 #endif
    304 
    305     ret
    306 
    307     /* Check for suspend */
    308 1:
    309     /*  At this point, the return pointer to the caller of
    310      *  common_periodicChecks is on the top of stack.  We need to preserve
    311      *  rPC(edx) and GLUE(ecx).  We'll spill rPC, and reload GLUE.
    312      *  The outgoing profile is:
    313      *      bool dvmCheckSuspendPending(Thread* self)
    314      *  Because we reached here via a call, go ahead and build a new frame.
    315      */
    316     EXPORT_PC()                         # need for precise GC
    317     movl    offGlue_self(%ecx),%eax      # eax<- glue->self
    318     SPILL(rPC)                      # save edx
    319     push    %ebp
    320     movl    %esp,%ebp
    321     subl    $$24,%esp
    322     movl    %eax,OUT_ARG0(%esp)
    323     call    dvmCheckSuspendPending
    324     addl    $$24,%esp
    325     pop     %ebp
    326     UNSPILL(rPC)
    327     GET_GLUE(%ecx)
    328     ret
    329 
    330     /* Switch interpreters */
    331     /* Note: %ebx contains the 16-bit word offset to be applied to rPC to
    332      * "complete" the interpretation of backwards branches.  In effect, we
    333      * are completing the interpretation of the branch instruction here,
    334      * and the new interpreter will resume interpretation at the branch
    335      * target. However, a switch request recognized during the handling
    336      * of a return from method instruction results in an immediate abort,
    337      * and the new interpreter will resume by re-interpreting the return
    338      * instruction.
    339      */
    340 3:
    341     leal    (rPC,%ebx,2),rPC       # adjust pc to show target
    342     GET_GLUE(%ecx)                 # bail expect GLUE already loaded
    343     movl    $$1,rINST_FULL         # set changeInterp to true
    344     jmp     common_gotoBail
    345 
    346 
    347 /*
    348  * Common code for handling a return instruction
    349  */
    350 common_returnFromMethod:
    351     GET_GLUE(%ecx)
    352     /* Set entry mode in case we bail */
    353     movb    $$kInterpEntryReturn,offGlue_entryPoint(%ecx)
    354     xorl    rINST_FULL,rINST_FULL   # zero offset in case we switch interps
    355     call    common_periodicChecks   # Note: expects %ecx to be preserved
    356 
    357     SAVEAREA_FROM_FP(%eax,rFP)                    # eax<- saveArea (old)
    358     movl    offStackSaveArea_prevFrame(%eax),rFP  # rFP<- prevFrame
    359     movl    (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST_FULL
    360     cmpl    $$0,rINST_FULL                        # break?
    361     je      common_gotoBail    # break frame, bail out completely
    362 
    363     movl    offStackSaveArea_savedPc(%eax),rPC    # pc<- saveArea->savedPC
    364     movl    offGlue_self(%ecx),%eax               # eax<- self
    365     movl    rINST_FULL,offGlue_method(%ecx)  # glue->method = newSave->meethod
    366     movl    rFP,offThread_curFrame(%eax)     # self->curFrame = fp
    367     movl    offMethod_clazz(rINST_FULL),%eax # eax<- method->clazz
    368     FETCH_INST_WORD(3)
    369     movl    offClassObject_pDvmDex(%eax),%eax # eax<- method->clazz->pDvmDex
    370     ADVANCE_PC(3)
    371     movl    %eax,offGlue_methodClassDex(%ecx)
    372     /* not bailing - restore entry mode to default */
    373     movb    $$kInterpEntryInstr,offGlue_entryPoint(%ecx)
    374     GOTO_NEXT
    375 
    376 /*
    377  * Prepare to strip the current frame and "longjump" back to caller of
    378  * dvmMterpStdRun.
    379  *
    380  * on entry:
    381  *    rINST_FULL holds changeInterp
    382  *    ecx holds glue pointer
    383  *
    384  * expected profile: dvmMterpStdBail(MterpGlue *glue, bool changeInterp)
    385  */
    386 common_gotoBail:
    387     SAVE_PC_TO_GLUE(%ecx)                # export state to glue
    388     SAVE_FP_TO_GLUE(%ecx)
    389     movl   %ecx,OUT_ARG0(%esp)           # glue in arg0
    390     movl   rINST_FULL,OUT_ARG1(%esp)     # changeInterp in arg1
    391     call    dvmMterpStdBail              # bail out....
    392 
    393 
    394 /*
    395  * After returning from a "glued" function, pull out the updated values
    396  * and start executing at the next instruction.
    397  */
    398  common_resumeAfterGlueCall:
    399      GET_GLUE(%ecx)
    400      LOAD_PC_FROM_GLUE(%ecx)
    401      LOAD_FP_FROM_GLUE(%ecx)
    402      FETCH_INST()
    403      GOTO_NEXT
    404 
    405 /*
    406  * Integer divide or mod by zero
    407  */
    408 common_errDivideByZero:
    409     EXPORT_PC()
    410     movl    $$.LstrArithmeticException,%eax
    411     movl    %eax,OUT_ARG0(%esp)
    412     movl    $$.LstrDivideByZero,%eax
    413     movl    %eax,OUT_ARG1(%esp)
    414     SPILL(rPC)
    415     call    dvmThrowException
    416     UNSPILL(rPC)
    417     jmp     common_exceptionThrown
    418 
    419 /*
    420  * Attempt to allocate an array with a negative size.
    421  */
    422 common_errNegativeArraySize:
    423     EXPORT_PC()
    424     movl    $$.LstrNegativeArraySizeException,%eax
    425     movl    %eax,OUT_ARG0(%esp)
    426     xorl    %eax,%eax
    427     movl    %eax,OUT_ARG1(%esp)
    428     SPILL(rPC)
    429     call    dvmThrowException
    430     UNSPILL(rPC)
    431     jmp     common_exceptionThrown
    432 
    433 /*
    434  * Attempt to allocate an array with a negative size.
    435  */
    436 common_errNoSuchMethod:
    437 
    438     EXPORT_PC()
    439     movl    $$.LstrNoSuchMethodError,%eax
    440     movl    %eax,OUT_ARG0(%esp)
    441     xorl    %eax,%eax
    442     movl    %eax,OUT_ARG1(%esp)
    443     SPILL(rPC)
    444     call    dvmThrowException
    445     UNSPILL(rPC)
    446     jmp     common_exceptionThrown
    447 
    448 /*
    449  * Hit a null object when we weren't expecting one.  Export the PC, throw a
    450  * NullPointerException and goto the exception processing code.
    451  */
    452 common_errNullObject:
    453     EXPORT_PC()
    454     movl    $$.LstrNullPointerException,%eax
    455     movl    %eax,OUT_ARG0(%esp)
    456     xorl    %eax,%eax
    457     movl    %eax,OUT_ARG1(%esp)
    458     SPILL(rPC)
    459     call    dvmThrowException
    460     UNSPILL(rPC)
    461     jmp     common_exceptionThrown
    462 
    463 /*
    464  * Array index exceeds max.
    465  */
    466 common_errArrayIndex:
    467     EXPORT_PC()
    468     movl    $$.LstrArrayIndexException,%eax
    469     movl    %eax,OUT_ARG0(%esp)
    470     xorl    %eax,%eax
    471     movl    %eax,OUT_ARG1(%esp)
    472     SPILL(rPC)
    473     call    dvmThrowException
    474     UNSPILL(rPC)
    475     jmp     common_exceptionThrown
    476 /*
    477  * Invalid array value.
    478  */
    479 common_errArrayStore:
    480     EXPORT_PC()
    481     movl    $$.LstrArrayStoreException,%eax
    482     movl    %eax,OUT_ARG0(%esp)
    483     xorl    %eax,%eax
    484     movl    %eax,OUT_ARG1(%esp)
    485     SPILL(rPC)
    486     call    dvmThrowException
    487     UNSPILL(rPC)
    488     jmp     common_exceptionThrown
    489 
    490 /*
    491  * Somebody has thrown an exception.  Handle it.
    492  *
    493  * If the exception processing code returns to us (instead of falling
    494  * out of the interpreter), continue with whatever the next instruction
    495  * now happens to be.
    496  *
    497  * This does not return.
    498  */
    499 common_exceptionThrown:
    500     GET_GLUE(%ecx)
    501     SAVE_PC_TO_GLUE(%ecx)
    502     SAVE_FP_TO_GLUE(%ecx)
    503     movl    %ecx,OUT_ARG0(%esp)
    504     call    dvmMterp_exceptionThrown
    505     jmp     common_resumeAfterGlueCall
    506 
    507 common_abort:
    508     movl    $$0xdeadf00d,%eax
    509     call     *%eax
    510 
    511 
    512 /*
    513  * Strings
    514  */
    515 
    516     .section     .rodata
    517 .LstrNullPointerException:
    518     .asciz    "Ljava/lang/NullPointerException;"
    519 .LstrArithmeticException:
    520     .asciz  "Ljava/lang/ArithmeticException;"
    521 .LstrDivideByZero:
    522     .asciz  "divide by zero"
    523 .LstrArrayIndexException:
    524     .asciz  "Ljava/lang/ArrayIndexOutOfBoundsException;"
    525 .LstrArrayStoreException:
    526     .asciz  "Ljava/lang/ArrayStoreException;"
    527 .LstrNegativeArraySizeException:
    528     .asciz  "Ljava/lang/NegativeArraySizeException;"
    529 .LstrInstantiationError:
    530     .asciz  "Ljava/lang/InstantiationError;"
    531 .LstrClassCastException:
    532     .asciz  "Ljava/lang/ClassCastException;"
    533 .LstrNoSuchMethodError:
    534     .asciz  "Ljava/lang/NoSuchMethodError;"
    535 .LstrInternalError:
    536     .asciz  "Ljava/lang/InternalError;"
    537 .LstrFilledNewArrayNotImpl:
    538     .asciz  "filled-new-array only implemented for 'int'"
    539 
    540