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