1/*
2 * This file was generated automatically by gen-template.py for 'armv7-a-neon'.
3 *
4 * --> DO NOT EDIT <--
5 */
6
7/* File: armv5te/header.S */
8/*
9 * Copyright (C) 2008 The Android Open Source Project
10 *
11 * Licensed under the Apache License, Version 2.0 (the "License");
12 * you may not use this file except in compliance with the License.
13 * You may obtain a copy of the License at
14 *
15 *      http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24#if defined(WITH_JIT)
25
26/*
27 * ARMv5 definitions and declarations.
28 */
29
30/*
31ARM EABI general notes:
32
33r0-r3 hold first 4 args to a method; they are not preserved across method calls
34r4-r8 are available for general use
35r9 is given special treatment in some situations, but not for us
36r10 (sl) seems to be generally available
37r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
38r12 (ip) is scratch -- not preserved across method calls
39r13 (sp) should be managed carefully in case a signal arrives
40r14 (lr) must be preserved
41r15 (pc) can be tinkered with directly
42
43r0 holds returns of <= 4 bytes
44r0-r1 hold returns of 8 bytes, low word in r0
45
46Callee must save/restore r4+ (except r12) if it modifies them.
47
48Stack is "full descending".  Only the arguments that don't fit in the first 4
49registers are placed on the stack.  "sp" points at the first stacked argument
50(i.e. the 5th arg).
51
52VFP: single-precision results in s0, double-precision results in d0.
53
54In the EABI, "sp" must be 64-bit aligned on entry to a function, and any
5564-bit quantities (long long, double) must be 64-bit aligned.
56*/
57
58/*
59JIT and ARM notes:
60
61The following registers have fixed assignments:
62
63  reg nick      purpose
64  r5  rFP       interpreted frame pointer, used for accessing locals and args
65  r6  rSELF     thread pointer
66
67The following registers have fixed assignments in mterp but are scratch
68registers in compiled code
69
70  reg nick      purpose
71  r4  rPC       interpreted program counter, used for fetching instructions
72  r7  rINST     first 16-bit code unit of current instruction
73  r8  rIBASE    interpreted instruction base pointer, used for computed goto
74
75Macros are provided for common operations.  Each macro MUST emit only
76one instruction to make instruction-counting easier.  They MUST NOT alter
77unspecified registers or condition codes.
78*/
79
80/* single-purpose registers, given names for clarity */
81#define rPC     r4
82#define rFP     r5
83#define rSELF   r6
84#define rINST   r7
85#define rIBASE  r8
86
87/*
88 * Given a frame pointer, find the stack save area.
89 *
90 * In C this is "((StackSaveArea*)(_fp) -1)".
91 */
92#define SAVEAREA_FROM_FP(_reg, _fpreg) \
93    sub     _reg, _fpreg, #sizeofStackSaveArea
94
95#define EXPORT_PC() \
96    str     rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
97
98/*
99 * This is a #include, not a %include, because we want the C pre-processor
100 * to expand the macros into assembler assignment statements.
101 */
102#include "../../../mterp/common/asm-constants.h"
103
104/* File: armv5te-vfp/platform.S */
105/*
106 * ===========================================================================
107 *  CPU-version-specific defines and utility
108 * ===========================================================================
109 */
110
111
112    .global dvmCompilerTemplateStart
113    .type   dvmCompilerTemplateStart, %function
114    .section .data.rel.ro
115
116dvmCompilerTemplateStart:
117
118/* ------------------------------ */
119    .balign 4
120    .global dvmCompiler_TEMPLATE_CMP_LONG
121dvmCompiler_TEMPLATE_CMP_LONG:
122/* File: armv5te/TEMPLATE_CMP_LONG.S */
123    /*
124     * Compare two 64-bit values.  Puts 0, 1, or -1 into the destination
125     * register based on the results of the comparison.
126     *
127     * We load the full values with LDM, but in practice many values could
128     * be resolved by only looking at the high word.  This could be made
129     * faster or slower by splitting the LDM into a pair of LDRs.
130     *
131     * If we just wanted to set condition flags, we could do this:
132     *  subs    ip, r0, r2
133     *  sbcs    ip, r1, r3
134     *  subeqs  ip, r0, r2
135     * Leaving { <0, 0, >0 } in ip.  However, we have to set it to a specific
136     * integer value, which we can do with 2 conditional mov/mvn instructions
137     * (set 1, set -1; if they're equal we already have 0 in ip), giving
138     * us a constant 5-cycle path plus a branch at the end to the
139     * instruction epilogue code.  The multi-compare approach below needs
140     * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
141     * in the worst case (the 64-bit values are equal).
142     */
143    /* cmp-long vAA, vBB, vCC */
144    cmp     r1, r3                      @ compare (vBB+1, vCC+1)
145    blt     .LTEMPLATE_CMP_LONG_less            @ signed compare on high part
146    bgt     .LTEMPLATE_CMP_LONG_greater
147    subs    r0, r0, r2                  @ r0<- r0 - r2
148    bxeq     lr
149    bhi     .LTEMPLATE_CMP_LONG_greater         @ unsigned compare on low part
150.LTEMPLATE_CMP_LONG_less:
151    mvn     r0, #0                      @ r0<- -1
152    bx      lr
153.LTEMPLATE_CMP_LONG_greater:
154    mov     r0, #1                      @ r0<- 1
155    bx      lr
156
157/* ------------------------------ */
158    .balign 4
159    .global dvmCompiler_TEMPLATE_RETURN
160dvmCompiler_TEMPLATE_RETURN:
161/* File: armv5te/TEMPLATE_RETURN.S */
162    /*
163     * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
164     * If the stored value in returnAddr
165     * is non-zero, the caller is compiled by the JIT thus return to the
166     * address in the code cache following the invoke instruction. Otherwise
167     * return to the special dvmJitToInterpNoChain entry point.
168     */
169#if defined(TEMPLATE_INLINE_PROFILING)
170    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
171    mov     r0, r6
172    @ r0=rSELF
173    ldr     ip, .LdvmFastMethodTraceExit
174    blx     ip
175    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
176#endif
177    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
178    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
179    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
180    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
181    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
182#if !defined(WITH_SELF_VERIFICATION)
183    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
184#else
185    mov     r9, #0                      @ disable chaining
186#endif
187                                        @ r2<- method we're returning to
188    cmp     r2, #0                      @ break frame?
189#if !defined(WITH_SELF_VERIFICATION)
190    beq     1f                          @ bail to interpreter
191#else
192    blxeq   lr                          @ punt to interpreter and compare state
193#endif
194    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
195    mov     rFP, r10                    @ publish new FP
196    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
197
198    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
199    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
200    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
201    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
202    str     r0, [rSELF, #offThread_methodClassDex]
203    cmp     r8, #0                      @ check the break flags
204    movne   r9, #0                      @ clear the chaining cell address
205    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
206    cmp     r9, #0                      @ chaining cell exists?
207    blxne   r9                          @ jump to the chaining cell
208#if defined(WITH_JIT_TUNING)
209    mov     r0, #kCallsiteInterpreted
210#endif
211    mov     pc, r1                      @ callsite is interpreted
2121:
213    mov     r0, #0
214    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
215    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
216    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
217    mov     r0, rSELF                   @ Expecting rSELF in r0
218    blx     r2                          @ exit the interpreter
219
220/* ------------------------------ */
221    .balign 4
222    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT
223dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
224/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S */
225    /*
226     * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
227     * into rPC then jump to dvmJitToInterpNoChain to dispatch the
228     * runtime-resolved callee.
229     */
230    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
231    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
232    ldrh    r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
233    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
234    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
235    add     r3, r1, #1  @ Thumb addr is odd
236    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
237    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
238    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
239    sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
240    cmp     r10, r9                     @ bottom < interpStackEnd?
241    bxlo    lr                          @ return to raise stack overflow excep.
242    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
243    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
244    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
245    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
246    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
247    ldr     rPC, [r0, #offMethod_insns]     @ rPC<- methodToCall->insns
248
249
250    @ set up newSaveArea
251    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
252    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
253    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
254    cmp     r8, #0                      @ breakFlags != 0
255    bxne    lr                          @ bail to the interpreter
256    tst     r10, #ACC_NATIVE
257#if !defined(WITH_SELF_VERIFICATION)
258    bne     .LinvokeNative
259#else
260    bxne    lr                          @ bail to the interpreter
261#endif
262
263    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
264    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
265
266    @ Update "thread" values for the new method
267    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
268    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
269    mov     rFP, r1                         @ fp = newFp
270    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
271#if defined(TEMPLATE_INLINE_PROFILING)
272    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
273    mov     r1, r6
274    @ r0=methodToCall, r1=rSELF
275    ldr     ip, .LdvmFastMethodTraceEnter
276    blx     ip
277    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
278#endif
279
280    @ Start executing the callee
281#if defined(WITH_JIT_TUNING)
282    mov     r0, #kInlineCacheMiss
283#endif
284    bx      r10                         @ dvmJitToInterpTraceSelectNoChain
285
286/* ------------------------------ */
287    .balign 4
288    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN
289dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
290/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S */
291    /*
292     * For monomorphic callsite, setup the Dalvik frame and return to the
293     * Thumb code through the link register to transfer control to the callee
294     * method through a dedicated chaining cell.
295     */
296    @ r0 = methodToCall, r1 = returnCell, r2 = methodToCall->outsSize
297    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
298    @ methodToCall is guaranteed to be non-native
299.LinvokeChain:
300    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
301    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
302    add     r3, r1, #1  @ Thumb addr is odd
303    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
304    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
305    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
306    add     r12, lr, #2                 @ setup the punt-to-interp address
307    sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
308    cmp     r10, r9                     @ bottom < interpStackEnd?
309    bxlo    r12                         @ return to raise stack overflow excep.
310    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
311    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
312    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
313    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
314
315    @ set up newSaveArea
316    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
317    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
318    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
319    cmp     r8, #0                      @ breakFlags != 0
320    bxne    r12                         @ bail to the interpreter
321
322    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
323
324    @ Update "thread" values for the new method
325    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
326    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
327    mov     rFP, r1                         @ fp = newFp
328    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
329#if defined(TEMPLATE_INLINE_PROFILING)
330    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
331    mov     r1, r6
332    @ r0=methodToCall, r1=rSELF
333    ldr     ip, .LdvmFastMethodTraceEnter
334    blx     ip
335    ldmfd   sp!, {r0-r2,lr}             @ restore registers
336#endif
337
338    bx      lr                              @ return to the callee-chaining cell
339
340/* ------------------------------ */
341    .balign 4
342    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
343dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN:
344/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
345    /*
346     * For polymorphic callsite, check whether the cached class pointer matches
347     * the current one. If so setup the Dalvik frame and return to the
348     * Thumb code through the link register to transfer control to the callee
349     * method through a dedicated chaining cell.
350     *
351     * The predicted chaining cell is declared in ArmLIR.h with the
352     * following layout:
353     *
354     *  typedef struct PredictedChainingCell {
355     *      u4 branch;
356     *      const ClassObject *clazz;
357     *      const Method *method;
358     *      u4 counter;
359     *  } PredictedChainingCell;
360     *
361     * Upon returning to the callsite:
362     *    - lr  : to branch to the chaining cell
363     *    - lr+2: to punt to the interpreter
364     *    - lr+4: to fully resolve the callee and may rechain.
365     *            r3 <- class
366     *            r9 <- counter
367     */
368    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
369    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
370    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
371    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
372    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
373    cmp     r3, r8          @ predicted class == actual class?
374#if defined(WITH_JIT_TUNING)
375    ldr     r7, .LdvmICHitCount
376#if defined(WORKAROUND_CORTEX_A9_745320)
377    /* Don't use conditional loads if the HW defect exists */
378    bne     101f
379    ldr     r10, [r7, #0]
380101:
381#else
382    ldreq   r10, [r7, #0]
383#endif
384    add     r10, r10, #1
385    streq   r10, [r7, #0]
386#endif
387    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
388    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
389    beq     .LinvokeChain   @ predicted chain is valid
390    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
391    cmp     r8, #0          @ initialized class or not
392    moveq   r1, #0
393    subne   r1, r9, #1      @ count--
394    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
395    add     lr, lr, #4      @ return to fully-resolve landing pad
396    /*
397     * r1 <- count
398     * r2 <- &predictedChainCell
399     * r3 <- this->class
400     * r4 <- dPC
401     * r7 <- this->class->vtable
402     */
403    bx      lr
404
405/* ------------------------------ */
406    .balign 4
407    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE
408dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
409/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
410    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
411    @ r7 = methodToCall->registersSize
412    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
413    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
414    add     r3, r1, #1  @ Thumb addr is odd
415    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
416    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
417    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
418    cmp     r10, r9                     @ bottom < interpStackEnd?
419    bxlo    lr                          @ return to raise stack overflow excep.
420    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
421    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
422    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
423
424    @ set up newSaveArea
425    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
426    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
427    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
428    cmp     r8, #0                      @ breakFlags != 0
429    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
430#if !defined(WITH_SELF_VERIFICATION)
431    bxne    lr                          @ bail to the interpreter
432#else
433    bx      lr                          @ bail to interpreter unconditionally
434#endif
435
436    @ go ahead and transfer control to the native code
437    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
438    mov     r2, #0
439    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
440    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
441    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
442                                        @ newFp->localRefCookie=top
443    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
444
445    mov     r2, r0                        @ arg2<- methodToCall
446    mov     r0, r1                        @ arg0<- newFP
447    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
448    mov     r3, rSELF                     @ arg3<- self
449#if defined(TEMPLATE_INLINE_PROFILING)
450    @ r2=methodToCall, r6=rSELF
451    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
452    stmfd   sp!, {r0-r3}                @ preserve r0-r3
453    mov     r0, r2
454    mov     r1, r6
455    @ r0=JNIMethod, r1=rSELF
456    ldr     ip, .LdvmFastMethodTraceEnter
457    blx     ip
458    ldmfd   sp!, {r0-r3}                @ restore r0-r3
459#endif
460
461    blx     r8                          @ off to the native code
462
463#if defined(TEMPLATE_INLINE_PROFILING)
464    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
465    @ r0=JNIMethod, r1=rSELF
466    ldr     ip, .LdvmFastNativeMethodTraceExit
467    blx     ip
468#endif
469    @ native return; r10=newSaveArea
470    @ equivalent to dvmPopJniLocals
471    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
472    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
473    ldr     r1, [rSELF, #offThread_exception] @ check for exception
474    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
475    cmp     r1, #0                      @ null?
476    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
477    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
478
479    @ r0 = dalvikCallsitePC
480    bne     .LhandleException           @ no, handle exception
481
482    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
483    cmp     r2, #0                      @ return chaining cell still exists?
484    bxne    r2                          @ yes - go ahead
485
486    @ continue executing the next instruction through the interpreter
487    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
488    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
489#if defined(WITH_JIT_TUNING)
490    mov     r0, #kCallsiteInterpreted
491#endif
492    mov     pc, r1
493
494/* ------------------------------ */
495    .balign 4
496    .global dvmCompiler_TEMPLATE_MUL_LONG
497dvmCompiler_TEMPLATE_MUL_LONG:
498/* File: armv5te/TEMPLATE_MUL_LONG.S */
499    /*
500     * Signed 64-bit integer multiply.
501     *
502     * For JIT: op1 in r0/r1, op2 in r2/r3, return in r0/r1
503     *
504     * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
505     *        WX
506     *      x YZ
507     *  --------
508     *     ZW ZX
509     *  YW YX
510     *
511     * The low word of the result holds ZX, the high word holds
512     * (ZW+YX) + (the high overflow from ZX).  YW doesn't matter because
513     * it doesn't fit in the low 64 bits.
514     *
515     * Unlike most ARM math operations, multiply instructions have
516     * restrictions on using the same register more than once (Rd and Rm
517     * cannot be the same).
518     */
519    /* mul-long vAA, vBB, vCC */
520    mul     ip, r2, r1                  @  ip<- ZxW
521    umull   r9, r10, r2, r0             @  r9/r10 <- ZxX
522    mla     r2, r0, r3, ip              @  r2<- YxX + (ZxW)
523    mov     r0, r9
524    add     r1, r2, r10                 @  r1<- r10 + low(ZxW + (YxX))
525    bx      lr
526
527/* ------------------------------ */
528    .balign 4
529    .global dvmCompiler_TEMPLATE_SHL_LONG
530dvmCompiler_TEMPLATE_SHL_LONG:
531/* File: armv5te/TEMPLATE_SHL_LONG.S */
532    /*
533     * Long integer shift.  This is different from the generic 32/64-bit
534     * binary operations because vAA/vBB are 64-bit but vCC (the shift
535     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
536     * 6 bits.
537     */
538    /* shl-long vAA, vBB, vCC */
539    and     r2, r2, #63                 @ r2<- r2 & 0x3f
540    mov     r1, r1, asl r2              @  r1<- r1 << r2
541    rsb     r3, r2, #32                 @  r3<- 32 - r2
542    orr     r1, r1, r0, lsr r3          @  r1<- r1 | (r0 << (32-r2))
543    subs    ip, r2, #32                 @  ip<- r2 - 32
544    movpl   r1, r0, asl ip              @  if r2 >= 32, r1<- r0 << (r2-32)
545    mov     r0, r0, asl r2              @  r0<- r0 << r2
546    bx      lr
547
548/* ------------------------------ */
549    .balign 4
550    .global dvmCompiler_TEMPLATE_SHR_LONG
551dvmCompiler_TEMPLATE_SHR_LONG:
552/* File: armv5te/TEMPLATE_SHR_LONG.S */
553    /*
554     * Long integer shift.  This is different from the generic 32/64-bit
555     * binary operations because vAA/vBB are 64-bit but vCC (the shift
556     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
557     * 6 bits.
558     */
559    /* shr-long vAA, vBB, vCC */
560    and     r2, r2, #63                 @ r0<- r0 & 0x3f
561    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
562    rsb     r3, r2, #32                 @  r3<- 32 - r2
563    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
564    subs    ip, r2, #32                 @  ip<- r2 - 32
565    movpl   r0, r1, asr ip              @  if r2 >= 32, r0<-r1 >> (r2-32)
566    mov     r1, r1, asr r2              @  r1<- r1 >> r2
567    bx      lr
568
569/* ------------------------------ */
570    .balign 4
571    .global dvmCompiler_TEMPLATE_USHR_LONG
572dvmCompiler_TEMPLATE_USHR_LONG:
573/* File: armv5te/TEMPLATE_USHR_LONG.S */
574    /*
575     * Long integer shift.  This is different from the generic 32/64-bit
576     * binary operations because vAA/vBB are 64-bit but vCC (the shift
577     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
578     * 6 bits.
579     */
580    /* ushr-long vAA, vBB, vCC */
581    and     r2, r2, #63                 @ r0<- r0 & 0x3f
582    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
583    rsb     r3, r2, #32                 @  r3<- 32 - r2
584    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
585    subs    ip, r2, #32                 @  ip<- r2 - 32
586    movpl   r0, r1, lsr ip              @  if r2 >= 32, r0<-r1 >>> (r2-32)
587    mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
588    bx      lr
589
590/* ------------------------------ */
591    .balign 4
592    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
593dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
594/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
595    /*
596     * Throw an exception from JIT'ed code.
597     * On entry:
598     *    r0    Dalvik PC that raises the exception
599     */
600    b       .LhandleException
601
602/* ------------------------------ */
603    .balign 4
604    .global dvmCompiler_TEMPLATE_MEM_OP_DECODE
605dvmCompiler_TEMPLATE_MEM_OP_DECODE:
606/* File: armv5te-vfp/TEMPLATE_MEM_OP_DECODE.S */
607#if defined(WITH_SELF_VERIFICATION)
608    /*
609     * This handler encapsulates heap memory ops for selfVerification mode.
610     *
611     * The call to the handler is inserted prior to a heap memory operation.
612     * This handler then calls a function to decode the memory op, and process
613     * it accordingly. Afterwards, the handler changes the return address to
614     * skip the memory op so it never gets executed.
615     */
616    vpush   {d0-d15}                    @ save out all fp registers
617    push    {r0-r12,lr}                 @ save out all registers
618    ldr     r2, .LdvmSelfVerificationMemOpDecode @ defined in footer.S
619    mov     r0, lr                      @ arg0 <- link register
620    mov     r1, sp                      @ arg1 <- stack pointer
621    blx     r2                          @ decode and handle the mem op
622    pop     {r0-r12,lr}                 @ restore all registers
623    vpop    {d0-d15}                    @ restore all fp registers
624    bx      lr                          @ return to compiled code
625#endif
626
627/* ------------------------------ */
628    .balign 4
629    .global dvmCompiler_TEMPLATE_STRING_COMPARETO
630dvmCompiler_TEMPLATE_STRING_COMPARETO:
631/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */
632    /*
633     * String's compareTo.
634     *
635     * Requires r0/r1 to have been previously checked for null.  Will
636     * return negative if this's string is < comp, 0 if they are the
637     * same and positive if >.
638     *
639     * IMPORTANT NOTE:
640     *
641     * This code relies on hard-coded offsets for string objects, and must be
642     * kept in sync with definitions in UtfString.h.  See asm-constants.h
643     *
644     * On entry:
645     *    r0:   this object pointer
646     *    r1:   comp object pointer
647     *
648     */
649
650    mov    r2, r0         @ this to r2, opening up r0 for return value
651    subs   r0, r2, r1     @ Same?
652    bxeq   lr
653
654    ldr    r4, [r2, #STRING_FIELDOFF_OFFSET]
655    ldr    r9, [r1, #STRING_FIELDOFF_OFFSET]
656    ldr    r7, [r2, #STRING_FIELDOFF_COUNT]
657    ldr    r10, [r1, #STRING_FIELDOFF_COUNT]
658    ldr    r2, [r2, #STRING_FIELDOFF_VALUE]
659    ldr    r1, [r1, #STRING_FIELDOFF_VALUE]
660
661    /*
662     * At this point, we have:
663     *    value:  r2/r1
664     *    offset: r4/r9
665     *    count:  r7/r10
666     * We're going to compute
667     *    r11 <- countDiff
668     *    r10 <- minCount
669     */
670     subs  r11, r7, r10
671     movls r10, r7
672
673     /* Now, build pointers to the string data */
674     add   r2, r2, r4, lsl #1
675     add   r1, r1, r9, lsl #1
676     /*
677      * Note: data pointers point to previous element so we can use pre-index
678      * mode with base writeback.
679      */
680     add   r2, #16-2   @ offset to contents[-1]
681     add   r1, #16-2   @ offset to contents[-1]
682
683     /*
684      * At this point we have:
685      *   r2: *this string data
686      *   r1: *comp string data
687      *   r10: iteration count for comparison
688      *   r11: value to return if the first part of the string is equal
689      *   r0: reserved for result
690      *   r3, r4, r7, r8, r9, r12 available for loading string data
691      */
692
693    subs  r10, #2
694    blt   do_remainder2
695
696      /*
697       * Unroll the first two checks so we can quickly catch early mismatch
698       * on long strings (but preserve incoming alignment)
699       */
700
701    ldrh  r3, [r2, #2]!
702    ldrh  r4, [r1, #2]!
703    ldrh  r7, [r2, #2]!
704    ldrh  r8, [r1, #2]!
705    subs  r0, r3, r4
706    subeqs  r0, r7, r8
707    bxne  lr
708    cmp   r10, #28
709    bgt   do_memcmp16
710    subs  r10, #3
711    blt   do_remainder
712
713loopback_triple:
714    ldrh  r3, [r2, #2]!
715    ldrh  r4, [r1, #2]!
716    ldrh  r7, [r2, #2]!
717    ldrh  r8, [r1, #2]!
718    ldrh  r9, [r2, #2]!
719    ldrh  r12,[r1, #2]!
720    subs  r0, r3, r4
721    subeqs  r0, r7, r8
722    subeqs  r0, r9, r12
723    bxne  lr
724    subs  r10, #3
725    bge   loopback_triple
726
727do_remainder:
728    adds  r10, #3
729    beq   returnDiff
730
731loopback_single:
732    ldrh  r3, [r2, #2]!
733    ldrh  r4, [r1, #2]!
734    subs  r0, r3, r4
735    bxne  lr
736    subs  r10, #1
737    bne     loopback_single
738
739returnDiff:
740    mov   r0, r11
741    bx    lr
742
743do_remainder2:
744    adds  r10, #2
745    bne   loopback_single
746    mov   r0, r11
747    bx    lr
748
749    /* Long string case */
750do_memcmp16:
751    mov   r4, lr
752    ldr   lr, .Lmemcmp16
753    mov   r7, r11
754    add   r0, r2, #2
755    add   r1, r1, #2
756    mov   r2, r10
757    blx   lr
758    cmp   r0, #0
759    bxne  r4
760    mov   r0, r7
761    bx    r4
762
763.Lmemcmp16:
764    .word __memcmp16
765
766/* ------------------------------ */
767    .balign 4
768    .global dvmCompiler_TEMPLATE_STRING_INDEXOF
769dvmCompiler_TEMPLATE_STRING_INDEXOF:
770/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */
771    /*
772     * String's indexOf.
773     *
774     * Requires r0 to have been previously checked for null.  Will
775     * return index of match of r1 in r0.
776     *
777     * IMPORTANT NOTE:
778     *
779     * This code relies on hard-coded offsets for string objects, and must be
780     * kept in sync wth definitions in UtfString.h  See asm-constants.h
781     *
782     * On entry:
783     *    r0:   string object pointer
784     *    r1:   char to match
785     *    r2:   Starting offset in string data
786     */
787
788    ldr    r3, [r0, #STRING_FIELDOFF_VALUE]
789    ldr    r7, [r0, #STRING_FIELDOFF_OFFSET]
790    ldr    r8, [r0, #STRING_FIELDOFF_COUNT]
791
792
793    /*
794     * At this point, we have:
795     *    r1: char to match
796     *    r2: starting offset
797     *    r3: object pointer (final result -> r0)
798     *    r7: offset
799     *    r8: string length
800     */
801
802     /* Build pointer to start of string data */
803     add   r3, #16
804     add   r0, r3, r7, lsl #1
805
806     /* Save a copy of starting data in r7 */
807     mov   r7, r0
808
809     /* Clamp start to [0..count] */
810     cmp   r2, #0
811     movlt r2, #0
812     cmp   r2, r8
813     movgt r2, r8
814
815     /* Build pointer to start of data to compare and pre-bias */
816     add   r0, r0, r2, lsl #1
817     sub   r0, #2
818
819     /* Compute iteration count */
820     sub   r8, r2
821
822     /*
823      * At this point we have:
824      *   r0: start of data to test
825      *   r1: chat to compare
826      *   r8: iteration count
827      *   r7: original start of string
828      *   r3, r4, r9, r10, r11, r12 available for loading string data
829      */
830
831    subs  r8, #4
832    blt   indexof_remainder
833
834indexof_loop4:
835    ldrh  r3, [r0, #2]!
836    ldrh  r4, [r0, #2]!
837    ldrh  r10, [r0, #2]!
838    ldrh  r11, [r0, #2]!
839    cmp   r3, r1
840    beq   match_0
841    cmp   r4, r1
842    beq   match_1
843    cmp   r10, r1
844    beq   match_2
845    cmp   r11, r1
846    beq   match_3
847    subs  r8, #4
848    bge   indexof_loop4
849
850indexof_remainder:
851    adds    r8, #4
852    beq     indexof_nomatch
853
854indexof_loop1:
855    ldrh  r3, [r0, #2]!
856    cmp   r3, r1
857    beq   match_3
858    subs  r8, #1
859    bne   indexof_loop1
860
861indexof_nomatch:
862    mov   r0, #-1
863    bx    lr
864
865match_0:
866    sub   r0, #6
867    sub   r0, r7
868    asr   r0, r0, #1
869    bx    lr
870match_1:
871    sub   r0, #4
872    sub   r0, r7
873    asr   r0, r0, #1
874    bx    lr
875match_2:
876    sub   r0, #2
877    sub   r0, r7
878    asr   r0, r0, #1
879    bx    lr
880match_3:
881    sub   r0, r7
882    asr   r0, r0, #1
883    bx    lr
884
885/* ------------------------------ */
886    .balign 4
887    .global dvmCompiler_TEMPLATE_INTERPRET
888dvmCompiler_TEMPLATE_INTERPRET:
889/* File: armv5te/TEMPLATE_INTERPRET.S */
890    /*
891     * This handler transfers control to the interpeter without performing
892     * any lookups.  It may be called either as part of a normal chaining
893     * operation, or from the transition code in header.S.  We distinquish
894     * the two cases by looking at the link register.  If called from a
895     * translation chain, it will point to the chaining Dalvik PC -3.
896     * On entry:
897     *    lr - if NULL:
898     *        r1 - the Dalvik PC to begin interpretation.
899     *    else
900     *        [lr, #3] contains Dalvik PC to begin interpretation
901     *    rSELF - pointer to thread
902     *    rFP - Dalvik frame pointer
903     */
904    cmp     lr, #0
905#if defined(WORKAROUND_CORTEX_A9_745320)
906    /* Don't use conditional loads if the HW defect exists */
907    beq     101f
908    ldr     r1,[lr, #3]
909101:
910#else
911    ldrne   r1,[lr, #3]
912#endif
913    ldr     r2, .LinterpPunt
914    mov     r0, r1                       @ set Dalvik PC
915    bx      r2
916    @ doesn't return
917
918.LinterpPunt:
919    .word   dvmJitToInterpPunt
920
921/* ------------------------------ */
922    .balign 4
923    .global dvmCompiler_TEMPLATE_MONITOR_ENTER
924dvmCompiler_TEMPLATE_MONITOR_ENTER:
925/* File: armv5te/TEMPLATE_MONITOR_ENTER.S */
926    /*
927     * Call out to the runtime to lock an object.  Because this thread
928     * may have been suspended in THREAD_MONITOR state and the Jit's
929     * translation cache subsequently cleared, we cannot return directly.
930     * Instead, unconditionally transition to the interpreter to resume.
931     *
932     * On entry:
933     *    r0 - self pointer
934     *    r1 - the object (which has already been null-checked by the caller
935     *    r4 - the Dalvik PC of the following instruction.
936     */
937    ldr     r2, .LdvmLockObject
938    mov     r3, #0                       @ Record that we're not returning
939    str     r3, [r0, #offThread_inJitCodeCache]
940    blx     r2                           @ dvmLockObject(self, obj)
941    ldr     r2, .LdvmJitToInterpNoChain
942    @ Bail to interpreter - no chain [note - r4 still contains rPC]
943#if defined(WITH_JIT_TUNING)
944    mov     r0, #kHeavyweightMonitor
945#endif
946    bx      r2
947
948/* ------------------------------ */
949    .balign 4
950    .global dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG
951dvmCompiler_TEMPLATE_MONITOR_ENTER_DEBUG:
952/* File: armv5te/TEMPLATE_MONITOR_ENTER_DEBUG.S */
953    /*
954     * To support deadlock prediction, this version of MONITOR_ENTER
955     * will always call the heavyweight dvmLockObject, check for an
956     * exception and then bail out to the interpreter.
957     *
958     * On entry:
959     *    r0 - self pointer
960     *    r1 - the object (which has already been null-checked by the caller
961     *    r4 - the Dalvik PC of the following instruction.
962     *
963     */
964    ldr     r2, .LdvmLockObject
965    mov     r3, #0                       @ Record that we're not returning
966    str     r3, [r0, #offThread_inJitCodeCache]
967    blx     r2             @ dvmLockObject(self, obj)
968    @ test for exception
969    ldr     r1, [rSELF, #offThread_exception]
970    cmp     r1, #0
971    beq     1f
972    ldr     r2, .LhandleException
973    sub     r0, r4, #2     @ roll dPC back to this monitor instruction
974    bx      r2
9751:
976    @ Bail to interpreter - no chain [note - r4 still contains rPC]
977#if defined(WITH_JIT_TUNING)
978    mov     r0, #kHeavyweightMonitor
979#endif
980    ldr     pc, .LdvmJitToInterpNoChain
981
982/* ------------------------------ */
983    .balign 4
984    .global dvmCompiler_TEMPLATE_PERIODIC_PROFILING
985dvmCompiler_TEMPLATE_PERIODIC_PROFILING:
986/* File: armv5te/TEMPLATE_PERIODIC_PROFILING.S */
987    /*
988     * Increment profile counter for this trace, and decrement
989     * sample counter.  If sample counter goes below zero, turn
990     * off profiling.
991     *
992     * On entry
993     * (lr-11) is address of pointer to counter.  Note: the counter
994     *    actually exists 10 bytes before the return target, but because
995     *    we are arriving from thumb mode, lr will have its low bit set.
996     */
997     ldr    r0, [lr,#-11]
998     ldr    r1, [rSELF, #offThread_pProfileCountdown]
999     ldr    r2, [r0]                    @ get counter
1000     ldr    r3, [r1]                    @ get countdown timer
1001     add    r2, #1
1002     subs   r2, #1
1003     blt    .LTEMPLATE_PERIODIC_PROFILING_disable_profiling
1004     str    r2, [r0]
1005     str    r3, [r1]
1006     bx     lr
1007
1008.LTEMPLATE_PERIODIC_PROFILING_disable_profiling:
1009     mov    r4, lr                     @ preserve lr
1010     ldr    r0, .LdvmJitTraceProfilingOff
1011     blx    r0
1012     bx     r4
1013
1014/* ------------------------------ */
1015    .balign 4
1016    .global dvmCompiler_TEMPLATE_RETURN_PROF
1017dvmCompiler_TEMPLATE_RETURN_PROF:
1018/* File: armv5te/TEMPLATE_RETURN_PROF.S */
1019#define TEMPLATE_INLINE_PROFILING
1020/* File: armv5te/TEMPLATE_RETURN.S */
1021    /*
1022     * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
1023     * If the stored value in returnAddr
1024     * is non-zero, the caller is compiled by the JIT thus return to the
1025     * address in the code cache following the invoke instruction. Otherwise
1026     * return to the special dvmJitToInterpNoChain entry point.
1027     */
1028#if defined(TEMPLATE_INLINE_PROFILING)
1029    stmfd   sp!, {r0-r2,lr}             @ preserve live registers
1030    mov     r0, r6
1031    @ r0=rSELF
1032    ldr     ip, .LdvmFastMethodTraceExit
1033    blx     ip
1034    ldmfd   sp!, {r0-r2,lr}             @ restore live registers
1035#endif
1036    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
1037    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
1038    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
1039    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
1040    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
1041#if !defined(WITH_SELF_VERIFICATION)
1042    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
1043#else
1044    mov     r9, #0                      @ disable chaining
1045#endif
1046                                        @ r2<- method we're returning to
1047    cmp     r2, #0                      @ break frame?
1048#if !defined(WITH_SELF_VERIFICATION)
1049    beq     1f                          @ bail to interpreter
1050#else
1051    blxeq   lr                          @ punt to interpreter and compare state
1052#endif
1053    ldr     r1, .LdvmJitToInterpNoChainNoProfile @ defined in footer.S
1054    mov     rFP, r10                    @ publish new FP
1055    ldr     r10, [r2, #offMethod_clazz] @ r10<- method->clazz
1056
1057    str     r2, [rSELF, #offThread_method]@ self->method = newSave->method
1058    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
1059    str     rFP, [rSELF, #offThread_curFrame] @ curFrame = fp
1060    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
1061    str     r0, [rSELF, #offThread_methodClassDex]
1062    cmp     r8, #0                      @ check the break flags
1063    movne   r9, #0                      @ clear the chaining cell address
1064    str     r9, [rSELF, #offThread_inJitCodeCache] @ in code cache or not
1065    cmp     r9, #0                      @ chaining cell exists?
1066    blxne   r9                          @ jump to the chaining cell
1067#if defined(WITH_JIT_TUNING)
1068    mov     r0, #kCallsiteInterpreted
1069#endif
1070    mov     pc, r1                      @ callsite is interpreted
10711:
1072    mov     r0, #0
1073    str     r0, [rSELF, #offThread_inJitCodeCache] @ reset inJitCodeCache
1074    stmia   rSELF, {rPC, rFP}           @ SAVE_PC_FP_TO_SELF()
1075    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
1076    mov     r0, rSELF                   @ Expecting rSELF in r0
1077    blx     r2                          @ exit the interpreter
1078
1079#undef TEMPLATE_INLINE_PROFILING
1080
1081/* ------------------------------ */
1082    .balign 4
1083    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF
1084dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT_PROF:
1085/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT_PROF.S */
1086#define TEMPLATE_INLINE_PROFILING
1087/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S */
1088    /*
1089     * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
1090     * into rPC then jump to dvmJitToInterpNoChain to dispatch the
1091     * runtime-resolved callee.
1092     */
1093    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
1094    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
1095    ldrh    r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
1096    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
1097    ldrb    r8, [rSELF, #offThread_breakFlags] @ r8<- breakFlags
1098    add     r3, r1, #1  @ Thumb addr is odd
1099    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
1100    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
1101    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
1102    sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
1103    cmp     r10, r9                     @ bottom < interpStackEnd?
1104    bxlo    lr                          @ return to raise stack overflow excep.
1105    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
1106    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
1107    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
1108    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
1109    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
1110    ldr     rPC, [r0, #offMethod_insns]     @ rPC<- methodToCall->insns
1111
1112
1113    @ set up newSaveArea
1114    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
1115    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
1116    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
1117    cmp     r8, #0                      @ breakFlags != 0
1118    bxne    lr                          @ bail to the interpreter
1119    tst     r10, #ACC_NATIVE
1120#if !defined(WITH_SELF_VERIFICATION)
1121    bne     .LinvokeNative
1122#else
1123    bxne    lr                          @ bail to the interpreter
1124#endif
1125
1126    ldr     r10, .LdvmJitToInterpTraceSelectNoChain
1127    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
1128
1129    @ Update "thread" values for the new method
1130    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
1131    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
1132    mov     rFP, r1                         @ fp = newFp
1133    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
1134#if defined(TEMPLATE_INLINE_PROFILING)
1135    stmfd   sp!, {r0-r3}                    @ preserve r0-r3
1136    mov     r1, r6
1137    @ r0=methodToCall, r1=rSELF
1138    ldr     ip, .LdvmFastMethodTraceEnter
1139    blx     ip
1140    ldmfd   sp!, {r0-r3}                    @ restore r0-r3
1141#endif
1142
1143    @ Start executing the callee
1144#if defined(WITH_JIT_TUNING)
1145    mov     r0, #kInlineCacheMiss
1146#endif
1147    bx      r10                         @ dvmJitToInterpTraceSelectNoChain
1148
1149#undef TEMPLATE_INLINE_PROFILING
1150
1151/* ------------------------------ */
1152    .balign 4
1153    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF
1154dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN_PROF:
1155/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN_PROF.S */
1156#define TEMPLATE_INLINE_PROFILING
1157/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S */
1158    /*
1159     * For monomorphic callsite, setup the Dalvik frame and return to the
1160     * Thumb code through the link register to transfer control to the callee
1161     * method through a dedicated chaining cell.
1162     */
1163    @ r0 = methodToCall, r1 = returnCell, r2 = methodToCall->outsSize
1164    @ rPC = dalvikCallsite, r7 = methodToCall->registersSize
1165    @ methodToCall is guaranteed to be non-native
1166.LinvokeChainProf:
1167    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
1168    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
1169    add     r3, r1, #1  @ Thumb addr is odd
1170    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
1171    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
1172    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
1173    add     r12, lr, #2                 @ setup the punt-to-interp address
1174    sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
1175    cmp     r10, r9                     @ bottom < interpStackEnd?
1176    bxlo    r12                         @ return to raise stack overflow excep.
1177    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
1178    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
1179    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
1180    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
1181
1182    @ set up newSaveArea
1183    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
1184    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
1185    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
1186    cmp     r8, #0                      @ breakFlags != 0
1187    bxne    r12                         @ bail to the interpreter
1188
1189    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
1190
1191    @ Update "thread" values for the new method
1192    str     r0, [rSELF, #offThread_method]    @ self->method = methodToCall
1193    str     r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ...
1194    mov     rFP, r1                         @ fp = newFp
1195    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = newFp
1196#if defined(TEMPLATE_INLINE_PROFILING)
1197    stmfd   sp!, {r0-r2,lr}             @ preserve clobbered live registers
1198    mov     r1, r6
1199    @ r0=methodToCall, r1=rSELF
1200    ldr     ip, .LdvmFastMethodTraceEnter
1201    blx     ip
1202    ldmfd   sp!, {r0-r2,lr}             @ restore registers
1203#endif
1204
1205    bx      lr                              @ return to the callee-chaining cell
1206
1207#undef TEMPLATE_INLINE_PROFILING
1208
1209/* ------------------------------ */
1210    .balign 4
1211    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF
1212dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF:
1213/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN_PROF.S */
1214#define TEMPLATE_INLINE_PROFILING
1215/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
1216    /*
1217     * For polymorphic callsite, check whether the cached class pointer matches
1218     * the current one. If so setup the Dalvik frame and return to the
1219     * Thumb code through the link register to transfer control to the callee
1220     * method through a dedicated chaining cell.
1221     *
1222     * The predicted chaining cell is declared in ArmLIR.h with the
1223     * following layout:
1224     *
1225     *  typedef struct PredictedChainingCell {
1226     *      u4 branch;
1227     *      const ClassObject *clazz;
1228     *      const Method *method;
1229     *      u4 counter;
1230     *  } PredictedChainingCell;
1231     *
1232     * Upon returning to the callsite:
1233     *    - lr  : to branch to the chaining cell
1234     *    - lr+2: to punt to the interpreter
1235     *    - lr+4: to fully resolve the callee and may rechain.
1236     *            r3 <- class
1237     *            r9 <- counter
1238     */
1239    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
1240    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
1241    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
1242    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
1243    ldr     r9, [rSELF, #offThread_icRechainCount] @ r1 <- shared rechainCount
1244    cmp     r3, r8          @ predicted class == actual class?
1245#if defined(WITH_JIT_TUNING)
1246    ldr     r7, .LdvmICHitCount
1247#if defined(WORKAROUND_CORTEX_A9_745320)
1248    /* Don't use conditional loads if the HW defect exists */
1249    bne     101f
1250    ldr     r10, [r7, #0]
1251101:
1252#else
1253    ldreq   r10, [r7, #0]
1254#endif
1255    add     r10, r10, #1
1256    streq   r10, [r7, #0]
1257#endif
1258    ldreqh  r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
1259    ldreqh  r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
1260    beq     .LinvokeChainProf   @ predicted chain is valid
1261    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
1262    cmp     r8, #0          @ initialized class or not
1263    moveq   r1, #0
1264    subne   r1, r9, #1      @ count--
1265    strne   r1, [rSELF, #offThread_icRechainCount]  @ write back to thread
1266    add     lr, lr, #4      @ return to fully-resolve landing pad
1267    /*
1268     * r1 <- count
1269     * r2 <- &predictedChainCell
1270     * r3 <- this->class
1271     * r4 <- dPC
1272     * r7 <- this->class->vtable
1273     */
1274    bx      lr
1275
1276#undef TEMPLATE_INLINE_PROFILING
1277
1278/* ------------------------------ */
1279    .balign 4
1280    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF
1281dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE_PROF:
1282/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE_PROF.S */
1283#define TEMPLATE_INLINE_PROFILING
1284/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
1285    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
1286    @ r7 = methodToCall->registersSize
1287    ldr     r9, [rSELF, #offThread_interpStackEnd]    @ r9<- interpStackEnd
1288    ldrb    r8, [rSELF, #offThread_breakFlags]        @ r8<- breakFlags
1289    add     r3, r1, #1  @ Thumb addr is odd
1290    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
1291    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
1292    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
1293    cmp     r10, r9                     @ bottom < interpStackEnd?
1294    bxlo    lr                          @ return to raise stack overflow excep.
1295    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
1296    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
1297    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
1298
1299    @ set up newSaveArea
1300    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
1301    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
1302    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
1303    cmp     r8, #0                      @ breakFlags != 0
1304    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
1305#if !defined(WITH_SELF_VERIFICATION)
1306    bxne    lr                          @ bail to the interpreter
1307#else
1308    bx      lr                          @ bail to interpreter unconditionally
1309#endif
1310
1311    @ go ahead and transfer control to the native code
1312    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
1313    mov     r2, #0
1314    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
1315    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in the jit code cache
1316    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
1317                                        @ newFp->localRefCookie=top
1318    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
1319
1320    mov     r2, r0                        @ arg2<- methodToCall
1321    mov     r0, r1                        @ arg0<- newFP
1322    add     r1, rSELF, #offThread_retval  @ arg1<- &retval
1323    mov     r3, rSELF                     @ arg3<- self
1324#if defined(TEMPLATE_INLINE_PROFILING)
1325    @ r2=methodToCall, r6=rSELF
1326    stmfd   sp!, {r2,r6}                @ to be consumed after JNI return
1327    stmfd   sp!, {r0-r3}                @ preserve r0-r3
1328    mov     r0, r2
1329    mov     r1, r6
1330    @ r0=JNIMethod, r1=rSELF
1331    ldr     ip, .LdvmFastMethodTraceEnter
1332    blx     ip
1333    ldmfd   sp!, {r0-r3}                @ restore r0-r3
1334#endif
1335
1336    blx     r8                          @ off to the native code
1337
1338#if defined(TEMPLATE_INLINE_PROFILING)
1339    ldmfd   sp!, {r0-r1}                @ restore r2 and r6
1340    @ r0=JNIMethod, r1=rSELF
1341    ldr     ip, .LdvmFastNativeMethodTraceExit
1342    blx     ip
1343#endif
1344    @ native return; r10=newSaveArea
1345    @ equivalent to dvmPopJniLocals
1346    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
1347    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
1348    ldr     r1, [rSELF, #offThread_exception] @ check for exception
1349    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
1350    cmp     r1, #0                      @ null?
1351    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
1352    ldr     r0, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
1353
1354    @ r0 = dalvikCallsitePC
1355    bne     .LhandleException           @ no, handle exception
1356
1357    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the mode properly
1358    cmp     r2, #0                      @ return chaining cell still exists?
1359    bxne    r2                          @ yes - go ahead
1360
1361    @ continue executing the next instruction through the interpreter
1362    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
1363    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
1364#if defined(WITH_JIT_TUNING)
1365    mov     r0, #kCallsiteInterpreted
1366#endif
1367    mov     pc, r1
1368
1369#undef TEMPLATE_INLINE_PROFILING
1370
1371    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
1372/* File: armv5te/footer.S */
1373/*
1374 * ===========================================================================
1375 *  Common subroutines and data
1376 * ===========================================================================
1377 */
1378
1379    .section .data.rel.ro
1380    .align  2
1381.LinvokeNative:
1382    @ Prep for the native call
1383    @ r1 = newFP, r0 = methodToCall
1384    mov     r2, #0
1385    ldr     r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->...
1386    str     r2, [rSELF, #offThread_inJitCodeCache] @ not in jit code cache
1387    str     r1, [rSELF, #offThread_curFrame]   @ curFrame = newFp
1388    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
1389                                        @ newFp->localRefCookie=top
1390    ldrh    lr, [rSELF, #offThread_subMode]
1391    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
1392
1393    mov     r2, r0                      @ r2<- methodToCall
1394    mov     r0, r1                      @ r0<- newFP
1395    add     r1, rSELF, #offThread_retval  @ r1<- &retval
1396    mov     r3, rSELF                   @ arg3<- self
1397    ands    lr, #kSubModeMethodTrace
1398    beq     121f                        @ hop if not profiling
1399    @ r2: methodToCall, r6: rSELF
1400    stmfd   sp!, {r2,r6}
1401    stmfd   sp!, {r0-r3}
1402    mov     r0, r2
1403    mov     r1, r6
1404    ldr     ip, .LdvmFastMethodTraceEnter
1405    blx     ip
1406    ldmfd   sp!, {r0-r3}
1407
1408    ldr     ip, [r2, #offMethod_nativeFunc]
1409    blx     ip
1410
1411    ldmfd   sp!, {r0-r1}
1412    ldr     ip, .LdvmFastNativeMethodTraceExit
1413    blx     ip
1414    b       212f
1415121:
1416    ldr     ip, [r2, #offMethod_nativeFunc]
1417    blx     ip
1418212:
1419
1420    @ native return; r10=newSaveArea
1421    @ equivalent to dvmPopJniLocals
1422    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
1423    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
1424    ldr     r1, [rSELF, #offThread_exception] @ check for exception
1425    str     rFP, [rSELF, #offThread_curFrame]  @ curFrame = fp
1426    cmp     r1, #0                      @ null?
1427    str     r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top
1428    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
1429
1430    @ r0 = dalvikCallsitePC
1431    bne     .LhandleException           @ no, handle exception
1432
1433    str     r2, [rSELF, #offThread_inJitCodeCache] @ set the new mode
1434    cmp     r2, #0                      @ return chaining cell still exists?
1435    bxne    r2                          @ yes - go ahead
1436
1437    @ continue executing the next instruction through the interpreter
1438    ldr     r1, .LdvmJitToInterpTraceSelectNoChain @ defined in footer.S
1439    add     rPC, r0, #6                 @ reconstruct new rPC (advance 6 bytes)
1440#if defined(WITH_JIT_TUNING)
1441    mov     r0, #kCallsiteInterpreted
1442#endif
1443    bx      r1
1444
1445/*
1446 * On entry:
1447 * r0  Faulting Dalvik PC
1448 */
1449.LhandleException:
1450#if defined(WITH_SELF_VERIFICATION)
1451    ldr     pc, .LdeadFood @ should not see this under self-verification mode
1452.LdeadFood:
1453    .word   0xdeadf00d
1454#endif
1455    mov     r2, #0
1456    str     r2, [rSELF, #offThread_inJitCodeCache] @ in interpreter land
1457    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
1458    ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
1459    mov     rPC, r0                 @ reload the faulting Dalvik address
1460    bx      r1                  @ branch to dvmMterpCommonExceptionThrown
1461
1462    .align  2
1463.LdvmAsmInstructionStart:
1464    .word   dvmAsmInstructionStart
1465.LdvmJitToInterpNoChainNoProfile:
1466    .word   dvmJitToInterpNoChainNoProfile
1467.LdvmJitToInterpTraceSelectNoChain:
1468    .word   dvmJitToInterpTraceSelectNoChain
1469.LdvmJitToInterpNoChain:
1470    .word   dvmJitToInterpNoChain
1471.LdvmMterpStdBail:
1472    .word   dvmMterpStdBail
1473.LdvmMterpCommonExceptionThrown:
1474    .word   dvmMterpCommonExceptionThrown
1475.LdvmLockObject:
1476    .word   dvmLockObject
1477.LdvmJitTraceProfilingOff:
1478    .word   dvmJitTraceProfilingOff
1479#if defined(WITH_JIT_TUNING)
1480.LdvmICHitCount:
1481    .word   gDvmICHitCount
1482#endif
1483#if defined(WITH_SELF_VERIFICATION)
1484.LdvmSelfVerificationMemOpDecode:
1485    .word   dvmSelfVerificationMemOpDecode
1486#endif
1487.LdvmFastMethodTraceEnter:
1488    .word   dvmFastMethodTraceEnter
1489.LdvmFastNativeMethodTraceExit:
1490    .word   dvmFastNativeMethodTraceExit
1491.LdvmFastMethodTraceExit:
1492    .word   dvmFastMethodTraceExit
1493.L__aeabi_cdcmple:
1494    .word   __aeabi_cdcmple
1495.L__aeabi_cfcmple:
1496    .word   __aeabi_cfcmple
1497
1498    .global dvmCompilerTemplateEnd
1499dvmCompilerTemplateEnd:
1500
1501#endif /* WITH_JIT */
1502
1503