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