OSDN Git Service

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