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.
38 #if defined(WITH_JIT_TUNING)
39 movl rPC, OUT_ARG0(%esp)
43 movl offThread_curHandlerTable(%ecx),rIBASE
47 .global dvmJitToInterpSingleStep
49 * Return to the interpreter to handle a single instruction.
50 * Should be reached via a call.
52 * 0(%esp) <= native return address within trace
53 * rPC <= Dalvik PC of this instruction
54 * OUT_ARG0+4(%esp) <= Dalvik PC of next instruction
56 dvmJitToInterpSingleStep:
62 movl OUT_ARG0(%esp), %edx
63 movl %eax,offThread_jitResumeNPC(%ecx)
64 movl %edx,offThread_jitResumeDPC(%ecx)
65 movl $$kInterpEntryInstr,offThread_entryPoint(%ecx)
66 movl $$1,rINST # changeInterp <= true
70 .global dvmJitToInterpNoChainNoProfile
72 * Return from the translation cache to the interpreter to do method
73 * invocation. Check if the translation exists for the callee, but don't
74 * chain to it. rPC must be set on entry.
76 dvmJitToInterpNoChainNoProfile:
77 #if defined(WITH_JIT_TUNING)
81 movl rPC,OUT_ARG0(%esp)
82 movl %eax,OUT_ARG1(%esp)
83 call dvmJitGetTraceAddrThread # (pc, self)
84 movl rSELF,%ecx # ecx <- self
85 movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
88 call *%eax # exec translation if we've got one
92 movl offThread_curHandlerTable(%ecx),rIBASE
97 * Return from the translation cache and immediately request a
98 * translation fro the exit target, but don't attempt to chain.
101 .global dvmJitToInterpTraceSelectNoChain
102 dvmJitToInterpTraceSelectNoChain:
103 #if defined(WITH_JIT_TUNING)
107 movl rPC,OUT_ARG0(%esp)
108 movl %eax,OUT_ARG1(%esp)
109 call dvmJitGetTraceAddrThread # (pc, self)
112 movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag
114 call *%eax # jump to tranlation
117 /* No Translation - request one */
119 GET_JIT_PROF_TABLE %ecx %eax
120 cmpl $$0, %eax # JIT enabled?
121 jnz 2f # Request one if so
123 movl offThread_curHandlerTable(%ecx),rIBASE
124 FETCH_INST_R %ecx # Continue interpreting if not
127 movl $$kJitTSelectRequestHot,rINST # ask for trace select
128 jmp common_selectTrace
131 * Return from the translation cache and immediately request a
132 * translation for the exit target. Reached via a call, and
135 .global dvmJitToInterpTraceSelect
136 dvmJitToInterpTraceSelect:
137 pop rINST # save chain cell address in callee save reg
140 movl rPC,OUT_ARG0(%esp)
141 movl %eax,OUT_ARG1(%esp)
142 call dvmJitGetTraceAddrThread # (pc, self)
144 jz 1b # no - ask for one
145 movl %eax,OUT_ARG0(%esp)
146 # TODO - need to adjust rINST to beginning of sequence
147 movl rINST,OUT_ARG1(%esp)
148 call dvmJitChain # Attempt dvmJitChain(codeAddr,chainAddr)
149 cmpl $$0,%eax # Success?
150 jz toInterpreter # didn't chain - interpret
155 * Placeholder entries for x86 JIT
157 .global dvmJitToInterpBackwardBranch
158 dvmJitToInterpBackwardBranch:
159 .global dvmJitToInterpNormal
160 dvmJitToInterpNormal:
161 .global dvmJitToInterpNoChain
162 dvmJitToInterpNoChain:
166 common_updateProfile:
171 andl $$((1<<JIT_PROF_SIZE_LOG_2)-1),%eax
178 * Here, we switch to the debug interpreter to request
179 * trace selection. First, though, check to see if there
180 * is already a native translation in place (and, if so,
183 GET_JIT_THRESHOLD %ecx rINST # leaves rSELF in %ecx
185 movb rINSTbl,(%edx,%eax) # reset counter
186 movl %ecx,rINST # preserve rSELF
188 movl rPC,OUT_ARG0(%esp)
189 movl %eax,OUT_ARG1(%esp)
190 call dvmJitGetTraceAddr # (pc, self)
191 movl %eax,offThread_inJitCodeCache(rINST) # set the inJitCodeCache flag
194 call *%eax # TODO: decide call vs/ jmp!. No return either way
196 movl $$kJitTSelectRequest,%eax
197 # On entry, eax<- jitState, rPC valid
203 movl %eax,offThread_jitState(%ecx)
204 movl $$kInterpEntryInstr,offThread_entryPoint(%ecx)
213 * Common code for jumbo method invocation.
216 * eax = Method* methodToCall
217 * rINSTw trashed, must reload
218 * rIBASE trashed, must reload before resuming interpreter
221 common_invokeMethodJumbo:
225 * prepare to copy args to "outs" area of current frame
227 movzwl 6(rPC),rINST # rINST<- BBBB
228 movzwl 8(rPC), %ecx # %ecx<- CCCC
229 ADVANCE_PC 2 # adjust pc to make return similar
230 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea
232 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BBBB
233 jz .LinvokeArgsDone # no args; jump to args done
234 jmp .LinvokeRangeArgs # handle args like invoke range
237 * Common code for method invocation with range.
240 * eax = Method* methodToCall
241 * rINSTw trashed, must reload
242 * rIBASE trashed, must reload before resuming interpreter
245 common_invokeMethodRange:
249 * prepare to copy args to "outs" area of current frame
252 movzbl 1(rPC),rINST # rINST<- AA
253 movzwl 4(rPC), %ecx # %ecx<- CCCC
254 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea
256 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
257 jz .LinvokeArgsDone # no args; jump to args done
261 * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count,
262 * %edx=&outs (&stackSaveArea). (very few methods have > 10 args;
263 * could unroll for common cases)
267 movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx
268 lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC
269 shll $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
270 subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs
271 shrl $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
273 movl (%ecx), %ebx # %ebx<- vCCCC
274 lea 4(%ecx), %ecx # %ecx<- &vCCCC++
275 subl $$1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET--
276 movl %ebx, (%edx) # *outs<- vCCCC
277 lea 4(%edx), %edx # outs++
278 jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero
279 movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx
280 jmp .LinvokeArgsDone # continue
283 * %eax is "Method* methodToCall", the method we're trying to call
284 * prepare to copy args to "outs" area of current frame
285 * rIBASE trashed, must reload before resuming interpreter
288 common_invokeMethodNoRange:
290 movzbl 1(rPC),rINST # rINST<- BA
291 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
292 shrl $$4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B
293 je .LinvokeArgsDone # no args; jump to args done
294 movzwl 4(rPC), %ecx # %ecx<- GFED
295 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea
298 * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
302 cmp $$2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
303 movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
305 je 2f # handle 2 args
306 cmp $$4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4
307 jl 3f # handle 3 args
308 je 4f # handle 4 args
310 andl $$15, rINST # rINSTw<- A
311 lea -4(%edx), %edx # %edx<- update &outs; &outs--
312 movl (rFP, rINST, 4), %ecx # %ecx<- vA
313 movl %ecx, (%edx) # *outs<- vA
314 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
316 shr $$12, %ecx # %ecx<- G
317 lea -4(%edx), %edx # %edx<- update &outs; &outs--
318 movl (rFP, %ecx, 4), %ecx # %ecx<- vG
319 movl %ecx, (%edx) # *outs<- vG
320 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
322 and $$0x0f00, %ecx # %ecx<- 0F00
323 shr $$8, %ecx # %ecx<- F
324 lea -4(%edx), %edx # %edx<- update &outs; &outs--
325 movl (rFP, %ecx, 4), %ecx # %ecx<- vF
326 movl %ecx, (%edx) # *outs<- vF
327 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
329 and $$0x00f0, %ecx # %ecx<- 00E0
330 shr $$4, %ecx # %ecx<- E
331 lea -4(%edx), %edx # %edx<- update &outs; &outs--
332 movl (rFP, %ecx, 4), %ecx # %ecx<- vE
333 movl %ecx, (%edx) # *outs<- vE
334 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
336 and $$0x000f, %ecx # %ecx<- 000D
337 movl (rFP, %ecx, 4), %ecx # %ecx<- vD
338 movl %ecx, -4(%edx) # *--outs<- vD
342 * %eax is "Method* methodToCall", the method we're trying to call
343 * find space for the new stack frame, check for overflow
347 movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
348 movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
349 movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall
350 shl $$2, %edx # %edx<- update offset
351 SAVEAREA_FROM_FP %eax # %eax<- &StackSaveArea
352 subl %edx, %eax # %eax<- newFP; (old savearea - regsSize)
353 movl rSELF,%edx # %edx<- pthread
354 movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs
355 subl $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
356 movl offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd
357 movl %edx, TMP_SPILL1(%ebp) # spill self->interpStackEnd
358 shl $$2, %ecx # %ecx<- update offset for outsSize
359 movl %eax, %edx # %edx<- newSaveArea
360 sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize)
361 cmp TMP_SPILL1(%ebp), %eax # compare interpStackEnd and bottom
362 movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall
363 jl .LstackOverflow # handle frame overflow
370 SAVEAREA_FROM_FP %ecx # %ecx<- &StackSaveArea
371 movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
373 movl rSELF,%ecx # %ecx<- pthread
374 movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
375 movl rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
377 /* Any special actions to take? */
378 cmpb $$0, offThread_subMode(%ecx)
379 jne 2f # Yes - handle them
381 testl $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
382 movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
383 jne .LinvokeNative # handle native call
386 * Update "self" values for the new method
387 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
389 movl offMethod_clazz(%eax), %edx # %edx<- method->clazz
390 movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
391 movl %eax, offThread_method(%ecx) # self->method<- methodToCall
392 movl %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex
393 movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
394 movl $$1, offThread_debugIsMethodEntry(%ecx)
395 movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
396 movl rFP, offThread_curFrame(%ecx) # self->curFrame<- newFP
397 movl offThread_curHandlerTable(%ecx),rIBASE
399 GOTO_NEXT # jump to methodToCall->insns
403 * On entry, preserve all:
406 * %edx: new save area
408 SPILL_TMP1(%eax) # preserve methodToCall
409 SPILL_TMP2(%edx) # preserve newSaveArea
410 movl rPC, offThread_pc(%ecx) # update interpSave.pc
411 movl rFP, offThread_fp(%ecx) # update interpSave.fp
412 movl %ecx, OUT_ARG0(%esp)
413 movl %eax, OUT_ARG1(%esp)
414 call dvmReportInvoke # (self, method)
417 movl rSELF,%ecx # restore rSELF
421 * Prep for the native call
422 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self
426 movl offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->...
427 movl rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
428 movl %edx, LOCAL2_OFFSET(%ebp) # save newSaveArea
429 movl LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP
430 movl rINST, offThread_curFrame(%ecx) # self->curFrame<- newFP
431 cmpb $$0, offThread_subMode(%ecx) # Anything special going on?
432 jne 11f # yes - handle it
433 movl %ecx, OUT_ARG3(%esp) # push parameter self
434 movl %eax, OUT_ARG2(%esp) # push parameter methodToCall
435 lea offThread_retval(%ecx), %ecx # %ecx<- &retval
436 movl %ecx, OUT_ARG1(%esp) # push parameter &retval
437 movl rINST, OUT_ARG0(%esp) # push parameter newFP
438 call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
440 movl LOCAL2_OFFSET(%ebp), %ecx # %ecx<- newSaveArea
441 movl rSELF, %eax # %eax<- self
442 movl offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
443 cmp $$0, offThread_exception(%eax) # check for exception
444 movl rFP, offThread_curFrame(%eax) # self->curFrame<- rFP
445 movl %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
446 jne common_exceptionThrown # handle exception
447 movl offThread_curHandlerTable(%eax),rIBASE
448 FETCH_INST_OPCODE 3 %ecx
450 GOTO_NEXT_R %ecx # jump to next instruction
454 * Handle any special subMode actions
455 * %eax=methodToCall, rINST=newFP, %ecx=self
457 SPILL_TMP1(%eax) # save methodTocall
458 movl rPC, offThread_pc(%ecx)
459 movl rFP, offThread_fp(%ecx)
460 movl %ecx, OUT_ARG0(%esp)
461 movl %eax, OUT_ARG1(%esp)
462 call dvmReportPreNativeInvoke # (self, methodToCall)
463 UNSPILL_TMP1(%eax) # restore methodToCall
464 movl rSELF,%ecx # restore self
466 /* Do the native call */
467 movl %ecx, OUT_ARG3(%esp) # push parameter self
468 lea offThread_retval(%ecx), %ecx # %ecx<- &retval
469 movl %eax, OUT_ARG2(%esp) # push parameter methodToCall
470 movl %ecx, OUT_ARG1(%esp) # push parameter &retval
471 movl rINST, OUT_ARG0(%esp) # push parameter newFP
472 call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
474 UNSPILL_TMP1(%eax) # restore methodToCall
476 movl %ecx, OUT_ARG0(%esp)
477 movl %eax, OUT_ARG1(%esp)
478 call dvmReportPostNativeInvoke # (self, methodToCall)
481 .LstackOverflow: # eax=methodToCall
482 movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
483 movl rSELF,%eax # %eax<- self
484 movl %eax, OUT_ARG0(%esp) # push parameter self
485 call dvmHandleStackOverflow # call: (Thread* self, Method* meth)
486 jmp common_exceptionThrown # handle exception
490 * Common code for handling a return instruction
492 common_returnFromMethod:
494 SAVEAREA_FROM_FP %eax # eax<- saveArea (old)
495 movl offStackSaveArea_prevFrame(%eax),rFP # rFP<- prevFrame
496 cmpb $$0, offThread_subMode(%ecx) # special action needed?
499 movl (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
500 cmpl $$0,rINST # break?
501 je common_gotoBail # break frame, bail out completely
503 movl offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
504 movl rINST,offThread_method(%ecx) # self->method = newSave->meethod
505 movl rFP,offThread_curFrame(%ecx) # self->curFrame = fp
506 movl offMethod_clazz(rINST),%eax # eax<- method->clazz
507 movl offThread_curHandlerTable(%ecx),rIBASE
508 movl offClassObject_pDvmDex(%eax),rINST # rINST<- method->clazz->pDvmDex
509 FETCH_INST_OPCODE 3 %eax
510 movl rINST,offThread_methodClassDex(%ecx)
516 * Handle special subMode actions
517 * On entry, rFP: prevFP, %ecx: self, %eax: saveArea
519 movl rFP, offThread_fp(%ecx) # update interpSave.fp
520 movl rPC, offThread_pc(%ecx) # update interpSave.pc
521 movl %ecx, OUT_ARG0(%esp) # parameter self
522 call dvmReportReturn # (self)
523 movl rSELF, %ecx # restore self
524 SAVEAREA_FROM_FP %eax # restore saveArea
529 * Prepare to strip the current frame and "longjump" back to caller of
533 * rINST holds changeInterp
534 * ecx holds self pointer
536 * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp)
539 movl rPC,offThread_pc(%ecx) # export state to self
540 movl rFP,offThread_fp(%ecx)
541 movl %ecx,OUT_ARG0(%esp) # self in arg0
542 movl rINST,OUT_ARG1(%esp) # changeInterp in arg1
543 call dvmMterpStdBail # bail out....
547 * After returning from a "selfd" function, pull out the updated values
548 * and start executing at the next instruction.
550 common_resumeAfterGlueCall:
552 movl offThread_pc(%eax),rPC
553 movl offThread_fp(%eax),rFP
554 movl offThread_curHandlerTable(%eax),rIBASE
559 * Integer divide or mod by zero
561 common_errDivideByZero:
563 movl $$.LstrDivideByZero,%eax
564 movl %eax,OUT_ARG0(%esp)
565 call dvmThrowArithmeticException
566 jmp common_exceptionThrown
569 * Attempt to allocate an array with a negative size.
570 * On entry, len in eax
572 common_errNegativeArraySize:
574 movl %eax,OUT_ARG0(%esp) # arg0<- len
575 call dvmThrowNegativeArraySizeException # (len)
576 jmp common_exceptionThrown
579 * Attempt to allocate an array with a negative size.
580 * On entry, method name in eax
582 common_errNoSuchMethod:
585 movl %eax,OUT_ARG0(%esp)
586 call dvmThrowNoSuchMethodError
587 jmp common_exceptionThrown
590 * Hit a null object when we weren't expecting one. Export the PC, throw a
591 * NullPointerException and goto the exception processing code.
593 common_errNullObject:
596 movl %eax,OUT_ARG0(%esp)
597 call dvmThrowNullPointerException
598 jmp common_exceptionThrown
601 * Array index exceeds max.
603 * eax <- array object
606 common_errArrayIndex:
608 movl offArrayObject_length(%eax), %eax
609 movl %eax,OUT_ARG0(%esp)
610 movl %ecx,OUT_ARG1(%esp)
611 call dvmThrowArrayIndexOutOfBoundsException # args (length, index)
612 jmp common_exceptionThrown
615 * Somebody has thrown an exception. Handle it.
617 * If the exception processing code returns to us (instead of falling
618 * out of the interpreter), continue with whatever the next instruction
621 * NOTE: special subMode handling done in dvmMterp_exceptionThrown
623 * This does not return.
625 common_exceptionThrown:
627 movl rPC,offThread_pc(%ecx)
628 movl rFP,offThread_fp(%ecx)
629 movl %ecx,OUT_ARG0(%esp)
630 call dvmMterp_exceptionThrown
631 jmp common_resumeAfterGlueCall
634 movl $$0xdeadf00d,%eax
644 .asciz "divide by zero"
645 .LstrFilledNewArrayNotImplA:
646 .asciz "filled-new-array only implemented for 'int'"