blob: b8763531837c3e88fd19134c0c8e43b69762c70d [file] [log] [blame]
Elliott Hughes0f3c5532012-03-30 14:51:51 -07001/*
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
Ian Rogers7655f292013-07-29 11:07:13 -070017#include "asm_support_mips.S"
buzbee5bc5a7b2012-03-07 15:52:59 -080018
Mathieu Chartier7410f292013-11-24 13:17:35 -080019#include "arch/quick_alloc_entrypoints.S"
20
jeffhao07030602012-09-26 14:33:14 -070021 .set noreorder
buzbee5bc5a7b2012-03-07 15:52:59 -080022 .balign 4
23
24 /* Deliver the given exception */
25 .extern artDeliverExceptionFromCode
26 /* Deliver an exception pending on a thread */
jeffhao8161c032012-10-31 15:50:00 -070027 .extern artDeliverPendingExceptionFromCode
buzbee5bc5a7b2012-03-07 15:52:59 -080028
Douglas Leung735b8552014-10-31 12:21:40 -070029#define ARG_SLOT_SIZE 32 // space for a0-a3 plus 4 more words
30
buzbee5bc5a7b2012-03-07 15:52:59 -080031 /*
32 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +010033 * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves)
Douglas Leung735b8552014-10-31 12:21:40 -070034 * 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.
Vladimir Markofd36f1f2016-08-03 18:49:58 +010037 * Reserves FRAME_SIZE_SAVE_ALL_CALLEE_SAVES + ARG_SLOT_SIZE bytes on the stack
buzbee5bc5a7b2012-03-07 15:52:59 -080038 */
Vladimir Markofd36f1f2016-08-03 18:49:58 +010039.macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
Andreas Gampea4e0e672015-05-27 18:31:42 -070040 addiu $sp, $sp, -96
41 .cfi_adjust_cfa_offset 96
Andreas Gampe5c1e4352014-04-21 19:28:24 -070042
43 // Ugly compile-time check, but we only have the preprocessor.
Vladimir Markofd36f1f2016-08-03 18:49:58 +010044#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 96)
45#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(MIPS) size not as expected."
Andreas Gampe5c1e4352014-04-21 19:28:24 -070046#endif
47
Andreas Gampea4e0e672015-05-27 18:31:42 -070048 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
Douglas Leung735b8552014-10-31 12:21:40 -070078 # 1 word for holding Method*
Ian Rogers1d8cdbc2014-09-22 22:51:09 -070079
Douglas Leung4af77b72014-10-22 16:32:28 -070080 lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
81 lw $t0, 0($t0)
Vladimir Markofd36f1f2016-08-03 18:49:58 +010082 lw $t0, RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET($t0)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -070083 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.
Douglas Leung735b8552014-10-31 12:21:40 -070085 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
86 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
buzbee5bc5a7b2012-03-07 15:52:59 -080087.endm
88
89 /*
90 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +010091 * Runtime::CreateCalleeSaveMethod(kSaveRefsOnly). Restoration assumes non-moving GC.
buzbee5bc5a7b2012-03-07 15:52:59 -080092 * Does not include rSUSPEND or rSELF
Douglas Leung735b8552014-10-31 12:21:40 -070093 * 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.
Vladimir Markofd36f1f2016-08-03 18:49:58 +010096 * Reserves FRAME_SIZE_SAVE_REFS_ONLY + ARG_SLOT_SIZE bytes on the stack
buzbee5bc5a7b2012-03-07 15:52:59 -080097 */
Vladimir Markofd36f1f2016-08-03 18:49:58 +010098.macro SETUP_SAVE_REFS_ONLY_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -070099 addiu $sp, $sp, -48
100 .cfi_adjust_cfa_offset 48
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700101
102 // Ugly compile-time check, but we only have the preprocessor.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100103#if (FRAME_SIZE_SAVE_REFS_ONLY != 48)
104#error "FRAME_SIZE_SAVE_REFS_ONLY(MIPS) size not as expected."
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700105#endif
106
Douglas Leung735b8552014-10-31 12:21:40 -0700107 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*
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700126
Douglas Leung4af77b72014-10-22 16:32:28 -0700127 lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
128 lw $t0, 0($t0)
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100129 lw $t0, RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET($t0)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700130 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.
Douglas Leung735b8552014-10-31 12:21:40 -0700132 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
133 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
buzbee5bc5a7b2012-03-07 15:52:59 -0800134.endm
135
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100136.macro RESTORE_SAVE_REFS_ONLY_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -0700137 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)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800140 .cfi_restore 31
Douglas Leung735b8552014-10-31 12:21:40 -0700141 lw $s8, 40($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800142 .cfi_restore 30
Douglas Leung735b8552014-10-31 12:21:40 -0700143 lw $gp, 36($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800144 .cfi_restore 28
Douglas Leung735b8552014-10-31 12:21:40 -0700145 lw $s7, 32($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800146 .cfi_restore 23
Douglas Leung735b8552014-10-31 12:21:40 -0700147 lw $s6, 28($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800148 .cfi_restore 22
Douglas Leung735b8552014-10-31 12:21:40 -0700149 lw $s5, 24($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800150 .cfi_restore 21
Douglas Leung735b8552014-10-31 12:21:40 -0700151 lw $s4, 20($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800152 .cfi_restore 20
Douglas Leung735b8552014-10-31 12:21:40 -0700153 lw $s3, 16($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800154 .cfi_restore 19
Douglas Leung735b8552014-10-31 12:21:40 -0700155 lw $s2, 12($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800156 .cfi_restore 18
Douglas Leung735b8552014-10-31 12:21:40 -0700157 addiu $sp, $sp, 48
158 .cfi_adjust_cfa_offset -48
buzbee5bc5a7b2012-03-07 15:52:59 -0800159.endm
160
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100161.macro RESTORE_SAVE_REFS_ONLY_FRAME_AND_RETURN
162 RESTORE_SAVE_REFS_ONLY_FRAME
Andreas Gampe8d365912015-01-13 11:32:32 -0800163 jalr $zero, $ra
Douglas Leung735b8552014-10-31 12:21:40 -0700164 nop
buzbee5bc5a7b2012-03-07 15:52:59 -0800165.endm
166
167 /*
Alexey Frunze279cfba2017-07-22 00:24:43 -0700168 * Individually usable part of macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY.
169 */
170.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_S4_THRU_S8
171 sw $s8, 104($sp)
172 .cfi_rel_offset 30, 104
173 sw $s7, 96($sp)
174 .cfi_rel_offset 23, 96
175 sw $s6, 92($sp)
176 .cfi_rel_offset 22, 92
177 sw $s5, 88($sp)
178 .cfi_rel_offset 21, 88
179 sw $s4, 84($sp)
180 .cfi_rel_offset 20, 84
181.endm
182
183 /*
buzbee5bc5a7b2012-03-07 15:52:59 -0800184 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100185 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs).
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800186 * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
187 * (26 total + 1 word padding + method*)
buzbee5bc5a7b2012-03-07 15:52:59 -0800188 */
Alexey Frunze279cfba2017-07-22 00:24:43 -0700189.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY save_s4_thru_s8=1
190 addiu $sp, $sp, -112
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800191 .cfi_adjust_cfa_offset 112
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700192
193 // Ugly compile-time check, but we only have the preprocessor.
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800194#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 112)
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100195#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(MIPS) size not as expected."
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700196#endif
197
Alexey Frunze279cfba2017-07-22 00:24:43 -0700198 sw $ra, 108($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800199 .cfi_rel_offset 31, 108
Alexey Frunze279cfba2017-07-22 00:24:43 -0700200 sw $gp, 100($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800201 .cfi_rel_offset 28, 100
Alexey Frunze279cfba2017-07-22 00:24:43 -0700202 .if \save_s4_thru_s8
203 SETUP_SAVE_REFS_AND_ARGS_FRAME_S4_THRU_S8
204 .endif
205 sw $s3, 80($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800206 .cfi_rel_offset 19, 80
Alexey Frunze279cfba2017-07-22 00:24:43 -0700207 sw $s2, 76($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800208 .cfi_rel_offset 18, 76
Alexey Frunze279cfba2017-07-22 00:24:43 -0700209 sw $t1, 72($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800210 .cfi_rel_offset 9, 72
Alexey Frunze279cfba2017-07-22 00:24:43 -0700211 sw $t0, 68($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800212 .cfi_rel_offset 8, 68
Alexey Frunze279cfba2017-07-22 00:24:43 -0700213 sw $a3, 64($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800214 .cfi_rel_offset 7, 64
Alexey Frunze279cfba2017-07-22 00:24:43 -0700215 sw $a2, 60($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800216 .cfi_rel_offset 6, 60
Alexey Frunze279cfba2017-07-22 00:24:43 -0700217 sw $a1, 56($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800218 .cfi_rel_offset 5, 56
Alexey Frunze279cfba2017-07-22 00:24:43 -0700219 SDu $f18, $f19, 48, $sp, $t8
220 SDu $f16, $f17, 40, $sp, $t8
221 SDu $f14, $f15, 32, $sp, $t8
222 SDu $f12, $f13, 24, $sp, $t8
223 SDu $f10, $f11, 16, $sp, $t8
224 SDu $f8, $f9, 8, $sp, $t8
jeffhaofa147e22012-10-12 17:03:32 -0700225 # bottom will hold Method*
Douglas Leung735b8552014-10-31 12:21:40 -0700226.endm
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700227
Douglas Leung735b8552014-10-31 12:21:40 -0700228 /*
229 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100230 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800231 * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
232 * (26 total + 1 word padding + method*)
Douglas Leung735b8552014-10-31 12:21:40 -0700233 * Clobbers $t0 and $sp
234 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100235 * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
Douglas Leung735b8552014-10-31 12:21:40 -0700236 */
Alexey Frunze279cfba2017-07-22 00:24:43 -0700237.macro SETUP_SAVE_REFS_AND_ARGS_FRAME save_s4_thru_s8_only=0
238 .if \save_s4_thru_s8_only
239 // It is expected that `SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY /* save_s4_thru_s8 */ 0`
240 // has been done prior to `SETUP_SAVE_REFS_AND_ARGS_FRAME /* save_s4_thru_s8_only */ 1`.
241 SETUP_SAVE_REFS_AND_ARGS_FRAME_S4_THRU_S8
242 .else
243 SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
244 .endif
Douglas Leung4af77b72014-10-22 16:32:28 -0700245 lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
246 lw $t0, 0($t0)
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100247 lw $t0, RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET($t0)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700248 sw $t0, 0($sp) # Place Method* at bottom of stack.
249 sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame.
Douglas Leung735b8552014-10-31 12:21:40 -0700250 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
251 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
252.endm
253
254 /*
255 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100256 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800257 * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
258 * (26 total + 1 word padding + method*)
Douglas Leung735b8552014-10-31 12:21:40 -0700259 * Clobbers $sp
260 * Use $a0 as the Method* and loads it into bottom of stack.
261 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100262 * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
Douglas Leung735b8552014-10-31 12:21:40 -0700263 */
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100264.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
265 SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
Douglas Leung735b8552014-10-31 12:21:40 -0700266 sw $a0, 0($sp) # Place Method* at bottom of stack.
267 sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame.
268 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
269 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
buzbee5bc5a7b2012-03-07 15:52:59 -0800270.endm
271
Alexey Frunze279cfba2017-07-22 00:24:43 -0700272 /*
273 * Individually usable part of macro RESTORE_SAVE_REFS_AND_ARGS_FRAME.
274 */
275.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP
276 lw $gp, 100($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800277 .cfi_restore 28
Alexey Frunze279cfba2017-07-22 00:24:43 -0700278.endm
279
280 /*
281 * Individually usable part of macro RESTORE_SAVE_REFS_AND_ARGS_FRAME.
282 */
283.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_A1
284 lw $a1, 56($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800285 .cfi_restore 5
Alexey Frunze279cfba2017-07-22 00:24:43 -0700286.endm
287
288.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME restore_s4_thru_s8=1, remove_arg_slots=1
289 .if \remove_arg_slots
290 addiu $sp, $sp, ARG_SLOT_SIZE # Remove argument slots from the stack.
291 .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
292 .endif
293 lw $ra, 108($sp)
294 .cfi_restore 31
295 .if \restore_s4_thru_s8
296 lw $s8, 104($sp)
297 .cfi_restore 30
298 .endif
299 RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP
300 .if \restore_s4_thru_s8
301 lw $s7, 96($sp)
302 .cfi_restore 23
303 lw $s6, 92($sp)
304 .cfi_restore 22
305 lw $s5, 88($sp)
306 .cfi_restore 21
307 lw $s4, 84($sp)
308 .cfi_restore 20
309 .endif
310 lw $s3, 80($sp)
311 .cfi_restore 19
312 lw $s2, 76($sp)
313 .cfi_restore 18
314 lw $t1, 72($sp)
315 .cfi_restore 9
316 lw $t0, 68($sp)
317 .cfi_restore 8
318 lw $a3, 64($sp)
319 .cfi_restore 7
320 lw $a2, 60($sp)
321 .cfi_restore 6
322 RESTORE_SAVE_REFS_AND_ARGS_FRAME_A1
323 LDu $f18, $f19, 48, $sp, $t8
324 LDu $f16, $f17, 40, $sp, $t8
325 LDu $f14, $f15, 32, $sp, $t8
326 LDu $f12, $f13, 24, $sp, $t8
327 LDu $f10, $f11, 16, $sp, $t8
328 LDu $f8, $f9, 8, $sp, $t8
329 addiu $sp, $sp, 112 # Pop frame.
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800330 .cfi_adjust_cfa_offset -112
buzbee5bc5a7b2012-03-07 15:52:59 -0800331.endm
332
333 /*
Vladimir Marko952dbb12016-07-28 12:01:51 +0100334 * Macro that sets up the callee save frame to conform with
335 * Runtime::CreateCalleeSaveMethod(kSaveEverything).
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000336 * when the $sp has already been decremented by FRAME_SIZE_SAVE_EVERYTHING.
Vladimir Marko952dbb12016-07-28 12:01:51 +0100337 * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
338 * 28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
339 * Clobbers $t0 and $t1.
340 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100341 * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
Vladimir Marko952dbb12016-07-28 12:01:51 +0100342 * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
343 */
Alexey Frunze19428ad2017-08-03 10:36:46 -0700344.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
Vladimir Marko952dbb12016-07-28 12:01:51 +0100345 // Ugly compile-time check, but we only have the preprocessor.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100346#if (FRAME_SIZE_SAVE_EVERYTHING != 256)
347#error "FRAME_SIZE_SAVE_EVERYTHING(MIPS) size not as expected."
Vladimir Marko952dbb12016-07-28 12:01:51 +0100348#endif
349
350 sw $ra, 252($sp)
351 .cfi_rel_offset 31, 252
352 sw $fp, 248($sp)
353 .cfi_rel_offset 30, 248
354 sw $gp, 244($sp)
355 .cfi_rel_offset 28, 244
356 sw $t9, 240($sp)
357 .cfi_rel_offset 25, 240
358 sw $t8, 236($sp)
359 .cfi_rel_offset 24, 236
360 sw $s7, 232($sp)
361 .cfi_rel_offset 23, 232
362 sw $s6, 228($sp)
363 .cfi_rel_offset 22, 228
364 sw $s5, 224($sp)
365 .cfi_rel_offset 21, 224
366 sw $s4, 220($sp)
367 .cfi_rel_offset 20, 220
368 sw $s3, 216($sp)
369 .cfi_rel_offset 19, 216
370 sw $s2, 212($sp)
371 .cfi_rel_offset 18, 212
372 sw $s1, 208($sp)
373 .cfi_rel_offset 17, 208
374 sw $s0, 204($sp)
375 .cfi_rel_offset 16, 204
376 sw $t7, 200($sp)
377 .cfi_rel_offset 15, 200
378 sw $t6, 196($sp)
379 .cfi_rel_offset 14, 196
380 sw $t5, 192($sp)
381 .cfi_rel_offset 13, 192
382 sw $t4, 188($sp)
383 .cfi_rel_offset 12, 188
384 sw $t3, 184($sp)
385 .cfi_rel_offset 11, 184
386 sw $t2, 180($sp)
387 .cfi_rel_offset 10, 180
388 sw $t1, 176($sp)
389 .cfi_rel_offset 9, 176
390 sw $t0, 172($sp)
391 .cfi_rel_offset 8, 172
392 sw $a3, 168($sp)
393 .cfi_rel_offset 7, 168
394 sw $a2, 164($sp)
395 .cfi_rel_offset 6, 164
396 sw $a1, 160($sp)
397 .cfi_rel_offset 5, 160
398 sw $a0, 156($sp)
399 .cfi_rel_offset 4, 156
400 sw $v1, 152($sp)
401 .cfi_rel_offset 3, 152
402 sw $v0, 148($sp)
403 .cfi_rel_offset 2, 148
404
405 // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
406 bal 1f
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200407 .set push
408 .set noat
Vladimir Marko952dbb12016-07-28 12:01:51 +0100409 sw $at, 144($sp)
410 .cfi_rel_offset 1, 144
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200411 .set pop
Vladimir Marko952dbb12016-07-28 12:01:51 +01004121:
413 .cpload $ra
414
415 SDu $f30, $f31, 136, $sp, $t1
416 SDu $f28, $f29, 128, $sp, $t1
417 SDu $f26, $f27, 120, $sp, $t1
418 SDu $f24, $f25, 112, $sp, $t1
419 SDu $f22, $f23, 104, $sp, $t1
420 SDu $f20, $f21, 96, $sp, $t1
421 SDu $f18, $f19, 88, $sp, $t1
422 SDu $f16, $f17, 80, $sp, $t1
423 SDu $f14, $f15, 72, $sp, $t1
424 SDu $f12, $f13, 64, $sp, $t1
425 SDu $f10, $f11, 56, $sp, $t1
426 SDu $f8, $f9, 48, $sp, $t1
427 SDu $f6, $f7, 40, $sp, $t1
428 SDu $f4, $f5, 32, $sp, $t1
429 SDu $f2, $f3, 24, $sp, $t1
430 SDu $f0, $f1, 16, $sp, $t1
431
432 # 3 words padding and 1 word for holding Method*
433
434 lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
435 lw $t0, 0($t0)
Alexey Frunze19428ad2017-08-03 10:36:46 -0700436 lw $t0, \runtime_method_offset($t0)
Vladimir Marko952dbb12016-07-28 12:01:51 +0100437 sw $t0, 0($sp) # Place Method* at bottom of stack.
438 sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame.
439 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
440 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
441.endm
442
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000443 /*
444 * Macro that sets up the callee save frame to conform with
445 * Runtime::CreateCalleeSaveMethod(kSaveEverything).
446 * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
447 * 28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
448 * Clobbers $t0 and $t1.
449 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
450 * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
451 * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
452 */
Alexey Frunze19428ad2017-08-03 10:36:46 -0700453.macro SETUP_SAVE_EVERYTHING_FRAME runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000454 addiu $sp, $sp, -(FRAME_SIZE_SAVE_EVERYTHING)
455 .cfi_adjust_cfa_offset (FRAME_SIZE_SAVE_EVERYTHING)
Alexey Frunze19428ad2017-08-03 10:36:46 -0700456 SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP \runtime_method_offset
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000457.endm
458
Alexey Frunzec61c0762017-04-10 13:54:23 -0700459.macro RESTORE_SAVE_EVERYTHING_FRAME restore_a0=1
Vladimir Marko952dbb12016-07-28 12:01:51 +0100460 addiu $sp, $sp, ARG_SLOT_SIZE # remove argument slots on the stack
461 .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
462
463 LDu $f30, $f31, 136, $sp, $t1
464 LDu $f28, $f29, 128, $sp, $t1
465 LDu $f26, $f27, 120, $sp, $t1
466 LDu $f24, $f25, 112, $sp, $t1
467 LDu $f22, $f23, 104, $sp, $t1
468 LDu $f20, $f21, 96, $sp, $t1
469 LDu $f18, $f19, 88, $sp, $t1
470 LDu $f16, $f17, 80, $sp, $t1
471 LDu $f14, $f15, 72, $sp, $t1
472 LDu $f12, $f13, 64, $sp, $t1
473 LDu $f10, $f11, 56, $sp, $t1
474 LDu $f8, $f9, 48, $sp, $t1
475 LDu $f6, $f7, 40, $sp, $t1
476 LDu $f4, $f5, 32, $sp, $t1
477 LDu $f2, $f3, 24, $sp, $t1
478 LDu $f0, $f1, 16, $sp, $t1
479
480 lw $ra, 252($sp)
481 .cfi_restore 31
482 lw $fp, 248($sp)
483 .cfi_restore 30
484 lw $gp, 244($sp)
485 .cfi_restore 28
486 lw $t9, 240($sp)
487 .cfi_restore 25
488 lw $t8, 236($sp)
489 .cfi_restore 24
490 lw $s7, 232($sp)
491 .cfi_restore 23
492 lw $s6, 228($sp)
493 .cfi_restore 22
494 lw $s5, 224($sp)
495 .cfi_restore 21
496 lw $s4, 220($sp)
497 .cfi_restore 20
498 lw $s3, 216($sp)
499 .cfi_restore 19
500 lw $s2, 212($sp)
501 .cfi_restore 18
502 lw $s1, 208($sp)
503 .cfi_restore 17
504 lw $s0, 204($sp)
505 .cfi_restore 16
506 lw $t7, 200($sp)
507 .cfi_restore 15
508 lw $t6, 196($sp)
509 .cfi_restore 14
510 lw $t5, 192($sp)
511 .cfi_restore 13
512 lw $t4, 188($sp)
513 .cfi_restore 12
514 lw $t3, 184($sp)
515 .cfi_restore 11
516 lw $t2, 180($sp)
517 .cfi_restore 10
518 lw $t1, 176($sp)
519 .cfi_restore 9
520 lw $t0, 172($sp)
521 .cfi_restore 8
522 lw $a3, 168($sp)
523 .cfi_restore 7
524 lw $a2, 164($sp)
525 .cfi_restore 6
526 lw $a1, 160($sp)
527 .cfi_restore 5
Alexey Frunzec61c0762017-04-10 13:54:23 -0700528 .if \restore_a0
Vladimir Marko952dbb12016-07-28 12:01:51 +0100529 lw $a0, 156($sp)
530 .cfi_restore 4
Alexey Frunzec61c0762017-04-10 13:54:23 -0700531 .endif
Vladimir Marko952dbb12016-07-28 12:01:51 +0100532 lw $v1, 152($sp)
533 .cfi_restore 3
534 lw $v0, 148($sp)
535 .cfi_restore 2
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200536 .set push
537 .set noat
Vladimir Marko952dbb12016-07-28 12:01:51 +0100538 lw $at, 144($sp)
539 .cfi_restore 1
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200540 .set pop
Vladimir Marko952dbb12016-07-28 12:01:51 +0100541
542 addiu $sp, $sp, 256 # pop frame
543 .cfi_adjust_cfa_offset -256
544.endm
545
546 /*
Alexey Frunzec61c0762017-04-10 13:54:23 -0700547 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
548 * exception is Thread::Current()->exception_ when the runtime method frame is ready.
549 * Requires $gp properly set up.
buzbee5bc5a7b2012-03-07 15:52:59 -0800550 */
Alexey Frunzec61c0762017-04-10 13:54:23 -0700551.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
jeffhao8161c032012-10-31 15:50:00 -0700552 la $t9, artDeliverPendingExceptionFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800553 jalr $zero, $t9 # artDeliverPendingExceptionFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700554 move $a0, rSELF # pass Thread::Current
buzbee5bc5a7b2012-03-07 15:52:59 -0800555.endm
556
Alexey Frunzec61c0762017-04-10 13:54:23 -0700557 /*
558 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
559 * exception is Thread::Current()->exception_.
560 * Requires $gp properly set up.
561 */
562.macro DELIVER_PENDING_EXCEPTION
563 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME # save callee saves for throw
564 DELIVER_PENDING_EXCEPTION_FRAME_READY
565.endm
566
buzbee5bc5a7b2012-03-07 15:52:59 -0800567.macro RETURN_IF_NO_EXCEPTION
jeffhao7fbee072012-08-24 17:56:54 -0700568 lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100569 RESTORE_SAVE_REFS_ONLY_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700570 bnez $t0, 1f # success if no exception is pending
buzbee5bc5a7b2012-03-07 15:52:59 -0800571 nop
Andreas Gampe8d365912015-01-13 11:32:32 -0800572 jalr $zero, $ra
buzbee5bc5a7b2012-03-07 15:52:59 -0800573 nop
5741:
575 DELIVER_PENDING_EXCEPTION
576.endm
577
578.macro RETURN_IF_ZERO
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100579 RESTORE_SAVE_REFS_ONLY_FRAME
jeffhao7fbee072012-08-24 17:56:54 -0700580 bnez $v0, 1f # success?
buzbee5bc5a7b2012-03-07 15:52:59 -0800581 nop
Andreas Gampe8d365912015-01-13 11:32:32 -0800582 jalr $zero, $ra # return on success
buzbee5bc5a7b2012-03-07 15:52:59 -0800583 nop
5841:
585 DELIVER_PENDING_EXCEPTION
586.endm
587
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800588.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100589 RESTORE_SAVE_REFS_ONLY_FRAME
jeffhao7fbee072012-08-24 17:56:54 -0700590 beqz $v0, 1f # success?
buzbee5bc5a7b2012-03-07 15:52:59 -0800591 nop
Andreas Gampe8d365912015-01-13 11:32:32 -0800592 jalr $zero, $ra # return on success
buzbee5bc5a7b2012-03-07 15:52:59 -0800593 nop
5941:
595 DELIVER_PENDING_EXCEPTION
596.endm
597
buzbee5bc5a7b2012-03-07 15:52:59 -0800598 /*
Goran Jakovljevic3bc13812016-03-22 17:16:05 +0100599 * On stack replacement stub.
600 * On entry:
601 * a0 = stack to copy
602 * a1 = size of stack
603 * a2 = pc to call
604 * a3 = JValue* result
605 * [sp + 16] = shorty
606 * [sp + 20] = thread
607 */
608ENTRY art_quick_osr_stub
609 // Save callee general purpose registers, RA and GP.
610 addiu $sp, $sp, -48
611 .cfi_adjust_cfa_offset 48
612 sw $ra, 44($sp)
613 .cfi_rel_offset 31, 44
614 sw $s8, 40($sp)
615 .cfi_rel_offset 30, 40
616 sw $gp, 36($sp)
617 .cfi_rel_offset 28, 36
618 sw $s7, 32($sp)
619 .cfi_rel_offset 23, 32
620 sw $s6, 28($sp)
621 .cfi_rel_offset 22, 28
622 sw $s5, 24($sp)
623 .cfi_rel_offset 21, 24
624 sw $s4, 20($sp)
625 .cfi_rel_offset 20, 20
626 sw $s3, 16($sp)
627 .cfi_rel_offset 19, 16
628 sw $s2, 12($sp)
629 .cfi_rel_offset 18, 12
630 sw $s1, 8($sp)
631 .cfi_rel_offset 17, 8
632 sw $s0, 4($sp)
633 .cfi_rel_offset 16, 4
634
635 move $s8, $sp # Save the stack pointer
636 move $s7, $a1 # Save size of stack
637 move $s6, $a2 # Save the pc to call
638 lw rSELF, 48+20($sp) # Save managed thread pointer into rSELF
639 addiu $t0, $sp, -12 # Reserve space for stack pointer,
640 # JValue* result, and ArtMethod* slot.
641 srl $t0, $t0, 4 # Align stack pointer to 16 bytes
642 sll $sp, $t0, 4 # Update stack pointer
643 sw $s8, 4($sp) # Save old stack pointer
644 sw $a3, 8($sp) # Save JValue* result
645 sw $zero, 0($sp) # Store null for ArtMethod* at bottom of frame
646 subu $sp, $a1 # Reserve space for callee stack
647 move $a2, $a1
648 move $a1, $a0
649 move $a0, $sp
650 la $t9, memcpy
651 jalr $t9 # memcpy (dest a0, src a1, bytes a2)
652 addiu $sp, $sp, -16 # make space for argument slots for memcpy
653 bal .Losr_entry # Call the method
654 addiu $sp, $sp, 16 # restore stack after memcpy
655 lw $a2, 8($sp) # Restore JValue* result
656 lw $sp, 4($sp) # Restore saved stack pointer
657 lw $a0, 48+16($sp) # load shorty
658 lbu $a0, 0($a0) # load return type
659 li $a1, 'D' # put char 'D' into a1
660 beq $a0, $a1, .Losr_fp_result # Test if result type char == 'D'
661 li $a1, 'F' # put char 'F' into a1
662 beq $a0, $a1, .Losr_fp_result # Test if result type char == 'F'
663 nop
664 sw $v0, 0($a2)
665 b .Losr_exit
666 sw $v1, 4($a2) # store v0/v1 into result
667.Losr_fp_result:
668 SDu $f0, $f1, 0, $a2, $t0 # store f0/f1 into result
669.Losr_exit:
670 lw $ra, 44($sp)
671 .cfi_restore 31
672 lw $s8, 40($sp)
673 .cfi_restore 30
674 lw $gp, 36($sp)
675 .cfi_restore 28
676 lw $s7, 32($sp)
677 .cfi_restore 23
678 lw $s6, 28($sp)
679 .cfi_restore 22
680 lw $s5, 24($sp)
681 .cfi_restore 21
682 lw $s4, 20($sp)
683 .cfi_restore 20
684 lw $s3, 16($sp)
685 .cfi_restore 19
686 lw $s2, 12($sp)
687 .cfi_restore 18
688 lw $s1, 8($sp)
689 .cfi_restore 17
690 lw $s0, 4($sp)
691 .cfi_restore 16
692 jalr $zero, $ra
693 addiu $sp, $sp, 48
694 .cfi_adjust_cfa_offset -48
695.Losr_entry:
696 addiu $s7, $s7, -4
697 addu $t0, $s7, $sp
698 move $t9, $s6
699 jalr $zero, $t9
700 sw $ra, 0($t0) # Store RA per the compiler ABI
701END art_quick_osr_stub
702
703 /*
jeffhao7fbee072012-08-24 17:56:54 -0700704 * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_
buzbee5bc5a7b2012-03-07 15:52:59 -0800705 * FIXME: just guessing about the shape of the jmpbuf. Where will pc be?
706 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800707ENTRY art_quick_do_long_jump
Duane Sande34652f2014-11-04 11:09:36 -0800708 LDu $f0, $f1, 0*8, $a1, $t1
709 LDu $f2, $f3, 1*8, $a1, $t1
710 LDu $f4, $f5, 2*8, $a1, $t1
711 LDu $f6, $f7, 3*8, $a1, $t1
712 LDu $f8, $f9, 4*8, $a1, $t1
713 LDu $f10, $f11, 5*8, $a1, $t1
714 LDu $f12, $f13, 6*8, $a1, $t1
715 LDu $f14, $f15, 7*8, $a1, $t1
716 LDu $f16, $f17, 8*8, $a1, $t1
717 LDu $f18, $f19, 9*8, $a1, $t1
718 LDu $f20, $f21, 10*8, $a1, $t1
719 LDu $f22, $f23, 11*8, $a1, $t1
720 LDu $f24, $f25, 12*8, $a1, $t1
721 LDu $f26, $f27, 13*8, $a1, $t1
722 LDu $f28, $f29, 14*8, $a1, $t1
723 LDu $f30, $f31, 15*8, $a1, $t1
724
Chris Dearman748dd952014-05-23 10:47:01 -0700725 .set push
726 .set nomacro
727 .set noat
jeffhao7fbee072012-08-24 17:56:54 -0700728 lw $at, 4($a0)
Chris Dearman748dd952014-05-23 10:47:01 -0700729 .set pop
jeffhao7fbee072012-08-24 17:56:54 -0700730 lw $v0, 8($a0)
731 lw $v1, 12($a0)
732 lw $a1, 20($a0)
733 lw $a2, 24($a0)
734 lw $a3, 28($a0)
735 lw $t0, 32($a0)
736 lw $t1, 36($a0)
737 lw $t2, 40($a0)
738 lw $t3, 44($a0)
739 lw $t4, 48($a0)
740 lw $t5, 52($a0)
741 lw $t6, 56($a0)
742 lw $t7, 60($a0)
743 lw $s0, 64($a0)
744 lw $s1, 68($a0)
745 lw $s2, 72($a0)
746 lw $s3, 76($a0)
747 lw $s4, 80($a0)
748 lw $s5, 84($a0)
749 lw $s6, 88($a0)
750 lw $s7, 92($a0)
751 lw $t8, 96($a0)
752 lw $t9, 100($a0)
jeffhao7fbee072012-08-24 17:56:54 -0700753 lw $gp, 112($a0)
754 lw $sp, 116($a0)
755 lw $fp, 120($a0)
756 lw $ra, 124($a0)
757 lw $a0, 16($a0)
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100758 move $v0, $zero # clear result registers v0 and v1 (in branch delay slot)
Goran Jakovljevic75969962015-10-27 12:29:07 +0100759 jalr $zero, $t9 # do long jump
jeffhao7fbee072012-08-24 17:56:54 -0700760 move $v1, $zero
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800761END art_quick_do_long_jump
buzbee5bc5a7b2012-03-07 15:52:59 -0800762
buzbee5bc5a7b2012-03-07 15:52:59 -0800763 /*
764 * Called by managed code, saves most registers (forms basis of long jump context) and passes
765 * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
Lazar Trsic84bc06e2015-06-10 16:05:46 +0200766 * the bottom of the thread. On entry a0 holds Throwable*
buzbee5bc5a7b2012-03-07 15:52:59 -0800767 */
Ian Rogers468532e2013-08-05 10:56:33 -0700768ENTRY art_quick_deliver_exception
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100769 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700770 la $t9, artDeliverExceptionFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800771 jalr $zero, $t9 # artDeliverExceptionFromCode(Throwable*, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700772 move $a1, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700773END art_quick_deliver_exception
buzbee5bc5a7b2012-03-07 15:52:59 -0800774
buzbee5bc5a7b2012-03-07 15:52:59 -0800775 /*
776 * Called by managed code to create and deliver a NullPointerException
777 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800778 .extern artThrowNullPointerExceptionFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100779ENTRY_NO_GP art_quick_throw_null_pointer_exception
780 // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
781 // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
782 SETUP_SAVE_EVERYTHING_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700783 la $t9, artThrowNullPointerExceptionFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800784 jalr $zero, $t9 # artThrowNullPointerExceptionFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700785 move $a0, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700786END art_quick_throw_null_pointer_exception
buzbee5bc5a7b2012-03-07 15:52:59 -0800787
Nicolas Geoffraye8e11272016-06-28 18:08:46 +0100788
789 /*
790 * Call installed by a signal handler to create and deliver a NullPointerException.
791 */
792 .extern artThrowNullPointerExceptionFromSignal
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000793ENTRY_NO_GP_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, FRAME_SIZE_SAVE_EVERYTHING
794 SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
795 # Retrieve the fault address from the padding where the signal handler stores it.
796 lw $a0, (ARG_SLOT_SIZE + __SIZEOF_POINTER__)($sp)
Nicolas Geoffraye8e11272016-06-28 18:08:46 +0100797 la $t9, artThrowNullPointerExceptionFromSignal
798 jalr $zero, $t9 # artThrowNullPointerExceptionFromSignal(uintptr_t, Thread*)
799 move $a1, rSELF # pass Thread::Current
800END art_quick_throw_null_pointer_exception_from_signal
801
buzbee5bc5a7b2012-03-07 15:52:59 -0800802 /*
803 * Called by managed code to create and deliver an ArithmeticException
804 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800805 .extern artThrowDivZeroFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100806ENTRY_NO_GP art_quick_throw_div_zero
807 SETUP_SAVE_EVERYTHING_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700808 la $t9, artThrowDivZeroFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800809 jalr $zero, $t9 # artThrowDivZeroFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700810 move $a0, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700811END art_quick_throw_div_zero
buzbee5bc5a7b2012-03-07 15:52:59 -0800812
buzbee5bc5a7b2012-03-07 15:52:59 -0800813 /*
814 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
815 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800816 .extern artThrowArrayBoundsFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100817ENTRY_NO_GP art_quick_throw_array_bounds
818 // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
819 // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
820 SETUP_SAVE_EVERYTHING_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700821 la $t9, artThrowArrayBoundsFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800822 jalr $zero, $t9 # artThrowArrayBoundsFromCode(index, limit, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700823 move $a2, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700824END art_quick_throw_array_bounds
buzbee5bc5a7b2012-03-07 15:52:59 -0800825
Ian Rogers57b86d42012-03-27 16:05:41 -0700826 /*
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100827 * Called by managed code to create and deliver a StringIndexOutOfBoundsException
828 * as if thrown from a call to String.charAt().
829 */
830 .extern artThrowStringBoundsFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100831ENTRY_NO_GP art_quick_throw_string_bounds
832 SETUP_SAVE_EVERYTHING_FRAME
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100833 la $t9, artThrowStringBoundsFromCode
834 jalr $zero, $t9 # artThrowStringBoundsFromCode(index, limit, Thread*)
835 move $a2, rSELF # pass Thread::Current
836END art_quick_throw_string_bounds
837
838 /*
Ian Rogers57b86d42012-03-27 16:05:41 -0700839 * Called by managed code to create and deliver a StackOverflowError.
840 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800841 .extern artThrowStackOverflowFromCode
Ian Rogers468532e2013-08-05 10:56:33 -0700842ENTRY art_quick_throw_stack_overflow
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100843 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700844 la $t9, artThrowStackOverflowFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800845 jalr $zero, $t9 # artThrowStackOverflowFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700846 move $a0, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700847END art_quick_throw_stack_overflow
buzbee5bc5a7b2012-03-07 15:52:59 -0800848
Ian Rogers57b86d42012-03-27 16:05:41 -0700849 /*
buzbee5bc5a7b2012-03-07 15:52:59 -0800850 * All generated callsites for interface invokes and invocation slow paths will load arguments
jeffhao7fbee072012-08-24 17:56:54 -0700851 * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100852 * the method_idx. This wrapper will save arg1-arg3, and call the appropriate C helper.
jeffhao7fbee072012-08-24 17:56:54 -0700853 * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
buzbee5bc5a7b2012-03-07 15:52:59 -0800854 *
jeffhao7fbee072012-08-24 17:56:54 -0700855 * The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting
856 * of the target Method* in $v0 and method->code_ in $v1.
buzbee5bc5a7b2012-03-07 15:52:59 -0800857 *
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700858 * If unsuccessful, the helper will return null/null. There will be a pending exception in the
buzbee5bc5a7b2012-03-07 15:52:59 -0800859 * thread and we branch to another stub to deliver it.
860 *
861 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
862 * pointing back to the original caller.
863 */
Alexey Frunze279cfba2017-07-22 00:24:43 -0700864.macro INVOKE_TRAMPOLINE_BODY cxx_name, save_s4_thru_s8_only=0
buzbee5bc5a7b2012-03-07 15:52:59 -0800865 .extern \cxx_name
Alexey Frunze279cfba2017-07-22 00:24:43 -0700866 SETUP_SAVE_REFS_AND_ARGS_FRAME \save_s4_thru_s8_only # save callee saves in case
867 # allocation triggers GC
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100868 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100869 la $t9, \cxx_name
870 jalr $t9 # (method_idx, this, Thread*, $sp)
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100871 addiu $a3, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
872 move $a0, $v0 # save target Method*
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100873 RESTORE_SAVE_REFS_AND_ARGS_FRAME
jeffhaofa147e22012-10-12 17:03:32 -0700874 beqz $v0, 1f
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100875 move $t9, $v1 # save $v0->code_
Andreas Gampe8d365912015-01-13 11:32:32 -0800876 jalr $zero, $t9
buzbee5bc5a7b2012-03-07 15:52:59 -0800877 nop
8781:
879 DELIVER_PENDING_EXCEPTION
Andreas Gampe3031c8d2015-07-13 20:11:06 -0700880.endm
881.macro INVOKE_TRAMPOLINE c_name, cxx_name
882ENTRY \c_name
883 INVOKE_TRAMPOLINE_BODY \cxx_name
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800884END \c_name
buzbee5bc5a7b2012-03-07 15:52:59 -0800885.endm
886
Logan Chien8dbb7082013-01-25 20:31:17 +0800887INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
buzbee5bc5a7b2012-03-07 15:52:59 -0800888
Logan Chien8dbb7082013-01-25 20:31:17 +0800889INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
890INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
891INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
892INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
buzbee5bc5a7b2012-03-07 15:52:59 -0800893
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800894// Each of the following macros expands into four instructions or 16 bytes.
895// They are used to build indexable "tables" of code.
896
897.macro LOAD_WORD_TO_REG reg, next_arg, index_reg, label
Goran Jakovljevicff734982015-08-24 12:58:55 +0000898 lw $\reg, -4($\next_arg) # next_arg points to argument after the current one (offset is 4)
899 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800900 addiu $\index_reg, 16
901 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000902.endm
903
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800904.macro LOAD_LONG_TO_REG reg1, reg2, next_arg, index_reg, next_index, label
Goran Jakovljevicff734982015-08-24 12:58:55 +0000905 lw $\reg1, -8($\next_arg) # next_arg points to argument after the current one (offset is 8)
906 lw $\reg2, -4($\next_arg)
907 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800908 li $\index_reg, \next_index
909 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000910.endm
911
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800912.macro LOAD_FLOAT_TO_REG reg, next_arg, index_reg, label
Goran Jakovljevicff734982015-08-24 12:58:55 +0000913 lwc1 $\reg, -4($\next_arg) # next_arg points to argument after the current one (offset is 4)
914 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800915 addiu $\index_reg, 16
916 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000917.endm
918
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800919#if defined(__mips_isa_rev) && __mips_isa_rev > 2
920// LDu expands into 3 instructions for 64-bit FPU, so index_reg cannot be updated here.
921.macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
922 .set reorder # force use of the branch delay slot
Goran Jakovljevicff734982015-08-24 12:58:55 +0000923 LDu $\reg1, $\reg2, -8, $\next_arg, $\tmp # next_arg points to argument after the current one
924 # (offset is 8)
925 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800926 .set noreorder
927 .balign 16
928.endm
929#else
930// LDu expands into 2 instructions for 32-bit FPU, so index_reg is updated here.
931.macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
932 LDu $\reg1, $\reg2, -8, $\next_arg, $\tmp # next_arg points to argument after the current one
933 # (offset is 8)
934 b \label
935 addiu $\index_reg, 16
936 .balign 16
937.endm
938#endif
939
940.macro LOAD_END index_reg, next_index, label
941 b \label
942 li $\index_reg, \next_index
943 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000944.endm
945
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100946#define SPILL_SIZE 32
947
Jeff Hao79fe5392013-04-24 18:41:58 -0700948 /*
Ian Rogersef7d42f2014-01-06 12:55:46 -0800949 * Invocation stub for quick code.
Jeff Hao5d917302013-02-27 17:57:33 -0800950 * On entry:
951 * a0 = method pointer
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700952 * a1 = argument array or null for no argument methods
Jeff Hao5d917302013-02-27 17:57:33 -0800953 * a2 = size of argument array in bytes
954 * a3 = (managed) thread pointer
Jeff Hao6474d192013-03-26 14:08:09 -0700955 * [sp + 16] = JValue* result
Ian Rogers0177e532014-02-11 16:30:46 -0800956 * [sp + 20] = shorty
Jeff Hao5d917302013-02-27 17:57:33 -0800957 */
958ENTRY art_quick_invoke_stub
Jeff Hao5d917302013-02-27 17:57:33 -0800959 sw $a0, 0($sp) # save out a0
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100960 addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
961 .cfi_adjust_cfa_offset SPILL_SIZE
962 sw $gp, 16($sp)
Jeff Hao5d917302013-02-27 17:57:33 -0800963 sw $ra, 12($sp)
964 .cfi_rel_offset 31, 12
965 sw $fp, 8($sp)
966 .cfi_rel_offset 30, 8
967 sw $s1, 4($sp)
968 .cfi_rel_offset 17, 4
969 sw $s0, 0($sp)
970 .cfi_rel_offset 16, 0
971 move $fp, $sp # save sp in fp
972 .cfi_def_cfa_register 30
973 move $s1, $a3 # move managed thread pointer into s1
974 addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval
Goran Jakovljevicff734982015-08-24 12:58:55 +0000975 addiu $t0, $a2, 4 # create space for ArtMethod* in frame.
Douglas Leung735b8552014-10-31 12:21:40 -0700976 subu $t0, $sp, $t0 # reserve & align *stack* to 16 bytes:
Goran Jakovljevicff734982015-08-24 12:58:55 +0000977 srl $t0, $t0, 4 # native calling convention only aligns to 8B,
978 sll $sp, $t0, 4 # so we have to ensure ART 16B alignment ourselves.
979 addiu $a0, $sp, 4 # pass stack pointer + ArtMethod* as dest for memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100980 la $t9, memcpy
981 jalr $t9 # (dest, src, bytes)
Jeff Hao5d917302013-02-27 17:57:33 -0800982 addiu $sp, $sp, -16 # make space for argument slots for memcpy
983 addiu $sp, $sp, 16 # restore stack after memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100984 lw $gp, 16($fp) # restore $gp
985 lw $a0, SPILL_SIZE($fp) # restore ArtMethod*
Goran Jakovljevicff734982015-08-24 12:58:55 +0000986 lw $a1, 4($sp) # a1 = this*
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800987 addiu $t8, $sp, 8 # t8 = pointer to the current argument (skip ArtMethod* and this*)
988 li $t6, 0 # t6 = gpr_index = 0 (corresponds to A2; A0 and A1 are skipped)
989 li $t7, 0 # t7 = fp_index = 0
990 lw $t9, 20 + SPILL_SIZE($fp) # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100991 # as the $fp is SPILL_SIZE bytes below the $sp on entry)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800992 addiu $t9, 1 # t9 = shorty + 1 (skip 1 for return type)
993
994 // Load the base addresses of tabInt ... tabDouble.
995 // We will use the register indices (gpr_index, fp_index) to branch.
996 // Note that the indices are scaled by 16, so they can be added to the bases directly.
997#if defined(__mips_isa_rev) && __mips_isa_rev >= 6
998 lapc $t2, tabInt
999 lapc $t3, tabLong
1000 lapc $t4, tabSingle
1001 lapc $t5, tabDouble
1002#else
1003 bltzal $zero, tabBase # nal
1004 addiu $t2, $ra, %lo(tabInt - tabBase)
1005tabBase:
1006 addiu $t3, $ra, %lo(tabLong - tabBase)
1007 addiu $t4, $ra, %lo(tabSingle - tabBase)
1008 addiu $t5, $ra, %lo(tabDouble - tabBase)
1009#endif
1010
Goran Jakovljevicff734982015-08-24 12:58:55 +00001011loop:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001012 lbu $ra, 0($t9) # ra = shorty[i]
1013 beqz $ra, loopEnd # finish getting args when shorty[i] == '\0'
1014 addiu $t9, 1
Goran Jakovljevicff734982015-08-24 12:58:55 +00001015
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001016 addiu $ra, -'J'
1017 beqz $ra, isLong # branch if result type char == 'J'
1018 addiu $ra, 'J' - 'D'
1019 beqz $ra, isDouble # branch if result type char == 'D'
1020 addiu $ra, 'D' - 'F'
1021 beqz $ra, isSingle # branch if result type char == 'F'
Goran Jakovljevicff734982015-08-24 12:58:55 +00001022
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001023 addu $ra, $t2, $t6
1024 jalr $zero, $ra
1025 addiu $t8, 4 # next_arg = curr_arg + 4
Goran Jakovljevicff734982015-08-24 12:58:55 +00001026
1027isLong:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001028 addu $ra, $t3, $t6
1029 jalr $zero, $ra
1030 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +00001031
1032isSingle:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001033 addu $ra, $t4, $t7
1034 jalr $zero, $ra
1035 addiu $t8, 4 # next_arg = curr_arg + 4
1036
1037isDouble:
1038 addu $ra, $t5, $t7
1039#if defined(__mips_isa_rev) && __mips_isa_rev > 2
1040 addiu $t7, 16 # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
1041#endif
1042 jalr $zero, $ra
1043 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +00001044
1045loopEnd:
Mathieu Chartiere401d142015-04-22 13:56:20 -07001046 lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0) # get pointer to the code
Jeff Hao5d917302013-02-27 17:57:33 -08001047 jalr $t9 # call the method
Goran Jakovljevicff734982015-08-24 12:58:55 +00001048 sw $zero, 0($sp) # store null for ArtMethod* at bottom of frame
Jeff Hao5d917302013-02-27 17:57:33 -08001049 move $sp, $fp # restore the stack
1050 lw $s0, 0($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001051 .cfi_restore 16
Jeff Hao5d917302013-02-27 17:57:33 -08001052 lw $s1, 4($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001053 .cfi_restore 17
Jeff Hao5d917302013-02-27 17:57:33 -08001054 lw $fp, 8($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001055 .cfi_restore 30
Jeff Hao5d917302013-02-27 17:57:33 -08001056 lw $ra, 12($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001057 .cfi_restore 31
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001058 addiu $sp, $sp, SPILL_SIZE
1059 .cfi_adjust_cfa_offset -SPILL_SIZE
Jeff Hao5d917302013-02-27 17:57:33 -08001060 lw $t0, 16($sp) # get result pointer
Ian Rogers0177e532014-02-11 16:30:46 -08001061 lw $t1, 20($sp) # get shorty
1062 lb $t1, 0($t1) # get result type char
Goran Jakovljevicff734982015-08-24 12:58:55 +00001063 li $t2, 'D' # put char 'D' into t2
1064 beq $t1, $t2, 5f # branch if result type char == 'D'
1065 li $t3, 'F' # put char 'F' into t3
1066 beq $t1, $t3, 5f # branch if result type char == 'F'
Jeff Hao5d917302013-02-27 17:57:33 -08001067 sw $v0, 0($t0) # store the result
Andreas Gampe8d365912015-01-13 11:32:32 -08001068 jalr $zero, $ra
Jeff Hao5d917302013-02-27 17:57:33 -08001069 sw $v1, 4($t0) # store the other half of the result
Goran Jakovljevicff734982015-08-24 12:58:55 +000010705:
Duane Sande34652f2014-11-04 11:09:36 -08001071 SDu $f0, $f1, 0, $t0, $t1 # store floating point result
Andreas Gampe8d365912015-01-13 11:32:32 -08001072 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08001073 nop
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001074
1075 // Note that gpr_index is kept within the range of tabInt and tabLong
1076 // and fp_index is kept within the range of tabSingle and tabDouble.
1077 .balign 16
1078tabInt:
1079 LOAD_WORD_TO_REG a2, t8, t6, loop # a2 = current argument, gpr_index += 16
1080 LOAD_WORD_TO_REG a3, t8, t6, loop # a3 = current argument, gpr_index += 16
1081 LOAD_WORD_TO_REG t0, t8, t6, loop # t0 = current argument, gpr_index += 16
1082 LOAD_WORD_TO_REG t1, t8, t6, loop # t1 = current argument, gpr_index += 16
1083 LOAD_END t6, 4*16, loop # no more GPR args, gpr_index = 4*16
1084tabLong:
1085 LOAD_LONG_TO_REG a2, a3, t8, t6, 2*16, loop # a2_a3 = curr_arg, gpr_index = 2*16
1086 LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop # t0_t1 = curr_arg, gpr_index = 4*16
1087 LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop # t0_t1 = curr_arg, gpr_index = 4*16
1088 LOAD_END t6, 4*16, loop # no more GPR args, gpr_index = 4*16
1089 LOAD_END t6, 4*16, loop # no more GPR args, gpr_index = 4*16
1090tabSingle:
1091 LOAD_FLOAT_TO_REG f8, t8, t7, loop # f8 = curr_arg, fp_index += 16
1092 LOAD_FLOAT_TO_REG f10, t8, t7, loop # f10 = curr_arg, fp_index += 16
1093 LOAD_FLOAT_TO_REG f12, t8, t7, loop # f12 = curr_arg, fp_index += 16
1094 LOAD_FLOAT_TO_REG f14, t8, t7, loop # f14 = curr_arg, fp_index += 16
1095 LOAD_FLOAT_TO_REG f16, t8, t7, loop # f16 = curr_arg, fp_index += 16
1096 LOAD_FLOAT_TO_REG f18, t8, t7, loop # f18 = curr_arg, fp_index += 16
1097 LOAD_END t7, 6*16, loop # no more FPR args, fp_index = 6*16
1098tabDouble:
1099 LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loop # f8_f9 = curr_arg; if FPU32, fp_index += 16
1100 LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loop # f10_f11 = curr_arg; if FPU32, fp_index += 16
1101 LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loop # f12_f13 = curr_arg; if FPU32, fp_index += 16
1102 LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loop # f14_f15 = curr_arg; if FPU32, fp_index += 16
1103 LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loop # f16_f17 = curr_arg; if FPU32, fp_index += 16
1104 LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loop # f18_f19 = curr_arg; if FPU32, fp_index += 16
1105 LOAD_END t7, 6*16, loop # no more FPR args, fp_index = 6*16
Jeff Hao5d917302013-02-27 17:57:33 -08001106END art_quick_invoke_stub
1107
1108 /*
Goran Jakovljevicff734982015-08-24 12:58:55 +00001109 * Invocation static stub for quick code.
1110 * On entry:
1111 * a0 = method pointer
1112 * a1 = argument array or null for no argument methods
1113 * a2 = size of argument array in bytes
1114 * a3 = (managed) thread pointer
1115 * [sp + 16] = JValue* result
1116 * [sp + 20] = shorty
1117 */
1118ENTRY art_quick_invoke_static_stub
1119 sw $a0, 0($sp) # save out a0
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001120 addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
1121 .cfi_adjust_cfa_offset SPILL_SIZE
1122 sw $gp, 16($sp)
Goran Jakovljevicff734982015-08-24 12:58:55 +00001123 sw $ra, 12($sp)
1124 .cfi_rel_offset 31, 12
1125 sw $fp, 8($sp)
1126 .cfi_rel_offset 30, 8
1127 sw $s1, 4($sp)
1128 .cfi_rel_offset 17, 4
1129 sw $s0, 0($sp)
1130 .cfi_rel_offset 16, 0
1131 move $fp, $sp # save sp in fp
1132 .cfi_def_cfa_register 30
1133 move $s1, $a3 # move managed thread pointer into s1
1134 addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval
1135 addiu $t0, $a2, 4 # create space for ArtMethod* in frame.
1136 subu $t0, $sp, $t0 # reserve & align *stack* to 16 bytes:
1137 srl $t0, $t0, 4 # native calling convention only aligns to 8B,
1138 sll $sp, $t0, 4 # so we have to ensure ART 16B alignment ourselves.
1139 addiu $a0, $sp, 4 # pass stack pointer + ArtMethod* as dest for memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001140 la $t9, memcpy
1141 jalr $t9 # (dest, src, bytes)
Goran Jakovljevicff734982015-08-24 12:58:55 +00001142 addiu $sp, $sp, -16 # make space for argument slots for memcpy
1143 addiu $sp, $sp, 16 # restore stack after memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001144 lw $gp, 16($fp) # restore $gp
1145 lw $a0, SPILL_SIZE($fp) # restore ArtMethod*
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001146 addiu $t8, $sp, 4 # t8 = pointer to the current argument (skip ArtMethod*)
1147 li $t6, 0 # t6 = gpr_index = 0 (corresponds to A1; A0 is skipped)
1148 li $t7, 0 # t7 = fp_index = 0
1149 lw $t9, 20 + SPILL_SIZE($fp) # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001150 # as the $fp is SPILL_SIZE bytes below the $sp on entry)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001151 addiu $t9, 1 # t9 = shorty + 1 (skip 1 for return type)
1152
1153 // Load the base addresses of tabIntS ... tabDoubleS.
1154 // We will use the register indices (gpr_index, fp_index) to branch.
1155 // Note that the indices are scaled by 16, so they can be added to the bases directly.
1156#if defined(__mips_isa_rev) && __mips_isa_rev >= 6
1157 lapc $t2, tabIntS
1158 lapc $t3, tabLongS
1159 lapc $t4, tabSingleS
1160 lapc $t5, tabDoubleS
1161#else
1162 bltzal $zero, tabBaseS # nal
1163 addiu $t2, $ra, %lo(tabIntS - tabBaseS)
1164tabBaseS:
1165 addiu $t3, $ra, %lo(tabLongS - tabBaseS)
1166 addiu $t4, $ra, %lo(tabSingleS - tabBaseS)
1167 addiu $t5, $ra, %lo(tabDoubleS - tabBaseS)
1168#endif
1169
Goran Jakovljevicff734982015-08-24 12:58:55 +00001170loopS:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001171 lbu $ra, 0($t9) # ra = shorty[i]
1172 beqz $ra, loopEndS # finish getting args when shorty[i] == '\0'
1173 addiu $t9, 1
Goran Jakovljevicff734982015-08-24 12:58:55 +00001174
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001175 addiu $ra, -'J'
1176 beqz $ra, isLongS # branch if result type char == 'J'
1177 addiu $ra, 'J' - 'D'
1178 beqz $ra, isDoubleS # branch if result type char == 'D'
1179 addiu $ra, 'D' - 'F'
1180 beqz $ra, isSingleS # branch if result type char == 'F'
Goran Jakovljevicff734982015-08-24 12:58:55 +00001181
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001182 addu $ra, $t2, $t6
1183 jalr $zero, $ra
1184 addiu $t8, 4 # next_arg = curr_arg + 4
Goran Jakovljevicff734982015-08-24 12:58:55 +00001185
1186isLongS:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001187 addu $ra, $t3, $t6
1188 jalr $zero, $ra
1189 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +00001190
1191isSingleS:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001192 addu $ra, $t4, $t7
1193 jalr $zero, $ra
1194 addiu $t8, 4 # next_arg = curr_arg + 4
1195
1196isDoubleS:
1197 addu $ra, $t5, $t7
1198#if defined(__mips_isa_rev) && __mips_isa_rev > 2
1199 addiu $t7, 16 # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
1200#endif
1201 jalr $zero, $ra
1202 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +00001203
1204loopEndS:
1205 lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0) # get pointer to the code
1206 jalr $t9 # call the method
1207 sw $zero, 0($sp) # store null for ArtMethod* at bottom of frame
1208 move $sp, $fp # restore the stack
1209 lw $s0, 0($sp)
1210 .cfi_restore 16
1211 lw $s1, 4($sp)
1212 .cfi_restore 17
1213 lw $fp, 8($sp)
1214 .cfi_restore 30
1215 lw $ra, 12($sp)
1216 .cfi_restore 31
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001217 addiu $sp, $sp, SPILL_SIZE
1218 .cfi_adjust_cfa_offset -SPILL_SIZE
Goran Jakovljevicff734982015-08-24 12:58:55 +00001219 lw $t0, 16($sp) # get result pointer
1220 lw $t1, 20($sp) # get shorty
1221 lb $t1, 0($t1) # get result type char
1222 li $t2, 'D' # put char 'D' into t2
1223 beq $t1, $t2, 6f # branch if result type char == 'D'
1224 li $t3, 'F' # put char 'F' into t3
1225 beq $t1, $t3, 6f # branch if result type char == 'F'
1226 sw $v0, 0($t0) # store the result
1227 jalr $zero, $ra
1228 sw $v1, 4($t0) # store the other half of the result
12296:
1230 SDu $f0, $f1, 0, $t0, $t1 # store floating point result
1231 jalr $zero, $ra
1232 nop
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001233
1234 // Note that gpr_index is kept within the range of tabIntS and tabLongS
1235 // and fp_index is kept within the range of tabSingleS and tabDoubleS.
1236 .balign 16
1237tabIntS:
1238 LOAD_WORD_TO_REG a1, t8, t6, loopS # a1 = current argument, gpr_index += 16
1239 LOAD_WORD_TO_REG a2, t8, t6, loopS # a2 = current argument, gpr_index += 16
1240 LOAD_WORD_TO_REG a3, t8, t6, loopS # a3 = current argument, gpr_index += 16
1241 LOAD_WORD_TO_REG t0, t8, t6, loopS # t0 = current argument, gpr_index += 16
1242 LOAD_WORD_TO_REG t1, t8, t6, loopS # t1 = current argument, gpr_index += 16
1243 LOAD_END t6, 5*16, loopS # no more GPR args, gpr_index = 5*16
1244tabLongS:
1245 LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS # a2_a3 = curr_arg, gpr_index = 3*16
1246 LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS # a2_a3 = curr_arg, gpr_index = 3*16
1247 LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS # t0_t1 = curr_arg, gpr_index = 5*16
1248 LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS # t0_t1 = curr_arg, gpr_index = 5*16
1249 LOAD_END t6, 5*16, loopS # no more GPR args, gpr_index = 5*16
1250 LOAD_END t6, 5*16, loopS # no more GPR args, gpr_index = 5*16
1251tabSingleS:
1252 LOAD_FLOAT_TO_REG f8, t8, t7, loopS # f8 = curr_arg, fp_index += 16
1253 LOAD_FLOAT_TO_REG f10, t8, t7, loopS # f10 = curr_arg, fp_index += 16
1254 LOAD_FLOAT_TO_REG f12, t8, t7, loopS # f12 = curr_arg, fp_index += 16
1255 LOAD_FLOAT_TO_REG f14, t8, t7, loopS # f14 = curr_arg, fp_index += 16
1256 LOAD_FLOAT_TO_REG f16, t8, t7, loopS # f16 = curr_arg, fp_index += 16
1257 LOAD_FLOAT_TO_REG f18, t8, t7, loopS # f18 = curr_arg, fp_index += 16
1258 LOAD_END t7, 6*16, loopS # no more FPR args, fp_index = 6*16
1259tabDoubleS:
1260 LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loopS # f8_f9 = curr_arg; if FPU32, fp_index += 16
1261 LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loopS # f10_f11 = curr_arg; if FPU32, fp_index += 16
1262 LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loopS # f12_f13 = curr_arg; if FPU32, fp_index += 16
1263 LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loopS # f14_f15 = curr_arg; if FPU32, fp_index += 16
1264 LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loopS # f16_f17 = curr_arg; if FPU32, fp_index += 16
1265 LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loopS # f18_f19 = curr_arg; if FPU32, fp_index += 16
1266 LOAD_END t7, 6*16, loopS # no more FPR args, fp_index = 6*16
Goran Jakovljevicff734982015-08-24 12:58:55 +00001267END art_quick_invoke_static_stub
1268
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001269#undef SPILL_SIZE
1270
Goran Jakovljevicff734982015-08-24 12:58:55 +00001271 /*
buzbee5bc5a7b2012-03-07 15:52:59 -08001272 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
1273 * failure.
1274 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08001275 .extern artHandleFillArrayDataFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07001276ENTRY art_quick_handle_fill_data
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001277 lw $a2, 0($sp) # pass referrer's Method*
1278 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case exception allocation triggers GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001279 la $t9, artHandleFillArrayDataFromCode
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001280 jalr $t9 # (payload offset, Array*, method, Thread*)
1281 move $a3, rSELF # pass Thread::Current
jeffhaofc6a30e2012-10-18 18:24:15 -07001282 RETURN_IF_ZERO
Ian Rogers468532e2013-08-05 10:56:33 -07001283END art_quick_handle_fill_data
buzbee5bc5a7b2012-03-07 15:52:59 -08001284
buzbee5bc5a7b2012-03-07 15:52:59 -08001285 /*
Ian Rogers57b86d42012-03-27 16:05:41 -07001286 * Entry from managed code that calls artLockObjectFromCode, may block for GC.
buzbee5bc5a7b2012-03-07 15:52:59 -08001287 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08001288 .extern artLockObjectFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07001289ENTRY art_quick_lock_object
Vladimir Marko804b03f2016-09-14 16:26:36 +01001290 beqz $a0, art_quick_throw_null_pointer_exception
Alexey Frunzead63fe52017-05-08 22:10:00 -07001291 li $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
1292 li $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
1293.Lretry_lock:
1294 lw $t0, THREAD_ID_OFFSET(rSELF) # TODO: Can the thread ID really change during the loop?
1295 ll $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1296 and $t2, $t1, $t3 # zero the gc bits
1297 bnez $t2, .Lnot_unlocked # already thin locked
1298 # Unlocked case - $t1: original lock word that's zero except for the read barrier bits.
1299 or $t2, $t1, $t0 # $t2 holds thread id with count of 0 with preserved read barrier bits
1300 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1301 beqz $t2, .Lretry_lock # store failed, retry
Ian Rogersa9a82542013-10-04 11:17:26 -07001302 nop
Alexey Frunzead63fe52017-05-08 22:10:00 -07001303 jalr $zero, $ra
1304 sync # full (LoadLoad|LoadStore) memory barrier
1305.Lnot_unlocked:
1306 # $t1: original lock word, $t0: thread_id with count of 0 and zero read barrier bits
1307 srl $t2, $t1, LOCK_WORD_STATE_SHIFT
1308 bnez $t2, .Lslow_lock # if either of the top two bits are set, go slow path
1309 xor $t2, $t1, $t0 # lock_word.ThreadId() ^ self->ThreadId()
1310 andi $t2, $t2, 0xFFFF # zero top 16 bits
1311 bnez $t2, .Lslow_lock # lock word and self thread id's match -> recursive lock
1312 # otherwise contention, go to slow path
1313 and $t2, $t1, $t3 # zero the gc bits
1314 addu $t2, $t2, $t8 # increment count in lock word
1315 srl $t2, $t2, LOCK_WORD_STATE_SHIFT # if the first gc state bit is set, we overflowed.
1316 bnez $t2, .Lslow_lock # if we overflow the count go slow path
1317 addu $t2, $t1, $t8 # increment count for real
1318 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1319 beqz $t2, .Lretry_lock # store failed, retry
1320 nop
1321 jalr $zero, $ra
1322 nop
1323.Lslow_lock:
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001324 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case we block
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001325 la $t9, artLockObjectFromCode
1326 jalr $t9 # (Object* obj, Thread*)
jeffhao7fbee072012-08-24 17:56:54 -07001327 move $a1, rSELF # pass Thread::Current
Ian Rogers6bcd1632013-10-08 18:50:47 -07001328 RETURN_IF_ZERO
Ian Rogers468532e2013-08-05 10:56:33 -07001329END art_quick_lock_object
buzbee5bc5a7b2012-03-07 15:52:59 -08001330
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001331ENTRY art_quick_lock_object_no_inline
Vladimir Marko804b03f2016-09-14 16:26:36 +01001332 beqz $a0, art_quick_throw_null_pointer_exception
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001333 nop
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001334 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case we block
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001335 la $t9, artLockObjectFromCode
1336 jalr $t9 # (Object* obj, Thread*)
1337 move $a1, rSELF # pass Thread::Current
1338 RETURN_IF_ZERO
1339END art_quick_lock_object_no_inline
1340
buzbee5bc5a7b2012-03-07 15:52:59 -08001341 /*
1342 * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
1343 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08001344 .extern artUnlockObjectFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07001345ENTRY art_quick_unlock_object
Vladimir Marko804b03f2016-09-14 16:26:36 +01001346 beqz $a0, art_quick_throw_null_pointer_exception
Alexey Frunzead63fe52017-05-08 22:10:00 -07001347 li $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
1348 li $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
1349.Lretry_unlock:
1350#ifndef USE_READ_BARRIER
1351 lw $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1352#else
1353 ll $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0) # Need to use atomic read-modify-write for read barrier
1354#endif
1355 srl $t2, $t1, LOCK_WORD_STATE_SHIFT
1356 bnez $t2, .Lslow_unlock # if either of the top two bits are set, go slow path
1357 lw $t0, THREAD_ID_OFFSET(rSELF)
1358 and $t2, $t1, $t3 # zero the gc bits
1359 xor $t2, $t2, $t0 # lock_word.ThreadId() ^ self->ThreadId()
1360 andi $t2, $t2, 0xFFFF # zero top 16 bits
1361 bnez $t2, .Lslow_unlock # do lock word and self thread id's match?
1362 and $t2, $t1, $t3 # zero the gc bits
1363 bgeu $t2, $t8, .Lrecursive_thin_unlock
1364 # transition to unlocked
1365 nor $t2, $zero, $t3 # $t2 = LOCK_WORD_GC_STATE_MASK_SHIFTED
1366 and $t2, $t1, $t2 # $t2: zero except for the preserved gc bits
1367 sync # full (LoadStore|StoreStore) memory barrier
1368#ifndef USE_READ_BARRIER
1369 jalr $zero, $ra
1370 sw $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1371#else
1372 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1373 beqz $t2, .Lretry_unlock # store failed, retry
Ian Rogersa9a82542013-10-04 11:17:26 -07001374 nop
Alexey Frunzead63fe52017-05-08 22:10:00 -07001375 jalr $zero, $ra
1376 nop
1377#endif
1378.Lrecursive_thin_unlock:
1379 # t1: original lock word
1380 subu $t2, $t1, $t8 # decrement count
1381#ifndef USE_READ_BARRIER
1382 jalr $zero, $ra
1383 sw $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1384#else
1385 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1386 beqz $t2, .Lretry_unlock # store failed, retry
1387 nop
1388 jalr $zero, $ra
1389 nop
1390#endif
1391.Lslow_unlock:
1392 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case exception allocation triggers GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001393 la $t9, artUnlockObjectFromCode
Alexey Frunzead63fe52017-05-08 22:10:00 -07001394 jalr $t9 # (Object* obj, Thread*)
1395 move $a1, rSELF # pass Thread::Current
buzbee5bc5a7b2012-03-07 15:52:59 -08001396 RETURN_IF_ZERO
Ian Rogers468532e2013-08-05 10:56:33 -07001397END art_quick_unlock_object
buzbee5bc5a7b2012-03-07 15:52:59 -08001398
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001399ENTRY art_quick_unlock_object_no_inline
Vladimir Marko804b03f2016-09-14 16:26:36 +01001400 beqz $a0, art_quick_throw_null_pointer_exception
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001401 nop
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001402 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case exception allocation triggers GC
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001403 la $t9, artUnlockObjectFromCode
1404 jalr $t9 # (Object* obj, Thread*)
1405 move $a1, rSELF # pass Thread::Current
1406 RETURN_IF_ZERO
1407END art_quick_unlock_object_no_inline
1408
buzbee5bc5a7b2012-03-07 15:52:59 -08001409 /*
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001410 * Entry from managed code that calls artInstanceOfFromCode and delivers exception on failure.
buzbee5bc5a7b2012-03-07 15:52:59 -08001411 */
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001412 .extern artInstanceOfFromCode
1413 .extern artThrowClassCastExceptionForObject
1414ENTRY art_quick_check_instance_of
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001415 addiu $sp, $sp, -32
1416 .cfi_adjust_cfa_offset 32
1417 sw $gp, 16($sp)
Ian Rogersa9a82542013-10-04 11:17:26 -07001418 sw $ra, 12($sp)
1419 .cfi_rel_offset 31, 12
1420 sw $t9, 8($sp)
1421 sw $a1, 4($sp)
1422 sw $a0, 0($sp)
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001423 la $t9, artInstanceOfFromCode
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001424 jalr $t9
Douglas Leung735b8552014-10-31 12:21:40 -07001425 addiu $sp, $sp, -16 # reserve argument slots on the stack
1426 addiu $sp, $sp, 16
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001427 lw $gp, 16($sp)
Ian Rogers86bcdc22014-02-21 22:06:38 -08001428 beqz $v0, .Lthrow_class_cast_exception
Ian Rogersa9a82542013-10-04 11:17:26 -07001429 lw $ra, 12($sp)
Andreas Gampe8d365912015-01-13 11:32:32 -08001430 jalr $zero, $ra
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001431 addiu $sp, $sp, 32
1432 .cfi_adjust_cfa_offset -32
Ian Rogers86bcdc22014-02-21 22:06:38 -08001433.Lthrow_class_cast_exception:
Ian Rogersa9a82542013-10-04 11:17:26 -07001434 lw $t9, 8($sp)
1435 lw $a1, 4($sp)
1436 lw $a0, 0($sp)
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001437 addiu $sp, $sp, 32
1438 .cfi_adjust_cfa_offset -32
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001439 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001440 la $t9, artThrowClassCastExceptionForObject
1441 jalr $zero, $t9 # artThrowClassCastException (Object*, Class*, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001442 move $a2, rSELF # pass Thread::Current
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001443END art_quick_check_instance_of
buzbee5bc5a7b2012-03-07 15:52:59 -08001444
buzbee5bc5a7b2012-03-07 15:52:59 -08001445 /*
Man Cao1aee9002015-07-14 22:31:42 -07001446 * Restore rReg's value from offset($sp) if rReg is not the same as rExclude.
1447 * nReg is the register number for rReg.
1448 */
1449.macro POP_REG_NE rReg, nReg, offset, rExclude
1450 .ifnc \rReg, \rExclude
1451 lw \rReg, \offset($sp) # restore rReg
1452 .cfi_restore \nReg
1453 .endif
1454.endm
1455
1456 /*
1457 * Macro to insert read barrier, only used in art_quick_aput_obj.
1458 * rObj and rDest are registers, offset is a defined literal such as MIRROR_OBJECT_CLASS_OFFSET.
1459 * TODO: When read barrier has a fast path, add heap unpoisoning support for the fast path.
1460 */
1461.macro READ_BARRIER rDest, rObj, offset
1462#ifdef USE_READ_BARRIER
1463 # saved registers used in art_quick_aput_obj: a0-a2, t0-t1, t9, ra. 8 words for 16B alignment.
1464 addiu $sp, $sp, -32
1465 .cfi_adjust_cfa_offset 32
1466 sw $ra, 28($sp)
1467 .cfi_rel_offset 31, 28
1468 sw $t9, 24($sp)
1469 .cfi_rel_offset 25, 24
1470 sw $t1, 20($sp)
1471 .cfi_rel_offset 9, 20
1472 sw $t0, 16($sp)
1473 .cfi_rel_offset 8, 16
1474 sw $a2, 8($sp) # padding slot at offset 12 (padding can be any slot in the 32B)
1475 .cfi_rel_offset 6, 8
1476 sw $a1, 4($sp)
1477 .cfi_rel_offset 5, 4
1478 sw $a0, 0($sp)
1479 .cfi_rel_offset 4, 0
1480
Man Cao63069212015-08-21 15:51:39 -07001481 # move $a0, \rRef # pass ref in a0 (no-op for now since parameter ref is unused)
Man Cao1aee9002015-07-14 22:31:42 -07001482 .ifnc \rObj, $a1
1483 move $a1, \rObj # pass rObj
1484 .endif
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001485 addiu $a2, $zero, \offset # pass offset
1486 la $t9, artReadBarrierSlow
1487 jalr $t9 # artReadBarrierSlow(ref, rObj, offset)
Man Cao1aee9002015-07-14 22:31:42 -07001488 addiu $sp, $sp, -16 # Use branch delay slot to reserve argument slots on the stack
1489 # before the call to artReadBarrierSlow.
1490 addiu $sp, $sp, 16 # restore stack after call to artReadBarrierSlow
1491 # No need to unpoison return value in v0, artReadBarrierSlow() would do the unpoisoning.
1492 move \rDest, $v0 # save return value in rDest
1493 # (rDest cannot be v0 in art_quick_aput_obj)
1494
1495 lw $a0, 0($sp) # restore registers except rDest
1496 # (rDest can only be t0 or t1 in art_quick_aput_obj)
1497 .cfi_restore 4
1498 lw $a1, 4($sp)
1499 .cfi_restore 5
1500 lw $a2, 8($sp)
1501 .cfi_restore 6
1502 POP_REG_NE $t0, 8, 16, \rDest
1503 POP_REG_NE $t1, 9, 20, \rDest
1504 lw $t9, 24($sp)
1505 .cfi_restore 25
1506 lw $ra, 28($sp) # restore $ra
1507 .cfi_restore 31
1508 addiu $sp, $sp, 32
1509 .cfi_adjust_cfa_offset -32
1510#else
1511 lw \rDest, \offset(\rObj)
1512 UNPOISON_HEAP_REF \rDest
1513#endif // USE_READ_BARRIER
1514.endm
1515
Man Cao1aee9002015-07-14 22:31:42 -07001516#ifdef USE_READ_BARRIER
1517 .extern artReadBarrierSlow
1518#endif
Ian Rogersa9a82542013-10-04 11:17:26 -07001519ENTRY art_quick_aput_obj
Ian Rogers86bcdc22014-02-21 22:06:38 -08001520 beqz $a2, .Ldo_aput_null
Ian Rogersa9a82542013-10-04 11:17:26 -07001521 nop
Man Cao1aee9002015-07-14 22:31:42 -07001522 READ_BARRIER $t0, $a0, MIRROR_OBJECT_CLASS_OFFSET
1523 READ_BARRIER $t1, $a2, MIRROR_OBJECT_CLASS_OFFSET
1524 READ_BARRIER $t0, $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET
Ian Rogers86bcdc22014-02-21 22:06:38 -08001525 bne $t1, $t0, .Lcheck_assignability # value's type == array's component type - trivial assignability
Ian Rogersa9a82542013-10-04 11:17:26 -07001526 nop
Ian Rogers86bcdc22014-02-21 22:06:38 -08001527.Ldo_aput:
Ian Rogersa9a82542013-10-04 11:17:26 -07001528 sll $a1, $a1, 2
1529 add $t0, $a0, $a1
Hiroshi Yamauchibfa5eb62015-05-29 15:04:41 -07001530 POISON_HEAP_REF $a2
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001531 sw $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
Ian Rogersa9a82542013-10-04 11:17:26 -07001532 lw $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
Mathieu Chartierafdcbcb2017-04-26 16:43:35 -07001533 srl $t1, $a0, CARD_TABLE_CARD_SHIFT
Ian Rogersa9a82542013-10-04 11:17:26 -07001534 add $t1, $t1, $t0
1535 sb $t0, ($t1)
Andreas Gampe8d365912015-01-13 11:32:32 -08001536 jalr $zero, $ra
Ian Rogersa9a82542013-10-04 11:17:26 -07001537 nop
Ian Rogers86bcdc22014-02-21 22:06:38 -08001538.Ldo_aput_null:
Ian Rogersa9a82542013-10-04 11:17:26 -07001539 sll $a1, $a1, 2
1540 add $t0, $a0, $a1
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001541 sw $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
Andreas Gampe8d365912015-01-13 11:32:32 -08001542 jalr $zero, $ra
Ian Rogersa9a82542013-10-04 11:17:26 -07001543 nop
Ian Rogers86bcdc22014-02-21 22:06:38 -08001544.Lcheck_assignability:
Ian Rogersa9a82542013-10-04 11:17:26 -07001545 addiu $sp, $sp, -32
1546 .cfi_adjust_cfa_offset 32
1547 sw $ra, 28($sp)
1548 .cfi_rel_offset 31, 28
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001549 sw $gp, 16($sp)
Ian Rogersa9a82542013-10-04 11:17:26 -07001550 sw $t9, 12($sp)
1551 sw $a2, 8($sp)
1552 sw $a1, 4($sp)
1553 sw $a0, 0($sp)
1554 move $a1, $t1
1555 move $a0, $t0
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001556 la $t9, artIsAssignableFromCode
1557 jalr $t9 # (Class*, Class*)
1558 addiu $sp, $sp, -16 # reserve argument slots on the stack
1559 addiu $sp, $sp, 16
Ian Rogersa9a82542013-10-04 11:17:26 -07001560 lw $ra, 28($sp)
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001561 lw $gp, 16($sp)
Ian Rogersa9a82542013-10-04 11:17:26 -07001562 lw $t9, 12($sp)
1563 lw $a2, 8($sp)
1564 lw $a1, 4($sp)
1565 lw $a0, 0($sp)
Duane Sande34652f2014-11-04 11:09:36 -08001566 addiu $sp, 32
Ian Rogersa9a82542013-10-04 11:17:26 -07001567 .cfi_adjust_cfa_offset -32
Ian Rogers86bcdc22014-02-21 22:06:38 -08001568 bnez $v0, .Ldo_aput
Ian Rogersa9a82542013-10-04 11:17:26 -07001569 nop
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001570 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
Ian Rogersa9a82542013-10-04 11:17:26 -07001571 move $a1, $a2
Ian Rogersa9a82542013-10-04 11:17:26 -07001572 la $t9, artThrowArrayStoreException
Andreas Gampe8d365912015-01-13 11:32:32 -08001573 jalr $zero, $t9 # artThrowArrayStoreException(Class*, Class*, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001574 move $a2, rSELF # pass Thread::Current
Ian Rogersa9a82542013-10-04 11:17:26 -07001575END art_quick_aput_obj
buzbee5bc5a7b2012-03-07 15:52:59 -08001576
Alexey Frunze0cb12422017-01-25 19:30:18 -08001577// Macros taking opportunity of code similarities for downcalls.
1578.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return
1579 .extern \entrypoint
1580ENTRY \name
1581 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1582 la $t9, \entrypoint
1583 jalr $t9 # (field_idx, Thread*)
1584 move $a1, rSELF # pass Thread::Current
1585 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1586END \name
1587.endm
1588
1589.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return
1590 .extern \entrypoint
1591ENTRY \name
1592 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1593 la $t9, \entrypoint
1594 jalr $t9 # (field_idx, Object*, Thread*) or
1595 # (field_idx, new_val, Thread*)
1596 move $a2, rSELF # pass Thread::Current
1597 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1598END \name
1599.endm
1600
1601.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
1602 .extern \entrypoint
1603ENTRY \name
1604 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1605 la $t9, \entrypoint
1606 jalr $t9 # (field_idx, Object*, new_val, Thread*)
1607 move $a3, rSELF # pass Thread::Current
1608 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1609END \name
1610.endm
1611
1612.macro FOUR_ARG_REF_DOWNCALL name, entrypoint, return
1613 .extern \entrypoint
1614ENTRY \name
1615 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1616 la $t9, \entrypoint
1617 jalr $t9 # (field_idx, Object*, 64-bit new_val, Thread*) or
1618 # (field_idx, 64-bit new_val, Thread*)
1619 # Note that a 64-bit new_val needs to be aligned with
1620 # an even-numbered register, hence A1 may be skipped
1621 # for new_val to reside in A2-A3.
1622 sw rSELF, 16($sp) # pass Thread::Current
1623 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1624END \name
1625.endm
Fred Shih37f05ef2014-07-16 18:38:08 -07001626
1627 /*
Alexey Frunze0cb12422017-01-25 19:30:18 -08001628 * Called by managed code to resolve a static/instance field and load/store a value.
Fred Shih37f05ef2014-07-16 18:38:08 -07001629 */
Alexey Frunze0cb12422017-01-25 19:30:18 -08001630ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1631ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1632ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1633ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1634ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1635ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1636ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1637TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1638TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1639TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1640TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1641TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1642TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1643TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1644TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCompiledCode, RETURN_IF_ZERO
1645TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCompiledCode, RETURN_IF_ZERO
1646TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCompiledCode, RETURN_IF_ZERO
1647TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCompiledCode, RETURN_IF_ZERO
1648FOUR_ARG_REF_DOWNCALL art_quick_set64_static, artSet64StaticFromCompiledCode, RETURN_IF_ZERO
1649THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCompiledCode, RETURN_IF_ZERO
1650THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCompiledCode, RETURN_IF_ZERO
1651THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCompiledCode, RETURN_IF_ZERO
1652THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCompiledCode, RETURN_IF_ZERO
1653FOUR_ARG_REF_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCompiledCode, RETURN_IF_ZERO
buzbee5bc5a7b2012-03-07 15:52:59 -08001654
Vladimir Markoa3c38272015-04-28 12:37:09 +01001655// Macro to facilitate adding new allocation entrypoints.
Vladimir Marko5ea536a2015-04-20 20:11:30 +01001656.macro ONE_ARG_DOWNCALL name, entrypoint, return
1657 .extern \entrypoint
1658ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001659 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001660 la $t9, \entrypoint
1661 jalr $t9
Vladimir Marko5ea536a2015-04-20 20:11:30 +01001662 move $a1, rSELF # pass Thread::Current
1663 \return
1664END \name
1665.endm
1666
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001667.macro TWO_ARG_DOWNCALL name, entrypoint, return
1668 .extern \entrypoint
1669ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001670 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001671 la $t9, \entrypoint
1672 jalr $t9
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001673 move $a2, rSELF # pass Thread::Current
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001674 \return
1675END \name
1676.endm
buzbee5bc5a7b2012-03-07 15:52:59 -08001677
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001678.macro THREE_ARG_DOWNCALL name, entrypoint, return
1679 .extern \entrypoint
1680ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001681 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001682 la $t9, \entrypoint
1683 jalr $t9
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001684 move $a3, rSELF # pass Thread::Current
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001685 \return
1686END \name
1687.endm
buzbee5bc5a7b2012-03-07 15:52:59 -08001688
Jeff Hao848f70a2014-01-15 13:49:50 -08001689.macro FOUR_ARG_DOWNCALL name, entrypoint, return
1690 .extern \entrypoint
1691ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001692 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001693 la $t9, \entrypoint
1694 jalr $t9
Vladimir Markoa3c38272015-04-28 12:37:09 +01001695 sw rSELF, 16($sp) # pass Thread::Current
Jeff Hao848f70a2014-01-15 13:49:50 -08001696 \return
1697END \name
1698.endm
1699
Mathieu Chartier7410f292013-11-24 13:17:35 -08001700// Generate the allocation entrypoints for each allocator.
Goran Jakovljevic854df412017-06-27 14:41:39 +02001701GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
1702// Comment out allocators that have mips specific asm.
1703// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
1704// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
1705GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
1706// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
1707// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab, RegionTLAB)
1708// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab, RegionTLAB)
1709// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab, RegionTLAB)
1710// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab, RegionTLAB)
1711GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
1712GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
1713GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
1714
1715// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
1716// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
1717GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
1718// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
1719// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_tlab, TLAB)
1720// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_tlab, TLAB)
1721// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_tlab, TLAB)
1722// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_tlab, TLAB)
1723GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
1724GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
1725GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
Hiroshi Yamauchi10d4c082016-02-24 12:51:18 -08001726
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001727// A hand-written override for:
1728// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
1729// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
Goran Jakovljevic854df412017-06-27 14:41:39 +02001730.macro ART_QUICK_ALLOC_OBJECT_ROSALLOC c_name, cxx_name, isInitialized
1731ENTRY_NO_GP \c_name
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001732 # Fast path rosalloc allocation
1733 # a0: type
1734 # s1: Thread::Current
1735 # -----------------------------
1736 # t1: object size
1737 # t2: rosalloc run
1738 # t3: thread stack top offset
1739 # t4: thread stack bottom offset
1740 # v0: free list head
1741 #
1742 # t5, t6 : temps
1743 lw $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1) # Check if thread local allocation
1744 lw $t4, THREAD_LOCAL_ALLOC_STACK_END_OFFSET($s1) # stack has any room left.
1745 bgeu $t3, $t4, .Lslow_path_\c_name
Pavle Batuta712c59d2015-12-02 18:39:01 +01001746
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001747 lw $t1, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0) # Load object size (t1).
1748 li $t5, ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE # Check if size is for a thread local
1749 # allocation. Also does the
1750 # initialized and finalizable checks.
Goran Jakovljevic854df412017-06-27 14:41:39 +02001751 # When isInitialized == 0, then the class is potentially not yet initialized.
1752 # If the class is not yet initialized, the object size will be very large to force the branch
1753 # below to be taken.
1754 #
1755 # See InitializeClassVisitors in class-inl.h for more details.
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001756 bgtu $t1, $t5, .Lslow_path_\c_name
1757
1758 # Compute the rosalloc bracket index from the size. Since the size is already aligned we can
1759 # combine the two shifts together.
1760 srl $t1, $t1, (ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT - POINTER_SIZE_SHIFT)
1761
1762 addu $t2, $t1, $s1
1763 lw $t2, (THREAD_ROSALLOC_RUNS_OFFSET - __SIZEOF_POINTER__)($t2) # Load rosalloc run (t2).
1764
1765 # Load the free list head (v0).
1766 # NOTE: this will be the return val.
1767 lw $v0, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
1768 beqz $v0, .Lslow_path_\c_name
1769 nop
1770
1771 # Load the next pointer of the head and update the list head with the next pointer.
1772 lw $t5, ROSALLOC_SLOT_NEXT_OFFSET($v0)
1773 sw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
1774
1775 # Store the class pointer in the header. This also overwrites the first pointer. The offsets are
1776 # asserted to match.
1777
1778#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
1779#error "Class pointer needs to overwrite next pointer."
1780#endif
1781
1782 POISON_HEAP_REF $a0
1783 sw $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)
1784
1785 # Push the new object onto the thread local allocation stack and increment the thread local
1786 # allocation stack top.
1787 sw $v0, 0($t3)
1788 addiu $t3, $t3, COMPRESSED_REFERENCE_SIZE
1789 sw $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)
1790
1791 # Decrement the size of the free list.
1792 lw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
1793 addiu $t5, $t5, -1
1794 sw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
1795
Goran Jakovljevic854df412017-06-27 14:41:39 +02001796.if \isInitialized == 0
1797 # This barrier is only necessary when the allocation also requires a class initialization check.
1798 #
1799 # If the class is already observably initialized, then new-instance allocations are protected
1800 # from publishing by the compiler which inserts its own StoreStore barrier.
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001801 sync # Fence.
Goran Jakovljevic854df412017-06-27 14:41:39 +02001802.endif
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001803 jalr $zero, $ra
1804 nop
1805
1806 .Lslow_path_\c_name:
Goran Jakovljevic854df412017-06-27 14:41:39 +02001807 addiu $t9, $t9, (.Lslow_path_\c_name - \c_name) + 4
1808 .cpload $t9
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001809 SETUP_SAVE_REFS_ONLY_FRAME
1810 la $t9, \cxx_name
1811 jalr $t9
1812 move $a1, $s1 # Pass self as argument.
1813 RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1814END \c_name
1815.endm
1816
Goran Jakovljevic854df412017-06-27 14:41:39 +02001817ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_resolved_rosalloc, artAllocObjectFromCodeResolvedRosAlloc, /* isInitialized */ 0
1818ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, artAllocObjectFromCodeInitializedRosAlloc, /* isInitialized */ 1
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001819
Goran Jakovljevic854df412017-06-27 14:41:39 +02001820// The common fast path code for art_quick_alloc_object_resolved/initialized_tlab
1821// and art_quick_alloc_object_resolved/initialized_region_tlab.
1822//
1823// a0: type, s1(rSELF): Thread::Current.
1824// Need to preserve a0 to the slow path.
1825//
1826// If isInitialized=1 then the compiler assumes the object's class has already been initialized.
1827// If isInitialized=0 the compiler can only assume it's been at least resolved.
1828.macro ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH slowPathLabel isInitialized
1829 lw $v0, THREAD_LOCAL_POS_OFFSET(rSELF) # Load thread_local_pos.
1830 lw $a2, THREAD_LOCAL_END_OFFSET(rSELF) # Load thread_local_end.
1831 subu $a3, $a2, $v0 # Compute the remaining buffer size.
1832 lw $t0, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0) # Load the object size.
1833
1834 # When isInitialized == 0, then the class is potentially not yet initialized.
1835 # If the class is not yet initialized, the object size will be very large to force the branch
1836 # below to be taken.
1837 #
1838 # See InitializeClassVisitors in class-inl.h for more details.
1839 bgtu $t0, $a3, \slowPathLabel # Check if it fits.
1840 addu $t1, $v0, $t0 # Add object size to tlab pos (in branch
1841 # delay slot).
1842 # "Point of no slow path". Won't go to the slow path from here on.
1843 sw $t1, THREAD_LOCAL_POS_OFFSET(rSELF) # Store new thread_local_pos.
1844 lw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF) # Increment thread_local_objects.
1845 addiu $a2, $a2, 1
1846 sw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
1847 POISON_HEAP_REF $a0
1848 sw $a0, MIRROR_OBJECT_CLASS_OFFSET($v0) # Store the class pointer.
1849
1850.if \isInitialized == 0
1851 # This barrier is only necessary when the allocation also requires a class initialization check.
1852 #
1853 # If the class is already observably initialized, then new-instance allocations are protected
1854 # from publishing by the compiler which inserts its own StoreStore barrier.
1855 sync # Fence.
1856.endif
1857 jalr $zero, $ra
1858 nop
1859.endm
1860
1861// The common code for art_quick_alloc_object_resolved/initialized_tlab
1862// and art_quick_alloc_object_resolved/initialized_region_tlab.
1863.macro GENERATE_ALLOC_OBJECT_TLAB name, entrypoint, isInitialized
1864ENTRY_NO_GP \name
1865 # Fast path tlab allocation.
1866 # a0: type, s1(rSELF): Thread::Current.
1867 ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lslow_path_\name, \isInitialized
1868.Lslow_path_\name:
1869 addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
1870 .cpload $t9
1871 SETUP_SAVE_REFS_ONLY_FRAME # Save callee saves in case of GC.
1872 la $t9, \entrypoint
1873 jalr $t9 # (mirror::Class*, Thread*)
1874 move $a1, rSELF # Pass Thread::Current.
1875 RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1876END \name
1877.endm
1878
1879GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_region_tlab, artAllocObjectFromCodeResolvedRegionTLAB, /* isInitialized */ 0
1880GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_region_tlab, artAllocObjectFromCodeInitializedRegionTLAB, /* isInitialized */ 1
1881GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_tlab, artAllocObjectFromCodeResolvedTLAB, /* isInitialized */ 0
1882GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_tlab, artAllocObjectFromCodeInitializedTLAB, /* isInitialized */ 1
1883
1884// The common fast path code for art_quick_alloc_array_resolved/initialized_tlab
1885// and art_quick_alloc_array_resolved/initialized_region_tlab.
1886//
1887// a0: type, a1: component_count, a2: total_size, s1(rSELF): Thread::Current.
1888// Need to preserve a0 and a1 to the slow path.
1889.macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE slowPathLabel
1890 li $a3, OBJECT_ALIGNMENT_MASK_TOGGLED # Apply alignemnt mask
1891 and $a2, $a2, $a3 # (addr + 7) & ~7.
1892
1893 lw $v0, THREAD_LOCAL_POS_OFFSET(rSELF) # Load thread_local_pos.
1894 lw $t1, THREAD_LOCAL_END_OFFSET(rSELF) # Load thread_local_end.
1895 subu $t2, $t1, $v0 # Compute the remaining buffer size.
1896 bgtu $a2, $t2, \slowPathLabel # Check if it fits.
1897 addu $a2, $v0, $a2 # Add object size to tlab pos (in branch
1898 # delay slot).
1899
1900 # "Point of no slow path". Won't go to the slow path from here on.
1901 sw $a2, THREAD_LOCAL_POS_OFFSET(rSELF) # Store new thread_local_pos.
1902 lw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF) # Increment thread_local_objects.
1903 addiu $a2, $a2, 1
1904 sw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
1905 POISON_HEAP_REF $a0
1906 sw $a0, MIRROR_OBJECT_CLASS_OFFSET($v0) # Store the class pointer.
1907 jalr $zero, $ra
1908 sw $a1, MIRROR_ARRAY_LENGTH_OFFSET($v0) # Store the array length.
1909.endm
1910
1911.macro GENERATE_ALLOC_ARRAY_TLAB name, entrypoint, size_setup
1912ENTRY_NO_GP \name
1913 # Fast path array allocation for region tlab allocation.
1914 # a0: mirror::Class* type
1915 # a1: int32_t component_count
1916 # s1(rSELF): Thread::Current
1917 \size_setup .Lslow_path_\name
1918 ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE .Lslow_path_\name
1919.Lslow_path_\name:
1920 # a0: mirror::Class* type
1921 # a1: int32_t component_count
1922 # a2: Thread* self
1923 addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
1924 .cpload $t9
1925 SETUP_SAVE_REFS_ONLY_FRAME # Save callee saves in case of GC.
1926 la $t9, \entrypoint
1927 jalr $t9
1928 move $a2, rSELF # Pass Thread::Current.
1929 RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1930END \name
1931.endm
1932
1933.macro COMPUTE_ARRAY_SIZE_UNKNOWN slow_path
1934 break # We should never enter here.
1935 # Code below is for reference.
1936 # Possibly a large object, go slow.
1937 # Also does negative array size check.
1938 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_WIDE_ARRAY_DATA_OFFSET) / 8)
1939 bgtu $a1, $a2, \slow_path
1940 # Array classes are never finalizable
1941 # or uninitialized, no need to check.
1942 lw $a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($a0) # Load component type.
1943 UNPOISON_HEAP_REF $a3
1944 lw $a3, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET($a3)
1945 srl $a3, $a3, PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT # Component size shift is in high 16 bits.
1946 sllv $a2, $a1, $a3 # Calculate data size.
1947 # Add array data offset and alignment.
1948 addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1949#if MIRROR_WIDE_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
1950#error Long array data offset must be 4 greater than int array data offset.
1951#endif
1952
1953 addiu $a3, $a3, 1 # Add 4 to the length only if the component
1954 andi $a3, $a3, 4 # size shift is 3 (for 64 bit alignment).
1955 addu $a2, $a2, $a3
1956.endm
1957
1958.macro COMPUTE_ARRAY_SIZE_8 slow_path
1959 # Possibly a large object, go slow.
1960 # Also does negative array size check.
1961 li $a2, (MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET)
1962 bgtu $a1, $a2, \slow_path
1963 # Add array data offset and alignment (in branch delay slot).
1964 addiu $a2, $a1, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1965.endm
1966
1967.macro COMPUTE_ARRAY_SIZE_16 slow_path
1968 # Possibly a large object, go slow.
1969 # Also does negative array size check.
1970 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 2)
1971 bgtu $a1, $a2, \slow_path
1972 sll $a2, $a1, 1
1973 # Add array data offset and alignment.
1974 addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1975.endm
1976
1977.macro COMPUTE_ARRAY_SIZE_32 slow_path
1978 # Possibly a large object, go slow.
1979 # Also does negative array size check.
1980 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 4)
1981 bgtu $a1, $a2, \slow_path
1982 sll $a2, $a1, 2
1983 # Add array data offset and alignment.
1984 addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1985.endm
1986
1987.macro COMPUTE_ARRAY_SIZE_64 slow_path
1988 # Possibly a large object, go slow.
1989 # Also does negative array size check.
1990 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_LONG_ARRAY_DATA_OFFSET) / 8)
1991 bgtu $a1, $a2, \slow_path
1992 sll $a2, $a1, 3
1993 # Add array data offset and alignment.
1994 addiu $a2, $a2, (MIRROR_WIDE_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1995.endm
1996
1997GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
1998GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_8
1999GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_16
2000GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_32
2001GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_64
2002
2003GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
2004GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_8
2005GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_16
2006GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
2007GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
Hiroshi Yamauchi10d4c082016-02-24 12:51:18 -08002008
Alexey Frunzec61c0762017-04-10 13:54:23 -07002009// Macro for string and type resolution and initialization.
2010// $a0 is both input and output.
Alexey Frunze19428ad2017-08-03 10:36:46 -07002011.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
Alexey Frunzec61c0762017-04-10 13:54:23 -07002012 .extern \entrypoint
2013ENTRY_NO_GP \name
Alexey Frunze19428ad2017-08-03 10:36:46 -07002014 SETUP_SAVE_EVERYTHING_FRAME \runtime_method_offset # Save everything in case of GC.
Alexey Frunzec61c0762017-04-10 13:54:23 -07002015 move $s2, $gp # Preserve $gp across the call for exception delivery.
2016 la $t9, \entrypoint
2017 jalr $t9 # (uint32_t index, Thread*)
2018 move $a1, rSELF # Pass Thread::Current (in delay slot).
2019 beqz $v0, 1f # Success?
2020 move $a0, $v0 # Move result to $a0 (in delay slot).
2021 RESTORE_SAVE_EVERYTHING_FRAME 0 # Restore everything except $a0.
2022 jalr $zero, $ra # Return on success.
2023 nop
20241:
2025 move $gp, $s2
2026 DELIVER_PENDING_EXCEPTION_FRAME_READY
2027END \name
2028.endm
2029
Alexey Frunze19428ad2017-08-03 10:36:46 -07002030.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT name, entrypoint
2031 ONE_ARG_SAVE_EVERYTHING_DOWNCALL \name, \entrypoint, RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET
2032.endm
2033
buzbee5bc5a7b2012-03-07 15:52:59 -08002034 /*
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002035 * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
Vladimir Marko5ea536a2015-04-20 20:11:30 +01002036 * exception on error. On success the String is returned. A0 holds the string index. The fast
2037 * path check for hit in strings cache has already been performed.
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002038 */
Alexey Frunzec61c0762017-04-10 13:54:23 -07002039ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002040
2041 /*
2042 * Entry from managed code when uninitialized static storage, this stub will run the class
2043 * initializer and deliver the exception on error. On success the static storage base is
2044 * returned.
2045 */
Alexey Frunze19428ad2017-08-03 10:36:46 -07002046ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002047
2048 /*
2049 * Entry from managed code when dex cache misses for a type_idx.
2050 */
Alexey Frunze19428ad2017-08-03 10:36:46 -07002051ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002052
2053 /*
2054 * Entry from managed code when type_idx needs to be checked for access and dex cache may also
2055 * miss.
2056 */
Alexey Frunzec61c0762017-04-10 13:54:23 -07002057ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002058
2059 /*
Ian Rogers57b86d42012-03-27 16:05:41 -07002060 * Called by managed code when the value in rSUSPEND has been decremented to 0.
buzbee5bc5a7b2012-03-07 15:52:59 -08002061 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002062 .extern artTestSuspendFromCode
Vladimir Marko952dbb12016-07-28 12:01:51 +01002063ENTRY_NO_GP art_quick_test_suspend
2064 lh rSUSPEND, THREAD_FLAGS_OFFSET(rSELF)
2065 bnez rSUSPEND, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002066 addiu rSUSPEND, $zero, SUSPEND_CHECK_INTERVAL # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
Andreas Gampe8d365912015-01-13 11:32:32 -08002067 jalr $zero, $ra
buzbee5bc5a7b2012-03-07 15:52:59 -08002068 nop
20691:
Alexey Frunze19428ad2017-08-03 10:36:46 -07002070 SETUP_SAVE_EVERYTHING_FRAME RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET
2071 # save everything for stack crawl
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002072 la $t9, artTestSuspendFromCode
Vladimir Marko952dbb12016-07-28 12:01:51 +01002073 jalr $t9 # (Thread*)
jeffhao7fbee072012-08-24 17:56:54 -07002074 move $a0, rSELF
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002075 RESTORE_SAVE_EVERYTHING_FRAME
Vladimir Marko952dbb12016-07-28 12:01:51 +01002076 jalr $zero, $ra
2077 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002078END art_quick_test_suspend
buzbee5bc5a7b2012-03-07 15:52:59 -08002079
buzbee5bc5a7b2012-03-07 15:52:59 -08002080 /*
2081 * Called by managed code that is attempting to call a method on a proxy class. On entry
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002082 * a0 holds the proxy method; a1, a2 and a3 may contain arguments.
buzbee5bc5a7b2012-03-07 15:52:59 -08002083 */
Jeff Hao5fa60c32013-04-04 17:57:01 -07002084 .extern artQuickProxyInvokeHandler
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002085ENTRY art_quick_proxy_invoke_handler
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002086 SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
Douglas Leung735b8552014-10-31 12:21:40 -07002087 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002088 la $t9, artQuickProxyInvokeHandler
2089 jalr $t9 # (Method* proxy method, receiver, Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002090 addiu $a3, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002091 lw $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002092 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002093 bnez $t7, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002094 # don't care if $v0 and/or $v1 are modified, when exception branch taken
2095 MTD $v0, $v1, $f0, $f1 # move float value to return value
Andreas Gampe8d365912015-01-13 11:32:32 -08002096 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002097 nop
buzbee5bc5a7b2012-03-07 15:52:59 -080020981:
2099 DELIVER_PENDING_EXCEPTION
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002100END art_quick_proxy_invoke_handler
buzbee5bc5a7b2012-03-07 15:52:59 -08002101
Jeff Hao88474b42013-10-23 16:24:40 -07002102 /*
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002103 * Called to resolve an imt conflict.
2104 * a0 is the conflict ArtMethod.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002105 * t7 is a hidden argument that holds the target interface method's dex method index.
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002106 *
Alexey Frunze279cfba2017-07-22 00:24:43 -07002107 * Note that this stub writes to v0-v1, a0, t2-t9, f0-f7.
Jeff Hao88474b42013-10-23 16:24:40 -07002108 */
Alexey Frunze279cfba2017-07-22 00:24:43 -07002109 .extern artLookupResolvedMethod
2110 .extern __atomic_load_8 # For int64_t std::atomic::load(std::memory_order).
Douglas Leung13738bf2014-10-27 14:44:47 -07002111ENTRY art_quick_imt_conflict_trampoline
Alexey Frunze279cfba2017-07-22 00:24:43 -07002112 SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY /* save_s4_thru_s8 */ 0
2113
2114 lw $t8, FRAME_SIZE_SAVE_REFS_AND_ARGS($sp) # $t8 = referrer.
Vladimir Marko5122e6b2017-08-17 16:10:09 +01002115 // If the method is obsolete, just go through the dex cache miss slow path.
2116 // The obsolete flag is set with suspended threads, so we do not need an acquire operation here.
2117 lw $t9, ART_METHOD_ACCESS_FLAGS_OFFSET($t8) # $t9 = access flags.
2118 sll $t9, $t9, 31 - ACC_OBSOLETE_METHOD_SHIFT # Move obsolete method bit to sign bit.
2119 bltz $t9, .Limt_conflict_trampoline_dex_cache_miss
2120 lw $t8, ART_METHOD_DECLARING_CLASS_OFFSET($t8) # $t8 = declaring class (no read barrier).
2121 lw $t8, MIRROR_CLASS_DEX_CACHE_OFFSET($t8) # $t8 = dex cache (without read barrier).
2122 UNPOISON_HEAP_REF $t8
Alexey Frunze279cfba2017-07-22 00:24:43 -07002123 la $t9, __atomic_load_8
2124 addiu $sp, $sp, -ARG_SLOT_SIZE # Reserve argument slots on the stack.
2125 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
Vladimir Marko5122e6b2017-08-17 16:10:09 +01002126 lw $t8, MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET($t8) # $t8 = dex cache methods array.
Alexey Frunze279cfba2017-07-22 00:24:43 -07002127
2128 move $s2, $t7 # $s2 = method index (callee-saved).
2129 lw $s3, ART_METHOD_JNI_OFFSET_32($a0) # $s3 = ImtConflictTable (callee-saved).
2130
2131 sll $t7, $t7, 32 - METHOD_DEX_CACHE_HASH_BITS # $t7 = slot index in top bits, zeroes below.
2132 srl $t7, $t7, 32 - METHOD_DEX_CACHE_HASH_BITS - (POINTER_SIZE_SHIFT + 1)
2133 # $t7 = slot offset.
2134
2135 li $a1, STD_MEMORY_ORDER_RELAXED # $a1 = std::memory_order_relaxed.
2136 jalr $t9 # [$v0, $v1] = __atomic_load_8($a0, $a1).
2137 addu $a0, $t8, $t7 # $a0 = DexCache method slot address.
2138
2139 bne $v1, $s2, .Limt_conflict_trampoline_dex_cache_miss # Branch if method index miss.
2140 addiu $sp, $sp, ARG_SLOT_SIZE # Remove argument slots from the stack.
2141 .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002142
2143.Limt_table_iterate:
Alexey Frunze279cfba2017-07-22 00:24:43 -07002144 lw $t8, 0($s3) # Load next entry in ImtConflictTable.
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002145 # Branch if found.
Alexey Frunze279cfba2017-07-22 00:24:43 -07002146 beq $t8, $v0, .Limt_table_found
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002147 nop
2148 # If the entry is null, the interface method is not in the ImtConflictTable.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002149 beqz $t8, .Lconflict_trampoline
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002150 nop
2151 # Iterate over the entries of the ImtConflictTable.
2152 b .Limt_table_iterate
Alexey Frunze279cfba2017-07-22 00:24:43 -07002153 addiu $s3, $s3, 2 * __SIZEOF_POINTER__ # Iterate to the next entry.
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002154
2155.Limt_table_found:
2156 # We successfully hit an entry in the table. Load the target method and jump to it.
Alexey Frunze279cfba2017-07-22 00:24:43 -07002157 .cfi_remember_state
2158 lw $a0, __SIZEOF_POINTER__($s3)
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002159 lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)
Alexey Frunze279cfba2017-07-22 00:24:43 -07002160 RESTORE_SAVE_REFS_AND_ARGS_FRAME /* restore_s4_thru_s8 */ 0, /* remove_arg_slots */ 0
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002161 jalr $zero, $t9
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002162 nop
Alexey Frunze279cfba2017-07-22 00:24:43 -07002163 .cfi_restore_state
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002164
2165.Lconflict_trampoline:
2166 # Call the runtime stub to populate the ImtConflictTable and jump to the resolved method.
Alexey Frunze279cfba2017-07-22 00:24:43 -07002167 .cfi_remember_state
2168 RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP # Restore clobbered $gp.
2169 RESTORE_SAVE_REFS_AND_ARGS_FRAME_A1 # Restore this.
2170 move $a0, $v0 # Load interface method.
2171 INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline, /* save_s4_thru_s8_only */ 1
2172 .cfi_restore_state
2173
2174.Limt_conflict_trampoline_dex_cache_miss:
2175 # We're not creating a proper runtime method frame here,
2176 # artLookupResolvedMethod() is not allowed to walk the stack.
2177 RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP # Restore clobbered $gp.
2178 lw $a1, FRAME_SIZE_SAVE_REFS_AND_ARGS($sp) # $a1 = referrer.
2179 la $t9, artLookupResolvedMethod
2180 addiu $sp, $sp, -ARG_SLOT_SIZE # Reserve argument slots on the stack.
2181 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
2182 jalr $t9 # (uint32_t method_index, ArtMethod* referrer).
2183 move $a0, $s2 # $a0 = method index.
2184
2185 # If the method wasn't resolved, skip the lookup and go to artInvokeInterfaceTrampoline().
2186 beqz $v0, .Lconflict_trampoline
2187 addiu $sp, $sp, ARG_SLOT_SIZE # Remove argument slots from the stack.
2188 .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
2189
2190 b .Limt_table_iterate
2191 nop
Jeff Hao88474b42013-10-23 16:24:40 -07002192END art_quick_imt_conflict_trampoline
2193
Ian Rogers468532e2013-08-05 10:56:33 -07002194 .extern artQuickResolutionTrampoline
2195ENTRY art_quick_resolution_trampoline
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002196 SETUP_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002197 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002198 la $t9, artQuickResolutionTrampoline
2199 jalr $t9 # (Method* called, receiver, Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002200 addiu $a3, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
Ian Rogers468532e2013-08-05 10:56:33 -07002201 beqz $v0, 1f
Douglas Leung735b8552014-10-31 12:21:40 -07002202 lw $a0, ARG_SLOT_SIZE($sp) # load resolved method to $a0
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002203 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Ian Rogers65d1b222013-09-27 10:59:41 -07002204 move $t9, $v0 # code pointer must be in $t9 to generate the global pointer
Douglas Leungf96e8bd2015-03-27 15:38:30 -07002205 jalr $zero, $t9 # tail call to method
Mathieu Chartier19841522013-10-22 11:29:00 -07002206 nop
Ian Rogers468532e2013-08-05 10:56:33 -070022071:
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002208 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Ian Rogers468532e2013-08-05 10:56:33 -07002209 DELIVER_PENDING_EXCEPTION
2210END art_quick_resolution_trampoline
2211
Douglas Leung735b8552014-10-31 12:21:40 -07002212 .extern artQuickGenericJniTrampoline
2213 .extern artQuickGenericJniEndTrampoline
2214ENTRY art_quick_generic_jni_trampoline
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002215 SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
Douglas Leung735b8552014-10-31 12:21:40 -07002216 move $s8, $sp # save $sp to $s8
2217 move $s3, $gp # save $gp to $s3
2218
2219 # prepare for call to artQuickGenericJniTrampoline(Thread*, SP)
2220 move $a0, rSELF # pass Thread::Current
2221 addiu $a1, $sp, ARG_SLOT_SIZE # save $sp (remove arg slots)
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002222 la $t9, artQuickGenericJniTrampoline
2223 jalr $t9 # (Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002224 addiu $sp, $sp, -5120 # reserve space on the stack
2225
2226 # The C call will have registered the complete save-frame on success.
2227 # The result of the call is:
2228 # v0: ptr to native code, 0 on error.
2229 # v1: ptr to the bottom of the used area of the alloca, can restore stack till here.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002230 beq $v0, $zero, 2f # check entry error
Douglas Leung735b8552014-10-31 12:21:40 -07002231 move $t9, $v0 # save the code ptr
2232 move $sp, $v1 # release part of the alloca
2233
2234 # Load parameters from stack into registers
2235 lw $a0, 0($sp)
2236 lw $a1, 4($sp)
2237 lw $a2, 8($sp)
Douglas Leung735b8552014-10-31 12:21:40 -07002238 lw $a3, 12($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002239
2240 # artQuickGenericJniTrampoline sets bit 0 of the native code address to 1
2241 # when the first two arguments are both single precision floats. This lets
2242 # us extract them properly from the stack and load into floating point
2243 # registers.
2244 MTD $a0, $a1, $f12, $f13
2245 andi $t0, $t9, 1
2246 xor $t9, $t9, $t0
2247 bnez $t0, 1f
2248 mtc1 $a1, $f14
2249 MTD $a2, $a3, $f14, $f15
2250
22511:
2252 jalr $t9 # native call
2253 nop
Douglas Leung735b8552014-10-31 12:21:40 -07002254 addiu $sp, $sp, 16 # remove arg slots
2255
2256 move $gp, $s3 # restore $gp from $s3
2257
2258 # result sign extension is handled in C code
2259 # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f)
2260 move $a0, rSELF # pass Thread::Current
2261 move $a2, $v0 # pass result
2262 move $a3, $v1
2263 addiu $sp, $sp, -24 # reserve arg slots
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002264 la $t9, artQuickGenericJniEndTrampoline
2265 jalr $t9
Douglas Leung735b8552014-10-31 12:21:40 -07002266 s.d $f0, 16($sp) # pass result_f
Douglas Leung735b8552014-10-31 12:21:40 -07002267
2268 lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002269 bne $t0, $zero, 2f # check for pending exceptions
Nicolas Geoffray126d6592015-03-03 14:28:35 +00002270
Douglas Leung735b8552014-10-31 12:21:40 -07002271 move $sp, $s8 # tear down the alloca
2272
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002273 # tear down the callee-save frame
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002274 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002275
Duane Sande34652f2014-11-04 11:09:36 -08002276 MTD $v0, $v1, $f0, $f1 # move float value to return value
Andreas Gampe8d365912015-01-13 11:32:32 -08002277 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002278 nop
Douglas Leung735b8552014-10-31 12:21:40 -07002279
Alexey Frunze1b8464d2016-11-12 17:22:05 -080022802:
Alexey Frunzec61c0762017-04-10 13:54:23 -07002281 lw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
2282 move $gp, $s3 # restore $gp from $s3
Nicolas Geoffray126d6592015-03-03 14:28:35 +00002283 # This will create a new save-all frame, required by the runtime.
Douglas Leung735b8552014-10-31 12:21:40 -07002284 DELIVER_PENDING_EXCEPTION
2285END art_quick_generic_jni_trampoline
Andreas Gampe2da88232014-02-27 12:26:20 -08002286
Ian Rogers468532e2013-08-05 10:56:33 -07002287 .extern artQuickToInterpreterBridge
2288ENTRY art_quick_to_interpreter_bridge
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002289 SETUP_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002290 move $a1, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002291 la $t9, artQuickToInterpreterBridge
2292 jalr $t9 # (Method* method, Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002293 addiu $a2, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002294 lw $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002295 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002296 bnez $t7, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002297 # don't care if $v0 and/or $v1 are modified, when exception branch taken
2298 MTD $v0, $v1, $f0, $f1 # move float value to return value
Andreas Gampe8d365912015-01-13 11:32:32 -08002299 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002300 nop
Ian Rogers7db619b2013-01-16 18:35:48 -080023011:
2302 DELIVER_PENDING_EXCEPTION
Ian Rogers468532e2013-08-05 10:56:33 -07002303END art_quick_to_interpreter_bridge
Ian Rogers7db619b2013-01-16 18:35:48 -08002304
Alex Lightdb01a092017-04-03 15:39:55 -07002305 .extern artInvokeObsoleteMethod
2306ENTRY art_invoke_obsolete_method_stub
2307 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
2308 la $t9, artInvokeObsoleteMethod
2309 jalr $t9 # (Method* method, Thread* self)
2310 move $a1, rSELF # pass Thread::Current
2311END art_invoke_obsolete_method_stub
2312
buzbee5bc5a7b2012-03-07 15:52:59 -08002313 /*
jeffhao725a9572012-11-13 18:20:12 -08002314 * Routine that intercepts method calls and returns.
buzbee5bc5a7b2012-03-07 15:52:59 -08002315 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002316 .extern artInstrumentationMethodEntryFromCode
2317 .extern artInstrumentationMethodExitFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07002318ENTRY art_quick_instrumentation_entry
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002319 SETUP_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002320 sw $a0, 28($sp) # save arg0 in free arg slot
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002321 addiu $a3, $sp, ARG_SLOT_SIZE # Pass $sp.
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002322 la $t9, artInstrumentationMethodEntryFromCode
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002323 jalr $t9 # (Method*, Object*, Thread*, SP)
Ian Rogers62d6c772013-02-27 08:32:07 -08002324 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002325 beqz $v0, .Ldeliver_instrumentation_entry_exception
jeffhao8161c032012-10-31 15:50:00 -07002326 move $t9, $v0 # $t9 holds reference to code
Douglas Leung735b8552014-10-31 12:21:40 -07002327 lw $a0, 28($sp) # restore arg0 from free arg slot
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002328 RESTORE_SAVE_REFS_AND_ARGS_FRAME
jeffhao8161c032012-10-31 15:50:00 -07002329 jalr $t9 # call method
Ian Rogers62d6c772013-02-27 08:32:07 -08002330 nop
Ian Rogers468532e2013-08-05 10:56:33 -07002331END art_quick_instrumentation_entry
buzbee5bc5a7b2012-03-07 15:52:59 -08002332 /* intentional fallthrough */
Ian Rogers468532e2013-08-05 10:56:33 -07002333 .global art_quick_instrumentation_exit
2334art_quick_instrumentation_exit:
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002335 .cfi_startproc
jeffhao12051ea2013-01-10 11:24:31 -08002336 addiu $t9, $ra, 4 # put current address into $t9 to rebuild $gp
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002337 .cpload $t9
Douglas Leungc3d131e2014-07-16 17:32:41 -07002338 move $ra, $zero # link register is to here, so clobber with 0 for later checks
Douglas Leung735b8552014-10-31 12:21:40 -07002339
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002340 SETUP_SAVE_REFS_ONLY_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002341 addiu $sp, $sp, -16 # allocate temp storage on the stack
2342 .cfi_adjust_cfa_offset 16
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002343 sw $v0, ARG_SLOT_SIZE+8($sp)
2344 .cfi_rel_offset 2, ARG_SLOT_SIZE+8
2345 sw $v1, ARG_SLOT_SIZE+12($sp)
2346 .cfi_rel_offset 3, ARG_SLOT_SIZE+12
Douglas Leungf96e8bd2015-03-27 15:38:30 -07002347 s.d $f0, ARG_SLOT_SIZE($sp)
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002348 addiu $a3, $sp, ARG_SLOT_SIZE # Pass fpr_res pointer.
2349 addiu $a2, $sp, ARG_SLOT_SIZE+8 # Pass gpr_res pointer.
2350 addiu $a1, $sp, ARG_SLOT_SIZE+16 # Pass $sp (remove arg slots and temp storage).
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002351 la $t9, artInstrumentationMethodExitFromCode
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002352 jalr $t9 # (Thread*, SP, gpr_res*, fpr_res*)
2353 move $a0, rSELF # Pass Thread::Current.
2354 move $t9, $v0 # Set aside returned link register.
2355 move $ra, $v1 # Set link register for deoptimization.
2356 lw $v0, ARG_SLOT_SIZE+8($sp) # Restore return values.
2357 lw $v1, ARG_SLOT_SIZE+12($sp)
Douglas Leungf96e8bd2015-03-27 15:38:30 -07002358 l.d $f0, ARG_SLOT_SIZE($sp)
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002359 addiu $sp, $sp, 16
2360 .cfi_adjust_cfa_offset -16
2361 RESTORE_SAVE_REFS_ONLY_FRAME
2362 beqz $t9, .Ldo_deliver_instrumentation_exception
2363 nop # Deliver exception if we got nullptr as function.
2364 jalr $zero, $t9 # Otherwise, return.
2365 nop
2366.Ldeliver_instrumentation_entry_exception:
2367 # Deliver exception for art_quick_instrumentation_entry placed after
2368 # art_quick_instrumentation_exit so that the fallthrough works.
2369 RESTORE_SAVE_REFS_AND_ARGS_FRAME
2370.Ldo_deliver_instrumentation_exception:
2371 DELIVER_PENDING_EXCEPTION
Ian Rogers468532e2013-08-05 10:56:33 -07002372END art_quick_instrumentation_exit
buzbee5bc5a7b2012-03-07 15:52:59 -08002373
jeffhao12051ea2013-01-10 11:24:31 -08002374 /*
Ian Rogers62d6c772013-02-27 08:32:07 -08002375 * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
2376 * will long jump to the upcall with a special exception of -1.
jeffhao12051ea2013-01-10 11:24:31 -08002377 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002378 .extern artDeoptimize
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002379ENTRY art_quick_deoptimize
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002380 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002381 la $t9, artDeoptimize
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01002382 jalr $t9 # (Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002383 move $a0, rSELF # pass Thread::current
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002384END art_quick_deoptimize
jeffhao12051ea2013-01-10 11:24:31 -08002385
buzbee5bc5a7b2012-03-07 15:52:59 -08002386 /*
Sebastien Hertz07474662015-08-25 15:12:33 +00002387 * Compiled code has requested that we deoptimize into the interpreter. The deoptimization
2388 * will long jump to the upcall with a special exception of -1.
2389 */
2390 .extern artDeoptimizeFromCompiledCode
2391ENTRY art_quick_deoptimize_from_compiled_code
Vladimir Marko239d6ea2016-09-05 10:44:04 +01002392 SETUP_SAVE_EVERYTHING_FRAME
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002393 la $t9, artDeoptimizeFromCompiledCode
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01002394 jalr $t9 # (DeoptimizationKind, Thread*)
2395 move $a1, rSELF # pass Thread::current
Sebastien Hertz07474662015-08-25 15:12:33 +00002396END art_quick_deoptimize_from_compiled_code
2397
2398 /*
buzbee5bc5a7b2012-03-07 15:52:59 -08002399 * Long integer shift. This is different from the generic 32/64-bit
2400 * binary operations because vAA/vBB are 64-bit but vCC (the shift
2401 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
2402 * 6 bits.
2403 * On entry:
jeffhao7fbee072012-08-24 17:56:54 -07002404 * $a0: low word
2405 * $a1: high word
2406 * $a2: shift count
buzbee5bc5a7b2012-03-07 15:52:59 -08002407 */
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002408ENTRY_NO_GP art_quick_shl_long
buzbee5bc5a7b2012-03-07 15:52:59 -08002409 /* shl-long vAA, vBB, vCC */
jeffhao7fbee072012-08-24 17:56:54 -07002410 sll $v0, $a0, $a2 # rlo<- alo << (shift&31)
2411 not $v1, $a2 # rhi<- 31-shift (shift is 5b)
2412 srl $a0, 1
2413 srl $a0, $v1 # alo<- alo >> (32-(shift&31))
2414 sll $v1, $a1, $a2 # rhi<- ahi << (shift&31)
jeffhao7fbee072012-08-24 17:56:54 -07002415 andi $a2, 0x20 # shift< shift & 0x20
Duane Sande34652f2014-11-04 11:09:36 -08002416 beqz $a2, 1f
2417 or $v1, $a0 # rhi<- rhi | alo
2418
2419 move $v1, $v0 # rhi<- rlo (if shift&0x20)
2420 move $v0, $zero # rlo<- 0 (if shift&0x20)
2421
Andreas Gampe8d365912015-01-13 11:32:32 -080024221: jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002423 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002424END art_quick_shl_long
buzbee5bc5a7b2012-03-07 15:52:59 -08002425
buzbee5bc5a7b2012-03-07 15:52:59 -08002426 /*
2427 * Long integer shift. This is different from the generic 32/64-bit
2428 * binary operations because vAA/vBB are 64-bit but vCC (the shift
2429 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
2430 * 6 bits.
2431 * On entry:
jeffhao7fbee072012-08-24 17:56:54 -07002432 * $a0: low word
2433 * $a1: high word
2434 * $a2: shift count
buzbee5bc5a7b2012-03-07 15:52:59 -08002435 */
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002436ENTRY_NO_GP art_quick_shr_long
jeffhao7fbee072012-08-24 17:56:54 -07002437 sra $v1, $a1, $a2 # rhi<- ahi >> (shift&31)
2438 srl $v0, $a0, $a2 # rlo<- alo >> (shift&31)
2439 sra $a3, $a1, 31 # $a3<- sign(ah)
2440 not $a0, $a2 # alo<- 31-shift (shift is 5b)
2441 sll $a1, 1
2442 sll $a1, $a0 # ahi<- ahi << (32-(shift&31))
jeffhao7fbee072012-08-24 17:56:54 -07002443 andi $a2, 0x20 # shift & 0x20
Douglas Leung475cfd82014-12-16 20:15:41 -08002444 beqz $a2, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002445 or $v0, $a1 # rlo<- rlo | ahi
2446
2447 move $v0, $v1 # rlo<- rhi (if shift&0x20)
2448 move $v1, $a3 # rhi<- sign(ahi) (if shift&0x20)
2449
Andreas Gampe8d365912015-01-13 11:32:32 -080024501: jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002451 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002452END art_quick_shr_long
buzbee5bc5a7b2012-03-07 15:52:59 -08002453
buzbee5bc5a7b2012-03-07 15:52:59 -08002454 /*
2455 * Long integer shift. This is different from the generic 32/64-bit
2456 * binary operations because vAA/vBB are 64-bit but vCC (the shift
2457 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
2458 * 6 bits.
2459 * On entry:
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002460 * $a0: low word
2461 * $a1: high word
2462 * $a2: shift count
buzbee5bc5a7b2012-03-07 15:52:59 -08002463 */
2464 /* ushr-long vAA, vBB, vCC */
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002465ENTRY_NO_GP art_quick_ushr_long
jeffhaofc6a30e2012-10-18 18:24:15 -07002466 srl $v1, $a1, $a2 # rhi<- ahi >> (shift&31)
jeffhao7fbee072012-08-24 17:56:54 -07002467 srl $v0, $a0, $a2 # rlo<- alo >> (shift&31)
jeffhao7fbee072012-08-24 17:56:54 -07002468 not $a0, $a2 # alo<- 31-shift (shift is 5b)
2469 sll $a1, 1
2470 sll $a1, $a0 # ahi<- ahi << (32-(shift&31))
jeffhao7fbee072012-08-24 17:56:54 -07002471 andi $a2, 0x20 # shift & 0x20
Duane Sande34652f2014-11-04 11:09:36 -08002472 beqz $a2, 1f
2473 or $v0, $a1 # rlo<- rlo | ahi
2474
2475 move $v0, $v1 # rlo<- rhi (if shift&0x20)
2476 move $v1, $zero # rhi<- 0 (if shift&0x20)
2477
Andreas Gampe8d365912015-01-13 11:32:32 -080024781: jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002479 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002480END art_quick_ushr_long
jeffhao7fbee072012-08-24 17:56:54 -07002481
Chris Larsencf283da2016-01-19 16:45:35 -08002482/* java.lang.String.indexOf(int ch, int fromIndex=0) */
2483ENTRY_NO_GP art_quick_indexof
2484/* $a0 holds address of "this" */
2485/* $a1 holds "ch" */
2486/* $a2 holds "fromIndex" */
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002487#if (STRING_COMPRESSION_FEATURE)
2488 lw $a3, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this
Chris Larsencf283da2016-01-19 16:45:35 -08002489#else
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002490 lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # this.length()
Chris Larsencf283da2016-01-19 16:45:35 -08002491#endif
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002492 slt $t1, $a2, $zero # if fromIndex < 0
Goran Jakovljeviccdb23d62017-02-28 14:58:01 +01002493#if defined(_MIPS_ARCH_MIPS32R6)
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002494 seleqz $a2, $a2, $t1 # fromIndex = 0;
2495#else
2496 movn $a2, $zero, $t1 # fromIndex = 0;
2497#endif
Goran Jakovljeviccdb23d62017-02-28 14:58:01 +01002498
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002499#if (STRING_COMPRESSION_FEATURE)
2500 srl $t0, $a3, 1 # $a3 holds count (with flag) and $t0 holds actual length
2501#endif
2502 subu $t0, $t0, $a2 # this.length() - fromIndex
2503 blez $t0, 6f # if this.length()-fromIndex <= 0
2504 li $v0, -1 # return -1;
Chris Larsencf283da2016-01-19 16:45:35 -08002505
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002506#if (STRING_COMPRESSION_FEATURE)
2507 sll $a3, $a3, 31 # Extract compression flag.
2508 beqz $a3, .Lstring_indexof_compressed
2509 move $t2, $a0 # Save a copy in $t2 to later compute result (in branch delay slot).
2510#endif
2511 sll $v0, $a2, 1 # $a0 += $a2 * 2
2512 addu $a0, $a0, $v0 # " ditto "
2513 move $v0, $a2 # Set i to fromIndex.
Chris Larsencf283da2016-01-19 16:45:35 -08002514
25151:
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002516 lhu $t3, MIRROR_STRING_VALUE_OFFSET($a0) # if this.charAt(i) == ch
2517 beq $t3, $a1, 6f # return i;
2518 addu $a0, $a0, 2 # i++
2519 subu $t0, $t0, 1 # this.length() - i
2520 bnez $t0, 1b # while this.length() - i > 0
2521 addu $v0, $v0, 1 # i++
Chris Larsencf283da2016-01-19 16:45:35 -08002522
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002523 li $v0, -1 # if this.length() - i <= 0
2524 # return -1;
Chris Larsencf283da2016-01-19 16:45:35 -08002525
25266:
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002527 j $ra
2528 nop
2529
2530#if (STRING_COMPRESSION_FEATURE)
2531.Lstring_indexof_compressed:
2532 addu $a0, $a0, $a2 # $a0 += $a2
2533
2534.Lstring_indexof_compressed_loop:
2535 lbu $t3, MIRROR_STRING_VALUE_OFFSET($a0)
2536 beq $t3, $a1, .Lstring_indexof_compressed_matched
2537 subu $t0, $t0, 1
2538 bgtz $t0, .Lstring_indexof_compressed_loop
2539 addu $a0, $a0, 1
2540
2541.Lstring_indexof_nomatch:
2542 jalr $zero, $ra
2543 li $v0, -1 # return -1;
2544
2545.Lstring_indexof_compressed_matched:
2546 jalr $zero, $ra
2547 subu $v0, $a0, $t2 # return (current - start);
2548#endif
Chris Larsencf283da2016-01-19 16:45:35 -08002549END art_quick_indexof
2550
Chris Larsencf283da2016-01-19 16:45:35 -08002551/* java.lang.String.compareTo(String anotherString) */
2552ENTRY_NO_GP art_quick_string_compareto
2553/* $a0 holds address of "this" */
2554/* $a1 holds address of "anotherString" */
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002555 beq $a0, $a1, .Lstring_compareto_length_diff # this and anotherString are the same object
2556 move $a3, $a2 # trick to return 0 (it returns a2 - a3)
Chris Larsencf283da2016-01-19 16:45:35 -08002557
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002558#if (STRING_COMPRESSION_FEATURE)
2559 lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this
2560 lw $t1, MIRROR_STRING_COUNT_OFFSET($a1) # 'count' field of anotherString
2561 sra $a2, $t0, 1 # this.length()
2562 sra $a3, $t1, 1 # anotherString.length()
2563#else
2564 lw $a2, MIRROR_STRING_COUNT_OFFSET($a0) # this.length()
2565 lw $a3, MIRROR_STRING_COUNT_OFFSET($a1) # anotherString.length()
2566#endif
Chris Larsencf283da2016-01-19 16:45:35 -08002567
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002568 MINu $t2, $a2, $a3
2569 # $t2 now holds min(this.length(),anotherString.length())
Chris Larsencf283da2016-01-19 16:45:35 -08002570
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002571 # while min(this.length(),anotherString.length())-i != 0
2572 beqz $t2, .Lstring_compareto_length_diff # if $t2==0
2573 nop # return (this.length() - anotherString.length())
2574
2575#if (STRING_COMPRESSION_FEATURE)
2576 # Differ cases:
2577 sll $t3, $t0, 31
2578 beqz $t3, .Lstring_compareto_this_is_compressed
2579 sll $t3, $t1, 31 # In branch delay slot.
2580 beqz $t3, .Lstring_compareto_that_is_compressed
2581 nop
2582 b .Lstring_compareto_both_not_compressed
2583 nop
2584
2585.Lstring_compareto_this_is_compressed:
2586 beqz $t3, .Lstring_compareto_both_compressed
2587 nop
2588 /* If (this->IsCompressed() && that->IsCompressed() == false) */
2589.Lstring_compareto_loop_comparison_this_compressed:
2590 lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2591 lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2592 bne $t0, $t1, .Lstring_compareto_char_diff
2593 addiu $a0, $a0, 1 # point at this.charAt(i++) - compressed
2594 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2595 bnez $t2, .Lstring_compareto_loop_comparison_this_compressed
2596 addiu $a1, $a1, 2 # point at anotherString.charAt(i++) - uncompressed
2597 jalr $zero, $ra
2598 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2599
2600.Lstring_compareto_that_is_compressed:
2601 lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2602 lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2603 bne $t0, $t1, .Lstring_compareto_char_diff
2604 addiu $a0, $a0, 2 # point at this.charAt(i++) - uncompressed
2605 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2606 bnez $t2, .Lstring_compareto_that_is_compressed
2607 addiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed
2608 jalr $zero, $ra
2609 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2610
2611.Lstring_compareto_both_compressed:
2612 lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2613 lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2614 bne $t0, $t1, .Lstring_compareto_char_diff
2615 addiu $a0, $a0, 1 # point at this.charAt(i++) - compressed
2616 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2617 bnez $t2, .Lstring_compareto_both_compressed
2618 addiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed
2619 jalr $zero, $ra
2620 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2621#endif
2622
2623.Lstring_compareto_both_not_compressed:
2624 lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0) # while this.charAt(i) == anotherString.charAt(i)
2625 lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2626 bne $t0, $t1, .Lstring_compareto_char_diff # if this.charAt(i) != anotherString.charAt(i)
2627 # return (this.charAt(i) - anotherString.charAt(i))
2628 addiu $a0, $a0, 2 # point at this.charAt(i++)
2629 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2630 bnez $t2, .Lstring_compareto_both_not_compressed
2631 addiu $a1, $a1, 2 # point at anotherString.charAt(i++)
2632
2633.Lstring_compareto_length_diff:
2634 jalr $zero, $ra
2635 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2636
2637.Lstring_compareto_char_diff:
2638 jalr $zero, $ra
2639 subu $v0, $t0, $t1 # return (this.charAt(i) - anotherString.charAt(i))
Chris Larsencf283da2016-01-19 16:45:35 -08002640END art_quick_string_compareto
Orion Hodsonac141392017-01-13 11:53:47 +00002641
Alexey Frunze15958152017-02-09 19:08:30 -08002642 /*
2643 * Create a function `name` calling the ReadBarrier::Mark routine,
2644 * getting its argument and returning its result through register
2645 * `reg`, saving and restoring all caller-save registers.
2646 */
2647.macro READ_BARRIER_MARK_REG name, reg
2648ENTRY \name
Alexey Frunzea3cb1322017-05-01 18:49:46 -07002649 // Null check so that we can load the lock word.
2650 bnez \reg, .Lnot_null_\name
2651 nop
2652.Lret_rb_\name:
2653 jalr $zero, $ra
2654 nop
2655.Lnot_null_\name:
2656 // Check lock word for mark bit, if marked return.
2657 lw $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET(\reg)
2658 .set push
2659 .set noat
2660 sll $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT # Move mark bit to sign bit.
2661 bltz $at, .Lret_rb_\name
2662#if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
2663 // The below code depends on the lock word state being in the highest bits
2664 // and the "forwarding address" state having all bits set.
2665#error "Unexpected lock word state shift or forwarding address state value."
2666#endif
2667 // Test that both the forwarding state bits are 1.
2668 sll $at, $t9, 1
2669 and $at, $at, $t9 # Sign bit = 1 IFF both bits are 1.
2670 bltz $at, .Lret_forwarding_address\name
2671 nop
2672 .set pop
2673
2674 addiu $sp, $sp, -160 # Includes 16 bytes of space for argument registers a0-a3.
Alexey Frunze15958152017-02-09 19:08:30 -08002675 .cfi_adjust_cfa_offset 160
2676
2677 sw $ra, 156($sp)
2678 .cfi_rel_offset 31, 156
2679 sw $t8, 152($sp)
2680 .cfi_rel_offset 24, 152
2681 sw $t7, 148($sp)
2682 .cfi_rel_offset 15, 148
2683 sw $t6, 144($sp)
2684 .cfi_rel_offset 14, 144
2685 sw $t5, 140($sp)
2686 .cfi_rel_offset 13, 140
2687 sw $t4, 136($sp)
2688 .cfi_rel_offset 12, 136
2689 sw $t3, 132($sp)
2690 .cfi_rel_offset 11, 132
2691 sw $t2, 128($sp)
2692 .cfi_rel_offset 10, 128
2693 sw $t1, 124($sp)
2694 .cfi_rel_offset 9, 124
2695 sw $t0, 120($sp)
2696 .cfi_rel_offset 8, 120
2697 sw $a3, 116($sp)
2698 .cfi_rel_offset 7, 116
2699 sw $a2, 112($sp)
2700 .cfi_rel_offset 6, 112
2701 sw $a1, 108($sp)
2702 .cfi_rel_offset 5, 108
2703 sw $a0, 104($sp)
2704 .cfi_rel_offset 4, 104
2705 sw $v1, 100($sp)
2706 .cfi_rel_offset 3, 100
2707 sw $v0, 96($sp)
2708 .cfi_rel_offset 2, 96
2709
2710 la $t9, artReadBarrierMark
2711
2712 sdc1 $f18, 88($sp)
2713 sdc1 $f16, 80($sp)
2714 sdc1 $f14, 72($sp)
2715 sdc1 $f12, 64($sp)
2716 sdc1 $f10, 56($sp)
2717 sdc1 $f8, 48($sp)
2718 sdc1 $f6, 40($sp)
2719 sdc1 $f4, 32($sp)
2720 sdc1 $f2, 24($sp)
2721
2722 .ifnc \reg, $a0
2723 move $a0, \reg # pass obj from `reg` in a0
2724 .endif
2725 jalr $t9 # v0 <- artReadBarrierMark(obj)
2726 sdc1 $f0, 16($sp) # in delay slot
2727
2728 lw $ra, 156($sp)
2729 .cfi_restore 31
2730 lw $t8, 152($sp)
2731 .cfi_restore 24
2732 lw $t7, 148($sp)
2733 .cfi_restore 15
2734 lw $t6, 144($sp)
2735 .cfi_restore 14
2736 lw $t5, 140($sp)
2737 .cfi_restore 13
2738 lw $t4, 136($sp)
2739 .cfi_restore 12
2740 lw $t3, 132($sp)
2741 .cfi_restore 11
2742 lw $t2, 128($sp)
2743 .cfi_restore 10
2744 lw $t1, 124($sp)
2745 .cfi_restore 9
2746 lw $t0, 120($sp)
2747 .cfi_restore 8
2748 lw $a3, 116($sp)
2749 .cfi_restore 7
2750 lw $a2, 112($sp)
2751 .cfi_restore 6
2752 lw $a1, 108($sp)
2753 .cfi_restore 5
2754 lw $a0, 104($sp)
2755 .cfi_restore 4
2756 lw $v1, 100($sp)
2757 .cfi_restore 3
2758
2759 .ifnc \reg, $v0
2760 move \reg, $v0 # `reg` <- v0
2761 lw $v0, 96($sp)
2762 .cfi_restore 2
2763 .endif
2764
2765 ldc1 $f18, 88($sp)
2766 ldc1 $f16, 80($sp)
2767 ldc1 $f14, 72($sp)
2768 ldc1 $f12, 64($sp)
2769 ldc1 $f10, 56($sp)
2770 ldc1 $f8, 48($sp)
2771 ldc1 $f6, 40($sp)
2772 ldc1 $f4, 32($sp)
2773 ldc1 $f2, 24($sp)
2774 ldc1 $f0, 16($sp)
2775
2776 jalr $zero, $ra
2777 addiu $sp, $sp, 160
2778 .cfi_adjust_cfa_offset -160
Alexey Frunzea3cb1322017-05-01 18:49:46 -07002779
2780.Lret_forwarding_address\name:
2781 jalr $zero, $ra
2782 // Shift left by the forwarding address shift. This clears out the state bits since they are
2783 // in the top 2 bits of the lock word.
2784 sll \reg, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
Alexey Frunze15958152017-02-09 19:08:30 -08002785END \name
2786.endm
2787
2788// Note that art_quick_read_barrier_mark_regXX corresponds to register XX+1.
2789// ZERO (register 0) is reserved.
2790// AT (register 1) is reserved as a temporary/scratch register.
2791READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, $v0
2792READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, $v1
2793READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, $a0
2794READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg04, $a1
2795READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, $a2
2796READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, $a3
2797READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg07, $t0
2798READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg08, $t1
2799READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg09, $t2
2800READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg10, $t3
2801READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg11, $t4
2802READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg12, $t5
2803READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg13, $t6
2804READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg14, $t7
2805// S0 and S1 (registers 16 and 17) are reserved as suspended and thread registers.
2806READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg17, $s2
2807READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, $s3
2808READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg19, $s4
2809READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg20, $s5
2810READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg21, $s6
2811READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg22, $s7
2812// T8 and T9 (registers 24 and 25) are reserved as temporary/scratch registers.
2813// K0, K1, GP, SP (registers 26 - 29) are reserved.
2814READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg29, $s8
2815// RA (register 31) is reserved.
2816
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002817// Caller code:
2818// Short constant offset/index:
2819// R2: | R6:
2820// lw $t9, pReadBarrierMarkReg00
2821// beqz $t9, skip_call | beqzc $t9, skip_call
2822// addiu $t9, $t9, thunk_disp | nop
2823// jalr $t9 | jialc $t9, thunk_disp
2824// nop |
2825// skip_call: | skip_call:
2826// lw `out`, ofs(`obj`) | lw `out`, ofs(`obj`)
2827// [subu `out`, $zero, `out`] | [subu `out`, $zero, `out`] # Unpoison reference.
2828.macro BRB_FIELD_SHORT_OFFSET_ENTRY obj
28291:
2830 # Explicit null check. May be redundant (for array elements or when the field
2831 # offset is larger than the page size, 4KB).
2832 # $ra will be adjusted to point to lw's stack map when throwing NPE.
2833 beqz \obj, .Lintrospection_throw_npe
2834#if defined(_MIPS_ARCH_MIPS32R6)
2835 lapc $gp, .Lintrospection_exits # $gp = address of .Lintrospection_exits.
2836#else
2837 addiu $gp, $t9, (.Lintrospection_exits - 1b) # $gp = address of .Lintrospection_exits.
2838#endif
2839 .set push
2840 .set noat
2841 lw $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
2842 sll $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT # Move barrier state bit
2843 # to sign bit.
2844 bltz $at, .Lintrospection_field_array # If gray, load reference, mark.
2845 move $t8, \obj # Move `obj` to $t8 for common code.
2846 .set pop
2847 jalr $zero, $ra # Otherwise, load-load barrier and return.
2848 sync
2849.endm
2850
2851// Caller code (R2):
2852// Long constant offset/index: | Variable index:
2853// lw $t9, pReadBarrierMarkReg00
2854// lui $t8, ofs_hi | sll $t8, `index`, 2
2855// beqz $t9, skip_call | beqz $t9, skip_call
2856// addiu $t9, $t9, thunk_disp | addiu $t9, $t9, thunk_disp
2857// jalr $t9 | jalr $t9
2858// skip_call: | skip_call:
2859// addu $t8, $t8, `obj` | addu $t8, $t8, `obj`
2860// lw `out`, ofs_lo($t8) | lw `out`, ofs($t8)
2861// [subu `out`, $zero, `out`] | [subu `out`, $zero, `out`] # Unpoison reference.
2862//
2863// Caller code (R6):
2864// Long constant offset/index: | Variable index:
2865// lw $t9, pReadBarrierMarkReg00
2866// beqz $t9, skip_call | beqz $t9, skip_call
2867// aui $t8, `obj`, ofs_hi | lsa $t8, `index`, `obj`, 2
2868// jialc $t9, thunk_disp | jialc $t9, thunk_disp
2869// skip_call: | skip_call:
2870// lw `out`, ofs_lo($t8) | lw `out`, ofs($t8)
2871// [subu `out`, $zero, `out`] | [subu `out`, $zero, `out`] # Unpoison reference.
2872.macro BRB_FIELD_LONG_OFFSET_ENTRY obj
28731:
2874 # No explicit null check for variable indices or large constant indices/offsets
2875 # as it must have been done earlier.
2876#if defined(_MIPS_ARCH_MIPS32R6)
2877 lapc $gp, .Lintrospection_exits # $gp = address of .Lintrospection_exits.
2878#else
2879 addiu $gp, $t9, (.Lintrospection_exits - 1b) # $gp = address of .Lintrospection_exits.
2880#endif
2881 .set push
2882 .set noat
2883 lw $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
2884 sll $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT # Move barrier state bit
2885 # to sign bit.
2886 bltz $at, .Lintrospection_field_array # If gray, load reference, mark.
2887 nop
2888 .set pop
2889 jalr $zero, $ra # Otherwise, load-load barrier and return.
2890 sync
2891 break # Padding to 8 instructions.
2892.endm
2893
2894.macro BRB_GC_ROOT_ENTRY root
28951:
2896#if defined(_MIPS_ARCH_MIPS32R6)
2897 lapc $gp, .Lintrospection_exit_\root # $gp = exit point address.
2898#else
2899 addiu $gp, $t9, (.Lintrospection_exit_\root - 1b) # $gp = exit point address.
2900#endif
2901 bnez \root, .Lintrospection_common
2902 move $t8, \root # Move reference to $t8 for common code.
2903 jalr $zero, $ra # Return if null.
2904 # The next instruction (from the following BRB_GC_ROOT_ENTRY) fills the delay slot.
2905 # This instruction has no effect (actual NOP for the last entry; otherwise changes $gp,
2906 # which is unused after that anyway).
2907.endm
2908
2909.macro BRB_FIELD_EXIT out
2910.Lintrospection_exit_\out:
2911 jalr $zero, $ra
2912 move \out, $t8 # Return reference in expected register.
2913.endm
2914
2915.macro BRB_FIELD_EXIT_BREAK
2916 break
2917 break
2918.endm
2919
2920ENTRY_NO_GP art_quick_read_barrier_mark_introspection
2921 # Entry points for offsets/indices not fitting into int16_t and for variable indices.
2922 BRB_FIELD_LONG_OFFSET_ENTRY $v0
2923 BRB_FIELD_LONG_OFFSET_ENTRY $v1
2924 BRB_FIELD_LONG_OFFSET_ENTRY $a0
2925 BRB_FIELD_LONG_OFFSET_ENTRY $a1
2926 BRB_FIELD_LONG_OFFSET_ENTRY $a2
2927 BRB_FIELD_LONG_OFFSET_ENTRY $a3
2928 BRB_FIELD_LONG_OFFSET_ENTRY $t0
2929 BRB_FIELD_LONG_OFFSET_ENTRY $t1
2930 BRB_FIELD_LONG_OFFSET_ENTRY $t2
2931 BRB_FIELD_LONG_OFFSET_ENTRY $t3
2932 BRB_FIELD_LONG_OFFSET_ENTRY $t4
2933 BRB_FIELD_LONG_OFFSET_ENTRY $t5
2934 BRB_FIELD_LONG_OFFSET_ENTRY $t6
2935 BRB_FIELD_LONG_OFFSET_ENTRY $t7
2936 BRB_FIELD_LONG_OFFSET_ENTRY $s2
2937 BRB_FIELD_LONG_OFFSET_ENTRY $s3
2938 BRB_FIELD_LONG_OFFSET_ENTRY $s4
2939 BRB_FIELD_LONG_OFFSET_ENTRY $s5
2940 BRB_FIELD_LONG_OFFSET_ENTRY $s6
2941 BRB_FIELD_LONG_OFFSET_ENTRY $s7
2942 BRB_FIELD_LONG_OFFSET_ENTRY $s8
2943
2944 # Entry points for offsets/indices fitting into int16_t.
2945 BRB_FIELD_SHORT_OFFSET_ENTRY $v0
2946 BRB_FIELD_SHORT_OFFSET_ENTRY $v1
2947 BRB_FIELD_SHORT_OFFSET_ENTRY $a0
2948 BRB_FIELD_SHORT_OFFSET_ENTRY $a1
2949 BRB_FIELD_SHORT_OFFSET_ENTRY $a2
2950 BRB_FIELD_SHORT_OFFSET_ENTRY $a3
2951 BRB_FIELD_SHORT_OFFSET_ENTRY $t0
2952 BRB_FIELD_SHORT_OFFSET_ENTRY $t1
2953 BRB_FIELD_SHORT_OFFSET_ENTRY $t2
2954 BRB_FIELD_SHORT_OFFSET_ENTRY $t3
2955 BRB_FIELD_SHORT_OFFSET_ENTRY $t4
2956 BRB_FIELD_SHORT_OFFSET_ENTRY $t5
2957 BRB_FIELD_SHORT_OFFSET_ENTRY $t6
2958 BRB_FIELD_SHORT_OFFSET_ENTRY $t7
2959 BRB_FIELD_SHORT_OFFSET_ENTRY $s2
2960 BRB_FIELD_SHORT_OFFSET_ENTRY $s3
2961 BRB_FIELD_SHORT_OFFSET_ENTRY $s4
2962 BRB_FIELD_SHORT_OFFSET_ENTRY $s5
2963 BRB_FIELD_SHORT_OFFSET_ENTRY $s6
2964 BRB_FIELD_SHORT_OFFSET_ENTRY $s7
2965 BRB_FIELD_SHORT_OFFSET_ENTRY $s8
2966
2967 .global art_quick_read_barrier_mark_introspection_gc_roots
2968art_quick_read_barrier_mark_introspection_gc_roots:
2969 # Entry points for GC roots.
2970 BRB_GC_ROOT_ENTRY $v0
2971 BRB_GC_ROOT_ENTRY $v1
2972 BRB_GC_ROOT_ENTRY $a0
2973 BRB_GC_ROOT_ENTRY $a1
2974 BRB_GC_ROOT_ENTRY $a2
2975 BRB_GC_ROOT_ENTRY $a3
2976 BRB_GC_ROOT_ENTRY $t0
2977 BRB_GC_ROOT_ENTRY $t1
2978 BRB_GC_ROOT_ENTRY $t2
2979 BRB_GC_ROOT_ENTRY $t3
2980 BRB_GC_ROOT_ENTRY $t4
2981 BRB_GC_ROOT_ENTRY $t5
2982 BRB_GC_ROOT_ENTRY $t6
2983 BRB_GC_ROOT_ENTRY $t7
2984 BRB_GC_ROOT_ENTRY $s2
2985 BRB_GC_ROOT_ENTRY $s3
2986 BRB_GC_ROOT_ENTRY $s4
2987 BRB_GC_ROOT_ENTRY $s5
2988 BRB_GC_ROOT_ENTRY $s6
2989 BRB_GC_ROOT_ENTRY $s7
2990 BRB_GC_ROOT_ENTRY $s8
2991 .global art_quick_read_barrier_mark_introspection_end_of_entries
2992art_quick_read_barrier_mark_introspection_end_of_entries:
2993 nop # Fill the delay slot of the last BRB_GC_ROOT_ENTRY.
2994
2995.Lintrospection_throw_npe:
2996 b art_quick_throw_null_pointer_exception
2997 addiu $ra, $ra, 4 # Skip lw, make $ra point to lw's stack map.
2998
2999 .set push
3000 .set noat
3001
3002 // Fields and array elements.
3003
3004.Lintrospection_field_array:
3005 // Get the field/element address using $t8 and the offset from the lw instruction.
3006 lh $at, 0($ra) # $ra points to lw: $at = field/element offset.
3007 addiu $ra, $ra, 4 + HEAP_POISON_INSTR_SIZE # Skip lw(+subu).
3008 addu $t8, $t8, $at # $t8 = field/element address.
3009
3010 // Calculate the address of the exit point, store it in $gp and load the reference into $t8.
3011 lb $at, (-HEAP_POISON_INSTR_SIZE - 2)($ra) # $ra-HEAP_POISON_INSTR_SIZE-4 points to
3012 # "lw `out`, ...".
3013 andi $at, $at, 31 # Extract `out` from lw.
3014 sll $at, $at, 3 # Multiply `out` by the exit point size (BRB_FIELD_EXIT* macros).
3015
3016 lw $t8, 0($t8) # $t8 = reference.
3017 UNPOISON_HEAP_REF $t8
3018
3019 // Return if null reference.
3020 bnez $t8, .Lintrospection_common
3021 addu $gp, $gp, $at # $gp = address of the exit point.
3022
3023 // Early return through the exit point.
3024.Lintrospection_return_early:
3025 jalr $zero, $gp # Move $t8 to `out` and return.
3026 nop
3027
3028 // Code common for GC roots, fields and array elements.
3029
3030.Lintrospection_common:
3031 // Check lock word for mark bit, if marked return.
3032 lw $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET($t8)
3033 sll $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT # Move mark bit to sign bit.
3034 bltz $at, .Lintrospection_return_early
3035#if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
3036 // The below code depends on the lock word state being in the highest bits
3037 // and the "forwarding address" state having all bits set.
3038#error "Unexpected lock word state shift or forwarding address state value."
3039#endif
3040 // Test that both the forwarding state bits are 1.
3041 sll $at, $t9, 1
3042 and $at, $at, $t9 # Sign bit = 1 IFF both bits are 1.
3043 bgez $at, .Lintrospection_mark
3044 nop
3045
3046 .set pop
3047
3048 // Shift left by the forwarding address shift. This clears out the state bits since they are
3049 // in the top 2 bits of the lock word.
3050 jalr $zero, $gp # Move $t8 to `out` and return.
3051 sll $t8, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
3052
3053.Lintrospection_mark:
3054 // Partially set up the stack frame preserving only $ra.
3055 addiu $sp, $sp, -160 # Includes 16 bytes of space for argument registers $a0-$a3.
3056 .cfi_adjust_cfa_offset 160
3057 sw $ra, 156($sp)
3058 .cfi_rel_offset 31, 156
3059
3060 // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
3061 bal 1f
3062 sw $gp, 152($sp) # Preserve the exit point address.
30631:
3064 .cpload $ra
3065
3066 // Finalize the stack frame and call.
3067 sw $t7, 148($sp)
3068 .cfi_rel_offset 15, 148
3069 sw $t6, 144($sp)
3070 .cfi_rel_offset 14, 144
3071 sw $t5, 140($sp)
3072 .cfi_rel_offset 13, 140
3073 sw $t4, 136($sp)
3074 .cfi_rel_offset 12, 136
3075 sw $t3, 132($sp)
3076 .cfi_rel_offset 11, 132
3077 sw $t2, 128($sp)
3078 .cfi_rel_offset 10, 128
3079 sw $t1, 124($sp)
3080 .cfi_rel_offset 9, 124
3081 sw $t0, 120($sp)
3082 .cfi_rel_offset 8, 120
3083 sw $a3, 116($sp)
3084 .cfi_rel_offset 7, 116
3085 sw $a2, 112($sp)
3086 .cfi_rel_offset 6, 112
3087 sw $a1, 108($sp)
3088 .cfi_rel_offset 5, 108
3089 sw $a0, 104($sp)
3090 .cfi_rel_offset 4, 104
3091 sw $v1, 100($sp)
3092 .cfi_rel_offset 3, 100
3093 sw $v0, 96($sp)
3094 .cfi_rel_offset 2, 96
3095
3096 la $t9, artReadBarrierMark
3097
3098 sdc1 $f18, 88($sp)
3099 sdc1 $f16, 80($sp)
3100 sdc1 $f14, 72($sp)
3101 sdc1 $f12, 64($sp)
3102 sdc1 $f10, 56($sp)
3103 sdc1 $f8, 48($sp)
3104 sdc1 $f6, 40($sp)
3105 sdc1 $f4, 32($sp)
3106 sdc1 $f2, 24($sp)
3107 sdc1 $f0, 16($sp)
3108
3109 jalr $t9 # $v0 <- artReadBarrierMark(reference)
3110 move $a0, $t8 # Pass reference in $a0.
3111 move $t8, $v0
3112
3113 lw $ra, 156($sp)
3114 .cfi_restore 31
3115 lw $gp, 152($sp) # $gp = address of the exit point.
3116 lw $t7, 148($sp)
3117 .cfi_restore 15
3118 lw $t6, 144($sp)
3119 .cfi_restore 14
3120 lw $t5, 140($sp)
3121 .cfi_restore 13
3122 lw $t4, 136($sp)
3123 .cfi_restore 12
3124 lw $t3, 132($sp)
3125 .cfi_restore 11
3126 lw $t2, 128($sp)
3127 .cfi_restore 10
3128 lw $t1, 124($sp)
3129 .cfi_restore 9
3130 lw $t0, 120($sp)
3131 .cfi_restore 8
3132 lw $a3, 116($sp)
3133 .cfi_restore 7
3134 lw $a2, 112($sp)
3135 .cfi_restore 6
3136 lw $a1, 108($sp)
3137 .cfi_restore 5
3138 lw $a0, 104($sp)
3139 .cfi_restore 4
3140 lw $v1, 100($sp)
3141 .cfi_restore 3
3142 lw $v0, 96($sp)
3143 .cfi_restore 2
3144
3145 ldc1 $f18, 88($sp)
3146 ldc1 $f16, 80($sp)
3147 ldc1 $f14, 72($sp)
3148 ldc1 $f12, 64($sp)
3149 ldc1 $f10, 56($sp)
3150 ldc1 $f8, 48($sp)
3151 ldc1 $f6, 40($sp)
3152 ldc1 $f4, 32($sp)
3153 ldc1 $f2, 24($sp)
3154 ldc1 $f0, 16($sp)
3155
3156 // Return through the exit point.
3157 jalr $zero, $gp # Move $t8 to `out` and return.
3158 addiu $sp, $sp, 160
3159 .cfi_adjust_cfa_offset -160
3160
3161.Lintrospection_exits:
3162 BRB_FIELD_EXIT_BREAK
3163 BRB_FIELD_EXIT_BREAK
3164 BRB_FIELD_EXIT $v0
3165 BRB_FIELD_EXIT $v1
3166 BRB_FIELD_EXIT $a0
3167 BRB_FIELD_EXIT $a1
3168 BRB_FIELD_EXIT $a2
3169 BRB_FIELD_EXIT $a3
3170 BRB_FIELD_EXIT $t0
3171 BRB_FIELD_EXIT $t1
3172 BRB_FIELD_EXIT $t2
3173 BRB_FIELD_EXIT $t3
3174 BRB_FIELD_EXIT $t4
3175 BRB_FIELD_EXIT $t5
3176 BRB_FIELD_EXIT $t6
3177 BRB_FIELD_EXIT $t7
3178 BRB_FIELD_EXIT_BREAK
3179 BRB_FIELD_EXIT_BREAK
3180 BRB_FIELD_EXIT $s2
3181 BRB_FIELD_EXIT $s3
3182 BRB_FIELD_EXIT $s4
3183 BRB_FIELD_EXIT $s5
3184 BRB_FIELD_EXIT $s6
3185 BRB_FIELD_EXIT $s7
3186 BRB_FIELD_EXIT_BREAK
3187 BRB_FIELD_EXIT_BREAK
3188 BRB_FIELD_EXIT_BREAK
3189 BRB_FIELD_EXIT_BREAK
3190 BRB_FIELD_EXIT_BREAK
3191 BRB_FIELD_EXIT_BREAK
3192 BRB_FIELD_EXIT $s8
3193 BRB_FIELD_EXIT_BREAK
3194END art_quick_read_barrier_mark_introspection
3195
Orion Hodsonac141392017-01-13 11:53:47 +00003196.extern artInvokePolymorphic
3197ENTRY art_quick_invoke_polymorphic
3198 SETUP_SAVE_REFS_AND_ARGS_FRAME
3199 move $a2, rSELF # Make $a2 an alias for the current Thread.
Alexey Frunzec480b982017-01-16 19:03:21 -08003200 addiu $a3, $sp, ARG_SLOT_SIZE # Make $a3 a pointer to the saved frame context.
Orion Hodsonac141392017-01-13 11:53:47 +00003201 sw $zero, 20($sp) # Initialize JValue result.
3202 sw $zero, 16($sp)
Orion Hodsonac141392017-01-13 11:53:47 +00003203 la $t9, artInvokePolymorphic
3204 jalr $t9 # (result, receiver, Thread*, context)
Alexey Frunzec480b982017-01-16 19:03:21 -08003205 addiu $a0, $sp, 16 # Make $a0 a pointer to the JValue result
Orion Hodsonac141392017-01-13 11:53:47 +00003206.macro MATCH_RETURN_TYPE c, handler
3207 li $t0, \c
3208 beq $v0, $t0, \handler
3209.endm
3210 MATCH_RETURN_TYPE 'V', .Lcleanup_and_return
3211 MATCH_RETURN_TYPE 'L', .Lstore_int_result
3212 MATCH_RETURN_TYPE 'I', .Lstore_int_result
3213 MATCH_RETURN_TYPE 'J', .Lstore_long_result
3214 MATCH_RETURN_TYPE 'B', .Lstore_int_result
3215 MATCH_RETURN_TYPE 'C', .Lstore_char_result
3216 MATCH_RETURN_TYPE 'D', .Lstore_double_result
3217 MATCH_RETURN_TYPE 'F', .Lstore_float_result
3218 MATCH_RETURN_TYPE 'S', .Lstore_int_result
Alexey Frunzec480b982017-01-16 19:03:21 -08003219 MATCH_RETURN_TYPE 'Z', .Lstore_boolean_result
Orion Hodsonac141392017-01-13 11:53:47 +00003220.purgem MATCH_RETURN_TYPE
3221 nop
3222 b .Lcleanup_and_return
3223 nop
3224.Lstore_boolean_result:
Alexey Frunzec480b982017-01-16 19:03:21 -08003225 b .Lcleanup_and_return
Orion Hodsonac141392017-01-13 11:53:47 +00003226 lbu $v0, 16($sp) # Move byte from JValue result to return value register.
Orion Hodsonac141392017-01-13 11:53:47 +00003227.Lstore_char_result:
Orion Hodsonac141392017-01-13 11:53:47 +00003228 b .Lcleanup_and_return
Alexey Frunzec480b982017-01-16 19:03:21 -08003229 lhu $v0, 16($sp) # Move char from JValue result to return value register.
Orion Hodsonac141392017-01-13 11:53:47 +00003230.Lstore_double_result:
3231.Lstore_float_result:
3232 LDu $f0, $f1, 16, $sp, $t0 # Move double/float from JValue result to return value register.
3233 b .Lcleanup_and_return
3234 nop
3235.Lstore_long_result:
3236 lw $v1, 20($sp) # Move upper bits from JValue result to return value register.
3237 // Fall-through for lower bits.
3238.Lstore_int_result:
3239 lw $v0, 16($sp) # Move lower bits from JValue result to return value register.
3240 // Fall-through to clean up and return.
3241.Lcleanup_and_return:
Orion Hodsonac141392017-01-13 11:53:47 +00003242 lw $t7, THREAD_EXCEPTION_OFFSET(rSELF) # Load Thread::Current()->exception_
3243 RESTORE_SAVE_REFS_AND_ARGS_FRAME
3244 bnez $t7, 1f # Success if no exception is pending.
3245 nop
3246 jalr $zero, $ra
3247 nop
32481:
3249 DELIVER_PENDING_EXCEPTION
3250END art_quick_invoke_polymorphic