• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2/*
3 * ===========================================================================
4 *  Common subroutines and data
5 * ===========================================================================
6 */
7
8
9
10    .text
11    .align  2
12
13#if defined(WITH_JIT)
14/*
15 * Return from the translation cache to the interpreter when the compiler is
16 * having issues translating/executing a Dalvik instruction. We have to skip
17 * the code cache lookup otherwise it is possible to indefinitely bouce
18 * between the interpreter and the code cache if the instruction that fails
19 * to be compiled happens to be at a trace start.
20 */
21    .global dvmJitToInterpPunt
22dvmJitToInterpPunt:
23    mov    rPC, r0
24#ifdef EXIT_STATS
25    mov    r0,lr
26    bl     dvmBumpPunt;
27#endif
28    EXPORT_PC()
29    adrl   rIBASE, dvmAsmInstructionStart
30    FETCH_INST()
31    GET_INST_OPCODE(ip)
32    GOTO_OPCODE(ip)
33
34/*
35 * Return to the interpreter to handle a single instruction.
36 * On entry:
37 *    r0 <= PC
38 *    r1 <= PC of resume instruction
39 *    lr <= resume point in translation
40 */
41    .global dvmJitToInterpSingleStep
42dvmJitToInterpSingleStep:
43    str    lr,[rGLUE,#offGlue_jitResume]
44    str    r1,[rGLUE,#offGlue_jitResumePC]
45    mov    r1,#kInterpEntryInstr
46    @ enum is 4 byte in aapcs-EABI
47    str    r1, [rGLUE, #offGlue_entryPoint]
48    mov    rPC,r0
49    EXPORT_PC()
50    adrl   rIBASE, dvmAsmInstructionStart
51    mov    r2,#kJitSingleStep     @ Ask for single step and then revert
52    str    r2,[rGLUE,#offGlue_jitState]
53    mov    r1,#1                  @ set changeInterp to bail to debug interp
54    b      common_gotoBail
55
56
57/*
58 * Return from the translation cache and immediately request
59 * a translation for the exit target.  Commonly used following
60 * invokes.
61 */
62    .global dvmJitToTraceSelect
63dvmJitToTraceSelect:
64    ldr    rPC,[r14, #-1]           @ get our target PC
65    add    rINST,r14,#-5            @ save start of chain branch
66    mov    r0,rPC
67    bl     dvmJitGetCodeAddr        @ Is there a translation?
68    cmp    r0,#0
69    beq    2f
70    mov    r1,rINST
71    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
72    cmp    r0,#0                    @ successful chain?
73    bxne   r0                       @ continue native execution
74    b      toInterpreter            @ didn't chain - resume with interpreter
75
76/* No translation, so request one if profiling isn't disabled*/
772:
78    adrl   rIBASE, dvmAsmInstructionStart
79    GET_JIT_PROF_TABLE(r0)
80    FETCH_INST()
81    cmp    r0, #0
82    bne    common_selectTrace
83    GET_INST_OPCODE(ip)
84    GOTO_OPCODE(ip)
85
86/*
87 * Return from the translation cache to the interpreter.
88 * The return was done with a BLX from thumb mode, and
89 * the following 32-bit word contains the target rPC value.
90 * Note that lr (r14) will have its low-order bit set to denote
91 * its thumb-mode origin.
92 *
93 * We'll need to stash our lr origin away, recover the new
94 * target and then check to see if there is a translation available
95 * for our new target.  If so, we do a translation chain and
96 * go back to native execution.  Otherwise, it's back to the
97 * interpreter (after treating this entry as a potential
98 * trace start).
99 */
100    .global dvmJitToInterpNormal
101dvmJitToInterpNormal:
102    ldr    rPC,[r14, #-1]           @ get our target PC
103    add    rINST,r14,#-5            @ save start of chain branch
104#ifdef EXIT_STATS
105    bl     dvmBumpNormal
106#endif
107    mov    r0,rPC
108    bl     dvmJitGetCodeAddr        @ Is there a translation?
109    cmp    r0,#0
110    beq    toInterpreter            @ go if not, otherwise do chain
111    mov    r1,rINST
112    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
113    cmp    r0,#0                    @ successful chain?
114    bxne   r0                       @ continue native execution
115    b      toInterpreter            @ didn't chain - resume with interpreter
116
117/*
118 * Return from the translation cache to the interpreter to do method invocation.
119 * Check if translation exists for the callee, but don't chain to it.
120 */
121    .global dvmJitToInterpNoChain
122dvmJitToInterpNoChain:
123#ifdef EXIT_STATS
124    bl     dvmBumpNoChain
125#endif
126    mov    r0,rPC
127    bl     dvmJitGetCodeAddr        @ Is there a translation?
128    cmp    r0,#0
129    bxne   r0                       @ continue native execution if so
130
131/*
132 * No translation, restore interpreter regs and start interpreting.
133 * rGLUE & rFP were preserved in the translated code, and rPC has
134 * already been restored by the time we get here.  We'll need to set
135 * up rIBASE & rINST, and load the address of the JitTable into r0.
136 */
137toInterpreter:
138    EXPORT_PC()
139    adrl   rIBASE, dvmAsmInstructionStart
140    FETCH_INST()
141    GET_JIT_PROF_TABLE(r0)
142    @ NOTE: intended fallthrough
143/*
144 * Common code to update potential trace start counter, and initiate
145 * a trace-build if appropriate.  On entry, rPC should point to the
146 * next instruction to execute, and rINST should be already loaded with
147 * the next opcode word, and r0 holds a pointer to the jit profile
148 * table (pJitProfTable).
149 */
150common_testUpdateProfile:
151    cmp     r0,#0
152    GET_INST_OPCODE(ip)
153    GOTO_OPCODE_IFEQ(ip)       @ if not profiling, fallthrough otherwise */
154
155common_updateProfile:
156    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
157    lsl     r3,r3,#23          @ shift out excess 511
158    ldrb    r1,[r0,r3,lsr #23] @ get counter
159    GET_INST_OPCODE(ip)
160    subs    r1,r1,#1           @ decrement counter
161    strb    r1,[r0,r3,lsr #23] @ and store it
162    GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
163
164/*
165 * Here, we switch to the debug interpreter to request
166 * trace selection.  First, though, check to see if there
167 * is already a native translation in place (and, if so,
168 * jump to it now).
169 */
170    mov     r1,#255
171    strb    r1,[r0,r3,lsr #23] @ reset counter
172    EXPORT_PC()
173    mov     r0,rPC
174    bl      dvmJitGetCodeAddr           @ r0<- dvmJitGetCodeAddr(rPC)
175    cmp     r0,#0
176    beq     common_selectTrace
177    bxne    r0                          @ jump to the translation
178common_selectTrace:
179    mov     r2,#kJitTSelectRequest      @ ask for trace selection
180    str     r2,[rGLUE,#offGlue_jitState]
181    mov     r1,#1                       @ set changeInterp
182    b       common_gotoBail
183
184#endif
185
186/*
187 * Common code when a backward branch is taken.
188 *
189 * On entry:
190 *  r9 is PC adjustment *in bytes*
191 */
192common_backwardBranch:
193    mov     r0, #kInterpEntryInstr
194    bl      common_periodicChecks
195#if defined(WITH_JIT)
196    GET_JIT_PROF_TABLE(r0)
197    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
198    cmp     r0,#0
199    bne     common_updateProfile
200    GET_INST_OPCODE(ip)
201    GOTO_OPCODE(ip)
202#else
203    FETCH_ADVANCE_INST_RB(r9)           @ update rPC, load rINST
204    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
205    GOTO_OPCODE(ip)                     @ jump to next instruction
206#endif
207
208
209/*
210 * Need to see if the thread needs to be suspended or debugger/profiler
211 * activity has begun.
212 *
213 * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
214 * have to do the second ldr.
215 *
216 * TODO: reduce this so we're just checking a single location.
217 *
218 * On entry:
219 *  r0 is reentry type, e.g. kInterpEntryInstr
220 *  r9 is trampoline PC adjustment *in bytes*
221 */
222common_periodicChecks:
223    ldr     r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
224
225#if defined(WITH_DEBUGGER)
226    ldr     r1, [rGLUE, #offGlue_pDebuggerActive]   @ r1<- &debuggerActive
227#endif
228#if defined(WITH_PROFILER)
229    ldr     r2, [rGLUE, #offGlue_pActiveProfilers]  @ r2<- &activeProfilers
230#endif
231
232    ldr     r3, [r3]                    @ r3<- suspendCount (int)
233
234#if defined(WITH_DEBUGGER)
235    ldrb    r1, [r1]                    @ r1<- debuggerActive (boolean)
236#endif
237#if defined (WITH_PROFILER)
238    ldr     r2, [r2]                    @ r2<- activeProfilers (int)
239#endif
240
241    cmp     r3, #0                      @ suspend pending?
242    bne     2f                          @ yes, do full suspension check
243
244#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
245# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
246    orrs    r1, r1, r2                  @ r1<- r1 | r2
247    cmp     r1, #0                      @ debugger attached or profiler started?
248# elif defined(WITH_DEBUGGER)
249    cmp     r1, #0                      @ debugger attached?
250# elif defined(WITH_PROFILER)
251    cmp     r2, #0                      @ profiler started?
252# endif
253    bne     3f                          @ debugger/profiler, switch interp
254#endif
255
256    bx      lr                          @ nothing to do, return
257
2582:  @ check suspend
259    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- glue->self
260    EXPORT_PC()                         @ need for precise GC
261    b       dvmCheckSuspendPending      @ suspend if necessary, then return
262
2633:  @ debugger/profiler enabled, bail out
264    add     rPC, rPC, r9                @ update rPC
265    str     r0, [rGLUE, #offGlue_entryPoint]
266    mov     r1, #1                      @ "want switch" = true
267    b       common_gotoBail
268
269
270/*
271 * The equivalent of "goto bail", this calls through the "bail handler".
272 *
273 * State registers will be saved to the "glue" area before bailing.
274 *
275 * On entry:
276 *  r1 is "bool changeInterp", indicating if we want to switch to the
277 *     other interpreter or just bail all the way out
278 */
279common_gotoBail:
280    SAVE_PC_FP_TO_GLUE()                @ export state to "glue"
281    mov     r0, rGLUE                   @ r0<- glue ptr
282    b       dvmMterpStdBail             @ call(glue, changeInterp)
283
284    @add     r1, r1, #1                  @ using (boolean+1)
285    @add     r0, rGLUE, #offGlue_jmpBuf  @ r0<- &glue->jmpBuf
286    @bl      _longjmp                    @ does not return
287    @bl      common_abort
288
289
290/*
291 * Common code for method invocation with range.
292 *
293 * On entry:
294 *  r0 is "Method* methodToCall", the method we're trying to call
295 */
296common_invokeMethodRange:
297.LinvokeNewRange:
298    @ prepare to copy args to "outs" area of current frame
299    movs    r2, rINST, lsr #8           @ r2<- AA (arg count) -- test for zero
300    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
301    beq     .LinvokeArgsDone            @ if no args, skip the rest
302    FETCH(r1, 2)                        @ r1<- CCCC
303
304    @ r0=methodToCall, r1=CCCC, r2=count, r10=outs
305    @ (very few methods have > 10 args; could unroll for common cases)
306    add     r3, rFP, r1, lsl #2         @ r3<- &fp[CCCC]
307    sub     r10, r10, r2, lsl #2        @ r10<- "outs" area, for call args
308    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
3091:  ldr     r1, [r3], #4                @ val = *fp++
310    subs    r2, r2, #1                  @ count--
311    str     r1, [r10], #4               @ *outs++ = val
312    bne     1b                          @ ...while count != 0
313    ldrh    r3, [r0, #offMethod_outsSize]   @ r3<- methodToCall->outsSize
314    b       .LinvokeArgsDone
315
316/*
317 * Common code for method invocation without range.
318 *
319 * On entry:
320 *  r0 is "Method* methodToCall", the method we're trying to call
321 */
322common_invokeMethodNoRange:
323.LinvokeNewNoRange:
324    @ prepare to copy args to "outs" area of current frame
325    movs    r2, rINST, lsr #12          @ r2<- B (arg count) -- test for zero
326    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
327    FETCH(r1, 2)                        @ r1<- GFED (load here to hide latency)
328    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
329    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
330    beq     .LinvokeArgsDone
331
332    @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
333.LinvokeNonRange:
334    rsb     r2, r2, #5                  @ r2<- 5-r2
335    add     pc, pc, r2, lsl #4          @ computed goto, 4 instrs each
336    bl      common_abort                @ (skipped due to ARM prefetch)
3375:  and     ip, rINST, #0x0f00          @ isolate A
338    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vA (shift right 8, left 2)
339    mov     r0, r0                      @ nop
340    str     r2, [r10, #-4]!             @ *--outs = vA
3414:  and     ip, r1, #0xf000             @ isolate G
342    ldr     r2, [rFP, ip, lsr #10]      @ r2<- vG (shift right 12, left 2)
343    mov     r0, r0                      @ nop
344    str     r2, [r10, #-4]!             @ *--outs = vG
3453:  and     ip, r1, #0x0f00             @ isolate F
346    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vF
347    mov     r0, r0                      @ nop
348    str     r2, [r10, #-4]!             @ *--outs = vF
3492:  and     ip, r1, #0x00f0             @ isolate E
350    ldr     r2, [rFP, ip, lsr #2]       @ r2<- vE
351    mov     r0, r0                      @ nop
352    str     r2, [r10, #-4]!             @ *--outs = vE
3531:  and     ip, r1, #0x000f             @ isolate D
354    ldr     r2, [rFP, ip, lsl #2]       @ r2<- vD
355    mov     r0, r0                      @ nop
356    str     r2, [r10, #-4]!             @ *--outs = vD
3570:  @ fall through to .LinvokeArgsDone
358
359.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
360    ldr     r2, [r0, #offMethod_insns]  @ r2<- method->insns
361    ldr     rINST, [r0, #offMethod_clazz]  @ rINST<- method->clazz
362    @ find space for the new stack frame, check for overflow
363    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
364    sub     r1, r1, r9, lsl #2          @ r1<- newFp (old savearea - regsSize)
365    SAVEAREA_FROM_FP(r10, r1)           @ r10<- newSaveArea
366@    bl      common_dumpRegs
367    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
368    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
369    cmp     r3, r9                      @ bottom < interpStackEnd?
370    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
371    blt     .LstackOverflow             @ yes, this frame will overflow stack
372
373    @ set up newSaveArea
374#ifdef EASY_GDB
375    SAVEAREA_FROM_FP(ip, rFP)           @ ip<- stack save area
376    str     ip, [r10, #offStackSaveArea_prevSave]
377#endif
378    str     rFP, [r10, #offStackSaveArea_prevFrame]
379    str     rPC, [r10, #offStackSaveArea_savedPc]
380#if defined(WITH_JIT)
381    mov     r9, #0
382    str     r9, [r10, #offStackSaveArea_returnAddr]
383#endif
384    str     r0, [r10, #offStackSaveArea_method]
385    tst     r3, #ACC_NATIVE
386    bne     .LinvokeNative
387
388    /*
389    stmfd   sp!, {r0-r3}
390    bl      common_printNewline
391    mov     r0, rFP
392    mov     r1, #0
393    bl      dvmDumpFp
394    ldmfd   sp!, {r0-r3}
395    stmfd   sp!, {r0-r3}
396    mov     r0, r1
397    mov     r1, r10
398    bl      dvmDumpFp
399    bl      common_printNewline
400    ldmfd   sp!, {r0-r3}
401    */
402
403    ldrh    r9, [r2]                        @ r9 <- load INST from new PC
404    ldr     r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
405    mov     rPC, r2                         @ publish new rPC
406    ldr     r2, [rGLUE, #offGlue_self]      @ r2<- glue->self
407
408    @ Update "glue" values for the new method
409    @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
410    str     r0, [rGLUE, #offGlue_method]    @ glue->method = methodToCall
411    str     r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
412#if defined(WITH_JIT)
413    GET_JIT_PROF_TABLE(r0)
414    mov     rFP, r1                         @ fp = newFp
415    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
416    mov     rINST, r9                       @ publish new rINST
417    str     r1, [r2, #offThread_curFrame]   @ self->curFrame = newFp
418    cmp     r0,#0
419    bne     common_updateProfile
420    GOTO_OPCODE(ip)                         @ jump to next instruction
421#else
422    mov     rFP, r1                         @ fp = newFp
423    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
424    mov     rINST, r9                       @ publish new rINST
425    str     r1, [r2, #offThread_curFrame]   @ self->curFrame = newFp
426    GOTO_OPCODE(ip)                         @ jump to next instruction
427#endif
428
429.LinvokeNative:
430    @ Prep for the native call
431    @ r0=methodToCall, r1=newFp, r10=newSaveArea
432    ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
433    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
434    str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
435    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
436    mov     r9, r3                      @ r9<- glue->self (preserve)
437
438    mov     r2, r0                      @ r2<- methodToCall
439    mov     r0, r1                      @ r0<- newFp (points to args)
440    add     r1, rGLUE, #offGlue_retval  @ r1<- &retval
441
442#ifdef ASSIST_DEBUGGER
443    /* insert fake function header to help gdb find the stack frame */
444    b       .Lskip
445    .type   dalvik_mterp, %function
446dalvik_mterp:
447    .fnstart
448    MTERP_ENTRY1
449    MTERP_ENTRY2
450.Lskip:
451#endif
452
453    @mov     lr, pc                      @ set return addr
454    @ldr     pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
455    LDR_PC_LR "[r2, #offMethod_nativeFunc]"
456
457    @ native return; r9=self, r10=newSaveArea
458    @ equivalent to dvmPopJniLocals
459    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
460    ldr     r1, [r9, #offThread_exception] @ check for exception
461    str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
462    cmp     r1, #0                      @ null?
463    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
464    bne     common_exceptionThrown      @ no, handle exception
465
466    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
467    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
468    GOTO_OPCODE(ip)                     @ jump to next instruction
469
470.LstackOverflow:
471    ldr     r0, [rGLUE, #offGlue_self]  @ r0<- self
472    bl      dvmHandleStackOverflow
473    b       common_exceptionThrown
474#ifdef ASSIST_DEBUGGER
475    .fnend
476#endif
477
478
479    /*
480     * Common code for method invocation, calling through "glue code".
481     *
482     * TODO: now that we have range and non-range invoke handlers, this
483     *       needs to be split into two.  Maybe just create entry points
484     *       that set r9 and jump here?
485     *
486     * On entry:
487     *  r0 is "Method* methodToCall", the method we're trying to call
488     *  r9 is "bool methodCallRange", indicating if this is a /range variant
489     */
490     .if    0
491.LinvokeOld:
492    sub     sp, sp, #8                  @ space for args + pad
493    FETCH(ip, 2)                        @ ip<- FEDC or CCCC
494    mov     r2, r0                      @ A2<- methodToCall
495    mov     r0, rGLUE                   @ A0<- glue
496    SAVE_PC_FP_TO_GLUE()                @ export state to "glue"
497    mov     r1, r9                      @ A1<- methodCallRange
498    mov     r3, rINST, lsr #8           @ A3<- AA
499    str     ip, [sp, #0]                @ A4<- ip
500    bl      dvmMterp_invokeMethod       @ call the C invokeMethod
501    add     sp, sp, #8                  @ remove arg area
502    b       common_resumeAfterGlueCall  @ continue to next instruction
503    .endif
504
505
506
507/*
508 * Common code for handling a return instruction.
509 *
510 * This does not return.
511 */
512common_returnFromMethod:
513.LreturnNew:
514    mov     r0, #kInterpEntryReturn
515    mov     r9, #0
516    bl      common_periodicChecks
517
518    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
519    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
520    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
521    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
522                                        @ r2<- method we're returning to
523    ldr     r3, [rGLUE, #offGlue_self]  @ r3<- glue->self
524    cmp     r2, #0                      @ is this a break frame?
525    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
526    mov     r1, #0                      @ "want switch" = false
527    beq     common_gotoBail             @ break frame, bail out completely
528
529    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
530    str     r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
531    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
532    str     rFP, [r3, #offThread_curFrame]  @ self->curFrame = fp
533#if defined(WITH_JIT)
534    ldr     r3, [r0, #offStackSaveArea_returnAddr] @ r3 = saveArea->returnAddr
535    GET_JIT_PROF_TABLE(r0)
536    mov     rPC, r9                     @ publish new rPC
537    str     r1, [rGLUE, #offGlue_methodClassDex]
538    cmp     r3, #0                      @ caller is compiled code
539    blxne   r3
540    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
541    cmp     r0,#0
542    bne     common_updateProfile
543    GOTO_OPCODE(ip)                     @ jump to next instruction
544#else
545    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
546    mov     rPC, r9                     @ publish new rPC
547    str     r1, [rGLUE, #offGlue_methodClassDex]
548    GOTO_OPCODE(ip)                     @ jump to next instruction
549#endif
550
551    /*
552     * Return handling, calls through "glue code".
553     */
554     .if    0
555.LreturnOld:
556    SAVE_PC_FP_TO_GLUE()                @ export state
557    mov     r0, rGLUE                   @ arg to function
558    bl      dvmMterp_returnFromMethod
559    b       common_resumeAfterGlueCall
560    .endif
561
562
563/*
564 * Somebody has thrown an exception.  Handle it.
565 *
566 * If the exception processing code returns to us (instead of falling
567 * out of the interpreter), continue with whatever the next instruction
568 * now happens to be.
569 *
570 * This does not return.
571 */
572     .global dvmMterpCommonExceptionThrown
573dvmMterpCommonExceptionThrown:
574common_exceptionThrown:
575.LexceptionNew:
576    mov     r0, #kInterpEntryThrow
577    mov     r9, #0
578    bl      common_periodicChecks
579
580#if defined(WITH_JIT)
581    mov     r2,#kJitTSelectAbort        @ abandon trace selection in progress
582    str     r2,[rGLUE,#offGlue_jitState]
583#endif
584
585    ldr     r10, [rGLUE, #offGlue_self] @ r10<- glue->self
586    ldr     r9, [r10, #offThread_exception] @ r9<- self->exception
587    mov     r1, r10                     @ r1<- self
588    mov     r0, r9                      @ r0<- exception
589    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
590    mov     r3, #0                      @ r3<- NULL
591    str     r3, [r10, #offThread_exception] @ self->exception = NULL
592
593    /* set up args and a local for "&fp" */
594    /* (str sp, [sp, #-4]!  would be perfect here, but is discouraged) */
595    str     rFP, [sp, #-4]!             @ *--sp = fp
596    mov     ip, sp                      @ ip<- &fp
597    mov     r3, #0                      @ r3<- false
598    str     ip, [sp, #-4]!              @ *--sp = &fp
599    ldr     r1, [rGLUE, #offGlue_method] @ r1<- glue->method
600    mov     r0, r10                     @ r0<- self
601    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
602    mov     r2, r9                      @ r2<- exception
603    sub     r1, rPC, r1                 @ r1<- pc - method->insns
604    mov     r1, r1, asr #1              @ r1<- offset in code units
605
606    /* call, r0 gets catchRelPc (a code-unit offset) */
607    bl      dvmFindCatchBlock           @ call(self, relPc, exc, scan?, &fp)
608
609    /* fix earlier stack overflow if necessary; may trash rFP */
610    ldrb    r1, [r10, #offThread_stackOverflowed]
611    cmp     r1, #0                      @ did we overflow earlier?
612    beq     1f                          @ no, skip ahead
613    mov     rFP, r0                     @ save relPc result in rFP
614    mov     r0, r10                     @ r0<- self
615    bl      dvmCleanupStackOverflow     @ call(self)
616    mov     r0, rFP                     @ restore result
6171:
618
619    /* update frame pointer and check result from dvmFindCatchBlock */
620    ldr     rFP, [sp, #4]               @ retrieve the updated rFP
621    cmp     r0, #0                      @ is catchRelPc < 0?
622    add     sp, sp, #8                  @ restore stack
623    bmi     .LnotCaughtLocally
624
625    /* adjust locals to match self->curFrame and updated PC */
626    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
627    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
628    str     r1, [rGLUE, #offGlue_method]    @ glue->method = new method
629    ldr     r2, [r1, #offMethod_clazz]      @ r2<- method->clazz
630    ldr     r3, [r1, #offMethod_insns]      @ r3<- method->insns
631    ldr     r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
632    add     rPC, r3, r0, asl #1             @ rPC<- method->insns + catchRelPc
633    str     r2, [rGLUE, #offGlue_methodClassDex] @ glue->pDvmDex = meth...
634
635    /* release the tracked alloc on the exception */
636    mov     r0, r9                      @ r0<- exception
637    mov     r1, r10                     @ r1<- self
638    bl      dvmReleaseTrackedAlloc      @ release the exception
639
640    /* restore the exception if the handler wants it */
641    FETCH_INST()                        @ load rINST from rPC
642    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
643    cmp     ip, #OP_MOVE_EXCEPTION      @ is it "move-exception"?
644    streq   r9, [r10, #offThread_exception] @ yes, restore the exception
645    GOTO_OPCODE(ip)                     @ jump to next instruction
646
647.LnotCaughtLocally: @ r9=exception, r10=self
648    /* fix stack overflow if necessary */
649    ldrb    r1, [r10, #offThread_stackOverflowed]
650    cmp     r1, #0                      @ did we overflow earlier?
651    movne   r0, r10                     @ if yes: r0<- self
652    blne    dvmCleanupStackOverflow     @ if yes: call(self)
653
654    @ may want to show "not caught locally" debug messages here
655#if DVM_SHOW_EXCEPTION >= 2
656    /* call __android_log_print(prio, tag, format, ...) */
657    /* "Exception %s from %s:%d not caught locally" */
658    @ dvmLineNumFromPC(method, pc - method->insns)
659    ldr     r0, [rGLUE, #offGlue_method]
660    ldr     r1, [r0, #offMethod_insns]
661    sub     r1, rPC, r1
662    asr     r1, r1, #1
663    bl      dvmLineNumFromPC
664    str     r0, [sp, #-4]!
665    @ dvmGetMethodSourceFile(method)
666    ldr     r0, [rGLUE, #offGlue_method]
667    bl      dvmGetMethodSourceFile
668    str     r0, [sp, #-4]!
669    @ exception->clazz->descriptor
670    ldr     r3, [r9, #offObject_clazz]
671    ldr     r3, [r3, #offClassObject_descriptor]
672    @
673    ldr     r2, strExceptionNotCaughtLocally
674    ldr     r1, strLogTag
675    mov     r0, #3                      @ LOG_DEBUG
676    bl      __android_log_print
677#endif
678    str     r9, [r10, #offThread_exception] @ restore exception
679    mov     r0, r9                      @ r0<- exception
680    mov     r1, r10                     @ r1<- self
681    bl      dvmReleaseTrackedAlloc      @ release the exception
682    mov     r1, #0                      @ "want switch" = false
683    b       common_gotoBail             @ bail out
684
685
686    /*
687     * Exception handling, calls through "glue code".
688     */
689    .if     0
690.LexceptionOld:
691    SAVE_PC_FP_TO_GLUE()                @ export state
692    mov     r0, rGLUE                   @ arg to function
693    bl      dvmMterp_exceptionThrown
694    b       common_resumeAfterGlueCall
695    .endif
696
697
698/*
699 * After returning from a "glued" function, pull out the updated
700 * values and start executing at the next instruction.
701 */
702common_resumeAfterGlueCall:
703    LOAD_PC_FP_FROM_GLUE()              @ pull rPC and rFP out of glue
704    FETCH_INST()                        @ load rINST from rPC
705    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
706    GOTO_OPCODE(ip)                     @ jump to next instruction
707
708/*
709 * Invalid array index.
710 */
711common_errArrayIndex:
712    EXPORT_PC()
713    ldr     r0, strArrayIndexException
714    mov     r1, #0
715    bl      dvmThrowException
716    b       common_exceptionThrown
717
718/*
719 * Invalid array value.
720 */
721common_errArrayStore:
722    EXPORT_PC()
723    ldr     r0, strArrayStoreException
724    mov     r1, #0
725    bl      dvmThrowException
726    b       common_exceptionThrown
727
728/*
729 * Integer divide or mod by zero.
730 */
731common_errDivideByZero:
732    EXPORT_PC()
733    ldr     r0, strArithmeticException
734    ldr     r1, strDivideByZero
735    bl      dvmThrowException
736    b       common_exceptionThrown
737
738/*
739 * Attempt to allocate an array with a negative size.
740 */
741common_errNegativeArraySize:
742    EXPORT_PC()
743    ldr     r0, strNegativeArraySizeException
744    mov     r1, #0
745    bl      dvmThrowException
746    b       common_exceptionThrown
747
748/*
749 * Invocation of a non-existent method.
750 */
751common_errNoSuchMethod:
752    EXPORT_PC()
753    ldr     r0, strNoSuchMethodError
754    mov     r1, #0
755    bl      dvmThrowException
756    b       common_exceptionThrown
757
758/*
759 * We encountered a null object when we weren't expecting one.  We
760 * export the PC, throw a NullPointerException, and goto the exception
761 * processing code.
762 */
763common_errNullObject:
764    EXPORT_PC()
765    ldr     r0, strNullPointerException
766    mov     r1, #0
767    bl      dvmThrowException
768    b       common_exceptionThrown
769
770/*
771 * For debugging, cause an immediate fault.  The source address will
772 * be in lr (use a bl instruction to jump here).
773 */
774common_abort:
775    ldr     pc, .LdeadFood
776.LdeadFood:
777    .word   0xdeadf00d
778
779/*
780 * Spit out a "we were here", preserving all registers.  (The attempt
781 * to save ip won't work, but we need to save an even number of
782 * registers for EABI 64-bit stack alignment.)
783 */
784    .macro  SQUEAK num
785common_squeak\num:
786    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
787    ldr     r0, strSqueak
788    mov     r1, #\num
789    bl      printf
790    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
791    bx      lr
792    .endm
793
794    SQUEAK  0
795    SQUEAK  1
796    SQUEAK  2
797    SQUEAK  3
798    SQUEAK  4
799    SQUEAK  5
800
801/*
802 * Spit out the number in r0, preserving registers.
803 */
804common_printNum:
805    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
806    mov     r1, r0
807    ldr     r0, strSqueak
808    bl      printf
809    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
810    bx      lr
811
812/*
813 * Print a newline, preserving registers.
814 */
815common_printNewline:
816    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
817    ldr     r0, strNewline
818    bl      printf
819    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
820    bx      lr
821
822    /*
823     * Print the 32-bit quantity in r0 as a hex value, preserving registers.
824     */
825common_printHex:
826    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
827    mov     r1, r0
828    ldr     r0, strPrintHex
829    bl      printf
830    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
831    bx      lr
832
833/*
834 * Print the 64-bit quantity in r0-r1, preserving registers.
835 */
836common_printLong:
837    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
838    mov     r3, r1
839    mov     r2, r0
840    ldr     r0, strPrintLong
841    bl      printf
842    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
843    bx      lr
844
845/*
846 * Print full method info.  Pass the Method* in r0.  Preserves regs.
847 */
848common_printMethod:
849    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
850    bl      dvmMterpPrintMethod
851    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
852    bx      lr
853
854/*
855 * Call a C helper function that dumps regs and possibly some
856 * additional info.  Requires the C function to be compiled in.
857 */
858    .if     0
859common_dumpRegs:
860    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
861    bl      dvmMterpDumpArmRegs
862    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
863    bx      lr
864    .endif
865
866#if 0
867/*
868 * Experiment on VFP mode.
869 *
870 * uint32_t setFPSCR(uint32_t val, uint32_t mask)
871 *
872 * Updates the bits specified by "mask", setting them to the values in "val".
873 */
874setFPSCR:
875    and     r0, r0, r1                  @ make sure no stray bits are set
876    fmrx    r2, fpscr                   @ get VFP reg
877    mvn     r1, r1                      @ bit-invert mask
878    and     r2, r2, r1                  @ clear masked bits
879    orr     r2, r2, r0                  @ set specified bits
880    fmxr    fpscr, r2                   @ set VFP reg
881    mov     r0, r2                      @ return new value
882    bx      lr
883
884    .align  2
885    .global dvmConfigureFP
886    .type   dvmConfigureFP, %function
887dvmConfigureFP:
888    stmfd   sp!, {ip, lr}
889    /* 0x03000000 sets DN/FZ */
890    /* 0x00009f00 clears the six exception enable flags */
891    bl      common_squeak0
892    mov     r0, #0x03000000             @ r0<- 0x03000000
893    add     r1, r0, #0x9f00             @ r1<- 0x03009f00
894    bl      setFPSCR
895    ldmfd   sp!, {ip, pc}
896#endif
897
898
899/*
900 * String references, must be close to the code that uses them.
901 */
902    .align  2
903strArithmeticException:
904    .word   .LstrArithmeticException
905strArrayIndexException:
906    .word   .LstrArrayIndexException
907strArrayStoreException:
908    .word   .LstrArrayStoreException
909strDivideByZero:
910    .word   .LstrDivideByZero
911strNegativeArraySizeException:
912    .word   .LstrNegativeArraySizeException
913strNoSuchMethodError:
914    .word   .LstrNoSuchMethodError
915strNullPointerException:
916    .word   .LstrNullPointerException
917
918strLogTag:
919    .word   .LstrLogTag
920strExceptionNotCaughtLocally:
921    .word   .LstrExceptionNotCaughtLocally
922
923strNewline:
924    .word   .LstrNewline
925strSqueak:
926    .word   .LstrSqueak
927strPrintHex:
928    .word   .LstrPrintHex
929strPrintLong:
930    .word   .LstrPrintLong
931
932/*
933 * Zero-terminated ASCII string data.
934 *
935 * On ARM we have two choices: do like gcc does, and LDR from a .word
936 * with the address, or use an ADR pseudo-op to get the address
937 * directly.  ADR saves 4 bytes and an indirection, but it's using a
938 * PC-relative addressing mode and hence has a limited range, which
939 * makes it not work well with mergeable string sections.
940 */
941    .section .rodata.str1.4,"aMS",%progbits,1
942
943.LstrBadEntryPoint:
944    .asciz  "Bad entry point %d\n"
945.LstrArithmeticException:
946    .asciz  "Ljava/lang/ArithmeticException;"
947.LstrArrayIndexException:
948    .asciz  "Ljava/lang/ArrayIndexOutOfBoundsException;"
949.LstrArrayStoreException:
950    .asciz  "Ljava/lang/ArrayStoreException;"
951.LstrClassCastException:
952    .asciz  "Ljava/lang/ClassCastException;"
953.LstrDivideByZero:
954    .asciz  "divide by zero"
955.LstrFilledNewArrayNotImpl:
956    .asciz  "filled-new-array only implemented for objects and 'int'"
957.LstrInternalError:
958    .asciz  "Ljava/lang/InternalError;"
959.LstrInstantiationError:
960    .asciz  "Ljava/lang/InstantiationError;"
961.LstrNegativeArraySizeException:
962    .asciz  "Ljava/lang/NegativeArraySizeException;"
963.LstrNoSuchMethodError:
964    .asciz  "Ljava/lang/NoSuchMethodError;"
965.LstrNullPointerException:
966    .asciz  "Ljava/lang/NullPointerException;"
967
968.LstrLogTag:
969    .asciz  "mterp"
970.LstrExceptionNotCaughtLocally:
971    .asciz  "Exception %s from %s:%d not caught locally\n"
972
973.LstrNewline:
974    .asciz  "\n"
975.LstrSqueak:
976    .asciz  "<%d>"
977.LstrPrintHex:
978    .asciz  "<0x%x>"
979.LstrPrintLong:
980    .asciz  "<%lld>"
981
982