quick_entrypoints_mips.S revision 4147fcc43c2ee019a06e55384985e3eaf82dcb8c
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(kSaveAllCalleeSaves)
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_SAVES + ARG_SLOT_SIZE bytes on the stack
38     */
39.macro SETUP_SAVE_ALL_CALLEE_SAVES_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_SAVES != 96)
45#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(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_SAVES_METHOD_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(kSaveRefsOnly). 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_SAVE_REFS_ONLY + ARG_SLOT_SIZE bytes on the stack
97     */
98.macro SETUP_SAVE_REFS_ONLY_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_SAVE_REFS_ONLY != 48)
104#error "FRAME_SIZE_SAVE_REFS_ONLY(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_SAVE_REFS_ONLY_METHOD_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_SAVE_REFS_ONLY_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_SAVE_REFS_ONLY_FRAME_AND_RETURN
162    RESTORE_SAVE_REFS_ONLY_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(kSaveRefsAndArgs).
170     * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
171     *              (26 total + 1 word padding + method*)
172     */
173.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
174    addiu  $sp, $sp, -112
175    .cfi_adjust_cfa_offset 112
176
177    // Ugly compile-time check, but we only have the preprocessor.
178#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 112)
179#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(MIPS) size not as expected."
180#endif
181
182    sw     $ra, 108($sp)
183    .cfi_rel_offset 31, 108
184    sw     $s8, 104($sp)
185    .cfi_rel_offset 30, 104
186    sw     $gp, 100($sp)
187    .cfi_rel_offset 28, 100
188    sw     $s7, 96($sp)
189    .cfi_rel_offset 23, 96
190    sw     $s6, 92($sp)
191    .cfi_rel_offset 22, 92
192    sw     $s5, 88($sp)
193    .cfi_rel_offset 21, 88
194    sw     $s4, 84($sp)
195    .cfi_rel_offset 20, 84
196    sw     $s3, 80($sp)
197    .cfi_rel_offset 19, 80
198    sw     $s2, 76($sp)
199    .cfi_rel_offset 18, 76
200    sw     $t1, 72($sp)
201    .cfi_rel_offset 9, 72
202    sw     $t0, 68($sp)
203    .cfi_rel_offset 8, 68
204    sw     $a3, 64($sp)
205    .cfi_rel_offset 7, 64
206    sw     $a2, 60($sp)
207    .cfi_rel_offset 6, 60
208    sw     $a1, 56($sp)
209    .cfi_rel_offset 5, 56
210    SDu $f18, $f19, 48, $sp, $t8
211    SDu $f16, $f17, 40, $sp, $t8
212    SDu $f14, $f15, 32, $sp, $t8
213    SDu $f12, $f13, 24, $sp, $t8
214    SDu $f10, $f11, 16, $sp, $t8
215    SDu $f8, $f9, 8, $sp, $t8
216    # bottom will hold Method*
217.endm
218
219    /*
220     * Macro that sets up the callee save frame to conform with
221     * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
222     * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
223     *              (26 total + 1 word padding + method*)
224     * Clobbers $t0 and $sp
225     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
226     * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
227     */
228.macro SETUP_SAVE_REFS_AND_ARGS_FRAME
229    SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
230    lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
231    lw $t0, 0($t0)
232    lw $t0, RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET($t0)
233    sw $t0, 0($sp)                                # Place Method* at bottom of stack.
234    sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
235    addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
236    .cfi_adjust_cfa_offset ARG_SLOT_SIZE
237.endm
238
239    /*
240     * Macro that sets up the callee save frame to conform with
241     * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
242     * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
243     *              (26 total + 1 word padding + method*)
244     * Clobbers $sp
245     * Use $a0 as the Method* and loads it into bottom of stack.
246     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
247     * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
248     */
249.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
250    SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
251    sw $a0, 0($sp)                                # Place Method* at bottom of stack.
252    sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
253    addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
254    .cfi_adjust_cfa_offset ARG_SLOT_SIZE
255.endm
256
257.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME
258    addiu  $sp, $sp, ARG_SLOT_SIZE                # remove argument slots on the stack
259    .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
260    lw     $ra, 108($sp)
261    .cfi_restore 31
262    lw     $s8, 104($sp)
263    .cfi_restore 30
264    lw     $gp, 100($sp)
265    .cfi_restore 28
266    lw     $s7, 96($sp)
267    .cfi_restore 23
268    lw     $s6, 92($sp)
269    .cfi_restore 22
270    lw     $s5, 88($sp)
271    .cfi_restore 21
272    lw     $s4, 84($sp)
273    .cfi_restore 20
274    lw     $s3, 80($sp)
275    .cfi_restore 19
276    lw     $s2, 76($sp)
277    .cfi_restore 18
278    lw     $t1, 72($sp)
279    .cfi_restore 9
280    lw     $t0, 68($sp)
281    .cfi_restore 8
282    lw     $a3, 64($sp)
283    .cfi_restore 7
284    lw     $a2, 60($sp)
285    .cfi_restore 6
286    lw     $a1, 56($sp)
287    .cfi_restore 5
288    LDu $f18, $f19, 48, $sp, $t8
289    LDu $f16, $f17, 40, $sp, $t8
290    LDu $f14, $f15, 32, $sp, $t8
291    LDu $f12, $f13, 24, $sp, $t8
292    LDu $f10, $f11, 16, $sp, $t8
293    LDu $f8, $f9, 8, $sp, $t8
294    addiu  $sp, $sp, 112          # pop frame
295    .cfi_adjust_cfa_offset -112
296.endm
297
298    /*
299     * Macro that sets up the callee save frame to conform with
300     * Runtime::CreateCalleeSaveMethod(kSaveEverything).
301     * when the $sp has already been decremented by FRAME_SIZE_SAVE_EVERYTHING.
302     * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
303     *              28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
304     * Clobbers $t0 and $t1.
305     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
306     * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
307     * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
308     */
309.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
310     // Ugly compile-time check, but we only have the preprocessor.
311#if (FRAME_SIZE_SAVE_EVERYTHING != 256)
312#error "FRAME_SIZE_SAVE_EVERYTHING(MIPS) size not as expected."
313#endif
314
315    sw     $ra, 252($sp)
316    .cfi_rel_offset 31, 252
317    sw     $fp, 248($sp)
318    .cfi_rel_offset 30, 248
319    sw     $gp, 244($sp)
320    .cfi_rel_offset 28, 244
321    sw     $t9, 240($sp)
322    .cfi_rel_offset 25, 240
323    sw     $t8, 236($sp)
324    .cfi_rel_offset 24, 236
325    sw     $s7, 232($sp)
326    .cfi_rel_offset 23, 232
327    sw     $s6, 228($sp)
328    .cfi_rel_offset 22, 228
329    sw     $s5, 224($sp)
330    .cfi_rel_offset 21, 224
331    sw     $s4, 220($sp)
332    .cfi_rel_offset 20, 220
333    sw     $s3, 216($sp)
334    .cfi_rel_offset 19, 216
335    sw     $s2, 212($sp)
336    .cfi_rel_offset 18, 212
337    sw     $s1, 208($sp)
338    .cfi_rel_offset 17, 208
339    sw     $s0, 204($sp)
340    .cfi_rel_offset 16, 204
341    sw     $t7, 200($sp)
342    .cfi_rel_offset 15, 200
343    sw     $t6, 196($sp)
344    .cfi_rel_offset 14, 196
345    sw     $t5, 192($sp)
346    .cfi_rel_offset 13, 192
347    sw     $t4, 188($sp)
348    .cfi_rel_offset 12, 188
349    sw     $t3, 184($sp)
350    .cfi_rel_offset 11, 184
351    sw     $t2, 180($sp)
352    .cfi_rel_offset 10, 180
353    sw     $t1, 176($sp)
354    .cfi_rel_offset 9, 176
355    sw     $t0, 172($sp)
356    .cfi_rel_offset 8, 172
357    sw     $a3, 168($sp)
358    .cfi_rel_offset 7, 168
359    sw     $a2, 164($sp)
360    .cfi_rel_offset 6, 164
361    sw     $a1, 160($sp)
362    .cfi_rel_offset 5, 160
363    sw     $a0, 156($sp)
364    .cfi_rel_offset 4, 156
365    sw     $v1, 152($sp)
366    .cfi_rel_offset 3, 152
367    sw     $v0, 148($sp)
368    .cfi_rel_offset 2, 148
369
370    // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
371    bal 1f
372    .set push
373    .set noat
374    sw     $at, 144($sp)
375    .cfi_rel_offset 1, 144
376    .set pop
3771:
378    .cpload $ra
379
380    SDu $f30, $f31, 136, $sp, $t1
381    SDu $f28, $f29, 128, $sp, $t1
382    SDu $f26, $f27, 120, $sp, $t1
383    SDu $f24, $f25, 112, $sp, $t1
384    SDu $f22, $f23, 104, $sp, $t1
385    SDu $f20, $f21, 96,  $sp, $t1
386    SDu $f18, $f19, 88,  $sp, $t1
387    SDu $f16, $f17, 80,  $sp, $t1
388    SDu $f14, $f15, 72,  $sp, $t1
389    SDu $f12, $f13, 64,  $sp, $t1
390    SDu $f10, $f11, 56,  $sp, $t1
391    SDu $f8, $f9, 48,  $sp, $t1
392    SDu $f6, $f7, 40,  $sp, $t1
393    SDu $f4, $f5, 32,  $sp, $t1
394    SDu $f2, $f3, 24,  $sp, $t1
395    SDu $f0, $f1, 16,  $sp, $t1
396
397    # 3 words padding and 1 word for holding Method*
398
399    lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
400    lw $t0, 0($t0)
401    lw $t0, RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET($t0)
402    sw $t0, 0($sp)                                # Place Method* at bottom of stack.
403    sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
404    addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
405    .cfi_adjust_cfa_offset ARG_SLOT_SIZE
406.endm
407
408    /*
409     * Macro that sets up the callee save frame to conform with
410     * Runtime::CreateCalleeSaveMethod(kSaveEverything).
411     * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
412     *              28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
413     * Clobbers $t0 and $t1.
414     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
415     * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
416     * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
417     */
418.macro SETUP_SAVE_EVERYTHING_FRAME
419    addiu  $sp, $sp, -(FRAME_SIZE_SAVE_EVERYTHING)
420    .cfi_adjust_cfa_offset (FRAME_SIZE_SAVE_EVERYTHING)
421    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
422.endm
423
424.macro RESTORE_SAVE_EVERYTHING_FRAME restore_a0=1
425    addiu  $sp, $sp, ARG_SLOT_SIZE                # remove argument slots on the stack
426    .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
427
428    LDu $f30, $f31, 136, $sp, $t1
429    LDu $f28, $f29, 128, $sp, $t1
430    LDu $f26, $f27, 120, $sp, $t1
431    LDu $f24, $f25, 112, $sp, $t1
432    LDu $f22, $f23, 104, $sp, $t1
433    LDu $f20, $f21, 96,  $sp, $t1
434    LDu $f18, $f19, 88,  $sp, $t1
435    LDu $f16, $f17, 80,  $sp, $t1
436    LDu $f14, $f15, 72,  $sp, $t1
437    LDu $f12, $f13, 64,  $sp, $t1
438    LDu $f10, $f11, 56,  $sp, $t1
439    LDu $f8, $f9, 48,  $sp, $t1
440    LDu $f6, $f7, 40,  $sp, $t1
441    LDu $f4, $f5, 32,  $sp, $t1
442    LDu $f2, $f3, 24,  $sp, $t1
443    LDu $f0, $f1, 16,  $sp, $t1
444
445    lw     $ra, 252($sp)
446    .cfi_restore 31
447    lw     $fp, 248($sp)
448    .cfi_restore 30
449    lw     $gp, 244($sp)
450    .cfi_restore 28
451    lw     $t9, 240($sp)
452    .cfi_restore 25
453    lw     $t8, 236($sp)
454    .cfi_restore 24
455    lw     $s7, 232($sp)
456    .cfi_restore 23
457    lw     $s6, 228($sp)
458    .cfi_restore 22
459    lw     $s5, 224($sp)
460    .cfi_restore 21
461    lw     $s4, 220($sp)
462    .cfi_restore 20
463    lw     $s3, 216($sp)
464    .cfi_restore 19
465    lw     $s2, 212($sp)
466    .cfi_restore 18
467    lw     $s1, 208($sp)
468    .cfi_restore 17
469    lw     $s0, 204($sp)
470    .cfi_restore 16
471    lw     $t7, 200($sp)
472    .cfi_restore 15
473    lw     $t6, 196($sp)
474    .cfi_restore 14
475    lw     $t5, 192($sp)
476    .cfi_restore 13
477    lw     $t4, 188($sp)
478    .cfi_restore 12
479    lw     $t3, 184($sp)
480    .cfi_restore 11
481    lw     $t2, 180($sp)
482    .cfi_restore 10
483    lw     $t1, 176($sp)
484    .cfi_restore 9
485    lw     $t0, 172($sp)
486    .cfi_restore 8
487    lw     $a3, 168($sp)
488    .cfi_restore 7
489    lw     $a2, 164($sp)
490    .cfi_restore 6
491    lw     $a1, 160($sp)
492    .cfi_restore 5
493    .if \restore_a0
494    lw     $a0, 156($sp)
495    .cfi_restore 4
496    .endif
497    lw     $v1, 152($sp)
498    .cfi_restore 3
499    lw     $v0, 148($sp)
500    .cfi_restore 2
501    .set push
502    .set noat
503    lw     $at, 144($sp)
504    .cfi_restore 1
505    .set pop
506
507    addiu  $sp, $sp, 256            # pop frame
508    .cfi_adjust_cfa_offset -256
509.endm
510
511    /*
512     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
513     * exception is Thread::Current()->exception_ when the runtime method frame is ready.
514     * Requires $gp properly set up.
515     */
516.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
517    la      $t9, artDeliverPendingExceptionFromCode
518    jalr    $zero, $t9                   # artDeliverPendingExceptionFromCode(Thread*)
519    move    $a0, rSELF                   # pass Thread::Current
520.endm
521
522    /*
523     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
524     * exception is Thread::Current()->exception_.
525     * Requires $gp properly set up.
526     */
527.macro DELIVER_PENDING_EXCEPTION
528    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME    # save callee saves for throw
529    DELIVER_PENDING_EXCEPTION_FRAME_READY
530.endm
531
532.macro RETURN_IF_NO_EXCEPTION
533    lw     $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
534    RESTORE_SAVE_REFS_ONLY_FRAME
535    bnez   $t0, 1f                       # success if no exception is pending
536    nop
537    jalr   $zero, $ra
538    nop
5391:
540    DELIVER_PENDING_EXCEPTION
541.endm
542
543.macro RETURN_IF_ZERO
544    RESTORE_SAVE_REFS_ONLY_FRAME
545    bnez   $v0, 1f                       # success?
546    nop
547    jalr   $zero, $ra                    # return on success
548    nop
5491:
550    DELIVER_PENDING_EXCEPTION
551.endm
552
553.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
554    RESTORE_SAVE_REFS_ONLY_FRAME
555    beqz   $v0, 1f                       # success?
556    nop
557    jalr   $zero, $ra                    # return on success
558    nop
5591:
560    DELIVER_PENDING_EXCEPTION
561.endm
562
563    /*
564     * On stack replacement stub.
565     * On entry:
566     *   a0 = stack to copy
567     *   a1 = size of stack
568     *   a2 = pc to call
569     *   a3 = JValue* result
570     *   [sp + 16] = shorty
571     *   [sp + 20] = thread
572     */
573ENTRY art_quick_osr_stub
574    // Save callee general purpose registers, RA and GP.
575    addiu  $sp, $sp, -48
576    .cfi_adjust_cfa_offset 48
577    sw     $ra, 44($sp)
578    .cfi_rel_offset 31, 44
579    sw     $s8, 40($sp)
580    .cfi_rel_offset 30, 40
581    sw     $gp, 36($sp)
582    .cfi_rel_offset 28, 36
583    sw     $s7, 32($sp)
584    .cfi_rel_offset 23, 32
585    sw     $s6, 28($sp)
586    .cfi_rel_offset 22, 28
587    sw     $s5, 24($sp)
588    .cfi_rel_offset 21, 24
589    sw     $s4, 20($sp)
590    .cfi_rel_offset 20, 20
591    sw     $s3, 16($sp)
592    .cfi_rel_offset 19, 16
593    sw     $s2, 12($sp)
594    .cfi_rel_offset 18, 12
595    sw     $s1, 8($sp)
596    .cfi_rel_offset 17, 8
597    sw     $s0, 4($sp)
598    .cfi_rel_offset 16, 4
599
600    move   $s8, $sp                        # Save the stack pointer
601    move   $s7, $a1                        # Save size of stack
602    move   $s6, $a2                        # Save the pc to call
603    lw     rSELF, 48+20($sp)               # Save managed thread pointer into rSELF
604    addiu  $t0, $sp, -12                   # Reserve space for stack pointer,
605                                           #    JValue* result, and ArtMethod* slot.
606    srl    $t0, $t0, 4                     # Align stack pointer to 16 bytes
607    sll    $sp, $t0, 4                     # Update stack pointer
608    sw     $s8, 4($sp)                     # Save old stack pointer
609    sw     $a3, 8($sp)                     # Save JValue* result
610    sw     $zero, 0($sp)                   # Store null for ArtMethod* at bottom of frame
611    subu   $sp, $a1                        # Reserve space for callee stack
612    move   $a2, $a1
613    move   $a1, $a0
614    move   $a0, $sp
615    la     $t9, memcpy
616    jalr   $t9                             # memcpy (dest a0, src a1, bytes a2)
617    addiu  $sp, $sp, -16                   # make space for argument slots for memcpy
618    bal    .Losr_entry                     # Call the method
619    addiu  $sp, $sp, 16                    # restore stack after memcpy
620    lw     $a2, 8($sp)                     # Restore JValue* result
621    lw     $sp, 4($sp)                     # Restore saved stack pointer
622    lw     $a0, 48+16($sp)                 # load shorty
623    lbu    $a0, 0($a0)                     # load return type
624    li     $a1, 'D'                        # put char 'D' into a1
625    beq    $a0, $a1, .Losr_fp_result       # Test if result type char == 'D'
626    li     $a1, 'F'                        # put char 'F' into a1
627    beq    $a0, $a1, .Losr_fp_result       # Test if result type char == 'F'
628    nop
629    sw     $v0, 0($a2)
630    b      .Losr_exit
631    sw     $v1, 4($a2)                     # store v0/v1 into result
632.Losr_fp_result:
633    SDu    $f0, $f1, 0, $a2, $t0           # store f0/f1 into result
634.Losr_exit:
635    lw     $ra, 44($sp)
636    .cfi_restore 31
637    lw     $s8, 40($sp)
638    .cfi_restore 30
639    lw     $gp, 36($sp)
640    .cfi_restore 28
641    lw     $s7, 32($sp)
642    .cfi_restore 23
643    lw     $s6, 28($sp)
644    .cfi_restore 22
645    lw     $s5, 24($sp)
646    .cfi_restore 21
647    lw     $s4, 20($sp)
648    .cfi_restore 20
649    lw     $s3, 16($sp)
650    .cfi_restore 19
651    lw     $s2, 12($sp)
652    .cfi_restore 18
653    lw     $s1, 8($sp)
654    .cfi_restore 17
655    lw     $s0, 4($sp)
656    .cfi_restore 16
657    jalr   $zero, $ra
658    addiu  $sp, $sp, 48
659    .cfi_adjust_cfa_offset -48
660.Losr_entry:
661    addiu  $s7, $s7, -4
662    addu   $t0, $s7, $sp
663    move   $t9, $s6
664    jalr   $zero, $t9
665    sw     $ra, 0($t0)                     # Store RA per the compiler ABI
666END art_quick_osr_stub
667
668    /*
669     * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_
670     * FIXME: just guessing about the shape of the jmpbuf.  Where will pc be?
671     */
672ENTRY art_quick_do_long_jump
673    LDu  $f0,  $f1,   0*8, $a1, $t1
674    LDu  $f2,  $f3,   1*8, $a1, $t1
675    LDu  $f4,  $f5,   2*8, $a1, $t1
676    LDu  $f6,  $f7,   3*8, $a1, $t1
677    LDu  $f8,  $f9,   4*8, $a1, $t1
678    LDu  $f10, $f11,  5*8, $a1, $t1
679    LDu  $f12, $f13,  6*8, $a1, $t1
680    LDu  $f14, $f15,  7*8, $a1, $t1
681    LDu  $f16, $f17,  8*8, $a1, $t1
682    LDu  $f18, $f19,  9*8, $a1, $t1
683    LDu  $f20, $f21, 10*8, $a1, $t1
684    LDu  $f22, $f23, 11*8, $a1, $t1
685    LDu  $f24, $f25, 12*8, $a1, $t1
686    LDu  $f26, $f27, 13*8, $a1, $t1
687    LDu  $f28, $f29, 14*8, $a1, $t1
688    LDu  $f30, $f31, 15*8, $a1, $t1
689
690    .set push
691    .set nomacro
692    .set noat
693    lw      $at, 4($a0)
694    .set pop
695    lw      $v0, 8($a0)
696    lw      $v1, 12($a0)
697    lw      $a1, 20($a0)
698    lw      $a2, 24($a0)
699    lw      $a3, 28($a0)
700    lw      $t0, 32($a0)
701    lw      $t1, 36($a0)
702    lw      $t2, 40($a0)
703    lw      $t3, 44($a0)
704    lw      $t4, 48($a0)
705    lw      $t5, 52($a0)
706    lw      $t6, 56($a0)
707    lw      $t7, 60($a0)
708    lw      $s0, 64($a0)
709    lw      $s1, 68($a0)
710    lw      $s2, 72($a0)
711    lw      $s3, 76($a0)
712    lw      $s4, 80($a0)
713    lw      $s5, 84($a0)
714    lw      $s6, 88($a0)
715    lw      $s7, 92($a0)
716    lw      $t8, 96($a0)
717    lw      $t9, 100($a0)
718    lw      $gp, 112($a0)
719    lw      $sp, 116($a0)
720    lw      $fp, 120($a0)
721    lw      $ra, 124($a0)
722    lw      $a0, 16($a0)
723    move    $v0, $zero          # clear result registers v0 and v1 (in branch delay slot)
724    jalr    $zero, $t9          # do long jump
725    move    $v1, $zero
726END art_quick_do_long_jump
727
728    /*
729     * Called by managed code, saves most registers (forms basis of long jump context) and passes
730     * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
731     * the bottom of the thread. On entry a0 holds Throwable*
732     */
733ENTRY art_quick_deliver_exception
734    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
735    la   $t9, artDeliverExceptionFromCode
736    jalr $zero, $t9                 # artDeliverExceptionFromCode(Throwable*, Thread*)
737    move $a1, rSELF                 # pass Thread::Current
738END art_quick_deliver_exception
739
740    /*
741     * Called by managed code to create and deliver a NullPointerException
742     */
743    .extern artThrowNullPointerExceptionFromCode
744ENTRY_NO_GP art_quick_throw_null_pointer_exception
745    // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
746    // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
747    SETUP_SAVE_EVERYTHING_FRAME
748    la   $t9, artThrowNullPointerExceptionFromCode
749    jalr $zero, $t9                 # artThrowNullPointerExceptionFromCode(Thread*)
750    move $a0, rSELF                 # pass Thread::Current
751END art_quick_throw_null_pointer_exception
752
753
754    /*
755     * Call installed by a signal handler to create and deliver a NullPointerException.
756     */
757    .extern artThrowNullPointerExceptionFromSignal
758ENTRY_NO_GP_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, FRAME_SIZE_SAVE_EVERYTHING
759    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
760    # Retrieve the fault address from the padding where the signal handler stores it.
761    lw   $a0, (ARG_SLOT_SIZE + __SIZEOF_POINTER__)($sp)
762    la   $t9, artThrowNullPointerExceptionFromSignal
763    jalr $zero, $t9                 # artThrowNullPointerExceptionFromSignal(uintptr_t, Thread*)
764    move $a1, rSELF                 # pass Thread::Current
765END art_quick_throw_null_pointer_exception_from_signal
766
767    /*
768     * Called by managed code to create and deliver an ArithmeticException
769     */
770    .extern artThrowDivZeroFromCode
771ENTRY_NO_GP art_quick_throw_div_zero
772    SETUP_SAVE_EVERYTHING_FRAME
773    la   $t9, artThrowDivZeroFromCode
774    jalr $zero, $t9                 # artThrowDivZeroFromCode(Thread*)
775    move $a0, rSELF                 # pass Thread::Current
776END art_quick_throw_div_zero
777
778    /*
779     * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
780     */
781    .extern artThrowArrayBoundsFromCode
782ENTRY_NO_GP art_quick_throw_array_bounds
783    // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
784    // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
785    SETUP_SAVE_EVERYTHING_FRAME
786    la   $t9, artThrowArrayBoundsFromCode
787    jalr $zero, $t9                 # artThrowArrayBoundsFromCode(index, limit, Thread*)
788    move $a2, rSELF                 # pass Thread::Current
789END art_quick_throw_array_bounds
790
791    /*
792     * Called by managed code to create and deliver a StringIndexOutOfBoundsException
793     * as if thrown from a call to String.charAt().
794     */
795    .extern artThrowStringBoundsFromCode
796ENTRY_NO_GP art_quick_throw_string_bounds
797    SETUP_SAVE_EVERYTHING_FRAME
798    la   $t9, artThrowStringBoundsFromCode
799    jalr $zero, $t9                 # artThrowStringBoundsFromCode(index, limit, Thread*)
800    move $a2, rSELF                 # pass Thread::Current
801END art_quick_throw_string_bounds
802
803    /*
804     * Called by managed code to create and deliver a StackOverflowError.
805     */
806    .extern artThrowStackOverflowFromCode
807ENTRY art_quick_throw_stack_overflow
808    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
809    la   $t9, artThrowStackOverflowFromCode
810    jalr $zero, $t9                 # artThrowStackOverflowFromCode(Thread*)
811    move $a0, rSELF                 # pass Thread::Current
812END art_quick_throw_stack_overflow
813
814    /*
815     * All generated callsites for interface invokes and invocation slow paths will load arguments
816     * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
817     * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
818     * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
819     *
820     * The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting
821     * of the target Method* in $v0 and method->code_ in $v1.
822     *
823     * If unsuccessful, the helper will return null/null. There will be a pending exception in the
824     * thread and we branch to another stub to deliver it.
825     *
826     * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
827     * pointing back to the original caller.
828     */
829.macro INVOKE_TRAMPOLINE_BODY cxx_name
830    .extern \cxx_name
831    SETUP_SAVE_REFS_AND_ARGS_FRAME         # save callee saves in case allocation triggers GC
832    move  $a2, rSELF                       # pass Thread::Current
833    la    $t9, \cxx_name
834    jalr  $t9                              # (method_idx, this, Thread*, $sp)
835    addiu $a3, $sp, ARG_SLOT_SIZE          # pass $sp (remove arg slots)
836    move  $a0, $v0                         # save target Method*
837    RESTORE_SAVE_REFS_AND_ARGS_FRAME
838    beqz  $v0, 1f
839    move  $t9, $v1                         # save $v0->code_
840    jalr  $zero, $t9
841    nop
8421:
843    DELIVER_PENDING_EXCEPTION
844.endm
845.macro INVOKE_TRAMPOLINE c_name, cxx_name
846ENTRY \c_name
847    INVOKE_TRAMPOLINE_BODY \cxx_name
848END \c_name
849.endm
850
851INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
852
853INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
854INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
855INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
856INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
857
858// Each of the following macros expands into four instructions or 16 bytes.
859// They are used to build indexable "tables" of code.
860
861.macro LOAD_WORD_TO_REG reg, next_arg, index_reg, label
862    lw    $\reg, -4($\next_arg)   # next_arg points to argument after the current one (offset is 4)
863    b     \label
864    addiu $\index_reg, 16
865    .balign 16
866.endm
867
868.macro LOAD_LONG_TO_REG reg1, reg2, next_arg, index_reg, next_index, label
869    lw    $\reg1, -8($\next_arg)  # next_arg points to argument after the current one (offset is 8)
870    lw    $\reg2, -4($\next_arg)
871    b     \label
872    li    $\index_reg, \next_index
873    .balign 16
874.endm
875
876.macro LOAD_FLOAT_TO_REG reg, next_arg, index_reg, label
877    lwc1  $\reg, -4($\next_arg)   # next_arg points to argument after the current one (offset is 4)
878    b     \label
879    addiu $\index_reg, 16
880    .balign 16
881.endm
882
883#if defined(__mips_isa_rev) && __mips_isa_rev > 2
884// LDu expands into 3 instructions for 64-bit FPU, so index_reg cannot be updated here.
885.macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
886    .set reorder                                # force use of the branch delay slot
887    LDu  $\reg1, $\reg2, -8, $\next_arg, $\tmp  # next_arg points to argument after the current one
888                                                # (offset is 8)
889    b     \label
890    .set noreorder
891    .balign 16
892.endm
893#else
894// LDu expands into 2 instructions for 32-bit FPU, so index_reg is updated here.
895.macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
896    LDu  $\reg1, $\reg2, -8, $\next_arg, $\tmp  # next_arg points to argument after the current one
897                                                # (offset is 8)
898    b     \label
899    addiu $\index_reg, 16
900    .balign 16
901.endm
902#endif
903
904.macro LOAD_END index_reg, next_index, label
905    b     \label
906    li    $\index_reg, \next_index
907    .balign 16
908.endm
909
910#define SPILL_SIZE    32
911
912    /*
913     * Invocation stub for quick code.
914     * On entry:
915     *   a0 = method pointer
916     *   a1 = argument array or null for no argument methods
917     *   a2 = size of argument array in bytes
918     *   a3 = (managed) thread pointer
919     *   [sp + 16] = JValue* result
920     *   [sp + 20] = shorty
921     */
922ENTRY art_quick_invoke_stub
923    sw    $a0, 0($sp)           # save out a0
924    addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
925    .cfi_adjust_cfa_offset SPILL_SIZE
926    sw    $gp, 16($sp)
927    sw    $ra, 12($sp)
928    .cfi_rel_offset 31, 12
929    sw    $fp, 8($sp)
930    .cfi_rel_offset 30, 8
931    sw    $s1, 4($sp)
932    .cfi_rel_offset 17, 4
933    sw    $s0, 0($sp)
934    .cfi_rel_offset 16, 0
935    move  $fp, $sp              # save sp in fp
936    .cfi_def_cfa_register 30
937    move  $s1, $a3              # move managed thread pointer into s1
938    addiu $s0, $zero, SUSPEND_CHECK_INTERVAL  # reset s0 to suspend check interval
939    addiu $t0, $a2, 4           # create space for ArtMethod* in frame.
940    subu  $t0, $sp, $t0         # reserve & align *stack* to 16 bytes:
941    srl   $t0, $t0, 4           #   native calling convention only aligns to 8B,
942    sll   $sp, $t0, 4           #   so we have to ensure ART 16B alignment ourselves.
943    addiu $a0, $sp, 4           # pass stack pointer + ArtMethod* as dest for memcpy
944    la    $t9, memcpy
945    jalr  $t9                   # (dest, src, bytes)
946    addiu $sp, $sp, -16         # make space for argument slots for memcpy
947    addiu $sp, $sp, 16          # restore stack after memcpy
948    lw    $gp, 16($fp)          # restore $gp
949    lw    $a0, SPILL_SIZE($fp)  # restore ArtMethod*
950    lw    $a1, 4($sp)           # a1 = this*
951    addiu $t8, $sp, 8           # t8 = pointer to the current argument (skip ArtMethod* and this*)
952    li    $t6, 0                # t6 = gpr_index = 0 (corresponds to A2; A0 and A1 are skipped)
953    li    $t7, 0                # t7 = fp_index = 0
954    lw    $t9, 20 + SPILL_SIZE($fp)  # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
955                                # as the $fp is SPILL_SIZE bytes below the $sp on entry)
956    addiu $t9, 1                # t9 = shorty + 1 (skip 1 for return type)
957
958    // Load the base addresses of tabInt ... tabDouble.
959    // We will use the register indices (gpr_index, fp_index) to branch.
960    // Note that the indices are scaled by 16, so they can be added to the bases directly.
961#if defined(__mips_isa_rev) && __mips_isa_rev >= 6
962    lapc  $t2, tabInt
963    lapc  $t3, tabLong
964    lapc  $t4, tabSingle
965    lapc  $t5, tabDouble
966#else
967    bltzal $zero, tabBase       # nal
968    addiu $t2, $ra, %lo(tabInt - tabBase)
969tabBase:
970    addiu $t3, $ra, %lo(tabLong - tabBase)
971    addiu $t4, $ra, %lo(tabSingle - tabBase)
972    addiu $t5, $ra, %lo(tabDouble - tabBase)
973#endif
974
975loop:
976    lbu   $ra, 0($t9)           # ra = shorty[i]
977    beqz  $ra, loopEnd          # finish getting args when shorty[i] == '\0'
978    addiu $t9, 1
979
980    addiu $ra, -'J'
981    beqz  $ra, isLong           # branch if result type char == 'J'
982    addiu $ra, 'J' - 'D'
983    beqz  $ra, isDouble         # branch if result type char == 'D'
984    addiu $ra, 'D' - 'F'
985    beqz  $ra, isSingle         # branch if result type char == 'F'
986
987    addu  $ra, $t2, $t6
988    jalr  $zero, $ra
989    addiu $t8, 4                # next_arg = curr_arg + 4
990
991isLong:
992    addu  $ra, $t3, $t6
993    jalr  $zero, $ra
994    addiu $t8, 8                # next_arg = curr_arg + 8
995
996isSingle:
997    addu  $ra, $t4, $t7
998    jalr  $zero, $ra
999    addiu $t8, 4                # next_arg = curr_arg + 4
1000
1001isDouble:
1002    addu  $ra, $t5, $t7
1003#if defined(__mips_isa_rev) && __mips_isa_rev > 2
1004    addiu $t7, 16               # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
1005#endif
1006    jalr  $zero, $ra
1007    addiu $t8, 8                # next_arg = curr_arg + 8
1008
1009loopEnd:
1010    lw    $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)  # get pointer to the code
1011    jalr  $t9                   # call the method
1012    sw    $zero, 0($sp)         # store null for ArtMethod* at bottom of frame
1013    move  $sp, $fp              # restore the stack
1014    lw    $s0, 0($sp)
1015    .cfi_restore 16
1016    lw    $s1, 4($sp)
1017    .cfi_restore 17
1018    lw    $fp, 8($sp)
1019    .cfi_restore 30
1020    lw    $ra, 12($sp)
1021    .cfi_restore 31
1022    addiu $sp, $sp, SPILL_SIZE
1023    .cfi_adjust_cfa_offset -SPILL_SIZE
1024    lw    $t0, 16($sp)          # get result pointer
1025    lw    $t1, 20($sp)          # get shorty
1026    lb    $t1, 0($t1)           # get result type char
1027    li    $t2, 'D'              # put char 'D' into t2
1028    beq   $t1, $t2, 5f          # branch if result type char == 'D'
1029    li    $t3, 'F'              # put char 'F' into t3
1030    beq   $t1, $t3, 5f          # branch if result type char == 'F'
1031    sw    $v0, 0($t0)           # store the result
1032    jalr  $zero, $ra
1033    sw    $v1, 4($t0)           # store the other half of the result
10345:
1035    SDu   $f0, $f1, 0, $t0, $t1 # store floating point result
1036    jalr  $zero, $ra
1037    nop
1038
1039    // Note that gpr_index is kept within the range of tabInt and tabLong
1040    // and fp_index is kept within the range of tabSingle and tabDouble.
1041    .balign 16
1042tabInt:
1043    LOAD_WORD_TO_REG a2, t8, t6, loop             # a2 = current argument, gpr_index += 16
1044    LOAD_WORD_TO_REG a3, t8, t6, loop             # a3 = current argument, gpr_index += 16
1045    LOAD_WORD_TO_REG t0, t8, t6, loop             # t0 = current argument, gpr_index += 16
1046    LOAD_WORD_TO_REG t1, t8, t6, loop             # t1 = current argument, gpr_index += 16
1047    LOAD_END t6, 4*16, loop                       # no more GPR args, gpr_index = 4*16
1048tabLong:
1049    LOAD_LONG_TO_REG a2, a3, t8, t6, 2*16, loop   # a2_a3 = curr_arg, gpr_index = 2*16
1050    LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop   # t0_t1 = curr_arg, gpr_index = 4*16
1051    LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop   # t0_t1 = curr_arg, gpr_index = 4*16
1052    LOAD_END t6, 4*16, loop                       # no more GPR args, gpr_index = 4*16
1053    LOAD_END t6, 4*16, loop                       # no more GPR args, gpr_index = 4*16
1054tabSingle:
1055    LOAD_FLOAT_TO_REG f8, t8, t7, loop            # f8 = curr_arg, fp_index += 16
1056    LOAD_FLOAT_TO_REG f10, t8, t7, loop           # f10 = curr_arg, fp_index += 16
1057    LOAD_FLOAT_TO_REG f12, t8, t7, loop           # f12 = curr_arg, fp_index += 16
1058    LOAD_FLOAT_TO_REG f14, t8, t7, loop           # f14 = curr_arg, fp_index += 16
1059    LOAD_FLOAT_TO_REG f16, t8, t7, loop           # f16 = curr_arg, fp_index += 16
1060    LOAD_FLOAT_TO_REG f18, t8, t7, loop           # f18 = curr_arg, fp_index += 16
1061    LOAD_END t7, 6*16, loop                       # no more FPR args, fp_index = 6*16
1062tabDouble:
1063    LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loop   # f8_f9 = curr_arg; if FPU32, fp_index += 16
1064    LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loop # f10_f11 = curr_arg; if FPU32, fp_index += 16
1065    LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loop # f12_f13 = curr_arg; if FPU32, fp_index += 16
1066    LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loop # f14_f15 = curr_arg; if FPU32, fp_index += 16
1067    LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loop # f16_f17 = curr_arg; if FPU32, fp_index += 16
1068    LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loop # f18_f19 = curr_arg; if FPU32, fp_index += 16
1069    LOAD_END t7, 6*16, loop                       # no more FPR args, fp_index = 6*16
1070END art_quick_invoke_stub
1071
1072    /*
1073     * Invocation static stub for quick code.
1074     * On entry:
1075     *   a0 = method pointer
1076     *   a1 = argument array or null for no argument methods
1077     *   a2 = size of argument array in bytes
1078     *   a3 = (managed) thread pointer
1079     *   [sp + 16] = JValue* result
1080     *   [sp + 20] = shorty
1081     */
1082ENTRY art_quick_invoke_static_stub
1083    sw    $a0, 0($sp)           # save out a0
1084    addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
1085    .cfi_adjust_cfa_offset SPILL_SIZE
1086    sw    $gp, 16($sp)
1087    sw    $ra, 12($sp)
1088    .cfi_rel_offset 31, 12
1089    sw    $fp, 8($sp)
1090    .cfi_rel_offset 30, 8
1091    sw    $s1, 4($sp)
1092    .cfi_rel_offset 17, 4
1093    sw    $s0, 0($sp)
1094    .cfi_rel_offset 16, 0
1095    move  $fp, $sp              # save sp in fp
1096    .cfi_def_cfa_register 30
1097    move  $s1, $a3              # move managed thread pointer into s1
1098    addiu $s0, $zero, SUSPEND_CHECK_INTERVAL  # reset s0 to suspend check interval
1099    addiu $t0, $a2, 4           # create space for ArtMethod* in frame.
1100    subu  $t0, $sp, $t0         # reserve & align *stack* to 16 bytes:
1101    srl   $t0, $t0, 4           #   native calling convention only aligns to 8B,
1102    sll   $sp, $t0, 4           #   so we have to ensure ART 16B alignment ourselves.
1103    addiu $a0, $sp, 4           # pass stack pointer + ArtMethod* as dest for memcpy
1104    la    $t9, memcpy
1105    jalr  $t9                   # (dest, src, bytes)
1106    addiu $sp, $sp, -16         # make space for argument slots for memcpy
1107    addiu $sp, $sp, 16          # restore stack after memcpy
1108    lw    $gp, 16($fp)          # restore $gp
1109    lw    $a0, SPILL_SIZE($fp)  # restore ArtMethod*
1110    addiu $t8, $sp, 4           # t8 = pointer to the current argument (skip ArtMethod*)
1111    li    $t6, 0                # t6 = gpr_index = 0 (corresponds to A1; A0 is skipped)
1112    li    $t7, 0                # t7 = fp_index = 0
1113    lw    $t9, 20 + SPILL_SIZE($fp)  # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
1114                                # as the $fp is SPILL_SIZE bytes below the $sp on entry)
1115    addiu $t9, 1                # t9 = shorty + 1 (skip 1 for return type)
1116
1117    // Load the base addresses of tabIntS ... tabDoubleS.
1118    // We will use the register indices (gpr_index, fp_index) to branch.
1119    // Note that the indices are scaled by 16, so they can be added to the bases directly.
1120#if defined(__mips_isa_rev) && __mips_isa_rev >= 6
1121    lapc  $t2, tabIntS
1122    lapc  $t3, tabLongS
1123    lapc  $t4, tabSingleS
1124    lapc  $t5, tabDoubleS
1125#else
1126    bltzal $zero, tabBaseS      # nal
1127    addiu $t2, $ra, %lo(tabIntS - tabBaseS)
1128tabBaseS:
1129    addiu $t3, $ra, %lo(tabLongS - tabBaseS)
1130    addiu $t4, $ra, %lo(tabSingleS - tabBaseS)
1131    addiu $t5, $ra, %lo(tabDoubleS - tabBaseS)
1132#endif
1133
1134loopS:
1135    lbu   $ra, 0($t9)           # ra = shorty[i]
1136    beqz  $ra, loopEndS         # finish getting args when shorty[i] == '\0'
1137    addiu $t9, 1
1138
1139    addiu $ra, -'J'
1140    beqz  $ra, isLongS          # branch if result type char == 'J'
1141    addiu $ra, 'J' - 'D'
1142    beqz  $ra, isDoubleS        # branch if result type char == 'D'
1143    addiu $ra, 'D' - 'F'
1144    beqz  $ra, isSingleS        # branch if result type char == 'F'
1145
1146    addu  $ra, $t2, $t6
1147    jalr  $zero, $ra
1148    addiu $t8, 4                # next_arg = curr_arg + 4
1149
1150isLongS:
1151    addu  $ra, $t3, $t6
1152    jalr  $zero, $ra
1153    addiu $t8, 8                # next_arg = curr_arg + 8
1154
1155isSingleS:
1156    addu  $ra, $t4, $t7
1157    jalr  $zero, $ra
1158    addiu $t8, 4                # next_arg = curr_arg + 4
1159
1160isDoubleS:
1161    addu  $ra, $t5, $t7
1162#if defined(__mips_isa_rev) && __mips_isa_rev > 2
1163    addiu $t7, 16               # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
1164#endif
1165    jalr  $zero, $ra
1166    addiu $t8, 8                # next_arg = curr_arg + 8
1167
1168loopEndS:
1169    lw    $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)  # get pointer to the code
1170    jalr  $t9                   # call the method
1171    sw    $zero, 0($sp)         # store null for ArtMethod* at bottom of frame
1172    move  $sp, $fp              # restore the stack
1173    lw    $s0, 0($sp)
1174    .cfi_restore 16
1175    lw    $s1, 4($sp)
1176    .cfi_restore 17
1177    lw    $fp, 8($sp)
1178    .cfi_restore 30
1179    lw    $ra, 12($sp)
1180    .cfi_restore 31
1181    addiu $sp, $sp, SPILL_SIZE
1182    .cfi_adjust_cfa_offset -SPILL_SIZE
1183    lw    $t0, 16($sp)          # get result pointer
1184    lw    $t1, 20($sp)          # get shorty
1185    lb    $t1, 0($t1)           # get result type char
1186    li    $t2, 'D'              # put char 'D' into t2
1187    beq   $t1, $t2, 6f          # branch if result type char == 'D'
1188    li    $t3, 'F'              # put char 'F' into t3
1189    beq   $t1, $t3, 6f          # branch if result type char == 'F'
1190    sw    $v0, 0($t0)           # store the result
1191    jalr  $zero, $ra
1192    sw    $v1, 4($t0)           # store the other half of the result
11936:
1194    SDu   $f0, $f1, 0, $t0, $t1 # store floating point result
1195    jalr  $zero, $ra
1196    nop
1197
1198    // Note that gpr_index is kept within the range of tabIntS and tabLongS
1199    // and fp_index is kept within the range of tabSingleS and tabDoubleS.
1200    .balign 16
1201tabIntS:
1202    LOAD_WORD_TO_REG a1, t8, t6, loopS             # a1 = current argument, gpr_index += 16
1203    LOAD_WORD_TO_REG a2, t8, t6, loopS             # a2 = current argument, gpr_index += 16
1204    LOAD_WORD_TO_REG a3, t8, t6, loopS             # a3 = current argument, gpr_index += 16
1205    LOAD_WORD_TO_REG t0, t8, t6, loopS             # t0 = current argument, gpr_index += 16
1206    LOAD_WORD_TO_REG t1, t8, t6, loopS             # t1 = current argument, gpr_index += 16
1207    LOAD_END t6, 5*16, loopS                       # no more GPR args, gpr_index = 5*16
1208tabLongS:
1209    LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS   # a2_a3 = curr_arg, gpr_index = 3*16
1210    LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS   # a2_a3 = curr_arg, gpr_index = 3*16
1211    LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS   # t0_t1 = curr_arg, gpr_index = 5*16
1212    LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS   # t0_t1 = curr_arg, gpr_index = 5*16
1213    LOAD_END t6, 5*16, loopS                       # no more GPR args, gpr_index = 5*16
1214    LOAD_END t6, 5*16, loopS                       # no more GPR args, gpr_index = 5*16
1215tabSingleS:
1216    LOAD_FLOAT_TO_REG f8, t8, t7, loopS            # f8 = curr_arg, fp_index += 16
1217    LOAD_FLOAT_TO_REG f10, t8, t7, loopS           # f10 = curr_arg, fp_index += 16
1218    LOAD_FLOAT_TO_REG f12, t8, t7, loopS           # f12 = curr_arg, fp_index += 16
1219    LOAD_FLOAT_TO_REG f14, t8, t7, loopS           # f14 = curr_arg, fp_index += 16
1220    LOAD_FLOAT_TO_REG f16, t8, t7, loopS           # f16 = curr_arg, fp_index += 16
1221    LOAD_FLOAT_TO_REG f18, t8, t7, loopS           # f18 = curr_arg, fp_index += 16
1222    LOAD_END t7, 6*16, loopS                       # no more FPR args, fp_index = 6*16
1223tabDoubleS:
1224    LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loopS   # f8_f9 = curr_arg; if FPU32, fp_index += 16
1225    LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loopS # f10_f11 = curr_arg; if FPU32, fp_index += 16
1226    LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loopS # f12_f13 = curr_arg; if FPU32, fp_index += 16
1227    LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loopS # f14_f15 = curr_arg; if FPU32, fp_index += 16
1228    LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loopS # f16_f17 = curr_arg; if FPU32, fp_index += 16
1229    LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loopS # f18_f19 = curr_arg; if FPU32, fp_index += 16
1230    LOAD_END t7, 6*16, loopS                       # no more FPR args, fp_index = 6*16
1231END art_quick_invoke_static_stub
1232
1233#undef SPILL_SIZE
1234
1235    /*
1236     * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
1237     * failure.
1238     */
1239    .extern artHandleFillArrayDataFromCode
1240ENTRY art_quick_handle_fill_data
1241    lw     $a2, 0($sp)                # pass referrer's Method*
1242    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case exception allocation triggers GC
1243    la     $t9, artHandleFillArrayDataFromCode
1244    jalr   $t9                        # (payload offset, Array*, method, Thread*)
1245    move   $a3, rSELF                 # pass Thread::Current
1246    RETURN_IF_ZERO
1247END art_quick_handle_fill_data
1248
1249    /*
1250     * Entry from managed code that calls artLockObjectFromCode, may block for GC.
1251     */
1252    .extern artLockObjectFromCode
1253ENTRY art_quick_lock_object
1254    beqz    $a0, art_quick_throw_null_pointer_exception
1255    li      $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
1256    li      $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
1257.Lretry_lock:
1258    lw      $t0, THREAD_ID_OFFSET(rSELF)  # TODO: Can the thread ID really change during the loop?
1259    ll      $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1260    and     $t2, $t1, $t3                 # zero the gc bits
1261    bnez    $t2, .Lnot_unlocked           # already thin locked
1262    # Unlocked case - $t1: original lock word that's zero except for the read barrier bits.
1263    or      $t2, $t1, $t0                 # $t2 holds thread id with count of 0 with preserved read barrier bits
1264    sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1265    beqz    $t2, .Lretry_lock             # store failed, retry
1266    nop
1267    jalr    $zero, $ra
1268    sync                                  # full (LoadLoad|LoadStore) memory barrier
1269.Lnot_unlocked:
1270    # $t1: original lock word, $t0: thread_id with count of 0 and zero read barrier bits
1271    srl     $t2, $t1, LOCK_WORD_STATE_SHIFT
1272    bnez    $t2, .Lslow_lock              # if either of the top two bits are set, go slow path
1273    xor     $t2, $t1, $t0                 # lock_word.ThreadId() ^ self->ThreadId()
1274    andi    $t2, $t2, 0xFFFF              # zero top 16 bits
1275    bnez    $t2, .Lslow_lock              # lock word and self thread id's match -> recursive lock
1276                                          # otherwise contention, go to slow path
1277    and     $t2, $t1, $t3                 # zero the gc bits
1278    addu    $t2, $t2, $t8                 # increment count in lock word
1279    srl     $t2, $t2, LOCK_WORD_STATE_SHIFT  # if the first gc state bit is set, we overflowed.
1280    bnez    $t2, .Lslow_lock              # if we overflow the count go slow path
1281    addu    $t2, $t1, $t8                 # increment count for real
1282    sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1283    beqz    $t2, .Lretry_lock             # store failed, retry
1284    nop
1285    jalr    $zero, $ra
1286    nop
1287.Lslow_lock:
1288    SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
1289    la      $t9, artLockObjectFromCode
1290    jalr    $t9                           # (Object* obj, Thread*)
1291    move    $a1, rSELF                    # pass Thread::Current
1292    RETURN_IF_ZERO
1293END art_quick_lock_object
1294
1295ENTRY art_quick_lock_object_no_inline
1296    beqz    $a0, art_quick_throw_null_pointer_exception
1297    nop
1298    SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
1299    la      $t9, artLockObjectFromCode
1300    jalr    $t9                           # (Object* obj, Thread*)
1301    move    $a1, rSELF                    # pass Thread::Current
1302    RETURN_IF_ZERO
1303END art_quick_lock_object_no_inline
1304
1305    /*
1306     * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
1307     */
1308    .extern artUnlockObjectFromCode
1309ENTRY art_quick_unlock_object
1310    beqz    $a0, art_quick_throw_null_pointer_exception
1311    li      $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
1312    li      $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
1313.Lretry_unlock:
1314#ifndef USE_READ_BARRIER
1315    lw      $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1316#else
1317    ll      $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)  # Need to use atomic read-modify-write for read barrier
1318#endif
1319    srl     $t2, $t1, LOCK_WORD_STATE_SHIFT
1320    bnez    $t2, .Lslow_unlock         # if either of the top two bits are set, go slow path
1321    lw      $t0, THREAD_ID_OFFSET(rSELF)
1322    and     $t2, $t1, $t3              # zero the gc bits
1323    xor     $t2, $t2, $t0              # lock_word.ThreadId() ^ self->ThreadId()
1324    andi    $t2, $t2, 0xFFFF           # zero top 16 bits
1325    bnez    $t2, .Lslow_unlock         # do lock word and self thread id's match?
1326    and     $t2, $t1, $t3              # zero the gc bits
1327    bgeu    $t2, $t8, .Lrecursive_thin_unlock
1328    # transition to unlocked
1329    nor     $t2, $zero, $t3            # $t2 = LOCK_WORD_GC_STATE_MASK_SHIFTED
1330    and     $t2, $t1, $t2              # $t2: zero except for the preserved gc bits
1331    sync                               # full (LoadStore|StoreStore) memory barrier
1332#ifndef USE_READ_BARRIER
1333    jalr    $zero, $ra
1334    sw      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1335#else
1336    sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1337    beqz    $t2, .Lretry_unlock        # store failed, retry
1338    nop
1339    jalr    $zero, $ra
1340    nop
1341#endif
1342.Lrecursive_thin_unlock:
1343    # t1: original lock word
1344    subu    $t2, $t1, $t8              # decrement count
1345#ifndef USE_READ_BARRIER
1346    jalr    $zero, $ra
1347    sw      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1348#else
1349    sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1350    beqz    $t2, .Lretry_unlock        # store failed, retry
1351    nop
1352    jalr    $zero, $ra
1353    nop
1354#endif
1355.Lslow_unlock:
1356    SETUP_SAVE_REFS_ONLY_FRAME         # save callee saves in case exception allocation triggers GC
1357    la      $t9, artUnlockObjectFromCode
1358    jalr    $t9                        # (Object* obj, Thread*)
1359    move    $a1, rSELF                 # pass Thread::Current
1360    RETURN_IF_ZERO
1361END art_quick_unlock_object
1362
1363ENTRY art_quick_unlock_object_no_inline
1364    beqz    $a0, art_quick_throw_null_pointer_exception
1365    nop
1366    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case exception allocation triggers GC
1367    la      $t9, artUnlockObjectFromCode
1368    jalr    $t9                       # (Object* obj, Thread*)
1369    move    $a1, rSELF                # pass Thread::Current
1370    RETURN_IF_ZERO
1371END art_quick_unlock_object_no_inline
1372
1373    /*
1374     * Entry from managed code that calls artInstanceOfFromCode and delivers exception on failure.
1375     */
1376    .extern artInstanceOfFromCode
1377    .extern artThrowClassCastExceptionForObject
1378ENTRY art_quick_check_instance_of
1379    addiu  $sp, $sp, -32
1380    .cfi_adjust_cfa_offset 32
1381    sw     $gp, 16($sp)
1382    sw     $ra, 12($sp)
1383    .cfi_rel_offset 31, 12
1384    sw     $t9, 8($sp)
1385    sw     $a1, 4($sp)
1386    sw     $a0, 0($sp)
1387    la     $t9, artInstanceOfFromCode
1388    jalr   $t9
1389    addiu  $sp, $sp, -16             # reserve argument slots on the stack
1390    addiu  $sp, $sp, 16
1391    lw     $gp, 16($sp)
1392    beqz   $v0, .Lthrow_class_cast_exception
1393    lw     $ra, 12($sp)
1394    jalr   $zero, $ra
1395    addiu  $sp, $sp, 32
1396    .cfi_adjust_cfa_offset -32
1397.Lthrow_class_cast_exception:
1398    lw     $t9, 8($sp)
1399    lw     $a1, 4($sp)
1400    lw     $a0, 0($sp)
1401    addiu  $sp, $sp, 32
1402    .cfi_adjust_cfa_offset -32
1403    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
1404    la   $t9, artThrowClassCastExceptionForObject
1405    jalr $zero, $t9                 # artThrowClassCastException (Object*, Class*, Thread*)
1406    move $a2, rSELF                 # pass Thread::Current
1407END art_quick_check_instance_of
1408
1409    /*
1410     * Restore rReg's value from offset($sp) if rReg is not the same as rExclude.
1411     * nReg is the register number for rReg.
1412     */
1413.macro POP_REG_NE rReg, nReg, offset, rExclude
1414    .ifnc \rReg, \rExclude
1415        lw \rReg, \offset($sp)      # restore rReg
1416        .cfi_restore \nReg
1417    .endif
1418.endm
1419
1420    /*
1421     * Macro to insert read barrier, only used in art_quick_aput_obj.
1422     * rObj and rDest are registers, offset is a defined literal such as MIRROR_OBJECT_CLASS_OFFSET.
1423     * TODO: When read barrier has a fast path, add heap unpoisoning support for the fast path.
1424     */
1425.macro READ_BARRIER rDest, rObj, offset
1426#ifdef USE_READ_BARRIER
1427    # saved registers used in art_quick_aput_obj: a0-a2, t0-t1, t9, ra. 8 words for 16B alignment.
1428    addiu  $sp, $sp, -32
1429    .cfi_adjust_cfa_offset 32
1430    sw     $ra, 28($sp)
1431    .cfi_rel_offset 31, 28
1432    sw     $t9, 24($sp)
1433    .cfi_rel_offset 25, 24
1434    sw     $t1, 20($sp)
1435    .cfi_rel_offset 9, 20
1436    sw     $t0, 16($sp)
1437    .cfi_rel_offset 8, 16
1438    sw     $a2, 8($sp)              # padding slot at offset 12 (padding can be any slot in the 32B)
1439    .cfi_rel_offset 6, 8
1440    sw     $a1, 4($sp)
1441    .cfi_rel_offset 5, 4
1442    sw     $a0, 0($sp)
1443    .cfi_rel_offset 4, 0
1444
1445    # move $a0, \rRef               # pass ref in a0 (no-op for now since parameter ref is unused)
1446    .ifnc \rObj, $a1
1447        move $a1, \rObj             # pass rObj
1448    .endif
1449    addiu  $a2, $zero, \offset      # pass offset
1450    la     $t9, artReadBarrierSlow
1451    jalr   $t9                      # artReadBarrierSlow(ref, rObj, offset)
1452    addiu  $sp, $sp, -16            # Use branch delay slot to reserve argument slots on the stack
1453                                    # before the call to artReadBarrierSlow.
1454    addiu  $sp, $sp, 16             # restore stack after call to artReadBarrierSlow
1455    # No need to unpoison return value in v0, artReadBarrierSlow() would do the unpoisoning.
1456    move \rDest, $v0                # save return value in rDest
1457                                    # (rDest cannot be v0 in art_quick_aput_obj)
1458
1459    lw     $a0, 0($sp)              # restore registers except rDest
1460                                    # (rDest can only be t0 or t1 in art_quick_aput_obj)
1461    .cfi_restore 4
1462    lw     $a1, 4($sp)
1463    .cfi_restore 5
1464    lw     $a2, 8($sp)
1465    .cfi_restore 6
1466    POP_REG_NE $t0, 8, 16, \rDest
1467    POP_REG_NE $t1, 9, 20, \rDest
1468    lw     $t9, 24($sp)
1469    .cfi_restore 25
1470    lw     $ra, 28($sp)             # restore $ra
1471    .cfi_restore 31
1472    addiu  $sp, $sp, 32
1473    .cfi_adjust_cfa_offset -32
1474#else
1475    lw     \rDest, \offset(\rObj)
1476    UNPOISON_HEAP_REF \rDest
1477#endif  // USE_READ_BARRIER
1478.endm
1479
1480#ifdef USE_READ_BARRIER
1481    .extern artReadBarrierSlow
1482#endif
1483ENTRY art_quick_aput_obj
1484    beqz $a2, .Ldo_aput_null
1485    nop
1486    READ_BARRIER $t0, $a0, MIRROR_OBJECT_CLASS_OFFSET
1487    READ_BARRIER $t1, $a2, MIRROR_OBJECT_CLASS_OFFSET
1488    READ_BARRIER $t0, $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET
1489    bne $t1, $t0, .Lcheck_assignability  # value's type == array's component type - trivial assignability
1490    nop
1491.Ldo_aput:
1492    sll $a1, $a1, 2
1493    add $t0, $a0, $a1
1494    POISON_HEAP_REF $a2
1495    sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
1496    lw  $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
1497    srl $t1, $a0, CARD_TABLE_CARD_SHIFT
1498    add $t1, $t1, $t0
1499    sb  $t0, ($t1)
1500    jalr $zero, $ra
1501    nop
1502.Ldo_aput_null:
1503    sll $a1, $a1, 2
1504    add $t0, $a0, $a1
1505    sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
1506    jalr $zero, $ra
1507    nop
1508.Lcheck_assignability:
1509    addiu  $sp, $sp, -32
1510    .cfi_adjust_cfa_offset 32
1511    sw     $ra, 28($sp)
1512    .cfi_rel_offset 31, 28
1513    sw     $gp, 16($sp)
1514    sw     $t9, 12($sp)
1515    sw     $a2, 8($sp)
1516    sw     $a1, 4($sp)
1517    sw     $a0, 0($sp)
1518    move   $a1, $t1
1519    move   $a0, $t0
1520    la     $t9, artIsAssignableFromCode
1521    jalr   $t9               # (Class*, Class*)
1522    addiu  $sp, $sp, -16     # reserve argument slots on the stack
1523    addiu  $sp, $sp, 16
1524    lw     $ra, 28($sp)
1525    lw     $gp, 16($sp)
1526    lw     $t9, 12($sp)
1527    lw     $a2, 8($sp)
1528    lw     $a1, 4($sp)
1529    lw     $a0, 0($sp)
1530    addiu  $sp, 32
1531    .cfi_adjust_cfa_offset -32
1532    bnez   $v0, .Ldo_aput
1533    nop
1534    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
1535    move $a1, $a2
1536    la   $t9, artThrowArrayStoreException
1537    jalr $zero, $t9                 # artThrowArrayStoreException(Class*, Class*, Thread*)
1538    move $a2, rSELF                 # pass Thread::Current
1539END art_quick_aput_obj
1540
1541// Macros taking opportunity of code similarities for downcalls.
1542.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return
1543    .extern \entrypoint
1544ENTRY \name
1545    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1546    la      $t9, \entrypoint
1547    jalr    $t9                       # (field_idx, Thread*)
1548    move    $a1, rSELF                # pass Thread::Current
1549    \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1550END \name
1551.endm
1552
1553.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return
1554    .extern \entrypoint
1555ENTRY \name
1556    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1557    la      $t9, \entrypoint
1558    jalr    $t9                       # (field_idx, Object*, Thread*) or
1559                                      # (field_idx, new_val, Thread*)
1560    move    $a2, rSELF                # pass Thread::Current
1561    \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1562END \name
1563.endm
1564
1565.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
1566    .extern \entrypoint
1567ENTRY \name
1568    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1569    la      $t9, \entrypoint
1570    jalr    $t9                       # (field_idx, Object*, new_val, Thread*)
1571    move    $a3, rSELF                # pass Thread::Current
1572    \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1573END \name
1574.endm
1575
1576.macro FOUR_ARG_REF_DOWNCALL name, entrypoint, return
1577    .extern \entrypoint
1578ENTRY \name
1579    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1580    la      $t9, \entrypoint
1581    jalr    $t9                       # (field_idx, Object*, 64-bit new_val, Thread*) or
1582                                      # (field_idx, 64-bit new_val, Thread*)
1583                                      # Note that a 64-bit new_val needs to be aligned with
1584                                      # an even-numbered register, hence A1 may be skipped
1585                                      # for new_val to reside in A2-A3.
1586    sw      rSELF, 16($sp)            # pass Thread::Current
1587    \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1588END \name
1589.endm
1590
1591    /*
1592     * Called by managed code to resolve a static/instance field and load/store a value.
1593     */
1594ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1595ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1596ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1597ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1598ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1599ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1600ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1601TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1602TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1603TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1604TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1605TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1606TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1607TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1608TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCompiledCode, RETURN_IF_ZERO
1609TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCompiledCode, RETURN_IF_ZERO
1610TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCompiledCode, RETURN_IF_ZERO
1611TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCompiledCode, RETURN_IF_ZERO
1612FOUR_ARG_REF_DOWNCALL art_quick_set64_static, artSet64StaticFromCompiledCode, RETURN_IF_ZERO
1613THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCompiledCode, RETURN_IF_ZERO
1614THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCompiledCode, RETURN_IF_ZERO
1615THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCompiledCode, RETURN_IF_ZERO
1616THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCompiledCode, RETURN_IF_ZERO
1617FOUR_ARG_REF_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCompiledCode, RETURN_IF_ZERO
1618
1619// Macro to facilitate adding new allocation entrypoints.
1620.macro ONE_ARG_DOWNCALL name, entrypoint, return
1621    .extern \entrypoint
1622ENTRY \name
1623    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1624    la      $t9, \entrypoint
1625    jalr    $t9
1626    move    $a1, rSELF                # pass Thread::Current
1627    \return
1628END \name
1629.endm
1630
1631.macro TWO_ARG_DOWNCALL name, entrypoint, return
1632    .extern \entrypoint
1633ENTRY \name
1634    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1635    la      $t9, \entrypoint
1636    jalr    $t9
1637    move    $a2, rSELF                # pass Thread::Current
1638    \return
1639END \name
1640.endm
1641
1642.macro THREE_ARG_DOWNCALL name, entrypoint, return
1643    .extern \entrypoint
1644ENTRY \name
1645    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1646    la      $t9, \entrypoint
1647    jalr    $t9
1648    move    $a3, rSELF                # pass Thread::Current
1649    \return
1650END \name
1651.endm
1652
1653.macro FOUR_ARG_DOWNCALL name, entrypoint, return
1654    .extern \entrypoint
1655ENTRY \name
1656    SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
1657    la      $t9, \entrypoint
1658    jalr    $t9
1659    sw      rSELF, 16($sp)            # pass Thread::Current
1660    \return
1661END \name
1662.endm
1663
1664// Generate the allocation entrypoints for each allocator.
1665GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
1666// Comment out allocators that have mips specific asm.
1667// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
1668// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
1669GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
1670// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
1671// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab, RegionTLAB)
1672// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab, RegionTLAB)
1673// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab, RegionTLAB)
1674// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab, RegionTLAB)
1675GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
1676GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
1677GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
1678
1679// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
1680// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
1681GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
1682// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
1683// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_tlab, TLAB)
1684// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_tlab, TLAB)
1685// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_tlab, TLAB)
1686// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_tlab, TLAB)
1687GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
1688GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
1689GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
1690
1691// A hand-written override for:
1692//   GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
1693//   GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
1694.macro ART_QUICK_ALLOC_OBJECT_ROSALLOC c_name, cxx_name, isInitialized
1695ENTRY_NO_GP \c_name
1696    # Fast path rosalloc allocation
1697    # a0: type
1698    # s1: Thread::Current
1699    # -----------------------------
1700    # t1: object size
1701    # t2: rosalloc run
1702    # t3: thread stack top offset
1703    # t4: thread stack bottom offset
1704    # v0: free list head
1705    #
1706    # t5, t6 : temps
1707    lw    $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)        # Check if thread local allocation
1708    lw    $t4, THREAD_LOCAL_ALLOC_STACK_END_OFFSET($s1)        # stack has any room left.
1709    bgeu  $t3, $t4, .Lslow_path_\c_name
1710
1711    lw    $t1, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0)  # Load object size (t1).
1712    li    $t5, ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE          # Check if size is for a thread local
1713                                                               # allocation. Also does the
1714                                                               # initialized and finalizable checks.
1715    # When isInitialized == 0, then the class is potentially not yet initialized.
1716    # If the class is not yet initialized, the object size will be very large to force the branch
1717    # below to be taken.
1718    #
1719    # See InitializeClassVisitors in class-inl.h for more details.
1720    bgtu  $t1, $t5, .Lslow_path_\c_name
1721
1722    # Compute the rosalloc bracket index from the size. Since the size is already aligned we can
1723    # combine the two shifts together.
1724    srl   $t1, $t1, (ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT - POINTER_SIZE_SHIFT)
1725
1726    addu  $t2, $t1, $s1
1727    lw    $t2, (THREAD_ROSALLOC_RUNS_OFFSET - __SIZEOF_POINTER__)($t2)  # Load rosalloc run (t2).
1728
1729    # Load the free list head (v0).
1730    # NOTE: this will be the return val.
1731    lw    $v0, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
1732    beqz  $v0, .Lslow_path_\c_name
1733    nop
1734
1735    # Load the next pointer of the head and update the list head with the next pointer.
1736    lw    $t5, ROSALLOC_SLOT_NEXT_OFFSET($v0)
1737    sw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
1738
1739    # Store the class pointer in the header. This also overwrites the first pointer. The offsets are
1740    # asserted to match.
1741
1742#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
1743#error "Class pointer needs to overwrite next pointer."
1744#endif
1745
1746    POISON_HEAP_REF $a0
1747    sw    $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)
1748
1749    # Push the new object onto the thread local allocation stack and increment the thread local
1750    # allocation stack top.
1751    sw    $v0, 0($t3)
1752    addiu $t3, $t3, COMPRESSED_REFERENCE_SIZE
1753    sw    $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)
1754
1755    # Decrement the size of the free list.
1756    lw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
1757    addiu $t5, $t5, -1
1758    sw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
1759
1760.if \isInitialized == 0
1761    # This barrier is only necessary when the allocation also requires a class initialization check.
1762    #
1763    # If the class is already observably initialized, then new-instance allocations are protected
1764    # from publishing by the compiler which inserts its own StoreStore barrier.
1765    sync                                                          # Fence.
1766.endif
1767    jalr  $zero, $ra
1768    nop
1769
1770  .Lslow_path_\c_name:
1771    addiu $t9, $t9, (.Lslow_path_\c_name - \c_name) + 4
1772    .cpload $t9
1773    SETUP_SAVE_REFS_ONLY_FRAME
1774    la    $t9, \cxx_name
1775    jalr  $t9
1776    move  $a1, $s1                                                # Pass self as argument.
1777    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1778END \c_name
1779.endm
1780
1781ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_resolved_rosalloc, artAllocObjectFromCodeResolvedRosAlloc, /* isInitialized */ 0
1782ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, artAllocObjectFromCodeInitializedRosAlloc, /* isInitialized */ 1
1783
1784// The common fast path code for art_quick_alloc_object_resolved/initialized_tlab
1785// and art_quick_alloc_object_resolved/initialized_region_tlab.
1786//
1787// a0: type, s1(rSELF): Thread::Current.
1788// Need to preserve a0 to the slow path.
1789//
1790// If isInitialized=1 then the compiler assumes the object's class has already been initialized.
1791// If isInitialized=0 the compiler can only assume it's been at least resolved.
1792.macro ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH slowPathLabel isInitialized
1793    lw    $v0, THREAD_LOCAL_POS_OFFSET(rSELF)          # Load thread_local_pos.
1794    lw    $a2, THREAD_LOCAL_END_OFFSET(rSELF)          # Load thread_local_end.
1795    subu  $a3, $a2, $v0                                # Compute the remaining buffer size.
1796    lw    $t0, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0)  # Load the object size.
1797
1798    # When isInitialized == 0, then the class is potentially not yet initialized.
1799    # If the class is not yet initialized, the object size will be very large to force the branch
1800    # below to be taken.
1801    #
1802    # See InitializeClassVisitors in class-inl.h for more details.
1803    bgtu  $t0, $a3, \slowPathLabel                     # Check if it fits.
1804    addu  $t1, $v0, $t0                                # Add object size to tlab pos (in branch
1805                                                       # delay slot).
1806    # "Point of no slow path". Won't go to the slow path from here on.
1807    sw    $t1, THREAD_LOCAL_POS_OFFSET(rSELF)          # Store new thread_local_pos.
1808    lw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)      # Increment thread_local_objects.
1809    addiu $a2, $a2, 1
1810    sw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
1811    POISON_HEAP_REF $a0
1812    sw    $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)         # Store the class pointer.
1813
1814.if \isInitialized == 0
1815    # This barrier is only necessary when the allocation also requires a class initialization check.
1816    #
1817    # If the class is already observably initialized, then new-instance allocations are protected
1818    # from publishing by the compiler which inserts its own StoreStore barrier.
1819    sync                                               # Fence.
1820.endif
1821    jalr  $zero, $ra
1822    nop
1823.endm
1824
1825// The common code for art_quick_alloc_object_resolved/initialized_tlab
1826// and art_quick_alloc_object_resolved/initialized_region_tlab.
1827.macro GENERATE_ALLOC_OBJECT_TLAB name, entrypoint, isInitialized
1828ENTRY_NO_GP \name
1829    # Fast path tlab allocation.
1830    # a0: type, s1(rSELF): Thread::Current.
1831    ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lslow_path_\name, \isInitialized
1832.Lslow_path_\name:
1833    addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
1834    .cpload $t9
1835    SETUP_SAVE_REFS_ONLY_FRAME                         # Save callee saves in case of GC.
1836    la    $t9, \entrypoint
1837    jalr  $t9                                          # (mirror::Class*, Thread*)
1838    move  $a1, rSELF                                   # Pass Thread::Current.
1839    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1840END \name
1841.endm
1842
1843GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_region_tlab, artAllocObjectFromCodeResolvedRegionTLAB, /* isInitialized */ 0
1844GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_region_tlab, artAllocObjectFromCodeInitializedRegionTLAB, /* isInitialized */ 1
1845GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_tlab, artAllocObjectFromCodeResolvedTLAB, /* isInitialized */ 0
1846GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_tlab, artAllocObjectFromCodeInitializedTLAB, /* isInitialized */ 1
1847
1848// The common fast path code for art_quick_alloc_array_resolved/initialized_tlab
1849// and art_quick_alloc_array_resolved/initialized_region_tlab.
1850//
1851// a0: type, a1: component_count, a2: total_size, s1(rSELF): Thread::Current.
1852// Need to preserve a0 and a1 to the slow path.
1853.macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE slowPathLabel
1854    li    $a3, OBJECT_ALIGNMENT_MASK_TOGGLED           # Apply alignemnt mask
1855    and   $a2, $a2, $a3                                # (addr + 7) & ~7.
1856
1857    lw    $v0, THREAD_LOCAL_POS_OFFSET(rSELF)          # Load thread_local_pos.
1858    lw    $t1, THREAD_LOCAL_END_OFFSET(rSELF)          # Load thread_local_end.
1859    subu  $t2, $t1, $v0                                # Compute the remaining buffer size.
1860    bgtu  $a2, $t2, \slowPathLabel                     # Check if it fits.
1861    addu  $a2, $v0, $a2                                # Add object size to tlab pos (in branch
1862                                                       # delay slot).
1863
1864    # "Point of no slow path". Won't go to the slow path from here on.
1865    sw    $a2, THREAD_LOCAL_POS_OFFSET(rSELF)          # Store new thread_local_pos.
1866    lw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)      # Increment thread_local_objects.
1867    addiu $a2, $a2, 1
1868    sw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
1869    POISON_HEAP_REF $a0
1870    sw    $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)         # Store the class pointer.
1871    jalr  $zero, $ra
1872    sw    $a1, MIRROR_ARRAY_LENGTH_OFFSET($v0)         # Store the array length.
1873.endm
1874
1875.macro GENERATE_ALLOC_ARRAY_TLAB name, entrypoint, size_setup
1876ENTRY_NO_GP \name
1877    # Fast path array allocation for region tlab allocation.
1878    # a0: mirror::Class* type
1879    # a1: int32_t component_count
1880    # s1(rSELF): Thread::Current
1881    \size_setup .Lslow_path_\name
1882    ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE .Lslow_path_\name
1883.Lslow_path_\name:
1884    # a0: mirror::Class* type
1885    # a1: int32_t component_count
1886    # a2: Thread* self
1887    addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
1888    .cpload $t9
1889    SETUP_SAVE_REFS_ONLY_FRAME                         # Save callee saves in case of GC.
1890    la    $t9, \entrypoint
1891    jalr  $t9
1892    move  $a2, rSELF                                   # Pass Thread::Current.
1893    RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1894END \name
1895.endm
1896
1897.macro COMPUTE_ARRAY_SIZE_UNKNOWN slow_path
1898    break                                              # We should never enter here.
1899                                                       # Code below is for reference.
1900                                                       # Possibly a large object, go slow.
1901                                                       # Also does negative array size check.
1902    li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_WIDE_ARRAY_DATA_OFFSET) / 8)
1903    bgtu  $a1, $a2, \slow_path
1904                                                       # Array classes are never finalizable
1905                                                       # or uninitialized, no need to check.
1906    lw    $a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($a0) # Load component type.
1907    UNPOISON_HEAP_REF $a3
1908    lw    $a3, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET($a3)
1909    srl   $a3, $a3, PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT    # Component size shift is in high 16 bits.
1910    sllv  $a2, $a1, $a3                                # Calculate data size.
1911                                                       # Add array data offset and alignment.
1912    addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1913#if MIRROR_WIDE_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
1914#error Long array data offset must be 4 greater than int array data offset.
1915#endif
1916
1917    addiu $a3, $a3, 1                                  # Add 4 to the length only if the component
1918    andi  $a3, $a3, 4                                  # size shift is 3 (for 64 bit alignment).
1919    addu  $a2, $a2, $a3
1920.endm
1921
1922.macro COMPUTE_ARRAY_SIZE_8 slow_path
1923    # Possibly a large object, go slow.
1924    # Also does negative array size check.
1925    li    $a2, (MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET)
1926    bgtu  $a1, $a2, \slow_path
1927    # Add array data offset and alignment (in branch delay slot).
1928    addiu $a2, $a1, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1929.endm
1930
1931.macro COMPUTE_ARRAY_SIZE_16 slow_path
1932    # Possibly a large object, go slow.
1933    # Also does negative array size check.
1934    li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 2)
1935    bgtu  $a1, $a2, \slow_path
1936    sll   $a2, $a1, 1
1937    # Add array data offset and alignment.
1938    addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1939.endm
1940
1941.macro COMPUTE_ARRAY_SIZE_32 slow_path
1942    # Possibly a large object, go slow.
1943    # Also does negative array size check.
1944    li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 4)
1945    bgtu  $a1, $a2, \slow_path
1946    sll   $a2, $a1, 2
1947    # Add array data offset and alignment.
1948    addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1949.endm
1950
1951.macro COMPUTE_ARRAY_SIZE_64 slow_path
1952    # Possibly a large object, go slow.
1953    # Also does negative array size check.
1954    li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_LONG_ARRAY_DATA_OFFSET) / 8)
1955    bgtu  $a1, $a2, \slow_path
1956    sll   $a2, $a1, 3
1957    # Add array data offset and alignment.
1958    addiu $a2, $a2, (MIRROR_WIDE_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1959.endm
1960
1961GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
1962GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_8
1963GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_16
1964GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_32
1965GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_64
1966
1967GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
1968GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_8
1969GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_16
1970GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
1971GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
1972
1973// Macro for string and type resolution and initialization.
1974// $a0 is both input and output.
1975.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint
1976    .extern \entrypoint
1977ENTRY_NO_GP \name
1978    SETUP_SAVE_EVERYTHING_FRAME       # Save everything in case of GC.
1979    move    $s2, $gp                  # Preserve $gp across the call for exception delivery.
1980    la      $t9, \entrypoint
1981    jalr    $t9                       # (uint32_t index, Thread*)
1982    move    $a1, rSELF                # Pass Thread::Current (in delay slot).
1983    beqz    $v0, 1f                   # Success?
1984    move    $a0, $v0                  # Move result to $a0 (in delay slot).
1985    RESTORE_SAVE_EVERYTHING_FRAME 0   # Restore everything except $a0.
1986    jalr    $zero, $ra                # Return on success.
1987    nop
19881:
1989    move    $gp, $s2
1990    DELIVER_PENDING_EXCEPTION_FRAME_READY
1991END \name
1992.endm
1993
1994    /*
1995     * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
1996     * exception on error. On success the String is returned. A0 holds the string index. The fast
1997     * path check for hit in strings cache has already been performed.
1998     */
1999ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
2000
2001    /*
2002     * Entry from managed code when uninitialized static storage, this stub will run the class
2003     * initializer and deliver the exception on error. On success the static storage base is
2004     * returned.
2005     */
2006ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
2007
2008    /*
2009     * Entry from managed code when dex cache misses for a type_idx.
2010     */
2011ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode
2012
2013    /*
2014     * Entry from managed code when type_idx needs to be checked for access and dex cache may also
2015     * miss.
2016     */
2017ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
2018
2019    /*
2020     * Called by managed code when the value in rSUSPEND has been decremented to 0.
2021     */
2022    .extern artTestSuspendFromCode
2023ENTRY_NO_GP art_quick_test_suspend
2024    lh     rSUSPEND, THREAD_FLAGS_OFFSET(rSELF)
2025    bnez   rSUSPEND, 1f
2026    addiu  rSUSPEND, $zero, SUSPEND_CHECK_INTERVAL   # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
2027    jalr   $zero, $ra
2028    nop
20291:
2030    SETUP_SAVE_EVERYTHING_FRAME                      # save everything for stack crawl
2031    la     $t9, artTestSuspendFromCode
2032    jalr   $t9                                       # (Thread*)
2033    move   $a0, rSELF
2034    RESTORE_SAVE_EVERYTHING_FRAME
2035    jalr   $zero, $ra
2036    nop
2037END art_quick_test_suspend
2038
2039    /*
2040     * Called by managed code that is attempting to call a method on a proxy class. On entry
2041     * a0 holds the proxy method; a1, a2 and a3 may contain arguments.
2042     */
2043    .extern artQuickProxyInvokeHandler
2044ENTRY art_quick_proxy_invoke_handler
2045    SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
2046    move    $a2, rSELF                  # pass Thread::Current
2047    la      $t9, artQuickProxyInvokeHandler
2048    jalr    $t9                         # (Method* proxy method, receiver, Thread*, SP)
2049    addiu   $a3, $sp, ARG_SLOT_SIZE     # pass $sp (remove arg slots)
2050    lw      $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
2051    RESTORE_SAVE_REFS_AND_ARGS_FRAME
2052    bnez    $t7, 1f
2053    # don't care if $v0 and/or $v1 are modified, when exception branch taken
2054    MTD     $v0, $v1, $f0, $f1          # move float value to return value
2055    jalr    $zero, $ra
2056    nop
20571:
2058    DELIVER_PENDING_EXCEPTION
2059END art_quick_proxy_invoke_handler
2060
2061    /*
2062     * Called to resolve an imt conflict.
2063     * a0 is the conflict ArtMethod.
2064     * t7 is a hidden argument that holds the target interface method's dex method index.
2065     *
2066     * Note that this stub writes to a0, t7 and t8.
2067     */
2068ENTRY art_quick_imt_conflict_trampoline
2069    lw      $t8, 0($sp)                                      # Load referrer.
2070    lw      $t8, ART_METHOD_DEX_CACHE_METHODS_OFFSET_32($t8) # Load dex cache methods array.
2071    sll     $t7, $t7, POINTER_SIZE_SHIFT                     # Calculate offset.
2072    addu    $t7, $t8, $t7                                    # Add offset to base.
2073    lw      $t7, 0($t7)                                      # Load interface method.
2074    lw      $a0, ART_METHOD_JNI_OFFSET_32($a0)               # Load ImtConflictTable.
2075
2076.Limt_table_iterate:
2077    lw      $t8, 0($a0)                                      # Load next entry in ImtConflictTable.
2078    # Branch if found.
2079    beq     $t8, $t7, .Limt_table_found
2080    nop
2081    # If the entry is null, the interface method is not in the ImtConflictTable.
2082    beqz    $t8, .Lconflict_trampoline
2083    nop
2084    # Iterate over the entries of the ImtConflictTable.
2085    b       .Limt_table_iterate
2086    addiu   $a0, $a0, 2 * __SIZEOF_POINTER__                 # Iterate to the next entry.
2087
2088.Limt_table_found:
2089    # We successfully hit an entry in the table. Load the target method and jump to it.
2090    lw      $a0, __SIZEOF_POINTER__($a0)
2091    lw      $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)
2092    jalr    $zero, $t9
2093    nop
2094
2095.Lconflict_trampoline:
2096    # Call the runtime stub to populate the ImtConflictTable and jump to the resolved method.
2097    move    $a0, $t7                                         # Load interface method.
2098    INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
2099END art_quick_imt_conflict_trampoline
2100
2101    .extern artQuickResolutionTrampoline
2102ENTRY art_quick_resolution_trampoline
2103    SETUP_SAVE_REFS_AND_ARGS_FRAME
2104    move    $a2, rSELF                    # pass Thread::Current
2105    la      $t9, artQuickResolutionTrampoline
2106    jalr    $t9                           # (Method* called, receiver, Thread*, SP)
2107    addiu   $a3, $sp, ARG_SLOT_SIZE       # pass $sp (remove arg slots)
2108    beqz    $v0, 1f
2109    lw      $a0, ARG_SLOT_SIZE($sp)       # load resolved method to $a0
2110    RESTORE_SAVE_REFS_AND_ARGS_FRAME
2111    move    $t9, $v0               # code pointer must be in $t9 to generate the global pointer
2112    jalr    $zero, $t9             # tail call to method
2113    nop
21141:
2115    RESTORE_SAVE_REFS_AND_ARGS_FRAME
2116    DELIVER_PENDING_EXCEPTION
2117END art_quick_resolution_trampoline
2118
2119    .extern artQuickGenericJniTrampoline
2120    .extern artQuickGenericJniEndTrampoline
2121ENTRY art_quick_generic_jni_trampoline
2122    SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
2123    move    $s8, $sp               # save $sp to $s8
2124    move    $s3, $gp               # save $gp to $s3
2125
2126    # prepare for call to artQuickGenericJniTrampoline(Thread*, SP)
2127    move    $a0, rSELF                     # pass Thread::Current
2128    addiu   $a1, $sp, ARG_SLOT_SIZE        # save $sp (remove arg slots)
2129    la      $t9, artQuickGenericJniTrampoline
2130    jalr    $t9                            # (Thread*, SP)
2131    addiu   $sp, $sp, -5120                # reserve space on the stack
2132
2133    # The C call will have registered the complete save-frame on success.
2134    # The result of the call is:
2135    # v0: ptr to native code, 0 on error.
2136    # v1: ptr to the bottom of the used area of the alloca, can restore stack till here.
2137    beq     $v0, $zero, 2f         # check entry error
2138    move    $t9, $v0               # save the code ptr
2139    move    $sp, $v1               # release part of the alloca
2140
2141    # Load parameters from stack into registers
2142    lw      $a0,   0($sp)
2143    lw      $a1,   4($sp)
2144    lw      $a2,   8($sp)
2145    lw      $a3,  12($sp)
2146
2147    # artQuickGenericJniTrampoline sets bit 0 of the native code address to 1
2148    # when the first two arguments are both single precision floats. This lets
2149    # us extract them properly from the stack and load into floating point
2150    # registers.
2151    MTD     $a0, $a1, $f12, $f13
2152    andi    $t0, $t9, 1
2153    xor     $t9, $t9, $t0
2154    bnez    $t0, 1f
2155    mtc1    $a1, $f14
2156    MTD     $a2, $a3, $f14, $f15
2157
21581:
2159    jalr    $t9                    # native call
2160    nop
2161    addiu   $sp, $sp, 16           # remove arg slots
2162
2163    move    $gp, $s3               # restore $gp from $s3
2164
2165    # result sign extension is handled in C code
2166    # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f)
2167    move    $a0, rSELF             # pass Thread::Current
2168    move    $a2, $v0               # pass result
2169    move    $a3, $v1
2170    addiu   $sp, $sp, -24          # reserve arg slots
2171    la      $t9, artQuickGenericJniEndTrampoline
2172    jalr    $t9
2173    s.d     $f0, 16($sp)           # pass result_f
2174
2175    lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
2176    bne     $t0, $zero, 2f         # check for pending exceptions
2177
2178    move    $sp, $s8               # tear down the alloca
2179
2180    # tear down the callee-save frame
2181    RESTORE_SAVE_REFS_AND_ARGS_FRAME
2182
2183    MTD     $v0, $v1, $f0, $f1     # move float value to return value
2184    jalr    $zero, $ra
2185    nop
2186
21872:
2188    lw      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
2189    move    $gp, $s3               # restore $gp from $s3
2190    # This will create a new save-all frame, required by the runtime.
2191    DELIVER_PENDING_EXCEPTION
2192END art_quick_generic_jni_trampoline
2193
2194    .extern artQuickToInterpreterBridge
2195ENTRY art_quick_to_interpreter_bridge
2196    SETUP_SAVE_REFS_AND_ARGS_FRAME
2197    move    $a1, rSELF                          # pass Thread::Current
2198    la      $t9, artQuickToInterpreterBridge
2199    jalr    $t9                                 # (Method* method, Thread*, SP)
2200    addiu   $a2, $sp, ARG_SLOT_SIZE             # pass $sp (remove arg slots)
2201    lw      $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
2202    RESTORE_SAVE_REFS_AND_ARGS_FRAME
2203    bnez    $t7, 1f
2204    # don't care if $v0 and/or $v1 are modified, when exception branch taken
2205    MTD     $v0, $v1, $f0, $f1                  # move float value to return value
2206    jalr    $zero, $ra
2207    nop
22081:
2209    DELIVER_PENDING_EXCEPTION
2210END art_quick_to_interpreter_bridge
2211
2212    .extern artInvokeObsoleteMethod
2213ENTRY art_invoke_obsolete_method_stub
2214    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
2215    la      $t9, artInvokeObsoleteMethod
2216    jalr    $t9                                 # (Method* method, Thread* self)
2217    move    $a1, rSELF                          # pass Thread::Current
2218END art_invoke_obsolete_method_stub
2219
2220    /*
2221     * Routine that intercepts method calls and returns.
2222     */
2223    .extern artInstrumentationMethodEntryFromCode
2224    .extern artInstrumentationMethodExitFromCode
2225ENTRY art_quick_instrumentation_entry
2226    SETUP_SAVE_REFS_AND_ARGS_FRAME
2227    sw       $a0, 28($sp)   # save arg0 in free arg slot
2228    addiu    $a3, $sp, ARG_SLOT_SIZE      # Pass $sp.
2229    la       $t9, artInstrumentationMethodEntryFromCode
2230    jalr     $t9            # (Method*, Object*, Thread*, SP)
2231    move     $a2, rSELF     # pass Thread::Current
2232    beqz     $v0, .Ldeliver_instrumentation_entry_exception
2233    move     $t9, $v0       # $t9 holds reference to code
2234    lw       $a0, 28($sp)   # restore arg0 from free arg slot
2235    RESTORE_SAVE_REFS_AND_ARGS_FRAME
2236    jalr     $t9            # call method
2237    nop
2238END art_quick_instrumentation_entry
2239    /* intentional fallthrough */
2240    .global art_quick_instrumentation_exit
2241art_quick_instrumentation_exit:
2242    .cfi_startproc
2243    addiu    $t9, $ra, 4    # put current address into $t9 to rebuild $gp
2244    .cpload  $t9
2245    move     $ra, $zero     # link register is to here, so clobber with 0 for later checks
2246
2247    SETUP_SAVE_REFS_ONLY_FRAME
2248    addiu    $sp, $sp, -16  # allocate temp storage on the stack
2249    .cfi_adjust_cfa_offset 16
2250    sw       $v0, ARG_SLOT_SIZE+8($sp)
2251    .cfi_rel_offset 2, ARG_SLOT_SIZE+8
2252    sw       $v1, ARG_SLOT_SIZE+12($sp)
2253    .cfi_rel_offset 3, ARG_SLOT_SIZE+12
2254    s.d      $f0, ARG_SLOT_SIZE($sp)
2255    addiu    $a3, $sp, ARG_SLOT_SIZE      # Pass fpr_res pointer.
2256    addiu    $a2, $sp, ARG_SLOT_SIZE+8    # Pass gpr_res pointer.
2257    addiu    $a1, $sp, ARG_SLOT_SIZE+16   # Pass $sp (remove arg slots and temp storage).
2258    la       $t9, artInstrumentationMethodExitFromCode
2259    jalr     $t9                          # (Thread*, SP, gpr_res*, fpr_res*)
2260    move     $a0, rSELF                   # Pass Thread::Current.
2261    move     $t9, $v0                     # Set aside returned link register.
2262    move     $ra, $v1                     # Set link register for deoptimization.
2263    lw       $v0, ARG_SLOT_SIZE+8($sp)    # Restore return values.
2264    lw       $v1, ARG_SLOT_SIZE+12($sp)
2265    l.d      $f0, ARG_SLOT_SIZE($sp)
2266    addiu    $sp, $sp, 16
2267    .cfi_adjust_cfa_offset -16
2268    RESTORE_SAVE_REFS_ONLY_FRAME
2269    beqz     $t9, .Ldo_deliver_instrumentation_exception
2270    nop                     # Deliver exception if we got nullptr as function.
2271    jalr     $zero, $t9     # Otherwise, return.
2272    nop
2273.Ldeliver_instrumentation_entry_exception:
2274    # Deliver exception for art_quick_instrumentation_entry placed after
2275    # art_quick_instrumentation_exit so that the fallthrough works.
2276    RESTORE_SAVE_REFS_AND_ARGS_FRAME
2277.Ldo_deliver_instrumentation_exception:
2278    DELIVER_PENDING_EXCEPTION
2279END art_quick_instrumentation_exit
2280
2281    /*
2282     * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
2283     * will long jump to the upcall with a special exception of -1.
2284     */
2285    .extern artDeoptimize
2286ENTRY art_quick_deoptimize
2287    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
2288    la       $t9, artDeoptimize
2289    jalr     $t9            # (Thread*)
2290    move     $a0, rSELF     # pass Thread::current
2291END art_quick_deoptimize
2292
2293    /*
2294     * Compiled code has requested that we deoptimize into the interpreter. The deoptimization
2295     * will long jump to the upcall with a special exception of -1.
2296     */
2297    .extern artDeoptimizeFromCompiledCode
2298ENTRY art_quick_deoptimize_from_compiled_code
2299    SETUP_SAVE_EVERYTHING_FRAME
2300    la       $t9, artDeoptimizeFromCompiledCode
2301    jalr     $t9                            # (DeoptimizationKind, Thread*)
2302    move     $a1, rSELF                     # pass Thread::current
2303END art_quick_deoptimize_from_compiled_code
2304
2305    /*
2306     * Long integer shift.  This is different from the generic 32/64-bit
2307     * binary operations because vAA/vBB are 64-bit but vCC (the shift
2308     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
2309     * 6 bits.
2310     * On entry:
2311     *   $a0: low word
2312     *   $a1: high word
2313     *   $a2: shift count
2314     */
2315ENTRY_NO_GP art_quick_shl_long
2316    /* shl-long vAA, vBB, vCC */
2317    sll     $v0, $a0, $a2                    #  rlo<- alo << (shift&31)
2318    not     $v1, $a2                         #  rhi<- 31-shift  (shift is 5b)
2319    srl     $a0, 1
2320    srl     $a0, $v1                         #  alo<- alo >> (32-(shift&31))
2321    sll     $v1, $a1, $a2                    #  rhi<- ahi << (shift&31)
2322    andi    $a2, 0x20                        #  shift< shift & 0x20
2323    beqz    $a2, 1f
2324    or      $v1, $a0                         #  rhi<- rhi | alo
2325
2326    move    $v1, $v0                         #  rhi<- rlo (if shift&0x20)
2327    move    $v0, $zero                       #  rlo<- 0 (if shift&0x20)
2328
23291:  jalr    $zero, $ra
2330    nop
2331END art_quick_shl_long
2332
2333    /*
2334     * Long integer shift.  This is different from the generic 32/64-bit
2335     * binary operations because vAA/vBB are 64-bit but vCC (the shift
2336     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
2337     * 6 bits.
2338     * On entry:
2339     *   $a0: low word
2340     *   $a1: high word
2341     *   $a2: shift count
2342     */
2343ENTRY_NO_GP art_quick_shr_long
2344    sra     $v1, $a1, $a2                    #  rhi<- ahi >> (shift&31)
2345    srl     $v0, $a0, $a2                    #  rlo<- alo >> (shift&31)
2346    sra     $a3, $a1, 31                     #  $a3<- sign(ah)
2347    not     $a0, $a2                         #  alo<- 31-shift (shift is 5b)
2348    sll     $a1, 1
2349    sll     $a1, $a0                         #  ahi<- ahi << (32-(shift&31))
2350    andi    $a2, 0x20                        #  shift & 0x20
2351    beqz    $a2, 1f
2352    or      $v0, $a1                         #  rlo<- rlo | ahi
2353
2354    move    $v0, $v1                         #  rlo<- rhi (if shift&0x20)
2355    move    $v1, $a3                         #  rhi<- sign(ahi) (if shift&0x20)
2356
23571:  jalr    $zero, $ra
2358    nop
2359END art_quick_shr_long
2360
2361    /*
2362     * Long integer shift.  This is different from the generic 32/64-bit
2363     * binary operations because vAA/vBB are 64-bit but vCC (the shift
2364     * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
2365     * 6 bits.
2366     * On entry:
2367     *   $a0: low word
2368     *   $a1: high word
2369     *   $a2: shift count
2370     */
2371    /* ushr-long vAA, vBB, vCC */
2372ENTRY_NO_GP art_quick_ushr_long
2373    srl     $v1, $a1, $a2                    #  rhi<- ahi >> (shift&31)
2374    srl     $v0, $a0, $a2                    #  rlo<- alo >> (shift&31)
2375    not     $a0, $a2                         #  alo<- 31-shift (shift is 5b)
2376    sll     $a1, 1
2377    sll     $a1, $a0                         #  ahi<- ahi << (32-(shift&31))
2378    andi    $a2, 0x20                        #  shift & 0x20
2379    beqz    $a2, 1f
2380    or      $v0, $a1                         #  rlo<- rlo | ahi
2381
2382    move    $v0, $v1                         #  rlo<- rhi (if shift&0x20)
2383    move    $v1, $zero                       #  rhi<- 0 (if shift&0x20)
2384
23851:  jalr    $zero, $ra
2386    nop
2387END art_quick_ushr_long
2388
2389/* java.lang.String.indexOf(int ch, int fromIndex=0) */
2390ENTRY_NO_GP art_quick_indexof
2391/* $a0 holds address of "this" */
2392/* $a1 holds "ch" */
2393/* $a2 holds "fromIndex" */
2394#if (STRING_COMPRESSION_FEATURE)
2395    lw    $a3, MIRROR_STRING_COUNT_OFFSET($a0)    # 'count' field of this
2396#else
2397    lw    $t0, MIRROR_STRING_COUNT_OFFSET($a0)    # this.length()
2398#endif
2399    slt   $t1, $a2, $zero # if fromIndex < 0
2400#if defined(_MIPS_ARCH_MIPS32R6)
2401    seleqz $a2, $a2, $t1  #     fromIndex = 0;
2402#else
2403    movn   $a2, $zero, $t1 #    fromIndex = 0;
2404#endif
2405
2406#if (STRING_COMPRESSION_FEATURE)
2407    srl   $t0, $a3, 1     # $a3 holds count (with flag) and $t0 holds actual length
2408#endif
2409    subu  $t0, $t0, $a2   # this.length() - fromIndex
2410    blez  $t0, 6f         # if this.length()-fromIndex <= 0
2411    li    $v0, -1         #     return -1;
2412
2413#if (STRING_COMPRESSION_FEATURE)
2414    sll   $a3, $a3, 31    # Extract compression flag.
2415    beqz  $a3, .Lstring_indexof_compressed
2416    move  $t2, $a0        # Save a copy in $t2 to later compute result (in branch delay slot).
2417#endif
2418    sll   $v0, $a2, 1     # $a0 += $a2 * 2
2419    addu  $a0, $a0, $v0   #  "  ditto  "
2420    move  $v0, $a2        # Set i to fromIndex.
2421
24221:
2423    lhu   $t3, MIRROR_STRING_VALUE_OFFSET($a0)    # if this.charAt(i) == ch
2424    beq   $t3, $a1, 6f                            #     return i;
2425    addu  $a0, $a0, 2     # i++
2426    subu  $t0, $t0, 1     # this.length() - i
2427    bnez  $t0, 1b         # while this.length() - i > 0
2428    addu  $v0, $v0, 1     # i++
2429
2430    li    $v0, -1         # if this.length() - i <= 0
2431                          #     return -1;
2432
24336:
2434    j     $ra
2435    nop
2436
2437#if (STRING_COMPRESSION_FEATURE)
2438.Lstring_indexof_compressed:
2439    addu  $a0, $a0, $a2   # $a0 += $a2
2440
2441.Lstring_indexof_compressed_loop:
2442    lbu   $t3, MIRROR_STRING_VALUE_OFFSET($a0)
2443    beq   $t3, $a1, .Lstring_indexof_compressed_matched
2444    subu  $t0, $t0, 1
2445    bgtz  $t0, .Lstring_indexof_compressed_loop
2446    addu  $a0, $a0, 1
2447
2448.Lstring_indexof_nomatch:
2449    jalr  $zero, $ra
2450    li    $v0, -1         # return -1;
2451
2452.Lstring_indexof_compressed_matched:
2453    jalr  $zero, $ra
2454    subu  $v0, $a0, $t2   # return (current - start);
2455#endif
2456END art_quick_indexof
2457
2458/* java.lang.String.compareTo(String anotherString) */
2459ENTRY_NO_GP art_quick_string_compareto
2460/* $a0 holds address of "this" */
2461/* $a1 holds address of "anotherString" */
2462    beq    $a0, $a1, .Lstring_compareto_length_diff   # this and anotherString are the same object
2463    move   $a3, $a2                                   # trick to return 0 (it returns a2 - a3)
2464
2465#if (STRING_COMPRESSION_FEATURE)
2466    lw     $t0, MIRROR_STRING_COUNT_OFFSET($a0)   # 'count' field of this
2467    lw     $t1, MIRROR_STRING_COUNT_OFFSET($a1)   # 'count' field of anotherString
2468    sra    $a2, $t0, 1                            # this.length()
2469    sra    $a3, $t1, 1                            # anotherString.length()
2470#else
2471    lw     $a2, MIRROR_STRING_COUNT_OFFSET($a0)   # this.length()
2472    lw     $a3, MIRROR_STRING_COUNT_OFFSET($a1)   # anotherString.length()
2473#endif
2474
2475    MINu   $t2, $a2, $a3
2476    # $t2 now holds min(this.length(),anotherString.length())
2477
2478    # while min(this.length(),anotherString.length())-i != 0
2479    beqz   $t2, .Lstring_compareto_length_diff # if $t2==0
2480    nop                                        #     return (this.length() - anotherString.length())
2481
2482#if (STRING_COMPRESSION_FEATURE)
2483    # Differ cases:
2484    sll    $t3, $t0, 31
2485    beqz   $t3, .Lstring_compareto_this_is_compressed
2486    sll    $t3, $t1, 31                           # In branch delay slot.
2487    beqz   $t3, .Lstring_compareto_that_is_compressed
2488    nop
2489    b      .Lstring_compareto_both_not_compressed
2490    nop
2491
2492.Lstring_compareto_this_is_compressed:
2493    beqz   $t3, .Lstring_compareto_both_compressed
2494    nop
2495    /* If (this->IsCompressed() && that->IsCompressed() == false) */
2496.Lstring_compareto_loop_comparison_this_compressed:
2497    lbu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2498    lhu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2499    bne    $t0, $t1, .Lstring_compareto_char_diff
2500    addiu  $a0, $a0, 1    # point at this.charAt(i++) - compressed
2501    subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
2502    bnez   $t2, .Lstring_compareto_loop_comparison_this_compressed
2503    addiu  $a1, $a1, 2    # point at anotherString.charAt(i++) - uncompressed
2504    jalr   $zero, $ra
2505    subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
2506
2507.Lstring_compareto_that_is_compressed:
2508    lhu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2509    lbu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2510    bne    $t0, $t1, .Lstring_compareto_char_diff
2511    addiu  $a0, $a0, 2    # point at this.charAt(i++) - uncompressed
2512    subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
2513    bnez   $t2, .Lstring_compareto_that_is_compressed
2514    addiu  $a1, $a1, 1    # point at anotherString.charAt(i++) - compressed
2515    jalr   $zero, $ra
2516    subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
2517
2518.Lstring_compareto_both_compressed:
2519    lbu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2520    lbu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2521    bne    $t0, $t1, .Lstring_compareto_char_diff
2522    addiu  $a0, $a0, 1    # point at this.charAt(i++) - compressed
2523    subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
2524    bnez   $t2, .Lstring_compareto_both_compressed
2525    addiu  $a1, $a1, 1    # point at anotherString.charAt(i++) - compressed
2526    jalr   $zero, $ra
2527    subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
2528#endif
2529
2530.Lstring_compareto_both_not_compressed:
2531    lhu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)   # while this.charAt(i) == anotherString.charAt(i)
2532    lhu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2533    bne    $t0, $t1, .Lstring_compareto_char_diff # if this.charAt(i) != anotherString.charAt(i)
2534                          #     return (this.charAt(i) - anotherString.charAt(i))
2535    addiu  $a0, $a0, 2    # point at this.charAt(i++)
2536    subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
2537    bnez   $t2, .Lstring_compareto_both_not_compressed
2538    addiu  $a1, $a1, 2    # point at anotherString.charAt(i++)
2539
2540.Lstring_compareto_length_diff:
2541    jalr   $zero, $ra
2542    subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
2543
2544.Lstring_compareto_char_diff:
2545    jalr   $zero, $ra
2546    subu   $v0, $t0, $t1  # return (this.charAt(i) - anotherString.charAt(i))
2547END art_quick_string_compareto
2548
2549    /*
2550     * Create a function `name` calling the ReadBarrier::Mark routine,
2551     * getting its argument and returning its result through register
2552     * `reg`, saving and restoring all caller-save registers.
2553     */
2554.macro READ_BARRIER_MARK_REG name, reg
2555ENTRY \name
2556    // Null check so that we can load the lock word.
2557    bnez    \reg, .Lnot_null_\name
2558    nop
2559.Lret_rb_\name:
2560    jalr    $zero, $ra
2561    nop
2562.Lnot_null_\name:
2563    // Check lock word for mark bit, if marked return.
2564    lw      $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET(\reg)
2565    .set push
2566    .set noat
2567    sll     $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT     # Move mark bit to sign bit.
2568    bltz    $at, .Lret_rb_\name
2569#if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
2570    // The below code depends on the lock word state being in the highest bits
2571    // and the "forwarding address" state having all bits set.
2572#error "Unexpected lock word state shift or forwarding address state value."
2573#endif
2574    // Test that both the forwarding state bits are 1.
2575    sll     $at, $t9, 1
2576    and     $at, $at, $t9                               # Sign bit = 1 IFF both bits are 1.
2577    bltz    $at, .Lret_forwarding_address\name
2578    nop
2579    .set pop
2580
2581    addiu   $sp, $sp, -160      # Includes 16 bytes of space for argument registers a0-a3.
2582    .cfi_adjust_cfa_offset 160
2583
2584    sw      $ra, 156($sp)
2585    .cfi_rel_offset 31, 156
2586    sw      $t8, 152($sp)
2587    .cfi_rel_offset 24, 152
2588    sw      $t7, 148($sp)
2589    .cfi_rel_offset 15, 148
2590    sw      $t6, 144($sp)
2591    .cfi_rel_offset 14, 144
2592    sw      $t5, 140($sp)
2593    .cfi_rel_offset 13, 140
2594    sw      $t4, 136($sp)
2595    .cfi_rel_offset 12, 136
2596    sw      $t3, 132($sp)
2597    .cfi_rel_offset 11, 132
2598    sw      $t2, 128($sp)
2599    .cfi_rel_offset 10, 128
2600    sw      $t1, 124($sp)
2601    .cfi_rel_offset 9, 124
2602    sw      $t0, 120($sp)
2603    .cfi_rel_offset 8, 120
2604    sw      $a3, 116($sp)
2605    .cfi_rel_offset 7, 116
2606    sw      $a2, 112($sp)
2607    .cfi_rel_offset 6, 112
2608    sw      $a1, 108($sp)
2609    .cfi_rel_offset 5, 108
2610    sw      $a0, 104($sp)
2611    .cfi_rel_offset 4, 104
2612    sw      $v1, 100($sp)
2613    .cfi_rel_offset 3, 100
2614    sw      $v0, 96($sp)
2615    .cfi_rel_offset 2, 96
2616
2617    la      $t9, artReadBarrierMark
2618
2619    sdc1    $f18, 88($sp)
2620    sdc1    $f16, 80($sp)
2621    sdc1    $f14, 72($sp)
2622    sdc1    $f12, 64($sp)
2623    sdc1    $f10, 56($sp)
2624    sdc1    $f8,  48($sp)
2625    sdc1    $f6,  40($sp)
2626    sdc1    $f4,  32($sp)
2627    sdc1    $f2,  24($sp)
2628
2629    .ifnc \reg, $a0
2630      move  $a0, \reg           # pass obj from `reg` in a0
2631    .endif
2632    jalr    $t9                 # v0 <- artReadBarrierMark(obj)
2633    sdc1    $f0,  16($sp)       # in delay slot
2634
2635    lw      $ra, 156($sp)
2636    .cfi_restore 31
2637    lw      $t8, 152($sp)
2638    .cfi_restore 24
2639    lw      $t7, 148($sp)
2640    .cfi_restore 15
2641    lw      $t6, 144($sp)
2642    .cfi_restore 14
2643    lw      $t5, 140($sp)
2644    .cfi_restore 13
2645    lw      $t4, 136($sp)
2646    .cfi_restore 12
2647    lw      $t3, 132($sp)
2648    .cfi_restore 11
2649    lw      $t2, 128($sp)
2650    .cfi_restore 10
2651    lw      $t1, 124($sp)
2652    .cfi_restore 9
2653    lw      $t0, 120($sp)
2654    .cfi_restore 8
2655    lw      $a3, 116($sp)
2656    .cfi_restore 7
2657    lw      $a2, 112($sp)
2658    .cfi_restore 6
2659    lw      $a1, 108($sp)
2660    .cfi_restore 5
2661    lw      $a0, 104($sp)
2662    .cfi_restore 4
2663    lw      $v1, 100($sp)
2664    .cfi_restore 3
2665
2666    .ifnc \reg, $v0
2667      move  \reg, $v0           # `reg` <- v0
2668      lw    $v0, 96($sp)
2669      .cfi_restore 2
2670    .endif
2671
2672    ldc1    $f18, 88($sp)
2673    ldc1    $f16, 80($sp)
2674    ldc1    $f14, 72($sp)
2675    ldc1    $f12, 64($sp)
2676    ldc1    $f10, 56($sp)
2677    ldc1    $f8,  48($sp)
2678    ldc1    $f6,  40($sp)
2679    ldc1    $f4,  32($sp)
2680    ldc1    $f2,  24($sp)
2681    ldc1    $f0,  16($sp)
2682
2683    jalr    $zero, $ra
2684    addiu   $sp, $sp, 160
2685    .cfi_adjust_cfa_offset -160
2686
2687.Lret_forwarding_address\name:
2688    jalr    $zero, $ra
2689    // Shift left by the forwarding address shift. This clears out the state bits since they are
2690    // in the top 2 bits of the lock word.
2691    sll     \reg, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
2692END \name
2693.endm
2694
2695// Note that art_quick_read_barrier_mark_regXX corresponds to register XX+1.
2696// ZERO (register 0) is reserved.
2697// AT (register 1) is reserved as a temporary/scratch register.
2698READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, $v0
2699READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, $v1
2700READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, $a0
2701READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg04, $a1
2702READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, $a2
2703READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, $a3
2704READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg07, $t0
2705READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg08, $t1
2706READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg09, $t2
2707READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg10, $t3
2708READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg11, $t4
2709READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg12, $t5
2710READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg13, $t6
2711READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg14, $t7
2712// S0 and S1 (registers 16 and 17) are reserved as suspended and thread registers.
2713READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg17, $s2
2714READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, $s3
2715READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg19, $s4
2716READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg20, $s5
2717READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg21, $s6
2718READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg22, $s7
2719// T8 and T9 (registers 24 and 25) are reserved as temporary/scratch registers.
2720// K0, K1, GP, SP (registers 26 - 29) are reserved.
2721READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg29, $s8
2722// RA (register 31) is reserved.
2723
2724// Caller code:
2725// Short constant offset/index:
2726// R2:                           | R6:
2727//  lw      $t9, pReadBarrierMarkReg00
2728//  beqz    $t9, skip_call       |  beqzc   $t9, skip_call
2729//  addiu   $t9, $t9, thunk_disp |  nop
2730//  jalr    $t9                  |  jialc   $t9, thunk_disp
2731//  nop                          |
2732// skip_call:                    | skip_call:
2733//  lw      `out`, ofs(`obj`)    |  lw      `out`, ofs(`obj`)
2734// [subu    `out`, $zero, `out`] | [subu    `out`, $zero, `out`]  # Unpoison reference.
2735.macro BRB_FIELD_SHORT_OFFSET_ENTRY obj
27361:
2737    # Explicit null check. May be redundant (for array elements or when the field
2738    # offset is larger than the page size, 4KB).
2739    # $ra will be adjusted to point to lw's stack map when throwing NPE.
2740    beqz    \obj, .Lintrospection_throw_npe
2741#if defined(_MIPS_ARCH_MIPS32R6)
2742    lapc    $gp, .Lintrospection_exits                  # $gp = address of .Lintrospection_exits.
2743#else
2744    addiu   $gp, $t9, (.Lintrospection_exits - 1b)      # $gp = address of .Lintrospection_exits.
2745#endif
2746    .set push
2747    .set noat
2748    lw      $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
2749    sll     $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT   # Move barrier state bit
2750                                                                # to sign bit.
2751    bltz    $at, .Lintrospection_field_array            # If gray, load reference, mark.
2752    move    $t8, \obj                                   # Move `obj` to $t8 for common code.
2753    .set pop
2754    jalr    $zero, $ra                                  # Otherwise, load-load barrier and return.
2755    sync
2756.endm
2757
2758// Caller code (R2):
2759// Long constant offset/index:   | Variable index:
2760//  lw      $t9, pReadBarrierMarkReg00
2761//  lui     $t8, ofs_hi          |  sll     $t8, `index`, 2
2762//  beqz    $t9, skip_call       |  beqz    $t9, skip_call
2763//  addiu   $t9, $t9, thunk_disp |  addiu   $t9, $t9, thunk_disp
2764//  jalr    $t9                  |  jalr    $t9
2765// skip_call:                    | skip_call:
2766//  addu    $t8, $t8, `obj`      |  addu    $t8, $t8, `obj`
2767//  lw      `out`, ofs_lo($t8)   |  lw      `out`, ofs($t8)
2768// [subu    `out`, $zero, `out`] | [subu    `out`, $zero, `out`]  # Unpoison reference.
2769//
2770// Caller code (R6):
2771// Long constant offset/index:   | Variable index:
2772//  lw      $t9, pReadBarrierMarkReg00
2773//  beqz    $t9, skip_call       |  beqz    $t9, skip_call
2774//  aui     $t8, `obj`, ofs_hi   |  lsa     $t8, `index`, `obj`, 2
2775//  jialc   $t9, thunk_disp      |  jialc   $t9, thunk_disp
2776// skip_call:                    | skip_call:
2777//  lw      `out`, ofs_lo($t8)   |  lw      `out`, ofs($t8)
2778// [subu    `out`, $zero, `out`] | [subu    `out`, $zero, `out`]  # Unpoison reference.
2779.macro BRB_FIELD_LONG_OFFSET_ENTRY obj
27801:
2781    # No explicit null check for variable indices or large constant indices/offsets
2782    # as it must have been done earlier.
2783#if defined(_MIPS_ARCH_MIPS32R6)
2784    lapc    $gp, .Lintrospection_exits                  # $gp = address of .Lintrospection_exits.
2785#else
2786    addiu   $gp, $t9, (.Lintrospection_exits - 1b)      # $gp = address of .Lintrospection_exits.
2787#endif
2788    .set push
2789    .set noat
2790    lw      $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
2791    sll     $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT   # Move barrier state bit
2792                                                                # to sign bit.
2793    bltz    $at, .Lintrospection_field_array            # If gray, load reference, mark.
2794    nop
2795    .set pop
2796    jalr    $zero, $ra                                  # Otherwise, load-load barrier and return.
2797    sync
2798    break                                               # Padding to 8 instructions.
2799.endm
2800
2801.macro BRB_GC_ROOT_ENTRY root
28021:
2803#if defined(_MIPS_ARCH_MIPS32R6)
2804    lapc    $gp, .Lintrospection_exit_\root             # $gp = exit point address.
2805#else
2806    addiu   $gp, $t9, (.Lintrospection_exit_\root - 1b)  # $gp = exit point address.
2807#endif
2808    bnez    \root, .Lintrospection_common
2809    move    $t8, \root                                  # Move reference to $t8 for common code.
2810    jalr    $zero, $ra                                  # Return if null.
2811    # The next instruction (from the following BRB_GC_ROOT_ENTRY) fills the delay slot.
2812    # This instruction has no effect (actual NOP for the last entry; otherwise changes $gp,
2813    # which is unused after that anyway).
2814.endm
2815
2816.macro BRB_FIELD_EXIT out
2817.Lintrospection_exit_\out:
2818    jalr    $zero, $ra
2819    move    \out, $t8                                   # Return reference in expected register.
2820.endm
2821
2822.macro BRB_FIELD_EXIT_BREAK
2823    break
2824    break
2825.endm
2826
2827ENTRY_NO_GP art_quick_read_barrier_mark_introspection
2828    # Entry points for offsets/indices not fitting into int16_t and for variable indices.
2829    BRB_FIELD_LONG_OFFSET_ENTRY $v0
2830    BRB_FIELD_LONG_OFFSET_ENTRY $v1
2831    BRB_FIELD_LONG_OFFSET_ENTRY $a0
2832    BRB_FIELD_LONG_OFFSET_ENTRY $a1
2833    BRB_FIELD_LONG_OFFSET_ENTRY $a2
2834    BRB_FIELD_LONG_OFFSET_ENTRY $a3
2835    BRB_FIELD_LONG_OFFSET_ENTRY $t0
2836    BRB_FIELD_LONG_OFFSET_ENTRY $t1
2837    BRB_FIELD_LONG_OFFSET_ENTRY $t2
2838    BRB_FIELD_LONG_OFFSET_ENTRY $t3
2839    BRB_FIELD_LONG_OFFSET_ENTRY $t4
2840    BRB_FIELD_LONG_OFFSET_ENTRY $t5
2841    BRB_FIELD_LONG_OFFSET_ENTRY $t6
2842    BRB_FIELD_LONG_OFFSET_ENTRY $t7
2843    BRB_FIELD_LONG_OFFSET_ENTRY $s2
2844    BRB_FIELD_LONG_OFFSET_ENTRY $s3
2845    BRB_FIELD_LONG_OFFSET_ENTRY $s4
2846    BRB_FIELD_LONG_OFFSET_ENTRY $s5
2847    BRB_FIELD_LONG_OFFSET_ENTRY $s6
2848    BRB_FIELD_LONG_OFFSET_ENTRY $s7
2849    BRB_FIELD_LONG_OFFSET_ENTRY $s8
2850
2851    # Entry points for offsets/indices fitting into int16_t.
2852    BRB_FIELD_SHORT_OFFSET_ENTRY $v0
2853    BRB_FIELD_SHORT_OFFSET_ENTRY $v1
2854    BRB_FIELD_SHORT_OFFSET_ENTRY $a0
2855    BRB_FIELD_SHORT_OFFSET_ENTRY $a1
2856    BRB_FIELD_SHORT_OFFSET_ENTRY $a2
2857    BRB_FIELD_SHORT_OFFSET_ENTRY $a3
2858    BRB_FIELD_SHORT_OFFSET_ENTRY $t0
2859    BRB_FIELD_SHORT_OFFSET_ENTRY $t1
2860    BRB_FIELD_SHORT_OFFSET_ENTRY $t2
2861    BRB_FIELD_SHORT_OFFSET_ENTRY $t3
2862    BRB_FIELD_SHORT_OFFSET_ENTRY $t4
2863    BRB_FIELD_SHORT_OFFSET_ENTRY $t5
2864    BRB_FIELD_SHORT_OFFSET_ENTRY $t6
2865    BRB_FIELD_SHORT_OFFSET_ENTRY $t7
2866    BRB_FIELD_SHORT_OFFSET_ENTRY $s2
2867    BRB_FIELD_SHORT_OFFSET_ENTRY $s3
2868    BRB_FIELD_SHORT_OFFSET_ENTRY $s4
2869    BRB_FIELD_SHORT_OFFSET_ENTRY $s5
2870    BRB_FIELD_SHORT_OFFSET_ENTRY $s6
2871    BRB_FIELD_SHORT_OFFSET_ENTRY $s7
2872    BRB_FIELD_SHORT_OFFSET_ENTRY $s8
2873
2874    .global art_quick_read_barrier_mark_introspection_gc_roots
2875art_quick_read_barrier_mark_introspection_gc_roots:
2876    # Entry points for GC roots.
2877    BRB_GC_ROOT_ENTRY $v0
2878    BRB_GC_ROOT_ENTRY $v1
2879    BRB_GC_ROOT_ENTRY $a0
2880    BRB_GC_ROOT_ENTRY $a1
2881    BRB_GC_ROOT_ENTRY $a2
2882    BRB_GC_ROOT_ENTRY $a3
2883    BRB_GC_ROOT_ENTRY $t0
2884    BRB_GC_ROOT_ENTRY $t1
2885    BRB_GC_ROOT_ENTRY $t2
2886    BRB_GC_ROOT_ENTRY $t3
2887    BRB_GC_ROOT_ENTRY $t4
2888    BRB_GC_ROOT_ENTRY $t5
2889    BRB_GC_ROOT_ENTRY $t6
2890    BRB_GC_ROOT_ENTRY $t7
2891    BRB_GC_ROOT_ENTRY $s2
2892    BRB_GC_ROOT_ENTRY $s3
2893    BRB_GC_ROOT_ENTRY $s4
2894    BRB_GC_ROOT_ENTRY $s5
2895    BRB_GC_ROOT_ENTRY $s6
2896    BRB_GC_ROOT_ENTRY $s7
2897    BRB_GC_ROOT_ENTRY $s8
2898    .global art_quick_read_barrier_mark_introspection_end_of_entries
2899art_quick_read_barrier_mark_introspection_end_of_entries:
2900    nop                         # Fill the delay slot of the last BRB_GC_ROOT_ENTRY.
2901
2902.Lintrospection_throw_npe:
2903    b       art_quick_throw_null_pointer_exception
2904    addiu   $ra, $ra, 4         # Skip lw, make $ra point to lw's stack map.
2905
2906    .set push
2907    .set noat
2908
2909    // Fields and array elements.
2910
2911.Lintrospection_field_array:
2912    // Get the field/element address using $t8 and the offset from the lw instruction.
2913    lh      $at, 0($ra)         # $ra points to lw: $at = field/element offset.
2914    addiu   $ra, $ra, 4 + HEAP_POISON_INSTR_SIZE  # Skip lw(+subu).
2915    addu    $t8, $t8, $at       # $t8 = field/element address.
2916
2917    // Calculate the address of the exit point, store it in $gp and load the reference into $t8.
2918    lb      $at, (-HEAP_POISON_INSTR_SIZE - 2)($ra)   # $ra-HEAP_POISON_INSTR_SIZE-4 points to
2919                                                      # "lw `out`, ...".
2920    andi    $at, $at, 31        # Extract `out` from lw.
2921    sll     $at, $at, 3         # Multiply `out` by the exit point size (BRB_FIELD_EXIT* macros).
2922
2923    lw      $t8, 0($t8)         # $t8 = reference.
2924    UNPOISON_HEAP_REF $t8
2925
2926    // Return if null reference.
2927    bnez    $t8, .Lintrospection_common
2928    addu    $gp, $gp, $at       # $gp = address of the exit point.
2929
2930    // Early return through the exit point.
2931.Lintrospection_return_early:
2932    jalr    $zero, $gp          # Move $t8 to `out` and return.
2933    nop
2934
2935    // Code common for GC roots, fields and array elements.
2936
2937.Lintrospection_common:
2938    // Check lock word for mark bit, if marked return.
2939    lw      $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET($t8)
2940    sll     $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT     # Move mark bit to sign bit.
2941    bltz    $at, .Lintrospection_return_early
2942#if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
2943    // The below code depends on the lock word state being in the highest bits
2944    // and the "forwarding address" state having all bits set.
2945#error "Unexpected lock word state shift or forwarding address state value."
2946#endif
2947    // Test that both the forwarding state bits are 1.
2948    sll     $at, $t9, 1
2949    and     $at, $at, $t9                               # Sign bit = 1 IFF both bits are 1.
2950    bgez    $at, .Lintrospection_mark
2951    nop
2952
2953    .set pop
2954
2955    // Shift left by the forwarding address shift. This clears out the state bits since they are
2956    // in the top 2 bits of the lock word.
2957    jalr    $zero, $gp          # Move $t8 to `out` and return.
2958    sll     $t8, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
2959
2960.Lintrospection_mark:
2961    // Partially set up the stack frame preserving only $ra.
2962    addiu   $sp, $sp, -160      # Includes 16 bytes of space for argument registers $a0-$a3.
2963    .cfi_adjust_cfa_offset 160
2964    sw      $ra, 156($sp)
2965    .cfi_rel_offset 31, 156
2966
2967    // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
2968    bal     1f
2969    sw      $gp, 152($sp)       # Preserve the exit point address.
29701:
2971    .cpload $ra
2972
2973    // Finalize the stack frame and call.
2974    sw      $t7, 148($sp)
2975    .cfi_rel_offset 15, 148
2976    sw      $t6, 144($sp)
2977    .cfi_rel_offset 14, 144
2978    sw      $t5, 140($sp)
2979    .cfi_rel_offset 13, 140
2980    sw      $t4, 136($sp)
2981    .cfi_rel_offset 12, 136
2982    sw      $t3, 132($sp)
2983    .cfi_rel_offset 11, 132
2984    sw      $t2, 128($sp)
2985    .cfi_rel_offset 10, 128
2986    sw      $t1, 124($sp)
2987    .cfi_rel_offset 9, 124
2988    sw      $t0, 120($sp)
2989    .cfi_rel_offset 8, 120
2990    sw      $a3, 116($sp)
2991    .cfi_rel_offset 7, 116
2992    sw      $a2, 112($sp)
2993    .cfi_rel_offset 6, 112
2994    sw      $a1, 108($sp)
2995    .cfi_rel_offset 5, 108
2996    sw      $a0, 104($sp)
2997    .cfi_rel_offset 4, 104
2998    sw      $v1, 100($sp)
2999    .cfi_rel_offset 3, 100
3000    sw      $v0, 96($sp)
3001    .cfi_rel_offset 2, 96
3002
3003    la      $t9, artReadBarrierMark
3004
3005    sdc1    $f18, 88($sp)
3006    sdc1    $f16, 80($sp)
3007    sdc1    $f14, 72($sp)
3008    sdc1    $f12, 64($sp)
3009    sdc1    $f10, 56($sp)
3010    sdc1    $f8,  48($sp)
3011    sdc1    $f6,  40($sp)
3012    sdc1    $f4,  32($sp)
3013    sdc1    $f2,  24($sp)
3014    sdc1    $f0,  16($sp)
3015
3016    jalr    $t9                 # $v0 <- artReadBarrierMark(reference)
3017    move    $a0, $t8            # Pass reference in $a0.
3018    move    $t8, $v0
3019
3020    lw      $ra, 156($sp)
3021    .cfi_restore 31
3022    lw      $gp, 152($sp)       # $gp = address of the exit point.
3023    lw      $t7, 148($sp)
3024    .cfi_restore 15
3025    lw      $t6, 144($sp)
3026    .cfi_restore 14
3027    lw      $t5, 140($sp)
3028    .cfi_restore 13
3029    lw      $t4, 136($sp)
3030    .cfi_restore 12
3031    lw      $t3, 132($sp)
3032    .cfi_restore 11
3033    lw      $t2, 128($sp)
3034    .cfi_restore 10
3035    lw      $t1, 124($sp)
3036    .cfi_restore 9
3037    lw      $t0, 120($sp)
3038    .cfi_restore 8
3039    lw      $a3, 116($sp)
3040    .cfi_restore 7
3041    lw      $a2, 112($sp)
3042    .cfi_restore 6
3043    lw      $a1, 108($sp)
3044    .cfi_restore 5
3045    lw      $a0, 104($sp)
3046    .cfi_restore 4
3047    lw      $v1, 100($sp)
3048    .cfi_restore 3
3049    lw      $v0, 96($sp)
3050    .cfi_restore 2
3051
3052    ldc1    $f18, 88($sp)
3053    ldc1    $f16, 80($sp)
3054    ldc1    $f14, 72($sp)
3055    ldc1    $f12, 64($sp)
3056    ldc1    $f10, 56($sp)
3057    ldc1    $f8,  48($sp)
3058    ldc1    $f6,  40($sp)
3059    ldc1    $f4,  32($sp)
3060    ldc1    $f2,  24($sp)
3061    ldc1    $f0,  16($sp)
3062
3063    // Return through the exit point.
3064    jalr    $zero, $gp          # Move $t8 to `out` and return.
3065    addiu   $sp, $sp, 160
3066    .cfi_adjust_cfa_offset -160
3067
3068.Lintrospection_exits:
3069    BRB_FIELD_EXIT_BREAK
3070    BRB_FIELD_EXIT_BREAK
3071    BRB_FIELD_EXIT $v0
3072    BRB_FIELD_EXIT $v1
3073    BRB_FIELD_EXIT $a0
3074    BRB_FIELD_EXIT $a1
3075    BRB_FIELD_EXIT $a2
3076    BRB_FIELD_EXIT $a3
3077    BRB_FIELD_EXIT $t0
3078    BRB_FIELD_EXIT $t1
3079    BRB_FIELD_EXIT $t2
3080    BRB_FIELD_EXIT $t3
3081    BRB_FIELD_EXIT $t4
3082    BRB_FIELD_EXIT $t5
3083    BRB_FIELD_EXIT $t6
3084    BRB_FIELD_EXIT $t7
3085    BRB_FIELD_EXIT_BREAK
3086    BRB_FIELD_EXIT_BREAK
3087    BRB_FIELD_EXIT $s2
3088    BRB_FIELD_EXIT $s3
3089    BRB_FIELD_EXIT $s4
3090    BRB_FIELD_EXIT $s5
3091    BRB_FIELD_EXIT $s6
3092    BRB_FIELD_EXIT $s7
3093    BRB_FIELD_EXIT_BREAK
3094    BRB_FIELD_EXIT_BREAK
3095    BRB_FIELD_EXIT_BREAK
3096    BRB_FIELD_EXIT_BREAK
3097    BRB_FIELD_EXIT_BREAK
3098    BRB_FIELD_EXIT_BREAK
3099    BRB_FIELD_EXIT $s8
3100    BRB_FIELD_EXIT_BREAK
3101END art_quick_read_barrier_mark_introspection
3102
3103.extern artInvokePolymorphic
3104ENTRY art_quick_invoke_polymorphic
3105    SETUP_SAVE_REFS_AND_ARGS_FRAME
3106    move  $a2, rSELF                          # Make $a2 an alias for the current Thread.
3107    addiu $a3, $sp, ARG_SLOT_SIZE             # Make $a3 a pointer to the saved frame context.
3108    sw    $zero, 20($sp)                      # Initialize JValue result.
3109    sw    $zero, 16($sp)
3110    la    $t9, artInvokePolymorphic
3111    jalr  $t9                                 # (result, receiver, Thread*, context)
3112    addiu $a0, $sp, 16                        # Make $a0 a pointer to the JValue result
3113.macro MATCH_RETURN_TYPE c, handler
3114    li    $t0, \c
3115    beq   $v0, $t0, \handler
3116.endm
3117    MATCH_RETURN_TYPE 'V', .Lcleanup_and_return
3118    MATCH_RETURN_TYPE 'L', .Lstore_int_result
3119    MATCH_RETURN_TYPE 'I', .Lstore_int_result
3120    MATCH_RETURN_TYPE 'J', .Lstore_long_result
3121    MATCH_RETURN_TYPE 'B', .Lstore_int_result
3122    MATCH_RETURN_TYPE 'C', .Lstore_char_result
3123    MATCH_RETURN_TYPE 'D', .Lstore_double_result
3124    MATCH_RETURN_TYPE 'F', .Lstore_float_result
3125    MATCH_RETURN_TYPE 'S', .Lstore_int_result
3126    MATCH_RETURN_TYPE 'Z', .Lstore_boolean_result
3127.purgem MATCH_RETURN_TYPE
3128    nop
3129    b .Lcleanup_and_return
3130    nop
3131.Lstore_boolean_result:
3132    b .Lcleanup_and_return
3133    lbu   $v0, 16($sp)                        # Move byte from JValue result to return value register.
3134.Lstore_char_result:
3135    b .Lcleanup_and_return
3136    lhu   $v0, 16($sp)                        # Move char from JValue result to return value register.
3137.Lstore_double_result:
3138.Lstore_float_result:
3139    LDu   $f0, $f1, 16, $sp, $t0              # Move double/float from JValue result to return value register.
3140    b .Lcleanup_and_return
3141    nop
3142.Lstore_long_result:
3143    lw    $v1, 20($sp)                        # Move upper bits from JValue result to return value register.
3144    // Fall-through for lower bits.
3145.Lstore_int_result:
3146    lw    $v0, 16($sp)                        # Move lower bits from JValue result to return value register.
3147    // Fall-through to clean up and return.
3148.Lcleanup_and_return:
3149    lw    $t7, THREAD_EXCEPTION_OFFSET(rSELF) # Load Thread::Current()->exception_
3150    RESTORE_SAVE_REFS_AND_ARGS_FRAME
3151    bnez  $t7, 1f                             # Success if no exception is pending.
3152    nop
3153    jalr  $zero, $ra
3154    nop
31551:
3156    DELIVER_PENDING_EXCEPTION
3157END art_quick_invoke_polymorphic
3158