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