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    mov     r2, r9                      @ r2<- exception
849    sub     r1, rPC, r1                 @ r1<- pc - method->insns
850    mov     r1, r1, asr #1              @ r1<- offset in code units
851
852    /* call, r0 gets catchRelPc (a code-unit offset) */
853    bl      dvmFindCatchBlock           @ call(self, relPc, exc, scan?, &fp)
854
855    /* fix earlier stack overflow if necessary; may trash rFP */
856    ldrb    r1, [rSELF, #offThread_stackOverflowed]
857    cmp     r1, #0                      @ did we overflow earlier?
858    beq     1f                          @ no, skip ahead
859    mov     rFP, r0                     @ save relPc result in rFP
860    mov     r0, rSELF                   @ r0<- self
861    mov     r1, r9                      @ r1<- exception
862    bl      dvmCleanupStackOverflow     @ call(self)
863    mov     r0, rFP                     @ restore result
8641:
865
866    /* update frame pointer and check result from dvmFindCatchBlock */
867    ldr     rFP, [sp, #4]               @ retrieve the updated rFP
868    cmp     r0, #0                      @ is catchRelPc < 0?
869    add     sp, sp, #8                  @ restore stack
870    bmi     .LnotCaughtLocally
871
872    /* adjust locals to match self->interpSave.curFrame and updated PC */
873    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- new save area
874    ldr     r1, [r1, #offStackSaveArea_method] @ r1<- new method
875    str     r1, [rSELF, #offThread_method]  @ self->method = new method
876    ldr     r2, [r1, #offMethod_clazz]      @ r2<- method->clazz
877    ldr     r3, [r1, #offMethod_insns]      @ r3<- method->insns
878    ldr     r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
879    add     rPC, r3, r0, asl #1             @ rPC<- method->insns + catchRelPc
880    str     r2, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth...
881
882    /* release the tracked alloc on the exception */
883    mov     r0, r9                      @ r0<- exception
884    mov     r1, rSELF                   @ r1<- self
885    bl      dvmReleaseTrackedAlloc      @ release the exception
886
887    /* restore the exception if the handler wants it */
888    ldr    rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh rIBASE
889    FETCH_INST()                        @ load rINST from rPC
890    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
891    cmp     ip, #OP_MOVE_EXCEPTION      @ is it "move-exception"?
892    streq   r9, [rSELF, #offThread_exception] @ yes, restore the exception
893    GOTO_OPCODE(ip)                     @ jump to next instruction
894
895    @ Manage debugger bookkeeping
8967:
897    str     rPC, [rSELF, #offThread_pc]     @ update interpSave.pc
898    str     rFP, [rSELF, #offThread_curFrame]     @ update interpSave.curFrame
899    mov     r0, rSELF                       @ arg0<- self
900    mov     r1, r9                          @ arg1<- exception
901    bl      dvmReportExceptionThrow         @ (self, exception)
902    b       8b                              @ resume with normal handling
903
904.LnotCaughtLocally: @ r9=exception
905    /* fix stack overflow if necessary */
906    ldrb    r1, [rSELF, #offThread_stackOverflowed]
907    cmp     r1, #0                      @ did we overflow earlier?
908    movne   r0, rSELF                   @ if yes: r0<- self
909    movne   r1, r9                      @ if yes: r1<- exception
910    blne    dvmCleanupStackOverflow     @ if yes: call(self)
911
912    @ may want to show "not caught locally" debug messages here
913#if DVM_SHOW_EXCEPTION >= 2
914    /* call __android_log_print(prio, tag, format, ...) */
915    /* "Exception %s from %s:%d not caught locally" */
916    @ dvmLineNumFromPC(method, pc - method->insns)
917    ldr     r0, [rSELF, #offThread_method]
918    ldr     r1, [r0, #offMethod_insns]
919    sub     r1, rPC, r1
920    asr     r1, r1, #1
921    bl      dvmLineNumFromPC
922    str     r0, [sp, #-4]!
923    @ dvmGetMethodSourceFile(method)
924    ldr     r0, [rSELF, #offThread_method]
925    bl      dvmGetMethodSourceFile
926    str     r0, [sp, #-4]!
927    @ exception->clazz->descriptor
928    ldr     r3, [r9, #offObject_clazz]
929    ldr     r3, [r3, #offClassObject_descriptor]
930    @
931    ldr     r2, strExceptionNotCaughtLocally
9320:  add     r2, pc
933    ldr     r1, strLogTag
9341:  add     r1, pc
935    mov     r0, #3                      @ LOG_DEBUG
936    bl      __android_log_print
937#endif
938    str     r9, [rSELF, #offThread_exception] @ restore exception
939    mov     r0, r9                      @ r0<- exception
940    mov     r1, rSELF                   @ r1<- self
941    bl      dvmReleaseTrackedAlloc      @ release the exception
942    b       common_gotoBail             @ bail out
943
944strExceptionNotCaughtLocally:
945    .word   PCREL_REF(.LstrExceptionNotCaughtLocally,0b)
946strLogTag:
947    .word   PCREL_REF(.LstrLogTag,1b)
948
949    /*
950     * Exception handling, calls through "glue code".
951     */
952    .if     0
953.LexceptionOld:
954    SAVE_PC_FP_TO_SELF()                @ export state
955    mov     r0, rSELF                   @ arg to function
956    bl      dvmMterp_exceptionThrown
957    b       common_resumeAfterGlueCall
958    .endif
959
960#if defined(WITH_JIT)
961    /*
962     * If the JIT is actively building a trace we need to make sure
963     * that the field is fully resolved before including the current
964     * instruction.
965     *
966     * On entry:
967     *     r10: &dvmDex->pResFields[field]
968     *     r0:  field pointer (must preserve)
969     */
970common_verifyField:
971    ldrh    r3, [rSELF, #offThread_subMode]  @ r3 <- submode byte
972    ands    r3, #kSubModeJitTraceBuild
973    bxeq    lr                          @ Not building trace, continue
974    ldr     r1, [r10]                   @ r1<- reload resolved StaticField ptr
975    cmp     r1, #0                      @ resolution complete?
976    bxne    lr                          @ yes, continue
977    stmfd   sp!, {r0-r2,lr}             @ save regs
978    mov     r0, rSELF
979    mov     r1, rPC
980    bl      dvmJitEndTraceSelect        @ (self,pc) end trace before this inst
981    ldmfd   sp!, {r0-r2, lr}
982    bx      lr                          @ return
983#endif
984
985/*
986 * After returning from a "glued" function, pull out the updated
987 * values and start executing at the next instruction.
988 */
989common_resumeAfterGlueCall:
990    LOAD_PC_FP_FROM_SELF()              @ pull rPC and rFP out of thread
991    ldr     rIBASE, [rSELF, #offThread_curHandlerTable]  @ refresh
992    FETCH_INST()                        @ load rINST from rPC
993    GET_INST_OPCODE(ip)                 @ extract opcode from rINST
994    GOTO_OPCODE(ip)                     @ jump to next instruction
995
996/*
997 * Invalid array index. Note that our calling convention is strange; we use r1
998 * and r3 because those just happen to be the registers all our callers are
999 * using. We move r3 before calling the C function, but r1 happens to match.
1000 * r1: index
1001 * r3: size
1002 */
1003common_errArrayIndex:
1004    EXPORT_PC()
1005    mov     r0, r3
1006    bl      dvmThrowArrayIndexOutOfBoundsException
1007    b       common_exceptionThrown
1008
1009/*
1010 * Integer divide or mod by zero.
1011 */
1012common_errDivideByZero:
1013    EXPORT_PC()
1014    ldr     r0, strDivideByZero
10150:  add     r0, pc
1016    bl      dvmThrowArithmeticException
1017    b       common_exceptionThrown
1018
1019strDivideByZero:
1020    .word   PCREL_REF(.LstrDivideByZero,0b)
1021
1022/*
1023 * Attempt to allocate an array with a negative size.
1024 * On entry: length in r1
1025 */
1026common_errNegativeArraySize:
1027    EXPORT_PC()
1028    mov     r0, r1                                @ arg0 <- len
1029    bl      dvmThrowNegativeArraySizeException    @ (len)
1030    b       common_exceptionThrown
1031
1032/*
1033 * Invocation of a non-existent method.
1034 * On entry: method name in r1
1035 */
1036common_errNoSuchMethod:
1037    EXPORT_PC()
1038    mov     r0, r1
1039    bl      dvmThrowNoSuchMethodError
1040    b       common_exceptionThrown
1041
1042/*
1043 * We encountered a null object when we weren't expecting one.  We
1044 * export the PC, throw a NullPointerException, and goto the exception
1045 * processing code.
1046 */
1047common_errNullObject:
1048    EXPORT_PC()
1049    mov     r0, #0
1050    bl      dvmThrowNullPointerException
1051    b       common_exceptionThrown
1052
1053/*
1054 * For debugging, cause an immediate fault.  The source address will
1055 * be in lr (use a bl instruction to jump here).
1056 */
1057common_abort:
1058    ldr     pc, .LdeadFood
1059.LdeadFood:
1060    .word   0xdeadf00d
1061
1062/*
1063 * Spit out a "we were here", preserving all registers.  (The attempt
1064 * to save ip won't work, but we need to save an even number of
1065 * registers for EABI 64-bit stack alignment.)
1066 */
1067    .macro  SQUEAK num
1068common_squeak\num:
1069    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1070    ldr     r0, strSqueak\num
10710:  add     r0, pc
1072    mov     r1, #\num
1073    bl      printf
1074    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1075    bx      lr
1076
1077strSqueak\num:
1078    .word   PCREL_REF(.LstrSqueak,0b)
1079    .endm
1080
1081    SQUEAK  0
1082    SQUEAK  1
1083    SQUEAK  2
1084    SQUEAK  3
1085    SQUEAK  4
1086    SQUEAK  5
1087
1088/*
1089 * Spit out the number in r0, preserving registers.
1090 */
1091common_printNum:
1092    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1093    mov     r1, r0
1094    ldr     r0, strSqueak
10950:  add     r0, pc
1096    bl      printf
1097    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1098    bx      lr
1099
1100strSqueak:
1101    .word   PCREL_REF(.LstrSqueak,0b)
1102
1103/*
1104 * Print a newline, preserving registers.
1105 */
1106common_printNewline:
1107    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1108    ldr     r0, strNewline
11090:  add     r0, pc
1110    bl      printf
1111    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1112    bx      lr
1113
1114strNewline:
1115    .word   PCREL_REF(.LstrNewline,0b)
1116
1117    /*
1118     * Print the 32-bit quantity in r0 as a hex value, preserving registers.
1119     */
1120common_printHex:
1121    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1122    mov     r1, r0
1123    ldr     r0, strPrintHex
11240:  add     r0, pc
1125    bl      printf
1126    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1127    bx      lr
1128
1129strPrintHex:
1130    .word   PCREL_REF(.LstrPrintHex,0b)
1131
1132/*
1133 * Print the 64-bit quantity in r0-r1, preserving registers.
1134 */
1135common_printLong:
1136    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1137    mov     r3, r1
1138    mov     r2, r0
1139    ldr     r0, strPrintLong
11400:  add     r0, pc
1141    bl      printf
1142    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1143    bx      lr
1144
1145strPrintLong:
1146    .word   PCREL_REF(.LstrPrintLong,0b)
1147
1148/*
1149 * Print full method info.  Pass the Method* in r0.  Preserves regs.
1150 */
1151common_printMethod:
1152    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1153    bl      dvmMterpPrintMethod
1154    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1155    bx      lr
1156
1157/*
1158 * Call a C helper function that dumps regs and possibly some
1159 * additional info.  Requires the C function to be compiled in.
1160 */
1161    .if     0
1162common_dumpRegs:
1163    stmfd   sp!, {r0, r1, r2, r3, ip, lr}
1164    bl      dvmMterpDumpArmRegs
1165    ldmfd   sp!, {r0, r1, r2, r3, ip, lr}
1166    bx      lr
1167    .endif
1168
1169#if 0
1170/*
1171 * Experiment on VFP mode.
1172 *
1173 * uint32_t setFPSCR(uint32_t val, uint32_t mask)
1174 *
1175 * Updates the bits specified by "mask", setting them to the values in "val".
1176 */
1177setFPSCR:
1178    and     r0, r0, r1                  @ make sure no stray bits are set
1179    fmrx    r2, fpscr                   @ get VFP reg
1180    mvn     r1, r1                      @ bit-invert mask
1181    and     r2, r2, r1                  @ clear masked bits
1182    orr     r2, r2, r0                  @ set specified bits
1183    fmxr    fpscr, r2                   @ set VFP reg
1184    mov     r0, r2                      @ return new value
1185    bx      lr
1186
1187    .align  2
1188    .global dvmConfigureFP
1189    .type   dvmConfigureFP, %function
1190dvmConfigureFP:
1191    stmfd   sp!, {ip, lr}
1192    /* 0x03000000 sets DN/FZ */
1193    /* 0x00009f00 clears the six exception enable flags */
1194    bl      common_squeak0
1195    mov     r0, #0x03000000             @ r0<- 0x03000000
1196    add     r1, r0, #0x9f00             @ r1<- 0x03009f00
1197    bl      setFPSCR
1198    ldmfd   sp!, {ip, pc}
1199#endif
1200
1201
1202
1203/*
1204 * Zero-terminated ASCII string data.
1205 *
1206 * On ARM we have two choices: do like gcc does, and LDR from a .word
1207 * with the address, or use an ADR pseudo-op to get the address
1208 * directly.  ADR saves 4 bytes and an indirection, but it's using a
1209 * PC-relative addressing mode and hence has a limited range, which
1210 * makes it not work well with mergeable string sections.
1211 */
1212    .section .rodata.str1.4,"aMS",%progbits,1
1213
1214.LstrBadEntryPoint:
1215    .asciz  "Bad entry point %d\n"
1216.LstrFilledNewArrayNotImpl:
1217    .asciz  "filled-new-array only implemented for objects and 'int'"
1218.LstrDivideByZero:
1219    .asciz  "divide by zero"
1220.LstrLogTag:
1221    .asciz  "mterp"
1222.LstrExceptionNotCaughtLocally:
1223    .asciz  "Exception %s from %s:%d not caught locally\n"
1224
1225.LstrNewline:
1226    .asciz  "\n"
1227.LstrSqueak:
1228    .asciz  "<%d>"
1229.LstrPrintHex:
1230    .asciz  "<%#x>"
1231.LstrPrintLong:
1232    .asciz  "<%lld>"
1233