quick_entrypoints_mips64.S revision 8223b809a527c15b68f7c5c462d4c55c1335c7a7
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_mips64.S"
18
19#include "arch/quick_alloc_entrypoints.S"
20
21    .set noreorder
22    .balign 16
23
24    /* Deliver the given exception */
25    .extern artDeliverExceptionFromCode
26    /* Deliver an exception pending on a thread */
27    .extern artDeliverPendingExceptionFromCode
28
29    /*
30     * Macro that sets up the callee save frame to conform with
31     * Runtime::CreateCalleeSaveMethod(kSaveAll)
32     * callee-save: padding + $f24-$f31 + $s0-$s7 + $gp + $ra + $s8 = 19 total + 1x8 bytes padding
33     */
34.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
35    daddiu $sp, $sp, -160
36    .cfi_adjust_cfa_offset 160
37
38     // Ugly compile-time check, but we only have the preprocessor.
39#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 160)
40#error "SAVE_ALL_CALLEE_SAVE_FRAME(MIPS64) size not as expected."
41#endif
42
43    sd     $ra, 152($sp)
44    .cfi_rel_offset 31, 152
45    sd     $s8, 144($sp)
46    .cfi_rel_offset 30, 144
47    sd     $gp, 136($sp)
48    .cfi_rel_offset 28, 136
49    sd     $s7, 128($sp)
50    .cfi_rel_offset 23, 128
51    sd     $s6, 120($sp)
52    .cfi_rel_offset 22, 120
53    sd     $s5, 112($sp)
54    .cfi_rel_offset 21, 112
55    sd     $s4, 104($sp)
56    .cfi_rel_offset 20, 104
57    sd     $s3,  96($sp)
58    .cfi_rel_offset 19, 96
59    sd     $s2,  88($sp)
60    .cfi_rel_offset 18, 88
61    sd     $s1,  80($sp)
62    .cfi_rel_offset 17, 80
63    sd     $s0,  72($sp)
64    .cfi_rel_offset 16, 72
65
66    // FP callee-saves
67    s.d    $f31, 64($sp)
68    s.d    $f30, 56($sp)
69    s.d    $f29, 48($sp)
70    s.d    $f28, 40($sp)
71    s.d    $f27, 32($sp)
72    s.d    $f26, 24($sp)
73    s.d    $f25, 16($sp)
74    s.d    $f24,  8($sp)
75
76    # load appropriate callee-save-method
77    ld      $v0, %got(_ZN3art7Runtime9instance_E)($gp)
78    ld      $v0, 0($v0)
79    THIS_LOAD_REQUIRES_READ_BARRIER
80    lwu     $v0, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET($v0)
81    sw      $v0, 0($sp)                                # Place Method* at bottom of stack.
82    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
83.endm
84
85    /*
86     * Macro that sets up the callee save frame to conform with
87     * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes
88     * non-moving GC.
89     * Does not include rSUSPEND or rSELF
90     * callee-save: padding + $s2-$s7 + $gp + $ra + $s8 = 9 total + 1x8 bytes padding
91     */
92.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
93    daddiu $sp, $sp, -80
94    .cfi_adjust_cfa_offset 80
95
96    // Ugly compile-time check, but we only have the preprocessor.
97#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 80)
98#error "REFS_ONLY_CALLEE_SAVE_FRAME(MIPS64) size not as expected."
99#endif
100
101    sd     $ra, 72($sp)
102    .cfi_rel_offset 31, 72
103    sd     $s8, 64($sp)
104    .cfi_rel_offset 30, 64
105    sd     $gp, 56($sp)
106    .cfi_rel_offset 28, 56
107    sd     $s7, 48($sp)
108    .cfi_rel_offset 23, 48
109    sd     $s6, 40($sp)
110    .cfi_rel_offset 22, 40
111    sd     $s5, 32($sp)
112    .cfi_rel_offset 21, 32
113    sd     $s4, 24($sp)
114    .cfi_rel_offset 20, 24
115    sd     $s3, 16($sp)
116    .cfi_rel_offset 19, 16
117    sd     $s2, 8($sp)
118    .cfi_rel_offset 18, 8
119    # load appropriate callee-save-method
120    ld      $v0, %got(_ZN3art7Runtime9instance_E)($gp)
121    ld      $v0, 0($v0)
122    THIS_LOAD_REQUIRES_READ_BARRIER
123    lwu     $v0, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET($v0)
124    sw      $v0, 0($sp)                                # Place Method* at bottom of stack.
125    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
126.endm
127
128.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
129    ld     $ra, 72($sp)
130    .cfi_restore 31
131    ld     $s8, 64($sp)
132    .cfi_restore 30
133    ld     $gp, 56($sp)
134    .cfi_restore 28
135    ld     $s7, 48($sp)
136    .cfi_restore 23
137    ld     $s6, 40($sp)
138    .cfi_restore 22
139    ld     $s5, 32($sp)
140    .cfi_restore 21
141    ld     $s4, 24($sp)
142    .cfi_restore 20
143    ld     $s3, 16($sp)
144    .cfi_restore 19
145    ld     $s2, 8($sp)
146    .cfi_restore 18
147    daddiu $sp, $sp, 80
148    .cfi_adjust_cfa_offset -80
149.endm
150
151.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
152    ld     $ra, 72($sp)
153    .cfi_restore 31
154    ld     $s8, 64($sp)
155    .cfi_restore 30
156    ld     $gp, 56($sp)
157    .cfi_restore 28
158    ld     $s7, 48($sp)
159    .cfi_restore 23
160    ld     $s6, 40($sp)
161    .cfi_restore 22
162    ld     $s5, 32($sp)
163    .cfi_restore 21
164    ld     $s4, 24($sp)
165    .cfi_restore 20
166    ld     $s3, 16($sp)
167    .cfi_restore 19
168    ld     $s2, 8($sp)
169    .cfi_restore 18
170    jalr   $zero, $ra
171    daddiu $sp, $sp, 80
172    .cfi_adjust_cfa_offset -80
173.endm
174
175// This assumes the top part of these stack frame types are identical.
176#define REFS_AND_ARGS_MINUS_REFS_SIZE (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
177
178.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
179    daddiu  $sp, $sp, -208
180    .cfi_adjust_cfa_offset 208
181
182    // Ugly compile-time check, but we only have the preprocessor.
183#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 208)
184#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(MIPS64) size not as expected."
185#endif
186
187    sd     $ra, 200($sp)           # = kQuickCalleeSaveFrame_RefAndArgs_LrOffset
188    .cfi_rel_offset 31, 200
189    sd     $s8, 192($sp)
190    .cfi_rel_offset 30, 192
191    sd     $gp, 184($sp)
192    .cfi_rel_offset 28, 184
193    sd     $s7, 176($sp)
194    .cfi_rel_offset 23, 176
195    sd     $s6, 168($sp)
196    .cfi_rel_offset 22, 168
197    sd     $s5, 160($sp)
198    .cfi_rel_offset 21, 160
199    sd     $s4, 152($sp)
200    .cfi_rel_offset 20, 152
201    sd     $s3, 144($sp)
202    .cfi_rel_offset 19, 144
203    sd     $s2, 136($sp)
204    .cfi_rel_offset 18, 136
205
206    sd     $a7, 128($sp)
207    .cfi_rel_offset 11, 128
208    sd     $a6, 120($sp)
209    .cfi_rel_offset 10, 120
210    sd     $a5, 112($sp)
211    .cfi_rel_offset 9, 112
212    sd     $a4, 104($sp)
213    .cfi_rel_offset 8, 104
214    sd     $a3,  96($sp)
215    .cfi_rel_offset 7, 96
216    sd     $a2,  88($sp)
217    .cfi_rel_offset 6, 88
218    sd     $a1,  80($sp)           # = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset
219    .cfi_rel_offset 5, 80
220
221    s.d    $f19, 72($sp)
222    s.d    $f18, 64($sp)
223    s.d    $f17, 56($sp)
224    s.d    $f16, 48($sp)
225    s.d    $f15, 40($sp)
226    s.d    $f14, 32($sp)
227    s.d    $f13, 24($sp)           # = kQuickCalleeSaveFrame_RefAndArgs_Fpr1Offset
228    s.d    $f12, 16($sp)           # This isn't necessary to store.
229    # 1x8 bytes padding + Method*
230.endm
231
232    /*
233     * Macro that sets up the callee save frame to conform with
234     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes
235     * non-moving GC.
236     * callee-save: padding + $f12-$f19 + $a1-$a7 + $s2-$s7 + $gp + $ra + $s8 = 24 total + 1 words padding + Method*
237     */
238.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
239    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
240    # load appropriate callee-save-method
241    ld      $v0, %got(_ZN3art7Runtime9instance_E)($gp)
242    ld      $v0, 0($v0)
243    THIS_LOAD_REQUIRES_READ_BARRIER
244    lwu     $v0, RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET($v0)
245    sw      $v0, 0($sp)                                # Place Method* at bottom of stack.
246    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
247.endm
248
249.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_A0
250    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL
251    sw      $a0, 0($sp)                                # Place Method* at bottom of stack.
252    sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
253.endm
254
255.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
256    ld     $ra, 200($sp)
257    .cfi_restore 31
258    ld     $s8, 192($sp)
259    .cfi_restore 30
260    ld     $gp, 184($sp)
261    .cfi_restore 28
262    ld     $s7, 176($sp)
263    .cfi_restore 23
264    ld     $s6, 168($sp)
265    .cfi_restore 22
266    ld     $s5, 160($sp)
267    .cfi_restore 21
268    ld     $s4, 152($sp)
269    .cfi_restore 20
270    ld     $s3, 144($sp)
271    .cfi_restore 19
272    ld     $s2, 136($sp)
273    .cfi_restore 18
274
275    ld     $a7, 128($sp)
276    .cfi_restore 11
277    ld     $a6, 120($sp)
278    .cfi_restore 10
279    ld     $a5, 112($sp)
280    .cfi_restore 9
281    ld     $a4, 104($sp)
282    .cfi_restore 8
283    ld     $a3,  96($sp)
284    .cfi_restore 7
285    ld     $a2,  88($sp)
286    .cfi_restore 6
287    ld     $a1,  80($sp)
288    .cfi_restore 5
289
290    l.d    $f19, 72($sp)
291    l.d    $f18, 64($sp)
292    l.d    $f17, 56($sp)
293    l.d    $f16, 48($sp)
294    l.d    $f15, 40($sp)
295    l.d    $f14, 32($sp)
296    l.d    $f13, 24($sp)
297    l.d    $f12, 16($sp)
298
299    daddiu $sp, $sp, 208
300    .cfi_adjust_cfa_offset -208
301.endm
302
303    /*
304     * Macro that set calls through to artDeliverPendingExceptionFromCode,
305     * where the pending
306     * exception is Thread::Current()->exception_
307     */
308.macro DELIVER_PENDING_EXCEPTION
309    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME     # save callee saves for throw
310    dla     $t9, artDeliverPendingExceptionFromCode
311    jalr    $zero, $t9                   # artDeliverPendingExceptionFromCode(Thread*)
312    move    $a0, rSELF                   # pass Thread::Current
313.endm
314
315.macro RETURN_IF_NO_EXCEPTION
316    ld     $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
317    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
318    bne    $t0, $zero, 1f                      # success if no exception is pending
319    nop
320    jalr   $zero, $ra
321    nop
3221:
323    DELIVER_PENDING_EXCEPTION
324.endm
325
326.macro RETURN_IF_ZERO
327    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
328    bne    $v0, $zero, 1f                # success?
329    nop
330    jalr   $zero, $ra                    # return on success
331    nop
3321:
333    DELIVER_PENDING_EXCEPTION
334.endm
335
336.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
337    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
338    beq    $v0, $zero, 1f                # success?
339    nop
340    jalr   $zero, $ra                    # return on success
341    nop
3421:
343    DELIVER_PENDING_EXCEPTION
344.endm
345
346    /*
347     * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_
348     * FIXME: just guessing about the shape of the jmpbuf.  Where will pc be?
349     */
350ENTRY art_quick_do_long_jump
351    l.d     $f0, 0($a1)
352    l.d     $f1, 8($a1)
353    l.d     $f2, 16($a1)
354    l.d     $f3, 24($a1)
355    l.d     $f4, 32($a1)
356    l.d     $f5, 40($a1)
357    l.d     $f6, 48($a1)
358    l.d     $f7, 56($a1)
359    l.d     $f8, 64($a1)
360    l.d     $f9, 72($a1)
361    l.d     $f10, 80($a1)
362    l.d     $f11, 88($a1)
363    l.d     $f12, 96($a1)
364    l.d     $f13, 104($a1)
365    l.d     $f14, 112($a1)
366    l.d     $f15, 120($a1)
367    l.d     $f16, 128($a1)
368    l.d     $f17, 136($a1)
369    l.d     $f18, 144($a1)
370    l.d     $f19, 152($a1)
371    l.d     $f20, 160($a1)
372    l.d     $f21, 168($a1)
373    l.d     $f22, 176($a1)
374    l.d     $f23, 184($a1)
375    l.d     $f24, 192($a1)
376    l.d     $f25, 200($a1)
377    l.d     $f26, 208($a1)
378    l.d     $f27, 216($a1)
379    l.d     $f28, 224($a1)
380    l.d     $f29, 232($a1)
381    l.d     $f30, 240($a1)
382    l.d     $f31, 248($a1)
383    .set push
384    .set nomacro
385    .set noat
386# no need to load zero
387    ld      $at, 8($a0)
388    .set pop
389    ld      $v0, 16($a0)
390    ld      $v1, 24($a0)
391# a0 has to be loaded last
392    ld      $a1, 40($a0)
393    ld      $a2, 48($a0)
394    ld      $a3, 56($a0)
395    ld      $a4, 64($a0)
396    ld      $a5, 72($a0)
397    ld      $a6, 80($a0)
398    ld      $a7, 88($a0)
399    ld      $t0, 96($a0)
400    ld      $t1, 104($a0)
401    ld      $t2, 112($a0)
402    ld      $t3, 120($a0)
403    ld      $s0, 128($a0)
404    ld      $s1, 136($a0)
405    ld      $s2, 144($a0)
406    ld      $s3, 152($a0)
407    ld      $s4, 160($a0)
408    ld      $s5, 168($a0)
409    ld      $s6, 176($a0)
410    ld      $s7, 184($a0)
411    ld      $t8, 192($a0)
412    ld      $t9, 200($a0)
413# no need to load k0, k1
414    ld      $gp, 224($a0)
415    ld      $sp, 232($a0)
416    ld      $s8, 240($a0)
417    ld      $ra, 248($a0)
418    ld      $a0, 32($a0)
419    move    $v0, $zero          # clear result registers v0 and v1
420    jalr    $zero, $ra          # do long jump
421    move    $v1, $zero
422END art_quick_do_long_jump
423
424    /*
425     * Called by managed code, saves most registers (forms basis of long jump
426     * context) and passes the bottom of the stack.
427     * artDeliverExceptionFromCode will place the callee save Method* at
428     * the bottom of the thread. On entry v0 holds Throwable*
429     */
430ENTRY art_quick_deliver_exception
431    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
432    dla  $t9, artDeliverExceptionFromCode
433    jalr $zero, $t9                 # artDeliverExceptionFromCode(Throwable*, Thread*)
434    move $a1, rSELF                 # pass Thread::Current
435END art_quick_deliver_exception
436
437    /*
438     * Called by managed code to create and deliver a NullPointerException
439     */
440    .extern artThrowNullPointerExceptionFromCode
441ENTRY art_quick_throw_null_pointer_exception
442.Lart_quick_throw_null_pointer_exception_gp_set:
443    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
444    dla  $t9, artThrowNullPointerExceptionFromCode
445    jalr $zero, $t9                 # artThrowNullPointerExceptionFromCode(Thread*)
446    move $a0, rSELF                 # pass Thread::Current
447END art_quick_throw_null_pointer_exception
448
449    /*
450     * Called by managed code to create and deliver an ArithmeticException
451     */
452    .extern artThrowDivZeroFromCode
453ENTRY art_quick_throw_div_zero
454    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
455    dla  $t9, artThrowDivZeroFromCode
456    jalr $zero, $t9                 # artThrowDivZeroFromCode(Thread*)
457    move $a0, rSELF                 # pass Thread::Current
458END art_quick_throw_div_zero
459
460    /*
461     * Called by managed code to create and deliver an
462     * ArrayIndexOutOfBoundsException
463     */
464    .extern artThrowArrayBoundsFromCode
465ENTRY art_quick_throw_array_bounds
466.Lart_quick_throw_array_bounds_gp_set:
467    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
468    dla  $t9, artThrowArrayBoundsFromCode
469    jalr $zero, $t9                 # artThrowArrayBoundsFromCode(index, limit, Thread*)
470    move $a2, rSELF                 # pass Thread::Current
471END art_quick_throw_array_bounds
472
473    /*
474     * Called by managed code to create and deliver a StackOverflowError.
475     */
476    .extern artThrowStackOverflowFromCode
477ENTRY art_quick_throw_stack_overflow
478    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
479    dla  $t9, artThrowStackOverflowFromCode
480    jalr $zero, $t9                 # artThrowStackOverflowFromCode(Thread*)
481    move $a0, rSELF                 # pass Thread::Current
482END art_quick_throw_stack_overflow
483
484    /*
485     * Called by managed code to create and deliver a NoSuchMethodError.
486     */
487    .extern artThrowNoSuchMethodFromCode
488ENTRY art_quick_throw_no_such_method
489    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
490    dla  $t9, artThrowNoSuchMethodFromCode
491    jalr $zero, $t9                 # artThrowNoSuchMethodFromCode(method_idx, Thread*)
492    move $a1, rSELF                 # pass Thread::Current
493END art_quick_throw_no_such_method
494
495    /*
496     * All generated callsites for interface invokes and invocation slow paths will load arguments
497     * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
498     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
499     * stack and call the appropriate C helper.
500     * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
501     *
502     * The helper will attempt to locate the target and return a 128-bit result in $v0/$v1 consisting
503     * of the target Method* in $v0 and method->code_ in $v1.
504     *
505     * If unsuccessful, the helper will return null/null. There will be a pending exception in the
506     * thread and we branch to another stub to deliver it.
507     *
508     * On success this wrapper will restore arguments and *jump* to the target, leaving the ra
509     * pointing back to the original caller.
510     */
511.macro INVOKE_TRAMPOLINE c_name, cxx_name
512    .extern \cxx_name
513ENTRY \c_name
514    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME  # save callee saves in case allocation triggers GC
515    lwu   $a2, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE($sp)  # pass caller Method*
516    move  $a3, rSELF                       # pass Thread::Current
517    jal   \cxx_name                        # (method_idx, this, caller, Thread*, $sp)
518    move  $a4, $sp                         # pass $sp
519    move  $a0, $v0                         # save target Method*
520    move  $t9, $v1                         # save $v0->code_
521    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
522    beq   $v0, $zero, 1f
523    nop
524    jalr  $zero, $t9
525    nop
5261:
527    DELIVER_PENDING_EXCEPTION
528END \c_name
529.endm
530
531INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
532INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
533
534INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
535INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
536INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
537INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
538
539    # On entry:
540    #   t0 = shorty
541    #   t1 = ptr to arg_array
542    #   t2 = number of argument bytes remain
543    #   v0 = ptr to stack frame where to copy arg_array
544    # This macro modifies t3, t9 and v0
545.macro LOOP_OVER_SHORTY_LOADING_REG gpu, fpu, label
546    lbu    $t3, 0($t0)           # get argument type from shorty
547    beqz   $t3, \label
548    daddiu $t0, 1
549    li     $t9, 68               # put char 'D' into t9
550    beq    $t9, $t3, 1f          # branch if result type char == 'D'
551    li     $t9, 70               # put char 'F' into t9
552    beq    $t9, $t3, 2f          # branch if result type char == 'F'
553    li     $t9, 74               # put char 'J' into t9
554    beq    $t9, $t3, 3f          # branch if result type char == 'J'
555    nop
556    lw     $\gpu, 0($t1)
557    sw     $\gpu, 0($v0)
558    daddiu $v0, 4
559    daddiu $t1, 4
560    b      4f
561    daddiu $t2, -4               # delay slot
562
5631:  # found double
564    lwu    $t3, 0($t1)
565    mtc1   $t3, $\fpu
566    sw     $t3, 0($v0)
567    lwu    $t3, 4($t1)
568    mthc1  $t3, $\fpu
569    sw     $t3, 4($v0)
570    daddiu $v0, 8
571    daddiu $t1, 8
572    b      4f
573    daddiu $t2, -8               # delay slot
574
5752:  # found float
576    lwu    $t3, 0($t1)
577    mtc1   $t3, $\fpu
578    sw     $t3, 0($v0)
579    daddiu $v0, 4
580    daddiu $t1, 4
581    b      4f
582    daddiu $t2, -4               # delay slot
583
5843:  # found long (8 bytes)
585    lwu    $t3, 0($t1)
586    sw     $t3, 0($v0)
587    lwu    $t9, 4($t1)
588    sw     $t9, 4($v0)
589    dsll   $t9, $t9, 32
590    or     $\gpu, $t9, $t3
591    daddiu $v0, 8
592    daddiu $t1, 8
593    daddiu $t2, -8
5944:
595.endm
596
597    /*
598     * Invocation stub for quick code.
599     * On entry:
600     *   a0 = method pointer
601     *   a1 = argument array that must at least contain the this ptr.
602     *   a2 = size of argument array in bytes
603     *   a3 = (managed) thread pointer
604     *   a4 = JValue* result
605     *   a5 = shorty
606     */
607ENTRY art_quick_invoke_stub
608    # push a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra onto the stack
609    daddiu $sp, $sp, -48
610    .cfi_adjust_cfa_offset 48
611    sd     $ra, 40($sp)
612    .cfi_rel_offset 31, 40
613    sd     $s8, 32($sp)
614    .cfi_rel_offset 30, 32
615    sd     $s1, 24($sp)
616    .cfi_rel_offset 17, 24
617    sd     $s0, 16($sp)
618    .cfi_rel_offset 16, 16
619    sd     $a5, 8($sp)
620    .cfi_rel_offset 9, 8
621    sd     $a4, 0($sp)
622    .cfi_rel_offset 8, 0
623
624    daddiu $s0, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
625    move   $s1, $a3              # move managed thread pointer into s1 (rSELF)
626    move   $s8, $sp              # save sp in s8 (fp)
627
628    daddiu $t3, $a2, 20          # add 4 for method* and 16 for stack alignment
629    dsrl   $t3, $t3, 4           # shift the frame size right 4
630    dsll   $t3, $t3, 4           # shift the frame size left 4 to align to 16 bytes
631    dsubu  $sp, $sp, $t3         # reserve stack space for argument array
632
633    daddiu $t0, $a5, 1           # t0 = shorty[1] (skip 1 for return type)
634    daddiu $t1, $a1, 4           # t1 = ptr to arg_array[4] (skip this ptr)
635    daddiu $t2, $a2, -4          # t2 = number of argument bytes remain (skip this ptr)
636    daddiu $v0, $sp, 8           # v0 points to where to copy arg_array
637    LOOP_OVER_SHORTY_LOADING_REG a2, f14, call_fn
638    LOOP_OVER_SHORTY_LOADING_REG a3, f15, call_fn
639    LOOP_OVER_SHORTY_LOADING_REG a4, f16, call_fn
640    LOOP_OVER_SHORTY_LOADING_REG a5, f17, call_fn
641    LOOP_OVER_SHORTY_LOADING_REG a6, f18, call_fn
642    LOOP_OVER_SHORTY_LOADING_REG a7, f19, call_fn
643
644    # copy arguments onto stack (t2 should be multiples of 4)
645    ble    $t2, $zero, call_fn   # t2 = number of argument bytes remain
6461:
647    lw     $t3, 0($t1)           # load from argument array
648    daddiu $t1, $t1, 4
649    sw     $t3, 0($v0)           # save to stack
650    daddiu $t2, -4
651    bgt    $t2, $zero, 1b        # t2 = number of argument bytes remain
652    daddiu $v0, $v0, 4
653
654call_fn:
655    # call method (a0 and a1 have been untouched)
656    lwu    $a1, 0($a1)           # make a1 = this ptr
657    sw     $a1, 4($sp)           # copy this ptr (skip 4 bytes for method*)
658    sw     $zero, 0($sp)         # store null for method* at bottom of frame
659    ld     $t9, MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64($a0)  # get pointer to the code
660    jalr   $t9                   # call the method
661    nop
662    move   $sp, $s8              # restore sp
663
664    # pop a4, a5, s1(rSELF), s8, ra off of the stack
665    ld     $a4, 0($sp)
666    .cfi_restore 8
667    ld     $a5, 8($sp)
668    .cfi_restore 9
669    ld     $s0, 16($sp)
670    .cfi_restore 16
671    ld     $s1, 24($sp)
672    .cfi_restore 17
673    ld     $s8, 32($sp)
674    .cfi_restore 30
675    ld     $ra, 40($sp)
676    .cfi_restore 31
677    daddiu $sp, $sp, 48
678    .cfi_adjust_cfa_offset -48
679
680    # a4 = JValue* result
681    # a5 = shorty string
682    lbu   $t1, 0($a5)           # get result type from shorty
683    li    $t2, 68               # put char 'D' into t2
684    beq   $t1, $t2, 1f          # branch if result type char == 'D'
685    li    $t3, 70               # put char 'F' into t3
686    beq   $t1, $t3, 1f          # branch if result type char == 'F'
687    sw    $v0, 0($a4)           # store the result
688    dsrl  $v1, $v0, 32
689    jalr  $zero, $ra
690    sw    $v1, 4($a4)           # store the other half of the result
6911:
692    mfc1  $v0, $f0
693    mfhc1 $v1, $f0
694    sw    $v0, 0($a4)           # store the result
695    jalr  $zero, $ra
696    sw    $v1, 4($a4)           # store the other half of the result
697END art_quick_invoke_stub
698
699    /*
700     * Invocation static stub for quick code.
701     * On entry:
702     *   a0 = method pointer
703     *   a1 = argument array that must at least contain the this ptr.
704     *   a2 = size of argument array in bytes
705     *   a3 = (managed) thread pointer
706     *   a4 = JValue* result
707     *   a5 = shorty
708     */
709ENTRY art_quick_invoke_static_stub
710
711    # push a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra, onto the stack
712    daddiu $sp, $sp, -48
713    .cfi_adjust_cfa_offset 48
714    sd     $ra, 40($sp)
715    .cfi_rel_offset 31, 40
716    sd     $s8, 32($sp)
717    .cfi_rel_offset 30, 32
718    sd     $s1, 24($sp)
719    .cfi_rel_offset 17, 24
720    sd     $s0, 16($sp)
721    .cfi_rel_offset 16, 16
722    sd     $a5, 8($sp)
723    .cfi_rel_offset 9, 8
724    sd     $a4, 0($sp)
725    .cfi_rel_offset 8, 0
726
727    daddiu $s0, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
728    move   $s1, $a3              # move managed thread pointer into s1 (rSELF)
729    move   $s8, $sp              # save sp in s8 (fp)
730
731    daddiu $t3, $a2, 20          # add 4 for method* and 16 for stack alignment
732    dsrl   $t3, $t3, 4           # shift the frame size right 4
733    dsll   $t3, $t3, 4           # shift the frame size left 4 to align to 16 bytes
734    dsubu  $sp, $sp, $t3         # reserve stack space for argument array
735
736    daddiu $t0, $a5, 1           # t0 = shorty[1] (skip 1 for return type)
737    move   $t1, $a1              # t1 = arg_array
738    move   $t2, $a2              # t2 = number of argument bytes remain
739    daddiu $v0, $sp, 4           # v0 points to where to copy arg_array
740    LOOP_OVER_SHORTY_LOADING_REG a1, f13, call_sfn
741    LOOP_OVER_SHORTY_LOADING_REG a2, f14, call_sfn
742    LOOP_OVER_SHORTY_LOADING_REG a3, f15, call_sfn
743    LOOP_OVER_SHORTY_LOADING_REG a4, f16, call_sfn
744    LOOP_OVER_SHORTY_LOADING_REG a5, f17, call_sfn
745    LOOP_OVER_SHORTY_LOADING_REG a6, f18, call_sfn
746    LOOP_OVER_SHORTY_LOADING_REG a7, f19, call_sfn
747
748    # copy arguments onto stack (t2 should be multiples of 4)
749    ble    $t2, $zero, call_sfn  # t2 = number of argument bytes remain
7501:
751    lw     $t3, 0($t1)           # load from argument array
752    daddiu $t1, $t1, 4
753    sw     $t3, 0($v0)           # save to stack
754    daddiu $t2, -4
755    bgt    $t2, $zero, 1b        # t2 = number of argument bytes remain
756    daddiu $v0, $v0, 4
757
758call_sfn:
759    # call method (a0 has been untouched)
760    sw     $zero, 0($sp)         # store null for method* at bottom of frame
761    ld     $t9, MIRROR_ART_METHOD_QUICK_CODE_OFFSET_64($a0)  # get pointer to the code
762    jalr   $t9                   # call the method
763    nop
764    move   $sp, $s8              # restore sp
765
766    # pop a4, a5, s0(rSUSPEND), s1(rSELF), s8, ra off of the stack
767    ld     $a4, 0($sp)
768    .cfi_restore 8
769    ld     $a5, 8($sp)
770    .cfi_restore 9
771    ld     $s0, 16($sp)
772    .cfi_restore 16
773    ld     $s1, 24($sp)
774    .cfi_restore 17
775    ld     $s8, 32($sp)
776    .cfi_restore 30
777    ld     $ra, 40($sp)
778    .cfi_restore 31
779    daddiu $sp, $sp, 48
780    .cfi_adjust_cfa_offset -48
781
782    # a4 = JValue* result
783    # a5 = shorty string
784    lbu   $t1, 0($a5)           # get result type from shorty
785    li    $t2, 68               # put char 'D' into t2
786    beq   $t1, $t2, 1f          # branch if result type char == 'D'
787    li    $t3, 70               # put char 'F' into t3
788    beq   $t1, $t3, 1f          # branch if result type char == 'F'
789    sw    $v0, 0($a4)           # store the result
790    dsrl  $v1, $v0, 32
791    jalr  $zero, $ra
792    sw    $v1, 4($a4)           # store the other half of the result
7931:
794    mfc1  $v0, $f0
795    mfhc1 $v1, $f0
796    sw    $v0, 0($a4)           # store the result
797    jalr  $zero, $ra
798    sw    $v1, 4($a4)           # store the other half of the result
799END art_quick_invoke_static_stub
800
801    /*
802     * Entry from managed code that calls artHandleFillArrayDataFromCode and
803     * delivers exception on failure.
804     */
805    .extern artHandleFillArrayDataFromCode
806ENTRY art_quick_handle_fill_data
807    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case exception allocation triggers GC
808    lwu     $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
809    jal     artHandleFillArrayDataFromCode              # (payload offset, Array*, method, Thread*)
810    move    $a3, rSELF                                  # pass Thread::Current
811    RETURN_IF_ZERO
812END art_quick_handle_fill_data
813
814    /*
815     * Entry from managed code that calls artLockObjectFromCode, may block for GC.
816     */
817    .extern artLockObjectFromCode
818ENTRY art_quick_lock_object
819    beq     $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set
820    nop
821    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME     # save callee saves in case we block
822    jal     artLockObjectFromCode         # (Object* obj, Thread*)
823    move    $a1, rSELF                    # pass Thread::Current
824    RETURN_IF_ZERO
825END art_quick_lock_object
826
827    /*
828     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
829     */
830    .extern artUnlockObjectFromCode
831ENTRY art_quick_unlock_object
832    beq     $a0, $zero, .Lart_quick_throw_null_pointer_exception_gp_set
833    nop
834    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case exception allocation triggers GC
835    jal     artUnlockObjectFromCode    # (Object* obj, Thread*)
836    move    $a1, rSELF                 # pass Thread::Current
837    RETURN_IF_ZERO
838END art_quick_unlock_object
839
840    /*
841     * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
842     */
843    .extern artThrowClassCastException
844ENTRY art_quick_check_cast
845    daddiu $sp, $sp, -32
846    .cfi_adjust_cfa_offset 32
847    sd     $ra, 24($sp)
848    .cfi_rel_offset 31, 24
849    sd     $t9, 16($sp)
850    sd     $a1, 8($sp)
851    sd     $a0, 0($sp)
852    jal    artIsAssignableFromCode
853    nop
854    beq    $v0, $zero, .Lthrow_class_cast_exception
855    ld     $ra, 24($sp)
856    jalr   $zero, $ra
857    daddiu $sp, $sp, 32
858    .cfi_adjust_cfa_offset -32
859.Lthrow_class_cast_exception:
860    ld     $t9, 16($sp)
861    ld     $a1, 8($sp)
862    ld     $a0, 0($sp)
863    daddiu $sp, $sp, 32
864    .cfi_adjust_cfa_offset -32
865    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
866    dla  $t9, artThrowClassCastException
867    jalr $zero, $t9                 # artThrowClassCastException (Class*, Class*, Thread*)
868    move $a2, rSELF                 # pass Thread::Current
869END art_quick_check_cast
870
871    /*
872     * Entry from managed code for array put operations of objects where the value being stored
873     * needs to be checked for compatibility.
874     * a0 = array, a1 = index, a2 = value
875     */
876ENTRY art_quick_aput_obj_with_null_and_bound_check
877    bne    $a0, $zero, .Lart_quick_aput_obj_with_bound_check_gp_set
878    nop
879    b .Lart_quick_throw_null_pointer_exception_gp_set
880    nop
881END art_quick_aput_obj_with_null_and_bound_check
882
883ENTRY art_quick_aput_obj_with_bound_check
884    lwu  $t0, MIRROR_ARRAY_LENGTH_OFFSET($a0)
885    sltu $t1, $a1, $t0
886    bne  $t1, $zero, .Lart_quick_aput_obj_gp_set
887    nop
888    move $a0, $a1
889    b .Lart_quick_throw_array_bounds_gp_set
890    move $a1, $t0
891END art_quick_aput_obj_with_bound_check
892
893ENTRY art_quick_aput_obj
894    beq  $a2, $zero, .Ldo_aput_null
895    nop
896    lwu $t0, MIRROR_OBJECT_CLASS_OFFSET($a0)
897    lwu $t1, MIRROR_OBJECT_CLASS_OFFSET($a2)
898    lwu $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($t0)
899    bne $t1, $t0, .Lcheck_assignability  # value's type == array's component type - trivial assignability
900    nop
901.Ldo_aput:
902    dsll  $a1, $a1, 2
903    daddu $t0, $a0, $a1
904    sw   $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
905    ld   $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
906    dsrl  $t1, $a0, 7
907    daddu $t1, $t1, $t0
908    sb   $t0, ($t1)
909    jalr $zero, $ra
910    nop
911.Ldo_aput_null:
912    dsll  $a1, $a1, 2
913    daddu $t0, $a0, $a1
914    sw   $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
915    jalr $zero, $ra
916    nop
917.Lcheck_assignability:
918    daddiu $sp, $sp, -64
919    .cfi_adjust_cfa_offset 64
920    sd     $ra, 56($sp)
921    .cfi_rel_offset 31, 56
922    sd     $t9, 24($sp)
923    sd     $a2, 16($sp)
924    sd     $a1, 8($sp)
925    sd     $a0, 0($sp)
926    move   $a1, $t1
927    move   $a0, $t0
928    jal    artIsAssignableFromCode  # (Class*, Class*)
929    nop
930    ld     $ra, 56($sp)
931    ld     $t9, 24($sp)
932    ld     $a2, 16($sp)
933    ld     $a1, 8($sp)
934    ld     $a0, 0($sp)
935    daddiu $sp, $sp, 64
936    .cfi_adjust_cfa_offset -64
937    bne    $v0, $zero, .Ldo_aput
938    nop
939    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
940    move   $a1, $a2
941    dla  $t9, artThrowArrayStoreException
942    jalr $zero, $t9                 # artThrowArrayStoreException(Class*, Class*, Thread*)
943    move   $a2, rSELF               # pass Thread::Current
944END art_quick_aput_obj
945
946    /*
947     * Called by managed code to resolve a static field and load a boolean primitive value.
948     */
949    .extern artGetBooleanStaticFromCode
950ENTRY art_quick_get_boolean_static
951    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
952    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
953    jal    artGetBooleanStaticFromCode   # (uint32_t field_idx, const Method* referrer, Thread*)
954    move   $a2, rSELF                    # pass Thread::Current
955    RETURN_IF_NO_EXCEPTION
956END art_quick_get_boolean_static
957
958    /*
959     * Called by managed code to resolve a static field and load a byte primitive value.
960     */
961    .extern artGetByteStaticFromCode
962ENTRY art_quick_get_byte_static
963    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
964    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
965    jal    artGetByteStaticFromCode      # (uint32_t field_idx, const Method* referrer, Thread*)
966    move   $a2, rSELF                    # pass Thread::Current
967    RETURN_IF_NO_EXCEPTION
968END art_quick_get_byte_static
969
970    /*
971     * Called by managed code to resolve a static field and load a char primitive value.
972     */
973    .extern artGetCharStaticFromCode
974ENTRY art_quick_get_char_static
975    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
976    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
977    jal    artGetCharStaticFromCode      # (uint32_t field_idx, const Method* referrer, Thread*)
978    move   $a2, rSELF                    # pass Thread::Current
979    RETURN_IF_NO_EXCEPTION
980END art_quick_get_char_static
981
982    /*
983     * Called by managed code to resolve a static field and load a short primitive value.
984     */
985    .extern artGetShortStaticFromCode
986ENTRY art_quick_get_short_static
987    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
988    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
989    jal    artGetShortStaticFromCode     # (uint32_t field_idx, const Method* referrer, Thread*)
990    move   $a2, rSELF                    # pass Thread::Current
991    RETURN_IF_NO_EXCEPTION
992END art_quick_get_short_static
993
994    /*
995     * Called by managed code to resolve a static field and load a 32-bit primitive value.
996     */
997    .extern artGet32StaticFromCode
998ENTRY art_quick_get32_static
999    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1000    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1001    jal    artGet32StaticFromCode        # (uint32_t field_idx, const Method* referrer, Thread*)
1002    move   $a2, rSELF                    # pass Thread::Current
1003    RETURN_IF_NO_EXCEPTION
1004END art_quick_get32_static
1005
1006    /*
1007     * Called by managed code to resolve a static field and load a 64-bit primitive value.
1008     */
1009    .extern artGet64StaticFromCode
1010ENTRY art_quick_get64_static
1011    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1012    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1013    jal    artGet64StaticFromCode        # (uint32_t field_idx, const Method* referrer, Thread*)
1014    move   $a2, rSELF                    # pass Thread::Current
1015    RETURN_IF_NO_EXCEPTION
1016END art_quick_get64_static
1017
1018    /*
1019     * Called by managed code to resolve a static field and load an object reference.
1020     */
1021    .extern artGetObjStaticFromCode
1022ENTRY art_quick_get_obj_static
1023    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1024    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1025    jal    artGetObjStaticFromCode       # (uint32_t field_idx, const Method* referrer, Thread*)
1026    move   $a2, rSELF                    # pass Thread::Current
1027    RETURN_IF_NO_EXCEPTION
1028END art_quick_get_obj_static
1029
1030    /*
1031     * Called by managed code to resolve an instance field and load a boolean primitive value.
1032     */
1033    .extern artGetBooleanInstanceFromCode
1034ENTRY art_quick_get_boolean_instance
1035    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1036    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1037    jal    artGetBooleanInstanceFromCode # (field_idx, Object*, referrer, Thread*)
1038    move   $a3, rSELF                    # pass Thread::Current
1039    RETURN_IF_NO_EXCEPTION
1040END art_quick_get_boolean_instance
1041
1042    /*
1043     * Called by managed code to resolve an instance field and load a byte primitive value.
1044     */
1045    .extern artGetByteInstanceFromCode
1046ENTRY art_quick_get_byte_instance
1047    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1048    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1049    jal    artGetByteInstanceFromCode    # (field_idx, Object*, referrer, Thread*)
1050    move   $a3, rSELF                    # pass Thread::Current
1051    RETURN_IF_NO_EXCEPTION
1052END art_quick_get_byte_instance
1053
1054    /*
1055     * Called by managed code to resolve an instance field and load a char primitive value.
1056     */
1057    .extern artGetCharInstanceFromCode
1058ENTRY art_quick_get_char_instance
1059    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1060    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1061    jal    artGetCharInstanceFromCode    # (field_idx, Object*, referrer, Thread*)
1062    move   $a3, rSELF                    # pass Thread::Current
1063    RETURN_IF_NO_EXCEPTION
1064END art_quick_get_char_instance
1065
1066    /*
1067     * Called by managed code to resolve an instance field and load a short primitive value.
1068     */
1069    .extern artGetShortInstanceFromCode
1070ENTRY art_quick_get_short_instance
1071    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1072    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1073    jal    artGetShortInstanceFromCode   # (field_idx, Object*, referrer, Thread*)
1074    move   $a3, rSELF                    # pass Thread::Current
1075    RETURN_IF_NO_EXCEPTION
1076END art_quick_get_short_instance
1077
1078    /*
1079     * Called by managed code to resolve an instance field and load a 32-bit primitive value.
1080     */
1081    .extern artGet32InstanceFromCode
1082ENTRY art_quick_get32_instance
1083    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1084    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1085    jal    artGet32InstanceFromCode      # (field_idx, Object*, referrer, Thread*)
1086    move   $a3, rSELF                    # pass Thread::Current
1087    RETURN_IF_NO_EXCEPTION
1088END art_quick_get32_instance
1089
1090    /*
1091     * Called by managed code to resolve an instance field and load a 64-bit primitive value.
1092     */
1093    .extern artGet64InstanceFromCode
1094ENTRY art_quick_get64_instance
1095    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1096    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1097    jal    artGet64InstanceFromCode      # (field_idx, Object*, referrer, Thread*)
1098    move   $a3, rSELF                    # pass Thread::Current
1099    RETURN_IF_NO_EXCEPTION
1100END art_quick_get64_instance
1101
1102    /*
1103     * Called by managed code to resolve an instance field and load an object reference.
1104     */
1105    .extern artGetObjInstanceFromCode
1106ENTRY art_quick_get_obj_instance
1107    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1108    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1109    jal    artGetObjInstanceFromCode     # (field_idx, Object*, referrer, Thread*)
1110    move   $a3, rSELF                    # pass Thread::Current
1111    RETURN_IF_NO_EXCEPTION
1112END art_quick_get_obj_instance
1113
1114    /*
1115     * Called by managed code to resolve a static field and store a 8-bit primitive value.
1116     */
1117    .extern artSet8StaticFromCode
1118ENTRY art_quick_set8_static
1119    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1120    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1121    jal    artSet8StaticFromCode         # (field_idx, new_val, referrer, Thread*)
1122    move   $a3, rSELF                    # pass Thread::Current
1123    RETURN_IF_ZERO
1124END art_quick_set8_static
1125
1126    /*
1127     * Called by managed code to resolve a static field and store a 16-bit primitive value.
1128     */
1129    .extern artSet16StaticFromCode
1130ENTRY art_quick_set16_static
1131    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1132    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1133    jal    artSet16StaticFromCode        # (field_idx, new_val, referrer, Thread*)
1134    move   $a3, rSELF                    # pass Thread::Current
1135    RETURN_IF_ZERO
1136END art_quick_set16_static
1137
1138    /*
1139     * Called by managed code to resolve a static field and store a 32-bit primitive value.
1140     */
1141    .extern artSet32StaticFromCode
1142ENTRY art_quick_set32_static
1143    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1144    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1145    jal    artSet32StaticFromCode        # (field_idx, new_val, referrer, Thread*)
1146    move   $a3, rSELF                    # pass Thread::Current
1147    RETURN_IF_ZERO
1148END art_quick_set32_static
1149
1150    /*
1151     * Called by managed code to resolve a static field and store a 64-bit primitive value.
1152     */
1153    .extern artSet64StaticFromCode
1154ENTRY art_quick_set64_static
1155    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1156    move   $a2, $a1                      # pass new_val
1157    lwu    $a1, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1158    jal    artSet64StaticFromCode        # (field_idx, referrer, new_val, Thread*)
1159    move   $a3, rSELF                    # pass Thread::Current
1160    RETURN_IF_ZERO
1161END art_quick_set64_static
1162
1163    /*
1164     * Called by managed code to resolve a static field and store an object reference.
1165     */
1166    .extern artSetObjStaticFromCode
1167ENTRY art_quick_set_obj_static
1168    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1169    lwu    $a2, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1170    jal    artSetObjStaticFromCode       # (field_idx, new_val, referrer, Thread*)
1171    move   $a3, rSELF                    # pass Thread::Current
1172    RETURN_IF_ZERO
1173END art_quick_set_obj_static
1174
1175    /*
1176     * Called by managed code to resolve an instance field and store a 8-bit primitive value.
1177     */
1178    .extern artSet8InstanceFromCode
1179ENTRY art_quick_set8_instance
1180    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1181    lwu    $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1182    jal    artSet8InstanceFromCode       # (field_idx, Object*, new_val, referrer, Thread*)
1183    move   $a4, rSELF                    # pass Thread::Current
1184    RETURN_IF_ZERO
1185END art_quick_set8_instance
1186
1187    /*
1188     * Called by managed code to resolve an instance field and store a 16-bit primitive value.
1189     */
1190    .extern artSet16InstanceFromCode
1191ENTRY art_quick_set16_instance
1192    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1193    lwu    $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1194    jal    artSet16InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
1195    move   $a4, rSELF                    # pass Thread::Current
1196    RETURN_IF_ZERO
1197END art_quick_set16_instance
1198
1199    /*
1200     * Called by managed code to resolve an instance field and store a 32-bit primitive value.
1201     */
1202    .extern artSet32InstanceFromCode
1203ENTRY art_quick_set32_instance
1204    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1205    lwu    $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1206    jal    artSet32InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
1207    move   $a4, rSELF                    # pass Thread::Current
1208    RETURN_IF_ZERO
1209END art_quick_set32_instance
1210
1211    /*
1212     * Called by managed code to resolve an instance field and store a 64-bit primitive value.
1213     */
1214    .extern artSet64InstanceFromCode
1215ENTRY art_quick_set64_instance
1216    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1217    lwu    $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1218    jal    artSet64InstanceFromCode      # (field_idx, Object*, new_val, referrer, Thread*)
1219    move   $a4, rSELF                    # pass Thread::Current
1220    RETURN_IF_ZERO
1221END art_quick_set64_instance
1222
1223    /*
1224     * Called by managed code to resolve an instance field and store an object reference.
1225     */
1226    .extern artSetObjInstanceFromCode
1227ENTRY art_quick_set_obj_instance
1228    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME    # save callee saves in case of GC
1229    lwu    $a3, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE($sp)  # pass referrer's Method*
1230    jal    artSetObjInstanceFromCode     # (field_idx, Object*, new_val, referrer, Thread*)
1231    move   $a4, rSELF                    # pass Thread::Current
1232    RETURN_IF_ZERO
1233END art_quick_set_obj_instance
1234
1235// Macro to facilitate adding new allocation entrypoints.
1236.macro ONE_ARG_DOWNCALL name, entrypoint, return
1237    .extern \entrypoint
1238ENTRY \name
1239    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
1240    jal     \entrypoint
1241    move    $a1, rSELF                 # pass Thread::Current
1242    \return
1243END \name
1244.endm
1245
1246// Macro to facilitate adding new allocation entrypoints.
1247.macro TWO_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    jal     \entrypoint
1252    move    $a2, rSELF                 # pass Thread::Current
1253    \return
1254END \name
1255.endm
1256
1257.macro THREE_ARG_DOWNCALL name, entrypoint, return
1258    .extern \entrypoint
1259ENTRY \name
1260    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
1261    jal     \entrypoint
1262    move    $a3, rSELF                 # pass Thread::Current
1263    \return
1264END \name
1265.endm
1266
1267.macro FOUR_ARG_DOWNCALL name, entrypoint, return
1268    .extern \entrypoint
1269ENTRY \name
1270    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME  # save callee saves in case of GC
1271    jal     \entrypoint
1272    move    $a4, rSELF                 # pass Thread::Current
1273    \return
1274END \name
1275.endm
1276
1277// Generate the allocation entrypoints for each allocator.
1278GENERATE_ALL_ALLOC_ENTRYPOINTS
1279
1280    /*
1281     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
1282     * exception on error. On success the String is returned. A0 holds the string index. The fast
1283     * path check for hit in strings cache has already been performed.
1284     */
1285ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1286
1287    /*
1288     * Entry from managed code when uninitialized static storage, this stub will run the class
1289     * initializer and deliver the exception on error. On success the static storage base is
1290     * returned.
1291     */
1292ONE_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1293
1294    /*
1295     * Entry from managed code when dex cache misses for a type_idx.
1296     */
1297ONE_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1298
1299    /*
1300     * Entry from managed code when type_idx needs to be checked for access and dex cache may also
1301     * miss.
1302     */
1303ONE_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1304
1305    /*
1306     * Called by managed code when the value in rSUSPEND has been decremented to 0.
1307     */
1308    .extern artTestSuspendFromCode
1309ENTRY art_quick_test_suspend
1310    lh     $a0, THREAD_FLAGS_OFFSET(rSELF)
1311    bne    $a0, $zero, 1f
1312    daddiu rSUSPEND, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
1313    jalr   $zero, $ra
1314    nop
13151:
1316    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME         # save callee saves for stack crawl
1317    jal    artTestSuspendFromCode             # (Thread*)
1318    move   $a0, rSELF
1319    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
1320END art_quick_test_suspend
1321
1322    /*
1323     * Called by managed code that is attempting to call a method on a proxy class. On entry
1324     * r0 holds the proxy method; r1, r2 and r3 may contain arguments.
1325     */
1326    .extern artQuickProxyInvokeHandler
1327ENTRY art_quick_proxy_invoke_handler
1328    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_A0
1329    move    $a2, rSELF             # pass Thread::Current
1330    jal     artQuickProxyInvokeHandler  # (Method* proxy method, receiver, Thread*, SP)
1331    move    $a3, $sp               # pass $sp
1332    ld      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
1333    daddiu  $sp, $sp, REFS_AND_ARGS_MINUS_REFS_SIZE  # skip a0-a7 and f12-f19
1334    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1335    bne     $t0, $zero, 1f
1336    dmtc1   $v0, $f0               # place return value to FP return value
1337    jalr    $zero, $ra
1338    dmtc1   $v1, $f1               # place return value to FP return value
13391:
1340    DELIVER_PENDING_EXCEPTION
1341END art_quick_proxy_invoke_handler
1342
1343    /*
1344     * Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's
1345     * dex method index.
1346     */
1347ENTRY art_quick_imt_conflict_trampoline
1348    lwu     $a0, 0($sp)            # load caller Method*
1349    lwu     $a0, MIRROR_ART_METHOD_DEX_CACHE_METHODS_OFFSET($a0)  # load dex_cache_resolved_methods
1350    dsll    $t0, 2                 # convert target method offset to bytes
1351    daddu   $a0, $t0               # get address of target method
1352    dla     $t9, art_quick_invoke_interface_trampoline
1353    jalr    $zero, $t9
1354    lwu     $a0, MIRROR_OBJECT_ARRAY_DATA_OFFSET($a0)  # load the target method
1355END art_quick_imt_conflict_trampoline
1356
1357    .extern artQuickResolutionTrampoline
1358ENTRY art_quick_resolution_trampoline
1359    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1360    move    $a2, rSELF             # pass Thread::Current
1361    jal     artQuickResolutionTrampoline  # (Method* called, receiver, Thread*, SP)
1362    move    $a3, $sp               # pass $sp
1363    beq     $v0, $zero, 1f
1364    lwu     $a0, 0($sp)            # load resolved method in $a0
1365                                   # artQuickResolutionTrampoline puts resolved method in *SP
1366    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1367    move    $t9, $v0               # code pointer must be in $t9 to generate the global pointer
1368    jalr    $zero, $t9             # tail call to method
1369    nop
13701:
1371    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1372    DELIVER_PENDING_EXCEPTION
1373END art_quick_resolution_trampoline
1374
1375    .extern artQuickGenericJniTrampoline
1376    .extern artQuickGenericJniEndTrampoline
1377ENTRY art_quick_generic_jni_trampoline
1378    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_A0
1379    move    $s8, $sp               # save $sp
1380
1381    # prepare for call to artQuickGenericJniTrampoline(Thread*, SP)
1382    move    $a0, rSELF             # pass Thread::Current
1383    move    $a1, $sp               # pass $sp
1384    jal     artQuickGenericJniTrampoline   # (Thread*, SP)
1385    daddiu  $sp, $sp, -5120        # reserve space on the stack
1386
1387    # The C call will have registered the complete save-frame on success.
1388    # The result of the call is:
1389    # v0: ptr to native code, 0 on error.
1390    # v1: ptr to the bottom of the used area of the alloca, can restore stack till here.
1391    beq     $v0, $zero, 1f         # check entry error
1392    move    $t9, $v0               # save the code ptr
1393    move    $sp, $v1               # release part of the alloca
1394
1395    # Load parameters from stack into registers
1396    ld      $a0,   0($sp)
1397    ld      $a1,   8($sp)
1398    ld      $a2,  16($sp)
1399    ld      $a3,  24($sp)
1400    ld      $a4,  32($sp)
1401    ld      $a5,  40($sp)
1402    ld      $a6,  48($sp)
1403    ld      $a7,  56($sp)
1404    # Load FPRs the same as GPRs. Look at BuildNativeCallFrameStateMachine.
1405    l.d     $f12,  0($sp)
1406    l.d     $f13,  8($sp)
1407    l.d     $f14, 16($sp)
1408    l.d     $f15, 24($sp)
1409    l.d     $f16, 32($sp)
1410    l.d     $f17, 40($sp)
1411    l.d     $f18, 48($sp)
1412    l.d     $f19, 56($sp)
1413    jalr    $t9                    # native call
1414    daddiu  $sp, $sp, 64
1415
1416    # result sign extension is handled in C code
1417    # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f)
1418    move    $a0, rSELF             # pass Thread::Current
1419    move    $a1, $v0
1420    jal     artQuickGenericJniEndTrampoline
1421    dmfc1   $a2, $f0
1422
1423    ld      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
1424    bne     $t0, $zero, 1f         # check for pending exceptions
1425    move    $sp, $s8               # tear down the alloca
1426
1427    # tear dpown the callee-save frame
1428    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1429
1430    jalr    $zero, $ra
1431    dmtc1   $v0, $f0               # place return value to FP return value
1432
14331:
1434    ld      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
1435    # This will create a new save-all frame, required by the runtime.
1436    DELIVER_PENDING_EXCEPTION
1437END art_quick_generic_jni_trampoline
1438
1439    .extern artQuickToInterpreterBridge
1440ENTRY art_quick_to_interpreter_bridge
1441    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1442    move    $a1, rSELF             # pass Thread::Current
1443    jal     artQuickToInterpreterBridge    # (Method* method, Thread*, SP)
1444    move    $a2, $sp               # pass $sp
1445    ld      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
1446    daddiu  $sp, $sp, REFS_AND_ARGS_MINUS_REFS_SIZE  # skip a0-a7 and f12-f19
1447    RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
1448    bne     $t0, $zero, 1f
1449    dmtc1   $v0, $f0               # place return value to FP return value
1450    jalr    $zero, $ra
1451    dmtc1   $v1, $f1               # place return value to FP return value
14521:
1453    DELIVER_PENDING_EXCEPTION
1454END art_quick_to_interpreter_bridge
1455
1456    /*
1457     * Routine that intercepts method calls and returns.
1458     */
1459    .extern artInstrumentationMethodEntryFromCode
1460    .extern artInstrumentationMethodExitFromCode
1461ENTRY art_quick_instrumentation_entry
1462    SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1463    daddiu   $sp, $sp, -16     # space for saving arg0
1464    .cfi_adjust_cfa_offset 16
1465    sd       $a0, 0($sp)       # save arg0
1466    move     $a3, $ra          # pass $ra
1467    jal      artInstrumentationMethodEntryFromCode  # (Method*, Object*, Thread*, RA)
1468    move     $a2, rSELF        # pass Thread::Current
1469    move     $t9, $v0          # $t9 holds reference to code
1470    ld       $a0, 0($sp)       # restore arg0
1471    daddiu   $sp, $sp, 16      # remove args
1472    .cfi_adjust_cfa_offset -16
1473    RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
1474    jalr     $t9               # call method
1475    nop
1476END art_quick_instrumentation_entry
1477    /* intentional fallthrough */
1478    .global art_quick_instrumentation_exit
1479art_quick_instrumentation_exit:
1480    .cfi_startproc
1481    daddiu   $t9, $ra, 4       # put current address into $t9 to rebuild $gp
1482    .cpload  $t9
1483    move     $ra, $zero        # link register is to here, so clobber with 0 for later checks
1484    SETUP_REFS_ONLY_CALLEE_SAVE_FRAME
1485    move     $t0, $sp          # remember bottom of caller's frame
1486    daddiu   $sp, $sp, -16     # save return values and set up args
1487    .cfi_adjust_cfa_offset 16
1488    sd       $v0, 0($sp)
1489    .cfi_rel_offset 2, 0
1490    s.d      $f0, 8($sp)
1491    mov.d    $f15, $f0         # pass fpr result
1492    move     $a2, $v0          # pass gpr result
1493    move     $a1, $t0          # pass $sp
1494    jal      artInstrumentationMethodExitFromCode  # (Thread*, SP, gpr_res, fpr_res)
1495    move     $a0, rSELF        # pass Thread::Current
1496    move     $t9, $v0          # set aside returned link register
1497    move     $ra, $v1          # set link register for deoptimization
1498    ld       $v0, 0($sp)       # restore return values
1499    l.d      $f0, 8($sp)
1500    jalr     $zero, $t9        # return
1501    daddiu   $sp, $sp, 16+FRAME_SIZE_REFS_ONLY_CALLEE_SAVE  # 16 bytes of saved values + ref_only callee save frame
1502    .cfi_adjust_cfa_offset -(16+FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
1503END art_quick_instrumentation_exit
1504
1505    /*
1506     * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
1507     * will long jump to the upcall with a special exception of -1.
1508     */
1509    .extern artDeoptimize
1510    .extern artEnterInterpreterFromDeoptimize
1511ENTRY art_quick_deoptimize
1512    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
1513    jal      artDeoptimize     # artDeoptimize(Thread*, SP)
1514                               # Returns caller method's frame size.
1515    move     $a0, rSELF        # pass Thread::current
1516END art_quick_deoptimize
1517
1518UNIMPLEMENTED art_quick_indexof
1519UNIMPLEMENTED art_quick_string_compareto
1520