OSDN Git Service

am 6892cab9: am e4195e1c: Fix a type error in the allocation of non-moving arrays.
[android-x86/dalvik.git] / vm / mterp / x86 / footer.S
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  */
37 dvmJitToInterpPunt:
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  */
56 dvmJitToInterpSingleStep:
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  */
76 dvmJitToInterpNoChainNoProfile:
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
90 1:
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
102 dvmJitToInterpTraceSelectNoChain:
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 */
118 1:
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
126 2:
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
136 dvmJitToInterpTraceSelect:
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
158 dvmJitToInterpBackwardBranch:
159     .global dvmJitToInterpNormal
160 dvmJitToInterpNormal:
161     .global dvmJitToInterpNoChain
162 dvmJitToInterpNoChain:
163 toInterpreter:
164     jmp  common_abort
165
166 common_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
174 1:
175     GOTO_NEXT
176 2:
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
195 1:
196     movl   $$kJitTSelectRequest,%eax
197     # On entry, eax<- jitState, rPC valid
198 common_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 jumbo method invocation.
214  *
215  * On entry:
216  *   eax = Method* methodToCall
217  *   rINSTw trashed, must reload
218  *   rIBASE trashed, must reload before resuming interpreter
219  */
220
221 common_invokeMethodJumbo:
222 .LinvokeNewJumbo:
223
224    /*
225     * prepare to copy args to "outs" area of current frame
226     */
227     movzwl      6(rPC),rINST            # rINST<- BBBB
228     movzwl      8(rPC), %ecx            # %ecx<- CCCC
229     ADVANCE_PC 2                        # adjust pc to make return similar
230     SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
231     test        rINST, rINST
232     movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BBBB
233     jz          .LinvokeArgsDone        # no args; jump to args done
234     jmp         .LinvokeRangeArgs       # handle args like invoke range
235
236 /*
237  * Common code for method invocation with range.
238  *
239  * On entry:
240  *   eax = Method* methodToCall
241  *   rINSTw trashed, must reload
242  *   rIBASE trashed, must reload before resuming interpreter
243  */
244
245 common_invokeMethodRange:
246 .LinvokeNewRange:
247
248    /*
249     * prepare to copy args to "outs" area of current frame
250     */
251
252     movzbl      1(rPC),rINST       # rINST<- AA
253     movzwl      4(rPC), %ecx            # %ecx<- CCCC
254     SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
255     test        rINST, rINST
256     movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
257     jz          .LinvokeArgsDone        # no args; jump to args done
258
259
260    /*
261     * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count,
262     * %edx=&outs (&stackSaveArea).  (very few methods have > 10 args;
263     * could unroll for common cases)
264     */
265
266 .LinvokeRangeArgs:
267     movl        %ebx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- save %ebx
268     lea         (rFP, %ecx, 4), %ecx    # %ecx<- &vCCCC
269     shll        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
270     subl        LOCAL0_OFFSET(%ebp), %edx       # %edx<- update &outs
271     shrl        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
272 1:
273     movl        (%ecx), %ebx            # %ebx<- vCCCC
274     lea         4(%ecx), %ecx           # %ecx<- &vCCCC++
275     subl        $$1, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET<- LOCAL0_OFFSET--
276     movl        %ebx, (%edx)            # *outs<- vCCCC
277     lea         4(%edx), %edx           # outs++
278     jne         1b                      # loop if count (LOCAL0_OFFSET(%ebp)) not zero
279     movl        LOCAL1_OFFSET(%ebp), %ebx       # %ebx<- restore %ebx
280     jmp         .LinvokeArgsDone        # continue
281
282    /*
283     * %eax is "Method* methodToCall", the method we're trying to call
284     * prepare to copy args to "outs" area of current frame
285     * rIBASE trashed, must reload before resuming interpreter
286     */
287
288 common_invokeMethodNoRange:
289 .LinvokeNewNoRange:
290     movzbl      1(rPC),rINST       # rINST<- BA
291     movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
292     shrl        $$4, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- B
293     je          .LinvokeArgsDone        # no args; jump to args done
294     movzwl      4(rPC), %ecx            # %ecx<- GFED
295     SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
296
297    /*
298     * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
299     */
300
301 .LinvokeNonRange:
302     cmp         $$2, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 2
303     movl        %ecx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- GFED
304     jl          1f                      # handle 1 arg
305     je          2f                      # handle 2 args
306     cmp         $$4, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 4
307     jl          3f                      # handle 3 args
308     je          4f                      # handle 4 args
309 5:
310     andl        $$15, rINST             # rINSTw<- A
311     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
312     movl        (rFP, rINST, 4), %ecx   # %ecx<- vA
313     movl        %ecx, (%edx)            # *outs<- vA
314     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
315 4:
316     shr         $$12, %ecx              # %ecx<- G
317     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
318     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vG
319     movl        %ecx, (%edx)            # *outs<- vG
320     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
321 3:
322     and         $$0x0f00, %ecx          # %ecx<- 0F00
323     shr         $$8, %ecx               # %ecx<- F
324     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
325     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vF
326     movl        %ecx, (%edx)            # *outs<- vF
327     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
328 2:
329     and         $$0x00f0, %ecx          # %ecx<- 00E0
330     shr         $$4, %ecx               # %ecx<- E
331     lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
332     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vE
333     movl        %ecx, (%edx)            # *outs<- vE
334     movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
335 1:
336     and         $$0x000f, %ecx          # %ecx<- 000D
337     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vD
338     movl        %ecx, -4(%edx)          # *--outs<- vD
339 0:
340
341    /*
342     * %eax is "Method* methodToCall", the method we're trying to call
343     * find space for the new stack frame, check for overflow
344     */
345
346 .LinvokeArgsDone:
347     movzwl      offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
348     movzwl      offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
349     movl        %eax, LOCAL0_OFFSET(%ebp)       # LOCAL0_OFFSET<- methodToCall
350     shl         $$2, %edx               # %edx<- update offset
351     SAVEAREA_FROM_FP %eax               # %eax<- &StackSaveArea
352     subl        %edx, %eax              # %eax<- newFP; (old savearea - regsSize)
353     movl        rSELF,%edx              # %edx<- pthread
354     movl        %eax, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- &outs
355     subl        $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
356     movl        offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd
357     movl        %edx, TMP_SPILL1(%ebp)  # spill self->interpStackEnd
358     shl         $$2, %ecx               # %ecx<- update offset for outsSize
359     movl        %eax, %edx              # %edx<- newSaveArea
360     sub         %ecx, %eax              # %eax<- bottom; (newSaveArea - outsSize)
361     cmp         TMP_SPILL1(%ebp), %eax  # compare interpStackEnd and bottom
362     movl        LOCAL0_OFFSET(%ebp), %eax       # %eax<- restore methodToCall
363     jl          .LstackOverflow         # handle frame overflow
364
365    /*
366     * set up newSaveArea
367     */
368
369 #ifdef EASY_GDB
370     SAVEAREA_FROM_FP %ecx               # %ecx<- &StackSaveArea
371     movl        %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
372 #endif
373     movl        rSELF,%ecx              # %ecx<- pthread
374     movl        rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
375     movl        rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
376
377     /* Any special actions to take? */
378     cmpb        $$0, offThread_subMode(%ecx)
379     jne         2f                     # Yes - handle them
380 1:
381     testl       $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
382     movl        %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
383     jne         .LinvokeNative          # handle native call
384
385    /*
386     * Update "self" values for the new method
387     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
388     */
389     movl        offMethod_clazz(%eax), %edx # %edx<- method->clazz
390     movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
391     movl        %eax, offThread_method(%ecx) # self->method<- methodToCall
392     movl        %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex
393     movl        offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
394     movl        $$1, offThread_debugIsMethodEntry(%ecx)
395     movl        LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
396     movl        rFP, offThread_curFrame(%ecx) # self->curFrame<- newFP
397     movl        offThread_curHandlerTable(%ecx),rIBASE
398     FETCH_INST
399     GOTO_NEXT                           # jump to methodToCall->insns
400
401 2:
402     /*
403      * On entry, preserve all:
404      *  %eax: method
405      *  %ecx: self
406      *  %edx: new save area
407      */
408     SPILL_TMP1(%eax)                   # preserve methodToCall
409     SPILL_TMP2(%edx)                   # preserve newSaveArea
410     movl        rPC, offThread_pc(%ecx) # update interpSave.pc
411     movl        rFP, offThread_fp(%ecx) # update interpSave.fp
412     movl        %ecx, OUT_ARG0(%esp)
413     movl        %eax, OUT_ARG1(%esp)
414     call        dvmReportInvoke        # (self, method)
415     UNSPILL_TMP1(%eax)
416     UNSPILL_TMP2(%edx)
417     movl        rSELF,%ecx             # restore rSELF
418     jmp         1b
419
420    /*
421     * Prep for the native call
422     * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
423     */
424
425 .LinvokeNative:
426     movl        offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->...
427     movl        rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
428     movl        %edx, LOCAL2_OFFSET(%ebp)  # save newSaveArea
429     movl        LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP
430     movl        rINST, offThread_curFrame(%ecx)  # self->curFrame<- newFP
431     cmpb        $$0, offThread_subMode(%ecx)  # Anything special going on?
432     jne         11f                     # yes - handle it
433     movl        %ecx, OUT_ARG3(%esp)    # push parameter self
434     movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
435     lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
436     movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
437     movl        rINST, OUT_ARG0(%esp)    # push parameter newFP
438     call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
439 7:
440     movl        LOCAL2_OFFSET(%ebp), %ecx    # %ecx<- newSaveArea
441     movl        rSELF, %eax             # %eax<- self
442     movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
443     cmp         $$0, offThread_exception(%eax) # check for exception
444     movl        rFP, offThread_curFrame(%eax) # self->curFrame<- rFP
445     movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
446     jne         common_exceptionThrown  # handle exception
447     movl        offThread_curHandlerTable(%eax),rIBASE
448     FETCH_INST_OPCODE 3 %ecx
449     ADVANCE_PC 3
450     GOTO_NEXT_R %ecx                    # jump to next instruction
451
452 11:
453     /*
454      * Handle any special subMode actions
455      * %eax=methodToCall, rINST=newFP, %ecx=self
456      */
457     SPILL_TMP1(%eax)                    # save methodTocall
458     movl        rPC, offThread_pc(%ecx)
459     movl        rFP, offThread_fp(%ecx)
460     movl        %ecx, OUT_ARG0(%esp)
461     movl        %eax, OUT_ARG1(%esp)
462     call        dvmReportPreNativeInvoke # (self, methodToCall)
463     UNSPILL_TMP1(%eax)                  # restore methodToCall
464     movl        rSELF,%ecx              # restore self
465
466     /* Do the native call */
467     movl        %ecx, OUT_ARG3(%esp)    # push parameter self
468     lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
469     movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
470     movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
471     movl        rINST, OUT_ARG0(%esp)   # push parameter newFP
472     call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
473
474     UNSPILL_TMP1(%eax)                  # restore methodToCall
475     movl        rSELF, %ecx
476     movl        %ecx, OUT_ARG0(%esp)
477     movl        %eax, OUT_ARG1(%esp)
478     call        dvmReportPostNativeInvoke # (self, methodToCall)
479     jmp         7b                      # rejoin
480
481 .LstackOverflow:    # eax=methodToCall
482     movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
483     movl        rSELF,%eax              # %eax<- self
484     movl        %eax, OUT_ARG0(%esp)    # push parameter self
485     call        dvmHandleStackOverflow  # call: (Thread* self, Method* meth)
486     jmp         common_exceptionThrown  # handle exception
487
488
489 /*
490  * Common code for handling a return instruction
491  */
492 common_returnFromMethod:
493     movl    rSELF,%ecx
494     SAVEAREA_FROM_FP %eax                         # eax<- saveArea (old)
495     movl    offStackSaveArea_prevFrame(%eax),rFP  # rFP<- prevFrame
496     cmpb    $$0, offThread_subMode(%ecx)          # special action needed?
497     jne     19f                                   # go if so
498 14:
499     movl    (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
500     cmpl    $$0,rINST                             # break?
501     je      common_gotoBail    # break frame, bail out completely
502
503     movl    offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
504     movl    rINST,offThread_method(%ecx)       # self->method = newSave->meethod
505     movl    rFP,offThread_curFrame(%ecx)       # self->curFrame = fp
506     movl    offMethod_clazz(rINST),%eax        # eax<- method->clazz
507     movl    offThread_curHandlerTable(%ecx),rIBASE
508     movl    offClassObject_pDvmDex(%eax),rINST # rINST<- method->clazz->pDvmDex
509     FETCH_INST_OPCODE 3 %eax
510     movl    rINST,offThread_methodClassDex(%ecx)
511     ADVANCE_PC 3
512     GOTO_NEXT_R %eax
513
514 19:
515     /*
516      * Handle special subMode actions
517      * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
518      */
519     movl     rFP, offThread_fp(%ecx)          # update interpSave.fp
520     movl     rPC, offThread_pc(%ecx)          # update interpSave.pc
521     movl     %ecx, OUT_ARG0(%esp)             # parameter self
522     call     dvmReportReturn                  # (self)
523     movl     rSELF, %ecx                      # restore self
524     SAVEAREA_FROM_FP %eax                     # restore saveArea
525     jmp      14b
526
527
528 /*
529  * Prepare to strip the current frame and "longjump" back to caller of
530  * dvmMterpStdRun.
531  *
532  * on entry:
533  *    rINST holds changeInterp
534  *    ecx holds self pointer
535  *
536  * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
537  */
538 common_gotoBail:
539     movl   rPC,offThread_pc(%ecx)     # export state to self
540     movl   rFP,offThread_fp(%ecx)
541     movl   %ecx,OUT_ARG0(%esp)      # self in arg0
542     movl   rINST,OUT_ARG1(%esp)     # changeInterp in arg1
543     call   dvmMterpStdBail          # bail out....
544
545
546 /*
547  * After returning from a "selfd" function, pull out the updated values
548  * and start executing at the next instruction.
549  */
550  common_resumeAfterGlueCall:
551      movl  rSELF, %eax
552      movl  offThread_pc(%eax),rPC
553      movl  offThread_fp(%eax),rFP
554      movl  offThread_curHandlerTable(%eax),rIBASE
555      FETCH_INST
556      GOTO_NEXT
557
558 /*
559  * Integer divide or mod by zero
560  */
561 common_errDivideByZero:
562     EXPORT_PC
563     movl    $$.LstrDivideByZero,%eax
564     movl    %eax,OUT_ARG0(%esp)
565     call    dvmThrowArithmeticException
566     jmp     common_exceptionThrown
567
568 /*
569  * Attempt to allocate an array with a negative size.
570  * On entry, len in eax
571  */
572 common_errNegativeArraySize:
573     EXPORT_PC
574     movl    %eax,OUT_ARG0(%esp)                  # arg0<- len
575     call    dvmThrowNegativeArraySizeException   # (len)
576     jmp     common_exceptionThrown
577
578 /*
579  * Attempt to allocate an array with a negative size.
580  * On entry, method name in eax
581  */
582 common_errNoSuchMethod:
583
584     EXPORT_PC
585     movl    %eax,OUT_ARG0(%esp)
586     call    dvmThrowNoSuchMethodError
587     jmp     common_exceptionThrown
588
589 /*
590  * Hit a null object when we weren't expecting one.  Export the PC, throw a
591  * NullPointerException and goto the exception processing code.
592  */
593 common_errNullObject:
594     EXPORT_PC
595     xorl    %eax,%eax
596     movl    %eax,OUT_ARG0(%esp)
597     call    dvmThrowNullPointerException
598     jmp     common_exceptionThrown
599
600 /*
601  * Array index exceeds max.
602  * On entry:
603  *    eax <- array object
604  *    ecx <- index
605  */
606 common_errArrayIndex:
607     EXPORT_PC
608     movl    offArrayObject_length(%eax), %eax
609     movl    %eax,OUT_ARG0(%esp)
610     movl    %ecx,OUT_ARG1(%esp)
611     call    dvmThrowArrayIndexOutOfBoundsException   # args (length, index)
612     jmp     common_exceptionThrown
613
614 /*
615  * Somebody has thrown an exception.  Handle it.
616  *
617  * If the exception processing code returns to us (instead of falling
618  * out of the interpreter), continue with whatever the next instruction
619  * now happens to be.
620  *
621  * NOTE: special subMode handling done in dvmMterp_exceptionThrown
622  *
623  * This does not return.
624  */
625 common_exceptionThrown:
626     movl    rSELF,%ecx
627     movl    rPC,offThread_pc(%ecx)
628     movl    rFP,offThread_fp(%ecx)
629     movl    %ecx,OUT_ARG0(%esp)
630     call    dvmMterp_exceptionThrown
631     jmp     common_resumeAfterGlueCall
632
633 common_abort:
634     movl    $$0xdeadf00d,%eax
635     call     *%eax
636
637
638 /*
639  * Strings
640  */
641
642     .section     .rodata
643 .LstrDivideByZero:
644     .asciz  "divide by zero"
645 .LstrFilledNewArrayNotImplA:
646     .asciz  "filled-new-array only implemented for 'int'"