footer.S revision 0c2dc522d0e120f346cf0a40c8cf0c93346131c2
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    GET_PC
39#if defined(WITH_JIT_TUNING)
40    movl   rPC, OUT_ARG0(%esp)
41    call   dvmBumpPunt
42#endif
43    movl   rSELF, %ecx
44    movl   offThread_curHandlerTable(%ecx),rIBASE
45    movl        $$0, offThread_inJitCodeCache(%ecx)
46    FETCH_INST_R %ecx
47    GOTO_NEXT_R %ecx
48
49    .global dvmJitToInterpSingleStep
50/*
51 * Return to the interpreter to handle a single instruction.
52 * Should be reached via a call.
53 * On entry:
54 *   0(%esp)          <= native return address within trace
55 *   rPC              <= Dalvik PC of this instruction
56 *   OUT_ARG0+4(%esp) <= Dalvik PC of next instruction
57 */
58dvmJitToInterpSingleStep:
59/* TODO */
60    call     dvmAbort
61#if 0
62    pop    %eax
63    movl   rSELF, %ecx
64    movl   OUT_ARG0(%esp), %edx
65    movl   %eax,offThread_jitResumeNPC(%ecx)
66    movl   %edx,offThread_jitResumeDPC(%ecx)
67    movl   $$kInterpEntryInstr,offThread_entryPoint(%ecx)
68    movl   $$1,rINST     # changeInterp <= true
69    jmp    common_gotoBail
70#endif
71
72    .global dvmJitToInterpNoChainNoProfile
73/*
74 * Return from the translation cache to the interpreter to do method
75 * invocation.  Check if the translation exists for the callee, but don't
76 * chain to it. rPC must be set on entry.
77 */
78dvmJitToInterpNoChainNoProfile:
79#if defined(WITH_JIT_TUNING)
80    call   dvmBumpNoChain
81#endif
82    movl   %eax, rPC
83    movl   rSELF, %eax
84    movl   rPC,OUT_ARG0(%esp)
85    movl   %eax,OUT_ARG1(%esp)
86    call   dvmJitGetTraceAddrThread  # (pc, self)
87    movl   rSELF,%ecx                # ecx <- self
88    movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
89    cmpl   $$0, %eax
90    jz     1f
91    jmp    *%eax                     # exec translation if we've got one
92    # won't return
931:
94    EXPORT_PC
95    movl   rSELF, %ecx
96    movl   offThread_curHandlerTable(%ecx),rIBASE
97    FETCH_INST_R %ecx
98    GOTO_NEXT_R %ecx
99
100/*
101 * Return from the translation cache and immediately request a
102 * translation from the exit target, but don't attempt to chain.
103 * rPC set on entry.
104 */
105    .global dvmJitToInterpTraceSelectNoChain
106dvmJitToInterpTraceSelectNoChain:
107#if defined(WITH_JIT_TUNING)
108    call   dvmBumpNoChain
109#endif
110    movl   %ebx, rPC
111    lea    4(%esp), %esp #to recover the esp update due to function call
112    movl   rSELF, %eax
113    movl   rPC,OUT_ARG0(%esp)
114    movl   %eax,OUT_ARG1(%esp)
115    call   dvmJitGetTraceAddrThread  # (pc, self)
116    movl   rSELF,%ecx
117    cmpl   $$0,%eax
118    movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
119    jz     1f
120    jmp    *%eax              # jump to tranlation
121    # won't return
122
123/* No Translation - request one */
1241:
125    GET_JIT_PROF_TABLE %ecx %eax
126    cmpl   $$0, %eax          # JIT enabled?
127    jnz    2f                 # Request one if so
128    movl   rSELF, %ecx
129    movl   offThread_curHandlerTable(%ecx),rIBASE
130    FETCH_INST_R %ecx         # Continue interpreting if not
131    GOTO_NEXT_R %ecx
1322:
133    ## Looks like an EXPORT_PC is needed here. Now jmp to common_selectTrace2
134    movl   $$kJitTSelectRequestHot,%eax # ask for trace select
135    jmp    common_selectTrace
136
137/*
138 * Return from the translation cache and immediately request a
139 * translation for the exit target.  Reached via a call, and
140 * (TOS)->rPC.
141 */
142    .global dvmJitToInterpTraceSelect
143dvmJitToInterpTraceSelect:
144    movl   0(%esp), %eax          # get return address
145    movl   %ebx, rPC              # get first argument (target rPC)
146
147    ## TODO, need to clean up stack manipulation ... this isn't signal safe and
148    ## doesn't use the calling conventions of header.S
149    lea    4(%esp), %esp #to recover the esp update due to function call
150
151    ## An additional 5B instruction "jump 0" was added for a thread-safe
152    ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
153    lea    -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx
154    lea    -4(%esp), %esp
155    movl   rSELF, %eax
156    movl   rPC,OUT_ARG0(%esp)
157    movl   %eax,OUT_ARG1(%esp)
158    call   dvmJitGetTraceAddrThread # (pc, self)
159    lea    4(%esp), %esp
160    cmpl   $$0,%eax
161    movl   rSELF, %ecx
162    movl   %eax,offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
163    jz     1b                 # no - ask for one
164    movl   %eax,OUT_ARG0(%esp)
165    movl   rINST,OUT_ARG1(%esp)
166    call   dvmJitChain        # Attempt dvmJitChain(codeAddr,chainAddr)
167    cmpl   $$0,%eax           # Success?
168    jz     toInterpreter      # didn't chain - interpret
169    jmp    *%eax
170    # won't return
171
172/*
173 * Placeholder entries for x86 JIT
174 */
175    .global dvmJitToInterpBackwardBranch
176dvmJitToInterpBackwardBranch:
177
178    .global     dvmJitToExceptionThrown
179dvmJitToExceptionThrown: //rPC in
180    movl   rSELF, %edx
181    GET_PC
182    movl   $$0, offThread_inJitCodeCache(%edx)
183    jmp common_exceptionThrown
184
185    .global dvmJitToInterpNormal
186dvmJitToInterpNormal:
187/* one input: the target rPC value */
188    movl        0(%esp), %eax          # get return address
189    movl        %ebx, rPC              # get first argument (target rPC)
190
191    ## TODO, need to clean up stack manipulation ... this isn't signal safe and
192    ## doesn't use the calling conventions of header.S
193
194    ## An additional 5B instruction "jump 0" was added for a thread-safe
195    ## chaining cell update in JIT code cache. So the offset is now -17=-12-5.
196    lea         -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx
197    lea         4(%esp), %esp
198    movl        rPC, OUT_ARG0(%esp)
199    movl        rSELF, %ecx
200    movl        %ecx, OUT_ARG1(%esp)
201    call        dvmJitGetTraceAddrThread
202    ## Here is the change from using rGLUE to rSELF for accessing the
203    ## JIT code cache flag
204    movl        rSELF, %ecx
205    movl        %eax, offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
206    #lea         4(%esp), %esp
207    cmp         $$0, %eax
208    je          toInterpreter
209    #lea         -8(%esp), %esp
210    movl        %ebx, OUT_ARG1(%esp)    # %ebx live thorugh dvmJitGetTraceAddrThread
211    movl        %eax, OUT_ARG0(%esp)    # first argument
212    call        dvmJitChain
213    #lea         8(%esp), %esp
214    cmp         $$0, %eax
215    je          toInterpreter
216    jmp         *%eax                   #to native address
217
218    .global dvmJitToInterpNoChain
219dvmJitToInterpNoChain:
220dvmJitToInterpNoChain: #rPC in eax
221    ## TODO, need to clean up stack manipulation ... this isn't signal safe and
222    ## doesn't use the calling conventions of header.S
223    movl        %eax, rPC
224    movl        rPC, OUT_ARG0(%esp)
225    movl        rSELF, %ecx
226    movl        %ecx, OUT_ARG1(%esp)
227    call        dvmJitGetTraceAddrThread
228    ## Here is the change from using rGLUE to rSELF for accessing the
229    ## JIT code cache flag
230    movl        rSELF, %ecx
231    movl        %eax, offThread_inJitCodeCache(%ecx)  # set inJitCodeCache flag
232    cmp         $$0, %eax
233    je          toInterpreter
234    jmp         *%eax                   #to native address
235
236toInterpreter:
237    EXPORT_PC
238    movl        rSELF, %ecx
239    movl        offThread_curHandlerTable(%ecx), rIBASE
240    FETCH_INST
241    movl        offThread_pJitProfTable(%ecx), %eax
242    #Fallthrough
243
244/* ebx holds the pointer to the jit profile table
245   edx has the opCode */
246common_testUpdateProfile:
247    cmp         $$0, %eax
248    je          4f
249/* eax holds the pointer to the jit profile table
250   edx has the opCode
251   rPC points to the next bytecode */
252
253common_updateProfile:
254    # quick & dirty hash
255    movl   rPC, %ecx
256    shrl   $$12, %ecx
257    xorl   rPC, %ecx
258    andl   $$((1<<JIT_PROF_SIZE_LOG_2)-1), %ecx
259    decb   (%ecx,%eax)
260    #jmp    1f # remove
261    jz     2f
2621:
263    GOTO_NEXT
2642:
265common_Profile:
266/*
267 * Here, we switch to the debug interpreter to request
268 * trace selection.  First, though, check to see if there
269 * is already a native translation in place (and, if so,
270 * jump to it now.
271 */
272    SPILL(rIBASE)
273    SPILL_TMP1(rINST)
274    movl        rSELF, rIBASE
275    GET_JIT_THRESHOLD rIBASE rINST  # leaves rSELF in %ecx
276    EXPORT_PC
277    movb   rINSTbl,(%ecx,%eax)   # reset counter
278    movl   rIBASE,rINST            # preserve rSELF
279    movl   rSELF, %eax
280    movl   rPC,OUT_ARG0(%esp)
281    movl   rIBASE,OUT_ARG1(%esp)
282    call   dvmJitGetTraceAddrThread  # (pc, self)
283    UNSPILL(rIBASE)
284    movl   %eax,offThread_inJitCodeCache(rINST)   # set the inJitCodeCache flag
285    UNSPILL_TMP1(rINST)
286    cmpl   $$0,%eax
287    #jmp    1f # remove
288    jz     1f
289    jmp   *%eax        # TODO: decide call vs/ jmp!.  No return either way
2901:
291    movl   $$kJitTSelectRequest,%eax
292    # On entry, eax<- jitState, rPC valid
293common_selectTrace:
294    mov         %ebx, EBX_SPILL(%ebp)
295    movl        rSELF, %ebx
296    movzwl      offThread_subMode(%ebx), %ecx
297    and         $$(kSubModeJitTraceBuild | kSubModeJitSV), %ecx
298    jne         3f                     # already doing JIT work, continue
299    movl        %eax, offThread_jitState(%ebx)
300    movl        rSELF, %eax
301    movl       %eax, OUT_ARG0(%esp)
302
303/*
304 * Call out to validate trace-building request. If successful, rIBASE will be swapped
305 * to send us into single-steppign trace building mode, so we need to refresh before
306 * we continue.
307 */
308
309   EXPORT_PC
310   SAVE_PC_FP_TO_SELF %ecx
311   call dvmJitCheckTraceRequest
3123:
313   mov          EBX_SPILL(%ebp), %ebx
314   FETCH_INST
315   movl rSELF, %ecx
316   movl offThread_curHandlerTable(%ecx), rIBASE
3174:
318   GOTO_NEXT
319
320common_selectTrace2:
321    mov         %ebx, EBX_SPILL(%ebp)
322    movl        rSELF, %ebx
323    movl        %ebx, OUT_ARG0(%esp)
324    movl        %eax, offThread_jitState(%ebx)
325    movzwl      offThread_subMode(%ebx), %ecx
326    mov         EBX_SPILL(%ebp), %ebx
327    and         (kSubModeJitTraceBuild | kSubModeJitSV), %ecx
328    jne         3f                     # already doing JIT work, continue
329
330
331
332/*
333 * Call out to validate trace-building request. If successful, rIBASE will be swapped
334 * to send us into single-steppign trace building mode, so we need to refresh before
335 * we continue.
336 */
337
338   EXPORT_PC
339   SAVE_PC_FP_TO_SELF %ecx
340   call dvmJitCheckTraceRequest
3413:
342   FETCH_INST
343   movl rSELF, %ecx
344   movl offThread_curHandlerTable(%ecx), rIBASE
3454:
346   GOTO_NEXT
347
348#endif
349
350/*
351 * For the invoke codes we need to know what register holds the "this" pointer. However
352 * it seems the this pointer is assigned consistently most times it is in %ecx but other
353 * times it is in OP_INVOKE_INTERFACE_JUMBO OP_INVOKE_INTERFACE OP_INVOKE_SUPER_QUICK and
354 * OP_INVOKE_VIRTUAL_QUICK
355*/
356
357/*
358 * Common code for method invocation with range.
359 *
360 * On entry:
361 *   eax = Method* methodToCall
362 *   ecx = "this"
363 *   rINSTw trashed, must reload
364 *   rIBASE trashed, must reload before resuming interpreter
365 */
366
367common_invokeMethodRange:
368.LinvokeNewRange:
369#if defined(WITH_JIT)
370    SPILL_TMP1(%edx)
371    SPILL_TMP2(%ebx)
372    movl        rSELF, %edx
373    movzwl      offThread_subMode(%edx), %ebx
374    and         $$kSubModeJitTraceBuild, %ebx
375    jz          6f
376    call        save_callsiteinfo
3776:
378    UNSPILL_TMP2(%ebx)
379    UNSPILL_TMP1(%edx)
380#endif
381   /*
382    * prepare to copy args to "outs" area of current frame
383    */
384
385    movzbl      1(rPC),rINST       # rINST<- AA
386    movzwl      4(rPC), %ecx            # %ecx<- CCCC
387    SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
388    test        rINST, rINST
389    movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
390    jz          .LinvokeArgsDone        # no args; jump to args done
391
392
393   /*
394    * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count,
395    * %edx=&outs (&stackSaveArea).  (very few methods have > 10 args;
396    * could unroll for common cases)
397    */
398
399.LinvokeRangeArgs:
400    movl        %ebx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- save %ebx
401    lea         (rFP, %ecx, 4), %ecx    # %ecx<- &vCCCC
402    shll        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
403    subl        LOCAL0_OFFSET(%ebp), %edx       # %edx<- update &outs
404    shrl        $$2, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- offset
4051:
406    movl        (%ecx), %ebx            # %ebx<- vCCCC
407    lea         4(%ecx), %ecx           # %ecx<- &vCCCC++
408    subl        $$1, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET<- LOCAL0_OFFSET--
409    movl        %ebx, (%edx)            # *outs<- vCCCC
410    lea         4(%edx), %edx           # outs++
411    jne         1b                      # loop if count (LOCAL0_OFFSET(%ebp)) not zero
412    movl        LOCAL1_OFFSET(%ebp), %ebx       # %ebx<- restore %ebx
413    jmp         .LinvokeArgsDone        # continue
414
415   /*
416    * %eax is "Method* methodToCall", the method we're trying to call
417    * prepare to copy args to "outs" area of current frame
418    * rIBASE trashed, must reload before resuming interpreter
419    */
420
421common_invokeMethodNoRange:
422#if defined(WITH_JIT)
423    SPILL_TMP1(%edx)
424    SPILL_TMP2(%ebx)
425    movl        rSELF, %edx
426    movzwl      offThread_subMode(%edx), %ebx
427    and         $$kSubModeJitTraceBuild, %ebx
428    jz          6f
429    call        save_callsiteinfo
4306:
431    UNSPILL_TMP2(%ebx)
432    UNSPILL_TMP1(%edx)
433#endif
434.LinvokeNewNoRange:
435    movzbl      1(rPC),rINST       # rINST<- BA
436    movl        rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
437    shrl        $$4, LOCAL0_OFFSET(%ebp)        # LOCAL0_OFFSET(%ebp)<- B
438    je          .LinvokeArgsDone        # no args; jump to args done
439    movzwl      4(rPC), %ecx            # %ecx<- GFED
440    SAVEAREA_FROM_FP %edx               # %edx<- &StackSaveArea
441
442   /*
443    * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
444    */
445
446.LinvokeNonRange:
447    cmp         $$2, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 2
448    movl        %ecx, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- GFED
449    jl          1f                      # handle 1 arg
450    je          2f                      # handle 2 args
451    cmp         $$4, LOCAL0_OFFSET(%ebp)        # compare LOCAL0_OFFSET(%ebp) to 4
452    jl          3f                      # handle 3 args
453    je          4f                      # handle 4 args
4545:
455    andl        $$15, rINST             # rINSTw<- A
456    lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
457    movl        (rFP, rINST, 4), %ecx   # %ecx<- vA
458    movl        %ecx, (%edx)            # *outs<- vA
459    movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
4604:
461    shr         $$12, %ecx              # %ecx<- G
462    lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
463    movl        (rFP, %ecx, 4), %ecx    # %ecx<- vG
464    movl        %ecx, (%edx)            # *outs<- vG
465    movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
4663:
467    and         $$0x0f00, %ecx          # %ecx<- 0F00
468    shr         $$8, %ecx               # %ecx<- F
469    lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
470    movl        (rFP, %ecx, 4), %ecx    # %ecx<- vF
471    movl        %ecx, (%edx)            # *outs<- vF
472    movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
4732:
474    and         $$0x00f0, %ecx          # %ecx<- 00E0
475    shr         $$4, %ecx               # %ecx<- E
476    lea         -4(%edx), %edx          # %edx<- update &outs; &outs--
477    movl        (rFP, %ecx, 4), %ecx    # %ecx<- vE
478    movl        %ecx, (%edx)            # *outs<- vE
479    movl        LOCAL1_OFFSET(%ebp), %ecx       # %ecx<- GFED
4801:
481    and         $$0x000f, %ecx          # %ecx<- 000D
482    movl        (rFP, %ecx, 4), %ecx    # %ecx<- vD
483    movl        %ecx, -4(%edx)          # *--outs<- vD
4840:
485
486   /*
487    * %eax is "Method* methodToCall", the method we're trying to call
488    * find space for the new stack frame, check for overflow
489    */
490
491.LinvokeArgsDone:
492    movzwl      offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
493    movzwl      offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
494    movl        %eax, LOCAL0_OFFSET(%ebp)       # LOCAL0_OFFSET<- methodToCall
495    shl         $$2, %edx               # %edx<- update offset
496    SAVEAREA_FROM_FP %eax               # %eax<- &StackSaveArea
497    subl        %edx, %eax              # %eax<- newFP; (old savearea - regsSize)
498    movl        rSELF,%edx              # %edx<- pthread
499    movl        %eax, LOCAL1_OFFSET(%ebp)       # LOCAL1_OFFSET(%ebp)<- &outs
500    subl        $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
501    movl        offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd
502    movl        %edx, TMP_SPILL1(%ebp)  # spill self->interpStackEnd
503    shl         $$2, %ecx               # %ecx<- update offset for outsSize
504    movl        %eax, %edx              # %edx<- newSaveArea
505    sub         %ecx, %eax              # %eax<- bottom; (newSaveArea - outsSize)
506    cmp         TMP_SPILL1(%ebp), %eax  # compare interpStackEnd and bottom
507    movl        LOCAL0_OFFSET(%ebp), %eax       # %eax<- restore methodToCall
508    jl          .LstackOverflow         # handle frame overflow
509
510   /*
511    * set up newSaveArea
512    */
513
514#ifdef EASY_GDB
515    SAVEAREA_FROM_FP %ecx               # %ecx<- &StackSaveArea
516    movl        %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
517#endif
518    movl        rSELF,%ecx              # %ecx<- pthread
519    movl        rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
520    movl        rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
521#if defined(WITH_JIT)
522    movl        $$0, offStackSaveArea_returnAddr(%edx)
523#endif
524
525    /* Any special actions to take? */
526    cmpw        $$0, offThread_subMode(%ecx)
527    jne         2f                     # Yes - handle them
5281:
529    testl       $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
530    movl        %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
531    jne         .LinvokeNative          # handle native call
532
533   /*
534    * Update "self" values for the new method
535    * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
536    */
537    movl        offMethod_clazz(%eax), %edx # %edx<- method->clazz
538    movl        offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
539    movl        %eax, offThread_method(%ecx) # self->method<- methodToCall
540    movl        %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex
541    movl        offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
542    movl        $$1, offThread_debugIsMethodEntry(%ecx)
543    movl        LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
544    movl        rFP, offThread_curFrame(%ecx) # curFrame<-newFP
545    movl        offThread_curHandlerTable(%ecx),rIBASE
546    FETCH_INST
547#if defined(WITH_JIT)
548    /* rPC is already updated */
549    GET_JIT_PROF_TABLE %ecx %eax
550    cmp         $$0, %eax
551    jne         common_updateProfile # set up %ebx & %edx & rPC
552#endif
553    GOTO_NEXT                           # jump to methodToCall->insns
554
5552:
556    /*
557     * On entry, preserve all:
558     *  %eax: method
559     *  %ecx: self
560     *  %edx: new save area
561     */
562    SPILL_TMP1(%eax)                   # preserve methodToCall
563    SPILL_TMP2(%edx)                   # preserve newSaveArea
564    movl        rPC, offThread_pc(%ecx) # update interpSave.pc
565    movl        %ecx, OUT_ARG0(%esp)
566    movl        %eax, OUT_ARG1(%esp)
567    call        dvmReportInvoke        # (self, method)
568    UNSPILL_TMP1(%eax)
569    UNSPILL_TMP2(%edx)
570    movl        rSELF,%ecx             # restore rSELF
571    jmp         1b
572
573   /*
574    * Prep for the native call
575    * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
576    */
577
578.LinvokeNative:
579    movl        offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->...
580    movl        rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
581    movl        %edx, LOCAL2_OFFSET(%ebp)  # save newSaveArea
582    movl        LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP
583    movl        rINST, offThread_curFrame(%ecx)  # curFrame<- newFP
584    cmpw        $$0, offThread_subMode(%ecx)  # Anything special going on?
585    jne         11f                     # yes - handle it
586    movl        %ecx, OUT_ARG3(%esp)    # push parameter self
587    movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
588    lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
589    movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
590    movl        rINST, OUT_ARG0(%esp)    # push parameter newFP
591    call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
5927:
593    movl        LOCAL2_OFFSET(%ebp), %ecx    # %ecx<- newSaveArea
594    movl        rSELF, %eax             # %eax<- self
595    movl        offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
596    cmp         $$0, offThread_exception(%eax) # check for exception
597    movl        rFP, offThread_curFrame(%eax) # curFrame<- rFP
598    movl        %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
599    jne         common_exceptionThrown  # handle exception
600    movl        offThread_curHandlerTable(%eax),rIBASE
601    FETCH_INST_OPCODE 3 %ecx
602    ADVANCE_PC 3
603    GOTO_NEXT_R %ecx                    # jump to next instruction
604
60511:
606    /*
607     * Handle any special subMode actions
608     * %eax=methodToCall, rINST=newFP, %ecx=self
609     */
610    SPILL_TMP1(%eax)                    # save methodTocall
611    movl        rPC, offThread_pc(%ecx)
612    movl        %ecx, OUT_ARG1(%esp)
613    movl        %eax, OUT_ARG0(%esp)
614    movl        rFP, OUT_ARG2(%esp)
615    call        dvmReportPreNativeInvoke # (methodToCall, self, fp)
616    UNSPILL_TMP1(%eax)                  # restore methodToCall
617    movl        rSELF,%ecx              # restore self
618
619    /* Do the native call */
620    movl        %ecx, OUT_ARG3(%esp)    # push parameter self
621    lea         offThread_retval(%ecx), %ecx # %ecx<- &retval
622    movl        %eax, OUT_ARG2(%esp)    # push parameter methodToCall
623    movl        %ecx, OUT_ARG1(%esp)    # push parameter &retval
624    movl        rINST, OUT_ARG0(%esp)   # push parameter newFP
625    call        *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
626
627    UNSPILL_TMP1(%eax)                  # restore methodToCall
628    movl        rSELF, %ecx
629    movl        %ecx, OUT_ARG1(%esp)
630    movl        %eax, OUT_ARG0(%esp)
631    movl        rFP, OUT_ARG2(%esp)
632    call        dvmReportPostNativeInvoke # (methodToCall, self, fp)
633    jmp         7b                      # rejoin
634
635.LstackOverflow:    # eax=methodToCall
636    movl        %eax, OUT_ARG1(%esp)    # push parameter methodToCall
637    movl        rSELF,%eax              # %eax<- self
638    movl        %eax, OUT_ARG0(%esp)    # push parameter self
639    call        dvmHandleStackOverflow  # call: (Thread* self, Method* meth)
640    jmp         common_exceptionThrown  # handle exception
641
642
643/*
644 * Common code for handling a return instruction
645 */
646common_returnFromMethod:
647    movl    rSELF, %ecx
648    SAVEAREA_FROM_FP %eax                       # %eax<- saveArea(old)
649    cmpw    $$0, offThread_subMode(%ecx)          # special action needed?
650    jne     19f                                   # go if so
65114:
652
653    movl        offStackSaveArea_prevFrame(%eax), rFP # rFP<- saveArea->PrevFrame
654    movl        (offStackSaveArea_method - sizeofStackSaveArea)(rFP), rINST # rINST<- method we are returning to
655    cmpl        $$0, rINST               # check for break frame
656    je          common_gotoBail         # bail if break frame
657    movl        offThread_curHandlerTable(%ecx),rIBASE
658    movl        offStackSaveArea_savedPc(%eax), rPC # rPC<- saveAreaOld->savedPc
659#if defined(WITH_JIT)
660    movl        offStackSaveArea_returnAddr(%eax), %ecx
661#endif
662    movl        rSELF, %eax
663    movl        rINST, offThread_method(%eax) # glue->method<- newSave->method
664    movl        offMethod_clazz(rINST), rINST # rINST<- method->clazz
665    movl        rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
666#if defined(WITH_JIT)
667    //update self->offThread_inJitCodeCache
668    movl        %ecx, offThread_inJitCodeCache(%eax)
669#endif
670    movl        offClassObject_pDvmDex(rINST), rINST # rINST<- method->clazz->pDvmDex
671    movl        rINST, offThread_methodClassDex(%eax) # glue->pDvmDex<- method->clazz->pDvmDex
672#if defined(WITH_JIT)
673    cmp         $$0, %ecx
674    je          .returnToBC
675    movl        %ecx, %eax
676    jmp         *%eax
677#endif
678
679.returnToBC:
680
681#if defined(WITH_JIT)
682    FETCH_INST_OPCODE  3, %ecx                 # %eax<- next instruction hi; fetch, advance
683    // %ecx has the opcode
684    addl         $$6, rPC               # 3*2 = 6
685    SPILL_TMP1   (%ecx)
686    movl         rSELF, %ecx
687    FETCH_INST
688    UNSPILL_TMP1   (%ecx)
689    movzbl      1(rPC), rINST
690    jmp     *(rIBASE,%ecx,4)
691#else
692    FETCH_INST_WORD 3
693    ADVANCE_PC 3
694    GOTO_NEXT
695#endif
696
69719:
698    /*
699     * Handle special subMode actions
700     * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
701     */
702    SPILL_TMP1(%ebx)
703    movl     offStackSaveArea_prevFrame(%eax), %ebx # %ebx<- saveArea->PrevFrame
704    movl     rPC, offThread_pc(%ecx)          # update interpSave.pc
705    movl     %ebx, offThread_curFrame(%ecx)    # update interpSave.curFrame
706    movl     %ecx, OUT_ARG0(%esp)             # parameter self
707    call     dvmReportReturn                  # (self)
708    UNSPILL_TMP1(%ebx)
709    movl     rSELF, %ecx                      # restore self
710    SAVEAREA_FROM_FP %eax                     # restore saveArea
711    jmp      14b
712
713
714/*
715 * Prepare to strip the current frame and "longjump" back to caller of
716 * dvmMterpStdRun.
717 *
718 * on entry:
719 *    rINST holds changeInterp
720 *    ecx holds self pointer
721 *
722 * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
723 */
724common_gotoBail:
725    movl   rPC,offThread_pc(%ecx)     # export state to self
726    movl   rFP,offThread_curFrame(%ecx)
727    movl   %ecx,OUT_ARG0(%esp)      # self in arg0
728    movl   rINST,OUT_ARG1(%esp)     # changeInterp in arg1
729    call   dvmMterpStdBail          # bail out....
730
731/*
732 * The JIT's invoke method needs to remember the callsite class and
733 * target pair.  Save them here so that they are available to
734 * dvmCheckJit following the interpretation of this invoke.
735 *
736 * eax = Method* methodToCall
737 * ecx = "this"
738 * edx = rSELF
739 * ebx = free to use
740 */
741#if defined(WITH_JIT)
742save_callsiteinfo:
743    cmp     $$0, %ecx
744    je      2f
745    movl    offObject_clazz(%ecx), %ecx
7462:
747    movl    rSELF, %ebx
748    movl    %eax, offThread_methodToCall(%ebx)
749    movl    %ecx, offThread_callsiteClass(%ebx)
750    ret
751#endif
752
753#if defined(WITH_JIT)
754
755    /*
756     * If the JIT is actively building a trace we need to make sure
757     * that the field is fully resolved before including the current
758     * instruction.
759     *
760     * On entry:
761     *     %ecx: &dvmDex->pResFields[field]
762     *     %eax:  field pointer (must preserve)
763     */
764common_verifyField:
765    movl    %ebx, TMP_SPILL1(%ebp)
766    movl     rSELF, %ebx
767    movzwl   offThread_subMode(%ebx), %ebx
768    andl     $$kSubModeJitTraceBuild, %ebx
769    movl    TMP_SPILL1(%ebp), %ebx
770    jne      1f
771    ret
7721:
773    movl    (%ecx), %ecx
774    cmp     $$0, %ecx
775    je      1f
776    ret
7771:
778    SPILL_TMP1(%eax)
779    SPILL_TMP2(%edx)
780    movl     rSELF, %ecx
781    # Because we call into this helper from a bytecode, we have
782    # to be careful not to write over the return address when using
783    # the OUT_ARG macros
784    lea      -8(%esp), %esp
785    movl     %ecx, OUT_ARG0(%esp)
786    movl     rPC, OUT_ARG1(%esp)
787    call     dvmJitEndTraceSelect
788    lea      8(%esp), %esp
789    UNSPILL_TMP2(%edx)
790    UNSPILL_TMP1(%eax)
791    ret
792#endif
793
794/*
795 * After returning from a "selfd" function, pull out the updated values
796 * and start executing at the next instruction.
797 */
798common_resumeAfterGlueCall:
799     movl  rSELF, %eax
800     movl  offThread_pc(%eax),rPC
801     movl  offThread_curFrame(%eax),rFP
802     movl  offThread_curHandlerTable(%eax),rIBASE
803     FETCH_INST
804     GOTO_NEXT
805
806/*
807 * Integer divide or mod by zero
808 */
809common_errDivideByZero:
810    EXPORT_PC
811    movl    $$.LstrDivideByZero,%eax
812    movl    %eax,OUT_ARG0(%esp)
813    call    dvmThrowArithmeticException
814    jmp     common_exceptionThrown
815
816/*
817 * Attempt to allocate an array with a negative size.
818 * On entry, len in eax
819 */
820common_errNegativeArraySize:
821    EXPORT_PC
822    movl    %eax,OUT_ARG0(%esp)                  # arg0<- len
823    call    dvmThrowNegativeArraySizeException   # (len)
824    jmp     common_exceptionThrown
825
826/*
827 * Attempt to allocate an array with a negative size.
828 * On entry, method name in eax
829 */
830common_errNoSuchMethod:
831    EXPORT_PC
832    movl    %eax,OUT_ARG0(%esp)
833    call    dvmThrowNoSuchMethodError
834    jmp     common_exceptionThrown
835
836/*
837 * Hit a null object when we weren't expecting one.  Export the PC, throw a
838 * NullPointerException and goto the exception processing code.
839 */
840common_errNullObject:
841    EXPORT_PC
842    xorl    %eax,%eax
843    movl    %eax,OUT_ARG0(%esp)
844    call    dvmThrowNullPointerException
845    jmp     common_exceptionThrown
846
847/*
848 * Array index exceeds max.
849 * On entry:
850 *    eax <- array object
851 *    ecx <- index
852 */
853common_errArrayIndex:
854    EXPORT_PC
855    movl    offArrayObject_length(%eax), %eax
856    movl    %eax,OUT_ARG0(%esp)
857    movl    %ecx,OUT_ARG1(%esp)
858    call    dvmThrowArrayIndexOutOfBoundsException   # args (length, index)
859    jmp     common_exceptionThrown
860
861/*
862 * Somebody has thrown an exception.  Handle it.
863 *
864 * If the exception processing code returns to us (instead of falling
865 * out of the interpreter), continue with whatever the next instruction
866 * now happens to be.
867 *
868 * NOTE: special subMode handling done in dvmMterp_exceptionThrown
869 *
870 * This does not return.
871 */
872common_exceptionThrown:
873.LexceptionNew:
874
875    EXPORT_PC
876    movl       rSELF, %ecx
877    movl       %ecx, OUT_ARG0(%esp)
878    call       dvmCheckSuspendPending
879
880    movl       rSELF, %ecx
881    movl       offThread_exception(%ecx), %edx   # %edx <- self->exception
882    movl       %edx, OUT_ARG0(%esp)
883    movl       %ecx, OUT_ARG1(%esp)
884    SPILL_TMP1(%edx)
885    call       dvmAddTrackedAlloc      # don't let the exception be GCed
886    UNSPILL_TMP1(%edx)
887    movl       rSELF, %ecx
888    movl       offThread_subMode(%ecx), %eax    # get subMode flags
889    movl       $$0, offThread_exception(%ecx)
890
891    # Special subMode?
892    cmpl       $$0, %eax                # any special subMode handling needed?
893    je         8f                      # go if so
894
895    # Manage debugger bookkeeping
896    movl       rPC, offThread_pc(%ecx) # update interpSave.pc
897    movl       rFP, offThread_curFrame(%ecx) # update interpSave.curFrame
898    movl       %ecx, OUT_ARG0(%esp)
899    movl       %edx, OUT_ARG1(%esp)
900    SPILL_TMP1(%edx)
901    call       dvmReportExceptionThrow # (self, exception)
902    UNSPILL_TMP1(%edx)
903    movl       rSELF, %ecx
904
9058:
906    /*
907    * set up args and a local for &fp
908    */
909    lea        20(%esp), %esp          # raise %esp
910    movl       rFP, (%esp)               # save fp
911    movl       %esp, %eax              # %eax = &fp
912    lea        -20(%esp), %esp         # reset %esp
913    movl       %eax, OUT_ARG4(%esp)    # Arg 4 = &fp
914    movl       $$0, OUT_ARG3(%esp)      # Arg 3 = false
915    movl       %edx, OUT_ARG2(%esp)    # Arg 2 = exception
916    movl       %ecx, OUT_ARG0(%esp)    # Arg 0 = self
917
918    movl       offThread_method(%ecx), %eax # %eax = self->method
919    movl       offMethod_insns(%eax), %eax  # %eax = self->method->insn
920    # ldrh    lr, [rSELF, #offThread_subMode]  @ lr<- subMode flags  # TODO
921    movl       rPC, %ecx
922    subl       %eax, %ecx              # %ecx = pc - self->method->insn
923    sar        $$1, %ecx                # adjust %ecx for code offset
924    movl       %ecx, OUT_ARG1(%esp)    # Arg 1 = %ecx
925
926    /* call, %eax gets catchRelPc (a code-unit offset) */
927    SPILL_TMP1(%edx)                   # save exception
928    call       dvmFindCatchBlock       # call(self, relPc, exc, scan?, &fp)
929    UNSPILL_TMP1(%edx)                 # restore exception
930
931    /* fix earlier stack overflow if necessary; may trash rFP */
932    movl       rSELF, %ecx
933    cmpl       $$0, offThread_stackOverflowed(%ecx) # did we overflow?
934    je         1f                         # no, skip ahead
935    movl       %eax, rFP                  # save relPc result in rFP
936    movl       %ecx, OUT_ARG0(%esp)       # Arg 0 = self
937    movl       %edx, OUT_ARG1(%esp)       # Arg 1 = exception
938    SPILL_TMP1(%edx)
939    call       dvmCleanupStackOverflow    # call(self, exception)
940    UNSPILL_TMP1(%edx)
941    movl       rFP, %eax                  # restore result
942    movl       rSELF, %ecx
9431:
944
945    /* update frame pointer and check result from dvmFindCatchBlock */
946    movl       20(%esp), rFP              # retrieve the updated rFP
947    cmpl       $$0, %eax                  # is catchRelPc < 0?
948    jl         .LnotCaughtLocally
949
950    /* adjust locals to match self->interpSave.curFrame and updated PC */
951    SAVEAREA_FROM_FP rINST             # rINST<- new save area
952    movl       offStackSaveArea_method(rINST), rINST # rINST<- new method
953    movl       rINST, offThread_method(%ecx)         # self->method = new method
954    movl       offMethod_clazz(rINST), %ecx          # %ecx = method->clazz
955    movl       offMethod_insns(rINST), rINST         # rINST = method->insn
956    movl       offClassObject_pDvmDex(%ecx), %ecx    # %ecx = method->clazz->pDvmDex
957    lea        (rINST, %eax, 2), rPC      # rPC<- method->insns + catchRelPc
958    movl       rSELF, rINST
959    movl       %ecx, offThread_methodClassDex(rINST) # self->pDvmDex = method->clazz->pDvmDex
960
961    /* release the tracked alloc on the exception */
962    movl       %edx, OUT_ARG0(%esp)       # Arg 0 = exception
963    movl       rINST, OUT_ARG1(%esp)      # Arg 1 = self
964    SPILL_TMP1(%edx)
965    call       dvmReleaseTrackedAlloc     # release the exception
966    UNSPILL_TMP1(%edx)
967
968    /* restore the exception if the handler wants it */
969    movl       rSELF, %ecx
970    FETCH_INST
971    movzbl     rINSTbl, %eax
972    cmpl       $$OP_MOVE_EXCEPTION, %eax   # is it "move-exception"?
973    jne        1f
974    movl       %edx, offThread_exception(%ecx) # restore exception
9751:
976    movl       offThread_curHandlerTable(%ecx), rIBASE # refresh rIBASE
977    GOTO_NEXT
978
979.LnotCaughtLocally: # %edx = exception
980    /* fix stack overflow if necessary */
981    movl       rSELF, %ecx
982    movl       offThread_stackOverflowed(%ecx), %eax
983    cmpl       $$0, %eax                   # did we overflow earlier?
984    je         1f
985    movl       %ecx, OUT_ARG0(%esp)
986    movl       %edx, OUT_ARG1(%esp)
987    SPILL_TMP1(%edx)
988    call       dvmCleanupStackOverflow
989    UNSPILL_TMP1(%edx)
990
9911:
992    movl       rSELF, %ecx
993    movl       %edx, offThread_exception(%ecx) #restore exception
994    movl       %edx, OUT_ARG0(%esp)
995    movl       %ecx, OUT_ARG1(%esp)
996    call       dvmReleaseTrackedAlloc     # release the exception
997    movl       rSELF, %ecx
998    jmp        common_gotoBail            # bail out
999
1000common_abort:
1001    movl    $$0xdeadf00d,%eax
1002    call     *%eax
1003
1004
1005/*
1006 * Strings
1007 */
1008
1009    .section     .rodata
1010.LstrDivideByZero:
1011    .asciz  "divide by zero"
1012.LstrFilledNewArrayNotImplA:
1013    .asciz  "filled-new-array only implemented for 'int'"
1014