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)
374:
38    movl        offGlue_pDebuggerActive(%edx), %eax # %eax<- pDebuggerActive
39    testl       %eax, %eax
40    je          5f
41    movzbl        (%eax), %eax            # %eax<- get debuggerActive (boolean)
425:
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
512:                                      # 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
623:                                      # 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
78common_periodicChecks_backwardBranch:
79    EXPORT_PC
80    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
81    movl        offGlue_pSelfSuspendCount(%ecx), rINST # %ebx<- pSuspendCount (int)
824:
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
875:
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
942:                                      # 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
1043:                                      # 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
119common_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
141common_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
1641:
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
179common_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
1995:
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
2054:
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
2113:
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
2182:
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
2251:
226    and         $$0x000f, %edx          # %edx<- 000D
227    movl        (rFP, %edx, 4), %edx    # %edx<- vD
228    movl        %edx, -4(%eax)          # *--outs<- vD
2290:
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
311dalvik_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
346common_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
3652:                                      # 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
3733:                                      # 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    */
3824:
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
405common_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
4701:
471    movl        %ecx, -12(%esp)         # push parameter 2 glue->self
4722:
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
5001:
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    */
5231:
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
539common_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
547common_abort:
548    jmp         .LdeadFood
549
550.LdeadFood:
551.int 0xdeadf00d
552
553   /*
554    * Invalid array index.
555    */
556
557common_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
571common_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
585common_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
599common_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
613common_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
627common_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