• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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#include "arch/quick_alloc_entrypoints.S"
20
21    /* Deliver the given exception */
22    .extern artDeliverExceptionFromCode
23    /* Deliver an exception pending on a thread */
24    .extern artDeliverPendingException
25
26    /*
27     * Macro to spill the GPRs.
28     */
29.macro SPILL_ALL_CALLEE_SAVE_GPRS
30    push {r4-r11, lr}                             @ 9 words (36 bytes) of callee saves.
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.endm
42
43    /*
44     * Macro that sets up the callee save frame to conform with
45     * Runtime::CreateCalleeSaveMethod(kSaveAll)
46     */
47.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME rTemp1, rTemp2
48    SPILL_ALL_CALLEE_SAVE_GPRS                    @ 9 words (36 bytes) of callee saves.
49    vpush {s16-s31}                               @ 16 words (64 bytes) of floats.
50    .cfi_adjust_cfa_offset 64
51    sub sp, #12                                   @ 3 words of space, bottom word will hold Method*
52    .cfi_adjust_cfa_offset 12
53    RUNTIME_CURRENT1 \rTemp1, \rTemp2             @ Load Runtime::Current into rTemp1.
54    ldr \rTemp1, [\rTemp1, #RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kSaveAll Method*.
55    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
56    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
57
58     // Ugly compile-time check, but we only have the preprocessor.
59#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 36 + 64 + 12)
60#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM) size not as expected."
61#endif
62.endm
63
64    /*
65     * Macro that sets up the callee save frame to conform with
66     * Runtime::CreateCalleeSaveMethod(kRefsOnly).
67     */
68.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME rTemp1, rTemp2
69    push {r5-r8, r10-r11, lr}                     @ 7 words of callee saves
70    .cfi_adjust_cfa_offset 28
71    .cfi_rel_offset r5, 0
72    .cfi_rel_offset r6, 4
73    .cfi_rel_offset r7, 8
74    .cfi_rel_offset r8, 12
75    .cfi_rel_offset r10, 16
76    .cfi_rel_offset r11, 20
77    .cfi_rel_offset lr, 24
78    sub sp, #4                                    @ bottom word will hold Method*
79    .cfi_adjust_cfa_offset 4
80    RUNTIME_CURRENT2 \rTemp1, \rTemp2             @ Load Runtime::Current into rTemp1.
81    ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kRefsOnly Method*.
82    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
83    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
84
85    // Ugly compile-time check, but we only have the preprocessor.
86#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 28 + 4)
87#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM) size not as expected."
88#endif
89.endm
90
91    /*
92     * Macro that sets up the callee save frame to conform with
93     * Runtime::CreateCalleeSaveMethod(kRefsOnly)
94     * and preserves the value of rTemp2 at entry.
95     */
96.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME_PRESERVE_RTEMP2 rTemp1, rTemp2
97    push {r5-r8, r10-r11, lr}                     @ 7 words of callee saves
98    .cfi_adjust_cfa_offset 28
99    .cfi_rel_offset r5, 0
100    .cfi_rel_offset r6, 4
101    .cfi_rel_offset r7, 8
102    .cfi_rel_offset r8, 12
103    .cfi_rel_offset r10, 16
104    .cfi_rel_offset r11, 20
105    .cfi_rel_offset lr, 24
106    sub sp, #4                                    @ bottom word will hold Method*
107    .cfi_adjust_cfa_offset 4
108    str \rTemp2, [sp, #0]                         @ save rTemp2
109    RUNTIME_CURRENT2 \rTemp1, \rTemp2             @ Load Runtime::Current into rTemp1.
110    ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kRefsOnly Method*.
111    ldr \rTemp2, [sp, #0]                         @ restore rTemp2
112    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
113    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
114
115    // Ugly compile-time check, but we only have the preprocessor.
116#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 28 + 4)
117#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM) size not as expected."
118#endif
119.endm
120
121.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
122    add sp, #4               @ bottom word holds Method*
123    .cfi_adjust_cfa_offset -4
124    pop {r5-r8, r10-r11, lr} @ 7 words of callee saves
125    .cfi_restore r5
126    .cfi_restore r6
127    .cfi_restore r7
128    .cfi_restore r8
129    .cfi_restore r10
130    .cfi_restore r11
131    .cfi_restore lr
132    .cfi_adjust_cfa_offset -28
133.endm
134
135.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
136    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
137    bx  lr                   @ return
138.endm
139
140    /*
141     * Macro that sets up the callee save frame to conform with
142     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs).
143     */
144.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
145    push {r1-r3, r5-r8, r10-r11, lr}   @ 10 words of callee saves and args.
146    .cfi_adjust_cfa_offset 40
147    .cfi_rel_offset r1, 0
148    .cfi_rel_offset r2, 4
149    .cfi_rel_offset r3, 8
150    .cfi_rel_offset r5, 12
151    .cfi_rel_offset r6, 16
152    .cfi_rel_offset r7, 20
153    .cfi_rel_offset r8, 24
154    .cfi_rel_offset r10, 28
155    .cfi_rel_offset r11, 32
156    .cfi_rel_offset lr, 36
157    vpush {s0-s15}                     @ 16 words of float args.
158    .cfi_adjust_cfa_offset 64
159    sub sp, #8                         @ 2 words of space, bottom word will hold Method*
160    .cfi_adjust_cfa_offset 8
161    // Ugly compile-time check, but we only have the preprocessor.
162#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 40 + 64 + 8)
163#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM) size not as expected."
164#endif
165.endm
166
167.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME rTemp1, rTemp2
168    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
169    RUNTIME_CURRENT3 \rTemp1, \rTemp2  @ Load Runtime::Current into rTemp1.
170     @ rTemp1 is kRefsAndArgs Method*.
171    ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET]
172    str \rTemp1, [sp, #0]                         @ Place Method* at bottom of stack.
173    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
174.endm
175
176.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
177    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY
178    str r0, [sp, #0]                   @ Store ArtMethod* to bottom of stack.
179    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
180.endm
181
182.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
183    add  sp, #8                      @ rewind sp
184    .cfi_adjust_cfa_offset -8
185    vpop {s0-s15}
186    .cfi_adjust_cfa_offset -64
187    pop {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
188    .cfi_restore r1
189    .cfi_restore r2
190    .cfi_restore r3
191    .cfi_restore r5
192    .cfi_restore r6
193    .cfi_restore r7
194    .cfi_restore r8
195    .cfi_restore r10
196    .cfi_restore r11
197    .cfi_restore lr
198    .cfi_adjust_cfa_offset -40
199.endm
200
201.macro RETURN_IF_RESULT_IS_ZERO
202    cbnz   r0, 1f              @ result non-zero branch over
203    bx     lr                  @ return
2041:
205.endm
206
207.macro RETURN_IF_RESULT_IS_NON_ZERO
208    cbz    r0, 1f              @ result zero branch over
209    bx     lr                  @ return
2101:
211.endm
212
213    /*
214     * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
215     * exception is Thread::Current()->exception_
216     */
217.macro DELIVER_PENDING_EXCEPTION
218    .fnend
219    .fnstart
220    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1    @ save callee saves for throw
221    mov    r0, r9                              @ pass Thread::Current
222    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*)
223.endm
224
225.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
226    .extern \cxx_name
227ENTRY \c_name
228    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  r0, r1 // save all registers as basis for long jump context
229    mov r0, r9                      @ pass Thread::Current
230    b   \cxx_name                   @ \cxx_name(Thread*)
231END \c_name
232.endm
233
234.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
235    .extern \cxx_name
236ENTRY \c_name
237    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r1, r2  // save all registers as basis for long jump context
238    mov r1, r9                      @ pass Thread::Current
239    b   \cxx_name                   @ \cxx_name(Thread*)
240END \c_name
241.endm
242
243.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
244    .extern \cxx_name
245ENTRY \c_name
246    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  r2, r3  // save all registers as basis for long jump context
247    mov r2, r9                      @ pass Thread::Current
248    b   \cxx_name                   @ \cxx_name(Thread*)
249END \c_name
250.endm
251
252.macro  RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg
253    ldr \reg, [r9, #THREAD_EXCEPTION_OFFSET]   // Get exception field.
254    cbnz \reg, 1f
255    bx lr
2561:
257    DELIVER_PENDING_EXCEPTION
258.endm
259
260.macro  RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
261    RETURN_OR_DELIVER_PENDING_EXCEPTION_REG r1
262.endm
263
264.macro RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
265    RETURN_IF_RESULT_IS_ZERO
266    DELIVER_PENDING_EXCEPTION
267.endm
268
269.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
270    RETURN_IF_RESULT_IS_NON_ZERO
271    DELIVER_PENDING_EXCEPTION
272.endm
273
274// Macros taking opportunity of code similarities for downcalls with referrer for non-wide fields.
275.macro  ONE_ARG_REF_DOWNCALL name, entrypoint, return
276    .extern \entrypoint
277ENTRY \name
278    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2  @ save callee saves in case of GC
279    ldr    r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
280    mov    r2, r9                        @ pass Thread::Current
281    bl     \entrypoint                   @ (uint32_t field_idx, const Method* referrer, Thread*)
282    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
283    \return
284END \name
285.endm
286
287.macro  TWO_ARG_REF_DOWNCALL name, entrypoint, return
288    .extern \entrypoint
289ENTRY \name
290    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case of GC
291    ldr    r2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
292    mov    r3, r9                        @ pass Thread::Current
293    bl     \entrypoint                   @ (field_idx, Object*, referrer, Thread*)
294    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
295    \return
296END \name
297.endm
298
299.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
300    .extern \entrypoint
301ENTRY \name
302    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r3, r12  @ save callee saves in case of GC
303    ldr    r3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
304    str    r9, [sp, #-16]!               @ expand the frame and pass Thread::Current
305    .cfi_adjust_cfa_offset 16
306    bl     \entrypoint                   @ (field_idx, Object*, new_val, referrer, Thread*)
307    add    sp, #16                       @ release out args
308    .cfi_adjust_cfa_offset -16
309    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  @ TODO: we can clearly save an add here
310    \return
311END \name
312.endm
313
314    /*
315     * Called by managed code, saves callee saves and then calls artThrowException
316     * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
317     */
318ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
319
320    /*
321     * Called by managed code to create and deliver a NullPointerException.
322     */
323NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
324
325    /*
326     * Called by managed code to create and deliver an ArithmeticException.
327     */
328NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
329
330    /*
331     * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
332     * index, arg2 holds limit.
333     */
334TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
335
336    /*
337     * Called by managed code to create and deliver a StackOverflowError.
338     */
339NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
340
341    /*
342     * Called by managed code to create and deliver a NoSuchMethodError.
343     */
344ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
345
346    /*
347     * All generated callsites for interface invokes and invocation slow paths will load arguments
348     * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
349     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
350     * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
351     *
352     * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
353     * of the target Method* in r0 and method->code_ in r1.
354     *
355     * If unsuccessful, the helper will return null/null. There will bea pending exception in the
356     * thread and we branch to another stub to deliver it.
357     *
358     * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
359     * pointing back to the original caller.
360     */
361.macro INVOKE_TRAMPOLINE_BODY cxx_name
362    .extern \cxx_name
363    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case allocation triggers GC
364    mov    r2, r9                         @ pass Thread::Current
365    mov    r3, sp
366    bl     \cxx_name                      @ (method_idx, this, Thread*, SP)
367    mov    r12, r1                        @ save Method*->code_
368    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
369    cbz    r0, 1f                         @ did we find the target? if not go to exception delivery
370    bx     r12                            @ tail call to target
3711:
372    DELIVER_PENDING_EXCEPTION
373.endm
374.macro INVOKE_TRAMPOLINE c_name, cxx_name
375ENTRY \c_name
376    INVOKE_TRAMPOLINE_BODY \cxx_name
377END \c_name
378.endm
379
380INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
381
382INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
383INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
384INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
385INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
386
387    /*
388     * Quick invocation stub internal.
389     * On entry:
390     *   r0 = method pointer
391     *   r1 = argument array or null for no argument methods
392     *   r2 = size of argument array in bytes
393     *   r3 = (managed) thread pointer
394     *   [sp] = JValue* result
395     *   [sp + 4] = result_in_float
396     *   [sp + 8] = core register argument array
397     *   [sp + 12] = fp register argument array
398     *  +-------------------------+
399     *  | uint32_t* fp_reg_args   |
400     *  | uint32_t* core_reg_args |
401     *  |   result_in_float       | <- Caller frame
402     *  |   Jvalue* result        |
403     *  +-------------------------+
404     *  |          lr             |
405     *  |          r11            |
406     *  |          r9             |
407     *  |          r4             | <- r11
408     *  +-------------------------+
409     *  | uint32_t out[n-1]       |
410     *  |    :      :             |        Outs
411     *  | uint32_t out[0]         |
412     *  | StackRef<ArtMethod>     | <- SP  value=null
413     *  +-------------------------+
414     */
415ENTRY art_quick_invoke_stub_internal
416    SPILL_ALL_CALLEE_SAVE_GPRS             @ spill regs (9)
417    mov    r11, sp                         @ save the stack pointer
418    .cfi_def_cfa_register r11
419
420    mov    r9, r3                          @ move managed thread pointer into r9
421
422    add    r4, r2, #4                      @ create space for method pointer in frame
423    sub    r4, sp, r4                      @ reserve & align *stack* to 16 bytes: native calling
424    and    r4, #0xFFFFFFF0                 @ convention only aligns to 8B, so we have to ensure ART
425    mov    sp, r4                          @ 16B alignment ourselves.
426
427    mov    r4, r0                          @ save method*
428    add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
429    bl     memcpy                          @ memcpy (dest, src, bytes)
430    mov    ip, #0                          @ set ip to 0
431    str    ip, [sp]                        @ store null for method* at bottom of frame
432
433    ldr    ip, [r11, #48]                  @ load fp register argument array pointer
434    vldm   ip, {s0-s15}                    @ copy s0 - s15
435
436    ldr    ip, [r11, #44]                  @ load core register argument array pointer
437    mov    r0, r4                          @ restore method*
438    add    ip, ip, #4                      @ skip r0
439    ldm    ip, {r1-r3}                     @ copy r1 - r3
440
441#ifdef ARM_R4_SUSPEND_FLAG
442    mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval
443#endif
444
445    ldr    ip, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]  @ get pointer to the code
446    blx    ip                              @ call the method
447
448    mov    sp, r11                         @ restore the stack pointer
449    .cfi_def_cfa_register sp
450
451    ldr    r4, [sp, #40]                   @ load result_is_float
452    ldr    r9, [sp, #36]                   @ load the result pointer
453    cmp    r4, #0
454    ite    eq
455    strdeq r0, [r9]                        @ store r0/r1 into result pointer
456    vstrne d0, [r9]                        @ store s0-s1/d0 into result pointer
457
458    pop    {r4, r5, r6, r7, r8, r9, r10, r11, pc}               @ restore spill regs
459END art_quick_invoke_stub_internal
460
461    /*
462     * On stack replacement stub.
463     * On entry:
464     *   r0 = stack to copy
465     *   r1 = size of stack
466     *   r2 = pc to call
467     *   r3 = JValue* result
468     *   [sp] = shorty
469     *   [sp + 4] = thread
470     */
471ENTRY art_quick_osr_stub
472    SPILL_ALL_CALLEE_SAVE_GPRS             @ Spill regs (9)
473    mov    r11, sp                         @ Save the stack pointer
474    mov    r10, r1                         @ Save size of stack
475    ldr    r9, [r11, #40]                  @ Move managed thread pointer into r9
476    mov    r8, r2                          @ Save the pc to call
477    sub    r7, sp, #12                     @ Reserve space for stack pointer,
478                                           @    JValue* result, and ArtMethod* slot.
479    and    r7, #0xFFFFFFF0                 @ Align stack pointer
480    mov    sp, r7                          @ Update stack pointer
481    str    r11, [sp, #4]                   @ Save old stack pointer
482    str    r3, [sp, #8]                    @ Save JValue* result
483    mov    ip, #0
484    str    ip, [sp]                        @ Store null for ArtMethod* at bottom of frame
485    sub    sp, sp, r1                      @ Reserve space for callee stack
486    mov    r2, r1
487    mov    r1, r0
488    mov    r0, sp
489    bl     memcpy                          @ memcpy (dest r0, src r1, bytes r2)
490    bl     .Losr_entry                     @ Call the method
491    ldr    r10, [sp, #8]                   @ Restore JValue* result
492    ldr    sp, [sp, #4]                    @ Restore saved stack pointer
493    ldr    r4, [sp, #36]                   @ load shorty
494    ldrb   r4, [r4, #0]                    @ load return type
495    cmp    r4, #68                         @ Test if result type char == 'D'.
496    beq    .Losr_fp_result
497    cmp    r4, #70                         @ Test if result type char == 'F'.
498    beq    .Losr_fp_result
499    strd r0, [r10]                         @ Store r0/r1 into result pointer
500    b    .Losr_exit
501.Losr_fp_result:
502    vstr d0, [r10]                         @ Store s0-s1/d0 into result pointer
503.Losr_exit:
504    pop    {r4, r5, r6, r7, r8, r9, r10, r11, pc}
505.Losr_entry:
506    sub r10, r10, #4
507    str lr, [sp, r10]                     @ Store link register per the compiler ABI
508    bx r8
509END art_quick_osr_stub
510
511    /*
512     * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_
513     */
514ARM_ENTRY art_quick_do_long_jump
515    vldm r1, {s0-s31}     @ load all fprs from argument fprs_
516    ldr  r2, [r0, #60]    @ r2 = r15 (PC from gprs_ 60=4*15)
517    ldr  r14, [r0, #56]   @ (LR from gprs_ 56=4*14)
518    add  r0, r0, #12      @ increment r0 to skip gprs_[0..2] 12=4*3
519    ldm  r0, {r3-r13}     @ load remaining gprs from argument gprs_
520    ldr  r0, [r0, #-12]   @ load r0 value
521    mov  r1, #0           @ clear result register r1
522    bx   r2               @ do long jump
523END art_quick_do_long_jump
524
525    /*
526     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
527     * failure.
528     */
529TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
530
531    /*
532     * Entry from managed code that calls artLockObjectFromCode, may block for GC. r0 holds the
533     * possibly null object to lock.
534     */
535    .extern artLockObjectFromCode
536ENTRY art_quick_lock_object
537    cbz    r0, .Lslow_lock
538.Lretry_lock:
539    ldr    r2, [r9, #THREAD_ID_OFFSET]
540    ldrex  r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
541    mov    r3, r1
542    and    r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  @ zero the read barrier bits
543    cbnz   r3, .Lnot_unlocked         @ already thin locked
544    @ unlocked case - r1: original lock word that's zero except for the read barrier bits.
545    orr    r2, r1, r2                 @ r2 holds thread id with count of 0 with preserved read barrier bits
546    strex  r3, r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
547    cbnz   r3, .Llock_strex_fail      @ store failed, retry
548    dmb    ish                        @ full (LoadLoad|LoadStore) memory barrier
549    bx lr
550.Lnot_unlocked:  @ r1: original lock word, r2: thread_id with count of 0 and zero read barrier bits
551    lsr    r3, r1, LOCK_WORD_STATE_SHIFT
552    cbnz   r3, .Lslow_lock            @ if either of the top two bits are set, go slow path
553    eor    r2, r1, r2                 @ lock_word.ThreadId() ^ self->ThreadId()
554    uxth   r2, r2                     @ zero top 16 bits
555    cbnz   r2, .Lslow_lock            @ lock word and self thread id's match -> recursive lock
556                                      @ else contention, go to slow path
557    mov    r3, r1                     @ copy the lock word to check count overflow.
558    and    r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  @ zero the read barrier bits.
559    add    r2, r3, #LOCK_WORD_THIN_LOCK_COUNT_ONE  @ increment count in lock word placing in r2 to check overflow
560    lsr    r3, r2, LOCK_WORD_READ_BARRIER_STATE_SHIFT  @ if either of the upper two bits (28-29) are set, we overflowed.
561    cbnz   r3, .Lslow_lock            @ if we overflow the count go slow path
562    add    r2, r1, #LOCK_WORD_THIN_LOCK_COUNT_ONE  @ increment count for real
563    strex  r3, r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits
564    cbnz   r3, .Llock_strex_fail      @ strex failed, retry
565    bx lr
566.Llock_strex_fail:
567    b      .Lretry_lock               @ retry
568.Lslow_lock:
569    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2  @ save callee saves in case we block
570    mov    r1, r9                     @ pass Thread::Current
571    bl     artLockObjectFromCode      @ (Object* obj, Thread*)
572    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
573    RETURN_IF_RESULT_IS_ZERO
574    DELIVER_PENDING_EXCEPTION
575END art_quick_lock_object
576
577ENTRY art_quick_lock_object_no_inline
578    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2  @ save callee saves in case we block
579    mov    r1, r9                     @ pass Thread::Current
580    bl     artLockObjectFromCode      @ (Object* obj, Thread*)
581    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
582    RETURN_IF_RESULT_IS_ZERO
583    DELIVER_PENDING_EXCEPTION
584END art_quick_lock_object_no_inline
585
586    /*
587     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
588     * r0 holds the possibly null object to lock.
589     */
590    .extern artUnlockObjectFromCode
591ENTRY art_quick_unlock_object
592    cbz    r0, .Lslow_unlock
593.Lretry_unlock:
594#ifndef USE_READ_BARRIER
595    ldr    r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
596#else
597    ldrex  r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]  @ Need to use atomic instructions for read barrier
598#endif
599    lsr    r2, r1, #LOCK_WORD_STATE_SHIFT
600    cbnz   r2, .Lslow_unlock          @ if either of the top two bits are set, go slow path
601    ldr    r2, [r9, #THREAD_ID_OFFSET]
602    mov    r3, r1                     @ copy lock word to check thread id equality
603    and    r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  @ zero the read barrier bits
604    eor    r3, r3, r2                 @ lock_word.ThreadId() ^ self->ThreadId()
605    uxth   r3, r3                     @ zero top 16 bits
606    cbnz   r3, .Lslow_unlock          @ do lock word and self thread id's match?
607    mov    r3, r1                     @ copy lock word to detect transition to unlocked
608    and    r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  @ zero the read barrier bits
609    cmp    r3, #LOCK_WORD_THIN_LOCK_COUNT_ONE
610    bpl    .Lrecursive_thin_unlock
611    @ transition to unlocked
612    mov    r3, r1
613    and    r3, #LOCK_WORD_READ_BARRIER_STATE_MASK  @ r3: zero except for the preserved read barrier bits
614    dmb    ish                        @ full (LoadStore|StoreStore) memory barrier
615#ifndef USE_READ_BARRIER
616    str    r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
617#else
618    strex  r2, r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]  @ strex necessary for read barrier bits
619    cbnz   r2, .Lunlock_strex_fail    @ store failed, retry
620#endif
621    bx     lr
622.Lrecursive_thin_unlock:  @ r1: original lock word
623    sub    r1, r1, #LOCK_WORD_THIN_LOCK_COUNT_ONE  @ decrement count
624#ifndef USE_READ_BARRIER
625    str    r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
626#else
627    strex  r2, r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]  @ strex necessary for read barrier bits
628    cbnz   r2, .Lunlock_strex_fail    @ store failed, retry
629#endif
630    bx     lr
631.Lunlock_strex_fail:
632    b      .Lretry_unlock             @ retry
633.Lslow_unlock:
634    @ save callee saves in case exception allocation triggers GC
635    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2
636    mov    r1, r9                     @ pass Thread::Current
637    bl     artUnlockObjectFromCode    @ (Object* obj, Thread*)
638    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
639    RETURN_IF_RESULT_IS_ZERO
640    DELIVER_PENDING_EXCEPTION
641END art_quick_unlock_object
642
643ENTRY art_quick_unlock_object_no_inline
644    @ save callee saves in case exception allocation triggers GC
645    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2
646    mov    r1, r9                     @ pass Thread::Current
647    bl     artUnlockObjectFromCode    @ (Object* obj, Thread*)
648    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
649    RETURN_IF_RESULT_IS_ZERO
650    DELIVER_PENDING_EXCEPTION
651END art_quick_unlock_object_no_inline
652
653    /*
654     * Entry from managed code that calls artIsAssignableFromCode and on failure calls
655     * artThrowClassCastException.
656     */
657    .extern artThrowClassCastException
658ENTRY art_quick_check_cast
659    push {r0-r1, lr}                    @ save arguments, link register and pad
660    .cfi_adjust_cfa_offset 12
661    .cfi_rel_offset r0, 0
662    .cfi_rel_offset r1, 4
663    .cfi_rel_offset lr, 8
664    sub sp, #4
665    .cfi_adjust_cfa_offset 4
666    bl artIsAssignableFromCode
667    cbz    r0, .Lthrow_class_cast_exception
668    add sp, #4
669    .cfi_adjust_cfa_offset -4
670    pop {r0-r1, pc}
671    .cfi_adjust_cfa_offset 4        @ Reset unwind info so following code unwinds.
672.Lthrow_class_cast_exception:
673    add sp, #4
674    .cfi_adjust_cfa_offset -4
675    pop {r0-r1, lr}
676    .cfi_adjust_cfa_offset -12
677    .cfi_restore r0
678    .cfi_restore r1
679    .cfi_restore lr
680    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r2, r3  // save all registers as basis for long jump context
681    mov r2, r9                      @ pass Thread::Current
682    b   artThrowClassCastException  @ (Class*, Class*, Thread*)
683    bkpt
684END art_quick_check_cast
685
686// Restore rReg's value from [sp, #offset] if rReg is not the same as rExclude.
687.macro POP_REG_NE rReg, offset, rExclude
688    .ifnc \rReg, \rExclude
689        ldr \rReg, [sp, #\offset]   @ restore rReg
690        .cfi_restore \rReg
691    .endif
692.endm
693
694    /*
695     * Macro to insert read barrier, only used in art_quick_aput_obj.
696     * rObj and rDest are registers, offset is a defined literal such as MIRROR_OBJECT_CLASS_OFFSET.
697     * TODO: When read barrier has a fast path, add heap unpoisoning support for the fast path.
698     */
699.macro READ_BARRIER rDest, rObj, offset
700#ifdef USE_READ_BARRIER
701    push {r0-r3, ip, lr}            @ 6 words for saved registers (used in art_quick_aput_obj)
702    .cfi_adjust_cfa_offset 24
703    .cfi_rel_offset r0, 0
704    .cfi_rel_offset r1, 4
705    .cfi_rel_offset r2, 8
706    .cfi_rel_offset r3, 12
707    .cfi_rel_offset ip, 16
708    .cfi_rel_offset lr, 20
709    sub sp, #8                      @ push padding
710    .cfi_adjust_cfa_offset 8
711    @ mov r0, \rRef                 @ pass ref in r0 (no-op for now since parameter ref is unused)
712    .ifnc \rObj, r1
713        mov r1, \rObj               @ pass rObj
714    .endif
715    mov r2, #\offset                @ pass offset
716    bl artReadBarrierSlow           @ artReadBarrierSlow(ref, rObj, offset)
717    @ No need to unpoison return value in r0, artReadBarrierSlow() would do the unpoisoning.
718    .ifnc \rDest, r0
719        mov \rDest, r0              @ save return value in rDest
720    .endif
721    add sp, #8                      @ pop padding
722    .cfi_adjust_cfa_offset -8
723    POP_REG_NE r0, 0, \rDest        @ conditionally restore saved registers
724    POP_REG_NE r1, 4, \rDest
725    POP_REG_NE r2, 8, \rDest
726    POP_REG_NE r3, 12, \rDest
727    POP_REG_NE ip, 16, \rDest
728    add sp, #20
729    .cfi_adjust_cfa_offset -20
730    pop {lr}                        @ restore lr
731    .cfi_adjust_cfa_offset -4
732    .cfi_restore lr
733#else
734    ldr \rDest, [\rObj, #\offset]
735    UNPOISON_HEAP_REF \rDest
736#endif  // USE_READ_BARRIER
737.endm
738
739    /*
740     * Entry from managed code for array put operations of objects where the value being stored
741     * needs to be checked for compatibility.
742     * r0 = array, r1 = index, r2 = value
743     */
744ENTRY art_quick_aput_obj_with_null_and_bound_check
745    tst r0, r0
746    bne art_quick_aput_obj_with_bound_check
747    b art_quick_throw_null_pointer_exception
748END art_quick_aput_obj_with_null_and_bound_check
749
750    .hidden art_quick_aput_obj_with_bound_check
751ENTRY art_quick_aput_obj_with_bound_check
752    ldr r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET]
753    cmp r3, r1
754    bhi art_quick_aput_obj
755    mov r0, r1
756    mov r1, r3
757    b art_quick_throw_array_bounds
758END art_quick_aput_obj_with_bound_check
759
760#ifdef USE_READ_BARRIER
761    .extern artReadBarrierSlow
762#endif
763    .hidden art_quick_aput_obj
764ENTRY art_quick_aput_obj
765#ifdef USE_READ_BARRIER
766    @ The offset to .Ldo_aput_null is too large to use cbz due to expansion from READ_BARRIER macro.
767    tst r2, r2
768    beq .Ldo_aput_null
769#else
770    cbz r2, .Ldo_aput_null
771#endif  // USE_READ_BARRIER
772    READ_BARRIER r3, r0, MIRROR_OBJECT_CLASS_OFFSET
773    READ_BARRIER ip, r2, MIRROR_OBJECT_CLASS_OFFSET
774    READ_BARRIER r3, r3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET
775    cmp r3, ip  @ value's type == array's component type - trivial assignability
776    bne .Lcheck_assignability
777.Ldo_aput:
778    add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
779    POISON_HEAP_REF r2
780    str r2, [r3, r1, lsl #2]
781    ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
782    lsr r0, r0, #7
783    strb r3, [r3, r0]
784    blx lr
785.Ldo_aput_null:
786    add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
787    str r2, [r3, r1, lsl #2]
788    blx lr
789.Lcheck_assignability:
790    push {r0-r2, lr}             @ save arguments
791    .cfi_adjust_cfa_offset 16
792    .cfi_rel_offset r0, 0
793    .cfi_rel_offset r1, 4
794    .cfi_rel_offset r2, 8
795    .cfi_rel_offset lr, 12
796    mov r1, ip
797    mov r0, r3
798    bl artIsAssignableFromCode
799    cbz r0, .Lthrow_array_store_exception
800    pop {r0-r2, lr}
801    .cfi_restore r0
802    .cfi_restore r1
803    .cfi_restore r2
804    .cfi_restore lr
805    .cfi_adjust_cfa_offset -16
806    add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
807    POISON_HEAP_REF r2
808    str r2, [r3, r1, lsl #2]
809    ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
810    lsr r0, r0, #7
811    strb r3, [r3, r0]
812    blx lr
813.Lthrow_array_store_exception:
814    pop {r0-r2, lr}
815    /* No need to repeat restore cfi directives, the ones above apply here. */
816    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r3, ip
817    mov r1, r2
818    mov r2, r9                     @ pass Thread::Current
819    b artThrowArrayStoreException  @ (Class*, Class*, Thread*)
820    bkpt                           @ unreached
821END art_quick_aput_obj
822
823// Macro to facilitate adding new allocation entrypoints.
824.macro ONE_ARG_DOWNCALL name, entrypoint, return
825    .extern \entrypoint
826ENTRY \name
827    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r1, r2  @ save callee saves in case of GC
828    mov    r1, r9                     @ pass Thread::Current
829    bl     \entrypoint     @ (uint32_t type_idx, Method* method, Thread*)
830    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
831    \return
832END \name
833.endm
834
835// Macro to facilitate adding new allocation entrypoints.
836.macro TWO_ARG_DOWNCALL name, entrypoint, return
837    .extern \entrypoint
838ENTRY \name
839    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3  @ save callee saves in case of GC
840    mov    r2, r9                     @ pass Thread::Current
841    bl     \entrypoint     @ (uint32_t type_idx, Method* method, Thread*)
842    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
843    \return
844END \name
845.endm
846
847// Macro to facilitate adding new array allocation entrypoints.
848.macro THREE_ARG_DOWNCALL name, entrypoint, return
849    .extern \entrypoint
850ENTRY \name
851    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r3, r12  @ save callee saves in case of GC
852    mov    r3, r9                     @ pass Thread::Current
853    @ (uint32_t type_idx, Method* method, int32_t component_count, Thread*)
854    bl     \entrypoint
855    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
856    \return
857END \name
858.endm
859
860// Macro to facilitate adding new allocation entrypoints.
861.macro FOUR_ARG_DOWNCALL name, entrypoint, return
862    .extern \entrypoint
863ENTRY \name
864    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME_PRESERVE_RTEMP2  r12, r3  @ save callee saves in case of GC
865    str    r9, [sp, #-16]!            @ expand the frame and pass Thread::Current
866    .cfi_adjust_cfa_offset 16
867    bl     \entrypoint
868    add    sp, #16                    @ strip the extra frame
869    .cfi_adjust_cfa_offset -16
870    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
871    \return
872END \name
873.endm
874
875ONE_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
876ONE_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
877ONE_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
878
879    /*
880     * Called by managed code to resolve a static field and load a non-wide value.
881     */
882ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
883ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
884ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
885ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
886ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
887ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
888    /*
889     * Called by managed code to resolve a static field and load a 64-bit primitive value.
890     */
891    .extern artGet64StaticFromCode
892ENTRY art_quick_get64_static
893    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3  @ save callee saves in case of GC
894    ldr    r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
895    mov    r2, r9                        @ pass Thread::Current
896    bl     artGet64StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*)
897    ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
898    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
899    cbnz   r2, 1f                        @ success if no exception pending
900    bx     lr                            @ return on success
9011:
902    DELIVER_PENDING_EXCEPTION
903END art_quick_get64_static
904
905    /*
906     * Called by managed code to resolve an instance field and load a non-wide value.
907     */
908TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
909TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
910TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
911TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
912TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
913TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
914    /*
915     * Called by managed code to resolve an instance field and load a 64-bit primitive value.
916     */
917    .extern artGet64InstanceFromCode
918ENTRY art_quick_get64_instance
919    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3  @ save callee saves in case of GC
920    ldr    r2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
921    mov    r3, r9                        @ pass Thread::Current
922    bl     artGet64InstanceFromCode      @ (field_idx, Object*, referrer, Thread*)
923    ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
924    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
925    cbnz   r2, 1f                        @ success if no exception pending
926    bx     lr                            @ return on success
9271:
928    DELIVER_PENDING_EXCEPTION
929END art_quick_get64_instance
930
931    /*
932     * Called by managed code to resolve a static field and store a non-wide value.
933     */
934TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
935TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
936TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
937TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
938    /*
939     * Called by managed code to resolve a static field and store a 64-bit primitive value.
940     * On entry r0 holds field index, r2:r3 hold new_val
941     */
942    .extern artSet64StaticFromCode
943ENTRY art_quick_set64_static
944    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r12   @ save callee saves in case of GC
945                                         @ r2:r3 contain the wide argument
946    ldr    r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
947    str    r9, [sp, #-16]!               @ expand the frame and pass Thread::Current
948    .cfi_adjust_cfa_offset 16
949    bl     artSet64StaticFromCode        @ (field_idx, referrer, new_val, Thread*)
950    add    sp, #16                       @ release out args
951    .cfi_adjust_cfa_offset -16
952    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  @ TODO: we can clearly save an add here
953    RETURN_IF_RESULT_IS_ZERO
954    DELIVER_PENDING_EXCEPTION
955END art_quick_set64_static
956
957    /*
958     * Called by managed code to resolve an instance field and store a non-wide value.
959     */
960THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
961THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
962THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
963THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER
964    /*
965     * Called by managed code to resolve an instance field and store a 64-bit primitive value.
966     */
967    .extern artSet64InstanceFromCode
968ENTRY art_quick_set64_instance
969    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r12, lr  @ save callee saves in case of GC
970                                         @ r2:r3 contain the wide argument
971    ldr    r12, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE]  @ pass referrer
972    str    r9, [sp, #-12]!               @ expand the frame and pass Thread::Current
973    .cfi_adjust_cfa_offset 12
974    str    r12, [sp, #-4]!               @ expand the frame and pass the referrer
975    .cfi_adjust_cfa_offset 4
976    bl     artSet64InstanceFromCode      @ (field_idx, Object*, new_val, Method* referrer, Thread*)
977    add    sp, #16                       @ release out args
978    .cfi_adjust_cfa_offset -16
979    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME  @ TODO: we can clearly save an add here
980    RETURN_IF_RESULT_IS_ZERO
981    DELIVER_PENDING_EXCEPTION
982END art_quick_set64_instance
983
984    /*
985     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
986     * exception on error. On success the String is returned. R0 holds the string index. The fast
987     * path check for hit in strings cache has already been performed.
988     */
989ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
990
991// Generate the allocation entrypoints for each allocator.
992GENERATE_ALLOC_ENTRYPOINTS_FOR_EACH_ALLOCATOR
993
994// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_rosalloc, RosAlloc).
995ENTRY art_quick_alloc_object_rosalloc
996    // Fast path rosalloc allocation.
997    // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current
998    // r2, r3, r12: free.
999    ldr    r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32]    // Load dex cache resolved types array
1000                                                              // Load the class (r2)
1001    ldr    r2, [r2, r0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
1002    cbz    r2, .Lart_quick_alloc_object_rosalloc_slow_path    // Check null class
1003                                                              // Check class status.
1004    ldr    r3, [r2, #MIRROR_CLASS_STATUS_OFFSET]
1005    cmp    r3, #MIRROR_CLASS_STATUS_INITIALIZED
1006    bne    .Lart_quick_alloc_object_rosalloc_slow_path
1007                                                              // Add a fake dependence from the
1008                                                              // following access flag and size
1009                                                              // loads to the status load.
1010                                                              // This is to prevent those loads
1011                                                              // from being reordered above the
1012                                                              // status load and reading wrong
1013                                                              // values (an alternative is to use
1014                                                              // a load-acquire for the status).
1015    eor    r3, r3, r3
1016    add    r2, r2, r3
1017                                                              // Check access flags has
1018                                                              // kAccClassIsFinalizable
1019    ldr    r3, [r2, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
1020    tst    r3, #ACCESS_FLAGS_CLASS_IS_FINALIZABLE
1021    bne    .Lart_quick_alloc_object_rosalloc_slow_path
1022
1023    ldr    r3, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET]     // Check if the thread local
1024                                                              // allocation stack has room.
1025                                                              // TODO: consider using ldrd.
1026    ldr    r12, [r9, #THREAD_LOCAL_ALLOC_STACK_END_OFFSET]
1027    cmp    r3, r12
1028    bhs    .Lart_quick_alloc_object_rosalloc_slow_path
1029
1030    ldr    r3, [r2, #MIRROR_CLASS_OBJECT_SIZE_OFFSET]         // Load the object size (r3)
1031    cmp    r3, #ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE        // Check if the size is for a thread
1032                                                              // local allocation
1033    bhs    .Lart_quick_alloc_object_rosalloc_slow_path
1034                                                              // Compute the rosalloc bracket index
1035                                                              // from the size.
1036                                                              // Align up the size by the rosalloc
1037                                                              // bracket quantum size and divide
1038                                                              // by the quantum size and subtract
1039                                                              // by 1. This code is a shorter but
1040                                                              // equivalent version.
1041    sub    r3, r3, #1
1042    lsr    r3, r3, #ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT
1043                                                              // Load the rosalloc run (r12)
1044    add    r12, r9, r3, lsl #POINTER_SIZE_SHIFT
1045    ldr    r12, [r12, #THREAD_ROSALLOC_RUNS_OFFSET]
1046                                                              // Load the free list head (r3). This
1047                                                              // will be the return val.
1048    ldr    r3, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)]
1049    cbz    r3, .Lart_quick_alloc_object_rosalloc_slow_path
1050    // "Point of no slow path". Won't go to the slow path from here on. OK to clobber r0 and r1.
1051    ldr    r1, [r3, #ROSALLOC_SLOT_NEXT_OFFSET]               // Load the next pointer of the head
1052                                                              // and update the list head with the
1053                                                              // next pointer.
1054    str    r1, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)]
1055                                                              // Store the class pointer in the
1056                                                              // header. This also overwrites the
1057                                                              // next pointer. The offsets are
1058                                                              // asserted to match.
1059#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
1060#error "Class pointer needs to overwrite next pointer."
1061#endif
1062    POISON_HEAP_REF r2
1063    str    r2, [r3, #MIRROR_OBJECT_CLASS_OFFSET]
1064                                                              // Push the new object onto the thread
1065                                                              // local allocation stack and
1066                                                              // increment the thread local
1067                                                              // allocation stack top.
1068    ldr    r1, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET]
1069    str    r3, [r1], #COMPRESSED_REFERENCE_SIZE               // (Increment r1 as a side effect.)
1070    str    r1, [r9, #THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET]
1071                                                              // Decrement the size of the free list
1072    ldr    r1, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)]
1073    sub    r1, #1
1074                                                              // TODO: consider combining this store
1075                                                              // and the list head store above using
1076                                                              // strd.
1077    str    r1, [r12, #(ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)]
1078                                                              // Fence. This is "ish" not "ishst" so
1079                                                              // that the code after this allocation
1080                                                              // site will see the right values in
1081                                                              // the fields of the class.
1082                                                              // Alternatively we could use "ishst"
1083                                                              // if we use load-acquire for the
1084                                                              // class status load.)
1085    dmb    ish
1086    mov    r0, r3                                             // Set the return value and return.
1087    bx     lr
1088
1089.Lart_quick_alloc_object_rosalloc_slow_path:
1090    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3  @ save callee saves in case of GC
1091    mov    r2, r9                     @ pass Thread::Current
1092    bl     artAllocObjectFromCodeRosAlloc     @ (uint32_t type_idx, Method* method, Thread*)
1093    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1094    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1095END art_quick_alloc_object_rosalloc
1096
1097// The common fast path code for art_quick_alloc_object_tlab and art_quick_alloc_object_region_tlab.
1098//
1099// r0: type_idx/return value, r1: ArtMethod*, r2: class, r9: Thread::Current, r3, r12: free.
1100// Need to preserve r0 and r1 to the slow path.
1101.macro ALLOC_OBJECT_TLAB_FAST_PATH slowPathLabel
1102    cbz    r2, \slowPathLabel                                 // Check null class
1103                                                              // Check class status.
1104    ldr    r3, [r2, #MIRROR_CLASS_STATUS_OFFSET]
1105    cmp    r3, #MIRROR_CLASS_STATUS_INITIALIZED
1106    bne    \slowPathLabel
1107                                                              // Add a fake dependence from the
1108                                                              // following access flag and size
1109                                                              // loads to the status load.
1110                                                              // This is to prevent those loads
1111                                                              // from being reordered above the
1112                                                              // status load and reading wrong
1113                                                              // values (an alternative is to use
1114                                                              // a load-acquire for the status).
1115    eor    r3, r3, r3
1116    add    r2, r2, r3
1117                                                              // Check access flags has
1118                                                              // kAccClassIsFinalizable.
1119    ldr    r3, [r2, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET]
1120    tst    r3, #ACCESS_FLAGS_CLASS_IS_FINALIZABLE
1121    bne    \slowPathLabel
1122                                                              // Load thread_local_pos (r12) and
1123                                                              // thread_local_end (r3) with ldrd.
1124                                                              // Check constraints for ldrd.
1125#if !((THREAD_LOCAL_POS_OFFSET + 4 == THREAD_LOCAL_END_OFFSET) && (THREAD_LOCAL_POS_OFFSET % 8 == 0))
1126#error "Thread::thread_local_pos/end must be consecutive and are 8 byte aligned for performance"
1127#endif
1128    ldrd   r12, r3, [r9, #THREAD_LOCAL_POS_OFFSET]
1129    sub    r12, r3, r12                                       // Compute the remaining buf size.
1130    ldr    r3, [r2, #MIRROR_CLASS_OBJECT_SIZE_OFFSET]         // Load the object size (r3).
1131    cmp    r3, r12                                            // Check if it fits. OK to do this
1132                                                              // before rounding up the object size
1133                                                              // assuming the buf size alignment.
1134    bhi    \slowPathLabel
1135    // "Point of no slow path". Won't go to the slow path from here on. OK to clobber r0 and r1.
1136                                                              // Round up the object size by the
1137                                                              // object alignment. (addr + 7) & ~7.
1138    add    r3, r3, #OBJECT_ALIGNMENT_MASK
1139    and    r3, r3, #OBJECT_ALIGNMENT_MASK_TOGGLED
1140                                                              // Reload old thread_local_pos (r0)
1141                                                              // for the return value.
1142    ldr    r0, [r9, #THREAD_LOCAL_POS_OFFSET]
1143    add    r1, r0, r3
1144    str    r1, [r9, #THREAD_LOCAL_POS_OFFSET]                 // Store new thread_local_pos.
1145    ldr    r1, [r9, #THREAD_LOCAL_OBJECTS_OFFSET]             // Increment thread_local_objects.
1146    add    r1, r1, #1
1147    str    r1, [r9, #THREAD_LOCAL_OBJECTS_OFFSET]
1148    POISON_HEAP_REF r2
1149    str    r2, [r0, #MIRROR_OBJECT_CLASS_OFFSET]              // Store the class pointer.
1150                                                              // Fence. This is "ish" not "ishst" so
1151                                                              // that the code after this allocation
1152                                                              // site will see the right values in
1153                                                              // the fields of the class.
1154                                                              // Alternatively we could use "ishst"
1155                                                              // if we use load-acquire for the
1156                                                              // class status load.)
1157    dmb    ish
1158    bx     lr
1159.endm
1160
1161// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB).
1162ENTRY art_quick_alloc_object_tlab
1163    // Fast path tlab allocation.
1164    // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current
1165    // r2, r3, r12: free.
1166#if defined(USE_READ_BARRIER)
1167    mvn    r0, #0                                             // Read barrier not supported here.
1168    bx     lr                                                 // Return -1.
1169#endif
1170    ldr    r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32]    // Load dex cache resolved types array
1171                                                              // Load the class (r2)
1172    ldr    r2, [r2, r0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
1173    ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_tlab_slow_path
1174.Lart_quick_alloc_object_tlab_slow_path:
1175    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3                 // Save callee saves in case of GC.
1176    mov    r2, r9                                             // Pass Thread::Current.
1177    bl     artAllocObjectFromCodeTLAB    // (uint32_t type_idx, Method* method, Thread*)
1178    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1179    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1180END art_quick_alloc_object_tlab
1181
1182// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB)
1183ENTRY art_quick_alloc_object_region_tlab
1184    // Fast path tlab allocation.
1185    // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current, r2, r3, r12: free.
1186#if !defined(USE_READ_BARRIER)
1187    eor    r0, r0, r0                                         // Read barrier must be enabled here.
1188    sub    r0, r0, #1                                         // Return -1.
1189    bx     lr
1190#endif
1191    ldr    r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32]    // Load dex cache resolved types array
1192                                                              // Load the class (r2)
1193    ldr    r2, [r2, r0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT]
1194                                                              // Read barrier for class load.
1195    ldr    r3, [r9, #THREAD_IS_GC_MARKING_OFFSET]
1196    cbnz   r3, .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path
1197.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit:
1198    ALLOC_OBJECT_TLAB_FAST_PATH .Lart_quick_alloc_object_region_tlab_slow_path
1199.Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path:
1200                                                              // The read barrier slow path. Mark
1201                                                              // the class.
1202    push   {r0, r1, r3, lr}                                   // Save registers. r3 is pushed only
1203                                                              // to align sp by 16 bytes.
1204    mov    r0, r2                                             // Pass the class as the first param.
1205    bl     artReadBarrierMark
1206    mov    r2, r0                                             // Get the (marked) class back.
1207    pop    {r0, r1, r3, lr}
1208    b      .Lart_quick_alloc_object_region_tlab_class_load_read_barrier_slow_path_exit
1209.Lart_quick_alloc_object_region_tlab_slow_path:
1210    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  r2, r3                 // Save callee saves in case of GC.
1211    mov    r2, r9                                             // Pass Thread::Current.
1212    bl     artAllocObjectFromCodeRegionTLAB    // (uint32_t type_idx, Method* method, Thread*)
1213    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1214    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1215END art_quick_alloc_object_region_tlab
1216
1217    /*
1218     * Called by managed code when the value in rSUSPEND has been decremented to 0.
1219     */
1220    .extern artTestSuspendFromCode
1221ENTRY art_quick_test_suspend
1222#ifdef ARM_R4_SUSPEND_FLAG
1223    ldrh   r0, [rSELF, #THREAD_FLAGS_OFFSET]
1224    mov    rSUSPEND, #SUSPEND_CHECK_INTERVAL  @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL
1225    cbnz   r0, 1f                             @ check Thread::Current()->suspend_count_ == 0
1226    bx     lr                                 @ return if suspend_count_ == 0
12271:
1228#endif
1229    mov    r0, rSELF
1230    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2   @ save callee saves for GC stack crawl
1231    @ TODO: save FPRs to enable access in the debugger?
1232    bl     artTestSuspendFromCode             @ (Thread*)
1233    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
1234END art_quick_test_suspend
1235
1236ENTRY art_quick_implicit_suspend
1237    mov    r0, rSELF
1238    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2   @ save callee saves for stack crawl
1239    bl     artTestSuspendFromCode             @ (Thread*)
1240    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
1241END art_quick_implicit_suspend
1242
1243    /*
1244     * Called by managed code that is attempting to call a method on a proxy class. On entry
1245     * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
1246     * frame size of the invoked proxy method agrees with a ref and args callee save frame.
1247     */
1248     .extern artQuickProxyInvokeHandler
1249ENTRY art_quick_proxy_invoke_handler
1250    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
1251    mov     r2, r9                 @ pass Thread::Current
1252    mov     r3, sp                 @ pass SP
1253    blx     artQuickProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
1254    ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
1255    // Tear down the callee-save frame. Skip arg registers.
1256    add     sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
1257    .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
1258    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1259    cbnz    r2, 1f                 @ success if no exception is pending
1260    vmov    d0, r0, r1             @ store into fpr, for when it's a fpr return...
1261    bx      lr                     @ return on success
12621:
1263    DELIVER_PENDING_EXCEPTION
1264END art_quick_proxy_invoke_handler
1265
1266    /*
1267     * Called to resolve an imt conflict.
1268     * r0 is the conflict ArtMethod.
1269     * r12 is a hidden argument that holds the target interface method's dex method index.
1270     *
1271     * Note that this stub writes to r0, r4, and r12.
1272     */
1273ENTRY art_quick_imt_conflict_trampoline
1274    ldr r4, [sp, #0]  // Load referrer
1275    ldr r4, [r4, #ART_METHOD_DEX_CACHE_METHODS_OFFSET_32]   // Load dex cache methods array
1276    ldr r12, [r4, r12, lsl #POINTER_SIZE_SHIFT]  // Load interface method
1277    ldr r0, [r0, #ART_METHOD_JNI_OFFSET_32]  // Load ImtConflictTable
1278    ldr r4, [r0]  // Load first entry in ImtConflictTable.
1279.Limt_table_iterate:
1280    cmp r4, r12
1281    // Branch if found. Benchmarks have shown doing a branch here is better.
1282    beq .Limt_table_found
1283    // If the entry is null, the interface method is not in the ImtConflictTable.
1284    cbz r4, .Lconflict_trampoline
1285    // Iterate over the entries of the ImtConflictTable.
1286    ldr r4, [r0, #(2 * __SIZEOF_POINTER__)]!
1287    b .Limt_table_iterate
1288.Limt_table_found:
1289    // We successfully hit an entry in the table. Load the target method
1290    // and jump to it.
1291    ldr r0, [r0, #__SIZEOF_POINTER__]
1292    ldr pc, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32]
1293.Lconflict_trampoline:
1294    // Call the runtime stub to populate the ImtConflictTable and jump to the
1295    // resolved method.
1296    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
1297END art_quick_imt_conflict_trampoline
1298
1299    .extern artQuickResolutionTrampoline
1300ENTRY art_quick_resolution_trampoline
1301    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3
1302    mov     r2, r9                 @ pass Thread::Current
1303    mov     r3, sp                 @ pass SP
1304    blx     artQuickResolutionTrampoline  @ (Method* called, receiver, Thread*, SP)
1305    cbz     r0, 1f                 @ is code pointer null? goto exception
1306    mov     r12, r0
1307    ldr  r0, [sp, #0]              @ load resolved method in r0
1308    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1309    bx      r12                    @ tail-call into actual code
13101:
1311    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1312    DELIVER_PENDING_EXCEPTION
1313END art_quick_resolution_trampoline
1314
1315    /*
1316     * Called to do a generic JNI down-call
1317     */
1318ENTRY art_quick_generic_jni_trampoline
1319    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
1320
1321    // Save rSELF
1322    mov r11, rSELF
1323    // Save SP , so we can have static CFI info. r10 is saved in ref_and_args.
1324    mov r10, sp
1325    .cfi_def_cfa_register r10
1326
1327    sub sp, sp, #5120
1328
1329    // prepare for artQuickGenericJniTrampoline call
1330    // (Thread*,  SP)
1331    //    r0      r1   <= C calling convention
1332    //  rSELF     r10  <= where they are
1333
1334    mov r0, rSELF   // Thread*
1335    mov r1, r10
1336    blx artQuickGenericJniTrampoline  // (Thread*, sp)
1337
1338    // The C call will have registered the complete save-frame on success.
1339    // The result of the call is:
1340    // r0: pointer to native code, 0 on error.
1341    // r1: pointer to the bottom of the used area of the alloca, can restore stack till there.
1342
1343    // Check for error = 0.
1344    cbz r0, .Lexception_in_native
1345
1346    // Release part of the alloca.
1347    mov sp, r1
1348
1349    // Save the code pointer
1350    mov r12, r0
1351
1352    // Load parameters from frame into registers.
1353    pop {r0-r3}
1354
1355    // Softfloat.
1356    // TODO: Change to hardfloat when supported.
1357
1358    blx r12           // native call.
1359
1360    // result sign extension is handled in C code
1361    // prepare for artQuickGenericJniEndTrampoline call
1362    // (Thread*, result, result_f)
1363    //    r0      r2,r3    stack       <= C calling convention
1364    //    r11     r0,r1    r0,r1          <= where they are
1365    sub sp, sp, #8 // Stack alignment.
1366
1367    push {r0-r1}
1368    mov r3, r1
1369    mov r2, r0
1370    mov r0, r11
1371
1372    blx artQuickGenericJniEndTrampoline
1373
1374    // Restore self pointer.
1375    mov r9, r11
1376
1377    // Pending exceptions possible.
1378    ldr r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
1379    cbnz r2, .Lexception_in_native
1380
1381    // Tear down the alloca.
1382    mov sp, r10
1383    .cfi_def_cfa_register sp
1384
1385    // Tear down the callee-save frame. Skip arg registers.
1386    add     sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
1387    .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
1388    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1389
1390    // store into fpr, for when it's a fpr return...
1391    vmov d0, r0, r1
1392    bx lr      // ret
1393    // Undo the unwinding information from above since it doesn't apply below.
1394    .cfi_def_cfa_register r10
1395    .cfi_adjust_cfa_offset FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
1396
1397.Lexception_in_native:
1398    ldr sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]
1399    .cfi_def_cfa_register sp
1400    # This will create a new save-all frame, required by the runtime.
1401    DELIVER_PENDING_EXCEPTION
1402END art_quick_generic_jni_trampoline
1403
1404    .extern artQuickToInterpreterBridge
1405ENTRY art_quick_to_interpreter_bridge
1406    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r1, r2
1407    mov     r1, r9                 @ pass Thread::Current
1408    mov     r2, sp                 @ pass SP
1409    blx     artQuickToInterpreterBridge    @ (Method* method, Thread*, SP)
1410    ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
1411    // Tear down the callee-save frame. Skip arg registers.
1412    add     sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
1413    .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
1414    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1415    cbnz    r2, 1f                 @ success if no exception is pending
1416    vmov    d0, r0, r1             @ store into fpr, for when it's a fpr return...
1417    bx      lr                     @ return on success
14181:
1419    DELIVER_PENDING_EXCEPTION
1420END art_quick_to_interpreter_bridge
1421
1422    /*
1423     * Routine that intercepts method calls and returns.
1424     */
1425    .extern artInstrumentationMethodEntryFromCode
1426    .extern artInstrumentationMethodExitFromCode
1427ENTRY art_quick_instrumentation_entry
1428    @ Make stack crawlable and clobber r2 and r3 (post saving)
1429    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3
1430    @ preserve r0 (not normally an arg) knowing there is a spare slot in kRefsAndArgs.
1431    str   r0, [sp, #4]
1432    mov   r2, r9         @ pass Thread::Current
1433    mov   r3, lr         @ pass LR
1434    blx   artInstrumentationMethodEntryFromCode  @ (Method*, Object*, Thread*, LR)
1435    mov   r12, r0        @ r12 holds reference to code
1436    ldr   r0, [sp, #4]   @ restore r0
1437    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1438    blx   r12            @ call method with lr set to art_quick_instrumentation_exit
1439@ Deliberate fall-through into art_quick_instrumentation_exit.
1440    .type art_quick_instrumentation_exit, #function
1441    .global art_quick_instrumentation_exit
1442art_quick_instrumentation_exit:
1443    mov   lr, #0         @ link register is to here, so clobber with 0 for later checks
1444    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3  @ set up frame knowing r2 and r3 must be dead on exit
1445    mov   r12, sp        @ remember bottom of caller's frame
1446    push  {r0-r1}        @ save return value
1447    .cfi_adjust_cfa_offset 8
1448    .cfi_rel_offset r0, 0
1449    .cfi_rel_offset r1, 4
1450    vpush {d0}           @ save fp return value
1451    .cfi_adjust_cfa_offset 8
1452    sub   sp, #8         @ space for return value argument. Note: AAPCS stack alignment is 8B, no
1453                         @ need to align by 16.
1454    .cfi_adjust_cfa_offset 8
1455    vstr  d0, [sp]       @ d0 -> [sp] for fpr_res
1456    mov   r2, r0         @ pass return value as gpr_res
1457    mov   r3, r1
1458    mov   r0, r9         @ pass Thread::Current
1459    mov   r1, r12        @ pass SP
1460    blx   artInstrumentationMethodExitFromCode  @ (Thread*, SP, gpr_res, fpr_res)
1461    add   sp, #8
1462    .cfi_adjust_cfa_offset -8
1463
1464    mov   r2, r0         @ link register saved by instrumentation
1465    mov   lr, r1         @ r1 is holding link register if we're to bounce to deoptimize
1466    vpop  {d0}           @ restore fp return value
1467    .cfi_adjust_cfa_offset -8
1468    pop   {r0, r1}       @ restore return value
1469    .cfi_adjust_cfa_offset -8
1470    .cfi_restore r0
1471    .cfi_restore r1
1472    add sp, #32          @ remove callee save frame
1473    .cfi_adjust_cfa_offset -32
1474    bx    r2             @ return
1475END art_quick_instrumentation_entry
1476
1477    /*
1478     * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
1479     * will long jump to the upcall with a special exception of -1.
1480     */
1481    .extern artDeoptimize
1482ENTRY art_quick_deoptimize
1483    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1
1484    mov    r0, r9         @ Set up args.
1485    blx    artDeoptimize  @ artDeoptimize(Thread*)
1486END art_quick_deoptimize
1487
1488    /*
1489     * Compiled code has requested that we deoptimize into the interpreter. The deoptimization
1490     * will long jump to the interpreter bridge.
1491     */
1492    .extern artDeoptimizeFromCompiledCode
1493ENTRY art_quick_deoptimize_from_compiled_code
1494    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1
1495    mov    r0, r9                         @ Set up args.
1496    blx    artDeoptimizeFromCompiledCode  @ artDeoptimizeFromCompiledCode(Thread*)
1497END art_quick_deoptimize_from_compiled_code
1498
1499    /*
1500     * Signed 64-bit integer multiply.
1501     *
1502     * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
1503     *        WX
1504     *      x YZ
1505     *  --------
1506     *     ZW ZX
1507     *  YW YX
1508     *
1509     * The low word of the result holds ZX, the high word holds
1510     * (ZW+YX) + (the high overflow from ZX).  YW doesn't matter because
1511     * it doesn't fit in the low 64 bits.
1512     *
1513     * Unlike most ARM math operations, multiply instructions have
1514     * restrictions on using the same register more than once (Rd and Rm
1515     * cannot be the same).
1516     */
1517    /* mul-long vAA, vBB, vCC */
1518ENTRY art_quick_mul_long
1519    push    {r9 - r10}
1520    .cfi_adjust_cfa_offset 8
1521    .cfi_rel_offset r9, 0
1522    .cfi_rel_offset r10, 4
1523    mul     ip, r2, r1                  @  ip<- ZxW
1524    umull   r9, r10, r2, r0             @  r9/r10 <- ZxX
1525    mla     r2, r0, r3, ip              @  r2<- YxX + (ZxW)
1526    add     r10, r2, r10                @  r10<- r10 + low(ZxW + (YxX))
1527    mov     r0,r9
1528    mov     r1,r10
1529    pop     {r9 - r10}
1530    .cfi_adjust_cfa_offset -8
1531    .cfi_restore r9
1532    .cfi_restore r10
1533    bx      lr
1534END art_quick_mul_long
1535
1536    /*
1537     * Long integer shift.  This is different from the generic 32/64-bit
1538     * binary operations because vAA/vBB are 64-bit but vCC (the shift
1539     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
1540     * 6 bits.
1541     * On entry:
1542     *   r0: low word
1543     *   r1: high word
1544     *   r2: shift count
1545     */
1546    /* shl-long vAA, vBB, vCC */
1547ARM_ENTRY art_quick_shl_long            @ ARM code as thumb code requires spills
1548    and     r2, r2, #63                 @ r2<- r2 & 0x3f
1549    mov     r1, r1, asl r2              @  r1<- r1 << r2
1550    rsb     r3, r2, #32                 @  r3<- 32 - r2
1551    orr     r1, r1, r0, lsr r3          @  r1<- r1 | (r0 << (32-r2))
1552    subs    ip, r2, #32                 @  ip<- r2 - 32
1553    movpl   r1, r0, asl ip              @  if r2 >= 32, r1<- r0 << (r2-32)
1554    mov     r0, r0, asl r2              @  r0<- r0 << r2
1555    bx      lr
1556END art_quick_shl_long
1557
1558    /*
1559     * Long integer shift.  This is different from the generic 32/64-bit
1560     * binary operations because vAA/vBB are 64-bit but vCC (the shift
1561     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
1562     * 6 bits.
1563     * On entry:
1564     *   r0: low word
1565     *   r1: high word
1566     *   r2: shift count
1567     */
1568    /* shr-long vAA, vBB, vCC */
1569ARM_ENTRY art_quick_shr_long            @ ARM code as thumb code requires spills
1570    and     r2, r2, #63                 @ r0<- r0 & 0x3f
1571    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
1572    rsb     r3, r2, #32                 @  r3<- 32 - r2
1573    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
1574    subs    ip, r2, #32                 @  ip<- r2 - 32
1575    movpl   r0, r1, asr ip              @  if r2 >= 32, r0<-r1 >> (r2-32)
1576    mov     r1, r1, asr r2              @  r1<- r1 >> r2
1577    bx      lr
1578END art_quick_shr_long
1579
1580    /*
1581     * Long integer shift.  This is different from the generic 32/64-bit
1582     * binary operations because vAA/vBB are 64-bit but vCC (the shift
1583     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
1584     * 6 bits.
1585     * On entry:
1586     *   r0: low word
1587     *   r1: high word
1588     *   r2: shift count
1589     */
1590    /* ushr-long vAA, vBB, vCC */
1591ARM_ENTRY art_quick_ushr_long           @ ARM code as thumb code requires spills
1592    and     r2, r2, #63                 @ r0<- r0 & 0x3f
1593    mov     r0, r0, lsr r2              @  r0<- r2 >> r2
1594    rsb     r3, r2, #32                 @  r3<- 32 - r2
1595    orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
1596    subs    ip, r2, #32                 @  ip<- r2 - 32
1597    movpl   r0, r1, lsr ip              @  if r2 >= 32, r0<-r1 >>> (r2-32)
1598    mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
1599    bx      lr
1600END art_quick_ushr_long
1601
1602    /*
1603     * String's indexOf.
1604     *
1605     * On entry:
1606     *    r0:   string object (known non-null)
1607     *    r1:   char to match (known <= 0xFFFF)
1608     *    r2:   Starting offset in string data
1609     */
1610ENTRY art_quick_indexof
1611    push {r4, r10-r11, lr} @ 4 words of callee saves
1612    .cfi_adjust_cfa_offset 16
1613    .cfi_rel_offset r4, 0
1614    .cfi_rel_offset r10, 4
1615    .cfi_rel_offset r11, 8
1616    .cfi_rel_offset lr, 12
1617    ldr   r3, [r0, #MIRROR_STRING_COUNT_OFFSET]
1618    add   r0, #MIRROR_STRING_VALUE_OFFSET
1619
1620    /* Clamp start to [0..count] */
1621    cmp   r2, #0
1622    it    lt
1623    movlt r2, #0
1624    cmp   r2, r3
1625    it    gt
1626    movgt r2, r3
1627
1628    /* Save a copy in r12 to later compute result */
1629    mov   r12, r0
1630
1631    /* Build pointer to start of data to compare and pre-bias */
1632    add   r0, r0, r2, lsl #1
1633    sub   r0, #2
1634
1635    /* Compute iteration count */
1636    sub   r2, r3, r2
1637
1638    /*
1639     * At this point we have:
1640     *   r0: start of data to test
1641     *   r1: char to compare
1642     *   r2: iteration count
1643     *   r12: original start of string data
1644     *   r3, r4, r10, r11 available for loading string data
1645     */
1646
1647    subs  r2, #4
1648    blt   .Lindexof_remainder
1649
1650.Lindexof_loop4:
1651    ldrh  r3, [r0, #2]!
1652    ldrh  r4, [r0, #2]!
1653    ldrh  r10, [r0, #2]!
1654    ldrh  r11, [r0, #2]!
1655    cmp   r3, r1
1656    beq   .Lmatch_0
1657    cmp   r4, r1
1658    beq   .Lmatch_1
1659    cmp   r10, r1
1660    beq   .Lmatch_2
1661    cmp   r11, r1
1662    beq   .Lmatch_3
1663    subs  r2, #4
1664    bge   .Lindexof_loop4
1665
1666.Lindexof_remainder:
1667    adds  r2, #4
1668    beq   .Lindexof_nomatch
1669
1670.Lindexof_loop1:
1671    ldrh  r3, [r0, #2]!
1672    cmp   r3, r1
1673    beq   .Lmatch_3
1674    subs  r2, #1
1675    bne   .Lindexof_loop1
1676
1677.Lindexof_nomatch:
1678    mov   r0, #-1
1679    pop {r4, r10-r11, pc}
1680
1681.Lmatch_0:
1682    sub   r0, #6
1683    sub   r0, r12
1684    asr   r0, r0, #1
1685    pop {r4, r10-r11, pc}
1686.Lmatch_1:
1687    sub   r0, #4
1688    sub   r0, r12
1689    asr   r0, r0, #1
1690    pop {r4, r10-r11, pc}
1691.Lmatch_2:
1692    sub   r0, #2
1693    sub   r0, r12
1694    asr   r0, r0, #1
1695    pop {r4, r10-r11, pc}
1696.Lmatch_3:
1697    sub   r0, r12
1698    asr   r0, r0, #1
1699    pop {r4, r10-r11, pc}
1700END art_quick_indexof
1701
1702   /*
1703     * String's compareTo.
1704     *
1705     * Requires rARG0/rARG1 to have been previously checked for null.  Will
1706     * return negative if this's string is < comp, 0 if they are the
1707     * same and positive if >.
1708     *
1709     * On entry:
1710     *    r0:   this object pointer
1711     *    r1:   comp object pointer
1712     *
1713     */
1714    .extern __memcmp16
1715ENTRY art_quick_string_compareto
1716    mov    r2, r0         @ this to r2, opening up r0 for return value
1717    sub    r0, r2, r1     @ Same?
1718    cbnz   r0,1f
1719    bx     lr
17201:                        @ Same strings, return.
1721
1722    push {r4, r7-r12, lr} @ 8 words - keep alignment
1723    .cfi_adjust_cfa_offset 32
1724    .cfi_rel_offset r4, 0
1725    .cfi_rel_offset r7, 4
1726    .cfi_rel_offset r8, 8
1727    .cfi_rel_offset r9, 12
1728    .cfi_rel_offset r10, 16
1729    .cfi_rel_offset r11, 20
1730    .cfi_rel_offset r12, 24
1731    .cfi_rel_offset lr, 28
1732
1733    ldr    r7, [r2, #MIRROR_STRING_COUNT_OFFSET]
1734    ldr    r10, [r1, #MIRROR_STRING_COUNT_OFFSET]
1735    add    r2, #MIRROR_STRING_VALUE_OFFSET
1736    add    r1, #MIRROR_STRING_VALUE_OFFSET
1737
1738    /*
1739     * At this point, we have:
1740     *    value:  r2/r1
1741     *    offset: r4/r9
1742     *    count:  r7/r10
1743     * We're going to compute
1744     *    r11 <- countDiff
1745     *    r10 <- minCount
1746     */
1747     subs  r11, r7, r10
1748     it    ls
1749     movls r10, r7
1750
1751     /*
1752      * Note: data pointers point to previous element so we can use pre-index
1753      * mode with base writeback.
1754      */
1755     subs  r2, #2   @ offset to contents[-1]
1756     subs  r1, #2   @ offset to contents[-1]
1757
1758     /*
1759      * At this point we have:
1760      *   r2: *this string data
1761      *   r1: *comp string data
1762      *   r10: iteration count for comparison
1763      *   r11: value to return if the first part of the string is equal
1764      *   r0: reserved for result
1765      *   r3, r4, r7, r8, r9, r12 available for loading string data
1766      */
1767
1768    subs  r10, #2
1769    blt   .Ldo_remainder2
1770
1771      /*
1772       * Unroll the first two checks so we can quickly catch early mismatch
1773       * on long strings (but preserve incoming alignment)
1774       */
1775
1776    ldrh  r3, [r2, #2]!
1777    ldrh  r4, [r1, #2]!
1778    ldrh  r7, [r2, #2]!
1779    ldrh  r8, [r1, #2]!
1780    subs  r0, r3, r4
1781    it    eq
1782    subseq  r0, r7, r8
1783    bne   .Ldone
1784    cmp   r10, #28
1785    bgt   .Ldo_memcmp16
1786    subs  r10, #3
1787    blt   .Ldo_remainder
1788
1789.Lloopback_triple:
1790    ldrh  r3, [r2, #2]!
1791    ldrh  r4, [r1, #2]!
1792    ldrh  r7, [r2, #2]!
1793    ldrh  r8, [r1, #2]!
1794    ldrh  r9, [r2, #2]!
1795    ldrh  r12,[r1, #2]!
1796    subs  r0, r3, r4
1797    it    eq
1798    subseq  r0, r7, r8
1799    it    eq
1800    subseq  r0, r9, r12
1801    bne   .Ldone
1802    subs  r10, #3
1803    bge   .Lloopback_triple
1804
1805.Ldo_remainder:
1806    adds  r10, #3
1807    beq   .Lreturn_diff
1808
1809.Lloopback_single:
1810    ldrh  r3, [r2, #2]!
1811    ldrh  r4, [r1, #2]!
1812    subs  r0, r3, r4
1813    bne   .Ldone
1814    subs  r10, #1
1815    bne   .Lloopback_single
1816
1817.Lreturn_diff:
1818    mov   r0, r11
1819    pop   {r4, r7-r12, pc}
1820
1821.Ldo_remainder2:
1822    adds  r10, #2
1823    bne   .Lloopback_single
1824    mov   r0, r11
1825    pop   {r4, r7-r12, pc}
1826
1827    /* Long string case */
1828.Ldo_memcmp16:
1829    mov   r7, r11
1830    add   r0, r2, #2
1831    add   r1, r1, #2
1832    mov   r2, r10
1833    bl    __memcmp16
1834    cmp   r0, #0
1835    it    eq
1836    moveq r0, r7
1837.Ldone:
1838    pop   {r4, r7-r12, pc}
1839END art_quick_string_compareto
1840
1841    /* Assembly routines used to handle ABI differences. */
1842
1843    /* double fmod(double a, double b) */
1844    .extern fmod
1845ENTRY art_quick_fmod
1846    push  {lr}
1847    .cfi_adjust_cfa_offset 4
1848    .cfi_rel_offset lr, 0
1849    sub   sp, #4
1850    .cfi_adjust_cfa_offset 4
1851    vmov  r0, r1, d0
1852    vmov  r2, r3, d1
1853    bl    fmod
1854    vmov  d0, r0, r1
1855    add   sp, #4
1856    .cfi_adjust_cfa_offset -4
1857    pop   {pc}
1858END art_quick_fmod
1859
1860    /* float fmodf(float a, float b) */
1861     .extern fmodf
1862ENTRY art_quick_fmodf
1863    push  {lr}
1864    .cfi_adjust_cfa_offset 4
1865    .cfi_rel_offset lr, 0
1866    sub   sp, #4
1867    .cfi_adjust_cfa_offset 4
1868    vmov  r0, r1, d0
1869    bl    fmodf
1870    vmov  s0, r0
1871    add   sp, #4
1872    .cfi_adjust_cfa_offset -4
1873    pop   {pc}
1874END art_quick_fmod
1875
1876    /* int64_t art_d2l(double d) */
1877    .extern art_d2l
1878ENTRY art_quick_d2l
1879    vmov  r0, r1, d0
1880    b     art_d2l
1881END art_quick_d2l
1882
1883    /* int64_t art_f2l(float f) */
1884    .extern art_f2l
1885ENTRY art_quick_f2l
1886    vmov  r0, s0
1887    b     art_f2l
1888END art_quick_f2l
1889
1890    /* float art_l2f(int64_t l) */
1891    .extern art_l2f
1892ENTRY art_quick_l2f
1893    push  {lr}
1894    .cfi_adjust_cfa_offset 4
1895    .cfi_rel_offset lr, 0
1896    sub   sp, #4
1897    .cfi_adjust_cfa_offset 4
1898    bl    art_l2f
1899    vmov  s0, r0
1900    add   sp, #4
1901    .cfi_adjust_cfa_offset -4
1902    pop   {pc}
1903END art_quick_l2f
1904