quick_entrypoints_arm64.S revision 9bd88b0933a372e6a7b64b850868e6a7998567e2
1/*
2 * Copyright (C) 2014 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_arm64.S"
18
19#include "arch/quick_alloc_entrypoints.S"
20
21
22    /*
23     * Macro that sets up the callee save frame to conform with
24     * Runtime::CreateCalleeSaveMethod(kSaveAll)
25     */
26.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
27    adrp xIP0, :got:_ZN3art7Runtime9instance_E
28    ldr xIP0, [xIP0, #:got_lo12:_ZN3art7Runtime9instance_E]
29
30    // Our registers aren't intermixed - just spill in order.
31    ldr xIP0, [xIP0]  // xIP0 = & (art::Runtime * art::Runtime.instance_) .
32
33    // xIP0 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs]  .
34    THIS_LOAD_REQUIRES_READ_BARRIER
35
36    // Loads appropriate callee-save-method.
37    ldr wIP0, [xIP0, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET ]
38
39    sub sp, sp, #176
40    .cfi_adjust_cfa_offset 176
41
42    // Ugly compile-time check, but we only have the preprocessor.
43#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 176)
44#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM64) size not as expected."
45#endif
46
47    // Stack alignment filler [sp, #8].
48    // FP callee-saves.
49    stp d8, d9,   [sp, #16]
50    stp d10, d11, [sp, #32]
51    stp d12, d13, [sp, #48]
52    stp d14, d15, [sp, #64]
53
54    // GP callee-saves
55    stp x19, x20, [sp, #80]
56    .cfi_rel_offset x19, 80
57    .cfi_rel_offset x20, 88
58
59    stp x21, x22, [sp, #96]
60    .cfi_rel_offset x21, 96
61    .cfi_rel_offset x22, 104
62
63    stp x23, x24, [sp, #112]
64    .cfi_rel_offset x23, 112
65    .cfi_rel_offset x24, 120
66
67    stp x25, x26, [sp, #128]
68    .cfi_rel_offset x25, 128
69    .cfi_rel_offset x26, 136
70
71    stp x27, x28, [sp, #144]
72    .cfi_rel_offset x27, 144
73    .cfi_rel_offset x28, 152
74
75    stp x29, xLR, [sp, #160]
76    .cfi_rel_offset x29, 160
77    .cfi_rel_offset x30, 168
78
79    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs].
80    str xIP0, [sp]
81    // Place sp in Thread::Current()->top_quick_frame.
82    mov xIP0, sp
83    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
84.endm
85
86    /*
87     * Macro that sets up the callee save frame to conform with
88     * Runtime::CreateCalleeSaveMethod(kRefsOnly).
89     */
90.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
91    adrp xIP0, :got:_ZN3art7Runtime9instance_E
92    ldr xIP0, [xIP0, #:got_lo12:_ZN3art7Runtime9instance_E]
93
94    // Our registers aren't intermixed - just spill in order.
95    ldr xIP0, [xIP0]  // xIP0 = & (art::Runtime * art::Runtime.instance_) .
96
97    // xIP0 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefOnly]  .
98    THIS_LOAD_REQUIRES_READ_BARRIER
99
100    // Loads appropriate callee-save-method.
101    ldr wIP0, [xIP0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET ]
102
103    sub sp, sp, #96
104    .cfi_adjust_cfa_offset 96
105
106    // Ugly compile-time check, but we only have the preprocessor.
107#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 96)
108#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM64) size not as expected."
109#endif
110
111    // GP callee-saves.
112    // x20 paired with ArtMethod* - see below.
113    stp x21, x22, [sp, #16]
114    .cfi_rel_offset x21, 16
115    .cfi_rel_offset x22, 24
116
117    stp x23, x24, [sp, #32]
118    .cfi_rel_offset x23, 32
119    .cfi_rel_offset x24, 40
120
121    stp x25, x26, [sp, #48]
122    .cfi_rel_offset x25, 48
123    .cfi_rel_offset x26, 56
124
125    stp x27, x28, [sp, #64]
126    .cfi_rel_offset x27, 64
127    .cfi_rel_offset x28, 72
128
129    stp x29, xLR, [sp, #80]
130    .cfi_rel_offset x29, 80
131    .cfi_rel_offset x30, 88
132
133    // Store ArtMethod* Runtime::callee_save_methods_[kRefsOnly].
134    stp xIP0, x20, [sp]
135    .cfi_rel_offset x20, 8
136
137    // Place sp in Thread::Current()->top_quick_frame.
138    mov xIP0, sp
139    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
140.endm
141
142// TODO: Probably no need to restore registers preserved by aapcs64.
143.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
144    // Callee-saves.
145    ldr x20, [sp, #8]
146    .cfi_restore x20
147
148    ldp x21, x22, [sp, #16]
149    .cfi_restore x21
150    .cfi_restore x22
151
152    ldp x23, x24, [sp, #32]
153    .cfi_restore x23
154    .cfi_restore x24
155
156    ldp x25, x26, [sp, #48]
157    .cfi_restore x25
158    .cfi_restore x26
159
160    ldp x27, x28, [sp, #64]
161    .cfi_restore x27
162    .cfi_restore x28
163
164    ldp x29, xLR, [sp, #80]
165    .cfi_restore x29
166    .cfi_restore x30
167
168    add sp, sp, #96
169    .cfi_adjust_cfa_offset -96
170.endm
171
172.macro POP_REFS_ONLY_CALLEE_SAVE_FRAME
173    add sp, sp, #96
174    .cfi_adjust_cfa_offset - 96
175.endm
176
177.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
178    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
179    ret
180.endm
181
182
183.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
184    sub sp, sp, #224
185    .cfi_adjust_cfa_offset 224
186
187    // Ugly compile-time check, but we only have the preprocessor.
188#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 224)
189#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM64) size not as expected."
190#endif
191
192    // Stack alignment filler [sp, #8].
193    // FP args.
194    stp d0, d1, [sp, #16]
195    stp d2, d3, [sp, #32]
196    stp d4, d5, [sp, #48]
197    stp d6, d7, [sp, #64]
198
199    // Core args.
200    stp x1, x2, [sp, #80]
201    .cfi_rel_offset x1, 80
202    .cfi_rel_offset x2, 88
203
204    stp x3, x4, [sp, #96]
205    .cfi_rel_offset x3, 96
206    .cfi_rel_offset x4, 104
207
208    stp x5, x6, [sp, #112]
209    .cfi_rel_offset x5, 112
210    .cfi_rel_offset x6, 120
211
212    // x7, Callee-saves.
213    stp x7, x20, [sp, #128]
214    .cfi_rel_offset x7, 128
215    .cfi_rel_offset x20, 136
216
217    stp x21, x22, [sp, #144]
218    .cfi_rel_offset x21, 144
219    .cfi_rel_offset x22, 152
220
221    stp x23, x24, [sp, #160]
222    .cfi_rel_offset x23, 160
223    .cfi_rel_offset x24, 168
224
225    stp x25, x26, [sp, #176]
226    .cfi_rel_offset x25, 176
227    .cfi_rel_offset x26, 184
228
229    stp x27, x28, [sp, #192]
230    .cfi_rel_offset x27, 192
231    .cfi_rel_offset x28, 200
232
233    // x29(callee-save) and LR.
234    stp x29, xLR, [sp, #208]
235    .cfi_rel_offset x29, 208
236    .cfi_rel_offset x30, 216
237
238.endm
239
240    /*
241     * Macro that sets up the callee save frame to conform with
242     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs).
243     *
244     * TODO This is probably too conservative - saving FP & LR.
245     */
246.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
247    adrp xIP0, :got:_ZN3art7Runtime9instance_E
248    ldr xIP0, [xIP0, #:got_lo12:_ZN3art7Runtime9instance_E]
249
250    // Our registers aren't intermixed - just spill in order.
251    ldr xIP0, [xIP0]  // xIP0 = & (art::Runtime * art::Runtime.instance_) .
252
253    // xIP0 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs]  .
254    THIS_LOAD_REQUIRES_READ_BARRIER
255    ldr wIP0, [xIP0, RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET ]
256
257    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
258
259    str xIP0, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
260    // Place sp in Thread::Current()->top_quick_frame.
261    mov xIP0, sp
262    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
263.endm
264
265.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_X0
266    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
267    str x0, [sp, #0]  // Store ArtMethod* to bottom of stack.
268    // Place sp in Thread::Current()->top_quick_frame.
269    mov xIP0, sp
270    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
271.endm
272
273// TODO: Probably no need to restore registers preserved by aapcs64.
274.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
275    // FP args.
276    ldp d0, d1, [sp, #16]
277    ldp d2, d3, [sp, #32]
278    ldp d4, d5, [sp, #48]
279    ldp d6, d7, [sp, #64]
280
281    // Core args.
282    ldp x1, x2, [sp, #80]
283    .cfi_restore x1
284    .cfi_restore x2
285
286    ldp x3, x4, [sp, #96]
287    .cfi_restore x3
288    .cfi_restore x4
289
290    ldp x5, x6, [sp, #112]
291    .cfi_restore x5
292    .cfi_restore x6
293
294    // x7, Callee-saves.
295    ldp x7, x20, [sp, #128]
296    .cfi_restore x7
297    .cfi_restore x20
298
299    ldp x21, x22, [sp, #144]
300    .cfi_restore x21
301    .cfi_restore x22
302
303    ldp x23, x24, [sp, #160]
304    .cfi_restore x23
305    .cfi_restore x24
306
307    ldp x25, x26, [sp, #176]
308    .cfi_restore x25
309    .cfi_restore x26
310
311    ldp x27, x28, [sp, #192]
312    .cfi_restore x27
313    .cfi_restore x28
314
315    // x29(callee-save) and LR.
316    ldp x29, xLR, [sp, #208]
317    .cfi_restore x29
318    .cfi_restore x30
319
320    add sp, sp, #224
321    .cfi_adjust_cfa_offset -224
322.endm
323
324.macro RETURN_IF_RESULT_IS_ZERO
325    cbnz x0, 1f                // result non-zero branch over
326    ret                        // return
3271:
328.endm
329
330.macro RETURN_IF_RESULT_IS_NON_ZERO
331    cbz x0, 1f                 // result zero branch over
332    ret                        // return
3331:
334.endm
335
336    /*
337     * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
338     * exception is Thread::Current()->exception_
339     */
340.macro DELIVER_PENDING_EXCEPTION
341    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
342    mov x0, xSELF
343
344    // Point of no return.
345    b artDeliverPendingExceptionFromCode  // artDeliverPendingExceptionFromCode(Thread*)
346    brk 0  // Unreached
347.endm
348
349.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg
350    ldr \reg, [xSELF, # THREAD_EXCEPTION_OFFSET]   // Get exception field.
351    cbnz \reg, 1f
352    ret
3531:
354    DELIVER_PENDING_EXCEPTION
355.endm
356
357.macro RETURN_OR_DELIVER_PENDING_EXCEPTION
358    RETURN_OR_DELIVER_PENDING_EXCEPTION_REG xIP0
359.endm
360
361// Same as above with x1. This is helpful in stubs that want to avoid clobbering another register.
362.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
363    RETURN_OR_DELIVER_PENDING_EXCEPTION_REG x1
364.endm
365
366.macro RETURN_IF_W0_IS_ZERO_OR_DELIVER
367    cbnz w0, 1f                // result non-zero branch over
368    ret                        // return
3691:
370    DELIVER_PENDING_EXCEPTION
371.endm
372
373.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
374    .extern \cxx_name
375ENTRY \c_name
376    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
377    mov x0, xSELF                     // pass Thread::Current
378    b   \cxx_name                     // \cxx_name(Thread*)
379END \c_name
380.endm
381
382.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
383    .extern \cxx_name
384ENTRY \c_name
385    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context.
386    mov x1, xSELF                     // pass Thread::Current.
387    b   \cxx_name                     // \cxx_name(arg, Thread*).
388    brk 0
389END \c_name
390.endm
391
392.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
393    .extern \cxx_name
394ENTRY \c_name
395    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
396    mov x2, xSELF                     // pass Thread::Current
397    b   \cxx_name                     // \cxx_name(arg1, arg2, Thread*)
398    brk 0
399END \c_name
400.endm
401
402    /*
403     * Called by managed code, saves callee saves and then calls artThrowException
404     * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
405     */
406ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
407
408    /*
409     * Called by managed code to create and deliver a NullPointerException.
410     */
411NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
412
413    /*
414     * Called by managed code to create and deliver an ArithmeticException.
415     */
416NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
417
418    /*
419     * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
420     * index, arg2 holds limit.
421     */
422TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
423
424    /*
425     * Called by managed code to create and deliver a StackOverflowError.
426     */
427NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
428
429    /*
430     * Called by managed code to create and deliver a NoSuchMethodError.
431     */
432ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
433
434    /*
435     * All generated callsites for interface invokes and invocation slow paths will load arguments
436     * as usual - except instead of loading arg0/x0 with the target Method*, arg0/x0 will contain
437     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
438     * NOTE: "this" is first visible argument of the target, and so can be found in arg1/x1.
439     *
440     * The helper will attempt to locate the target and return a 128-bit result in x0/x1 consisting
441     * of the target Method* in x0 and method->code_ in x1.
442     *
443     * If unsuccessful, the helper will return null/????. There will be a pending exception in the
444     * thread and we branch to another stub to deliver it.
445     *
446     * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
447     * pointing back to the original caller.
448     *
449     * Adapted from ARM32 code.
450     *
451     * Clobbers xIP0.
452     */
453.macro INVOKE_TRAMPOLINE c_name, cxx_name
454    .extern \cxx_name
455ENTRY \c_name
456    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // save callee saves in case allocation triggers GC
457    // Helper signature is always
458    // (method_idx, *this_object, *caller_method, *self, sp)
459
460    mov    x2, xSELF                      // pass Thread::Current
461    mov    x3, sp
462    bl     \cxx_name                      // (method_idx, this, Thread*, SP)
463    mov    xIP0, x1                       // save Method*->code_
464    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
465    cbz    x0, 1f                         // did we find the target? if not go to exception delivery
466    br     xIP0                           // tail call to target
4671:
468    DELIVER_PENDING_EXCEPTION
469END \c_name
470.endm
471
472INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
473INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
474
475INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
476INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
477INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
478INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
479
480
481.macro INVOKE_STUB_CREATE_FRAME
482
483SAVE_SIZE=15*8   // x4, x5, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, SP, LR, FP saved.
484SAVE_SIZE_AND_METHOD=SAVE_SIZE+STACK_REFERENCE_SIZE
485
486
487    mov x9, sp                             // Save stack pointer.
488    .cfi_register sp,x9
489
490    add x10, x2, # SAVE_SIZE_AND_METHOD    // calculate size of frame.
491    sub x10, sp, x10                       // Calculate SP position - saves + ArtMethod* +  args
492    and x10, x10, # ~0xf                   // Enforce 16 byte stack alignment.
493    mov sp, x10                            // Set new SP.
494
495    sub x10, x9, #SAVE_SIZE                // Calculate new FP (later). Done here as we must move SP
496    .cfi_def_cfa_register x10              // before this.
497    .cfi_adjust_cfa_offset SAVE_SIZE
498
499    str x28, [x10, #112]
500    .cfi_rel_offset x28, 112
501
502    stp x26, x27, [x10, #96]
503    .cfi_rel_offset x26, 96
504    .cfi_rel_offset x27, 104
505
506    stp x24, x25, [x10, #80]
507    .cfi_rel_offset x24, 80
508    .cfi_rel_offset x25, 88
509
510    stp x22, x23, [x10, #64]
511    .cfi_rel_offset x22, 64
512    .cfi_rel_offset x23, 72
513
514    stp x20, x21, [x10, #48]
515    .cfi_rel_offset x20, 48
516    .cfi_rel_offset x21, 56
517
518    stp x9, x19, [x10, #32]                // Save old stack pointer and x19.
519    .cfi_rel_offset sp, 32
520    .cfi_rel_offset x19, 40
521
522    stp x4, x5, [x10, #16]                 // Save result and shorty addresses.
523    .cfi_rel_offset x4, 16
524    .cfi_rel_offset x5, 24
525
526    stp xFP, xLR, [x10]                    // Store LR & FP.
527    .cfi_rel_offset x29, 0
528    .cfi_rel_offset x30, 8
529
530    mov xFP, x10                           // Use xFP now, as it's callee-saved.
531    .cfi_def_cfa_register x29
532    mov xSELF, x3                          // Move thread pointer into SELF register.
533
534    // Copy arguments into stack frame.
535    // Use simple copy routine for now.
536    // 4 bytes per slot.
537    // X1 - source address
538    // W2 - args length
539    // X9 - destination address.
540    // W10 - temporary
541    add x9, sp, #4                         // Destination address is bottom of stack + null.
542
543    // Use \@ to differentiate between macro invocations.
544.LcopyParams\@:
545    cmp w2, #0
546    beq .LendCopyParams\@
547    sub w2, w2, #4      // Need 65536 bytes of range.
548    ldr w10, [x1, x2]
549    str w10, [x9, x2]
550
551    b .LcopyParams\@
552
553.LendCopyParams\@:
554
555    // Store null into StackReference<Method>* at bottom of frame.
556    str wzr, [sp]
557
558#if (STACK_REFERENCE_SIZE != 4)
559#error "STACK_REFERENCE_SIZE(ARM64) size not as expected."
560#endif
561.endm
562
563.macro INVOKE_STUB_CALL_AND_RETURN
564
565    // load method-> METHOD_QUICK_CODE_OFFSET
566    ldr x9, [x0 , #MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64]
567    // Branch to method.
568    blr x9
569
570    // Restore return value address and shorty address.
571    ldp x4,x5, [xFP, #16]
572    .cfi_restore x4
573    .cfi_restore x5
574
575    ldr x28, [xFP, #112]
576    .cfi_restore x28
577
578    ldp x26, x27, [xFP, #96]
579    .cfi_restore x26
580    .cfi_restore x27
581
582    ldp x24, x25, [xFP, #80]
583    .cfi_restore x24
584    .cfi_restore x25
585
586    ldp x22, x23, [xFP, #64]
587    .cfi_restore x22
588    .cfi_restore x23
589
590    ldp x20, x21, [xFP, #48]
591    .cfi_restore x20
592    .cfi_restore x21
593
594    // Store result (w0/x0/s0/d0) appropriately, depending on resultType.
595    ldrb w10, [x5]
596
597    // Don't set anything for a void type.
598    cmp w10, #'V'
599    beq .Lexit_art_quick_invoke_stub\@
600
601    cmp w10, #'D'
602    bne .Lreturn_is_float\@
603    str d0, [x4]
604    b .Lexit_art_quick_invoke_stub\@
605
606.Lreturn_is_float\@:
607    cmp w10, #'F'
608    bne .Lreturn_is_int\@
609    str s0, [x4]
610    b .Lexit_art_quick_invoke_stub\@
611
612    // Just store x0. Doesn't matter if it is 64 or 32 bits.
613.Lreturn_is_int\@:
614    str x0, [x4]
615
616.Lexit_art_quick_invoke_stub\@:
617    ldp x2, x19, [xFP, #32]   // Restore stack pointer and x19.
618    .cfi_restore x19
619    mov sp, x2
620    .cfi_restore sp
621
622    ldp xFP, xLR, [xFP]    // Restore old frame pointer and link register.
623    .cfi_restore x29
624    .cfi_restore x30
625
626    ret
627
628.endm
629
630
631/*
632 *  extern"C" void art_quick_invoke_stub(ArtMethod *method,   x0
633 *                                       uint32_t  *args,     x1
634 *                                       uint32_t argsize,    w2
635 *                                       Thread *self,        x3
636 *                                       JValue *result,      x4
637 *                                       char   *shorty);     x5
638 *  +----------------------+
639 *  |                      |
640 *  |  C/C++ frame         |
641 *  |       LR''           |
642 *  |       FP''           | <- SP'
643 *  +----------------------+
644 *  +----------------------+
645 *  |        x28           | <- TODO: Remove callee-saves.
646 *  |         :            |
647 *  |        x19           |
648 *  |        SP'           |
649 *  |        X5            |
650 *  |        X4            |        Saved registers
651 *  |        LR'           |
652 *  |        FP'           | <- FP
653 *  +----------------------+
654 *  | uint32_t out[n-1]    |
655 *  |    :      :          |        Outs
656 *  | uint32_t out[0]      |
657 *  | StackRef<ArtMethod>  | <- SP  value=null
658 *  +----------------------+
659 *
660 * Outgoing registers:
661 *  x0    - Method*
662 *  x1-x7 - integer parameters.
663 *  d0-d7 - Floating point parameters.
664 *  xSELF = self
665 *  SP = & of ArtMethod*
666 *  x1 = "this" pointer.
667 *
668 */
669ENTRY art_quick_invoke_stub
670    // Spill registers as per AACPS64 calling convention.
671    INVOKE_STUB_CREATE_FRAME
672
673    // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters.
674    // Parse the passed shorty to determine which register to load.
675    // Load addresses for routines that load WXSD registers.
676    adr  x11, .LstoreW2
677    adr  x12, .LstoreX2
678    adr  x13, .LstoreS0
679    adr  x14, .LstoreD0
680
681    // Initialize routine offsets to 0 for integers and floats.
682    // x8 for integers, x15 for floating point.
683    mov x8, #0
684    mov x15, #0
685
686    add x10, x5, #1         // Load shorty address, plus one to skip return value.
687    ldr w1, [x9],#4         // Load "this" parameter, and increment arg pointer.
688
689    // Loop to fill registers.
690.LfillRegisters:
691    ldrb w17, [x10], #1       // Load next character in signature, and increment.
692    cbz w17, .LcallFunction   // Exit at end of signature. Shorty 0 terminated.
693
694    cmp  w17, #'F' // is this a float?
695    bne .LisDouble
696
697    cmp x15, # 8*12         // Skip this load if all registers full.
698    beq .Ladvance4
699
700    add x17, x13, x15       // Calculate subroutine to jump to.
701    br  x17
702
703.LisDouble:
704    cmp w17, #'D'           // is this a double?
705    bne .LisLong
706
707    cmp x15, # 8*12         // Skip this load if all registers full.
708    beq .Ladvance8
709
710    add x17, x14, x15       // Calculate subroutine to jump to.
711    br x17
712
713.LisLong:
714    cmp w17, #'J'           // is this a long?
715    bne .LisOther
716
717    cmp x8, # 6*12          // Skip this load if all registers full.
718    beq .Ladvance8
719
720    add x17, x12, x8        // Calculate subroutine to jump to.
721    br x17
722
723.LisOther:                  // Everything else takes one vReg.
724    cmp x8, # 6*12          // Skip this load if all registers full.
725    beq .Ladvance4
726
727    add x17, x11, x8        // Calculate subroutine to jump to.
728    br x17
729
730.Ladvance4:
731    add x9, x9, #4
732    b .LfillRegisters
733
734.Ladvance8:
735    add x9, x9, #8
736    b .LfillRegisters
737
738// Macro for loading a parameter into a register.
739//  counter - the register with offset into these tables
740//  size - the size of the register - 4 or 8 bytes.
741//  register - the name of the register to be loaded.
742.macro LOADREG counter size register return
743    ldr \register , [x9], #\size
744    add \counter, \counter, 12
745    b \return
746.endm
747
748// Store ints.
749.LstoreW2:
750    LOADREG x8 4 w2 .LfillRegisters
751    LOADREG x8 4 w3 .LfillRegisters
752    LOADREG x8 4 w4 .LfillRegisters
753    LOADREG x8 4 w5 .LfillRegisters
754    LOADREG x8 4 w6 .LfillRegisters
755    LOADREG x8 4 w7 .LfillRegisters
756
757// Store longs.
758.LstoreX2:
759    LOADREG x8 8 x2 .LfillRegisters
760    LOADREG x8 8 x3 .LfillRegisters
761    LOADREG x8 8 x4 .LfillRegisters
762    LOADREG x8 8 x5 .LfillRegisters
763    LOADREG x8 8 x6 .LfillRegisters
764    LOADREG x8 8 x7 .LfillRegisters
765
766// Store singles.
767.LstoreS0:
768    LOADREG x15 4 s0 .LfillRegisters
769    LOADREG x15 4 s1 .LfillRegisters
770    LOADREG x15 4 s2 .LfillRegisters
771    LOADREG x15 4 s3 .LfillRegisters
772    LOADREG x15 4 s4 .LfillRegisters
773    LOADREG x15 4 s5 .LfillRegisters
774    LOADREG x15 4 s6 .LfillRegisters
775    LOADREG x15 4 s7 .LfillRegisters
776
777// Store doubles.
778.LstoreD0:
779    LOADREG x15 8 d0 .LfillRegisters
780    LOADREG x15 8 d1 .LfillRegisters
781    LOADREG x15 8 d2 .LfillRegisters
782    LOADREG x15 8 d3 .LfillRegisters
783    LOADREG x15 8 d4 .LfillRegisters
784    LOADREG x15 8 d5 .LfillRegisters
785    LOADREG x15 8 d6 .LfillRegisters
786    LOADREG x15 8 d7 .LfillRegisters
787
788
789.LcallFunction:
790
791    INVOKE_STUB_CALL_AND_RETURN
792
793END art_quick_invoke_stub
794
795/*  extern"C"
796 *     void art_quick_invoke_static_stub(ArtMethod *method,   x0
797 *                                       uint32_t  *args,     x1
798 *                                       uint32_t argsize,    w2
799 *                                       Thread *self,        x3
800 *                                       JValue *result,      x4
801 *                                       char   *shorty);     x5
802 */
803ENTRY art_quick_invoke_static_stub
804    // Spill registers as per AACPS64 calling convention.
805    INVOKE_STUB_CREATE_FRAME
806
807    // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters.
808    // Parse the passed shorty to determine which register to load.
809    // Load addresses for routines that load WXSD registers.
810    adr  x11, .LstoreW1_2
811    adr  x12, .LstoreX1_2
812    adr  x13, .LstoreS0_2
813    adr  x14, .LstoreD0_2
814
815    // Initialize routine offsets to 0 for integers and floats.
816    // x8 for integers, x15 for floating point.
817    mov x8, #0
818    mov x15, #0
819
820    add x10, x5, #1     // Load shorty address, plus one to skip return value.
821
822    // Loop to fill registers.
823.LfillRegisters2:
824    ldrb w17, [x10], #1         // Load next character in signature, and increment.
825    cbz w17, .LcallFunction2    // Exit at end of signature. Shorty 0 terminated.
826
827    cmp  w17, #'F'          // is this a float?
828    bne .LisDouble2
829
830    cmp x15, # 8*12         // Skip this load if all registers full.
831    beq .Ladvance4_2
832
833    add x17, x13, x15       // Calculate subroutine to jump to.
834    br  x17
835
836.LisDouble2:
837    cmp w17, #'D'           // is this a double?
838    bne .LisLong2
839
840    cmp x15, # 8*12         // Skip this load if all registers full.
841    beq .Ladvance8_2
842
843    add x17, x14, x15       // Calculate subroutine to jump to.
844    br x17
845
846.LisLong2:
847    cmp w17, #'J'           // is this a long?
848    bne .LisOther2
849
850    cmp x8, # 7*12          // Skip this load if all registers full.
851    beq .Ladvance8_2
852
853    add x17, x12, x8        // Calculate subroutine to jump to.
854    br x17
855
856.LisOther2:                 // Everything else takes one vReg.
857    cmp x8, # 7*12          // Skip this load if all registers full.
858    beq .Ladvance4_2
859
860    add x17, x11, x8        // Calculate subroutine to jump to.
861    br x17
862
863.Ladvance4_2:
864    add x9, x9, #4
865    b .LfillRegisters2
866
867.Ladvance8_2:
868    add x9, x9, #8
869    b .LfillRegisters2
870
871// Store ints.
872.LstoreW1_2:
873    LOADREG x8 4 w1 .LfillRegisters2
874    LOADREG x8 4 w2 .LfillRegisters2
875    LOADREG x8 4 w3 .LfillRegisters2
876    LOADREG x8 4 w4 .LfillRegisters2
877    LOADREG x8 4 w5 .LfillRegisters2
878    LOADREG x8 4 w6 .LfillRegisters2
879    LOADREG x8 4 w7 .LfillRegisters2
880
881// Store longs.
882.LstoreX1_2:
883    LOADREG x8 8 x1 .LfillRegisters2
884    LOADREG x8 8 x2 .LfillRegisters2
885    LOADREG x8 8 x3 .LfillRegisters2
886    LOADREG x8 8 x4 .LfillRegisters2
887    LOADREG x8 8 x5 .LfillRegisters2
888    LOADREG x8 8 x6 .LfillRegisters2
889    LOADREG x8 8 x7 .LfillRegisters2
890
891// Store singles.
892.LstoreS0_2:
893    LOADREG x15 4 s0 .LfillRegisters2
894    LOADREG x15 4 s1 .LfillRegisters2
895    LOADREG x15 4 s2 .LfillRegisters2
896    LOADREG x15 4 s3 .LfillRegisters2
897    LOADREG x15 4 s4 .LfillRegisters2
898    LOADREG x15 4 s5 .LfillRegisters2
899    LOADREG x15 4 s6 .LfillRegisters2
900    LOADREG x15 4 s7 .LfillRegisters2
901
902// Store doubles.
903.LstoreD0_2:
904    LOADREG x15 8 d0 .LfillRegisters2
905    LOADREG x15 8 d1 .LfillRegisters2
906    LOADREG x15 8 d2 .LfillRegisters2
907    LOADREG x15 8 d3 .LfillRegisters2
908    LOADREG x15 8 d4 .LfillRegisters2
909    LOADREG x15 8 d5 .LfillRegisters2
910    LOADREG x15 8 d6 .LfillRegisters2
911    LOADREG x15 8 d7 .LfillRegisters2
912
913
914.LcallFunction2:
915
916    INVOKE_STUB_CALL_AND_RETURN
917
918END art_quick_invoke_static_stub
919
920
921
922    /*
923     * On entry x0 is uintptr_t* gprs_ and x1 is uint64_t* fprs_
924     */
925
926ENTRY art_quick_do_long_jump
927    // Load FPRs
928    ldp d0, d1, [x1], #16
929    ldp d2, d3, [x1], #16
930    ldp d4, d5, [x1], #16
931    ldp d6, d7, [x1], #16
932    ldp d8, d9, [x1], #16
933    ldp d10, d11, [x1], #16
934    ldp d12, d13, [x1], #16
935    ldp d14, d15, [x1], #16
936    ldp d16, d17, [x1], #16
937    ldp d18, d19, [x1], #16
938    ldp d20, d21, [x1], #16
939    ldp d22, d23, [x1], #16
940    ldp d24, d25, [x1], #16
941    ldp d26, d27, [x1], #16
942    ldp d28, d29, [x1], #16
943    ldp d30, d31, [x1]
944
945    // Load GPRs
946    // TODO: lots of those are smashed, could optimize.
947    add x0, x0, #30*8
948    ldp x30, x1, [x0], #-16
949    ldp x28, x29, [x0], #-16
950    ldp x26, x27, [x0], #-16
951    ldp x24, x25, [x0], #-16
952    ldp x22, x23, [x0], #-16
953    ldp x20, x21, [x0], #-16
954    ldp x18, x19, [x0], #-16
955    ldp x16, x17, [x0], #-16
956    ldp x14, x15, [x0], #-16
957    ldp x12, x13, [x0], #-16
958    ldp x10, x11, [x0], #-16
959    ldp x8, x9, [x0], #-16
960    ldp x6, x7, [x0], #-16
961    ldp x4, x5, [x0], #-16
962    ldp x2, x3, [x0], #-16
963    mov sp, x1
964
965    // TODO: Is it really OK to use LR for the target PC?
966    mov x0, #0
967    mov x1, #0
968    br  xLR
969END art_quick_do_long_jump
970
971    /*
972     * Entry from managed code that calls artLockObjectFromCode, may block for GC. x0 holds the
973     * possibly null object to lock.
974     *
975     * Derived from arm32 code.
976     */
977    .extern artLockObjectFromCode
978ENTRY art_quick_lock_object
979    cbz    w0, .Lslow_lock
980    add    x4, x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET  // exclusive load/store has no immediate anymore
981.Lretry_lock:
982    ldr    w2, [xSELF, #THREAD_ID_OFFSET] // TODO: Can the thread ID really change during the loop?
983    ldxr   w1, [x4]
984    mov    x3, x1
985    and    w3, w3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  // zero the read barrier bits
986    cbnz   w3, .Lnot_unlocked         // already thin locked
987    // unlocked case - x1: original lock word that's zero except for the read barrier bits.
988    orr    x2, x1, x2                 // x2 holds thread id with count of 0 with preserved read barrier bits
989    stxr   w3, w2, [x4]
990    cbnz   w3, .Llock_stxr_fail       // store failed, retry
991    dmb    ishld                      // full (LoadLoad|LoadStore) memory barrier
992    ret
993.Lnot_unlocked:  // x1: original lock word
994    lsr    w3, w1, LOCK_WORD_STATE_SHIFT
995    cbnz   w3, .Lslow_lock            // if either of the top two bits are set, go slow path
996    eor    w2, w1, w2                 // lock_word.ThreadId() ^ self->ThreadId()
997    uxth   w2, w2                     // zero top 16 bits
998    cbnz   w2, .Lslow_lock            // lock word and self thread id's match -> recursive lock
999                                      // else contention, go to slow path
1000    mov    x3, x1                     // copy the lock word to check count overflow.
1001    and    w3, w3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  // zero the read barrier bits.
1002    add    w2, w3, #LOCK_WORD_THIN_LOCK_COUNT_ONE  // increment count in lock word placing in w2 to check overflow
1003    lsr    w3, w2, LOCK_WORD_READ_BARRIER_STATE_SHIFT  // if either of the upper two bits (28-29) are set, we overflowed.
1004    cbnz   w3, .Lslow_lock            // if we overflow the count go slow path
1005    add    w2, w1, #LOCK_WORD_THIN_LOCK_COUNT_ONE  // increment count for real
1006    stxr   w3, w2, [x4]
1007    cbnz   w3, .Llock_stxr_fail       // store failed, retry
1008    ret
1009.Llock_stxr_fail:
1010    b      .Lretry_lock               // retry
1011.Lslow_lock:
1012    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case we block
1013    mov    x1, xSELF                  // pass Thread::Current
1014    bl     artLockObjectFromCode      // (Object* obj, Thread*)
1015    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1016    RETURN_IF_W0_IS_ZERO_OR_DELIVER
1017END art_quick_lock_object
1018
1019    /*
1020     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
1021     * x0 holds the possibly null object to lock.
1022     *
1023     * Derived from arm32 code.
1024     */
1025    .extern artUnlockObjectFromCode
1026ENTRY art_quick_unlock_object
1027    cbz    x0, .Lslow_unlock
1028    add    x4, x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET  // exclusive load/store has no immediate anymore
1029.Lretry_unlock:
1030#ifndef USE_READ_BARRIER
1031    ldr    w1, [x4]
1032#else
1033    ldxr   w1, [x4]                   // Need to use atomic instructions for read barrier
1034#endif
1035    lsr    w2, w1, LOCK_WORD_STATE_SHIFT
1036    cbnz   w2, .Lslow_unlock          // if either of the top two bits are set, go slow path
1037    ldr    w2, [xSELF, #THREAD_ID_OFFSET]
1038    mov    x3, x1                     // copy lock word to check thread id equality
1039    and    w3, w3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  // zero the read barrier bits
1040    eor    w3, w3, w2                 // lock_word.ThreadId() ^ self->ThreadId()
1041    uxth   w3, w3                     // zero top 16 bits
1042    cbnz   w3, .Lslow_unlock          // do lock word and self thread id's match?
1043    mov    x3, x1                     // copy lock word to detect transition to unlocked
1044    and    w3, w3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED  // zero the read barrier bits
1045    cmp    w3, #LOCK_WORD_THIN_LOCK_COUNT_ONE
1046    bpl    .Lrecursive_thin_unlock
1047    // transition to unlocked
1048    mov    x3, x1
1049    and    w3, w3, #LOCK_WORD_READ_BARRIER_STATE_MASK  // w3: zero except for the preserved read barrier bits
1050    dmb    ish                        // full (LoadStore|StoreStore) memory barrier
1051#ifndef USE_READ_BARRIER
1052    str    w3, [x4]
1053#else
1054    stxr   w2, w3, [x4]               // Need to use atomic instructions for read barrier
1055    cbnz   w2, .Lunlock_stxr_fail     // store failed, retry
1056#endif
1057    ret
1058.Lrecursive_thin_unlock:  // w1: original lock word
1059    sub    w1, w1, #LOCK_WORD_THIN_LOCK_COUNT_ONE  // decrement count
1060#ifndef USE_READ_BARRIER
1061    str    w1, [x4]
1062#else
1063    stxr   w2, w1, [x4]               // Need to use atomic instructions for read barrier
1064    cbnz   w2, .Lunlock_stxr_fail     // store failed, retry
1065#endif
1066    ret
1067.Lunlock_stxr_fail:
1068    b      .Lretry_unlock               // retry
1069.Lslow_unlock:
1070    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case exception allocation triggers GC
1071    mov    x1, xSELF                  // pass Thread::Current
1072    bl     artUnlockObjectFromCode    // (Object* obj, Thread*)
1073    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1074    RETURN_IF_W0_IS_ZERO_OR_DELIVER
1075END art_quick_unlock_object
1076
1077    /*
1078     * Entry from managed code that calls artIsAssignableFromCode and on failure calls
1079     * artThrowClassCastException.
1080     */
1081    .extern artThrowClassCastException
1082ENTRY art_quick_check_cast
1083    // Store arguments and link register
1084    // Stack needs to be 16B aligned on calls.
1085    stp x0, x1, [sp,#-32]!
1086    .cfi_adjust_cfa_offset 32
1087    .cfi_rel_offset x0, 0
1088    .cfi_rel_offset x1, 8
1089    str xLR, [sp, #24]
1090    .cfi_rel_offset x30, 24
1091
1092    // Call runtime code
1093    bl artIsAssignableFromCode
1094
1095    // Check for exception
1096    cbz x0, .Lthrow_class_cast_exception
1097
1098    // Restore and return
1099    ldr xLR, [sp, #24]
1100    .cfi_restore x30
1101    ldp x0, x1, [sp], #32
1102    .cfi_restore x0
1103    .cfi_restore x1
1104    .cfi_adjust_cfa_offset -32
1105    ret
1106
1107.Lthrow_class_cast_exception:
1108    // Restore
1109    ldr xLR, [sp, #24]
1110    .cfi_restore x30
1111    ldp x0, x1, [sp], #32
1112    .cfi_restore x0
1113    .cfi_restore x1
1114    .cfi_adjust_cfa_offset -32
1115
1116    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
1117    mov x2, xSELF                     // pass Thread::Current
1118    b artThrowClassCastException      // (Class*, Class*, Thread*)
1119    brk 0                             // We should not return here...
1120END art_quick_check_cast
1121
1122    /*
1123     * Entry from managed code for array put operations of objects where the value being stored
1124     * needs to be checked for compatibility.
1125     * x0 = array, x1 = index, x2 = value
1126     *
1127     * Currently all values should fit into w0/w1/w2, and w1 always will as indices are 32b. We
1128     * assume, though, that the upper 32b are zeroed out. At least for x1/w1 we can do better by
1129     * using index-zero-extension in load/stores.
1130     *
1131     * Temporaries: x3, x4
1132     * TODO: x4 OK? ip seems wrong here.
1133     */
1134ENTRY art_quick_aput_obj_with_null_and_bound_check
1135    tst x0, x0
1136    bne art_quick_aput_obj_with_bound_check
1137    b art_quick_throw_null_pointer_exception
1138END art_quick_aput_obj_with_null_and_bound_check
1139
1140ENTRY art_quick_aput_obj_with_bound_check
1141    ldr w3, [x0, #MIRROR_ARRAY_LENGTH_OFFSET]
1142    cmp w3, w1
1143    bhi art_quick_aput_obj
1144    mov x0, x1
1145    mov x1, x3
1146    b art_quick_throw_array_bounds
1147END art_quick_aput_obj_with_bound_check
1148
1149ENTRY art_quick_aput_obj
1150    cbz x2, .Ldo_aput_null
1151    ldr w3, [x0, #MIRROR_OBJECT_CLASS_OFFSET]            // Heap reference = 32b
1152                                                         // This also zero-extends to x3
1153    ldr w4, [x2, #MIRROR_OBJECT_CLASS_OFFSET]            // Heap reference = 32b
1154                                                         // This also zero-extends to x4
1155    ldr w3, [x3, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET]    // Heap reference = 32b
1156                                                         // This also zero-extends to x3
1157    cmp w3, w4  // value's type == array's component type - trivial assignability
1158    bne .Lcheck_assignability
1159.Ldo_aput:
1160    add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
1161                                                         // "Compress" = do nothing
1162    str w2, [x3, x1, lsl #2]                             // Heap reference = 32b
1163    ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1164    lsr x0, x0, #7
1165    strb w3, [x3, x0]
1166    ret
1167.Ldo_aput_null:
1168    add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
1169                                                         // "Compress" = do nothing
1170    str w2, [x3, x1, lsl #2]                             // Heap reference = 32b
1171    ret
1172.Lcheck_assignability:
1173    // Store arguments and link register
1174    stp x0, x1, [sp,#-32]!
1175    .cfi_adjust_cfa_offset 32
1176    .cfi_rel_offset x0, 0
1177    .cfi_rel_offset x1, 8
1178    stp x2, xLR, [sp, #16]
1179    .cfi_rel_offset x2, 16
1180    .cfi_rel_offset x30, 24
1181
1182    // Call runtime code
1183    mov x0, x3              // Heap reference, 32b, "uncompress" = do nothing, already zero-extended
1184    mov x1, x4              // Heap reference, 32b, "uncompress" = do nothing, already zero-extended
1185    bl artIsAssignableFromCode
1186
1187    // Check for exception
1188    cbz x0, .Lthrow_array_store_exception
1189
1190    // Restore
1191    ldp x2, x30, [sp, #16]
1192    .cfi_restore x2
1193    .cfi_restore x30
1194    ldp x0, x1, [sp], #32
1195    .cfi_restore x0
1196    .cfi_restore x1
1197    .cfi_adjust_cfa_offset -32
1198
1199    add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
1200                                                          // "Compress" = do nothing
1201    str w2, [x3, x1, lsl #2]                              // Heap reference = 32b
1202    ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET]
1203    lsr x0, x0, #7
1204    strb w3, [x3, x0]
1205    ret
1206.Lthrow_array_store_exception:
1207    ldp x2, x30, [sp, #16]
1208    .cfi_restore x2
1209    .cfi_restore x30
1210    ldp x0, x1, [sp], #32
1211    .cfi_restore x0
1212    .cfi_restore x1
1213    .cfi_adjust_cfa_offset -32
1214
1215    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
1216    mov x1, x2                    // Pass value.
1217    mov x2, xSELF                 // Pass Thread::Current.
1218    b artThrowArrayStoreException // (Object*, Object*, Thread*).
1219    brk 0                         // Unreached.
1220END art_quick_aput_obj
1221
1222// Macro to facilitate adding new allocation entrypoints.
1223.macro ONE_ARG_DOWNCALL name, entrypoint, return
1224    .extern \entrypoint
1225ENTRY \name
1226    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
1227    mov    x1, xSELF                  // pass Thread::Current
1228    bl     \entrypoint                // (uint32_t type_idx, Method* method, Thread*)
1229    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1230    \return
1231END \name
1232.endm
1233
1234// Macro to facilitate adding new allocation entrypoints.
1235.macro TWO_ARG_DOWNCALL name, entrypoint, return
1236    .extern \entrypoint
1237ENTRY \name
1238    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
1239    mov    x2, xSELF                  // pass Thread::Current
1240    bl     \entrypoint                // (uint32_t type_idx, Method* method, Thread*)
1241    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1242    \return
1243END \name
1244.endm
1245
1246// Macro to facilitate adding new allocation entrypoints.
1247.macro THREE_ARG_DOWNCALL name, entrypoint, return
1248    .extern \entrypoint
1249ENTRY \name
1250    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
1251    mov    x3, xSELF                  // pass Thread::Current
1252    bl     \entrypoint
1253    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1254    \return
1255END \name
1256.endm
1257
1258// Macro to facilitate adding new allocation entrypoints.
1259.macro FOUR_ARG_DOWNCALL name, entrypoint, return
1260    .extern \entrypoint
1261ENTRY \name
1262    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC
1263    mov    x4, xSELF                  // pass Thread::Current
1264    bl     \entrypoint                //
1265    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1266    \return
1267    DELIVER_PENDING_EXCEPTION
1268END \name
1269.endm
1270
1271// Macros taking opportunity of code similarities for downcalls with referrer.
1272.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return
1273    .extern \entrypoint
1274ENTRY \name
1275    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
1276    ldr    w1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
1277    mov    x2, xSELF                  // pass Thread::Current
1278    bl     \entrypoint                // (uint32_t type_idx, Method* method, Thread*, SP)
1279    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1280    \return
1281END \name
1282.endm
1283
1284.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return
1285    .extern \entrypoint
1286ENTRY \name
1287    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
1288    ldr    w2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
1289    mov    x3, xSELF                  // pass Thread::Current
1290    bl     \entrypoint
1291    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1292    \return
1293END \name
1294.endm
1295
1296.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
1297    .extern \entrypoint
1298ENTRY \name
1299    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
1300    ldr    w3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
1301    mov    x4, xSELF                  // pass Thread::Current
1302    bl     \entrypoint
1303    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1304    \return
1305END \name
1306.endm
1307
1308.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1309    cbz w0, 1f                 // result zero branch over
1310    ret                        // return
13111:
1312    DELIVER_PENDING_EXCEPTION
1313.endm
1314
1315    /*
1316     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
1317     * failure.
1318     */
1319TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1320
1321    /*
1322     * Entry from managed code when uninitialized static storage, this stub will run the class
1323     * initializer and deliver the exception on error. On success the static storage base is
1324     * returned.
1325     */
1326ONE_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1327
1328ONE_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1329ONE_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1330
1331ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1332ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1333ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1334ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1335ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1336ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1337ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1338
1339TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1340TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1341TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1342TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1343TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1344TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1345TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1
1346
1347TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1348TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1349TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1350TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1351
1352THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1353THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1354THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1355THREE_ARG_REF_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1356THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER
1357
1358// This is separated out as the argument order is different.
1359    .extern artSet64StaticFromCode
1360ENTRY art_quick_set64_static
1361    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  // save callee saves in case of GC
1362    mov    x3, x1                     // Store value
1363    ldr    w1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer
1364    mov    x2, x3                     // Put value param
1365    mov    x3, xSELF                  // pass Thread::Current
1366    bl     artSet64StaticFromCode
1367    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1368    RETURN_IF_W0_IS_ZERO_OR_DELIVER
1369END art_quick_set64_static
1370
1371    /*
1372     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
1373     * exception on error. On success the String is returned. w0 holds the string index. The fast
1374     * path check for hit in strings cache has already been performed.
1375     */
1376ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1377
1378// Generate the allocation entrypoints for each allocator.
1379GENERATE_ALL_ALLOC_ENTRYPOINTS
1380
1381    /*
1382     * Called by managed code when the thread has been asked to suspend.
1383     */
1384    .extern artTestSuspendFromCode
1385ENTRY art_quick_test_suspend
1386    ldrh   w0, [xSELF, #THREAD_FLAGS_OFFSET]  // get xSELF->state_and_flags.as_struct.flags
1387    cbnz   w0, .Lneed_suspend                 // check flags == 0
1388    ret                                       // return if flags == 0
1389.Lneed_suspend:
1390    mov    x0, xSELF
1391    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME          // save callee saves for stack crawl
1392    bl     artTestSuspendFromCode             // (Thread*)
1393    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
1394END art_quick_test_suspend
1395
1396ENTRY art_quick_implicit_suspend
1397    mov    x0, xSELF
1398    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME          // save callee saves for stack crawl
1399    bl     artTestSuspendFromCode             // (Thread*)
1400    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
1401END art_quick_implicit_suspend
1402
1403     /*
1404     * Called by managed code that is attempting to call a method on a proxy class. On entry
1405     * x0 holds the proxy method and x1 holds the receiver; The frame size of the invoked proxy
1406     * method agrees with a ref and args callee save frame.
1407     */
1408     .extern artQuickProxyInvokeHandler
1409ENTRY art_quick_proxy_invoke_handler
1410    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_X0
1411    mov     x2, xSELF                   // pass Thread::Current
1412    mov     x3, sp                      // pass SP
1413    bl      artQuickProxyInvokeHandler  // (Method* proxy method, receiver, Thread*, SP)
1414    ldr     x2, [xSELF, THREAD_EXCEPTION_OFFSET]
1415    cbnz    x2, .Lexception_in_proxy    // success if no exception is pending
1416    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME // Restore frame
1417    fmov    d0, x0                      // Store result in d0 in case it was float or double
1418    ret                                 // return on success
1419.Lexception_in_proxy:
1420    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1421    DELIVER_PENDING_EXCEPTION
1422END art_quick_proxy_invoke_handler
1423
1424    /*
1425     * Called to resolve an imt conflict. xIP1 is a hidden argument that holds the target method's
1426     * dex method index.
1427     */
1428ENTRY art_quick_imt_conflict_trampoline
1429    ldr    w0, [sp, #0]                                // load caller Method*
1430    ldr    w0, [x0, #MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET]  // load dex_cache_resolved_methods
1431    add    x0, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET    // get starting address of data
1432    ldr    w0, [x0, xIP1, lsl 2]                       // load the target method
1433    b art_quick_invoke_interface_trampoline
1434END art_quick_imt_conflict_trampoline
1435
1436ENTRY art_quick_resolution_trampoline
1437    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1438    mov x2, xSELF
1439    mov x3, sp
1440    bl artQuickResolutionTrampoline  // (called, receiver, Thread*, SP)
1441    cbz x0, 1f
1442    mov xIP0, x0            // Remember returned code pointer in xIP0.
1443    ldr w0, [sp, #0]        // artQuickResolutionTrampoline puts called method in *SP.
1444    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1445    br xIP0
14461:
1447    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1448    DELIVER_PENDING_EXCEPTION
1449END art_quick_resolution_trampoline
1450
1451/*
1452 * Generic JNI frame layout:
1453 *
1454 * #-------------------#
1455 * |                   |
1456 * | caller method...  |
1457 * #-------------------#    <--- SP on entry
1458 * | Return X30/LR     |
1459 * | X29/FP            |    callee save
1460 * | X28               |    callee save
1461 * | X27               |    callee save
1462 * | X26               |    callee save
1463 * | X25               |    callee save
1464 * | X24               |    callee save
1465 * | X23               |    callee save
1466 * | X22               |    callee save
1467 * | X21               |    callee save
1468 * | X20               |    callee save
1469 * | X19               |    callee save
1470 * | X7                |    arg7
1471 * | X6                |    arg6
1472 * | X5                |    arg5
1473 * | X4                |    arg4
1474 * | X3                |    arg3
1475 * | X2                |    arg2
1476 * | X1                |    arg1
1477 * | D7                |    float arg 8
1478 * | D6                |    float arg 7
1479 * | D5                |    float arg 6
1480 * | D4                |    float arg 5
1481 * | D3                |    float arg 4
1482 * | D2                |    float arg 3
1483 * | D1                |    float arg 2
1484 * | D0                |    float arg 1
1485 * | Method*           | <- X0
1486 * #-------------------#
1487 * | local ref cookie  | // 4B
1488 * | handle scope size | // 4B
1489 * #-------------------#
1490 * | JNI Call Stack    |
1491 * #-------------------#    <--- SP on native call
1492 * |                   |
1493 * | Stack for Regs    |    The trampoline assembly will pop these values
1494 * |                   |    into registers for native call
1495 * #-------------------#
1496 * | Native code ptr   |
1497 * #-------------------#
1498 * | Free scratch      |
1499 * #-------------------#
1500 * | Ptr to (1)        |    <--- SP
1501 * #-------------------#
1502 */
1503    /*
1504     * Called to do a generic JNI down-call
1505     */
1506ENTRY art_quick_generic_jni_trampoline
1507    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_X0
1508
1509    // Save SP , so we can have static CFI info.
1510    mov x28, sp
1511    .cfi_def_cfa_register x28
1512
1513    // This looks the same, but is different: this will be updated to point to the bottom
1514    // of the frame when the handle scope is inserted.
1515    mov xFP, sp
1516
1517    mov xIP0, #5120
1518    sub sp, sp, xIP0
1519
1520    // prepare for artQuickGenericJniTrampoline call
1521    // (Thread*,  SP)
1522    //    x0      x1   <= C calling convention
1523    //   xSELF    xFP  <= where they are
1524
1525    mov x0, xSELF   // Thread*
1526    mov x1, xFP
1527    bl artQuickGenericJniTrampoline  // (Thread*, sp)
1528
1529    // The C call will have registered the complete save-frame on success.
1530    // The result of the call is:
1531    // x0: pointer to native code, 0 on error.
1532    // x1: pointer to the bottom of the used area of the alloca, can restore stack till there.
1533
1534    // Check for error = 0.
1535    cbz x0, .Lexception_in_native
1536
1537    // Release part of the alloca.
1538    mov sp, x1
1539
1540    // Save the code pointer
1541    mov xIP0, x0
1542
1543    // Load parameters from frame into registers.
1544    // TODO Check with artQuickGenericJniTrampoline.
1545    //      Also, check again APPCS64 - the stack arguments are interleaved.
1546    ldp x0, x1, [sp]
1547    ldp x2, x3, [sp, #16]
1548    ldp x4, x5, [sp, #32]
1549    ldp x6, x7, [sp, #48]
1550
1551    ldp d0, d1, [sp, #64]
1552    ldp d2, d3, [sp, #80]
1553    ldp d4, d5, [sp, #96]
1554    ldp d6, d7, [sp, #112]
1555
1556    add sp, sp, #128
1557
1558    blr xIP0        // native call.
1559
1560    // result sign extension is handled in C code
1561    // prepare for artQuickGenericJniEndTrampoline call
1562    // (Thread*, result, result_f)
1563    //    x0       x1       x2        <= C calling convention
1564    mov x1, x0      // Result (from saved).
1565    mov x0, xSELF   // Thread register.
1566    fmov x2, d0     // d0 will contain floating point result, but needs to go into x2
1567
1568    bl artQuickGenericJniEndTrampoline
1569
1570    // Pending exceptions possible.
1571    ldr x2, [xSELF, THREAD_EXCEPTION_OFFSET]
1572    cbnz x2, .Lexception_in_native
1573
1574    // Tear down the alloca.
1575    mov sp, x28
1576    .cfi_def_cfa_register sp
1577
1578    // Tear down the callee-save frame.
1579    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1580
1581    // store into fpr, for when it's a fpr return...
1582    fmov d0, x0
1583    ret
1584
1585.Lexception_in_native:
1586    // Move to x1 then sp to please assembler.
1587    ldr x1, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
1588    mov sp, x1
1589    .cfi_def_cfa_register sp
1590    # This will create a new save-all frame, required by the runtime.
1591    DELIVER_PENDING_EXCEPTION
1592END art_quick_generic_jni_trampoline
1593
1594/*
1595 * Called to bridge from the quick to interpreter ABI. On entry the arguments match those
1596 * of a quick call:
1597 * x0 = method being called/to bridge to.
1598 * x1..x7, d0..d7 = arguments to that method.
1599 */
1600ENTRY art_quick_to_interpreter_bridge
1601    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME   // Set up frame and save arguments.
1602
1603    //  x0 will contain mirror::ArtMethod* method.
1604    mov x1, xSELF                          // How to get Thread::Current() ???
1605    mov x2, sp
1606
1607    // uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Thread* self,
1608    //                                      mirror::ArtMethod** sp)
1609    bl   artQuickToInterpreterBridge
1610
1611    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // TODO: no need to restore arguments in this case.
1612
1613    fmov d0, x0
1614
1615    RETURN_OR_DELIVER_PENDING_EXCEPTION
1616END art_quick_to_interpreter_bridge
1617
1618
1619//
1620// Instrumentation-related stubs
1621//
1622    .extern artInstrumentationMethodEntryFromCode
1623ENTRY art_quick_instrumentation_entry
1624    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1625
1626    mov   x20, x0             // Preserve method reference in a callee-save.
1627
1628    mov   x2, xSELF
1629    mov   x3, xLR
1630    bl    artInstrumentationMethodEntryFromCode  // (Method*, Object*, Thread*, LR)
1631
1632    mov   xIP0, x0            // x0 = result of call.
1633    mov   x0, x20             // Reload method reference.
1634
1635    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME  // Note: will restore xSELF
1636    adr   xLR, art_quick_instrumentation_exit
1637    br    xIP0                // Tail-call method with lr set to art_quick_instrumentation_exit.
1638END art_quick_instrumentation_entry
1639
1640    .extern artInstrumentationMethodExitFromCode
1641ENTRY art_quick_instrumentation_exit
1642    mov   xLR, #0             // Clobber LR for later checks.
1643
1644    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
1645
1646    // We need to save x0 and d0. We could use a callee-save from SETUP_REF_ONLY, but then
1647    // we would need to fully restore it. As there are a lot of callee-save registers, it seems
1648    // easier to have an extra small stack area.
1649
1650    str x0, [sp, #-16]!       // Save integer result.
1651    .cfi_adjust_cfa_offset 16
1652    str d0,  [sp, #8]         // Save floating-point result.
1653
1654    add   x1, sp, #16         // Pass SP.
1655    mov   x2, x0              // Pass integer result.
1656    fmov  x3, d0              // Pass floating-point result.
1657    mov   x0, xSELF           // Pass Thread.
1658    bl   artInstrumentationMethodExitFromCode    // (Thread*, SP, gpr_res, fpr_res)
1659
1660    mov   xIP0, x0            // Return address from instrumentation call.
1661    mov   xLR, x1             // r1 is holding link register if we're to bounce to deoptimize
1662
1663    ldr   d0, [sp, #8]        // Restore floating-point result.
1664    ldr   x0, [sp], 16        // Restore integer result, and drop stack area.
1665    .cfi_adjust_cfa_offset 16
1666
1667    POP_REFS_ONLY_CALLEE_SAVE_FRAME
1668
1669    br    xIP0                // Tail-call out.
1670END art_quick_instrumentation_exit
1671
1672    /*
1673     * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
1674     * will long jump to the upcall with a special exception of -1.
1675     */
1676    .extern artDeoptimize
1677ENTRY art_quick_deoptimize
1678    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
1679    mov    x0, xSELF          // Pass thread.
1680    bl     artDeoptimize      // artDeoptimize(Thread*)
1681    brk 0
1682END art_quick_deoptimize
1683
1684
1685    /*
1686     * String's indexOf.
1687     *
1688     * TODO: Not very optimized.
1689     * On entry:
1690     *    x0:   string object (known non-null)
1691     *    w1:   char to match (known <= 0xFFFF)
1692     *    w2:   Starting offset in string data
1693     */
1694ENTRY art_quick_indexof
1695    ldr   w3, [x0, #MIRROR_STRING_COUNT_OFFSET]
1696    add   x0, x0, #MIRROR_STRING_VALUE_OFFSET
1697
1698    /* Clamp start to [0..count] */
1699    cmp   w2, #0
1700    csel  w2, wzr, w2, lt
1701    cmp   w2, w3
1702    csel  w2, w3, w2, gt
1703
1704    /* Save a copy to compute result */
1705    mov   x5, x0
1706
1707    /* Build pointer to start of data to compare and pre-bias */
1708    add   x0, x0, x2, lsl #1
1709    sub   x0, x0, #2
1710
1711    /* Compute iteration count */
1712    sub   w2, w3, w2
1713
1714    /*
1715     * At this point we have:
1716     *  x0: start of the data to test
1717     *  w1: char to compare
1718     *  w2: iteration count
1719     *  x5: original start of string data
1720     */
1721
1722    subs  w2, w2, #4
1723    b.lt  .Lindexof_remainder
1724
1725.Lindexof_loop4:
1726    ldrh  w6, [x0, #2]!
1727    ldrh  w7, [x0, #2]!
1728    ldrh  wIP0, [x0, #2]!
1729    ldrh  wIP1, [x0, #2]!
1730    cmp   w6, w1
1731    b.eq  .Lmatch_0
1732    cmp   w7, w1
1733    b.eq  .Lmatch_1
1734    cmp   wIP0, w1
1735    b.eq  .Lmatch_2
1736    cmp   wIP1, w1
1737    b.eq  .Lmatch_3
1738    subs  w2, w2, #4
1739    b.ge  .Lindexof_loop4
1740
1741.Lindexof_remainder:
1742    adds  w2, w2, #4
1743    b.eq  .Lindexof_nomatch
1744
1745.Lindexof_loop1:
1746    ldrh  w6, [x0, #2]!
1747    cmp   w6, w1
1748    b.eq  .Lmatch_3
1749    subs  w2, w2, #1
1750    b.ne  .Lindexof_loop1
1751
1752.Lindexof_nomatch:
1753    mov   x0, #-1
1754    ret
1755
1756.Lmatch_0:
1757    sub   x0, x0, #6
1758    sub   x0, x0, x5
1759    asr   x0, x0, #1
1760    ret
1761.Lmatch_1:
1762    sub   x0, x0, #4
1763    sub   x0, x0, x5
1764    asr   x0, x0, #1
1765    ret
1766.Lmatch_2:
1767    sub   x0, x0, #2
1768    sub   x0, x0, x5
1769    asr   x0, x0, #1
1770    ret
1771.Lmatch_3:
1772    sub   x0, x0, x5
1773    asr   x0, x0, #1
1774    ret
1775END art_quick_indexof
1776
1777   /*
1778     * String's compareTo.
1779     *
1780     * TODO: Not very optimized.
1781     *
1782     * On entry:
1783     *    x0:   this object pointer
1784     *    x1:   comp object pointer
1785     *
1786     */
1787    .extern __memcmp16
1788ENTRY art_quick_string_compareto
1789    mov    x2, x0         // x0 is return, use x2 for first input.
1790    sub    x0, x2, x1     // Same string object?
1791    cbnz   x0,1f
1792    ret
17931:                        // Different string objects.
1794
1795    ldr    w4, [x2, #MIRROR_STRING_COUNT_OFFSET]
1796    ldr    w3, [x1, #MIRROR_STRING_COUNT_OFFSET]
1797    add    x2, x2, #MIRROR_STRING_VALUE_OFFSET
1798    add    x1, x1, #MIRROR_STRING_VALUE_OFFSET
1799
1800    /*
1801     * Now:           Data*  Count
1802     *    first arg    x2      w4
1803     *   second arg    x1      w3
1804     */
1805
1806    // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4.
1807    subs x0, x4, x3
1808    // Min(count1, count2) into w3.
1809    csel x3, x3, x4, ge
1810
1811    // TODO: Tune this value.
1812    // Check for long string, do memcmp16 for them.
1813    cmp w3, #28  // Constant from arm32.
1814    bgt .Ldo_memcmp16
1815
1816    /*
1817     * Now:
1818     *   x2: *first string data
1819     *   x1: *second string data
1820     *   w3: iteration count
1821     *   x0: return value if comparison equal
1822     *   x4, x5, x6, x7: free
1823     */
1824
1825    // Do a simple unrolled loop.
1826.Lloop:
1827    // At least two more elements?
1828    subs w3, w3, #2
1829    b.lt .Lremainder_or_done
1830
1831    ldrh w4, [x2], #2
1832    ldrh w5, [x1], #2
1833
1834    ldrh w6, [x2], #2
1835    ldrh w7, [x1], #2
1836
1837    subs w4, w4, w5
1838    b.ne .Lw4_result
1839
1840    subs w6, w6, w7
1841    b.ne .Lw6_result
1842
1843    b .Lloop
1844
1845.Lremainder_or_done:
1846    adds w3, w3, #1
1847    b.eq .Lremainder
1848    ret
1849
1850.Lremainder:
1851    ldrh w4, [x2], #2
1852    ldrh w5, [x1], #2
1853    subs w4, w4, w5
1854    b.ne .Lw4_result
1855    ret
1856
1857// Result is in w4
1858.Lw4_result:
1859    sxtw x0, w4
1860    ret
1861
1862// Result is in w6
1863.Lw6_result:
1864    sxtw x0, w6
1865    ret
1866
1867.Ldo_memcmp16:
1868    mov x14, x0                  // Save x0 and LR. __memcmp16 does not use these temps.
1869    mov x15, xLR                 //                 TODO: Codify and check that?
1870
1871    mov x0, x2
1872    uxtw x2, w3
1873    bl __memcmp16
1874
1875    mov xLR, x15                 // Restore LR.
1876
1877    cmp x0, #0                   // Check the memcmp difference.
1878    csel x0, x0, x14, ne         // x0 := x0 != 0 ? x14(prev x0=length diff) : x1.
1879    ret
1880END art_quick_string_compareto
1881