OSDN Git Service

am b498bf42: Merge "[X86] X86 trace JIT compiler support"
[android-x86/dalvik.git] / vm / mterp / x86 / footer.S
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /*
17  * Common subroutines and data.
18  */
19
20 #if defined(WITH_JIT)
21 /*
22  * JIT-related re-entries into the interpreter.  In general, if the
23  * exit from a translation can at some point be chained, the entry
24  * here requires that control arrived via a call, and that the "rp"
25  * on TOS is actually a pointer to a 32-bit cell containing the Dalvik PC
26  * of the next insn to handle.  If no chaining will happen, the entry
27  * should be reached via a direct jump and rPC set beforehand.
28  */
29
30     .global dvmJitToInterpPunt
31 /*
32  * The compiler will generate a jump to this entry point when it is
33  * having difficulty translating a Dalvik instruction.  We must skip
34  * the code cache lookup & prevent chaining to avoid bouncing between
35  * the interpreter and code cache. rPC must be set on entry.
36  */
37 dvmJitToInterpPunt:
38     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  */
58 dvmJitToInterpSingleStep:
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  */
78 dvmJitToInterpNoChainNoProfile:
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
93 1:
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
106 dvmJitToInterpTraceSelectNoChain:
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 */
124 1:
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
132 2:
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
143 dvmJitToInterpTraceSelect:
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
176 dvmJitToInterpBackwardBranch:
177
178     .global     dvmJitToExceptionThrown
179 dvmJitToExceptionThrown: //rPC in
180     movl   rSELF, %edx
181     GET_PC
182     movl   $$0, offThread_inJitCodeCache(%edx)
183     jmp common_exceptionThrown
184
185     .global dvmJitToInterpNormal
186 dvmJitToInterpNormal:
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
219 dvmJitToInterpNoChain:
220 dvmJitToInterpNoChain: #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
236 toInterpreter:
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 */
246 common_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
253 common_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
262 1:
263     GOTO_NEXT
264 2:
265 common_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
290 1:
291     movl   $$kJitTSelectRequest,%eax
292     # On entry, eax<- jitState, rPC valid
293 common_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
312 3:
313    mov          EBX_SPILL(%ebp), %ebx
314    FETCH_INST
315    movl rSELF, %ecx
316    movl offThread_curHandlerTable(%ecx), rIBASE
317 4:
318    GOTO_NEXT
319
320 common_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
341 3:
342    FETCH_INST
343    movl rSELF, %ecx
344    movl offThread_curHandlerTable(%ecx), rIBASE
345 4:
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
367 common_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
377 6:
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
405 1:
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
421 common_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
430 6:
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
454 5:
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
460 4:
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
466 3:
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
473 2:
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
480 1:
481     and         $$0x000f, %ecx          # %ecx<- 000D
482     movl        (rFP, %ecx, 4), %ecx    # %ecx<- vD
483     movl        %ecx, -4(%edx)          # *--outs<- vD
484 0:
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
528 1:
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
555 2:
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
592 7:
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
605 11:
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  */
646 common_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
651 14:
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
697 19:
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  */
724 common_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)
742 save_callsiteinfo:
743     cmp     $$0, %ecx
744     je      2f
745     movl    offObject_clazz(%ecx), %ecx
746 2:
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      */
764 common_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
772 1:
773     movl    (%ecx), %ecx
774     cmp     $$0, %ecx
775     je      1f
776     ret
777 1:
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  */
798 common_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  */
809 common_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  */
820 common_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  */
830 common_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  */
840 common_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  */
853 common_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  */
872 common_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
905 8:
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
943 1:
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
975 1:
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
991 1:
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
1000 common_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'"