1/*
2 * ===========================================================================
3 *  Common subroutines and data
4 * ===========================================================================
5 */
6
7    .text
8    .align  2
9
10#if defined(WITH_JIT)
11
12#if defined(WITH_SELF_VERIFICATION)
13/*
14 * "longjmp" to a translation after single-stepping.  Before returning
15 * to translation, must save state for self-verification.
16 */
17    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
18dvmJitResumeTranslation:
19    mov    rSELF, r0                             @ restore self
20    mov    rPC, r1                               @ restore Dalvik pc
21    mov    rFP, r2                               @ restore Dalvik fp
22    ldr    r10, [rSELF,#offThread_jitResumeNPC]  @ resume address
23    mov    r2, #0
24    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
25    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
26    b      jitSVShadowRunStart                   @ resume as if cache hit
27                                                 @ expects resume addr in r10
28
29    .global dvmJitToInterpPunt
30dvmJitToInterpPunt:
31    mov    r2,#kSVSPunt                 @ r2<- interpreter entry point
32    mov    r3, #0
33    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
34    b      jitSVShadowRunEnd            @ doesn't return
35
36    .global dvmJitToInterpSingleStep
37dvmJitToInterpSingleStep:
38    mov    rPC, r0              @ set up dalvik pc
39    EXPORT_PC()
40    str    lr, [rSELF,#offThread_jitResumeNPC]
41    str    sp, [rSELF,#offThread_jitResumeNSP]
42    str    r1, [rSELF,#offThread_jitResumeDPC]
43    mov    r2,#kSVSSingleStep           @ r2<- interpreter entry point
44    b      jitSVShadowRunEnd            @ doesn't return
45
46
47    .global dvmJitToInterpNoChainNoProfile
48dvmJitToInterpNoChainNoProfile:
49    mov    r0,rPC                       @ pass our target PC
50    mov    r2,#kSVSNoProfile            @ r2<- interpreter entry point
51    mov    r3, #0                       @ 0 means !inJitCodeCache
52    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
53    b      jitSVShadowRunEnd            @ doesn't return
54
55    .global dvmJitToInterpTraceSelectNoChain
56dvmJitToInterpTraceSelectNoChain:
57    mov    r0,rPC                       @ pass our target PC
58    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
59    mov    r3, #0                       @ 0 means !inJitCodeCache
60    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
61    b      jitSVShadowRunEnd            @ doesn't return
62
63    .global dvmJitToInterpTraceSelect
64dvmJitToInterpTraceSelect:
65    ldr    r0,[lr, #-1]                 @ pass our target PC
66    mov    r2,#kSVSTraceSelect          @ r2<- interpreter entry point
67    mov    r3, #0                       @ 0 means !inJitCodeCache
68    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
69    b      jitSVShadowRunEnd            @ doesn't return
70
71    .global dvmJitToInterpBackwardBranch
72dvmJitToInterpBackwardBranch:
73    ldr    r0,[lr, #-1]                 @ pass our target PC
74    mov    r2,#kSVSBackwardBranch       @ r2<- interpreter entry point
75    mov    r3, #0                       @ 0 means !inJitCodeCache
76    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
77    b      jitSVShadowRunEnd            @ doesn't return
78
79    .global dvmJitToInterpNormal
80dvmJitToInterpNormal:
81    ldr    r0,[lr, #-1]                 @ pass our target PC
82    mov    r2,#kSVSNormal               @ r2<- interpreter entry point
83    mov    r3, #0                       @ 0 means !inJitCodeCache
84    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
85    b      jitSVShadowRunEnd            @ doesn't return
86
87    .global dvmJitToInterpNoChain
88dvmJitToInterpNoChain:
89    mov    r0,rPC                       @ pass our target PC
90    mov    r2,#kSVSNoChain              @ r2<- interpreter entry point
91    mov    r3, #0                       @ 0 means !inJitCodeCache
92    str    r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
93    b      jitSVShadowRunEnd            @ doesn't return
94#else
95
96/*
97 * "longjmp" to a translation after single-stepping.
98 */
99    .global dvmJitResumeTranslation              @ (Thread* self, u4* dFP)
100dvmJitResumeTranslation:
101    mov    rSELF, r0                             @ restore self
102    mov    rPC, r1                               @ restore Dalvik pc
103    mov    rFP, r2                               @ restore Dalvik fp
104    ldr    r0, [rSELF,#offThread_jitResumeNPC]
105    mov    r2, #0
106    str    r2, [rSELF,#offThread_jitResumeNPC]   @ reset resume address
107    ldr    sp, [rSELF,#offThread_jitResumeNSP]   @ cut back native stack
108    bx     r0                                    @ resume translation
109
110/*
111 * Return from the translation cache to the interpreter when the compiler is
112 * having issues translating/executing a Dalvik instruction. We have to skip
113 * the code cache lookup otherwise it is possible to indefinitely bouce
114 * between the interpreter and the code cache if the instruction that fails
115 * to be compiled happens to be at a trace start.
116 */
117    .global dvmJitToInterpPunt
118dvmJitToInterpPunt:
119    mov    rPC, r0
120#if defined(WITH_JIT_TUNING)
121    mov    r0,lr
122    bl     dvmBumpPunt;
123#endif
124    EXPORT_PC()
125    mov    r0, #0
126    str    r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land
127    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
128    FETCH_INST()
129    GET_INST_OPCODE(ip)
130    GOTO_OPCODE(ip)
131
132/*
133 * Return to the interpreter to handle a single instruction.
134 * We'll use the normal single-stepping mechanism via interpBreak,
135 * but also save the native pc of the resume point in the translation
136 * and the native sp so that we can later do the equivalent of a
137 * longjmp() to resume.
138 * On entry:
139 *    dPC <= Dalvik PC of instrucion to interpret
140 *    lr <= resume point in translation
141 *    r1 <= Dalvik PC of next instruction
142 */
143    .global dvmJitToInterpSingleStep
144dvmJitToInterpSingleStep:
145    mov    rPC, r0              @ set up dalvik pc
146    EXPORT_PC()
147    str    lr, [rSELF,#offThread_jitResumeNPC]
148    str    sp, [rSELF,#offThread_jitResumeNSP]
149    str    r1, [rSELF,#offThread_jitResumeDPC]
150    mov    r1, #1
151    str    r1, [rSELF,#offThread_singleStepCount]  @ just step once
152    mov    r0, rSELF
153    mov    r1, #kSubModeCountedStep
154    bl     dvmEnableSubMode     @ (self, newMode)
155    ldr    rIBASE, [rSELF,#offThread_curHandlerTable]
156    FETCH_INST()
157    GET_INST_OPCODE(ip)
158    GOTO_OPCODE(ip)
159
160/*
161 * Return from the translation cache and immediately request
162 * a translation for the exit target.  Commonly used for callees.
163 */
164    .global dvmJitToInterpTraceSelectNoChain
165dvmJitToInterpTraceSelectNoChain:
166#if defined(WITH_JIT_TUNING)
167    bl     dvmBumpNoChain
168#endif
169    mov    r0,rPC
170    mov    r1,rSELF
171    bl     dvmJitGetTraceAddrThread @ (pc, self)
172    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
173    mov    r1, rPC                  @ arg1 of translation may need this
174    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
175    cmp    r0,#0                    @ !0 means translation exists
176    bxne   r0                       @ continue native execution if so
177    b      2f                       @ branch over to use the interpreter
178
179/*
180 * Return from the translation cache and immediately request
181 * a translation for the exit target.  Commonly used following
182 * invokes.
183 */
184    .global dvmJitToInterpTraceSelect
185dvmJitToInterpTraceSelect:
186    ldr    rPC,[lr, #-1]           @ get our target PC
187    add    rINST,lr,#-5            @ save start of chain branch
188    add    rINST, #-4              @  .. which is 9 bytes back
189    mov    r0,rPC
190    mov    r1,rSELF
191    bl     dvmJitGetTraceAddrThread @ (pc, self)
192    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
193    cmp    r0,#0
194    beq    2f
195    mov    r1,rINST
196    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
197    mov    r1, rPC                  @ arg1 of translation may need this
198    mov    lr, #0                   @ in case target is HANDLER_INTERPRET
199    cmp    r0,#0                    @ successful chain?
200    bxne   r0                       @ continue native execution
201    b      toInterpreter            @ didn't chain - resume with interpreter
202
203/* No translation, so request one if profiling isn't disabled*/
2042:
205    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
206    ldr    r0, [rSELF, #offThread_pJitProfTable]
207    FETCH_INST()
208    cmp    r0, #0
209    movne  r2,#kJitTSelectRequestHot   @ ask for trace selection
210    bne    common_selectTrace
211    GET_INST_OPCODE(ip)
212    GOTO_OPCODE(ip)
213
214/*
215 * Return from the translation cache to the interpreter.
216 * The return was done with a BLX from thumb mode, and
217 * the following 32-bit word contains the target rPC value.
218 * Note that lr (r14) will have its low-order bit set to denote
219 * its thumb-mode origin.
220 *
221 * We'll need to stash our lr origin away, recover the new
222 * target and then check to see if there is a translation available
223 * for our new target.  If so, we do a translation chain and
224 * go back to native execution.  Otherwise, it's back to the
225 * interpreter (after treating this entry as a potential
226 * trace start).
227 */
228    .global dvmJitToInterpNormal
229dvmJitToInterpNormal:
230    ldr    rPC,[lr, #-1]           @ get our target PC
231    add    rINST,lr,#-5            @ save start of chain branch
232    add    rINST,#-4               @ .. which is 9 bytes back
233#if defined(WITH_JIT_TUNING)
234    bl     dvmBumpNormal
235#endif
236    mov    r0,rPC
237    mov    r1,rSELF
238    bl     dvmJitGetTraceAddrThread @ (pc, self)
239    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
240    cmp    r0,#0
241    beq    toInterpreter            @ go if not, otherwise do chain
242    mov    r1,rINST
243    bl     dvmJitChain              @ r0<- dvmJitChain(codeAddr,chainAddr)
244    mov    r1, rPC                  @ arg1 of translation may need this
245    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
246    cmp    r0,#0                    @ successful chain?
247    bxne   r0                       @ continue native execution
248    b      toInterpreter            @ didn't chain - resume with interpreter
249
250/*
251 * Return from the translation cache to the interpreter to do method invocation.
252 * Check if translation exists for the callee, but don't chain to it.
253 */
254    .global dvmJitToInterpNoChainNoProfile
255dvmJitToInterpNoChainNoProfile:
256#if defined(WITH_JIT_TUNING)
257    bl     dvmBumpNoChain
258#endif
259    mov    r0,rPC
260    mov    r1,rSELF
261    bl     dvmJitGetTraceAddrThread @ (pc, self)
262    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
263    mov    r1, rPC                  @ arg1 of translation may need this
264    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
265    cmp    r0,#0
266    bxne   r0                       @ continue native execution if so
267    EXPORT_PC()
268    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
269    FETCH_INST()
270    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
271    GOTO_OPCODE(ip)                     @ jump to next instruction
272
273/*
274 * Return from the translation cache to the interpreter to do method invocation.
275 * Check if translation exists for the callee, but don't chain to it.
276 */
277    .global dvmJitToInterpNoChain
278dvmJitToInterpNoChain:
279#if defined(WITH_JIT_TUNING)
280    bl     dvmBumpNoChain
281#endif
282    mov    r0,rPC
283    mov    r1,rSELF
284    bl     dvmJitGetTraceAddrThread @ (pc, self)
285    str    r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
286    mov    r1, rPC                  @ arg1 of translation may need this
287    mov    lr, #0                   @  in case target is HANDLER_INTERPRET
288    cmp    r0,#0
289    bxne   r0                       @ continue native execution if so
290#endif
291
292/*
293 * No translation, restore interpreter regs and start interpreting.
294 * rSELF & rFP were preserved in the translated code, and rPC has
295 * already been restored by the time we get here.  We'll need to set
296 * up rIBASE & rINST, and load the address of the JitTable into r0.
297 */
298toInterpreter:
299    EXPORT_PC()
300    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
301    FETCH_INST()
302    ldr    r0, [rSELF, #offThread_pJitProfTable]
303    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
304    @ NOTE: intended fallthrough
305
306/*
307 * Similar to common_updateProfile, but tests for null pJitProfTable
308 * r0 holds pJifProfTAble, rINST is loaded, rPC is current and
309 * rIBASE has been recently refreshed.
310 */
311common_testUpdateProfile:
312    cmp     r0, #0               @ JIT switched off?
313    beq     4f                   @ return to interp if so
314
315/*
316 * Common code to update potential trace start counter, and initiate
317 * a trace-build if appropriate.
318 * On entry here:
319 *    r0    <= pJitProfTable (verified non-NULL)
320 *    rPC   <= Dalvik PC
321 *    rINST <= next instruction
322 */
323common_updateProfile:
324    eor     r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
325    lsl     r3,r3,#(32 - JIT_PROF_SIZE_LOG_2)          @ shift out excess bits
326    ldrb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter
327    GET_INST_OPCODE(ip)
328    subs    r1,r1,#1           @ decrement counter
329    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it
330    GOTO_OPCODE_IFNE(ip)       @ if not threshold, fallthrough otherwise */
331
332    /* Looks good, reset the counter */
333    ldr     r1, [rSELF, #offThread_jitThreshold]
334    strb    r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter
335    EXPORT_PC()
336    mov     r0,rPC
337    mov     r1,rSELF
338    bl      dvmJitGetTraceAddrThread    @ (pc, self)
339    str     r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag
340    mov     r1, rPC                     @ arg1 of translation may need this
341    mov     lr, #0                      @  in case target is HANDLER_INTERPRET
342    cmp     r0,#0
343#if !defined(WITH_SELF_VERIFICATION)
344    bxne    r0                          @ jump to the translation
345    mov     r2,#kJitTSelectRequest      @ ask for trace selection
346    @ fall-through to common_selectTrace
347#else
348    moveq   r2,#kJitTSelectRequest      @ ask for trace selection
349    beq     common_selectTrace
350    /*
351     * At this point, we have a target translation.  However, if
352     * that translation is actually the interpret-only pseudo-translation
353     * we want to treat it the same as no translation.
354     */
355    mov     r10, r0                     @ save target
356    bl      dvmCompilerGetInterpretTemplate
357    cmp     r0, r10                     @ special case?
358    bne     jitSVShadowRunStart         @ set up self verification shadow space
359    @ Need to clear the inJitCodeCache flag
360    mov    r3, #0                       @ 0 means not in the JIT code cache
361    str    r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land
362    GET_INST_OPCODE(ip)
363    GOTO_OPCODE(ip)
364    /* no return */
365#endif
366
367/*
368 * On entry:
369 *  r2 is jit state.
370 */
371common_selectTrace:
372    ldrh    r0,[rSELF,#offThread_subMode]
373    ands    r0, #(kSubModeJitTraceBuild | kSubModeJitSV)
374    bne     3f                         @ already doing JIT work, continue
375    str     r2,[rSELF,#offThread_jitState]
376    mov     r0, rSELF
377/*
378 * Call out to validate trace-building request.  If successful,
379 * rIBASE will be swapped to to send us into single-stepping trace
380 * building mode, so we need to refresh before we continue.
381 */
382    EXPORT_PC()
383    SAVE_PC_FP_TO_SELF()                 @ copy of pc/fp to Thread
384    bl      dvmJitCheckTraceRequest
3853:
386    FETCH_INST()
387    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
3884:
389    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
390    GOTO_OPCODE(ip)
391    /* no return */
392#endif
393
394#if defined(WITH_SELF_VERIFICATION)
395/*
396 * Save PC and registers to shadow memory for self verification mode
397 * before jumping to native translation.
398 * On entry:
399 *    rPC, rFP, rSELF: the values that they should contain
400 *    r10: the address of the target translation.
401 */
402jitSVShadowRunStart:
403    mov     r0,rPC                      @ r0<- program counter
404    mov     r1,rFP                      @ r1<- frame pointer
405    mov     r2,rSELF                    @ r2<- self (Thread) pointer
406    mov     r3,r10                      @ r3<- target translation
407    bl      dvmSelfVerificationSaveState @ save registers to shadow space
408    ldr     rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space
409    bx      r10                         @ jump to the translation
410
411/*
412 * Restore PC, registers, and interpreter state to original values
413 * before jumping back to the interpreter.
414 * On entry:
415 *   r0:  dPC
416 *   r2:  self verification state
417 */
418jitSVShadowRunEnd:
419    mov    r1,rFP                        @ pass ending fp
420    mov    r3,rSELF                      @ pass self ptr for convenience
421    bl     dvmSelfVerificationRestoreState @ restore pc and fp values
422    LOAD_PC_FP_FROM_SELF()               @ restore pc, fp
423    ldr    r1,[r0,#offShadowSpace_svState] @ get self verification state
424    cmp    r1,#0                         @ check for punt condition
425    beq    1f
426    @ Set up SV single-stepping
427    mov    r0, rSELF
428    mov    r1, #kSubModeJitSV
429    bl     dvmEnableSubMode              @ (self, subMode)
430    mov    r2,#kJitSelfVerification      @ ask for self verification
431    str    r2,[rSELF,#offThread_jitState]
432    @ intentional fallthrough
4331:                                       @ exit to interpreter without check
434    EXPORT_PC()
435    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]
436    FETCH_INST()
437    GET_INST_OPCODE(ip)
438    GOTO_OPCODE(ip)
439#endif
440
441/*
442 * The equivalent of "goto bail", this calls through the "bail handler".
443 * It will end this interpreter activation, and return to the caller
444 * of dvmMterpStdRun.
445 *
446 * State registers will be saved to the "thread" area before bailing
447 * debugging purposes
448 */
449common_gotoBail:
450    SAVE_PC_FP_TO_SELF()                @ export state to "thread"
451    mov     r0, rSELF                   @ r0<- self ptr
452    b       dvmMterpStdBail             @ call(self, changeInterp)
453
454/*
455 * The JIT's invoke method needs to remember the callsite class and
456 * target pair.  Save them here so that they are available to
457 * dvmCheckJit following the interpretation of this invoke.
458 */
459#if defined(WITH_JIT)
460save_callsiteinfo:
461    cmp     r9, #0
462    ldrne   r9, [r9, #offObject_clazz]
463    str     r0, [rSELF, #offThread_methodToCall]
464    str     r9, [rSELF, #offThread_callsiteClass]
465    bx      lr
466#endif
467
468/*
469 * Common code for method invocation with range.
470 *
471 * On entry:
472 *  r0 is "Method* methodToCall", r9 is "this"
473 */
474common_invokeMethodRange:
475.LinvokeNewRange:
476#if defined(WITH_JIT)
477    ldrh    r1, [rSELF, #offThread_subMode]
478    ands    r1, #kSubModeJitTraceBuild
479    blne    save_callsiteinfo
480#endif
481    @ prepare to copy args to "outs" area of current frame
482    movs    r2, rINST, lsr #8           @ r2<- AA (arg count) -- test for zero
483    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
484    beq     .LinvokeArgsDone            @ if no args, skip the rest
485    FETCH(r1, 2)                        @ r1<- CCCC
486
487.LinvokeRangeArgs:
488    @ r0=methodToCall, r1=CCCC, r2=count, r10=outs
489    @ (very few methods have > 10 args; could unroll for common cases)
490    add     r3, rFP, r1, lsl #2         @ r3<- &fp[CCCC]
491    sub     r10, r10, r2, lsl #2        @ r10<- "outs" area, for call args
4921:  ldr     r1, [r3], #4                @ val = *fp++
493    subs    r2, r2, #1                  @ count--
494    str     r1, [r10], #4               @ *outs++ = val
495    bne     1b                          @ ...while count != 0
496    b       .LinvokeArgsDone
497
498/*
499 * Common code for method invocation without range.
500 *
501 * On entry:
502 *  r0 is "Method* methodToCall", r9 is "this"
503 */
504common_invokeMethodNoRange:
505.LinvokeNewNoRange:
506#if defined(WITH_JIT)
507    ldrh    r1, [rSELF, #offThread_subMode]
508    ands    r1, #kSubModeJitTraceBuild
509    blne    save_callsiteinfo
510#endif
511    @ prepare to copy args to "outs" area of current frame
512    movs    r2, rINST, lsr #12          @ r2<- B (arg count) -- test for zero
513    SAVEAREA_FROM_FP(r10, rFP)          @ r10<- stack save area
514    FETCH(r1, 2)                        @ r1<- GFED (load here to hide latency)
515    beq     .LinvokeArgsDone
516
517    @ r0=methodToCall, r1=GFED, r2=count, r10=outs
518.LinvokeNonRange:
519    rsb     r2, r2, #5                  @ r2<- 5-r2
520    add     pc, pc, r2, lsl #4          @ computed goto, 4 instrs each
521    bl      common_abort                @ (skipped due to ARM prefetch)
5225:  and     ip, rINST, #0x0f00          @ isolate A
523    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vA (shift right 8, left 2)
524    mov     r0, r0                      @ nop
525    str     r2, [r10, #-4]!             @ *--outs = vA
5264:  and     ip, r1, #0xf000             @ isolate G
527    ldr     r2, [rFP, ip, lsr #10]      @ r2<- vG (shift right 12, left 2)
528    mov     r0, r0                      @ nop
529    str     r2, [r10, #-4]!             @ *--outs = vG
5303:  and     ip, r1, #0x0f00             @ isolate F
531    ldr     r2, [rFP, ip, lsr #6]       @ r2<- vF
532    mov     r0, r0                      @ nop
533    str     r2, [r10, #-4]!             @ *--outs = vF
5342:  and     ip, r1, #0x00f0             @ isolate E
535    ldr     r2, [rFP, ip, lsr #2]       @ r2<- vE
536    mov     r0, r0                      @ nop
537    str     r2, [r10, #-4]!             @ *--outs = vE
5381:  and     ip, r1, #0x000f             @ isolate D
539    ldr     r2, [rFP, ip, lsl #2]       @ r2<- vD
540    mov     r0, r0                      @ nop
541    str     r2, [r10, #-4]!             @ *--outs = vD
5420:  @ fall through to .LinvokeArgsDone
543
544.LinvokeArgsDone: @ r0=methodToCall
545    ldrh    r9, [r0, #offMethod_registersSize]  @ r9<- methodToCall->regsSize
546    ldrh    r3, [r0, #offMethod_outsSize]  @ r3<- methodToCall->outsSize
547    ldr     r2, [r0, #offMethod_insns]  @ r2<- method->insns
548    ldr     rINST, [r0, #offMethod_clazz]  @ rINST<- method->clazz
549    @ find space for the new stack frame, check for overflow
550    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
551    sub     r1, r1, r9, lsl #2          @ r1<- newFp (old savearea - regsSize)
552    SAVEAREA_FROM_FP(r10, r1)           @ r10<- newSaveArea
553@    bl      common_dumpRegs
554    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
555    sub     r3, r10, r3, lsl #2         @ r3<- bottom (newsave - outsSize)
556    cmp     r3, r9                      @ bottom < interpStackEnd?
557    ldrh    lr, [rSELF, #offThread_subMode]
558    ldr     r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
559    blo     .LstackOverflow             @ yes, this frame will overflow stack
560
561    @ set up newSaveArea
562#ifdef EASY_GDB
563    SAVEAREA_FROM_FP(ip, rFP)           @ ip<- stack save area
564    str     ip, [r10, #offStackSaveArea_prevSave]
565#endif
566    str     rFP, [r10, #offStackSaveArea_prevFrame]
567    str     rPC, [r10, #offStackSaveArea_savedPc]
568#if defined(WITH_JIT)
569    mov     r9, #0
570    str     r9, [r10, #offStackSaveArea_returnAddr]
571#endif
572    str     r0, [r10, #offStackSaveArea_method]
573
574    @ Profiling?
575    cmp     lr, #0                      @ any special modes happening?
576    bne     2f                          @ go if so
5771:
578    tst     r3, #ACC_NATIVE
579    bne     .LinvokeNative
580
581    /*
582    stmfd   sp!, {r0-r3}
583    bl      common_printNewline
584    mov     r0, rFP
585    mov     r1, #0
586    bl      dvmDumpFp
587    ldmfd   sp!, {r0-r3}
588    stmfd   sp!, {r0-r3}
589    mov     r0, r1
590    mov     r1, r10
591    bl      dvmDumpFp
592    bl      common_printNewline
593    ldmfd   sp!, {r0-r3}
594    */
595
596    ldrh    r9, [r2]                        @ r9 <- load INST from new PC
597    ldr     r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
598    mov     rPC, r2                         @ publish new rPC
599
600    @ Update state values for the new method
601    @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST
602    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
603    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
604    mov     r2, #1
605    str     r2, [rSELF, #offThread_debugIsMethodEntry]
606#if defined(WITH_JIT)
607    ldr     r0, [rSELF, #offThread_pJitProfTable]
608    mov     rFP, r1                         @ fp = newFp
609    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
610    mov     rINST, r9                       @ publish new rINST
611    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
612    cmp     r0,#0
613    bne     common_updateProfile
614    GOTO_OPCODE(ip)                         @ jump to next instruction
615#else
616    mov     rFP, r1                         @ fp = newFp
617    GET_PREFETCHED_OPCODE(ip, r9)           @ extract prefetched opcode from r9
618    mov     rINST, r9                       @ publish new rINST
619    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
620    GOTO_OPCODE(ip)                         @ jump to next instruction
621#endif
622
6232:
624    @ Profiling - record method entry.  r0: methodToCall
625    stmfd   sp!, {r0-r3}                @ preserve r0-r3
626    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
627    mov     r1, r0
628    mov     r0, rSELF
629    bl      dvmReportInvoke             @ (self, method)
630    ldmfd   sp!, {r0-r3}                @ restore r0-r3
631    b       1b
632
633.LinvokeNative:
634    @ Prep for the native call
635    @ r0=methodToCall, r1=newFp, r10=newSaveArea
636    ldrh    lr, [rSELF, #offThread_subMode]
637    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
638    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
639    str     r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top
640    mov     r2, r0                      @ r2<- methodToCall
641    mov     r0, r1                      @ r0<- newFp (points to args)
642    add     r1, rSELF, #offThread_retval  @ r1<- &retval
643    mov     r3, rSELF                   @ arg3<- self
644
645#ifdef ASSIST_DEBUGGER
646    /* insert fake function header to help gdb find the stack frame */
647    b       .Lskip
648    .type   dalvik_mterp, %function
649dalvik_mterp:
650    .fnstart
651    MTERP_ENTRY1
652    MTERP_ENTRY2
653.Lskip:
654#endif
655
656    cmp     lr, #0                      @ any special SubModes active?
657    bne     11f                         @ go handle them if so
658    ldr     ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
659    blx     ip
6607:
661
662    @ native return; r10=newSaveArea
663    @ equivalent to dvmPopJniLocals
664    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top
665    ldr     r1, [rSELF, #offThread_exception] @ check for exception
666    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
667    cmp     r1, #0                      @ null?
668    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
669    bne     common_exceptionThrown      @ no, handle exception
670
671    FETCH_ADVANCE_INST(3)               @ advance rPC, load rINST
672    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
673    GOTO_OPCODE(ip)                     @ jump to next instruction
674
67511:
676    @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes
677    stmfd   sp!, {r0-r3}                @ save all but subModes
678    mov     r0, r2                      @ r0<- methodToCall
679    mov     r1, rSELF
680    mov     r2, rFP
681    bl      dvmReportPreNativeInvoke    @ (methodToCall, self, fp)
682    ldmfd   sp, {r0-r3}                 @ refresh.  NOTE: no sp autoincrement
683
684    @ Call the native method
685    ldr     ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
686    blx     ip
687
688    @ Restore the pre-call arguments
689    ldmfd   sp!, {r0-r3}                @ r2<- methodToCall (others unneeded)
690
691    @ Finish up any post-invoke subMode requirements
692    mov     r0, r2                      @ r0<- methodToCall
693    mov     r1, rSELF
694    mov     r2, rFP
695    bl      dvmReportPostNativeInvoke   @ (methodToCall, self, fp)
696    b       7b                          @ resume
697
698.LstackOverflow:    @ r0=methodToCall
699    mov     r1, r0                      @ r1<- methodToCall
700    mov     r0, rSELF                   @ r0<- self
701    bl      dvmHandleStackOverflow
702    b       common_exceptionThrown
703#ifdef ASSIST_DEBUGGER
704    .fnend
705    .size   dalvik_mterp, .-dalvik_mterp
706#endif
707
708
709    /*
710     * Common code for method invocation, calling through "glue code".
711     *
712     * TODO: now that we have range and non-range invoke handlers, this
713     *       needs to be split into two.  Maybe just create entry points
714     *       that set r9 and jump here?
715     *
716     * On entry:
717     *  r0 is "Method* methodToCall", the method we're trying to call
718     *  r9 is "bool methodCallRange", indicating if this is a /range variant
719     */
720     .if    0
721.LinvokeOld:
722    sub     sp, sp, #8                  @ space for args + pad
723    FETCH(ip, 2)                        @ ip<- FEDC or CCCC
724    mov     r2, r0                      @ A2<- methodToCall
725    mov     r0, rSELF                   @ A0<- self
726    SAVE_PC_FP_TO_SELF()                @ export state to "self"
727    mov     r1, r9                      @ A1<- methodCallRange
728    mov     r3, rINST, lsr #8           @ A3<- AA
729    str     ip, [sp, #0]                @ A4<- ip
730    bl      dvmMterp_invokeMethod       @ call the C invokeMethod
731    add     sp, sp, #8                  @ remove arg area
732    b       common_resumeAfterGlueCall  @ continue to next instruction
733    .endif
734
735
736
737/*
738 * Common code for handling a return instruction.
739 *
740 * This does not return.
741 */
742common_returnFromMethod:
743.LreturnNew:
744    ldrh    lr, [rSELF, #offThread_subMode]
745    SAVEAREA_FROM_FP(r0, rFP)
746    ldr     r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
747    cmp     lr, #0                      @ any special subMode handling needed?
748    bne     19f
74914:
750    ldr     rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
751    ldr     r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
752                                        @ r2<- method we're returning to
753    cmp     r2, #0                      @ is this a break frame?
754#if defined(WORKAROUND_CORTEX_A9_745320)
755    /* Don't use conditional loads if the HW defect exists */
756    beq     15f
757    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
75815:
759#else
760    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
761#endif
762    beq     common_gotoBail             @ break frame, bail out completely
763
764    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
765    PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
766    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
767    ldr     r1, [r10, #offClassObject_pDvmDex]   @ r1<- method->clazz->pDvmDex
768    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
769#if defined(WITH_JIT)
770    ldr     r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr
771    mov     rPC, r9                     @ publish new rPC
772    str     r1, [rSELF, #offThread_methodClassDex]
773    str     r10, [rSELF, #offThread_inJitCodeCache]  @ may return to JIT'ed land
774    cmp     r10, #0                      @ caller is compiled code
775    blxne   r10
776    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
777    GOTO_OPCODE(ip)                     @ jump to next instruction
778#else
779    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
780    mov     rPC, r9                     @ publish new rPC
781    str     r1, [rSELF, #offThread_methodClassDex]
782    GOTO_OPCODE(ip)                     @ jump to next instruction
783#endif
784
78519:
786    @ Handle special actions
787    @ On entry, r0: StackSaveArea
788    ldr     r1, [r0, #offStackSaveArea_prevFrame]  @ r2<- prevFP
789    str     rPC, [rSELF, #offThread_pc] @ update interpSave.pc
790    str     r1, [rSELF, #offThread_curFrame]   @ update interpSave.curFrame
791    mov     r0, rSELF
792    bl      dvmReportReturn             @ (self)
793    SAVEAREA_FROM_FP(r0, rFP)           @ restore StackSaveArea
794    b       14b                         @ continue
795
796    /*
797     * Return handling, calls through "glue code".
798     */
799     .if    0
800.LreturnOld:
801    SAVE_PC_FP_TO_SELF()                @ export state
802    mov     r0, rSELF                   @ arg to function
803    bl      dvmMterp_returnFromMethod
804    b       common_resumeAfterGlueCall
805    .endif
806
807
808/*
809 * Somebody has thrown an exception.  Handle it.
810 *
811 * If the exception processing code returns to us (instead of falling
812 * out of the interpreter), continue with whatever the next instruction
813 * now happens to be.
814 *
815 * This does not return.
816 */
817     .global dvmMterpCommonExceptionThrown
818dvmMterpCommonExceptionThrown:
819common_exceptionThrown:
820.LexceptionNew:
821
822    EXPORT_PC()
823
824    mov     r0, rSELF
825    bl      dvmCheckSuspendPending
826
827    ldr     r9, [rSELF, #offThread_exception] @ r9<- self->exception
828    mov     r1, rSELF                   @ r1<- self
829    mov     r0, r9                      @ r0<- exception
830    bl      dvmAddTrackedAlloc          @ don't let the exception be GCed
831    ldrh    r2, [rSELF, #offThread_subMode]  @ get subMode flags
832    mov     r3, #0                      @ r3<- NULL
833    str     r3, [rSELF, #offThread_exception] @ self->exception = NULL
834
835    @ Special subMode?
836    cmp     r2, #0                      @ any special subMode handling needed?
837    bne     7f                          @ go if so
8388:
839    /* set up args and a local for "&fp" */
840    /* (str sp, [sp, #-4]!  would be perfect here, but is discouraged) */
841    str     rFP, [sp, #-4]!             @ *--sp = fp
842    mov     ip, sp                      @ ip<- &fp
843    mov     r3, #0                      @ r3<- false
844    str     ip, [sp, #-4]!              @ *--sp = &fp
845    ldr     r1, [rSELF, #offThread_method] @ r1<- self->method
846    mov     r0, rSELF                   @ r0<- self
847    ldr     r1, [r1, #offMethod_insns]  @ r1<- method->insns
848    ldrh    lr, [rSELF, #offThread_subMode]  @ lr<- subMode flags
849    mov     r2, r9                      @ r2<- exception
850    sub     r1, rPC, r1                 @ r1<- pc - method->insns
851    mov     r1, r1, asr #1              @ r1<- offset in code units
852
853    /* call, r0 gets catchRelPc (a code-unit offset) */
854    bl      dvmFindCatchBlock           @ call(self, relPc, exc, scan?, &fp)
855
856    /* fix earlier stack overflow if necessary; may trash rFP */
857    ldrb    r1, [rSELF, #offThread_stackOverflowed]
858    cmp     r1, #0                      @ did we overflow earlier?
859    beq     1f                          @ no, skip ahead
860    mov     rFP, r0                     @ save relPc result in rFP
861    mov     r0, rSELF                   @ r0<- self
862    mov     r1, r9                      @ r1<- exception
863    bl      dvmCleanupStackOverflow     @ call(self)
864    mov     r0, rFP                     @ restore result
8651:
866
867    /* update frame pointer and check result from dvmFindCatchBlock */
868    ldr     rFP, [sp, #4]               @ retrieve the updated rFP
869    cmp     r0, #0                      @ is catchRelPc < 0?
870    add     sp, sp, #8                  @ restore stack
871    bmi     .LnotCaughtLocally
872
873    /* adjust locals to match self->interpSave.curFrame and updated PC */
874    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
875    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
876    str     r1, [rSELF, #offThread_method]  @ self->method = new method
877    ldr     r2, [r1, #offMethod_clazz]      @ r2<- method->clazz
878    ldr     r3, [r1, #offMethod_insns]      @ r3<- method->insns
879    ldr     r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
880    add     rPC, r3, r0, asl #1             @ rPC<- method->insns + catchRelPc
881    str     r2, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
882
883    /* release the tracked alloc on the exception */
884    mov     r0, r9                      @ r0<- exception
885    mov     r1, rSELF                   @ r1<- self
886    bl      dvmReleaseTrackedAlloc      @ release the exception
887
888    /* restore the exception if the handler wants it */
889    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
890    FETCH_INST()                        @ load rINST from rPC
891    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
892    cmp     ip, #OP_MOVE_EXCEPTION      @ is it "move-exception"?
893    streq   r9, [rSELF, #offThread_exception] @ yes, restore the exception
894    GOTO_OPCODE(ip)                     @ jump to next instruction
895
896    @ Manage debugger bookkeeping
8977:
898    str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
899    str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
900    mov     r0, rSELF                       @ arg0<- self
901    mov     r1, r9                          @ arg1<- exception
902    bl      dvmReportExceptionThrow         @ (self, exception)
903    b       8b                              @ resume with normal handling
904
905.LnotCaughtLocally: @ r9=exception
906    /* fix stack overflow if necessary */
907    ldrb    r1, [rSELF, #offThread_stackOverflowed]
908    cmp     r1, #0                      @ did we overflow earlier?
909    movne   r0, rSELF                   @ if yes: r0<- self
910    movne   r1, r9                      @ if yes: r1<- exception
911    blne    dvmCleanupStackOverflow     @ if yes: call(self)
912
913    @ may want to show "not caught locally" debug messages here
914#if DVM_SHOW_EXCEPTION >= 2
915    /* call __android_log_print(prio, tag, format, ...) */
916    /* "Exception %s from %s:%d not caught locally" */
917    @ dvmLineNumFromPC(method, pc - method->insns)
918    ldr     r0, [rSELF, #offThread_method]
919    ldr     r1, [r0, #offMethod_insns]
920    sub     r1, rPC, r1
921    asr     r1, r1, #1
922    bl      dvmLineNumFromPC
923    str     r0, [sp, #-4]!
924    @ dvmGetMethodSourceFile(method)
925    ldr     r0, [rSELF, #offThread_method]
926    bl      dvmGetMethodSourceFile
927    str     r0, [sp, #-4]!
928    @ exception->clazz->descriptor
929    ldr     r3, [r9, #offObject_clazz]
930    ldr     r3, [r3, #offClassObject_descriptor]
931    @
932    ldr     r2, strExceptionNotCaughtLocally
9330:  add     r2, pc
934    ldr     r1, strLogTag
9351:  add     r1, pc
936    mov     r0, #3                      @ LOG_DEBUG
937    bl      __android_log_print
938#endif
939    str     r9, [rSELF, #offThread_exception] @ restore exception
940    mov     r0, r9                      @ r0<- exception
941    mov     r1, rSELF                   @ r1<- self
942    bl      dvmReleaseTrackedAlloc      @ release the exception
943    b       common_gotoBail             @ bail out
944
945strExceptionNotCaughtLocally:
946    .word   PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
947strLogTag:
948    .word   PCREL_REF(.LstrLogTag,1b)
949
950    /*
951     * Exception handling, calls through "glue code".
952     */
953    .if     0
954.LexceptionOld:
955    SAVE_PC_FP_TO_SELF()                @ export state
956    mov     r0, rSELF                   @ arg to function
957    bl      dvmMterp_exceptionThrown
958    b       common_resumeAfterGlueCall
959    .endif
960
961#if defined(WITH_JIT)
962    /*
963     * If the JIT is actively building a trace we need to make sure
964     * that the field is fully resolved before including the current
965     * instruction.
966     *
967     * On entry:
968     *     r10: &dvmDex->pResFields[field]
969     *     r0:  field pointer (must preserve)
970     */
971common_verifyField:
972    ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
973    ands    r3, #kSubModeJitTraceBuild
974    bxeq    lr                          @ Not building trace, continue
975    ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
976    cmp     r1, #0                      @ resolution complete?
977    bxne    lr                          @ yes, continue
978    stmfd   sp!, {r0-r2,lr}             @ save regs
979    mov     r0, rSELF
980    mov     r1, rPC
981    bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
982    ldmfd   sp!, {r0-r2, lr}
983    bx      lr                          @ return
984#endif
985
986/*
987 * After returning from a "glued" function, pull out the updated
988 * values and start executing at the next instruction.
989 */
990common_resumeAfterGlueCall:
991    LOAD_PC_FP_FROM_SELF()              @ pull rPC and rFP out of thread
992    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
993    FETCH_INST()                        @ load rINST from rPC
994    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
995    GOTO_OPCODE(ip)                     @ jump to next instruction
996
997/*
998 * Invalid array index. Note that our calling convention is strange; we use r1
999 * and r3 because those just happen to be the registers all our callers are
1000 * using. We move r3 before calling the C function, but r1 happens to match.
1001 * r1: index
1002 * r3: size
1003 */
1004common_errArrayIndex:
1005    EXPORT_PC()
1006    mov     r0, r3
1007    bl      dvmThrowArrayIndexOutOfBoundsException
1008    b       common_exceptionThrown
1009
1010/*
1011 * Integer divide or mod by zero.
1012 */
1013common_errDivideByZero:
1014    EXPORT_PC()
1015    ldr     r0, strDivideByZero
10160:  add     r0, pc
1017    bl      dvmThrowArithmeticException
1018    b       common_exceptionThrown
1019
1020strDivideByZero:
1021    .word   PCREL_REF(.LstrDivideByZero,0b)
1022
1023/*
1024 * Attempt to allocate an array with a negative size.
1025 * On entry: length in r1
1026 */
1027common_errNegativeArraySize:
1028    EXPORT_PC()
1029    mov     r0, r1                                @ arg0 <- len
1030    bl      dvmThrowNegativeArraySizeException    @ (len)
1031    b       common_exceptionThrown
1032
1033/*
1034 * Invocation of a non-existent method.
1035 * On entry: method name in r1
1036 */
1037common_errNoSuchMethod:
1038    EXPORT_PC()
1039    mov     r0, r1
1040    bl      dvmThrowNoSuchMethodError
1041    b       common_exceptionThrown
1042
1043/*
1044 * We encountered a null object when we weren't expecting one.  We
1045 * export the PC, throw a NullPointerException, and goto the exception
1046 * processing code.
1047 */
1048common_errNullObject:
1049    EXPORT_PC()
1050    mov     r0, #0
1051    bl      dvmThrowNullPointerException
1052    b       common_exceptionThrown
1053
1054/*
1055 * For debugging, cause an immediate fault.  The source address will
1056 * be in lr (use a bl instruction to jump here).
1057 */
1058common_abort:
1059    ldr     pc, .LdeadFood
1060.LdeadFood:
1061    .word   0xdeadf00d
1062
1063/*
1064 * Spit out a "we were here", preserving all registers.  (The attempt
1065 * to save ip won't work, but we need to save an even number of
1066 * registers for EABI 64-bit stack alignment.)
1067 */
1068    .macro  SQUEAK num
1069common_squeak\num:
1070    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1071    ldr     r0, strSqueak\num
10720:  add     r0, pc
1073    mov     r1, #\num
1074    bl      printf
1075    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1076    bx      lr
1077
1078strSqueak\num:
1079    .word   PCREL_REF(.LstrSqueak,0b)
1080    .endm
1081
1082    SQUEAK  0
1083    SQUEAK  1
1084    SQUEAK  2
1085    SQUEAK  3
1086    SQUEAK  4
1087    SQUEAK  5
1088
1089/*
1090 * Spit out the number in r0, preserving registers.
1091 */
1092common_printNum:
1093    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1094    mov     r1, r0
1095    ldr     r0, strSqueak
10960:  add     r0, pc
1097    bl      printf
1098    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1099    bx      lr
1100
1101strSqueak:
1102    .word   PCREL_REF(.LstrSqueak,0b)
1103
1104/*
1105 * Print a newline, preserving registers.
1106 */
1107common_printNewline:
1108    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1109    ldr     r0, strNewline
11100:  add     r0, pc
1111    bl      printf
1112    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1113    bx      lr
1114
1115strNewline:
1116    .word   PCREL_REF(.LstrNewline,0b)
1117
1118    /*
1119     * Print the 32-bit quantity in r0 as a hex value, preserving registers.
1120     */
1121common_printHex:
1122    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1123    mov     r1, r0
1124    ldr     r0, strPrintHex
11250:  add     r0, pc
1126    bl      printf
1127    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1128    bx      lr
1129
1130strPrintHex:
1131    .word   PCREL_REF(.LstrPrintHex,0b)
1132
1133/*
1134 * Print the 64-bit quantity in r0-r1, preserving registers.
1135 */
1136common_printLong:
1137    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1138    mov     r3, r1
1139    mov     r2, r0
1140    ldr     r0, strPrintLong
11410:  add     r0, pc
1142    bl      printf
1143    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1144    bx      lr
1145
1146strPrintLong:
1147    .word   PCREL_REF(.LstrPrintLong,0b)
1148
1149/*
1150 * Print full method info.  Pass the Method* in r0.  Preserves regs.
1151 */
1152common_printMethod:
1153    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1154    bl      dvmMterpPrintMethod
1155    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1156    bx      lr
1157
1158/*
1159 * Call a C helper function that dumps regs and possibly some
1160 * additional info.  Requires the C function to be compiled in.
1161 */
1162    .if     0
1163common_dumpRegs:
1164    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1165    bl      dvmMterpDumpArmRegs
1166    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1167    bx      lr
1168    .endif
1169
1170#if 0
1171/*
1172 * Experiment on VFP mode.
1173 *
1174 * uint32_t setFPSCR(uint32_t val, uint32_t mask)
1175 *
1176 * Updates the bits specified by "mask", setting them to the values in "val".
1177 */
1178setFPSCR:
1179    and     r0, r0, r1                  @ make sure no stray bits are set
1180    fmrx    r2, fpscr                   @ get VFP reg
1181    mvn     r1, r1                      @ bit-invert mask
1182    and     r2, r2, r1                  @ clear masked bits
1183    orr     r2, r2, r0                  @ set specified bits
1184    fmxr    fpscr, r2                   @ set VFP reg
1185    mov     r0, r2                      @ return new value
1186    bx      lr
1187
1188    .align  2
1189    .global dvmConfigureFP
1190    .type   dvmConfigureFP, %function
1191dvmConfigureFP:
1192    stmfd   sp!, {ip, lr}
1193    /* 0x03000000 sets DN/FZ */
1194    /* 0x00009f00 clears the six exception enable flags */
1195    bl      common_squeak0
1196    mov     r0, #0x03000000             @ r0<- 0x03000000
1197    add     r1, r0, #0x9f00             @ r1<- 0x03009f00
1198    bl      setFPSCR
1199    ldmfd   sp!, {ip, pc}
1200#endif
1201
1202
1203
1204/*
1205 * Zero-terminated ASCII string data.
1206 *
1207 * On ARM we have two choices: do like gcc does, and LDR from a .word
1208 * with the address, or use an ADR pseudo-op to get the address
1209 * directly.  ADR saves 4 bytes and an indirection, but it's using a
1210 * PC-relative addressing mode and hence has a limited range, which
1211 * makes it not work well with mergeable string sections.
1212 */
1213    .section .rodata.str1.4,"aMS",%progbits,1
1214
1215.LstrBadEntryPoint:
1216    .asciz  "Bad entry point %d\n"
1217.LstrFilledNewArrayNotImpl:
1218    .asciz  "filled-new-array only implemented for objects and 'int'"
1219.LstrDivideByZero:
1220    .asciz  "divide by zero"
1221.LstrLogTag:
1222    .asciz  "mterp"
1223.LstrExceptionNotCaughtLocally:
1224    .asciz  "Exception %s from %s:%d not caught locally\n"
1225
1226.LstrNewline:
1227    .asciz  "\n"
1228.LstrSqueak:
1229    .asciz  "<%d>"
1230.LstrPrintHex:
1231    .asciz  "<%#x>"
1232.LstrPrintLong:
1233    .asciz  "<%lld>"
1234