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