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