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 * Placeholder entries for x86 JIT
24 .global dvmJitToInterpPunt
26 .global dvmJitToInterpSingleStep
27 dvmJitToInterpSingleStep:
28 .global dvmJitToInterpNoChainNoProfile
29 dvmJitToInterpNoChainNoProfile:
30 .global dvmJitToInterpTraceSelectNoChain
31 dvmJitToInterpTraceSelectNoChain:
32 .global dvmJitToInterpTraceSelect
33 dvmJitToInterpTraceSelect:
34 .global dvmJitToInterpBackwardBranch
35 dvmJitToInterpBackwardBranch:
36 .global dvmJitToInterpNormal
38 .global dvmJitToInterpNoChain
39 dvmJitToInterpNoChain:
44 * Common code when a backwards branch is taken
47 * ebx (a.k.a. rINST) -> PC adjustment in 16-bit words
49 common_backwardBranch:
51 call common_periodicChecks # Note: expects rPC to be preserved
52 ADVANCE_PC_INDEXED rINST
59 * Common code for method invocation with range.
62 * eax = Method* methodToCall
63 * rINSTw trashed, must reload
66 common_invokeMethodRange:
70 * prepare to copy args to "outs" area of current frame
73 movzbl 1(rPC),rINST # rINST<- AA
74 movzwl 4(rPC), %ecx # %ecx<- CCCC
75 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea
77 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
78 jz .LinvokeArgsDone # no args; jump to args done
82 * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, %edx=&outs (&stackSaveArea)
83 * (very few methods have > 10 args; could unroll for common cases)
86 movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx
87 lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC
88 shll $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
89 subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs
90 shrl $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
92 movl (%ecx), %ebx # %ebx<- vCCCC
93 lea 4(%ecx), %ecx # %ecx<- &vCCCC++
94 subl $$1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET--
95 movl %ebx, (%edx) # *outs<- vCCCC
96 lea 4(%edx), %edx # outs++
97 jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero
98 movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx
99 jmp .LinvokeArgsDone # continue
102 * %eax is "Method* methodToCall", the method we're trying to call
103 * prepare to copy args to "outs" area of current frame
106 common_invokeMethodNoRange:
108 movzbl 1(rPC),rINST # rINST<- BA
109 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
110 shrl $$4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B
111 je .LinvokeArgsDone # no args; jump to args done
112 movzwl 4(rPC), %ecx # %ecx<- GFED
113 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea
116 * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
120 cmp $$2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
121 movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
123 je 2f # handle 2 args
124 cmp $$4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4
125 jl 3f # handle 3 args
126 je 4f # handle 4 args
128 andl $$15, rINST # rINSTw<- A
129 lea -4(%edx), %edx # %edx<- update &outs; &outs--
130 movl (rFP, rINST, 4), %ecx # %ecx<- vA
131 movl %ecx, (%edx) # *outs<- vA
132 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
134 shr $$12, %ecx # %ecx<- G
135 lea -4(%edx), %edx # %edx<- update &outs; &outs--
136 movl (rFP, %ecx, 4), %ecx # %ecx<- vG
137 movl %ecx, (%edx) # *outs<- vG
138 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
140 and $$0x0f00, %ecx # %ecx<- 0F00
141 shr $$8, %ecx # %ecx<- F
142 lea -4(%edx), %edx # %edx<- update &outs; &outs--
143 movl (rFP, %ecx, 4), %ecx # %ecx<- vF
144 movl %ecx, (%edx) # *outs<- vF
145 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
147 and $$0x00f0, %ecx # %ecx<- 00E0
148 shr $$4, %ecx # %ecx<- E
149 lea -4(%edx), %edx # %edx<- update &outs; &outs--
150 movl (rFP, %ecx, 4), %ecx # %ecx<- vE
151 movl %ecx, (%edx) # *outs<- vE
152 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
154 and $$0x000f, %ecx # %ecx<- 000D
155 movl (rFP, %ecx, 4), %ecx # %ecx<- vD
156 movl %ecx, -4(%edx) # *--outs<- vD
160 * %eax is "Method* methodToCall", the method we're trying to call
161 * find space for the new stack frame, check for overflow
165 movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
166 movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
167 movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall
168 shl $$2, %edx # %edx<- update offset
169 SAVEAREA_FROM_FP %eax # %eax<- &StackSaveArea
170 subl %edx, %eax # %eax<- newFP; (old savearea - regsSize)
171 movl rGLUE,%edx # %edx<- pMterpGlue
172 movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs
173 subl $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
174 movl offGlue_interpStackEnd(%edx), %edx # %edx<- glue->interpStackEnd
175 movl %edx, LOCAL2_OFFSET(%ebp) # LOCAL2_OFFSET<- glue->interpStackEnd
176 shl $$2, %ecx # %ecx<- update offset for outsSize
177 movl %eax, %edx # %edx<- newSaveArea
178 sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize)
179 cmp LOCAL2_OFFSET(%ebp), %eax # compare interpStackEnd and bottom
180 movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall
181 jl .LstackOverflow # handle frame overflow
188 SAVEAREA_FROM_FP %ecx # %ecx<- &StackSaveArea
189 movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
191 movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
192 movl rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
193 testl $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
194 movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
195 jne .LinvokeNative # handle native call
198 * Update "glue" values for the new method
199 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
202 movl offMethod_clazz(%eax), %edx # %edx<- method->clazz
203 movl rGLUE,%ecx # %ecx<- pMterpGlue
204 movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
205 movl %eax, offGlue_method(%ecx) # glue->method<- methodToCall
206 movl %edx, offGlue_methodClassDex(%ecx) # glue->methodClassDex<- method->clazz->pDvmDex
207 movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
208 movl offGlue_self(%ecx), %eax # %eax<- glue->self
209 movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
210 movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- newFP
212 GOTO_NEXT # jump to methodToCall->insns
215 * Prep for the native call
216 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea
220 movl rGLUE,%ecx # %ecx<- pMterpGlue
221 movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
222 movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
223 movl offThread_jniLocal_topCookie(%ecx), %eax # %eax<- self->localRef->...
224 movl %eax, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top
225 movl %edx, OUT_ARG4(%esp) # save newSaveArea
226 movl LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
227 movl %edx, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
228 movl %ecx, OUT_ARG3(%esp) # save glue->self
229 movl %ecx, OUT_ARG2(%esp) # push parameter glue->self
230 movl rGLUE,%ecx # %ecx<- pMterpGlue
231 movl OUT_ARG1(%esp), %eax # %eax<- methodToCall
232 lea offGlue_retval(%ecx), %ecx # %ecx<- &retval
233 movl %ecx, OUT_ARG0(%esp) # push parameter pMterpGlue
234 push %edx # push parameter newFP
236 call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
238 movl OUT_ARG4(%esp), %ecx # %ecx<- newSaveArea
239 movl OUT_ARG3(%esp), %eax # %eax<- glue->self
240 movl offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top
241 cmp $$0, offThread_exception(%eax) # check for exception
242 movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
243 movl %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top
244 jne common_exceptionThrown # handle exception
245 FETCH_INST_OPCODE 3 %edx
247 GOTO_NEXT_R %edx # jump to next instruction
249 .LstackOverflow: # eax=methodToCall
250 movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
251 movl rGLUE,%eax # %eax<- pMterpGlue
252 movl offGlue_self(%eax), %eax # %eax<- glue->self
253 movl %eax, OUT_ARG0(%esp) # push parameter self
254 call dvmHandleStackOverflow # call: (Thread* self, Method* meth)
255 jmp common_exceptionThrown # handle exception
259 * Do we need the thread to be suspended or have debugger/profiling activity?
262 * ebx -> PC adjustment in 16-bit words (must be preserved)
263 * ecx -> GLUE pointer
264 * reentry type, e.g. kInterpEntryInstr stored in rGLUE->entryPoint
266 * Note: A call will normally kill %eax and %ecx. To
267 * streamline the normal case, this routine will preserve
268 * %ecx in addition to the normal caller save regs. The save/restore
269 * is a bit ugly, but will happen in the relatively uncommon path.
270 * TODO: Basic-block style Jit will need a hook here as well. Fold it into
271 * the suspendCount check so we can get both in 1 shot.
273 common_periodicChecks:
274 movl offGlue_pSelfSuspendCount(%ecx),%eax # eax <- &suspendCount
279 movl offGlue_pDebuggerActive(%ecx),%eax # eax <- &DebuggerActive
280 movl offGlue_pActiveProfilers(%ecx),%ecx # ecx <- &ActiveProfilers
281 testl %eax,%eax # debugger enabled?
283 movzbl (%eax),%eax # get active count
285 orl (%ecx),%eax # eax <- debuggerActive | activeProfilers
286 movl rGLUE,%ecx # restore rGLUE
287 jne 3f # one or both active - switch interp
292 /* Check for suspend */
294 /* At this point, the return pointer to the caller of
295 * common_periodicChecks is on the top of stack. We need to preserve
297 * The outgoing profile is:
298 * bool dvmCheckSuspendPending(Thread* self)
299 * Because we reached here via a call, go ahead and build a new frame.
301 EXPORT_PC # need for precise GC
302 movl offGlue_self(%ecx),%eax # eax<- glue->self
306 movl %eax,OUT_ARG0(%esp)
307 call dvmCheckSuspendPending
313 * Need to check to see if debugger or profiler flags got set
314 * while we were suspended.
318 /* Switch interpreters */
319 /* Note: %ebx contains the 16-bit word offset to be applied to rPC to
320 * "complete" the interpretation of backwards branches. In effect, we
321 * are completing the interpretation of the branch instruction here,
322 * and the new interpreter will resume interpretation at the branch
323 * target. However, a switch request recognized during the handling
324 * of a return from method instruction results in an immediate abort,
325 * and the new interpreter will resume by re-interpreting the return
329 leal (rPC,%ebx,2),rPC # adjust pc to show target
330 movl rGLUE,%ecx # bail expect GLUE already loaded
331 movl $$1,rINST # set changeInterp to true
336 * Common code for handling a return instruction
338 common_returnFromMethod:
340 /* Set entry mode in case we bail */
341 movb $$kInterpEntryReturn,offGlue_entryPoint(%ecx)
342 xorl rINST,rINST # zero offset in case we switch interps
343 call common_periodicChecks # Note: expects %ecx to be preserved
345 SAVEAREA_FROM_FP %eax # eax<- saveArea (old)
346 movl offStackSaveArea_prevFrame(%eax),rFP # rFP<- prevFrame
347 movl (offStackSaveArea_method-sizeofStackSaveArea)(rFP),rINST
348 cmpl $$0,rINST # break?
349 je common_gotoBail # break frame, bail out completely
351 movl offStackSaveArea_savedPc(%eax),rPC # pc<- saveArea->savedPC
352 movl offGlue_self(%ecx),%eax # eax<- self
353 movl rINST,offGlue_method(%ecx) # glue->method = newSave->meethod
354 movl rFP,offThread_curFrame(%eax) # self->curFrame = fp
355 movl offMethod_clazz(rINST),%eax # eax<- method->clazz
356 FETCH_INST_OPCODE 3 %edx
357 movl offClassObject_pDvmDex(%eax),%eax # eax<- method->clazz->pDvmDex
359 movl %eax,offGlue_methodClassDex(%ecx)
360 /* not bailing - restore entry mode to default */
361 movb $$kInterpEntryInstr,offGlue_entryPoint(%ecx)
365 * Prepare to strip the current frame and "longjump" back to caller of
369 * rINST holds changeInterp
370 * ecx holds glue pointer
372 * expected profile: dvmMterpStdBail(MterpGlue *glue, bool changeInterp)
375 movl rPC,offGlue_pc(%ecx) # export state to glue
376 movl rFP,offGlue_fp(%ecx)
377 movl %ecx,OUT_ARG0(%esp) # glue in arg0
378 movl rINST,OUT_ARG1(%esp) # changeInterp in arg1
379 call dvmMterpStdBail # bail out....
383 * After returning from a "glued" function, pull out the updated values
384 * and start executing at the next instruction.
386 common_resumeAfterGlueCall:
392 * Integer divide or mod by zero
394 common_errDivideByZero:
396 movl $$.LstrArithmeticException,%eax
397 movl %eax,OUT_ARG0(%esp)
398 movl $$.LstrDivideByZero,%eax
399 movl %eax,OUT_ARG1(%esp)
400 call dvmThrowException
401 jmp common_exceptionThrown
404 * Attempt to allocate an array with a negative size.
406 common_errNegativeArraySize:
408 movl $$.LstrNegativeArraySizeException,%eax
409 movl %eax,OUT_ARG0(%esp)
411 movl %eax,OUT_ARG1(%esp)
412 call dvmThrowException
413 jmp common_exceptionThrown
416 * Attempt to allocate an array with a negative size.
418 common_errNoSuchMethod:
421 movl $$.LstrNoSuchMethodError,%eax
422 movl %eax,OUT_ARG0(%esp)
424 movl %eax,OUT_ARG1(%esp)
425 call dvmThrowException
426 jmp common_exceptionThrown
429 * Hit a null object when we weren't expecting one. Export the PC, throw a
430 * NullPointerException and goto the exception processing code.
432 common_errNullObject:
434 movl $$.LstrNullPointerException,%eax
435 movl %eax,OUT_ARG0(%esp)
437 movl %eax,OUT_ARG1(%esp)
438 call dvmThrowException
439 jmp common_exceptionThrown
442 * Array index exceeds max.
444 * eax <- array object
447 common_errArrayIndex:
449 movl offArrayObject_length(%eax), %eax
450 movl %ecx,OUT_ARG0(%esp)
451 movl %eax,OUT_ARG1(%esp)
452 call dvmThrowAIOOBE # dvmThrowAIOO(index, length)
453 jmp common_exceptionThrown
456 * Somebody has thrown an exception. Handle it.
458 * If the exception processing code returns to us (instead of falling
459 * out of the interpreter), continue with whatever the next instruction
462 * This does not return.
464 common_exceptionThrown:
466 movl rPC,offGlue_pc(%ecx)
467 movl rFP,offGlue_fp(%ecx)
468 movl %ecx,OUT_ARG0(%esp)
469 call dvmMterp_exceptionThrown
470 jmp common_resumeAfterGlueCall
473 movl $$0xdeadf00d,%eax
482 .LstrNullPointerException:
483 .asciz "Ljava/lang/NullPointerException;"
484 .LstrArithmeticException:
485 .asciz "Ljava/lang/ArithmeticException;"
487 .asciz "divide by zero"
488 .LstrNegativeArraySizeException:
489 .asciz "Ljava/lang/NegativeArraySizeException;"
490 .LstrInstantiationError:
491 .asciz "Ljava/lang/InstantiationError;"
492 .LstrNoSuchMethodError:
493 .asciz "Ljava/lang/NoSuchMethodError;"
495 .asciz "Ljava/lang/InternalError;"
496 .LstrFilledNewArrayNotImplA:
497 .asciz "filled-new-array only implemented for 'int'"