1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "asm_support_arm.S"
18
19    /* Deliver the given exception */
20    .extern artDeliverExceptionFromCode
21    /* Deliver an exception pending on a thread */
22    .extern artDeliverPendingException
23
24    /*
25     * Macro that sets up the callee save frame to conform with
26     * Runtime::CreateCalleeSaveMethod(kSaveAll)
27     */
28.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
29    push {r4-r11, lr} @ 9 words of callee saves
30    .save {r4-r11, lr}
31    .cfi_adjust_cfa_offset 36
32    .cfi_rel_offset r4, 0
33    .cfi_rel_offset r5, 4
34    .cfi_rel_offset r6, 8
35    .cfi_rel_offset r7, 12
36    .cfi_rel_offset r8, 16
37    .cfi_rel_offset r9, 20
38    .cfi_rel_offset r10, 24
39    .cfi_rel_offset r11, 28
40    .cfi_rel_offset lr, 32
41    vpush {s0-s31}
42    .pad #128
43    .cfi_adjust_cfa_offset 128
44    sub sp, #12       @ 3 words of space, bottom word will hold Method*
45    .pad #12
46    .cfi_adjust_cfa_offset 12
47.endm
48
49    /*
50     * Macro that sets up the callee save frame to conform with
51     * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes non-moving GC.
52     */
53.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
54    push {r5-r8, r10-r11, lr} @ 7 words of callee saves
55    .save {r5-r8, r10-r11, lr}
56    .cfi_adjust_cfa_offset 28
57    .cfi_rel_offset r5, 0
58    .cfi_rel_offset r6, 4
59    .cfi_rel_offset r7, 8
60    .cfi_rel_offset r8, 12
61    .cfi_rel_offset r10, 16
62    .cfi_rel_offset r11, 20
63    .cfi_rel_offset lr, 24
64    sub sp, #4                @ bottom word will hold Method*
65    .pad #4
66    .cfi_adjust_cfa_offset 4
67.endm
68
69.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
70    ldr lr, [sp, #28]  @ restore lr for return
71    add sp, #32        @ unwind stack
72    .cfi_adjust_cfa_offset -32
73.endm
74
75.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
76    ldr lr, [sp, #28]  @ restore lr for return
77    add sp, #32        @ unwind stack
78    .cfi_adjust_cfa_offset -32
79    bx  lr             @ return
80.endm
81
82    /*
83     * Macro that sets up the callee save frame to conform with
84     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC.
85     */
86.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
87    push {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
88    .save {r1-r3, r5-r8, r10-r11, lr}
89    .cfi_adjust_cfa_offset 40
90    .cfi_rel_offset r1, 0
91    .cfi_rel_offset r2, 4
92    .cfi_rel_offset r3, 8
93    .cfi_rel_offset r5, 12
94    .cfi_rel_offset r6, 16
95    .cfi_rel_offset r7, 20
96    .cfi_rel_offset r8, 24
97    .cfi_rel_offset r10, 28
98    .cfi_rel_offset r11, 32
99    .cfi_rel_offset lr, 36
100    sub sp, #8                        @ 2 words of space, bottom word will hold Method*
101    .pad #8
102    .cfi_adjust_cfa_offset 8
103.endm
104
105.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
106    ldr  r1, [sp, #8]          @ restore non-callee save r1
107    ldrd r2, [sp, #12]         @ restore non-callee saves r2-r3
108    ldr  lr, [sp, #44]         @ restore lr
109    add  sp, #48               @ rewind sp
110    .cfi_adjust_cfa_offset -48
111.endm
112
113.macro RETURN_IF_RESULT_IS_ZERO
114    cbnz   r0, 1f              @ result non-zero branch over
115    bx     lr                  @ return
1161:
117.endm
118
119.macro RETURN_IF_RESULT_IS_NON_ZERO
120    cbz    r0, 1f              @ result zero branch over
121    bx     lr                  @ return
1221:
123.endm
124
125    /*
126     * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
127     * exception is Thread::Current()->exception_
128     */
129.macro DELIVER_PENDING_EXCEPTION
130    .fnend
131    .fnstart
132    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME           @ save callee saves for throw
133    mov    r0, r9                              @ pass Thread::Current
134    mov    r1, sp                              @ pass SP
135    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
136.endm
137
138.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
139    .extern \cxx_name
140ENTRY \c_name
141    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
142    mov r0, r9                      @ pass Thread::Current
143    mov r1, sp                      @ pass SP
144    b   \cxx_name                   @ \cxx_name(Thread*, SP)
145END \c_name
146.endm
147
148.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
149    .extern \cxx_name
150ENTRY \c_name
151    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
152    mov r1, r9                      @ pass Thread::Current
153    mov r2, sp                      @ pass SP
154    b   \cxx_name                   @ \cxx_name(Thread*, SP)
155END \c_name
156.endm
157
158.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
159    .extern \cxx_name
160ENTRY \c_name
161    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
162    mov r2, r9                      @ pass Thread::Current
163    mov r3, sp                      @ pass SP
164    b   \cxx_name                   @ \cxx_name(Thread*, SP)
165END \c_name
166.endm
167
168    /*
169     * Called by managed code, saves callee saves and then calls artThrowException
170     * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
171     */
172ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
173
174    /*
175     * Called by managed code to create and deliver a NullPointerException.
176     */
177NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
178
179    /*
180     * Called by managed code to create and deliver an ArithmeticException.
181     */
182NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
183
184    /*
185     * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
186     * index, arg2 holds limit.
187     */
188TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
189
190    /*
191     * Called by managed code to create and deliver a StackOverflowError.
192     */
193NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
194
195    /*
196     * Called by managed code to create and deliver a NoSuchMethodError.
197     */
198ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
199
200    /*
201     * All generated callsites for interface invokes and invocation slow paths will load arguments
202     * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
203     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
204     * stack and call the appropriate C helper.
205     * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
206     *
207     * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
208     * of the target Method* in r0 and method->code_ in r1.
209     *
210     * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the
211     * thread and we branch to another stub to deliver it.
212     *
213     * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
214     * pointing back to the original caller.
215     */
216.macro INVOKE_TRAMPOLINE c_name, cxx_name
217    .extern \cxx_name
218ENTRY \c_name
219    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
220    ldr    r2, [sp, #48]                  @ pass caller Method*
221    mov    r3, r9                         @ pass Thread::Current
222    mov    r12, sp
223    str    r12, [sp, #-16]!               @ expand the frame and pass SP
224    .pad #16
225    .cfi_adjust_cfa_offset 16
226    bl     \cxx_name                      @ (method_idx, this, caller, Thread*, SP)
227    add    sp, #16                        @ strip the extra frame
228    .cfi_adjust_cfa_offset -16
229    mov    r12, r1                        @ save Method*->code_
230    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
231    cbz    r0, 1f                         @ did we find the target? if not go to exception delivery
232    bx     r12                            @ tail call to target
2331:
234    DELIVER_PENDING_EXCEPTION
235END \c_name
236.endm
237
238INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
239INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
240
241INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
242INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
243INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
244INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
245
246    /*
247     * Quick invocation stub.
248     * On entry:
249     *   r0 = method pointer
250     *   r1 = argument array or NULL for no argument methods
251     *   r2 = size of argument array in bytes
252     *   r3 = (managed) thread pointer
253     *   [sp] = JValue* result
254     *   [sp + 4] = result type char
255     */
256ENTRY art_quick_invoke_stub
257    push   {r0, r4, r5, r9, r11, lr}       @ spill regs
258    .save  {r0, r4, r5, r9, r11, lr}
259    .pad #24
260    .cfi_adjust_cfa_offset 24
261    .cfi_rel_offset r0, 0
262    .cfi_rel_offset r4, 4
263    .cfi_rel_offset r5, 8
264    .cfi_rel_offset r9, 12
265    .cfi_rel_offset r11, 16
266    .cfi_rel_offset lr, 20
267    mov    r11, sp                         @ save the stack pointer
268    .cfi_def_cfa_register r11
269    mov    r9, r3                          @ move managed thread pointer into r9
270    mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval
271    add    r5, r2, #16                     @ create space for method pointer in frame
272    and    r5, #0xFFFFFFF0                 @ align frame size to 16 bytes
273    sub    sp, r5                          @ reserve stack space for argument array
274    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
275    bl     memcpy                          @ memcpy (dest, src, bytes)
276    ldr    r0, [r11]                       @ restore method*
277    ldr    r1, [sp, #4]                    @ copy arg value for r1
278    ldr    r2, [sp, #8]                    @ copy arg value for r2
279    ldr    r3, [sp, #12]                   @ copy arg value for r3
280    mov    ip, #0                          @ set ip to 0
281    str    ip, [sp]                        @ store NULL for method* at bottom of frame
282    ldr    ip, [r0, #METHOD_CODE_OFFSET]   @ get pointer to the code
283    blx    ip                              @ call the method
284    mov    sp, r11                         @ restore the stack pointer
285    ldr    ip, [sp, #24]                   @ load the result pointer
286    strd   r0, [ip]                        @ store r0/r1 into result pointer
287    pop    {r0, r4, r5, r9, r11, lr}       @ restore spill regs
288    .cfi_adjust_cfa_offset -24
289    bx     lr
290END art_quick_invoke_stub
291
292    /*
293     * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_
294     */
295ARM_ENTRY art_quick_do_long_jump
296    vldm r1, {s0-s31}     @ load all fprs from argument fprs_
297    ldr  r2, [r0, #60]    @ r2 = r15 (PC from gprs_ 60=4*15)
298    add  r0, r0, #12      @ increment r0 to skip gprs_[0..2] 12=4*3
299    ldm  r0, {r3-r14}     @ load remaining gprs from argument gprs_
300    mov  r0, #0           @ clear result registers r0 and r1
301    mov  r1, #0
302    bx   r2               @ do long jump
303END art_quick_do_long_jump
304
305    /*
306     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
307     * failure.
308     */
309    .extern artHandleFillArrayDataFromCode
310ENTRY art_quick_handle_fill_data
311    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case exception allocation triggers GC
312    mov    r2, r9                          @ pass Thread::Current
313    mov    r3, sp                          @ pass SP
314    bl     artHandleFillArrayDataFromCode  @ (Array*, const DexFile::Payload*, Thread*, SP)
315    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
316    RETURN_IF_RESULT_IS_ZERO
317    DELIVER_PENDING_EXCEPTION
318END art_quick_handle_fill_data
319
320    /*
321     * Entry from managed code that calls artLockObjectFromCode, may block for GC.
322     */
323    .extern artLockObjectFromCode
324ENTRY art_quick_lock_object
325    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case we block
326    mov    r1, r9                     @ pass Thread::Current
327    mov    r2, sp                     @ pass SP
328    bl     artLockObjectFromCode      @ (Object* obj, Thread*, SP)
329    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
330END art_quick_lock_object
331
332    /*
333     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
334     */
335    .extern artUnlockObjectFromCode
336ENTRY art_quick_unlock_object
337    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case exception allocation triggers GC
338    mov    r1, r9                     @ pass Thread::Current
339    mov    r2, sp                     @ pass SP
340    bl     artUnlockObjectFromCode    @ (Object* obj, Thread*, SP)
341    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
342    RETURN_IF_RESULT_IS_ZERO
343    DELIVER_PENDING_EXCEPTION
344END art_quick_unlock_object
345
346    /*
347     * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
348     */
349    .extern artCheckCastFromCode
350ENTRY art_quick_check_cast
351    SETUP_REF_ONLY_CALLEE_SAVE_FRAME    @ save callee saves in case exception allocation triggers GC
352    mov    r2, r9                       @ pass Thread::Current
353    mov    r3, sp                       @ pass SP
354    bl     artCheckCastFromCode         @ (Class* a, Class* b, Thread*, SP)
355    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
356    RETURN_IF_RESULT_IS_ZERO
357    DELIVER_PENDING_EXCEPTION
358END art_quick_check_cast
359
360    /*
361     * Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on
362     * failure.
363     */
364    .extern artCanPutArrayElementFromCode
365ENTRY art_quick_can_put_array_element
366    SETUP_REF_ONLY_CALLEE_SAVE_FRAME    @ save callee saves in case exception allocation triggers GC
367    mov    r2, r9                         @ pass Thread::Current
368    mov    r3, sp                         @ pass SP
369    bl     artCanPutArrayElementFromCode  @ (Object* element, Class* array_class, Thread*, SP)
370    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
371    RETURN_IF_RESULT_IS_ZERO
372    DELIVER_PENDING_EXCEPTION
373END art_quick_can_put_array_element
374
375    /*
376     * Entry from managed code when uninitialized static storage, this stub will run the class
377     * initializer and deliver the exception on error. On success the static storage base is
378     * returned.
379     */
380    .extern artInitializeStaticStorageFromCode
381ENTRY art_quick_initialize_static_storage
382    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
383    mov    r2, r9                              @ pass Thread::Current
384    mov    r3, sp                              @ pass SP
385    @ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
386    bl     artInitializeStaticStorageFromCode
387    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
388    RETURN_IF_RESULT_IS_NON_ZERO
389    DELIVER_PENDING_EXCEPTION
390END art_quick_initialize_static_storage
391
392    /*
393     * Entry from managed code when dex cache misses for a type_idx
394     */
395    .extern artInitializeTypeFromCode
396ENTRY art_quick_initialize_type
397    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
398    mov    r2, r9                              @ pass Thread::Current
399    mov    r3, sp                              @ pass SP
400    @ artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
401    bl     artInitializeTypeFromCode
402    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
403    RETURN_IF_RESULT_IS_NON_ZERO
404    DELIVER_PENDING_EXCEPTION
405END art_quick_initialize_type
406
407    /*
408     * Entry from managed code when type_idx needs to be checked for access and dex cache may also
409     * miss.
410     */
411    .extern artInitializeTypeAndVerifyAccessFromCode
412ENTRY art_quick_initialize_type_and_verify_access
413    SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
414    mov    r2, r9                              @ pass Thread::Current
415    mov    r3, sp                              @ pass SP
416    @ artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
417    bl     artInitializeTypeAndVerifyAccessFromCode
418    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
419    RETURN_IF_RESULT_IS_NON_ZERO
420    DELIVER_PENDING_EXCEPTION
421END art_quick_initialize_type_and_verify_access
422
423    /*
424     * Called by managed code to resolve a static field and load a 32-bit primitive value.
425     */
426    .extern artGet32StaticFromCode
427ENTRY art_quick_get32_static
428    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
429    ldr    r1, [sp, #32]                 @ pass referrer
430    mov    r2, r9                        @ pass Thread::Current
431    mov    r3, sp                        @ pass SP
432    bl     artGet32StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
433    ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
434    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
435    cbnz   r1, 1f                        @ success if no exception pending
436    bx     lr                            @ return on success
4371:
438    DELIVER_PENDING_EXCEPTION
439END art_quick_get32_static
440
441    /*
442     * Called by managed code to resolve a static field and load a 64-bit primitive value.
443     */
444    .extern artGet64StaticFromCode
445ENTRY art_quick_get64_static
446    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
447    ldr    r1, [sp, #32]                 @ pass referrer
448    mov    r2, r9                        @ pass Thread::Current
449    mov    r3, sp                        @ pass SP
450    bl     artGet64StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
451    ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
452    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
453    cbnz   r2, 1f                        @ success if no exception pending
454    bx     lr                            @ return on success
4551:
456    DELIVER_PENDING_EXCEPTION
457END art_quick_get64_static
458
459    /*
460     * Called by managed code to resolve a static field and load an object reference.
461     */
462    .extern artGetObjStaticFromCode
463ENTRY art_quick_get_obj_static
464    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
465    ldr    r1, [sp, #32]                 @ pass referrer
466    mov    r2, r9                        @ pass Thread::Current
467    mov    r3, sp                        @ pass SP
468    bl     artGetObjStaticFromCode       @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
469    ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
470    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
471    cbnz   r1, 1f                        @ success if no exception pending
472    bx     lr                            @ return on success
4731:
474    DELIVER_PENDING_EXCEPTION
475END art_quick_get_obj_static
476
477    /*
478     * Called by managed code to resolve an instance field and load a 32-bit primitive value.
479     */
480    .extern artGet32InstanceFromCode
481ENTRY art_quick_get32_instance
482    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
483    ldr    r2, [sp, #32]                 @ pass referrer
484    mov    r3, r9                        @ pass Thread::Current
485    mov    r12, sp
486    str    r12, [sp, #-16]!              @ expand the frame and pass SP
487    bl     artGet32InstanceFromCode      @ (field_idx, Object*, referrer, Thread*, SP)
488    add    sp, #16                       @ strip the extra frame
489    ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
490    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
491    cbnz   r1, 1f                        @ success if no exception pending
492    bx     lr                            @ return on success
4931:
494    DELIVER_PENDING_EXCEPTION
495END art_quick_get32_instance
496
497    /*
498     * Called by managed code to resolve an instance field and load a 64-bit primitive value.
499     */
500    .extern artGet64InstanceFromCode
501ENTRY art_quick_get64_instance
502    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
503    ldr    r2, [sp, #32]                 @ pass referrer
504    mov    r3, r9                        @ pass Thread::Current
505    mov    r12, sp
506    str    r12, [sp, #-16]!              @ expand the frame and pass SP
507    .pad #16
508    .cfi_adjust_cfa_offset 16
509    bl     artGet64InstanceFromCode      @ (field_idx, Object*, referrer, Thread*, SP)
510    add    sp, #16                       @ strip the extra frame
511    .cfi_adjust_cfa_offset -16
512    ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
513    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
514    cbnz   r2, 1f                        @ success if no exception pending
515    bx     lr                            @ return on success
5161:
517    DELIVER_PENDING_EXCEPTION
518END art_quick_get64_instance
519
520    /*
521     * Called by managed code to resolve an instance field and load an object reference.
522     */
523    .extern artGetObjInstanceFromCode
524ENTRY art_quick_get_obj_instance
525    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
526    ldr    r2, [sp, #32]                 @ pass referrer
527    mov    r3, r9                        @ pass Thread::Current
528    mov    r12, sp
529    str    r12, [sp, #-16]!              @ expand the frame and pass SP
530    .pad #16
531    .cfi_adjust_cfa_offset 16
532    bl     artGetObjInstanceFromCode     @ (field_idx, Object*, referrer, Thread*, SP)
533    add    sp, #16                       @ strip the extra frame
534    .cfi_adjust_cfa_offset -16
535    ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
536    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
537    cbnz   r1, 1f                        @ success if no exception pending
538    bx     lr                            @ return on success
5391:
540    DELIVER_PENDING_EXCEPTION
541END art_quick_get_obj_instance
542
543    /*
544     * Called by managed code to resolve a static field and store a 32-bit primitive value.
545     */
546    .extern artSet32StaticFromCode
547ENTRY art_quick_set32_static
548    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
549    ldr    r2, [sp, #32]                 @ pass referrer
550    mov    r3, r9                        @ pass Thread::Current
551    mov    r12, sp
552    str    r12, [sp, #-16]!              @ expand the frame and pass SP
553    .pad #16
554    .cfi_adjust_cfa_offset 16
555    bl     artSet32StaticFromCode        @ (field_idx, new_val, referrer, Thread*, SP)
556    add    sp, #16                       @ strip the extra frame
557    .cfi_adjust_cfa_offset -16
558    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
559    RETURN_IF_RESULT_IS_ZERO
560    DELIVER_PENDING_EXCEPTION
561END art_quick_set32_static
562
563    /*
564     * Called by managed code to resolve a static field and store a 64-bit primitive value.
565     * On entry r0 holds field index, r1:r2 hold new_val
566     */
567    .extern artSet64StaticFromCode
568ENTRY art_quick_set64_static
569    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
570    mov    r3, r2                        @ pass one half of wide argument
571    mov    r2, r1                        @ pass other half of wide argument
572    ldr    r1, [sp, #32]                 @ pass referrer
573    mov    r12, sp                       @ save SP
574    sub    sp, #8                        @ grow frame for alignment with stack args
575    .pad #8
576    .cfi_adjust_cfa_offset 8
577    push   {r9, r12}                     @ pass Thread::Current and SP
578    .save {r9, r12}
579    .cfi_adjust_cfa_offset 8
580    .cfi_rel_offset r9, 0
581    bl     artSet64StaticFromCode        @ (field_idx, referrer, new_val, Thread*, SP)
582    add    sp, #16                       @ release out args
583    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
584    RETURN_IF_RESULT_IS_ZERO
585    DELIVER_PENDING_EXCEPTION
586END art_quick_set64_static
587
588    /*
589     * Called by managed code to resolve a static field and store an object reference.
590     */
591    .extern artSetObjStaticFromCode
592ENTRY art_quick_set_obj_static
593    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
594    ldr    r2, [sp, #32]                 @ pass referrer
595    mov    r3, r9                        @ pass Thread::Current
596    mov    r12, sp
597    str    r12, [sp, #-16]!              @ expand the frame and pass SP
598    .pad #16
599    .cfi_adjust_cfa_offset 16
600    bl     artSetObjStaticFromCode       @ (field_idx, new_val, referrer, Thread*, SP)
601    add    sp, #16                       @ strip the extra frame
602    .cfi_adjust_cfa_offset -16
603    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
604    RETURN_IF_RESULT_IS_ZERO
605    DELIVER_PENDING_EXCEPTION
606END art_quick_set_obj_static
607
608    /*
609     * Called by managed code to resolve an instance field and store a 32-bit primitive value.
610     */
611    .extern artSet32InstanceFromCode
612ENTRY art_quick_set32_instance
613    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
614    ldr    r3, [sp, #32]                 @ pass referrer
615    mov    r12, sp                       @ save SP
616    sub    sp, #8                        @ grow frame for alignment with stack args
617    .pad #8
618    .cfi_adjust_cfa_offset 8
619    push   {r9, r12}                     @ pass Thread::Current and SP
620    .save {r9, r12}
621    .cfi_adjust_cfa_offset 8
622    .cfi_rel_offset r9, 0
623    .cfi_rel_offset r12, 4
624    bl     artSet32InstanceFromCode      @ (field_idx, Object*, new_val, referrer, Thread*, SP)
625    add    sp, #16                       @ release out args
626    .cfi_adjust_cfa_offset -16
627    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
628    RETURN_IF_RESULT_IS_ZERO
629    DELIVER_PENDING_EXCEPTION
630END art_quick_set32_instance
631
632    /*
633     * Called by managed code to resolve an instance field and store a 64-bit primitive value.
634     */
635    .extern artSet32InstanceFromCode
636ENTRY art_quick_set64_instance
637    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
638    mov    r12, sp                       @ save SP
639    sub    sp, #8                        @ grow frame for alignment with stack args
640    .pad #8
641    .cfi_adjust_cfa_offset 8
642    push   {r9, r12}                     @ pass Thread::Current and SP
643    .save {r9, r12}
644    .cfi_adjust_cfa_offset 8
645    .cfi_rel_offset r9, 0
646    bl     artSet64InstanceFromCode      @ (field_idx, Object*, new_val, Thread*, SP)
647    add    sp, #16                       @ release out args
648    .cfi_adjust_cfa_offset -16
649    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
650    RETURN_IF_RESULT_IS_ZERO
651    DELIVER_PENDING_EXCEPTION
652END art_quick_set64_instance
653
654    /*
655     * Called by managed code to resolve an instance field and store an object reference.
656     */
657    .extern artSetObjInstanceFromCode
658ENTRY art_quick_set_obj_instance
659    SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
660    ldr    r3, [sp, #32]                 @ pass referrer
661    mov    r12, sp                       @ save SP
662    sub    sp, #8                        @ grow frame for alignment with stack args
663    .pad #8
664    .cfi_adjust_cfa_offset 8
665    push   {r9, r12}                     @ pass Thread::Current and SP
666    .save {r9, r12}
667    .cfi_adjust_cfa_offset 8
668    .cfi_rel_offset r9, 0
669    bl     artSetObjInstanceFromCode     @ (field_idx, Object*, new_val, referrer, Thread*, SP)
670    add    sp, #16                       @ release out args
671    .cfi_adjust_cfa_offset -16
672    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
673    RETURN_IF_RESULT_IS_ZERO
674    DELIVER_PENDING_EXCEPTION
675END art_quick_set_obj_instance
676
677    /*
678     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
679     * exception on error. On success the String is returned. R0 holds the referring method,
680     * R1 holds the string index. The fast path check for hit in strings cache has already been
681     * performed.
682     */
683    .extern artResolveStringFromCode
684ENTRY art_quick_resolve_string
685    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
686    mov    r2, r9                     @ pass Thread::Current
687    mov    r3, sp                     @ pass SP
688    @ artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*, SP)
689    bl     artResolveStringFromCode
690    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
691    RETURN_IF_RESULT_IS_NON_ZERO
692    DELIVER_PENDING_EXCEPTION
693END art_quick_resolve_string
694
695    /*
696     * Called by managed code to allocate an object
697     */
698    .extern artAllocObjectFromCode
699ENTRY art_quick_alloc_object
700    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
701    mov    r2, r9                     @ pass Thread::Current
702    mov    r3, sp                     @ pass SP
703    bl     artAllocObjectFromCode     @ (uint32_t type_idx, Method* method, Thread*, SP)
704    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
705    RETURN_IF_RESULT_IS_NON_ZERO
706    DELIVER_PENDING_EXCEPTION
707END art_quick_alloc_object
708
709    /*
710     * Called by managed code to allocate an object when the caller doesn't know whether it has
711     * access to the created type.
712     */
713    .extern artAllocObjectFromCodeWithAccessCheck
714ENTRY art_quick_alloc_object_with_access_check
715    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
716    mov    r2, r9                     @ pass Thread::Current
717    mov    r3, sp                     @ pass SP
718    bl     artAllocObjectFromCodeWithAccessCheck  @ (uint32_t type_idx, Method* method, Thread*, SP)
719    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
720    RETURN_IF_RESULT_IS_NON_ZERO
721    DELIVER_PENDING_EXCEPTION
722END art_quick_alloc_object_with_access_check
723
724    /*
725     * Called by managed code to allocate an array.
726     */
727    .extern artAllocArrayFromCode
728ENTRY art_quick_alloc_array
729    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
730    mov    r3, r9                     @ pass Thread::Current
731    mov    r12, sp
732    str    r12, [sp, #-16]!           @ expand the frame and pass SP
733    .pad #16
734    .cfi_adjust_cfa_offset 16
735    @ artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count, Thread*, SP)
736    bl     artAllocArrayFromCode
737    add    sp, #16                    @ strip the extra frame
738    .cfi_adjust_cfa_offset -16
739    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
740    RETURN_IF_RESULT_IS_NON_ZERO
741    DELIVER_PENDING_EXCEPTION
742END art_quick_alloc_array
743
744    /*
745     * Called by managed code to allocate an array when the caller doesn't know whether it has
746     * access to the created type.
747     */
748    .extern artAllocArrayFromCodeWithAccessCheck
749ENTRY art_quick_alloc_array_with_access_check
750    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
751    mov    r3, r9                     @ pass Thread::Current
752    mov    r12, sp
753    str    r12, [sp, #-16]!           @ expand the frame and pass SP
754    .pad #16
755    .cfi_adjust_cfa_offset 16
756    @ artAllocArrayFromCodeWithAccessCheck(type_idx, method, component_count, Thread*, SP)
757    bl     artAllocArrayFromCodeWithAccessCheck
758    add    sp, #16                    @ strip the extra frame
759    .cfi_adjust_cfa_offset -16
760    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
761    RETURN_IF_RESULT_IS_NON_ZERO
762    DELIVER_PENDING_EXCEPTION
763END art_quick_alloc_array_with_access_check
764
765    /*
766     * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
767     */
768    .extern artCheckAndAllocArrayFromCode
769ENTRY art_quick_check_and_alloc_array
770    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
771    mov    r3, r9                     @ pass Thread::Current
772    mov    r12, sp
773    str    r12, [sp, #-16]!           @ expand the frame and pass SP
774    .pad #16
775    .cfi_adjust_cfa_offset 16
776    @ artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t count, Thread* , SP)
777    bl     artCheckAndAllocArrayFromCode
778    add    sp, #16                    @ strip the extra frame
779    .cfi_adjust_cfa_offset -16
780    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
781    RETURN_IF_RESULT_IS_NON_ZERO
782    DELIVER_PENDING_EXCEPTION
783END art_quick_check_and_alloc_array
784
785    /*
786     * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
787     */
788    .extern artCheckAndAllocArrayFromCodeWithAccessCheck
789ENTRY art_quick_check_and_alloc_array_with_access_check
790    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
791    mov    r3, r9                     @ pass Thread::Current
792    mov    r12, sp
793    str    r12, [sp, #-16]!           @ expand the frame and pass SP
794    .pad #16
795    .cfi_adjust_cfa_offset 16
796    @ artCheckAndAllocArrayFromCodeWithAccessCheck(type_idx, method, count, Thread* , SP)
797    bl     artCheckAndAllocArrayFromCodeWithAccessCheck
798    add    sp, #16                    @ strip the extra frame
799    .cfi_adjust_cfa_offset -16
800    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
801    RETURN_IF_RESULT_IS_NON_ZERO
802    DELIVER_PENDING_EXCEPTION
803END art_quick_check_and_alloc_array_with_access_check
804
805    /*
806     * Called by managed code when the value in rSUSPEND has been decremented to 0.
807     */
808    .extern artTestSuspendFromCode
809ENTRY art_quick_test_suspend
810    ldrh    r0, [rSELF, #THREAD_FLAGS_OFFSET]
811    mov    rSUSPEND, #SUSPEND_CHECK_INTERVAL  @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL
812    cbnz   r0, 1f                             @ check Thread::Current()->suspend_count_ == 0
813    bx     lr                                 @ return if suspend_count_ == 0
8141:
815    mov    r0, rSELF
816    SETUP_REF_ONLY_CALLEE_SAVE_FRAME          @ save callee saves for stack crawl
817    mov    r1, sp
818    bl     artTestSuspendFromCode             @ (Thread*, SP)
819    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
820END art_quick_test_suspend
821
822    /*
823     * Called by managed code that is attempting to call a method on a proxy class. On entry
824     * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
825     * frame size of the invoked proxy method agrees with a ref and args callee save frame.
826     */
827     .extern artQuickProxyInvokeHandler
828ENTRY art_quick_proxy_invoke_handler
829    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
830    str     r0, [sp, #0]           @ place proxy method at bottom of frame
831    mov     r2, r9                 @ pass Thread::Current
832    mov     r3, sp                 @ pass SP
833    blx     artQuickProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
834    ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
835    ldr     lr,  [sp, #44]         @ restore lr
836    add     sp,  #48               @ pop frame
837    .cfi_adjust_cfa_offset -48
838    cbnz    r2, 1f                 @ success if no exception is pending
839    bx      lr                     @ return on success
8401:
841    DELIVER_PENDING_EXCEPTION
842END art_quick_proxy_invoke_handler
843
844    .extern artQuickResolutionTrampoline
845ENTRY art_quick_resolution_trampoline
846    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
847    mov     r2, r9                 @ pass Thread::Current
848    mov     r3, sp                 @ pass SP
849    blx     artQuickResolutionTrampoline  @ (Method* called, receiver, Thread*, SP)
850    cbz     r0, 1f                 @ is code pointer null? goto exception
851    mov     r12, r0
852    ldr  r0, [sp, #0]              @ load resolved method in r0
853    ldr  r1, [sp, #8]              @ restore non-callee save r1
854    ldrd r2, [sp, #12]             @ restore non-callee saves r2-r3
855    ldr  lr, [sp, #44]             @ restore lr
856    add  sp, #48                   @ rewind sp
857    .cfi_adjust_cfa_offset -48
858    bx      r12                    @ tail-call into actual code
8591:
860    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
861    DELIVER_PENDING_EXCEPTION
862END art_quick_resolution_trampoline
863
864    .extern artQuickToInterpreterBridge
865ENTRY art_quick_to_interpreter_bridge
866    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
867    mov     r1, r9                 @ pass Thread::Current
868    mov     r2, sp                 @ pass SP
869    blx     artQuickToInterpreterBridge    @ (Method* method, Thread*, SP)
870    ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
871    ldr     lr,  [sp, #44]         @ restore lr
872    add     sp,  #48               @ pop frame
873    .cfi_adjust_cfa_offset -48
874    cbnz    r2, 1f                 @ success if no exception is pending
875    bx    lr                       @ return on success
8761:
877    DELIVER_PENDING_EXCEPTION
878END art_quick_to_interpreter_bridge
879
880    /*
881     * Routine that intercepts method calls and returns.
882     */
883    .extern artInstrumentationMethodEntryFromCode
884    .extern artInstrumentationMethodExitFromCode
885ENTRY art_quick_instrumentation_entry
886    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
887    str   r0, [sp, #4]     @ preserve r0
888    mov   r12, sp          @ remember sp
889    str   lr, [sp, #-16]!  @ expand the frame and pass LR
890    .pad #16
891    .cfi_adjust_cfa_offset 16
892    .cfi_rel_offset lr, 0
893    mov   r2, r9         @ pass Thread::Current
894    mov   r3, r12        @ pass SP
895    blx   artInstrumentationMethodEntryFromCode  @ (Method*, Object*, Thread*, SP, LR)
896    add   sp, #16        @ remove out argument and padding from stack
897    .cfi_adjust_cfa_offset -16
898    mov   r12, r0        @ r12 holds reference to code
899    ldr   r0, [sp, #4]   @ restore r0
900    RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
901    blx   r12            @ call method with lr set to art_quick_instrumentation_exit
902END art_quick_instrumentation_entry
903    .type art_quick_instrumentation_exit, #function
904    .global art_quick_instrumentation_exit
905art_quick_instrumentation_exit:
906    .cfi_startproc
907    .fnstart
908    mov   lr, #0         @ link register is to here, so clobber with 0 for later checks
909    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
910    mov   r12, sp        @ remember bottom of caller's frame
911    push  {r0-r1}        @ save return value
912    .save {r0-r1}
913    .cfi_adjust_cfa_offset 8
914    .cfi_rel_offset r0, 0
915    .cfi_rel_offset r1, 4
916    sub   sp, #8         @ space for return value argument
917    .pad #8
918    .cfi_adjust_cfa_offset 8
919    strd r0, [sp]        @ r0/r1 -> [sp] for fpr_res
920    mov   r2, r0         @ pass return value as gpr_res
921    mov   r3, r1
922    mov   r0, r9         @ pass Thread::Current
923    mov   r1, r12        @ pass SP
924    blx   artInstrumentationMethodExitFromCode  @ (Thread*, SP, gpr_res, fpr_res)
925    add   sp, #8
926    .cfi_adjust_cfa_offset -8
927
928    mov   r2, r0         @ link register saved by instrumentation
929    mov   lr, r1         @ r1 is holding link register if we're to bounce to deoptimize
930    pop   {r0, r1}       @ restore return value
931    add sp, #32          @ remove callee save frame
932    .cfi_adjust_cfa_offset -32
933    bx    r2             @ return
934END art_quick_instrumentation_exit
935
936    /*
937     * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
938     * will long jump to the upcall with a special exception of -1.
939     */
940    .extern artDeoptimize
941ENTRY art_quick_deoptimize
942    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
943    mov    r0, r9         @ Set up args.
944    mov    r1, sp
945    blx    artDeoptimize  @ artDeoptimize(Thread*, SP)
946END art_quick_deoptimize
947
948    /*
949     * Signed 64-bit integer multiply.
950     *
951     * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
952     *        WX
953     *      x YZ
954     *  --------
955     *     ZW ZX
956     *  YW YX
957     *
958     * The low word of the result holds ZX, the high word holds
959     * (ZW+YX) + (the high overflow from ZX).  YW doesn't matter because
960     * it doesn't fit in the low 64 bits.
961     *
962     * Unlike most ARM math operations, multiply instructions have
963     * restrictions on using the same register more than once (Rd and Rm
964     * cannot be the same).
965     */
966    /* mul-long vAA, vBB, vCC */
967ENTRY art_quick_mul_long
968    push    {r9 - r10}
969    .save {r9 - r10}
970    .cfi_adjust_cfa_offset 8
971    .cfi_rel_offset r9, 0
972    .cfi_rel_offset r10, 4
973    mul     ip, r2, r1                  @  ip<- ZxW
974    umull   r9, r10, r2, r0             @  r9/r10 <- ZxX
975    mla     r2, r0, r3, ip              @  r2<- YxX + (ZxW)
976    add     r10, r2, r10                @  r10<- r10 + low(ZxW + (YxX))
977    mov     r0,r9
978    mov     r1,r10
979    pop     {r9 - r10}
980    .cfi_adjust_cfa_offset -8
981    bx      lr
982END art_quick_mul_long
983
984    /*
985     * Long integer shift.  This is different from the generic 32/64-bit
986     * binary operations because vAA/vBB are 64-bit but vCC (the shift
987     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
988     * 6 bits.
989     * On entry:
990     *   r0: low word
991     *   r1: high word
992     *   r2: shift count
993     */
994    /* shl-long vAA, vBB, vCC */
995ARM_ENTRY art_quick_shl_long            @ ARM code as thumb code requires spills
996    and     r2, r2, #63                 @ r2<- r2 & 0x3f
997    mov     r1, r1, asl r2              @  r1<- r1 << r2
998    rsb     r3, r2, #32                 @  r3<- 32 - r2
999    orr     r1, r1, r0, lsr r3          @  r1<- r1 | (r0 << (32-r2))
1000    subs    ip, r2, #32                 @  ip<- r2 - 32
1001    movpl   r1, r0, asl ip              @  if r2 >= 32, r1<- r0 << (r2-32)
1002    mov     r0, r0, asl r2              @  r0<- r0 << r2
1003    bx      lr
1004END art_quick_shl_long
1005
1006    /*
1007     * Long integer shift.  This is different from the generic 32/64-bit
1008     * binary operations because vAA/vBB are 64-bit but vCC (the shift
1009     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
1010     * 6 bits.
1011     * On entry:
1012     *   r0: low word
1013     *   r1: high word
1014     *   r2: shift count
1015     */
1016    /* shr-long vAA, vBB, vCC */
1017ARM_ENTRY art_quick_shr_long            @ ARM code as thumb code requires spills
1018    and     r2, r2, #63                 @ r0<- r0 & 0x3f
1019    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
1020    rsb     r3, r2, #32                 @  r3<- 32 - r2
1021    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
1022    subs    ip, r2, #32                 @  ip<- r2 - 32
1023    movpl   r0, r1, asr ip              @  if r2 >= 32, r0<-r1 >> (r2-32)
1024    mov     r1, r1, asr r2              @  r1<- r1 >> r2
1025    bx      lr
1026END art_quick_shr_long
1027
1028    /*
1029     * Long integer shift.  This is different from the generic 32/64-bit
1030     * binary operations because vAA/vBB are 64-bit but vCC (the shift
1031     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
1032     * 6 bits.
1033     * On entry:
1034     *   r0: low word
1035     *   r1: high word
1036     *   r2: shift count
1037     */
1038    /* ushr-long vAA, vBB, vCC */
1039ARM_ENTRY art_quick_ushr_long           @ ARM code as thumb code requires spills
1040    and     r2, r2, #63                 @ r0<- r0 & 0x3f
1041    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
1042    rsb     r3, r2, #32                 @  r3<- 32 - r2
1043    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
1044    subs    ip, r2, #32                 @  ip<- r2 - 32
1045    movpl   r0, r1, lsr ip              @  if r2 >= 32, r0<-r1 >>> (r2-32)
1046    mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
1047    bx      lr
1048END art_quick_ushr_long
1049
1050    /*
1051     * String's indexOf.
1052     *
1053     * On entry:
1054     *    r0:   string object (known non-null)
1055     *    r1:   char to match (known <= 0xFFFF)
1056     *    r2:   Starting offset in string data
1057     */
1058ENTRY art_quick_indexof
1059    push {r4, r10-r11, lr} @ 4 words of callee saves
1060    .save {r4, r10-r11, lr}
1061    .cfi_adjust_cfa_offset 16
1062    .cfi_rel_offset r4, 0
1063    .cfi_rel_offset r10, 4
1064    .cfi_rel_offset r11, 8
1065    .cfi_rel_offset lr, 12
1066    ldr   r3, [r0, #STRING_COUNT_OFFSET]
1067    ldr   r12, [r0, #STRING_OFFSET_OFFSET]
1068    ldr   r0, [r0, #STRING_VALUE_OFFSET]
1069
1070    /* Clamp start to [0..count] */
1071    cmp   r2, #0
1072    it    lt
1073    movlt r2, #0
1074    cmp   r2, r3
1075    it    gt
1076    movgt r2, r3
1077
1078    /* Build a pointer to the start of string data */
1079    add   r0, #STRING_DATA_OFFSET
1080    add   r0, r0, r12, lsl #1
1081
1082    /* Save a copy in r12 to later compute result */
1083    mov   r12, r0
1084
1085    /* Build pointer to start of data to compare and pre-bias */
1086    add   r0, r0, r2, lsl #1
1087    sub   r0, #2
1088
1089    /* Compute iteration count */
1090    sub   r2, r3, r2
1091
1092    /*
1093     * At this point we have:
1094     *   r0: start of data to test
1095     *   r1: char to compare
1096     *   r2: iteration count
1097     *   r12: original start of string data
1098     *   r3, r4, r10, r11 available for loading string data
1099     */
1100
1101    subs  r2, #4
1102    blt   indexof_remainder
1103
1104indexof_loop4:
1105    ldrh  r3, [r0, #2]!
1106    ldrh  r4, [r0, #2]!
1107    ldrh  r10, [r0, #2]!
1108    ldrh  r11, [r0, #2]!
1109    cmp   r3, r1
1110    beq   match_0
1111    cmp   r4, r1
1112    beq   match_1
1113    cmp   r10, r1
1114    beq   match_2
1115    cmp   r11, r1
1116    beq   match_3
1117    subs  r2, #4
1118    bge   indexof_loop4
1119
1120indexof_remainder:
1121    adds    r2, #4
1122    beq     indexof_nomatch
1123
1124indexof_loop1:
1125    ldrh  r3, [r0, #2]!
1126    cmp   r3, r1
1127    beq   match_3
1128    subs  r2, #1
1129    bne   indexof_loop1
1130
1131indexof_nomatch:
1132    mov   r0, #-1
1133    pop {r4, r10-r11, pc}
1134
1135match_0:
1136    sub   r0, #6
1137    sub   r0, r12
1138    asr   r0, r0, #1
1139    pop {r4, r10-r11, pc}
1140match_1:
1141    sub   r0, #4
1142    sub   r0, r12
1143    asr   r0, r0, #1
1144    pop {r4, r10-r11, pc}
1145match_2:
1146    sub   r0, #2
1147    sub   r0, r12
1148    asr   r0, r0, #1
1149    pop {r4, r10-r11, pc}
1150match_3:
1151    sub   r0, r12
1152    asr   r0, r0, #1
1153    pop {r4, r10-r11, pc}
1154END art_quick_indexof
1155
1156   /*
1157     * String's compareTo.
1158     *
1159     * Requires rARG0/rARG1 to have been previously checked for null.  Will
1160     * return negative if this's string is < comp, 0 if they are the
1161     * same and positive if >.
1162     *
1163     * On entry:
1164     *    r0:   this object pointer
1165     *    r1:   comp object pointer
1166     *
1167     */
1168    .extern __memcmp16
1169ENTRY art_quick_string_compareto
1170    mov    r2, r0         @ this to r2, opening up r0 for return value
1171    sub    r0, r2, r1     @ Same?
1172    cbnz   r0,1f
1173    bx     lr
11741:                        @ Same strings, return.
1175
1176    push {r4, r7-r12, lr} @ 8 words - keep alignment
1177    .save {r4, r7-r12, lr}
1178    .cfi_adjust_cfa_offset 32
1179    .cfi_rel_offset r4, 0
1180    .cfi_rel_offset r7, 4
1181    .cfi_rel_offset r8, 8
1182    .cfi_rel_offset r9, 12
1183    .cfi_rel_offset r10, 16
1184    .cfi_rel_offset r11, 20
1185    .cfi_rel_offset r12, 24
1186    .cfi_rel_offset lr, 28
1187
1188    ldr    r4, [r2, #STRING_OFFSET_OFFSET]
1189    ldr    r9, [r1, #STRING_OFFSET_OFFSET]
1190    ldr    r7, [r2, #STRING_COUNT_OFFSET]
1191    ldr    r10, [r1, #STRING_COUNT_OFFSET]
1192    ldr    r2, [r2, #STRING_VALUE_OFFSET]
1193    ldr    r1, [r1, #STRING_VALUE_OFFSET]
1194
1195    /*
1196     * At this point, we have:
1197     *    value:  r2/r1
1198     *    offset: r4/r9
1199     *    count:  r7/r10
1200     * We're going to compute
1201     *    r11 <- countDiff
1202     *    r10 <- minCount
1203     */
1204     subs  r11, r7, r10
1205     it    ls
1206     movls r10, r7
1207
1208     /* Now, build pointers to the string data */
1209     add   r2, r2, r4, lsl #1
1210     add   r1, r1, r9, lsl #1
1211     /*
1212      * Note: data pointers point to previous element so we can use pre-index
1213      * mode with base writeback.
1214      */
1215     add   r2, #STRING_DATA_OFFSET-2   @ offset to contents[-1]
1216     add   r1, #STRING_DATA_OFFSET-2   @ offset to contents[-1]
1217
1218     /*
1219      * At this point we have:
1220      *   r2: *this string data
1221      *   r1: *comp string data
1222      *   r10: iteration count for comparison
1223      *   r11: value to return if the first part of the string is equal
1224      *   r0: reserved for result
1225      *   r3, r4, r7, r8, r9, r12 available for loading string data
1226      */
1227
1228    subs  r10, #2
1229    blt   do_remainder2
1230
1231      /*
1232       * Unroll the first two checks so we can quickly catch early mismatch
1233       * on long strings (but preserve incoming alignment)
1234       */
1235
1236    ldrh  r3, [r2, #2]!
1237    ldrh  r4, [r1, #2]!
1238    ldrh  r7, [r2, #2]!
1239    ldrh  r8, [r1, #2]!
1240    subs  r0, r3, r4
1241    it    eq
1242    subseq  r0, r7, r8
1243    bne   done
1244    cmp   r10, #28
1245    bgt   do_memcmp16
1246    subs  r10, #3
1247    blt   do_remainder
1248
1249loopback_triple:
1250    ldrh  r3, [r2, #2]!
1251    ldrh  r4, [r1, #2]!
1252    ldrh  r7, [r2, #2]!
1253    ldrh  r8, [r1, #2]!
1254    ldrh  r9, [r2, #2]!
1255    ldrh  r12,[r1, #2]!
1256    subs  r0, r3, r4
1257    it    eq
1258    subseq  r0, r7, r8
1259    it    eq
1260    subseq  r0, r9, r12
1261    bne   done
1262    subs  r10, #3
1263    bge   loopback_triple
1264
1265do_remainder:
1266    adds  r10, #3
1267    beq   returnDiff
1268
1269loopback_single:
1270    ldrh  r3, [r2, #2]!
1271    ldrh  r4, [r1, #2]!
1272    subs  r0, r3, r4
1273    bne   done
1274    subs  r10, #1
1275    bne     loopback_single
1276
1277returnDiff:
1278    mov   r0, r11
1279    pop   {r4, r7-r12, pc}
1280
1281do_remainder2:
1282    adds  r10, #2
1283    bne   loopback_single
1284    mov   r0, r11
1285    pop   {r4, r7-r12, pc}
1286
1287    /* Long string case */
1288do_memcmp16:
1289    mov   r7, r11
1290    add   r0, r2, #2
1291    add   r1, r1, #2
1292    mov   r2, r10
1293    bl    __memcmp16
1294    cmp   r0, #0
1295    it    eq
1296    moveq r0, r7
1297done:
1298    pop   {r4, r7-r12, pc}
1299END art_quick_string_compareto
1300