CompilerTemplateAsm-armv5te.S revision ab875c79c56eacc510b09710d38a9b20f7337486
1/*
2 * This file was generated automatically by gen-template.py for 'armv5te'.
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  rGLUE     MterpGlue 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 rGLUE   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
105/* File: armv5te/platform.S */
106/*
107 * ===========================================================================
108 *  CPU-version-specific defines
109 * ===========================================================================
110 */
111
112/*
113 * Macro for "MOV LR,PC / LDR PC,xxx", which is not allowed pre-ARMv5.
114 * Jump to subroutine.
115 *
116 * May modify IP and LR.
117 */
118.macro  LDR_PC_LR source
119    mov     lr, pc
120    ldr     pc, \source
121.endm
122
123
124    .global dvmCompilerTemplateStart
125    .type   dvmCompilerTemplateStart, %function
126    .text
127
128dvmCompilerTemplateStart:
129
130/* ------------------------------ */
131    .balign 4
132    .global dvmCompiler_TEMPLATE_CMP_LONG
133dvmCompiler_TEMPLATE_CMP_LONG:
134/* File: armv5te/TEMPLATE_CMP_LONG.S */
135    /*
136     * Compare two 64-bit values.  Puts 0, 1, or -1 into the destination
137     * register based on the results of the comparison.
138     *
139     * We load the full values with LDM, but in practice many values could
140     * be resolved by only looking at the high word.  This could be made
141     * faster or slower by splitting the LDM into a pair of LDRs.
142     *
143     * If we just wanted to set condition flags, we could do this:
144     *  subs    ip, r0, r2
145     *  sbcs    ip, r1, r3
146     *  subeqs  ip, r0, r2
147     * Leaving { <0, 0, >0 } in ip.  However, we have to set it to a specific
148     * integer value, which we can do with 2 conditional mov/mvn instructions
149     * (set 1, set -1; if they're equal we already have 0 in ip), giving
150     * us a constant 5-cycle path plus a branch at the end to the
151     * instruction epilogue code.  The multi-compare approach below needs
152     * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
153     * in the worst case (the 64-bit values are equal).
154     */
155    /* cmp-long vAA, vBB, vCC */
156    cmp     r1, r3                      @ compare (vBB+1, vCC+1)
157    blt     .LTEMPLATE_CMP_LONG_less            @ signed compare on high part
158    bgt     .LTEMPLATE_CMP_LONG_greater
159    subs    r0, r0, r2                  @ r0<- r0 - r2
160    bxeq     lr
161    bhi     .LTEMPLATE_CMP_LONG_greater         @ unsigned compare on low part
162.LTEMPLATE_CMP_LONG_less:
163    mvn     r0, #0                      @ r0<- -1
164    bx      lr
165.LTEMPLATE_CMP_LONG_greater:
166    mov     r0, #1                      @ r0<- 1
167    bx      lr
168
169
170/* ------------------------------ */
171    .balign 4
172    .global dvmCompiler_TEMPLATE_RETURN
173dvmCompiler_TEMPLATE_RETURN:
174/* File: armv5te/TEMPLATE_RETURN.S */
175    /*
176     * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
177     * If the stored value in returnAddr
178     * is non-zero, the caller is compiled by the JIT thus return to the
179     * address in the code cache following the invoke instruction. Otherwise
180     * return to the special dvmJitToInterpNoChain entry point.
181     */
182    SAVEAREA_FROM_FP(r0, rFP)           @ r0<- saveArea (old)
183    ldr     r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
184    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
185    ldr     rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
186#if !defined(WITH_SELF_VERIFICATION)
187    ldr     r9,  [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
188#else
189    mov     r9, #0                      @ disable chaining
190#endif
191    ldr     r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
192                                        @ r2<- method we're returning to
193    ldr     r3, [rGLUE, #offGlue_self]  @ r3<- glue->self
194    cmp     r2, #0                      @ break frame?
195#if !defined(WITH_SELF_VERIFICATION)
196    beq     1f                          @ bail to interpreter
197#else
198    blxeq   lr                          @ punt to interpreter and compare state
199#endif
200    ldr     r1, .LdvmJitToInterpNoChain @ defined in footer.S
201    mov     rFP, r10                    @ publish new FP
202    ldrne   r10, [r2, #offMethod_clazz] @ r10<- method->clazz
203    ldr     r8, [r8]                    @ r8<- suspendCount
204
205    str     r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
206    ldr     r0, [r10, #offClassObject_pDvmDex] @ r0<- method->clazz->pDvmDex
207    str     rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
208    add     rPC, rPC, #6                @ publish new rPC (advance 6 bytes)
209    str     r0, [rGLUE, #offGlue_methodClassDex]
210    cmp     r8, #0                      @ check the suspendCount
211    movne   r9, #0                      @ clear the chaining cell address
212    cmp     r9, #0                      @ chaining cell exists?
213    blxne   r9                          @ jump to the chaining cell
214#if defined(EXIT_STATS)
215    mov     r0, #kCallsiteInterpreted
216#endif
217    mov     pc, r1                      @ callsite is interpreted
2181:
219    stmia   rGLUE, {rPC, rFP}           @ SAVE_PC_FP_TO_GLUE()
220    ldr     r2, .LdvmMterpStdBail       @ defined in footer.S
221    mov     r1, #0                      @ changeInterp = false
222    mov     r0, rGLUE                   @ Expecting rGLUE in r0
223    blx     r2                          @ exit the interpreter
224
225/* ------------------------------ */
226    .balign 4
227    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT
228dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
229/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S */
230    /*
231     * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
232     * into rPC then jump to dvmJitToInterpNoChain to dispatch the
233     * runtime-resolved callee.
234     */
235    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
236    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
237    ldrh    r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
238    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
239    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
240    add     r3, r1, #1  @ Thumb addr is odd
241    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
242    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
243    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
244    sub     r10, r10, r2, lsl #2        @ r10<- bottom (newsave - outsSize)
245    ldr     r8, [r8]                    @ r3<- suspendCount (int)
246    cmp     r10, r9                     @ bottom < interpStackEnd?
247    bxlt    lr                          @ return to raise stack overflow excep.
248    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
249    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
250    ldr     r10, [r0, #offMethod_accessFlags] @ r10<- methodToCall->accessFlags
251    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
252    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
253    ldr     rPC, [r0, #offMethod_insns]     @ rPC<- methodToCall->insns
254
255
256    @ set up newSaveArea
257    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
258    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
259    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
260    cmp     r8, #0                      @ suspendCount != 0
261    bxne    lr                          @ bail to the interpreter
262    tst     r10, #ACC_NATIVE
263#if !defined(WITH_SELF_VERIFICATION)
264    bne     .LinvokeNative
265#else
266    bxne    lr                          @ bail to the interpreter
267#endif
268
269    ldr     r10, .LdvmJitToInterpNoChain
270    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
271    ldr     r2, [rGLUE, #offGlue_self]      @ r2<- glue->self
272
273    @ Update "glue" values for the new method
274    str     r0, [rGLUE, #offGlue_method]    @ glue->method = methodToCall
275    str     r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
276    mov     rFP, r1                         @ fp = newFp
277    str     rFP, [r2, #offThread_curFrame]  @ self->curFrame = newFp
278
279    @ Start executing the callee
280#if defined(EXIT_STATS)
281    mov     r0, #kInlineCacheMiss
282#endif
283    mov     pc, r10                         @ dvmJitToInterpNoChain
284
285/* ------------------------------ */
286    .balign 4
287    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN
288dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
289/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S */
290    /*
291     * For monomorphic callsite, setup the Dalvik frame and return to the
292     * Thumb code through the link register to transfer control to the callee
293     * method through a dedicated chaining cell.
294     */
295    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
296    @ methodToCall is guaranteed to be non-native
297.LinvokeChain:
298    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
299    ldrh    r2, [r0, #offMethod_outsSize]  @ r2<- methodToCall->outsSize
300    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
301    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
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    ldr     r8, [r8]                    @ r3<- suspendCount (int)
309    cmp     r10, r9                     @ bottom < interpStackEnd?
310    bxlt    r12                         @ return to raise stack overflow excep.
311    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
312    ldr     r9, [r0, #offMethod_clazz]      @ r9<- method->clazz
313    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
314    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
315    ldr     rPC, [r0, #offMethod_insns]     @ rPC<- methodToCall->insns
316
317
318    @ set up newSaveArea
319    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
320    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
321    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
322    cmp     r8, #0                      @ suspendCount != 0
323    bxne    r12                         @ bail to the interpreter
324
325    ldr     r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
326    ldr     r2, [rGLUE, #offGlue_self]      @ r2<- glue->self
327
328    @ Update "glue" values for the new method
329    str     r0, [rGLUE, #offGlue_method]    @ glue->method = methodToCall
330    str     r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
331    mov     rFP, r1                         @ fp = newFp
332    str     rFP, [r2, #offThread_curFrame]  @ self->curFrame = newFp
333
334    bx      lr                              @ return to the callee-chaining cell
335
336
337
338/* ------------------------------ */
339    .balign 4
340    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN
341dvmCompiler_TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN:
342/* File: armv5te/TEMPLATE_INVOKE_METHOD_PREDICTED_CHAIN.S */
343    /*
344     * For polymorphic callsite, check whether the cached class pointer matches
345     * the current one. If so setup the Dalvik frame and return to the
346     * Thumb code through the link register to transfer control to the callee
347     * method through a dedicated chaining cell.
348     *
349     * The predicted chaining cell is declared in ArmLIR.h with the
350     * following layout:
351     *
352     *  typedef struct PredictedChainingCell {
353     *      u4 branch;
354     *      const ClassObject *clazz;
355     *      const Method *method;
356     *      u4 counter;
357     *  } PredictedChainingCell;
358     *
359     * Upon returning to the callsite:
360     *    - lr  : to branch to the chaining cell
361     *    - lr+2: to punt to the interpreter
362     *    - lr+4: to fully resolve the callee and may rechain.
363     *            r3 <- class
364     *            r9 <- counter
365     */
366    @ r0 = this, r1 = returnCell, r2 = predictedChainCell, rPC = dalvikCallsite
367    ldr     r3, [r0, #offObject_clazz]  @ r3 <- this->class
368    ldr     r8, [r2, #4]    @ r8 <- predictedChainCell->clazz
369    ldr     r0, [r2, #8]    @ r0 <- predictedChainCell->method
370    ldr     r9, [r2, #12]   @ r9 <- predictedChainCell->counter
371    cmp     r3, r8          @ predicted class == actual class?
372    beq     .LinvokeChain   @ predicted chain is valid
373    ldr     r7, [r3, #offClassObject_vtable] @ r7 <- this->class->vtable
374    sub     r1, r9, #1      @ count--
375    str     r1, [r2, #12]   @ write back to PredictedChainingCell->counter
376    add     lr, lr, #4      @ return to fully-resolve landing pad
377    /*
378     * r1 <- count
379     * r2 <- &predictedChainCell
380     * r3 <- this->class
381     * r4 <- dPC
382     * r7 <- this->class->vtable
383     */
384    bx      lr
385
386/* ------------------------------ */
387    .balign 4
388    .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE
389dvmCompiler_TEMPLATE_INVOKE_METHOD_NATIVE:
390/* File: armv5te/TEMPLATE_INVOKE_METHOD_NATIVE.S */
391    @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
392    ldrh    r7, [r0, #offMethod_registersSize]  @ r7<- methodToCall->regsSize
393    ldr     r9, [rGLUE, #offGlue_interpStackEnd]    @ r9<- interpStackEnd
394    ldr     r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
395    add     r3, r1, #1  @ Thumb addr is odd
396    SAVEAREA_FROM_FP(r1, rFP)           @ r1<- stack save area
397    sub     r1, r1, r7, lsl #2          @ r1<- newFp (old savearea - regsSize)
398    SAVEAREA_FROM_FP(r10, r1)           @ r10<- stack save area
399    ldr     r8, [r8]                    @ r3<- suspendCount (int)
400    cmp     r10, r9                     @ bottom < interpStackEnd?
401    bxlt    lr                          @ return to raise stack overflow excep.
402    @ r1 = newFP, r0 = methodToCall, r3 = returnCell, rPC = dalvikCallsite
403    str     rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
404    str     rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
405    ldr     rPC, [r0, #offMethod_insns]     @ rPC<- methodToCall->insns
406
407
408    @ set up newSaveArea
409    str     rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
410    str     r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
411    ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
412    str     r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
413    cmp     r8, #0                      @ suspendCount != 0
414    ldr     r8, [r0, #offMethod_nativeFunc] @ r8<- method->nativeFunc
415#if !defined(WITH_SELF_VERIFICATION)
416    bxne    lr                          @ bail to the interpreter
417#else
418    bx      lr                          @ bail to interpreter unconditionally
419#endif
420
421    @ go ahead and transfer control to the native code
422    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
423    str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
424    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
425                                        @ newFp->localRefCookie=top
426    mov     r9, r3                      @ r9<- glue->self (preserve)
427    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
428
429    mov     r2, r0                      @ r2<- methodToCall
430    mov     r0, r1                      @ r0<- newFP
431    add     r1, rGLUE, #offGlue_retval  @ r1<- &retval
432
433    blx     r8                          @ off to the native code
434
435    @ native return; r9=self, r10=newSaveArea
436    @ equivalent to dvmPopJniLocals
437    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
438    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
439    ldr     r1, [r9, #offThread_exception] @ check for exception
440    str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
441    cmp     r1, #0                      @ null?
442    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
443    bne     .LhandleException             @ no, handle exception
444    bx      r2
445
446
447/* ------------------------------ */
448    .balign 4
449    .global dvmCompiler_TEMPLATE_CMPG_DOUBLE
450dvmCompiler_TEMPLATE_CMPG_DOUBLE:
451/* File: armv5te/TEMPLATE_CMPG_DOUBLE.S */
452/* File: armv5te/TEMPLATE_CMPL_DOUBLE.S */
453    /*
454     * For the JIT: incoming arguments in r0-r1, r2-r3
455     *              result in r0
456     *
457     * Compare two floating-point values.  Puts 0, 1, or -1 into the
458     * destination register based on the results of the comparison.
459     *
460     * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
461     * on what value we'd like to return when one of the operands is NaN.
462     *
463     * See OP_CMPL_FLOAT for an explanation.
464     *
465     * For: cmpl-double, cmpg-double
466     */
467    /* op vAA, vBB, vCC */
468    push    {r0-r3}                     @ save operands
469    mov     r11, lr                     @ save return address
470    LDR_PC_LR ".L__aeabi_cdcmple"       @ PIC way of "bl __aeabi_cdcmple"
471    bhi     .LTEMPLATE_CMPG_DOUBLE_gt_or_nan       @ C set and Z clear, disambiguate
472    mvncc   r0, #0                      @ (less than) r1<- -1
473    moveq   r0, #0                      @ (equal) r1<- 0, trumps less than
474    add     sp, #16                     @ drop unused operands
475    bx      r11
476
477    @ Test for NaN with a second comparison.  EABI forbids testing bit
478    @ patterns, and we can't represent 0x7fc00000 in immediate form, so
479    @ make the library call.
480.LTEMPLATE_CMPG_DOUBLE_gt_or_nan:
481    pop     {r2-r3}                     @ restore operands in reverse order
482    pop     {r0-r1}                     @ restore operands in reverse order
483    LDR_PC_LR ".L__aeabi_cdcmple"       @ r0<- Z set if eq, C clear if <
484    movcc   r0, #1                      @ (greater than) r1<- 1
485    bxcc    r11
486    mov     r0, #1                            @ r1<- 1 or -1 for NaN
487    bx      r11
488
489
490
491/* ------------------------------ */
492    .balign 4
493    .global dvmCompiler_TEMPLATE_CMPL_DOUBLE
494dvmCompiler_TEMPLATE_CMPL_DOUBLE:
495/* File: armv5te/TEMPLATE_CMPL_DOUBLE.S */
496    /*
497     * For the JIT: incoming arguments in r0-r1, r2-r3
498     *              result in r0
499     *
500     * Compare two floating-point values.  Puts 0, 1, or -1 into the
501     * destination register based on the results of the comparison.
502     *
503     * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
504     * on what value we'd like to return when one of the operands is NaN.
505     *
506     * See OP_CMPL_FLOAT for an explanation.
507     *
508     * For: cmpl-double, cmpg-double
509     */
510    /* op vAA, vBB, vCC */
511    push    {r0-r3}                     @ save operands
512    mov     r11, lr                     @ save return address
513    LDR_PC_LR ".L__aeabi_cdcmple"       @ PIC way of "bl __aeabi_cdcmple"
514    bhi     .LTEMPLATE_CMPL_DOUBLE_gt_or_nan       @ C set and Z clear, disambiguate
515    mvncc   r0, #0                      @ (less than) r1<- -1
516    moveq   r0, #0                      @ (equal) r1<- 0, trumps less than
517    add     sp, #16                     @ drop unused operands
518    bx      r11
519
520    @ Test for NaN with a second comparison.  EABI forbids testing bit
521    @ patterns, and we can't represent 0x7fc00000 in immediate form, so
522    @ make the library call.
523.LTEMPLATE_CMPL_DOUBLE_gt_or_nan:
524    pop     {r2-r3}                     @ restore operands in reverse order
525    pop     {r0-r1}                     @ restore operands in reverse order
526    LDR_PC_LR ".L__aeabi_cdcmple"       @ r0<- Z set if eq, C clear if <
527    movcc   r0, #1                      @ (greater than) r1<- 1
528    bxcc    r11
529    mvn     r0, #0                            @ r1<- 1 or -1 for NaN
530    bx      r11
531
532
533/* ------------------------------ */
534    .balign 4
535    .global dvmCompiler_TEMPLATE_CMPG_FLOAT
536dvmCompiler_TEMPLATE_CMPG_FLOAT:
537/* File: armv5te/TEMPLATE_CMPG_FLOAT.S */
538/* File: armv5te/TEMPLATE_CMPL_FLOAT.S */
539    /*
540     * For the JIT: incoming arguments in r0-r1, r2-r3
541     *              result in r0
542     *
543     * Compare two floating-point values.  Puts 0, 1, or -1 into the
544     * destination register based on the results of the comparison.
545     *
546     * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
547     * on what value we'd like to return when one of the operands is NaN.
548     *
549     * The operation we're implementing is:
550     *   if (x == y)
551     *     return 0;
552     *   else if (x < y)
553     *     return -1;
554     *   else if (x > y)
555     *     return 1;
556     *   else
557     *     return {-1,1};  // one or both operands was NaN
558     *
559     * The straightforward implementation requires 3 calls to functions
560     * that return a result in r0.  We can do it with two calls if our
561     * EABI library supports __aeabi_cfcmple (only one if we want to check
562     * for NaN directly):
563     *   check x <= y
564     *     if <, return -1
565     *     if ==, return 0
566     *   check y <= x
567     *     if <, return 1
568     *   return {-1,1}
569     *
570     * for: cmpl-float, cmpg-float
571     */
572    /* op vAA, vBB, vCC */
573    mov     r9, r0                      @ Save copies - we may need to redo
574    mov     r10, r1
575    mov     r11, lr                     @ save return address
576    LDR_PC_LR ".L__aeabi_cfcmple"       @ cmp <=: C clear if <, Z set if eq
577    bhi     .LTEMPLATE_CMPG_FLOAT_gt_or_nan       @ C set and Z clear, disambiguate
578    mvncc   r0, #0                      @ (less than) r0<- -1
579    moveq   r0, #0                      @ (equal) r0<- 0, trumps less than
580    bx      r11
581    @ Test for NaN with a second comparison.  EABI forbids testing bit
582    @ patterns, and we can't represent 0x7fc00000 in immediate form, so
583    @ make the library call.
584.LTEMPLATE_CMPG_FLOAT_gt_or_nan:
585    mov     r0, r10                     @ restore in reverse order
586    mov     r1, r9
587    LDR_PC_LR ".L__aeabi_cfcmple"       @ r0<- Z set if eq, C clear if <
588    movcc   r0, #1                      @ (greater than) r1<- 1
589    bxcc    r11
590    mov     r0, #1                            @ r1<- 1 or -1 for NaN
591    bx      r11
592
593
594
595
596/* ------------------------------ */
597    .balign 4
598    .global dvmCompiler_TEMPLATE_CMPL_FLOAT
599dvmCompiler_TEMPLATE_CMPL_FLOAT:
600/* File: armv5te/TEMPLATE_CMPL_FLOAT.S */
601    /*
602     * For the JIT: incoming arguments in r0-r1, r2-r3
603     *              result in r0
604     *
605     * Compare two floating-point values.  Puts 0, 1, or -1 into the
606     * destination register based on the results of the comparison.
607     *
608     * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
609     * on what value we'd like to return when one of the operands is NaN.
610     *
611     * The operation we're implementing is:
612     *   if (x == y)
613     *     return 0;
614     *   else if (x < y)
615     *     return -1;
616     *   else if (x > y)
617     *     return 1;
618     *   else
619     *     return {-1,1};  // one or both operands was NaN
620     *
621     * The straightforward implementation requires 3 calls to functions
622     * that return a result in r0.  We can do it with two calls if our
623     * EABI library supports __aeabi_cfcmple (only one if we want to check
624     * for NaN directly):
625     *   check x <= y
626     *     if <, return -1
627     *     if ==, return 0
628     *   check y <= x
629     *     if <, return 1
630     *   return {-1,1}
631     *
632     * for: cmpl-float, cmpg-float
633     */
634    /* op vAA, vBB, vCC */
635    mov     r9, r0                      @ Save copies - we may need to redo
636    mov     r10, r1
637    mov     r11, lr                     @ save return address
638    LDR_PC_LR ".L__aeabi_cfcmple"       @ cmp <=: C clear if <, Z set if eq
639    bhi     .LTEMPLATE_CMPL_FLOAT_gt_or_nan       @ C set and Z clear, disambiguate
640    mvncc   r0, #0                      @ (less than) r0<- -1
641    moveq   r0, #0                      @ (equal) r0<- 0, trumps less than
642    bx      r11
643    @ Test for NaN with a second comparison.  EABI forbids testing bit
644    @ patterns, and we can't represent 0x7fc00000 in immediate form, so
645    @ make the library call.
646.LTEMPLATE_CMPL_FLOAT_gt_or_nan:
647    mov     r0, r10                     @ restore in reverse order
648    mov     r1, r9
649    LDR_PC_LR ".L__aeabi_cfcmple"       @ r0<- Z set if eq, C clear if <
650    movcc   r0, #1                      @ (greater than) r1<- 1
651    bxcc    r11
652    mvn     r0, #0                            @ r1<- 1 or -1 for NaN
653    bx      r11
654
655
656
657/* ------------------------------ */
658    .balign 4
659    .global dvmCompiler_TEMPLATE_MUL_LONG
660dvmCompiler_TEMPLATE_MUL_LONG:
661/* File: armv5te/TEMPLATE_MUL_LONG.S */
662    /*
663     * Signed 64-bit integer multiply.
664     *
665     * For JIT: op1 in r0/r1, op2 in r2/r3, return in r0/r1
666     *
667     * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
668     *        WX
669     *      x YZ
670     *  --------
671     *     ZW ZX
672     *  YW YX
673     *
674     * The low word of the result holds ZX, the high word holds
675     * (ZW+YX) + (the high overflow from ZX).  YW doesn't matter because
676     * it doesn't fit in the low 64 bits.
677     *
678     * Unlike most ARM math operations, multiply instructions have
679     * restrictions on using the same register more than once (Rd and Rm
680     * cannot be the same).
681     */
682    /* mul-long vAA, vBB, vCC */
683    mul     ip, r2, r1                  @  ip<- ZxW
684    umull   r9, r10, r2, r0             @  r9/r10 <- ZxX
685    mla     r2, r0, r3, ip              @  r2<- YxX + (ZxW)
686    add     r10, r2, r10                @  r10<- r10 + low(ZxW + (YxX))
687    mov     r0,r9
688    mov     r1,r10
689    bx      lr
690
691/* ------------------------------ */
692    .balign 4
693    .global dvmCompiler_TEMPLATE_SHL_LONG
694dvmCompiler_TEMPLATE_SHL_LONG:
695/* File: armv5te/TEMPLATE_SHL_LONG.S */
696    /*
697     * Long integer shift.  This is different from the generic 32/64-bit
698     * binary operations because vAA/vBB are 64-bit but vCC (the shift
699     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
700     * 6 bits.
701     */
702    /* shl-long vAA, vBB, vCC */
703    and     r2, r2, #63                 @ r2<- r2 & 0x3f
704    mov     r1, r1, asl r2              @  r1<- r1 << r2
705    rsb     r3, r2, #32                 @  r3<- 32 - r2
706    orr     r1, r1, r0, lsr r3          @  r1<- r1 | (r0 << (32-r2))
707    subs    ip, r2, #32                 @  ip<- r2 - 32
708    movpl   r1, r0, asl ip              @  if r2 >= 32, r1<- r0 << (r2-32)
709    mov     r0, r0, asl r2              @  r0<- r0 << r2
710    bx      lr
711
712/* ------------------------------ */
713    .balign 4
714    .global dvmCompiler_TEMPLATE_SHR_LONG
715dvmCompiler_TEMPLATE_SHR_LONG:
716/* File: armv5te/TEMPLATE_SHR_LONG.S */
717    /*
718     * Long integer shift.  This is different from the generic 32/64-bit
719     * binary operations because vAA/vBB are 64-bit but vCC (the shift
720     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
721     * 6 bits.
722     */
723    /* shr-long vAA, vBB, vCC */
724    and     r2, r2, #63                 @ r0<- r0 & 0x3f
725    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
726    rsb     r3, r2, #32                 @  r3<- 32 - r2
727    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
728    subs    ip, r2, #32                 @  ip<- r2 - 32
729    movpl   r0, r1, asr ip              @  if r2 >= 32, r0<-r1 >> (r2-32)
730    mov     r1, r1, asr r2              @  r1<- r1 >> r2
731    bx      lr
732
733
734/* ------------------------------ */
735    .balign 4
736    .global dvmCompiler_TEMPLATE_USHR_LONG
737dvmCompiler_TEMPLATE_USHR_LONG:
738/* File: armv5te/TEMPLATE_USHR_LONG.S */
739    /*
740     * Long integer shift.  This is different from the generic 32/64-bit
741     * binary operations because vAA/vBB are 64-bit but vCC (the shift
742     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
743     * 6 bits.
744     */
745    /* ushr-long vAA, vBB, vCC */
746    and     r2, r2, #63                 @ r0<- r0 & 0x3f
747    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
748    rsb     r3, r2, #32                 @  r3<- 32 - r2
749    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
750    subs    ip, r2, #32                 @  ip<- r2 - 32
751    movpl   r0, r1, lsr ip              @  if r2 >= 32, r0<-r1 >>> (r2-32)
752    mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
753    bx      lr
754
755
756/* ------------------------------ */
757    .balign 4
758    .global dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON
759dvmCompiler_TEMPLATE_THROW_EXCEPTION_COMMON:
760/* File: armv5te/TEMPLATE_THROW_EXCEPTION_COMMON.S */
761    /*
762     * Throw an exception from JIT'ed code.
763     * On entry:
764     *    r0    Dalvik PC that raises the exception
765     */
766    b       .LhandleException
767
768/* ------------------------------ */
769    .balign 4
770    .global dvmCompiler_TEMPLATE_SAVE_STATE
771dvmCompiler_TEMPLATE_SAVE_STATE:
772/* File: armv5te/TEMPLATE_SAVE_STATE.S */
773    /*
774     * This handler performs a register save for selfVerification mode.
775     * On entry:
776     *    Top of stack + 4: r7 value to save
777     *    Top of stack + 0: r0 value to save
778     *    r0 - offset from rGLUE to the beginning of the heapArgSpace record
779     *    r7 - the value of regMap
780     *
781     * The handler must save regMap, r0-r12 and then return with r0-r12
782     * with their original values (note that this means r0 and r7 must take
783     * the values on the stack - not the ones in those registers on entry.
784     * Finally, the two registers previously pushed must be popped.
785     */
786    add     r0, r0, rGLUE               @ pointer to heapArgSpace
787    stmia   r0!, {r7}                   @ save regMap
788    ldr     r7, [r13, #0]               @ recover r0 value
789    stmia   r0!, {r7}                   @ save r0
790    ldr     r7, [r13, #4]               @ recover r7 value
791    stmia   r0!, {r1-r12}
792    pop     {r0, r7}                    @ recover r0, r7
793    bx      lr
794
795/* ------------------------------ */
796    .balign 4
797    .global dvmCompiler_TEMPLATE_RESTORE_STATE
798dvmCompiler_TEMPLATE_RESTORE_STATE:
799/* File: armv5te/TEMPLATE_RESTORE_STATE.S */
800    /*
801     * This handler restores state following a selfVerification memory access.
802     * On entry:
803     *    r0 - offset from rGLUE to the 1st element of the coreRegs save array.
804     */
805    add     r0, r0, rGLUE               @ pointer to heapArgSpace.coreRegs[0]
806    ldmia   r0, {r0-r12}
807    bx      lr
808
809/* ------------------------------ */
810    .balign 4
811    .global dvmCompiler_TEMPLATE_STRING_COMPARETO
812dvmCompiler_TEMPLATE_STRING_COMPARETO:
813/* File: armv5te/TEMPLATE_STRING_COMPARETO.S */
814    /*
815     * String's compareTo.
816     *
817     * Requires r0/r1 to have been previously checked for null.  Will
818     * return negative if this's string is < comp, 0 if they are the
819     * same and positive if >.
820     *
821     * IMPORTANT NOTE:
822     *
823     * This code relies on hard-coded offsets for string objects, and must be
824     * kept in sync with definitions in UtfString.h.  See asm-constants.h
825     *
826     * On entry:
827     *    r0:   this object pointer
828     *    r1:   comp object pointer
829     *
830     */
831
832    mov    r2, r0         @ this to r2, opening up r0 for return value
833    subs   r0, r2, r1     @ Same?
834    bxeq   lr
835
836    ldr    r4, [r2, #STRING_FIELDOFF_OFFSET]
837    ldr    r9, [r1, #STRING_FIELDOFF_OFFSET]
838    ldr    r7, [r2, #STRING_FIELDOFF_COUNT]
839    ldr    r10, [r1, #STRING_FIELDOFF_COUNT]
840    ldr    r2, [r2, #STRING_FIELDOFF_VALUE]
841    ldr    r1, [r1, #STRING_FIELDOFF_VALUE]
842
843    /*
844     * At this point, we have:
845     *    value:  r2/r1
846     *    offset: r4/r9
847     *    count:  r7/r10
848     * We're going to compute
849     *    r11 <- countDiff
850     *    r10 <- minCount
851     */
852     subs  r11, r7, r10
853     movls r10, r7
854
855     /* Now, build pointers to the string data */
856     add   r2, r2, r4, lsl #1
857     add   r1, r1, r9, lsl #1
858     /*
859      * Note: data pointers point to previous element so we can use pre-index
860      * mode with base writeback.
861      */
862     add   r2, #16-2   @ offset to contents[-1]
863     add   r1, #16-2   @ offset to contents[-1]
864
865     /*
866      * At this point we have:
867      *   r2: *this string data
868      *   r1: *comp string data
869      *   r10: iteration count for comparison
870      *   r11: value to return if the first part of the string is equal
871      *   r0: reserved for result
872      *   r3, r4, r7, r8, r9, r12 available for loading string data
873      */
874
875    subs  r10, #2
876    blt   do_remainder2
877
878      /*
879       * Unroll the first two checks so we can quickly catch early mismatch
880       * on long strings (but preserve incoming alignment)
881       */
882
883    ldrh  r3, [r2, #2]!
884    ldrh  r4, [r1, #2]!
885    ldrh  r7, [r2, #2]!
886    ldrh  r8, [r1, #2]!
887    subs  r0, r3, r4
888    subeqs  r0, r7, r8
889    bxne  lr
890    cmp   r10, #28
891    bgt   do_memcmp16
892    subs  r10, #3
893    blt   do_remainder
894
895loopback_triple:
896    ldrh  r3, [r2, #2]!
897    ldrh  r4, [r1, #2]!
898    ldrh  r7, [r2, #2]!
899    ldrh  r8, [r1, #2]!
900    ldrh  r9, [r2, #2]!
901    ldrh  r12,[r1, #2]!
902    subs  r0, r3, r4
903    subeqs  r0, r7, r8
904    subeqs  r0, r9, r12
905    bxne  lr
906    subs  r10, #3
907    bge   loopback_triple
908
909do_remainder:
910    adds  r10, #3
911    beq   returnDiff
912
913loopback_single:
914    ldrh  r3, [r2, #2]!
915    ldrh  r4, [r1, #2]!
916    subs  r0, r3, r4
917    bxne  lr
918    subs  r10, #1
919    bne     loopback_single
920
921returnDiff:
922    mov   r0, r11
923    bx    lr
924
925do_remainder2:
926    adds  r10, #2
927    bne   loopback_single
928    mov   r0, r11
929    bx    lr
930
931    /* Long string case */
932do_memcmp16:
933    mov   r4, lr
934    ldr   lr, .Lmemcmp16
935    mov   r7, r11
936    add   r0, r2, #2
937    add   r1, r1, #2
938    mov   r2, r10
939    blx   lr
940    cmp   r0, #0
941    bxne  r4
942    mov   r0, r7
943    bx    r4
944
945.Lmemcmp16:
946    .word __memcmp16
947
948
949/* ------------------------------ */
950    .balign 4
951    .global dvmCompiler_TEMPLATE_STRING_INDEXOF
952dvmCompiler_TEMPLATE_STRING_INDEXOF:
953/* File: armv5te/TEMPLATE_STRING_INDEXOF.S */
954    /*
955     * String's indexOf.
956     *
957     * Requires r0 to have been previously checked for null.  Will
958     * return index of match of r1 in r0.
959     *
960     * IMPORTANT NOTE:
961     *
962     * This code relies on hard-coded offsets for string objects, and must be
963     * kept in sync wth definitions in UtfString.h  See asm-constants.h
964     *
965     * On entry:
966     *    r0:   string object pointer
967     *    r1:   char to match
968     *    r2:   Starting offset in string data
969     */
970
971    ldr    r7, [r0, #STRING_FIELDOFF_OFFSET]
972    ldr    r8, [r0, #STRING_FIELDOFF_COUNT]
973    ldr    r0, [r0, #STRING_FIELDOFF_VALUE]
974
975    /*
976     * At this point, we have:
977     *    r0: object pointer
978     *    r1: char to match
979     *    r2: starting offset
980     *    r7: offset
981     *    r8: string length
982     */
983
984     /* Build pointer to start of string data */
985     add   r0, #16
986     add   r0, r0, r7, lsl #1
987
988     /* Save a copy of starting data in r7 */
989     mov   r7, r0
990
991     /* Clamp start to [0..count] */
992     cmp   r2, #0
993     movlt r2, #0
994     cmp   r2, r8
995     movgt r2, r8
996
997     /* Build pointer to start of data to compare and pre-bias */
998     add   r0, r0, r2, lsl #1
999     sub   r0, #2
1000
1001     /* Compute iteration count */
1002     sub   r8, r2
1003
1004     /*
1005      * At this point we have:
1006      *   r0: start of data to test
1007      *   r1: chat to compare
1008      *   r8: iteration count
1009      *   r7: original start of string
1010      *   r3, r4, r9, r10, r11, r12 available for loading string data
1011      */
1012
1013    subs  r8, #4
1014    blt   indexof_remainder
1015
1016indexof_loop4:
1017    ldrh  r3, [r0, #2]!
1018    ldrh  r4, [r0, #2]!
1019    ldrh  r10, [r0, #2]!
1020    ldrh  r11, [r0, #2]!
1021    cmp   r3, r1
1022    beq   match_0
1023    cmp   r4, r1
1024    beq   match_1
1025    cmp   r10, r1
1026    beq   match_2
1027    cmp   r11, r1
1028    beq   match_3
1029    subs  r8, #4
1030    bge   indexof_loop4
1031
1032indexof_remainder:
1033    adds    r8, #4
1034    beq     indexof_nomatch
1035
1036indexof_loop1:
1037    ldrh  r3, [r0, #2]!
1038    cmp   r3, r1
1039    beq   match_3
1040    subs  r8, #1
1041    bne   indexof_loop1
1042
1043indexof_nomatch:
1044    mov   r0, #-1
1045    bx    lr
1046
1047match_0:
1048    sub   r0, #6
1049    sub   r0, r7
1050    asr   r0, r0, #1
1051    bx    lr
1052match_1:
1053    sub   r0, #4
1054    sub   r0, r7
1055    asr   r0, r0, #1
1056    bx    lr
1057match_2:
1058    sub   r0, #2
1059    sub   r0, r7
1060    asr   r0, r0, #1
1061    bx    lr
1062match_3:
1063    sub   r0, r7
1064    asr   r0, r0, #1
1065    bx    lr
1066
1067
1068/* ------------------------------ */
1069    .balign 4
1070    .global dvmCompiler_TEMPLATE_INTERPRET
1071dvmCompiler_TEMPLATE_INTERPRET:
1072/* File: armv5te/TEMPLATE_INTERPRET.S */
1073    /*
1074     * This handler transfers control to the interpeter without performing
1075     * any lookups.  It may be called either as part of a normal chaining
1076     * operation, or from the transition code in header.S.  We distinquish
1077     * the two cases by looking at the link register.  If called from a
1078     * translation chain, it will point to the chaining Dalvik PC + 1.
1079     * On entry:
1080     *    lr - if NULL:
1081     *        r1 - the Dalvik PC to begin interpretation.
1082     *    else
1083     *        [lr, #-1] contains Dalvik PC to begin interpretation
1084     *    rGLUE - pointer to interpState
1085     *    rFP - Dalvik frame pointer
1086     */
1087    cmp     lr, #0
1088    ldrne   r1,[lr, #-1]
1089    ldr     r2, .LinterpPunt
1090    mov     r0, r1                       @ set Dalvik PC
1091    bx      r2
1092    @ doesn't return
1093
1094.LinterpPunt:
1095    .word   dvmJitToInterpPunt
1096
1097    .size   dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
1098/* File: armv5te/footer.S */
1099/*
1100 * ===========================================================================
1101 *  Common subroutines and data
1102 * ===========================================================================
1103 */
1104
1105    .text
1106    .align  2
1107.LinvokeNative:
1108    @ Prep for the native call
1109    @ r1 = newFP, r0 = methodToCall
1110    ldr     r3, [rGLUE, #offGlue_self]      @ r3<- glue->self
1111    ldr     r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->...
1112    str     r1, [r3, #offThread_curFrame]   @ self->curFrame = newFp
1113    str     r9, [r1, #(offStackSaveArea_localRefCookie - sizeofStackSaveArea)]
1114                                        @ newFp->localRefCookie=top
1115    mov     r9, r3                      @ r9<- glue->self (preserve)
1116    SAVEAREA_FROM_FP(r10, r1)           @ r10<- new stack save area
1117
1118    mov     r2, r0                      @ r2<- methodToCall
1119    mov     r0, r1                      @ r0<- newFP
1120    add     r1, rGLUE, #offGlue_retval  @ r1<- &retval
1121
1122    LDR_PC_LR "[r2, #offMethod_nativeFunc]"
1123
1124    @ native return; r9=self, r10=newSaveArea
1125    @ equivalent to dvmPopJniLocals
1126    ldr     r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
1127    ldr     r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved->top
1128    ldr     r1, [r9, #offThread_exception] @ check for exception
1129    str     rFP, [r9, #offThread_curFrame]  @ self->curFrame = fp
1130    cmp     r1, #0                      @ null?
1131    str     r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top
1132    ldr     r0, [r10, #offStackSaveArea_savedPc] @ reload rPC
1133    bne     .LhandleException             @ no, handle exception
1134    bx      r2
1135
1136/*
1137 * On entry:
1138 * r0  Faulting Dalvik PC
1139 */
1140.LhandleException:
1141    ldr     r1, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
1142    ldr     rIBASE, .LdvmAsmInstructionStart    @ same as above
1143    mov     rPC, r0                 @ reload the faulting Dalvik address
1144    mov     pc, r1                  @ branch to dvmMterpCommonExceptionThrown
1145
1146    .align  2
1147.LdvmAsmInstructionStart:
1148    .word   dvmAsmInstructionStart
1149.LdvmJitToInterpNoChain:
1150    .word   dvmJitToInterpNoChain
1151.LdvmMterpStdBail:
1152    .word   dvmMterpStdBail
1153.LdvmMterpCommonExceptionThrown:
1154    .word   dvmMterpCommonExceptionThrown
1155.L__aeabi_cdcmple:
1156    .word   __aeabi_cdcmple
1157.L__aeabi_cfcmple:
1158    .word   __aeabi_cfcmple
1159
1160    .global dmvCompilerTemplateEnd
1161dmvCompilerTemplateEnd:
1162
1163#endif /* WITH_JIT */
1164
1165