2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * Common subroutines and data.
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.
30 .global dvmJitToInterpPunt
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.
39 #if defined(WITH_JIT_TUNING)
40 movl rPC, OUT_ARG0(%esp)
44 movl offThread_curHandlerTable(%ecx),rIBASE
45 movl $$0, offThread_inJitCodeCache(%ecx)
49 .global dvmJitToInterpSingleStep
51 * Return to the interpreter to handle a single instruction.
52 * Should be reached via a call.
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
58 dvmJitToInterpSingleStep:
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
72 .global dvmJitToInterpNoChainNoProfile
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.
78 dvmJitToInterpNoChainNoProfile:
79 #if defined(WITH_JIT_TUNING)
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
91 jmp *%eax # exec translation if we've got one
96 movl offThread_curHandlerTable(%ecx),rIBASE
101 * Return from the translation cache and immediately request a
102 * translation from the exit target, but don't attempt to chain.
105 .global dvmJitToInterpTraceSelectNoChain
106 dvmJitToInterpTraceSelectNoChain:
107 #if defined(WITH_JIT_TUNING)
111 lea 4(%esp), %esp #to recover the esp update due to function call
113 movl rPC,OUT_ARG0(%esp)
114 movl %eax,OUT_ARG1(%esp)
115 call dvmJitGetTraceAddrThread # (pc, self)
118 movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
120 jmp *%eax # jump to tranlation
123 /* No Translation - request one */
125 GET_JIT_PROF_TABLE %ecx %eax
126 cmpl $$0, %eax # JIT enabled?
127 jnz 2f # Request one if so
129 movl offThread_curHandlerTable(%ecx),rIBASE
130 FETCH_INST_R %ecx # Continue interpreting if not
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
138 * Return from the translation cache and immediately request a
139 * translation for the exit target. Reached via a call, and
142 .global dvmJitToInterpTraceSelect
143 dvmJitToInterpTraceSelect:
144 movl 0(%esp), %eax # get return address
145 movl %ebx, rPC # get first argument (target rPC)
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
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
156 movl rPC,OUT_ARG0(%esp)
157 movl %eax,OUT_ARG1(%esp)
158 call dvmJitGetTraceAddrThread # (pc, self)
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
173 * Placeholder entries for x86 JIT
175 .global dvmJitToInterpBackwardBranch
176 dvmJitToInterpBackwardBranch:
178 .global dvmJitToExceptionThrown
179 dvmJitToExceptionThrown: //rPC in
182 movl $$0, offThread_inJitCodeCache(%edx)
183 jmp common_exceptionThrown
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)
191 ## TODO, need to clean up stack manipulation ... this isn't signal safe and
192 ## doesn't use the calling conventions of header.S
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
198 movl rPC, OUT_ARG0(%esp)
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
205 movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
210 movl %ebx, OUT_ARG1(%esp) # %ebx live thorugh dvmJitGetTraceAddrThread
211 movl %eax, OUT_ARG0(%esp) # first argument
216 jmp *%eax #to native address
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
224 movl rPC, OUT_ARG0(%esp)
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
231 movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
234 jmp *%eax #to native address
239 movl offThread_curHandlerTable(%ecx), rIBASE
241 movl offThread_pJitProfTable(%ecx), %eax
244 /* ebx holds the pointer to the jit profile table
245 edx has the opCode */
246 common_testUpdateProfile:
249 /* eax holds the pointer to the jit profile table
251 rPC points to the next bytecode */
253 common_updateProfile:
258 andl $$((1<<JIT_PROF_SIZE_LOG_2)-1), %ecx
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,
275 GET_JIT_THRESHOLD rIBASE rINST # leaves rSELF in %ecx
277 movb rINSTbl,(%ecx,%eax) # reset counter
278 movl rIBASE,rINST # preserve rSELF
280 movl rPC,OUT_ARG0(%esp)
281 movl rIBASE,OUT_ARG1(%esp)
282 call dvmJitGetTraceAddrThread # (pc, self)
284 movl %eax,offThread_inJitCodeCache(rINST) # set the inJitCodeCache flag
289 jmp *%eax # TODO: decide call vs/ jmp!. No return either way
291 movl $$kJitTSelectRequest,%eax
292 # On entry, eax<- jitState, rPC valid
294 mov %ebx, EBX_SPILL(%ebp)
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)
301 movl %eax, OUT_ARG0(%esp)
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
310 SAVE_PC_FP_TO_SELF %ecx
311 call dvmJitCheckTraceRequest
313 mov EBX_SPILL(%ebp), %ebx
316 movl offThread_curHandlerTable(%ecx), rIBASE
321 mov %ebx, EBX_SPILL(%ebp)
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
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
339 SAVE_PC_FP_TO_SELF %ecx
340 call dvmJitCheckTraceRequest
344 movl offThread_curHandlerTable(%ecx), rIBASE
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
358 * Common code for method invocation with range.
361 * eax = Method* methodToCall
363 * rINSTw trashed, must reload
364 * rIBASE trashed, must reload before resuming interpreter
367 common_invokeMethodRange:
369 #if defined(WITH_JIT)
373 movzwl offThread_subMode(%edx), %ebx
374 and $$kSubModeJitTraceBuild, %ebx
376 call save_callsiteinfo
382 * prepare to copy args to "outs" area of current frame
385 movzbl 1(rPC),rINST # rINST<- AA
386 movzwl 4(rPC), %ecx # %ecx<- CCCC
387 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea
389 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
390 jz .LinvokeArgsDone # no args; jump to args done
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)
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
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
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
421 common_invokeMethodNoRange:
422 #if defined(WITH_JIT)
426 movzwl offThread_subMode(%edx), %ebx
427 and $$kSubModeJitTraceBuild, %ebx
429 call save_callsiteinfo
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
443 * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
447 cmp $$2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
448 movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
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
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
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
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
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
481 and $$0x000f, %ecx # %ecx<- 000D
482 movl (rFP, %ecx, 4), %ecx # %ecx<- vD
483 movl %ecx, -4(%edx) # *--outs<- vD
487 * %eax is "Method* methodToCall", the method we're trying to call
488 * find space for the new stack frame, check for overflow
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
515 SAVEAREA_FROM_FP %ecx # %ecx<- &StackSaveArea
516 movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
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)
525 /* Any special actions to take? */
526 cmpw $$0, offThread_subMode(%ecx)
527 jne 2f # Yes - handle them
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
534 * Update "self" values for the new method
535 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
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
547 #if defined(WITH_JIT)
548 /* rPC is already updated */
549 GET_JIT_PROF_TABLE %ecx %eax
551 jne common_updateProfile # set up %ebx & %edx & rPC
553 GOTO_NEXT # jump to methodToCall->insns
557 * On entry, preserve all:
560 * %edx: new save area
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)
570 movl rSELF,%ecx # restore rSELF
574 * Prep for the native call
575 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
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
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
603 GOTO_NEXT_R %ecx # jump to next instruction
607 * Handle any special subMode actions
608 * %eax=methodToCall, rINST=newFP, %ecx=self
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
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
627 UNSPILL_TMP1(%eax) # restore methodToCall
629 movl %ecx, OUT_ARG1(%esp)
630 movl %eax, OUT_ARG0(%esp)
631 movl rFP, OUT_ARG2(%esp)
632 call dvmReportPostNativeInvoke # (methodToCall, self, fp)
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
644 * Common code for handling a return instruction
646 common_returnFromMethod:
648 SAVEAREA_FROM_FP %eax # %eax<- saveArea(old)
649 cmpw $$0, offThread_subMode(%ecx) # special action needed?
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
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)
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)
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
699 * Handle special subMode actions
700 * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
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)
709 movl rSELF, %ecx # restore self
710 SAVEAREA_FROM_FP %eax # restore saveArea
715 * Prepare to strip the current frame and "longjump" back to caller of
719 * rINST holds changeInterp
720 * ecx holds self pointer
722 * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
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....
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.
736 * eax = Method* methodToCall
741 #if defined(WITH_JIT)
745 movl offObject_clazz(%ecx), %ecx
748 movl %eax, offThread_methodToCall(%ebx)
749 movl %ecx, offThread_callsiteClass(%ebx)
753 #if defined(WITH_JIT)
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
761 * %ecx: &dvmDex->pResFields[field]
762 * %eax: field pointer (must preserve)
765 movl %ebx, TMP_SPILL1(%ebp)
767 movzwl offThread_subMode(%ebx), %ebx
768 andl $$kSubModeJitTraceBuild, %ebx
769 movl TMP_SPILL1(%ebp), %ebx
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
785 movl %ecx, OUT_ARG0(%esp)
786 movl rPC, OUT_ARG1(%esp)
787 call dvmJitEndTraceSelect
795 * After returning from a "selfd" function, pull out the updated values
796 * and start executing at the next instruction.
798 common_resumeAfterGlueCall:
800 movl offThread_pc(%eax),rPC
801 movl offThread_curFrame(%eax),rFP
802 movl offThread_curHandlerTable(%eax),rIBASE
807 * Integer divide or mod by zero
809 common_errDivideByZero:
811 movl $$.LstrDivideByZero,%eax
812 movl %eax,OUT_ARG0(%esp)
813 call dvmThrowArithmeticException
814 jmp common_exceptionThrown
817 * Attempt to allocate an array with a negative size.
818 * On entry, len in eax
820 common_errNegativeArraySize:
822 movl %eax,OUT_ARG0(%esp) # arg0<- len
823 call dvmThrowNegativeArraySizeException # (len)
824 jmp common_exceptionThrown
827 * Attempt to allocate an array with a negative size.
828 * On entry, method name in eax
830 common_errNoSuchMethod:
832 movl %eax,OUT_ARG0(%esp)
833 call dvmThrowNoSuchMethodError
834 jmp common_exceptionThrown
837 * Hit a null object when we weren't expecting one. Export the PC, throw a
838 * NullPointerException and goto the exception processing code.
840 common_errNullObject:
843 movl %eax,OUT_ARG0(%esp)
844 call dvmThrowNullPointerException
845 jmp common_exceptionThrown
848 * Array index exceeds max.
850 * eax <- array object
853 common_errArrayIndex:
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
862 * Somebody has thrown an exception. Handle it.
864 * If the exception processing code returns to us (instead of falling
865 * out of the interpreter), continue with whatever the next instruction
868 * NOTE: special subMode handling done in dvmMterp_exceptionThrown
870 * This does not return.
872 common_exceptionThrown:
877 movl %ecx, OUT_ARG0(%esp)
878 call dvmCheckSuspendPending
881 movl offThread_exception(%ecx), %edx # %edx <- self->exception
882 movl %edx, OUT_ARG0(%esp)
883 movl %ecx, OUT_ARG1(%esp)
885 call dvmAddTrackedAlloc # don't let the exception be GCed
888 movl offThread_subMode(%ecx), %eax # get subMode flags
889 movl $$0, offThread_exception(%ecx)
892 cmpl $$0, %eax # any special subMode handling needed?
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)
901 call dvmReportExceptionThrow # (self, exception)
907 * set up args and a local for &fp
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
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
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
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
931 /* fix earlier stack overflow if necessary; may trash rFP */
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
939 call dvmCleanupStackOverflow # call(self, exception)
941 movl rFP, %eax # restore result
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
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
959 movl %ecx, offThread_methodClassDex(rINST) # self->pDvmDex = method->clazz->pDvmDex
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
965 call dvmReleaseTrackedAlloc # release the exception
968 /* restore the exception if the handler wants it */
972 cmpl $$OP_MOVE_EXCEPTION, %eax # is it "move-exception"?
974 movl %edx, offThread_exception(%ecx) # restore exception
976 movl offThread_curHandlerTable(%ecx), rIBASE # refresh rIBASE
979 .LnotCaughtLocally: # %edx = exception
980 /* fix stack overflow if necessary */
982 movl offThread_stackOverflowed(%ecx), %eax
983 cmpl $$0, %eax # did we overflow earlier?
985 movl %ecx, OUT_ARG0(%esp)
986 movl %edx, OUT_ARG1(%esp)
988 call dvmCleanupStackOverflow
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
998 jmp common_gotoBail # bail out
1001 movl $$0xdeadf00d,%eax
1011 .asciz "divide by zero"
1012 .LstrFilledNewArrayNotImplA:
1013 .asciz "filled-new-array only implemented for 'int'"