blob: d9abaa05ec5c76408b87157b61572888daa1f64d [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 /*
168 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100169 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs).
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800170 * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
171 * (26 total + 1 word padding + method*)
buzbee5bc5a7b2012-03-07 15:52:59 -0800172 */
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100173.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800174 addiu $sp, $sp, -112
175 .cfi_adjust_cfa_offset 112
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700176
177 // Ugly compile-time check, but we only have the preprocessor.
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800178#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 112)
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100179#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(MIPS) size not as expected."
Andreas Gampe5c1e4352014-04-21 19:28:24 -0700180#endif
181
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800182 sw $ra, 108($sp)
183 .cfi_rel_offset 31, 108
184 sw $s8, 104($sp)
185 .cfi_rel_offset 30, 104
186 sw $gp, 100($sp)
187 .cfi_rel_offset 28, 100
188 sw $s7, 96($sp)
189 .cfi_rel_offset 23, 96
190 sw $s6, 92($sp)
191 .cfi_rel_offset 22, 92
192 sw $s5, 88($sp)
193 .cfi_rel_offset 21, 88
194 sw $s4, 84($sp)
195 .cfi_rel_offset 20, 84
196 sw $s3, 80($sp)
197 .cfi_rel_offset 19, 80
198 sw $s2, 76($sp)
199 .cfi_rel_offset 18, 76
200 sw $t1, 72($sp)
201 .cfi_rel_offset 9, 72
202 sw $t0, 68($sp)
203 .cfi_rel_offset 8, 68
204 sw $a3, 64($sp)
205 .cfi_rel_offset 7, 64
206 sw $a2, 60($sp)
207 .cfi_rel_offset 6, 60
208 sw $a1, 56($sp)
209 .cfi_rel_offset 5, 56
210 SDu $f18, $f19, 48, $sp, $t8
211 SDu $f16, $f17, 40, $sp, $t8
212 SDu $f14, $f15, 32, $sp, $t8
213 SDu $f12, $f13, 24, $sp, $t8
214 SDu $f10, $f11, 16, $sp, $t8
215 SDu $f8, $f9, 8, $sp, $t8
jeffhaofa147e22012-10-12 17:03:32 -0700216 # bottom will hold Method*
Douglas Leung735b8552014-10-31 12:21:40 -0700217.endm
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700218
Douglas Leung735b8552014-10-31 12:21:40 -0700219 /*
220 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100221 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800222 * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
223 * (26 total + 1 word padding + method*)
Douglas Leung735b8552014-10-31 12:21:40 -0700224 * Clobbers $t0 and $sp
225 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100226 * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
Douglas Leung735b8552014-10-31 12:21:40 -0700227 */
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100228.macro SETUP_SAVE_REFS_AND_ARGS_FRAME
229 SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
Douglas Leung4af77b72014-10-22 16:32:28 -0700230 lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
231 lw $t0, 0($t0)
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100232 lw $t0, RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET($t0)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700233 sw $t0, 0($sp) # Place Method* at bottom of stack.
234 sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame.
Douglas Leung735b8552014-10-31 12:21:40 -0700235 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
236 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
237.endm
238
239 /*
240 * Macro that sets up the callee save frame to conform with
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100241 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800242 * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
243 * (26 total + 1 word padding + method*)
Douglas Leung735b8552014-10-31 12:21:40 -0700244 * Clobbers $sp
245 * Use $a0 as the Method* and loads it into bottom of stack.
246 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100247 * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
Douglas Leung735b8552014-10-31 12:21:40 -0700248 */
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100249.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
250 SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
Douglas Leung735b8552014-10-31 12:21:40 -0700251 sw $a0, 0($sp) # Place Method* at bottom of stack.
252 sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame.
253 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
254 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
buzbee5bc5a7b2012-03-07 15:52:59 -0800255.endm
256
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100257.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -0700258 addiu $sp, $sp, ARG_SLOT_SIZE # remove argument slots on the stack
259 .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800260 lw $ra, 108($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800261 .cfi_restore 31
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800262 lw $s8, 104($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800263 .cfi_restore 30
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800264 lw $gp, 100($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800265 .cfi_restore 28
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800266 lw $s7, 96($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800267 .cfi_restore 23
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800268 lw $s6, 92($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800269 .cfi_restore 22
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800270 lw $s5, 88($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800271 .cfi_restore 21
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800272 lw $s4, 84($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800273 .cfi_restore 20
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800274 lw $s3, 80($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800275 .cfi_restore 19
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800276 lw $s2, 76($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800277 .cfi_restore 18
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800278 lw $t1, 72($sp)
279 .cfi_restore 9
280 lw $t0, 68($sp)
281 .cfi_restore 8
282 lw $a3, 64($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800283 .cfi_restore 7
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800284 lw $a2, 60($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800285 .cfi_restore 6
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800286 lw $a1, 56($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -0800287 .cfi_restore 5
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800288 LDu $f18, $f19, 48, $sp, $t8
289 LDu $f16, $f17, 40, $sp, $t8
290 LDu $f14, $f15, 32, $sp, $t8
291 LDu $f12, $f13, 24, $sp, $t8
292 LDu $f10, $f11, 16, $sp, $t8
293 LDu $f8, $f9, 8, $sp, $t8
294 addiu $sp, $sp, 112 # pop frame
295 .cfi_adjust_cfa_offset -112
buzbee5bc5a7b2012-03-07 15:52:59 -0800296.endm
297
298 /*
Vladimir Marko952dbb12016-07-28 12:01:51 +0100299 * Macro that sets up the callee save frame to conform with
300 * Runtime::CreateCalleeSaveMethod(kSaveEverything).
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000301 * when the $sp has already been decremented by FRAME_SIZE_SAVE_EVERYTHING.
Vladimir Marko952dbb12016-07-28 12:01:51 +0100302 * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
303 * 28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
304 * Clobbers $t0 and $t1.
305 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100306 * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
Vladimir Marko952dbb12016-07-28 12:01:51 +0100307 * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
308 */
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000309.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
Vladimir Marko952dbb12016-07-28 12:01:51 +0100310 // Ugly compile-time check, but we only have the preprocessor.
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100311#if (FRAME_SIZE_SAVE_EVERYTHING != 256)
312#error "FRAME_SIZE_SAVE_EVERYTHING(MIPS) size not as expected."
Vladimir Marko952dbb12016-07-28 12:01:51 +0100313#endif
314
315 sw $ra, 252($sp)
316 .cfi_rel_offset 31, 252
317 sw $fp, 248($sp)
318 .cfi_rel_offset 30, 248
319 sw $gp, 244($sp)
320 .cfi_rel_offset 28, 244
321 sw $t9, 240($sp)
322 .cfi_rel_offset 25, 240
323 sw $t8, 236($sp)
324 .cfi_rel_offset 24, 236
325 sw $s7, 232($sp)
326 .cfi_rel_offset 23, 232
327 sw $s6, 228($sp)
328 .cfi_rel_offset 22, 228
329 sw $s5, 224($sp)
330 .cfi_rel_offset 21, 224
331 sw $s4, 220($sp)
332 .cfi_rel_offset 20, 220
333 sw $s3, 216($sp)
334 .cfi_rel_offset 19, 216
335 sw $s2, 212($sp)
336 .cfi_rel_offset 18, 212
337 sw $s1, 208($sp)
338 .cfi_rel_offset 17, 208
339 sw $s0, 204($sp)
340 .cfi_rel_offset 16, 204
341 sw $t7, 200($sp)
342 .cfi_rel_offset 15, 200
343 sw $t6, 196($sp)
344 .cfi_rel_offset 14, 196
345 sw $t5, 192($sp)
346 .cfi_rel_offset 13, 192
347 sw $t4, 188($sp)
348 .cfi_rel_offset 12, 188
349 sw $t3, 184($sp)
350 .cfi_rel_offset 11, 184
351 sw $t2, 180($sp)
352 .cfi_rel_offset 10, 180
353 sw $t1, 176($sp)
354 .cfi_rel_offset 9, 176
355 sw $t0, 172($sp)
356 .cfi_rel_offset 8, 172
357 sw $a3, 168($sp)
358 .cfi_rel_offset 7, 168
359 sw $a2, 164($sp)
360 .cfi_rel_offset 6, 164
361 sw $a1, 160($sp)
362 .cfi_rel_offset 5, 160
363 sw $a0, 156($sp)
364 .cfi_rel_offset 4, 156
365 sw $v1, 152($sp)
366 .cfi_rel_offset 3, 152
367 sw $v0, 148($sp)
368 .cfi_rel_offset 2, 148
369
370 // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
371 bal 1f
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200372 .set push
373 .set noat
Vladimir Marko952dbb12016-07-28 12:01:51 +0100374 sw $at, 144($sp)
375 .cfi_rel_offset 1, 144
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200376 .set pop
Vladimir Marko952dbb12016-07-28 12:01:51 +01003771:
378 .cpload $ra
379
380 SDu $f30, $f31, 136, $sp, $t1
381 SDu $f28, $f29, 128, $sp, $t1
382 SDu $f26, $f27, 120, $sp, $t1
383 SDu $f24, $f25, 112, $sp, $t1
384 SDu $f22, $f23, 104, $sp, $t1
385 SDu $f20, $f21, 96, $sp, $t1
386 SDu $f18, $f19, 88, $sp, $t1
387 SDu $f16, $f17, 80, $sp, $t1
388 SDu $f14, $f15, 72, $sp, $t1
389 SDu $f12, $f13, 64, $sp, $t1
390 SDu $f10, $f11, 56, $sp, $t1
391 SDu $f8, $f9, 48, $sp, $t1
392 SDu $f6, $f7, 40, $sp, $t1
393 SDu $f4, $f5, 32, $sp, $t1
394 SDu $f2, $f3, 24, $sp, $t1
395 SDu $f0, $f1, 16, $sp, $t1
396
397 # 3 words padding and 1 word for holding Method*
398
399 lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
400 lw $t0, 0($t0)
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100401 lw $t0, RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET($t0)
Vladimir Marko952dbb12016-07-28 12:01:51 +0100402 sw $t0, 0($sp) # Place Method* at bottom of stack.
403 sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF) # Place sp in Thread::Current()->top_quick_frame.
404 addiu $sp, $sp, -ARG_SLOT_SIZE # reserve argument slots on the stack
405 .cfi_adjust_cfa_offset ARG_SLOT_SIZE
406.endm
407
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000408 /*
409 * Macro that sets up the callee save frame to conform with
410 * Runtime::CreateCalleeSaveMethod(kSaveEverything).
411 * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
412 * 28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
413 * Clobbers $t0 and $t1.
414 * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
415 * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
416 * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
417 */
418.macro SETUP_SAVE_EVERYTHING_FRAME
419 addiu $sp, $sp, -(FRAME_SIZE_SAVE_EVERYTHING)
420 .cfi_adjust_cfa_offset (FRAME_SIZE_SAVE_EVERYTHING)
421 SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
422.endm
423
Alexey Frunzec61c0762017-04-10 13:54:23 -0700424.macro RESTORE_SAVE_EVERYTHING_FRAME restore_a0=1
Vladimir Marko952dbb12016-07-28 12:01:51 +0100425 addiu $sp, $sp, ARG_SLOT_SIZE # remove argument slots on the stack
426 .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
427
428 LDu $f30, $f31, 136, $sp, $t1
429 LDu $f28, $f29, 128, $sp, $t1
430 LDu $f26, $f27, 120, $sp, $t1
431 LDu $f24, $f25, 112, $sp, $t1
432 LDu $f22, $f23, 104, $sp, $t1
433 LDu $f20, $f21, 96, $sp, $t1
434 LDu $f18, $f19, 88, $sp, $t1
435 LDu $f16, $f17, 80, $sp, $t1
436 LDu $f14, $f15, 72, $sp, $t1
437 LDu $f12, $f13, 64, $sp, $t1
438 LDu $f10, $f11, 56, $sp, $t1
439 LDu $f8, $f9, 48, $sp, $t1
440 LDu $f6, $f7, 40, $sp, $t1
441 LDu $f4, $f5, 32, $sp, $t1
442 LDu $f2, $f3, 24, $sp, $t1
443 LDu $f0, $f1, 16, $sp, $t1
444
445 lw $ra, 252($sp)
446 .cfi_restore 31
447 lw $fp, 248($sp)
448 .cfi_restore 30
449 lw $gp, 244($sp)
450 .cfi_restore 28
451 lw $t9, 240($sp)
452 .cfi_restore 25
453 lw $t8, 236($sp)
454 .cfi_restore 24
455 lw $s7, 232($sp)
456 .cfi_restore 23
457 lw $s6, 228($sp)
458 .cfi_restore 22
459 lw $s5, 224($sp)
460 .cfi_restore 21
461 lw $s4, 220($sp)
462 .cfi_restore 20
463 lw $s3, 216($sp)
464 .cfi_restore 19
465 lw $s2, 212($sp)
466 .cfi_restore 18
467 lw $s1, 208($sp)
468 .cfi_restore 17
469 lw $s0, 204($sp)
470 .cfi_restore 16
471 lw $t7, 200($sp)
472 .cfi_restore 15
473 lw $t6, 196($sp)
474 .cfi_restore 14
475 lw $t5, 192($sp)
476 .cfi_restore 13
477 lw $t4, 188($sp)
478 .cfi_restore 12
479 lw $t3, 184($sp)
480 .cfi_restore 11
481 lw $t2, 180($sp)
482 .cfi_restore 10
483 lw $t1, 176($sp)
484 .cfi_restore 9
485 lw $t0, 172($sp)
486 .cfi_restore 8
487 lw $a3, 168($sp)
488 .cfi_restore 7
489 lw $a2, 164($sp)
490 .cfi_restore 6
491 lw $a1, 160($sp)
492 .cfi_restore 5
Alexey Frunzec61c0762017-04-10 13:54:23 -0700493 .if \restore_a0
Vladimir Marko952dbb12016-07-28 12:01:51 +0100494 lw $a0, 156($sp)
495 .cfi_restore 4
Alexey Frunzec61c0762017-04-10 13:54:23 -0700496 .endif
Vladimir Marko952dbb12016-07-28 12:01:51 +0100497 lw $v1, 152($sp)
498 .cfi_restore 3
499 lw $v0, 148($sp)
500 .cfi_restore 2
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200501 .set push
502 .set noat
Vladimir Marko952dbb12016-07-28 12:01:51 +0100503 lw $at, 144($sp)
504 .cfi_restore 1
Goran Jakovljevic2e42cf12016-08-09 15:15:39 +0200505 .set pop
Vladimir Marko952dbb12016-07-28 12:01:51 +0100506
507 addiu $sp, $sp, 256 # pop frame
508 .cfi_adjust_cfa_offset -256
509.endm
510
511 /*
Alexey Frunzec61c0762017-04-10 13:54:23 -0700512 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
513 * exception is Thread::Current()->exception_ when the runtime method frame is ready.
514 * Requires $gp properly set up.
buzbee5bc5a7b2012-03-07 15:52:59 -0800515 */
Alexey Frunzec61c0762017-04-10 13:54:23 -0700516.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
jeffhao8161c032012-10-31 15:50:00 -0700517 la $t9, artDeliverPendingExceptionFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800518 jalr $zero, $t9 # artDeliverPendingExceptionFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700519 move $a0, rSELF # pass Thread::Current
buzbee5bc5a7b2012-03-07 15:52:59 -0800520.endm
521
Alexey Frunzec61c0762017-04-10 13:54:23 -0700522 /*
523 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
524 * exception is Thread::Current()->exception_.
525 * Requires $gp properly set up.
526 */
527.macro DELIVER_PENDING_EXCEPTION
528 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME # save callee saves for throw
529 DELIVER_PENDING_EXCEPTION_FRAME_READY
530.endm
531
buzbee5bc5a7b2012-03-07 15:52:59 -0800532.macro RETURN_IF_NO_EXCEPTION
jeffhao7fbee072012-08-24 17:56:54 -0700533 lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100534 RESTORE_SAVE_REFS_ONLY_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700535 bnez $t0, 1f # success if no exception is pending
buzbee5bc5a7b2012-03-07 15:52:59 -0800536 nop
Andreas Gampe8d365912015-01-13 11:32:32 -0800537 jalr $zero, $ra
buzbee5bc5a7b2012-03-07 15:52:59 -0800538 nop
5391:
540 DELIVER_PENDING_EXCEPTION
541.endm
542
543.macro RETURN_IF_ZERO
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100544 RESTORE_SAVE_REFS_ONLY_FRAME
jeffhao7fbee072012-08-24 17:56:54 -0700545 bnez $v0, 1f # success?
buzbee5bc5a7b2012-03-07 15:52:59 -0800546 nop
Andreas Gampe8d365912015-01-13 11:32:32 -0800547 jalr $zero, $ra # return on success
buzbee5bc5a7b2012-03-07 15:52:59 -0800548 nop
5491:
550 DELIVER_PENDING_EXCEPTION
551.endm
552
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800553.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100554 RESTORE_SAVE_REFS_ONLY_FRAME
jeffhao7fbee072012-08-24 17:56:54 -0700555 beqz $v0, 1f # success?
buzbee5bc5a7b2012-03-07 15:52:59 -0800556 nop
Andreas Gampe8d365912015-01-13 11:32:32 -0800557 jalr $zero, $ra # return on success
buzbee5bc5a7b2012-03-07 15:52:59 -0800558 nop
5591:
560 DELIVER_PENDING_EXCEPTION
561.endm
562
buzbee5bc5a7b2012-03-07 15:52:59 -0800563 /*
Goran Jakovljevic3bc13812016-03-22 17:16:05 +0100564 * On stack replacement stub.
565 * On entry:
566 * a0 = stack to copy
567 * a1 = size of stack
568 * a2 = pc to call
569 * a3 = JValue* result
570 * [sp + 16] = shorty
571 * [sp + 20] = thread
572 */
573ENTRY art_quick_osr_stub
574 // Save callee general purpose registers, RA and GP.
575 addiu $sp, $sp, -48
576 .cfi_adjust_cfa_offset 48
577 sw $ra, 44($sp)
578 .cfi_rel_offset 31, 44
579 sw $s8, 40($sp)
580 .cfi_rel_offset 30, 40
581 sw $gp, 36($sp)
582 .cfi_rel_offset 28, 36
583 sw $s7, 32($sp)
584 .cfi_rel_offset 23, 32
585 sw $s6, 28($sp)
586 .cfi_rel_offset 22, 28
587 sw $s5, 24($sp)
588 .cfi_rel_offset 21, 24
589 sw $s4, 20($sp)
590 .cfi_rel_offset 20, 20
591 sw $s3, 16($sp)
592 .cfi_rel_offset 19, 16
593 sw $s2, 12($sp)
594 .cfi_rel_offset 18, 12
595 sw $s1, 8($sp)
596 .cfi_rel_offset 17, 8
597 sw $s0, 4($sp)
598 .cfi_rel_offset 16, 4
599
600 move $s8, $sp # Save the stack pointer
601 move $s7, $a1 # Save size of stack
602 move $s6, $a2 # Save the pc to call
603 lw rSELF, 48+20($sp) # Save managed thread pointer into rSELF
604 addiu $t0, $sp, -12 # Reserve space for stack pointer,
605 # JValue* result, and ArtMethod* slot.
606 srl $t0, $t0, 4 # Align stack pointer to 16 bytes
607 sll $sp, $t0, 4 # Update stack pointer
608 sw $s8, 4($sp) # Save old stack pointer
609 sw $a3, 8($sp) # Save JValue* result
610 sw $zero, 0($sp) # Store null for ArtMethod* at bottom of frame
611 subu $sp, $a1 # Reserve space for callee stack
612 move $a2, $a1
613 move $a1, $a0
614 move $a0, $sp
615 la $t9, memcpy
616 jalr $t9 # memcpy (dest a0, src a1, bytes a2)
617 addiu $sp, $sp, -16 # make space for argument slots for memcpy
618 bal .Losr_entry # Call the method
619 addiu $sp, $sp, 16 # restore stack after memcpy
620 lw $a2, 8($sp) # Restore JValue* result
621 lw $sp, 4($sp) # Restore saved stack pointer
622 lw $a0, 48+16($sp) # load shorty
623 lbu $a0, 0($a0) # load return type
624 li $a1, 'D' # put char 'D' into a1
625 beq $a0, $a1, .Losr_fp_result # Test if result type char == 'D'
626 li $a1, 'F' # put char 'F' into a1
627 beq $a0, $a1, .Losr_fp_result # Test if result type char == 'F'
628 nop
629 sw $v0, 0($a2)
630 b .Losr_exit
631 sw $v1, 4($a2) # store v0/v1 into result
632.Losr_fp_result:
633 SDu $f0, $f1, 0, $a2, $t0 # store f0/f1 into result
634.Losr_exit:
635 lw $ra, 44($sp)
636 .cfi_restore 31
637 lw $s8, 40($sp)
638 .cfi_restore 30
639 lw $gp, 36($sp)
640 .cfi_restore 28
641 lw $s7, 32($sp)
642 .cfi_restore 23
643 lw $s6, 28($sp)
644 .cfi_restore 22
645 lw $s5, 24($sp)
646 .cfi_restore 21
647 lw $s4, 20($sp)
648 .cfi_restore 20
649 lw $s3, 16($sp)
650 .cfi_restore 19
651 lw $s2, 12($sp)
652 .cfi_restore 18
653 lw $s1, 8($sp)
654 .cfi_restore 17
655 lw $s0, 4($sp)
656 .cfi_restore 16
657 jalr $zero, $ra
658 addiu $sp, $sp, 48
659 .cfi_adjust_cfa_offset -48
660.Losr_entry:
661 addiu $s7, $s7, -4
662 addu $t0, $s7, $sp
663 move $t9, $s6
664 jalr $zero, $t9
665 sw $ra, 0($t0) # Store RA per the compiler ABI
666END art_quick_osr_stub
667
668 /*
jeffhao7fbee072012-08-24 17:56:54 -0700669 * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_
buzbee5bc5a7b2012-03-07 15:52:59 -0800670 * FIXME: just guessing about the shape of the jmpbuf. Where will pc be?
671 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800672ENTRY art_quick_do_long_jump
Duane Sande34652f2014-11-04 11:09:36 -0800673 LDu $f0, $f1, 0*8, $a1, $t1
674 LDu $f2, $f3, 1*8, $a1, $t1
675 LDu $f4, $f5, 2*8, $a1, $t1
676 LDu $f6, $f7, 3*8, $a1, $t1
677 LDu $f8, $f9, 4*8, $a1, $t1
678 LDu $f10, $f11, 5*8, $a1, $t1
679 LDu $f12, $f13, 6*8, $a1, $t1
680 LDu $f14, $f15, 7*8, $a1, $t1
681 LDu $f16, $f17, 8*8, $a1, $t1
682 LDu $f18, $f19, 9*8, $a1, $t1
683 LDu $f20, $f21, 10*8, $a1, $t1
684 LDu $f22, $f23, 11*8, $a1, $t1
685 LDu $f24, $f25, 12*8, $a1, $t1
686 LDu $f26, $f27, 13*8, $a1, $t1
687 LDu $f28, $f29, 14*8, $a1, $t1
688 LDu $f30, $f31, 15*8, $a1, $t1
689
Chris Dearman748dd952014-05-23 10:47:01 -0700690 .set push
691 .set nomacro
692 .set noat
jeffhao7fbee072012-08-24 17:56:54 -0700693 lw $at, 4($a0)
Chris Dearman748dd952014-05-23 10:47:01 -0700694 .set pop
jeffhao7fbee072012-08-24 17:56:54 -0700695 lw $v0, 8($a0)
696 lw $v1, 12($a0)
697 lw $a1, 20($a0)
698 lw $a2, 24($a0)
699 lw $a3, 28($a0)
700 lw $t0, 32($a0)
701 lw $t1, 36($a0)
702 lw $t2, 40($a0)
703 lw $t3, 44($a0)
704 lw $t4, 48($a0)
705 lw $t5, 52($a0)
706 lw $t6, 56($a0)
707 lw $t7, 60($a0)
708 lw $s0, 64($a0)
709 lw $s1, 68($a0)
710 lw $s2, 72($a0)
711 lw $s3, 76($a0)
712 lw $s4, 80($a0)
713 lw $s5, 84($a0)
714 lw $s6, 88($a0)
715 lw $s7, 92($a0)
716 lw $t8, 96($a0)
717 lw $t9, 100($a0)
jeffhao7fbee072012-08-24 17:56:54 -0700718 lw $gp, 112($a0)
719 lw $sp, 116($a0)
720 lw $fp, 120($a0)
721 lw $ra, 124($a0)
722 lw $a0, 16($a0)
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100723 move $v0, $zero # clear result registers v0 and v1 (in branch delay slot)
Goran Jakovljevic75969962015-10-27 12:29:07 +0100724 jalr $zero, $t9 # do long jump
jeffhao7fbee072012-08-24 17:56:54 -0700725 move $v1, $zero
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800726END art_quick_do_long_jump
buzbee5bc5a7b2012-03-07 15:52:59 -0800727
buzbee5bc5a7b2012-03-07 15:52:59 -0800728 /*
729 * Called by managed code, saves most registers (forms basis of long jump context) and passes
730 * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
Lazar Trsic84bc06e2015-06-10 16:05:46 +0200731 * the bottom of the thread. On entry a0 holds Throwable*
buzbee5bc5a7b2012-03-07 15:52:59 -0800732 */
Ian Rogers468532e2013-08-05 10:56:33 -0700733ENTRY art_quick_deliver_exception
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100734 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700735 la $t9, artDeliverExceptionFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800736 jalr $zero, $t9 # artDeliverExceptionFromCode(Throwable*, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700737 move $a1, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700738END art_quick_deliver_exception
buzbee5bc5a7b2012-03-07 15:52:59 -0800739
buzbee5bc5a7b2012-03-07 15:52:59 -0800740 /*
741 * Called by managed code to create and deliver a NullPointerException
742 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800743 .extern artThrowNullPointerExceptionFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100744ENTRY_NO_GP art_quick_throw_null_pointer_exception
745 // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
746 // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
747 SETUP_SAVE_EVERYTHING_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700748 la $t9, artThrowNullPointerExceptionFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800749 jalr $zero, $t9 # artThrowNullPointerExceptionFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700750 move $a0, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700751END art_quick_throw_null_pointer_exception
buzbee5bc5a7b2012-03-07 15:52:59 -0800752
Nicolas Geoffraye8e11272016-06-28 18:08:46 +0100753
754 /*
755 * Call installed by a signal handler to create and deliver a NullPointerException.
756 */
757 .extern artThrowNullPointerExceptionFromSignal
Vladimir Marko3b7537b2016-09-13 11:56:01 +0000758ENTRY_NO_GP_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, FRAME_SIZE_SAVE_EVERYTHING
759 SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
760 # Retrieve the fault address from the padding where the signal handler stores it.
761 lw $a0, (ARG_SLOT_SIZE + __SIZEOF_POINTER__)($sp)
Nicolas Geoffraye8e11272016-06-28 18:08:46 +0100762 la $t9, artThrowNullPointerExceptionFromSignal
763 jalr $zero, $t9 # artThrowNullPointerExceptionFromSignal(uintptr_t, Thread*)
764 move $a1, rSELF # pass Thread::Current
765END art_quick_throw_null_pointer_exception_from_signal
766
buzbee5bc5a7b2012-03-07 15:52:59 -0800767 /*
768 * Called by managed code to create and deliver an ArithmeticException
769 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800770 .extern artThrowDivZeroFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100771ENTRY_NO_GP art_quick_throw_div_zero
772 SETUP_SAVE_EVERYTHING_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700773 la $t9, artThrowDivZeroFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800774 jalr $zero, $t9 # artThrowDivZeroFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700775 move $a0, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700776END art_quick_throw_div_zero
buzbee5bc5a7b2012-03-07 15:52:59 -0800777
buzbee5bc5a7b2012-03-07 15:52:59 -0800778 /*
779 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
780 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800781 .extern artThrowArrayBoundsFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100782ENTRY_NO_GP art_quick_throw_array_bounds
783 // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
784 // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
785 SETUP_SAVE_EVERYTHING_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700786 la $t9, artThrowArrayBoundsFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800787 jalr $zero, $t9 # artThrowArrayBoundsFromCode(index, limit, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700788 move $a2, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700789END art_quick_throw_array_bounds
buzbee5bc5a7b2012-03-07 15:52:59 -0800790
Ian Rogers57b86d42012-03-27 16:05:41 -0700791 /*
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100792 * Called by managed code to create and deliver a StringIndexOutOfBoundsException
793 * as if thrown from a call to String.charAt().
794 */
795 .extern artThrowStringBoundsFromCode
Vladimir Marko804b03f2016-09-14 16:26:36 +0100796ENTRY_NO_GP art_quick_throw_string_bounds
797 SETUP_SAVE_EVERYTHING_FRAME
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100798 la $t9, artThrowStringBoundsFromCode
799 jalr $zero, $t9 # artThrowStringBoundsFromCode(index, limit, Thread*)
800 move $a2, rSELF # pass Thread::Current
801END art_quick_throw_string_bounds
802
803 /*
Ian Rogers57b86d42012-03-27 16:05:41 -0700804 * Called by managed code to create and deliver a StackOverflowError.
805 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800806 .extern artThrowStackOverflowFromCode
Ian Rogers468532e2013-08-05 10:56:33 -0700807ENTRY art_quick_throw_stack_overflow
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100808 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
jeffhao8161c032012-10-31 15:50:00 -0700809 la $t9, artThrowStackOverflowFromCode
Andreas Gampe8d365912015-01-13 11:32:32 -0800810 jalr $zero, $t9 # artThrowStackOverflowFromCode(Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -0700811 move $a0, rSELF # pass Thread::Current
Ian Rogers468532e2013-08-05 10:56:33 -0700812END art_quick_throw_stack_overflow
buzbee5bc5a7b2012-03-07 15:52:59 -0800813
Ian Rogers57b86d42012-03-27 16:05:41 -0700814 /*
buzbee5bc5a7b2012-03-07 15:52:59 -0800815 * All generated callsites for interface invokes and invocation slow paths will load arguments
jeffhao7fbee072012-08-24 17:56:54 -0700816 * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100817 * the method_idx. This wrapper will save arg1-arg3, and call the appropriate C helper.
jeffhao7fbee072012-08-24 17:56:54 -0700818 * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
buzbee5bc5a7b2012-03-07 15:52:59 -0800819 *
jeffhao7fbee072012-08-24 17:56:54 -0700820 * The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting
821 * of the target Method* in $v0 and method->code_ in $v1.
buzbee5bc5a7b2012-03-07 15:52:59 -0800822 *
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700823 * If unsuccessful, the helper will return null/null. There will be a pending exception in the
buzbee5bc5a7b2012-03-07 15:52:59 -0800824 * thread and we branch to another stub to deliver it.
825 *
826 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
827 * pointing back to the original caller.
828 */
Andreas Gampe3031c8d2015-07-13 20:11:06 -0700829.macro INVOKE_TRAMPOLINE_BODY cxx_name
buzbee5bc5a7b2012-03-07 15:52:59 -0800830 .extern \cxx_name
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100831 SETUP_SAVE_REFS_AND_ARGS_FRAME # save callee saves in case allocation triggers GC
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100832 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100833 la $t9, \cxx_name
834 jalr $t9 # (method_idx, this, Thread*, $sp)
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100835 addiu $a3, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
836 move $a0, $v0 # save target Method*
Vladimir Markofd36f1f2016-08-03 18:49:58 +0100837 RESTORE_SAVE_REFS_AND_ARGS_FRAME
jeffhaofa147e22012-10-12 17:03:32 -0700838 beqz $v0, 1f
Nicolas Geoffray7ea6a172015-05-19 18:58:54 +0100839 move $t9, $v1 # save $v0->code_
Andreas Gampe8d365912015-01-13 11:32:32 -0800840 jalr $zero, $t9
buzbee5bc5a7b2012-03-07 15:52:59 -0800841 nop
8421:
843 DELIVER_PENDING_EXCEPTION
Andreas Gampe3031c8d2015-07-13 20:11:06 -0700844.endm
845.macro INVOKE_TRAMPOLINE c_name, cxx_name
846ENTRY \c_name
847 INVOKE_TRAMPOLINE_BODY \cxx_name
Jeff Haod4c3f7d2013-02-14 14:14:44 -0800848END \c_name
buzbee5bc5a7b2012-03-07 15:52:59 -0800849.endm
850
Logan Chien8dbb7082013-01-25 20:31:17 +0800851INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
buzbee5bc5a7b2012-03-07 15:52:59 -0800852
Logan Chien8dbb7082013-01-25 20:31:17 +0800853INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
854INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
855INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
856INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
buzbee5bc5a7b2012-03-07 15:52:59 -0800857
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800858// Each of the following macros expands into four instructions or 16 bytes.
859// They are used to build indexable "tables" of code.
860
861.macro LOAD_WORD_TO_REG reg, next_arg, index_reg, label
Goran Jakovljevicff734982015-08-24 12:58:55 +0000862 lw $\reg, -4($\next_arg) # next_arg points to argument after the current one (offset is 4)
863 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800864 addiu $\index_reg, 16
865 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000866.endm
867
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800868.macro LOAD_LONG_TO_REG reg1, reg2, next_arg, index_reg, next_index, label
Goran Jakovljevicff734982015-08-24 12:58:55 +0000869 lw $\reg1, -8($\next_arg) # next_arg points to argument after the current one (offset is 8)
870 lw $\reg2, -4($\next_arg)
871 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800872 li $\index_reg, \next_index
873 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000874.endm
875
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800876.macro LOAD_FLOAT_TO_REG reg, next_arg, index_reg, label
Goran Jakovljevicff734982015-08-24 12:58:55 +0000877 lwc1 $\reg, -4($\next_arg) # next_arg points to argument after the current one (offset is 4)
878 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800879 addiu $\index_reg, 16
880 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000881.endm
882
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800883#if defined(__mips_isa_rev) && __mips_isa_rev > 2
884// LDu expands into 3 instructions for 64-bit FPU, so index_reg cannot be updated here.
885.macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
886 .set reorder # force use of the branch delay slot
Goran Jakovljevicff734982015-08-24 12:58:55 +0000887 LDu $\reg1, $\reg2, -8, $\next_arg, $\tmp # next_arg points to argument after the current one
888 # (offset is 8)
889 b \label
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800890 .set noreorder
891 .balign 16
892.endm
893#else
894// LDu expands into 2 instructions for 32-bit FPU, so index_reg is updated here.
895.macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
896 LDu $\reg1, $\reg2, -8, $\next_arg, $\tmp # next_arg points to argument after the current one
897 # (offset is 8)
898 b \label
899 addiu $\index_reg, 16
900 .balign 16
901.endm
902#endif
903
904.macro LOAD_END index_reg, next_index, label
905 b \label
906 li $\index_reg, \next_index
907 .balign 16
Goran Jakovljevicff734982015-08-24 12:58:55 +0000908.endm
909
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100910#define SPILL_SIZE 32
911
Jeff Hao79fe5392013-04-24 18:41:58 -0700912 /*
Ian Rogersef7d42f2014-01-06 12:55:46 -0800913 * Invocation stub for quick code.
Jeff Hao5d917302013-02-27 17:57:33 -0800914 * On entry:
915 * a0 = method pointer
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700916 * a1 = argument array or null for no argument methods
Jeff Hao5d917302013-02-27 17:57:33 -0800917 * a2 = size of argument array in bytes
918 * a3 = (managed) thread pointer
Jeff Hao6474d192013-03-26 14:08:09 -0700919 * [sp + 16] = JValue* result
Ian Rogers0177e532014-02-11 16:30:46 -0800920 * [sp + 20] = shorty
Jeff Hao5d917302013-02-27 17:57:33 -0800921 */
922ENTRY art_quick_invoke_stub
Jeff Hao5d917302013-02-27 17:57:33 -0800923 sw $a0, 0($sp) # save out a0
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100924 addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
925 .cfi_adjust_cfa_offset SPILL_SIZE
926 sw $gp, 16($sp)
Jeff Hao5d917302013-02-27 17:57:33 -0800927 sw $ra, 12($sp)
928 .cfi_rel_offset 31, 12
929 sw $fp, 8($sp)
930 .cfi_rel_offset 30, 8
931 sw $s1, 4($sp)
932 .cfi_rel_offset 17, 4
933 sw $s0, 0($sp)
934 .cfi_rel_offset 16, 0
935 move $fp, $sp # save sp in fp
936 .cfi_def_cfa_register 30
937 move $s1, $a3 # move managed thread pointer into s1
938 addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval
Goran Jakovljevicff734982015-08-24 12:58:55 +0000939 addiu $t0, $a2, 4 # create space for ArtMethod* in frame.
Douglas Leung735b8552014-10-31 12:21:40 -0700940 subu $t0, $sp, $t0 # reserve & align *stack* to 16 bytes:
Goran Jakovljevicff734982015-08-24 12:58:55 +0000941 srl $t0, $t0, 4 # native calling convention only aligns to 8B,
942 sll $sp, $t0, 4 # so we have to ensure ART 16B alignment ourselves.
943 addiu $a0, $sp, 4 # pass stack pointer + ArtMethod* as dest for memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100944 la $t9, memcpy
945 jalr $t9 # (dest, src, bytes)
Jeff Hao5d917302013-02-27 17:57:33 -0800946 addiu $sp, $sp, -16 # make space for argument slots for memcpy
947 addiu $sp, $sp, 16 # restore stack after memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100948 lw $gp, 16($fp) # restore $gp
949 lw $a0, SPILL_SIZE($fp) # restore ArtMethod*
Goran Jakovljevicff734982015-08-24 12:58:55 +0000950 lw $a1, 4($sp) # a1 = this*
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800951 addiu $t8, $sp, 8 # t8 = pointer to the current argument (skip ArtMethod* and this*)
952 li $t6, 0 # t6 = gpr_index = 0 (corresponds to A2; A0 and A1 are skipped)
953 li $t7, 0 # t7 = fp_index = 0
954 lw $t9, 20 + SPILL_SIZE($fp) # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
Goran Jakovljevic590b1362016-03-21 14:24:43 +0100955 # as the $fp is SPILL_SIZE bytes below the $sp on entry)
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800956 addiu $t9, 1 # t9 = shorty + 1 (skip 1 for return type)
957
958 // Load the base addresses of tabInt ... tabDouble.
959 // We will use the register indices (gpr_index, fp_index) to branch.
960 // Note that the indices are scaled by 16, so they can be added to the bases directly.
961#if defined(__mips_isa_rev) && __mips_isa_rev >= 6
962 lapc $t2, tabInt
963 lapc $t3, tabLong
964 lapc $t4, tabSingle
965 lapc $t5, tabDouble
966#else
967 bltzal $zero, tabBase # nal
968 addiu $t2, $ra, %lo(tabInt - tabBase)
969tabBase:
970 addiu $t3, $ra, %lo(tabLong - tabBase)
971 addiu $t4, $ra, %lo(tabSingle - tabBase)
972 addiu $t5, $ra, %lo(tabDouble - tabBase)
973#endif
974
Goran Jakovljevicff734982015-08-24 12:58:55 +0000975loop:
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800976 lbu $ra, 0($t9) # ra = shorty[i]
977 beqz $ra, loopEnd # finish getting args when shorty[i] == '\0'
978 addiu $t9, 1
Goran Jakovljevicff734982015-08-24 12:58:55 +0000979
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800980 addiu $ra, -'J'
981 beqz $ra, isLong # branch if result type char == 'J'
982 addiu $ra, 'J' - 'D'
983 beqz $ra, isDouble # branch if result type char == 'D'
984 addiu $ra, 'D' - 'F'
985 beqz $ra, isSingle # branch if result type char == 'F'
Goran Jakovljevicff734982015-08-24 12:58:55 +0000986
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800987 addu $ra, $t2, $t6
988 jalr $zero, $ra
989 addiu $t8, 4 # next_arg = curr_arg + 4
Goran Jakovljevicff734982015-08-24 12:58:55 +0000990
991isLong:
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800992 addu $ra, $t3, $t6
993 jalr $zero, $ra
994 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +0000995
996isSingle:
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800997 addu $ra, $t4, $t7
998 jalr $zero, $ra
999 addiu $t8, 4 # next_arg = curr_arg + 4
1000
1001isDouble:
1002 addu $ra, $t5, $t7
1003#if defined(__mips_isa_rev) && __mips_isa_rev > 2
1004 addiu $t7, 16 # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
1005#endif
1006 jalr $zero, $ra
1007 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +00001008
1009loopEnd:
Mathieu Chartiere401d142015-04-22 13:56:20 -07001010 lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0) # get pointer to the code
Jeff Hao5d917302013-02-27 17:57:33 -08001011 jalr $t9 # call the method
Goran Jakovljevicff734982015-08-24 12:58:55 +00001012 sw $zero, 0($sp) # store null for ArtMethod* at bottom of frame
Jeff Hao5d917302013-02-27 17:57:33 -08001013 move $sp, $fp # restore the stack
1014 lw $s0, 0($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001015 .cfi_restore 16
Jeff Hao5d917302013-02-27 17:57:33 -08001016 lw $s1, 4($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001017 .cfi_restore 17
Jeff Hao5d917302013-02-27 17:57:33 -08001018 lw $fp, 8($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001019 .cfi_restore 30
Jeff Hao5d917302013-02-27 17:57:33 -08001020 lw $ra, 12($sp)
Dave Allisonbbb32c22013-11-05 18:25:18 -08001021 .cfi_restore 31
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001022 addiu $sp, $sp, SPILL_SIZE
1023 .cfi_adjust_cfa_offset -SPILL_SIZE
Jeff Hao5d917302013-02-27 17:57:33 -08001024 lw $t0, 16($sp) # get result pointer
Ian Rogers0177e532014-02-11 16:30:46 -08001025 lw $t1, 20($sp) # get shorty
1026 lb $t1, 0($t1) # get result type char
Goran Jakovljevicff734982015-08-24 12:58:55 +00001027 li $t2, 'D' # put char 'D' into t2
1028 beq $t1, $t2, 5f # branch if result type char == 'D'
1029 li $t3, 'F' # put char 'F' into t3
1030 beq $t1, $t3, 5f # branch if result type char == 'F'
Jeff Hao5d917302013-02-27 17:57:33 -08001031 sw $v0, 0($t0) # store the result
Andreas Gampe8d365912015-01-13 11:32:32 -08001032 jalr $zero, $ra
Jeff Hao5d917302013-02-27 17:57:33 -08001033 sw $v1, 4($t0) # store the other half of the result
Goran Jakovljevicff734982015-08-24 12:58:55 +000010345:
Duane Sande34652f2014-11-04 11:09:36 -08001035 SDu $f0, $f1, 0, $t0, $t1 # store floating point result
Andreas Gampe8d365912015-01-13 11:32:32 -08001036 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08001037 nop
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001038
1039 // Note that gpr_index is kept within the range of tabInt and tabLong
1040 // and fp_index is kept within the range of tabSingle and tabDouble.
1041 .balign 16
1042tabInt:
1043 LOAD_WORD_TO_REG a2, t8, t6, loop # a2 = current argument, gpr_index += 16
1044 LOAD_WORD_TO_REG a3, t8, t6, loop # a3 = current argument, gpr_index += 16
1045 LOAD_WORD_TO_REG t0, t8, t6, loop # t0 = current argument, gpr_index += 16
1046 LOAD_WORD_TO_REG t1, t8, t6, loop # t1 = current argument, gpr_index += 16
1047 LOAD_END t6, 4*16, loop # no more GPR args, gpr_index = 4*16
1048tabLong:
1049 LOAD_LONG_TO_REG a2, a3, t8, t6, 2*16, loop # a2_a3 = curr_arg, gpr_index = 2*16
1050 LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop # t0_t1 = curr_arg, gpr_index = 4*16
1051 LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop # t0_t1 = curr_arg, gpr_index = 4*16
1052 LOAD_END t6, 4*16, loop # no more GPR args, gpr_index = 4*16
1053 LOAD_END t6, 4*16, loop # no more GPR args, gpr_index = 4*16
1054tabSingle:
1055 LOAD_FLOAT_TO_REG f8, t8, t7, loop # f8 = curr_arg, fp_index += 16
1056 LOAD_FLOAT_TO_REG f10, t8, t7, loop # f10 = curr_arg, fp_index += 16
1057 LOAD_FLOAT_TO_REG f12, t8, t7, loop # f12 = curr_arg, fp_index += 16
1058 LOAD_FLOAT_TO_REG f14, t8, t7, loop # f14 = curr_arg, fp_index += 16
1059 LOAD_FLOAT_TO_REG f16, t8, t7, loop # f16 = curr_arg, fp_index += 16
1060 LOAD_FLOAT_TO_REG f18, t8, t7, loop # f18 = curr_arg, fp_index += 16
1061 LOAD_END t7, 6*16, loop # no more FPR args, fp_index = 6*16
1062tabDouble:
1063 LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loop # f8_f9 = curr_arg; if FPU32, fp_index += 16
1064 LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loop # f10_f11 = curr_arg; if FPU32, fp_index += 16
1065 LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loop # f12_f13 = curr_arg; if FPU32, fp_index += 16
1066 LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loop # f14_f15 = curr_arg; if FPU32, fp_index += 16
1067 LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loop # f16_f17 = curr_arg; if FPU32, fp_index += 16
1068 LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loop # f18_f19 = curr_arg; if FPU32, fp_index += 16
1069 LOAD_END t7, 6*16, loop # no more FPR args, fp_index = 6*16
Jeff Hao5d917302013-02-27 17:57:33 -08001070END art_quick_invoke_stub
1071
1072 /*
Goran Jakovljevicff734982015-08-24 12:58:55 +00001073 * Invocation static stub for quick code.
1074 * On entry:
1075 * a0 = method pointer
1076 * a1 = argument array or null for no argument methods
1077 * a2 = size of argument array in bytes
1078 * a3 = (managed) thread pointer
1079 * [sp + 16] = JValue* result
1080 * [sp + 20] = shorty
1081 */
1082ENTRY art_quick_invoke_static_stub
1083 sw $a0, 0($sp) # save out a0
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001084 addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
1085 .cfi_adjust_cfa_offset SPILL_SIZE
1086 sw $gp, 16($sp)
Goran Jakovljevicff734982015-08-24 12:58:55 +00001087 sw $ra, 12($sp)
1088 .cfi_rel_offset 31, 12
1089 sw $fp, 8($sp)
1090 .cfi_rel_offset 30, 8
1091 sw $s1, 4($sp)
1092 .cfi_rel_offset 17, 4
1093 sw $s0, 0($sp)
1094 .cfi_rel_offset 16, 0
1095 move $fp, $sp # save sp in fp
1096 .cfi_def_cfa_register 30
1097 move $s1, $a3 # move managed thread pointer into s1
1098 addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval
1099 addiu $t0, $a2, 4 # create space for ArtMethod* in frame.
1100 subu $t0, $sp, $t0 # reserve & align *stack* to 16 bytes:
1101 srl $t0, $t0, 4 # native calling convention only aligns to 8B,
1102 sll $sp, $t0, 4 # so we have to ensure ART 16B alignment ourselves.
1103 addiu $a0, $sp, 4 # pass stack pointer + ArtMethod* as dest for memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001104 la $t9, memcpy
1105 jalr $t9 # (dest, src, bytes)
Goran Jakovljevicff734982015-08-24 12:58:55 +00001106 addiu $sp, $sp, -16 # make space for argument slots for memcpy
1107 addiu $sp, $sp, 16 # restore stack after memcpy
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001108 lw $gp, 16($fp) # restore $gp
1109 lw $a0, SPILL_SIZE($fp) # restore ArtMethod*
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001110 addiu $t8, $sp, 4 # t8 = pointer to the current argument (skip ArtMethod*)
1111 li $t6, 0 # t6 = gpr_index = 0 (corresponds to A1; A0 is skipped)
1112 li $t7, 0 # t7 = fp_index = 0
1113 lw $t9, 20 + SPILL_SIZE($fp) # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001114 # as the $fp is SPILL_SIZE bytes below the $sp on entry)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001115 addiu $t9, 1 # t9 = shorty + 1 (skip 1 for return type)
1116
1117 // Load the base addresses of tabIntS ... tabDoubleS.
1118 // We will use the register indices (gpr_index, fp_index) to branch.
1119 // Note that the indices are scaled by 16, so they can be added to the bases directly.
1120#if defined(__mips_isa_rev) && __mips_isa_rev >= 6
1121 lapc $t2, tabIntS
1122 lapc $t3, tabLongS
1123 lapc $t4, tabSingleS
1124 lapc $t5, tabDoubleS
1125#else
1126 bltzal $zero, tabBaseS # nal
1127 addiu $t2, $ra, %lo(tabIntS - tabBaseS)
1128tabBaseS:
1129 addiu $t3, $ra, %lo(tabLongS - tabBaseS)
1130 addiu $t4, $ra, %lo(tabSingleS - tabBaseS)
1131 addiu $t5, $ra, %lo(tabDoubleS - tabBaseS)
1132#endif
1133
Goran Jakovljevicff734982015-08-24 12:58:55 +00001134loopS:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001135 lbu $ra, 0($t9) # ra = shorty[i]
1136 beqz $ra, loopEndS # finish getting args when shorty[i] == '\0'
1137 addiu $t9, 1
Goran Jakovljevicff734982015-08-24 12:58:55 +00001138
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001139 addiu $ra, -'J'
1140 beqz $ra, isLongS # branch if result type char == 'J'
1141 addiu $ra, 'J' - 'D'
1142 beqz $ra, isDoubleS # branch if result type char == 'D'
1143 addiu $ra, 'D' - 'F'
1144 beqz $ra, isSingleS # branch if result type char == 'F'
Goran Jakovljevicff734982015-08-24 12:58:55 +00001145
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001146 addu $ra, $t2, $t6
1147 jalr $zero, $ra
1148 addiu $t8, 4 # next_arg = curr_arg + 4
Goran Jakovljevicff734982015-08-24 12:58:55 +00001149
1150isLongS:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001151 addu $ra, $t3, $t6
1152 jalr $zero, $ra
1153 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +00001154
1155isSingleS:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001156 addu $ra, $t4, $t7
1157 jalr $zero, $ra
1158 addiu $t8, 4 # next_arg = curr_arg + 4
1159
1160isDoubleS:
1161 addu $ra, $t5, $t7
1162#if defined(__mips_isa_rev) && __mips_isa_rev > 2
1163 addiu $t7, 16 # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
1164#endif
1165 jalr $zero, $ra
1166 addiu $t8, 8 # next_arg = curr_arg + 8
Goran Jakovljevicff734982015-08-24 12:58:55 +00001167
1168loopEndS:
1169 lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0) # get pointer to the code
1170 jalr $t9 # call the method
1171 sw $zero, 0($sp) # store null for ArtMethod* at bottom of frame
1172 move $sp, $fp # restore the stack
1173 lw $s0, 0($sp)
1174 .cfi_restore 16
1175 lw $s1, 4($sp)
1176 .cfi_restore 17
1177 lw $fp, 8($sp)
1178 .cfi_restore 30
1179 lw $ra, 12($sp)
1180 .cfi_restore 31
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001181 addiu $sp, $sp, SPILL_SIZE
1182 .cfi_adjust_cfa_offset -SPILL_SIZE
Goran Jakovljevicff734982015-08-24 12:58:55 +00001183 lw $t0, 16($sp) # get result pointer
1184 lw $t1, 20($sp) # get shorty
1185 lb $t1, 0($t1) # get result type char
1186 li $t2, 'D' # put char 'D' into t2
1187 beq $t1, $t2, 6f # branch if result type char == 'D'
1188 li $t3, 'F' # put char 'F' into t3
1189 beq $t1, $t3, 6f # branch if result type char == 'F'
1190 sw $v0, 0($t0) # store the result
1191 jalr $zero, $ra
1192 sw $v1, 4($t0) # store the other half of the result
11936:
1194 SDu $f0, $f1, 0, $t0, $t1 # store floating point result
1195 jalr $zero, $ra
1196 nop
Alexey Frunze1b8464d2016-11-12 17:22:05 -08001197
1198 // Note that gpr_index is kept within the range of tabIntS and tabLongS
1199 // and fp_index is kept within the range of tabSingleS and tabDoubleS.
1200 .balign 16
1201tabIntS:
1202 LOAD_WORD_TO_REG a1, t8, t6, loopS # a1 = current argument, gpr_index += 16
1203 LOAD_WORD_TO_REG a2, t8, t6, loopS # a2 = current argument, gpr_index += 16
1204 LOAD_WORD_TO_REG a3, t8, t6, loopS # a3 = current argument, gpr_index += 16
1205 LOAD_WORD_TO_REG t0, t8, t6, loopS # t0 = current argument, gpr_index += 16
1206 LOAD_WORD_TO_REG t1, t8, t6, loopS # t1 = current argument, gpr_index += 16
1207 LOAD_END t6, 5*16, loopS # no more GPR args, gpr_index = 5*16
1208tabLongS:
1209 LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS # a2_a3 = curr_arg, gpr_index = 3*16
1210 LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS # a2_a3 = curr_arg, gpr_index = 3*16
1211 LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS # t0_t1 = curr_arg, gpr_index = 5*16
1212 LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS # t0_t1 = curr_arg, gpr_index = 5*16
1213 LOAD_END t6, 5*16, loopS # no more GPR args, gpr_index = 5*16
1214 LOAD_END t6, 5*16, loopS # no more GPR args, gpr_index = 5*16
1215tabSingleS:
1216 LOAD_FLOAT_TO_REG f8, t8, t7, loopS # f8 = curr_arg, fp_index += 16
1217 LOAD_FLOAT_TO_REG f10, t8, t7, loopS # f10 = curr_arg, fp_index += 16
1218 LOAD_FLOAT_TO_REG f12, t8, t7, loopS # f12 = curr_arg, fp_index += 16
1219 LOAD_FLOAT_TO_REG f14, t8, t7, loopS # f14 = curr_arg, fp_index += 16
1220 LOAD_FLOAT_TO_REG f16, t8, t7, loopS # f16 = curr_arg, fp_index += 16
1221 LOAD_FLOAT_TO_REG f18, t8, t7, loopS # f18 = curr_arg, fp_index += 16
1222 LOAD_END t7, 6*16, loopS # no more FPR args, fp_index = 6*16
1223tabDoubleS:
1224 LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loopS # f8_f9 = curr_arg; if FPU32, fp_index += 16
1225 LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loopS # f10_f11 = curr_arg; if FPU32, fp_index += 16
1226 LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loopS # f12_f13 = curr_arg; if FPU32, fp_index += 16
1227 LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loopS # f14_f15 = curr_arg; if FPU32, fp_index += 16
1228 LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loopS # f16_f17 = curr_arg; if FPU32, fp_index += 16
1229 LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loopS # f18_f19 = curr_arg; if FPU32, fp_index += 16
1230 LOAD_END t7, 6*16, loopS # no more FPR args, fp_index = 6*16
Goran Jakovljevicff734982015-08-24 12:58:55 +00001231END art_quick_invoke_static_stub
1232
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001233#undef SPILL_SIZE
1234
Goran Jakovljevicff734982015-08-24 12:58:55 +00001235 /*
buzbee5bc5a7b2012-03-07 15:52:59 -08001236 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
1237 * failure.
1238 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08001239 .extern artHandleFillArrayDataFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07001240ENTRY art_quick_handle_fill_data
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001241 lw $a2, 0($sp) # pass referrer's Method*
1242 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case exception allocation triggers GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001243 la $t9, artHandleFillArrayDataFromCode
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001244 jalr $t9 # (payload offset, Array*, method, Thread*)
1245 move $a3, rSELF # pass Thread::Current
jeffhaofc6a30e2012-10-18 18:24:15 -07001246 RETURN_IF_ZERO
Ian Rogers468532e2013-08-05 10:56:33 -07001247END art_quick_handle_fill_data
buzbee5bc5a7b2012-03-07 15:52:59 -08001248
buzbee5bc5a7b2012-03-07 15:52:59 -08001249 /*
Ian Rogers57b86d42012-03-27 16:05:41 -07001250 * Entry from managed code that calls artLockObjectFromCode, may block for GC.
buzbee5bc5a7b2012-03-07 15:52:59 -08001251 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08001252 .extern artLockObjectFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07001253ENTRY art_quick_lock_object
Vladimir Marko804b03f2016-09-14 16:26:36 +01001254 beqz $a0, art_quick_throw_null_pointer_exception
Alexey Frunzead63fe52017-05-08 22:10:00 -07001255 li $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
1256 li $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
1257.Lretry_lock:
1258 lw $t0, THREAD_ID_OFFSET(rSELF) # TODO: Can the thread ID really change during the loop?
1259 ll $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1260 and $t2, $t1, $t3 # zero the gc bits
1261 bnez $t2, .Lnot_unlocked # already thin locked
1262 # Unlocked case - $t1: original lock word that's zero except for the read barrier bits.
1263 or $t2, $t1, $t0 # $t2 holds thread id with count of 0 with preserved read barrier bits
1264 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1265 beqz $t2, .Lretry_lock # store failed, retry
Ian Rogersa9a82542013-10-04 11:17:26 -07001266 nop
Alexey Frunzead63fe52017-05-08 22:10:00 -07001267 jalr $zero, $ra
1268 sync # full (LoadLoad|LoadStore) memory barrier
1269.Lnot_unlocked:
1270 # $t1: original lock word, $t0: thread_id with count of 0 and zero read barrier bits
1271 srl $t2, $t1, LOCK_WORD_STATE_SHIFT
1272 bnez $t2, .Lslow_lock # if either of the top two bits are set, go slow path
1273 xor $t2, $t1, $t0 # lock_word.ThreadId() ^ self->ThreadId()
1274 andi $t2, $t2, 0xFFFF # zero top 16 bits
1275 bnez $t2, .Lslow_lock # lock word and self thread id's match -> recursive lock
1276 # otherwise contention, go to slow path
1277 and $t2, $t1, $t3 # zero the gc bits
1278 addu $t2, $t2, $t8 # increment count in lock word
1279 srl $t2, $t2, LOCK_WORD_STATE_SHIFT # if the first gc state bit is set, we overflowed.
1280 bnez $t2, .Lslow_lock # if we overflow the count go slow path
1281 addu $t2, $t1, $t8 # increment count for real
1282 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1283 beqz $t2, .Lretry_lock # store failed, retry
1284 nop
1285 jalr $zero, $ra
1286 nop
1287.Lslow_lock:
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001288 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case we block
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001289 la $t9, artLockObjectFromCode
1290 jalr $t9 # (Object* obj, Thread*)
jeffhao7fbee072012-08-24 17:56:54 -07001291 move $a1, rSELF # pass Thread::Current
Ian Rogers6bcd1632013-10-08 18:50:47 -07001292 RETURN_IF_ZERO
Ian Rogers468532e2013-08-05 10:56:33 -07001293END art_quick_lock_object
buzbee5bc5a7b2012-03-07 15:52:59 -08001294
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001295ENTRY art_quick_lock_object_no_inline
Vladimir Marko804b03f2016-09-14 16:26:36 +01001296 beqz $a0, art_quick_throw_null_pointer_exception
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001297 nop
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001298 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case we block
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001299 la $t9, artLockObjectFromCode
1300 jalr $t9 # (Object* obj, Thread*)
1301 move $a1, rSELF # pass Thread::Current
1302 RETURN_IF_ZERO
1303END art_quick_lock_object_no_inline
1304
buzbee5bc5a7b2012-03-07 15:52:59 -08001305 /*
1306 * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
1307 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08001308 .extern artUnlockObjectFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07001309ENTRY art_quick_unlock_object
Vladimir Marko804b03f2016-09-14 16:26:36 +01001310 beqz $a0, art_quick_throw_null_pointer_exception
Alexey Frunzead63fe52017-05-08 22:10:00 -07001311 li $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
1312 li $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
1313.Lretry_unlock:
1314#ifndef USE_READ_BARRIER
1315 lw $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1316#else
1317 ll $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0) # Need to use atomic read-modify-write for read barrier
1318#endif
1319 srl $t2, $t1, LOCK_WORD_STATE_SHIFT
1320 bnez $t2, .Lslow_unlock # if either of the top two bits are set, go slow path
1321 lw $t0, THREAD_ID_OFFSET(rSELF)
1322 and $t2, $t1, $t3 # zero the gc bits
1323 xor $t2, $t2, $t0 # lock_word.ThreadId() ^ self->ThreadId()
1324 andi $t2, $t2, 0xFFFF # zero top 16 bits
1325 bnez $t2, .Lslow_unlock # do lock word and self thread id's match?
1326 and $t2, $t1, $t3 # zero the gc bits
1327 bgeu $t2, $t8, .Lrecursive_thin_unlock
1328 # transition to unlocked
1329 nor $t2, $zero, $t3 # $t2 = LOCK_WORD_GC_STATE_MASK_SHIFTED
1330 and $t2, $t1, $t2 # $t2: zero except for the preserved gc bits
1331 sync # full (LoadStore|StoreStore) memory barrier
1332#ifndef USE_READ_BARRIER
1333 jalr $zero, $ra
1334 sw $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1335#else
1336 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1337 beqz $t2, .Lretry_unlock # store failed, retry
Ian Rogersa9a82542013-10-04 11:17:26 -07001338 nop
Alexey Frunzead63fe52017-05-08 22:10:00 -07001339 jalr $zero, $ra
1340 nop
1341#endif
1342.Lrecursive_thin_unlock:
1343 # t1: original lock word
1344 subu $t2, $t1, $t8 # decrement count
1345#ifndef USE_READ_BARRIER
1346 jalr $zero, $ra
1347 sw $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1348#else
1349 sc $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
1350 beqz $t2, .Lretry_unlock # store failed, retry
1351 nop
1352 jalr $zero, $ra
1353 nop
1354#endif
1355.Lslow_unlock:
1356 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case exception allocation triggers GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001357 la $t9, artUnlockObjectFromCode
Alexey Frunzead63fe52017-05-08 22:10:00 -07001358 jalr $t9 # (Object* obj, Thread*)
1359 move $a1, rSELF # pass Thread::Current
buzbee5bc5a7b2012-03-07 15:52:59 -08001360 RETURN_IF_ZERO
Ian Rogers468532e2013-08-05 10:56:33 -07001361END art_quick_unlock_object
buzbee5bc5a7b2012-03-07 15:52:59 -08001362
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001363ENTRY art_quick_unlock_object_no_inline
Vladimir Marko804b03f2016-09-14 16:26:36 +01001364 beqz $a0, art_quick_throw_null_pointer_exception
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001365 nop
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001366 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case exception allocation triggers GC
Andreas Gampec7ed09b2016-04-25 20:08:55 -07001367 la $t9, artUnlockObjectFromCode
1368 jalr $t9 # (Object* obj, Thread*)
1369 move $a1, rSELF # pass Thread::Current
1370 RETURN_IF_ZERO
1371END art_quick_unlock_object_no_inline
1372
buzbee5bc5a7b2012-03-07 15:52:59 -08001373 /*
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001374 * Entry from managed code that calls artInstanceOfFromCode and delivers exception on failure.
buzbee5bc5a7b2012-03-07 15:52:59 -08001375 */
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001376 .extern artInstanceOfFromCode
1377 .extern artThrowClassCastExceptionForObject
1378ENTRY art_quick_check_instance_of
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001379 addiu $sp, $sp, -32
1380 .cfi_adjust_cfa_offset 32
1381 sw $gp, 16($sp)
Ian Rogersa9a82542013-10-04 11:17:26 -07001382 sw $ra, 12($sp)
1383 .cfi_rel_offset 31, 12
1384 sw $t9, 8($sp)
1385 sw $a1, 4($sp)
1386 sw $a0, 0($sp)
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001387 la $t9, artInstanceOfFromCode
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001388 jalr $t9
Douglas Leung735b8552014-10-31 12:21:40 -07001389 addiu $sp, $sp, -16 # reserve argument slots on the stack
1390 addiu $sp, $sp, 16
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001391 lw $gp, 16($sp)
Ian Rogers86bcdc22014-02-21 22:06:38 -08001392 beqz $v0, .Lthrow_class_cast_exception
Ian Rogersa9a82542013-10-04 11:17:26 -07001393 lw $ra, 12($sp)
Andreas Gampe8d365912015-01-13 11:32:32 -08001394 jalr $zero, $ra
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001395 addiu $sp, $sp, 32
1396 .cfi_adjust_cfa_offset -32
Ian Rogers86bcdc22014-02-21 22:06:38 -08001397.Lthrow_class_cast_exception:
Ian Rogersa9a82542013-10-04 11:17:26 -07001398 lw $t9, 8($sp)
1399 lw $a1, 4($sp)
1400 lw $a0, 0($sp)
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001401 addiu $sp, $sp, 32
1402 .cfi_adjust_cfa_offset -32
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001403 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001404 la $t9, artThrowClassCastExceptionForObject
1405 jalr $zero, $t9 # artThrowClassCastException (Object*, Class*, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001406 move $a2, rSELF # pass Thread::Current
Mathieu Chartierb99f4d62016-11-07 16:17:26 -08001407END art_quick_check_instance_of
buzbee5bc5a7b2012-03-07 15:52:59 -08001408
buzbee5bc5a7b2012-03-07 15:52:59 -08001409 /*
Man Cao1aee9002015-07-14 22:31:42 -07001410 * Restore rReg's value from offset($sp) if rReg is not the same as rExclude.
1411 * nReg is the register number for rReg.
1412 */
1413.macro POP_REG_NE rReg, nReg, offset, rExclude
1414 .ifnc \rReg, \rExclude
1415 lw \rReg, \offset($sp) # restore rReg
1416 .cfi_restore \nReg
1417 .endif
1418.endm
1419
1420 /*
1421 * Macro to insert read barrier, only used in art_quick_aput_obj.
1422 * rObj and rDest are registers, offset is a defined literal such as MIRROR_OBJECT_CLASS_OFFSET.
1423 * TODO: When read barrier has a fast path, add heap unpoisoning support for the fast path.
1424 */
1425.macro READ_BARRIER rDest, rObj, offset
1426#ifdef USE_READ_BARRIER
1427 # saved registers used in art_quick_aput_obj: a0-a2, t0-t1, t9, ra. 8 words for 16B alignment.
1428 addiu $sp, $sp, -32
1429 .cfi_adjust_cfa_offset 32
1430 sw $ra, 28($sp)
1431 .cfi_rel_offset 31, 28
1432 sw $t9, 24($sp)
1433 .cfi_rel_offset 25, 24
1434 sw $t1, 20($sp)
1435 .cfi_rel_offset 9, 20
1436 sw $t0, 16($sp)
1437 .cfi_rel_offset 8, 16
1438 sw $a2, 8($sp) # padding slot at offset 12 (padding can be any slot in the 32B)
1439 .cfi_rel_offset 6, 8
1440 sw $a1, 4($sp)
1441 .cfi_rel_offset 5, 4
1442 sw $a0, 0($sp)
1443 .cfi_rel_offset 4, 0
1444
Man Cao63069212015-08-21 15:51:39 -07001445 # move $a0, \rRef # pass ref in a0 (no-op for now since parameter ref is unused)
Man Cao1aee9002015-07-14 22:31:42 -07001446 .ifnc \rObj, $a1
1447 move $a1, \rObj # pass rObj
1448 .endif
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001449 addiu $a2, $zero, \offset # pass offset
1450 la $t9, artReadBarrierSlow
1451 jalr $t9 # artReadBarrierSlow(ref, rObj, offset)
Man Cao1aee9002015-07-14 22:31:42 -07001452 addiu $sp, $sp, -16 # Use branch delay slot to reserve argument slots on the stack
1453 # before the call to artReadBarrierSlow.
1454 addiu $sp, $sp, 16 # restore stack after call to artReadBarrierSlow
1455 # No need to unpoison return value in v0, artReadBarrierSlow() would do the unpoisoning.
1456 move \rDest, $v0 # save return value in rDest
1457 # (rDest cannot be v0 in art_quick_aput_obj)
1458
1459 lw $a0, 0($sp) # restore registers except rDest
1460 # (rDest can only be t0 or t1 in art_quick_aput_obj)
1461 .cfi_restore 4
1462 lw $a1, 4($sp)
1463 .cfi_restore 5
1464 lw $a2, 8($sp)
1465 .cfi_restore 6
1466 POP_REG_NE $t0, 8, 16, \rDest
1467 POP_REG_NE $t1, 9, 20, \rDest
1468 lw $t9, 24($sp)
1469 .cfi_restore 25
1470 lw $ra, 28($sp) # restore $ra
1471 .cfi_restore 31
1472 addiu $sp, $sp, 32
1473 .cfi_adjust_cfa_offset -32
1474#else
1475 lw \rDest, \offset(\rObj)
1476 UNPOISON_HEAP_REF \rDest
1477#endif // USE_READ_BARRIER
1478.endm
1479
Man Cao1aee9002015-07-14 22:31:42 -07001480#ifdef USE_READ_BARRIER
1481 .extern artReadBarrierSlow
1482#endif
Ian Rogersa9a82542013-10-04 11:17:26 -07001483ENTRY art_quick_aput_obj
Ian Rogers86bcdc22014-02-21 22:06:38 -08001484 beqz $a2, .Ldo_aput_null
Ian Rogersa9a82542013-10-04 11:17:26 -07001485 nop
Man Cao1aee9002015-07-14 22:31:42 -07001486 READ_BARRIER $t0, $a0, MIRROR_OBJECT_CLASS_OFFSET
1487 READ_BARRIER $t1, $a2, MIRROR_OBJECT_CLASS_OFFSET
1488 READ_BARRIER $t0, $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET
Ian Rogers86bcdc22014-02-21 22:06:38 -08001489 bne $t1, $t0, .Lcheck_assignability # value's type == array's component type - trivial assignability
Ian Rogersa9a82542013-10-04 11:17:26 -07001490 nop
Ian Rogers86bcdc22014-02-21 22:06:38 -08001491.Ldo_aput:
Ian Rogersa9a82542013-10-04 11:17:26 -07001492 sll $a1, $a1, 2
1493 add $t0, $a0, $a1
Hiroshi Yamauchibfa5eb62015-05-29 15:04:41 -07001494 POISON_HEAP_REF $a2
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001495 sw $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
Ian Rogersa9a82542013-10-04 11:17:26 -07001496 lw $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
Mathieu Chartierafdcbcb2017-04-26 16:43:35 -07001497 srl $t1, $a0, CARD_TABLE_CARD_SHIFT
Ian Rogersa9a82542013-10-04 11:17:26 -07001498 add $t1, $t1, $t0
1499 sb $t0, ($t1)
Andreas Gampe8d365912015-01-13 11:32:32 -08001500 jalr $zero, $ra
Ian Rogersa9a82542013-10-04 11:17:26 -07001501 nop
Ian Rogers86bcdc22014-02-21 22:06:38 -08001502.Ldo_aput_null:
Ian Rogersa9a82542013-10-04 11:17:26 -07001503 sll $a1, $a1, 2
1504 add $t0, $a0, $a1
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001505 sw $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
Andreas Gampe8d365912015-01-13 11:32:32 -08001506 jalr $zero, $ra
Ian Rogersa9a82542013-10-04 11:17:26 -07001507 nop
Ian Rogers86bcdc22014-02-21 22:06:38 -08001508.Lcheck_assignability:
Ian Rogersa9a82542013-10-04 11:17:26 -07001509 addiu $sp, $sp, -32
1510 .cfi_adjust_cfa_offset 32
1511 sw $ra, 28($sp)
1512 .cfi_rel_offset 31, 28
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001513 sw $gp, 16($sp)
Ian Rogersa9a82542013-10-04 11:17:26 -07001514 sw $t9, 12($sp)
1515 sw $a2, 8($sp)
1516 sw $a1, 4($sp)
1517 sw $a0, 0($sp)
1518 move $a1, $t1
1519 move $a0, $t0
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001520 la $t9, artIsAssignableFromCode
1521 jalr $t9 # (Class*, Class*)
1522 addiu $sp, $sp, -16 # reserve argument slots on the stack
1523 addiu $sp, $sp, 16
Ian Rogersa9a82542013-10-04 11:17:26 -07001524 lw $ra, 28($sp)
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001525 lw $gp, 16($sp)
Ian Rogersa9a82542013-10-04 11:17:26 -07001526 lw $t9, 12($sp)
1527 lw $a2, 8($sp)
1528 lw $a1, 4($sp)
1529 lw $a0, 0($sp)
Duane Sande34652f2014-11-04 11:09:36 -08001530 addiu $sp, 32
Ian Rogersa9a82542013-10-04 11:17:26 -07001531 .cfi_adjust_cfa_offset -32
Ian Rogers86bcdc22014-02-21 22:06:38 -08001532 bnez $v0, .Ldo_aput
Ian Rogersa9a82542013-10-04 11:17:26 -07001533 nop
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001534 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
Ian Rogersa9a82542013-10-04 11:17:26 -07001535 move $a1, $a2
Ian Rogersa9a82542013-10-04 11:17:26 -07001536 la $t9, artThrowArrayStoreException
Andreas Gampe8d365912015-01-13 11:32:32 -08001537 jalr $zero, $t9 # artThrowArrayStoreException(Class*, Class*, Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001538 move $a2, rSELF # pass Thread::Current
Ian Rogersa9a82542013-10-04 11:17:26 -07001539END art_quick_aput_obj
buzbee5bc5a7b2012-03-07 15:52:59 -08001540
Alexey Frunze0cb12422017-01-25 19:30:18 -08001541// Macros taking opportunity of code similarities for downcalls.
1542.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return
1543 .extern \entrypoint
1544ENTRY \name
1545 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1546 la $t9, \entrypoint
1547 jalr $t9 # (field_idx, Thread*)
1548 move $a1, rSELF # pass Thread::Current
1549 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1550END \name
1551.endm
1552
1553.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return
1554 .extern \entrypoint
1555ENTRY \name
1556 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1557 la $t9, \entrypoint
1558 jalr $t9 # (field_idx, Object*, Thread*) or
1559 # (field_idx, new_val, Thread*)
1560 move $a2, rSELF # pass Thread::Current
1561 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1562END \name
1563.endm
1564
1565.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
1566 .extern \entrypoint
1567ENTRY \name
1568 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1569 la $t9, \entrypoint
1570 jalr $t9 # (field_idx, Object*, new_val, Thread*)
1571 move $a3, rSELF # pass Thread::Current
1572 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1573END \name
1574.endm
1575
1576.macro FOUR_ARG_REF_DOWNCALL name, entrypoint, return
1577 .extern \entrypoint
1578ENTRY \name
1579 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
1580 la $t9, \entrypoint
1581 jalr $t9 # (field_idx, Object*, 64-bit new_val, Thread*) or
1582 # (field_idx, 64-bit new_val, Thread*)
1583 # Note that a 64-bit new_val needs to be aligned with
1584 # an even-numbered register, hence A1 may be skipped
1585 # for new_val to reside in A2-A3.
1586 sw rSELF, 16($sp) # pass Thread::Current
1587 \return # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
1588END \name
1589.endm
Fred Shih37f05ef2014-07-16 18:38:08 -07001590
1591 /*
Alexey Frunze0cb12422017-01-25 19:30:18 -08001592 * Called by managed code to resolve a static/instance field and load/store a value.
Fred Shih37f05ef2014-07-16 18:38:08 -07001593 */
Alexey Frunze0cb12422017-01-25 19:30:18 -08001594ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1595ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1596ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1597ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1598ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1599ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1600ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
1601TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1602TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1603TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1604TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1605TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1606TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1607TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
1608TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCompiledCode, RETURN_IF_ZERO
1609TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCompiledCode, RETURN_IF_ZERO
1610TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCompiledCode, RETURN_IF_ZERO
1611TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCompiledCode, RETURN_IF_ZERO
1612FOUR_ARG_REF_DOWNCALL art_quick_set64_static, artSet64StaticFromCompiledCode, RETURN_IF_ZERO
1613THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCompiledCode, RETURN_IF_ZERO
1614THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCompiledCode, RETURN_IF_ZERO
1615THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCompiledCode, RETURN_IF_ZERO
1616THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCompiledCode, RETURN_IF_ZERO
1617FOUR_ARG_REF_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCompiledCode, RETURN_IF_ZERO
buzbee5bc5a7b2012-03-07 15:52:59 -08001618
Vladimir Markoa3c38272015-04-28 12:37:09 +01001619// Macro to facilitate adding new allocation entrypoints.
Vladimir Marko5ea536a2015-04-20 20:11:30 +01001620.macro ONE_ARG_DOWNCALL name, entrypoint, return
1621 .extern \entrypoint
1622ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001623 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001624 la $t9, \entrypoint
1625 jalr $t9
Vladimir Marko5ea536a2015-04-20 20:11:30 +01001626 move $a1, rSELF # pass Thread::Current
1627 \return
1628END \name
1629.endm
1630
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001631.macro TWO_ARG_DOWNCALL name, entrypoint, return
1632 .extern \entrypoint
1633ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001634 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001635 la $t9, \entrypoint
1636 jalr $t9
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001637 move $a2, rSELF # pass Thread::Current
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001638 \return
1639END \name
1640.endm
buzbee5bc5a7b2012-03-07 15:52:59 -08001641
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001642.macro THREE_ARG_DOWNCALL name, entrypoint, return
1643 .extern \entrypoint
1644ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001645 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001646 la $t9, \entrypoint
1647 jalr $t9
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07001648 move $a3, rSELF # pass Thread::Current
Mathieu Chartiercbb2d202013-11-14 17:45:16 -08001649 \return
1650END \name
1651.endm
buzbee5bc5a7b2012-03-07 15:52:59 -08001652
Jeff Hao848f70a2014-01-15 13:49:50 -08001653.macro FOUR_ARG_DOWNCALL name, entrypoint, return
1654 .extern \entrypoint
1655ENTRY \name
Vladimir Markofd36f1f2016-08-03 18:49:58 +01001656 SETUP_SAVE_REFS_ONLY_FRAME # save callee saves in case of GC
Goran Jakovljevic590b1362016-03-21 14:24:43 +01001657 la $t9, \entrypoint
1658 jalr $t9
Vladimir Markoa3c38272015-04-28 12:37:09 +01001659 sw rSELF, 16($sp) # pass Thread::Current
Jeff Hao848f70a2014-01-15 13:49:50 -08001660 \return
1661END \name
1662.endm
1663
Mathieu Chartier7410f292013-11-24 13:17:35 -08001664// Generate the allocation entrypoints for each allocator.
Goran Jakovljevic854df412017-06-27 14:41:39 +02001665GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
1666// Comment out allocators that have mips specific asm.
1667// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
1668// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
1669GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
1670// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
1671// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab, RegionTLAB)
1672// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab, RegionTLAB)
1673// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab, RegionTLAB)
1674// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab, RegionTLAB)
1675GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
1676GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
1677GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
1678
1679// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
1680// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
1681GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
1682// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
1683// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_tlab, TLAB)
1684// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_tlab, TLAB)
1685// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_tlab, TLAB)
1686// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_tlab, TLAB)
1687GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
1688GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
1689GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
Hiroshi Yamauchi10d4c082016-02-24 12:51:18 -08001690
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001691// A hand-written override for:
1692// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
1693// GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
Goran Jakovljevic854df412017-06-27 14:41:39 +02001694.macro ART_QUICK_ALLOC_OBJECT_ROSALLOC c_name, cxx_name, isInitialized
1695ENTRY_NO_GP \c_name
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001696 # Fast path rosalloc allocation
1697 # a0: type
1698 # s1: Thread::Current
1699 # -----------------------------
1700 # t1: object size
1701 # t2: rosalloc run
1702 # t3: thread stack top offset
1703 # t4: thread stack bottom offset
1704 # v0: free list head
1705 #
1706 # t5, t6 : temps
1707 lw $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1) # Check if thread local allocation
1708 lw $t4, THREAD_LOCAL_ALLOC_STACK_END_OFFSET($s1) # stack has any room left.
1709 bgeu $t3, $t4, .Lslow_path_\c_name
Pavle Batuta712c59d2015-12-02 18:39:01 +01001710
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001711 lw $t1, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0) # Load object size (t1).
1712 li $t5, ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE # Check if size is for a thread local
1713 # allocation. Also does the
1714 # initialized and finalizable checks.
Goran Jakovljevic854df412017-06-27 14:41:39 +02001715 # When isInitialized == 0, then the class is potentially not yet initialized.
1716 # If the class is not yet initialized, the object size will be very large to force the branch
1717 # below to be taken.
1718 #
1719 # See InitializeClassVisitors in class-inl.h for more details.
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001720 bgtu $t1, $t5, .Lslow_path_\c_name
1721
1722 # Compute the rosalloc bracket index from the size. Since the size is already aligned we can
1723 # combine the two shifts together.
1724 srl $t1, $t1, (ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT - POINTER_SIZE_SHIFT)
1725
1726 addu $t2, $t1, $s1
1727 lw $t2, (THREAD_ROSALLOC_RUNS_OFFSET - __SIZEOF_POINTER__)($t2) # Load rosalloc run (t2).
1728
1729 # Load the free list head (v0).
1730 # NOTE: this will be the return val.
1731 lw $v0, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
1732 beqz $v0, .Lslow_path_\c_name
1733 nop
1734
1735 # Load the next pointer of the head and update the list head with the next pointer.
1736 lw $t5, ROSALLOC_SLOT_NEXT_OFFSET($v0)
1737 sw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
1738
1739 # Store the class pointer in the header. This also overwrites the first pointer. The offsets are
1740 # asserted to match.
1741
1742#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
1743#error "Class pointer needs to overwrite next pointer."
1744#endif
1745
1746 POISON_HEAP_REF $a0
1747 sw $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)
1748
1749 # Push the new object onto the thread local allocation stack and increment the thread local
1750 # allocation stack top.
1751 sw $v0, 0($t3)
1752 addiu $t3, $t3, COMPRESSED_REFERENCE_SIZE
1753 sw $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)
1754
1755 # Decrement the size of the free list.
1756 lw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
1757 addiu $t5, $t5, -1
1758 sw $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
1759
Goran Jakovljevic854df412017-06-27 14:41:39 +02001760.if \isInitialized == 0
1761 # This barrier is only necessary when the allocation also requires a class initialization check.
1762 #
1763 # If the class is already observably initialized, then new-instance allocations are protected
1764 # from publishing by the compiler which inserts its own StoreStore barrier.
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001765 sync # Fence.
Goran Jakovljevic854df412017-06-27 14:41:39 +02001766.endif
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001767 jalr $zero, $ra
1768 nop
1769
1770 .Lslow_path_\c_name:
Goran Jakovljevic854df412017-06-27 14:41:39 +02001771 addiu $t9, $t9, (.Lslow_path_\c_name - \c_name) + 4
1772 .cpload $t9
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001773 SETUP_SAVE_REFS_ONLY_FRAME
1774 la $t9, \cxx_name
1775 jalr $t9
1776 move $a1, $s1 # Pass self as argument.
1777 RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1778END \c_name
1779.endm
1780
Goran Jakovljevic854df412017-06-27 14:41:39 +02001781ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_resolved_rosalloc, artAllocObjectFromCodeResolvedRosAlloc, /* isInitialized */ 0
1782ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, artAllocObjectFromCodeInitializedRosAlloc, /* isInitialized */ 1
Goran Jakovljevic2449e5c2017-01-19 11:39:18 +01001783
Goran Jakovljevic854df412017-06-27 14:41:39 +02001784// The common fast path code for art_quick_alloc_object_resolved/initialized_tlab
1785// and art_quick_alloc_object_resolved/initialized_region_tlab.
1786//
1787// a0: type, s1(rSELF): Thread::Current.
1788// Need to preserve a0 to the slow path.
1789//
1790// If isInitialized=1 then the compiler assumes the object's class has already been initialized.
1791// If isInitialized=0 the compiler can only assume it's been at least resolved.
1792.macro ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH slowPathLabel isInitialized
1793 lw $v0, THREAD_LOCAL_POS_OFFSET(rSELF) # Load thread_local_pos.
1794 lw $a2, THREAD_LOCAL_END_OFFSET(rSELF) # Load thread_local_end.
1795 subu $a3, $a2, $v0 # Compute the remaining buffer size.
1796 lw $t0, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0) # Load the object size.
1797
1798 # When isInitialized == 0, then the class is potentially not yet initialized.
1799 # If the class is not yet initialized, the object size will be very large to force the branch
1800 # below to be taken.
1801 #
1802 # See InitializeClassVisitors in class-inl.h for more details.
1803 bgtu $t0, $a3, \slowPathLabel # Check if it fits.
1804 addu $t1, $v0, $t0 # Add object size to tlab pos (in branch
1805 # delay slot).
1806 # "Point of no slow path". Won't go to the slow path from here on.
1807 sw $t1, THREAD_LOCAL_POS_OFFSET(rSELF) # Store new thread_local_pos.
1808 lw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF) # Increment thread_local_objects.
1809 addiu $a2, $a2, 1
1810 sw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
1811 POISON_HEAP_REF $a0
1812 sw $a0, MIRROR_OBJECT_CLASS_OFFSET($v0) # Store the class pointer.
1813
1814.if \isInitialized == 0
1815 # This barrier is only necessary when the allocation also requires a class initialization check.
1816 #
1817 # If the class is already observably initialized, then new-instance allocations are protected
1818 # from publishing by the compiler which inserts its own StoreStore barrier.
1819 sync # Fence.
1820.endif
1821 jalr $zero, $ra
1822 nop
1823.endm
1824
1825// The common code for art_quick_alloc_object_resolved/initialized_tlab
1826// and art_quick_alloc_object_resolved/initialized_region_tlab.
1827.macro GENERATE_ALLOC_OBJECT_TLAB name, entrypoint, isInitialized
1828ENTRY_NO_GP \name
1829 # Fast path tlab allocation.
1830 # a0: type, s1(rSELF): Thread::Current.
1831 ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lslow_path_\name, \isInitialized
1832.Lslow_path_\name:
1833 addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
1834 .cpload $t9
1835 SETUP_SAVE_REFS_ONLY_FRAME # Save callee saves in case of GC.
1836 la $t9, \entrypoint
1837 jalr $t9 # (mirror::Class*, Thread*)
1838 move $a1, rSELF # Pass Thread::Current.
1839 RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1840END \name
1841.endm
1842
1843GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_region_tlab, artAllocObjectFromCodeResolvedRegionTLAB, /* isInitialized */ 0
1844GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_region_tlab, artAllocObjectFromCodeInitializedRegionTLAB, /* isInitialized */ 1
1845GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_tlab, artAllocObjectFromCodeResolvedTLAB, /* isInitialized */ 0
1846GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_tlab, artAllocObjectFromCodeInitializedTLAB, /* isInitialized */ 1
1847
1848// The common fast path code for art_quick_alloc_array_resolved/initialized_tlab
1849// and art_quick_alloc_array_resolved/initialized_region_tlab.
1850//
1851// a0: type, a1: component_count, a2: total_size, s1(rSELF): Thread::Current.
1852// Need to preserve a0 and a1 to the slow path.
1853.macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE slowPathLabel
1854 li $a3, OBJECT_ALIGNMENT_MASK_TOGGLED # Apply alignemnt mask
1855 and $a2, $a2, $a3 # (addr + 7) & ~7.
1856
1857 lw $v0, THREAD_LOCAL_POS_OFFSET(rSELF) # Load thread_local_pos.
1858 lw $t1, THREAD_LOCAL_END_OFFSET(rSELF) # Load thread_local_end.
1859 subu $t2, $t1, $v0 # Compute the remaining buffer size.
1860 bgtu $a2, $t2, \slowPathLabel # Check if it fits.
1861 addu $a2, $v0, $a2 # Add object size to tlab pos (in branch
1862 # delay slot).
1863
1864 # "Point of no slow path". Won't go to the slow path from here on.
1865 sw $a2, THREAD_LOCAL_POS_OFFSET(rSELF) # Store new thread_local_pos.
1866 lw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF) # Increment thread_local_objects.
1867 addiu $a2, $a2, 1
1868 sw $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
1869 POISON_HEAP_REF $a0
1870 sw $a0, MIRROR_OBJECT_CLASS_OFFSET($v0) # Store the class pointer.
1871 jalr $zero, $ra
1872 sw $a1, MIRROR_ARRAY_LENGTH_OFFSET($v0) # Store the array length.
1873.endm
1874
1875.macro GENERATE_ALLOC_ARRAY_TLAB name, entrypoint, size_setup
1876ENTRY_NO_GP \name
1877 # Fast path array allocation for region tlab allocation.
1878 # a0: mirror::Class* type
1879 # a1: int32_t component_count
1880 # s1(rSELF): Thread::Current
1881 \size_setup .Lslow_path_\name
1882 ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE .Lslow_path_\name
1883.Lslow_path_\name:
1884 # a0: mirror::Class* type
1885 # a1: int32_t component_count
1886 # a2: Thread* self
1887 addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
1888 .cpload $t9
1889 SETUP_SAVE_REFS_ONLY_FRAME # Save callee saves in case of GC.
1890 la $t9, \entrypoint
1891 jalr $t9
1892 move $a2, rSELF # Pass Thread::Current.
1893 RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
1894END \name
1895.endm
1896
1897.macro COMPUTE_ARRAY_SIZE_UNKNOWN slow_path
1898 break # We should never enter here.
1899 # Code below is for reference.
1900 # Possibly a large object, go slow.
1901 # Also does negative array size check.
1902 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_WIDE_ARRAY_DATA_OFFSET) / 8)
1903 bgtu $a1, $a2, \slow_path
1904 # Array classes are never finalizable
1905 # or uninitialized, no need to check.
1906 lw $a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($a0) # Load component type.
1907 UNPOISON_HEAP_REF $a3
1908 lw $a3, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET($a3)
1909 srl $a3, $a3, PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT # Component size shift is in high 16 bits.
1910 sllv $a2, $a1, $a3 # Calculate data size.
1911 # Add array data offset and alignment.
1912 addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1913#if MIRROR_WIDE_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
1914#error Long array data offset must be 4 greater than int array data offset.
1915#endif
1916
1917 addiu $a3, $a3, 1 # Add 4 to the length only if the component
1918 andi $a3, $a3, 4 # size shift is 3 (for 64 bit alignment).
1919 addu $a2, $a2, $a3
1920.endm
1921
1922.macro COMPUTE_ARRAY_SIZE_8 slow_path
1923 # Possibly a large object, go slow.
1924 # Also does negative array size check.
1925 li $a2, (MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET)
1926 bgtu $a1, $a2, \slow_path
1927 # Add array data offset and alignment (in branch delay slot).
1928 addiu $a2, $a1, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1929.endm
1930
1931.macro COMPUTE_ARRAY_SIZE_16 slow_path
1932 # Possibly a large object, go slow.
1933 # Also does negative array size check.
1934 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 2)
1935 bgtu $a1, $a2, \slow_path
1936 sll $a2, $a1, 1
1937 # Add array data offset and alignment.
1938 addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1939.endm
1940
1941.macro COMPUTE_ARRAY_SIZE_32 slow_path
1942 # Possibly a large object, go slow.
1943 # Also does negative array size check.
1944 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 4)
1945 bgtu $a1, $a2, \slow_path
1946 sll $a2, $a1, 2
1947 # Add array data offset and alignment.
1948 addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1949.endm
1950
1951.macro COMPUTE_ARRAY_SIZE_64 slow_path
1952 # Possibly a large object, go slow.
1953 # Also does negative array size check.
1954 li $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_LONG_ARRAY_DATA_OFFSET) / 8)
1955 bgtu $a1, $a2, \slow_path
1956 sll $a2, $a1, 3
1957 # Add array data offset and alignment.
1958 addiu $a2, $a2, (MIRROR_WIDE_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
1959.endm
1960
1961GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
1962GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_8
1963GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_16
1964GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_32
1965GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_64
1966
1967GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
1968GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_8
1969GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_16
1970GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
1971GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
Hiroshi Yamauchi10d4c082016-02-24 12:51:18 -08001972
Alexey Frunzec61c0762017-04-10 13:54:23 -07001973// Macro for string and type resolution and initialization.
1974// $a0 is both input and output.
1975.macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint
1976 .extern \entrypoint
1977ENTRY_NO_GP \name
1978 SETUP_SAVE_EVERYTHING_FRAME # Save everything in case of GC.
1979 move $s2, $gp # Preserve $gp across the call for exception delivery.
1980 la $t9, \entrypoint
1981 jalr $t9 # (uint32_t index, Thread*)
1982 move $a1, rSELF # Pass Thread::Current (in delay slot).
1983 beqz $v0, 1f # Success?
1984 move $a0, $v0 # Move result to $a0 (in delay slot).
1985 RESTORE_SAVE_EVERYTHING_FRAME 0 # Restore everything except $a0.
1986 jalr $zero, $ra # Return on success.
1987 nop
19881:
1989 move $gp, $s2
1990 DELIVER_PENDING_EXCEPTION_FRAME_READY
1991END \name
1992.endm
1993
buzbee5bc5a7b2012-03-07 15:52:59 -08001994 /*
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08001995 * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
Vladimir Marko5ea536a2015-04-20 20:11:30 +01001996 * exception on error. On success the String is returned. A0 holds the string index. The fast
1997 * path check for hit in strings cache has already been performed.
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08001998 */
Alexey Frunzec61c0762017-04-10 13:54:23 -07001999ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002000
2001 /*
2002 * Entry from managed code when uninitialized static storage, this stub will run the class
2003 * initializer and deliver the exception on error. On success the static storage base is
2004 * returned.
2005 */
Alexey Frunzec61c0762017-04-10 13:54:23 -07002006ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002007
2008 /*
2009 * Entry from managed code when dex cache misses for a type_idx.
2010 */
Alexey Frunzec61c0762017-04-10 13:54:23 -07002011ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002012
2013 /*
2014 * Entry from managed code when type_idx needs to be checked for access and dex cache may also
2015 * miss.
2016 */
Alexey Frunzec61c0762017-04-10 13:54:23 -07002017ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002018
2019 /*
Ian Rogers57b86d42012-03-27 16:05:41 -07002020 * Called by managed code when the value in rSUSPEND has been decremented to 0.
buzbee5bc5a7b2012-03-07 15:52:59 -08002021 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002022 .extern artTestSuspendFromCode
Vladimir Marko952dbb12016-07-28 12:01:51 +01002023ENTRY_NO_GP art_quick_test_suspend
2024 lh rSUSPEND, THREAD_FLAGS_OFFSET(rSELF)
2025 bnez rSUSPEND, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002026 addiu rSUSPEND, $zero, SUSPEND_CHECK_INTERVAL # reset rSUSPEND to SUSPEND_CHECK_INTERVAL
Andreas Gampe8d365912015-01-13 11:32:32 -08002027 jalr $zero, $ra
buzbee5bc5a7b2012-03-07 15:52:59 -08002028 nop
20291:
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002030 SETUP_SAVE_EVERYTHING_FRAME # save everything for stack crawl
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002031 la $t9, artTestSuspendFromCode
Vladimir Marko952dbb12016-07-28 12:01:51 +01002032 jalr $t9 # (Thread*)
jeffhao7fbee072012-08-24 17:56:54 -07002033 move $a0, rSELF
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002034 RESTORE_SAVE_EVERYTHING_FRAME
Vladimir Marko952dbb12016-07-28 12:01:51 +01002035 jalr $zero, $ra
2036 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002037END art_quick_test_suspend
buzbee5bc5a7b2012-03-07 15:52:59 -08002038
buzbee5bc5a7b2012-03-07 15:52:59 -08002039 /*
2040 * Called by managed code that is attempting to call a method on a proxy class. On entry
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002041 * a0 holds the proxy method; a1, a2 and a3 may contain arguments.
buzbee5bc5a7b2012-03-07 15:52:59 -08002042 */
Jeff Hao5fa60c32013-04-04 17:57:01 -07002043 .extern artQuickProxyInvokeHandler
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002044ENTRY art_quick_proxy_invoke_handler
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002045 SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
Douglas Leung735b8552014-10-31 12:21:40 -07002046 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002047 la $t9, artQuickProxyInvokeHandler
2048 jalr $t9 # (Method* proxy method, receiver, Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002049 addiu $a3, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002050 lw $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002051 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002052 bnez $t7, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002053 # don't care if $v0 and/or $v1 are modified, when exception branch taken
2054 MTD $v0, $v1, $f0, $f1 # move float value to return value
Andreas Gampe8d365912015-01-13 11:32:32 -08002055 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002056 nop
buzbee5bc5a7b2012-03-07 15:52:59 -080020571:
2058 DELIVER_PENDING_EXCEPTION
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002059END art_quick_proxy_invoke_handler
buzbee5bc5a7b2012-03-07 15:52:59 -08002060
Jeff Hao88474b42013-10-23 16:24:40 -07002061 /*
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002062 * Called to resolve an imt conflict.
2063 * a0 is the conflict ArtMethod.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002064 * t7 is a hidden argument that holds the target interface method's dex method index.
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002065 *
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002066 * Note that this stub writes to a0, t7 and t8.
Jeff Hao88474b42013-10-23 16:24:40 -07002067 */
Douglas Leung13738bf2014-10-27 14:44:47 -07002068ENTRY art_quick_imt_conflict_trampoline
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002069 lw $t8, 0($sp) # Load referrer.
2070 lw $t8, ART_METHOD_DEX_CACHE_METHODS_OFFSET_32($t8) # Load dex cache methods array.
2071 sll $t7, $t7, POINTER_SIZE_SHIFT # Calculate offset.
2072 addu $t7, $t8, $t7 # Add offset to base.
2073 lw $t7, 0($t7) # Load interface method.
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002074 lw $a0, ART_METHOD_JNI_OFFSET_32($a0) # Load ImtConflictTable.
2075
2076.Limt_table_iterate:
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002077 lw $t8, 0($a0) # Load next entry in ImtConflictTable.
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002078 # Branch if found.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002079 beq $t8, $t7, .Limt_table_found
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002080 nop
2081 # If the entry is null, the interface method is not in the ImtConflictTable.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002082 beqz $t8, .Lconflict_trampoline
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002083 nop
2084 # Iterate over the entries of the ImtConflictTable.
2085 b .Limt_table_iterate
2086 addiu $a0, $a0, 2 * __SIZEOF_POINTER__ # Iterate to the next entry.
2087
2088.Limt_table_found:
2089 # We successfully hit an entry in the table. Load the target method and jump to it.
2090 lw $a0, __SIZEOF_POINTER__($a0)
2091 lw $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002092 jalr $zero, $t9
Goran Jakovljevic59028d92016-03-29 18:05:03 +02002093 nop
2094
2095.Lconflict_trampoline:
2096 # Call the runtime stub to populate the ImtConflictTable and jump to the resolved method.
Jeff Hao5667f562017-02-27 19:32:01 -08002097 move $a0, $t7 # Load interface method.
Andreas Gampe3031c8d2015-07-13 20:11:06 -07002098 INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
Jeff Hao88474b42013-10-23 16:24:40 -07002099END art_quick_imt_conflict_trampoline
2100
Ian Rogers468532e2013-08-05 10:56:33 -07002101 .extern artQuickResolutionTrampoline
2102ENTRY art_quick_resolution_trampoline
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002103 SETUP_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002104 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002105 la $t9, artQuickResolutionTrampoline
2106 jalr $t9 # (Method* called, receiver, Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002107 addiu $a3, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
Ian Rogers468532e2013-08-05 10:56:33 -07002108 beqz $v0, 1f
Douglas Leung735b8552014-10-31 12:21:40 -07002109 lw $a0, ARG_SLOT_SIZE($sp) # load resolved method to $a0
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002110 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Ian Rogers65d1b222013-09-27 10:59:41 -07002111 move $t9, $v0 # code pointer must be in $t9 to generate the global pointer
Douglas Leungf96e8bd2015-03-27 15:38:30 -07002112 jalr $zero, $t9 # tail call to method
Mathieu Chartier19841522013-10-22 11:29:00 -07002113 nop
Ian Rogers468532e2013-08-05 10:56:33 -070021141:
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002115 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Ian Rogers468532e2013-08-05 10:56:33 -07002116 DELIVER_PENDING_EXCEPTION
2117END art_quick_resolution_trampoline
2118
Douglas Leung735b8552014-10-31 12:21:40 -07002119 .extern artQuickGenericJniTrampoline
2120 .extern artQuickGenericJniEndTrampoline
2121ENTRY art_quick_generic_jni_trampoline
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002122 SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
Douglas Leung735b8552014-10-31 12:21:40 -07002123 move $s8, $sp # save $sp to $s8
2124 move $s3, $gp # save $gp to $s3
2125
2126 # prepare for call to artQuickGenericJniTrampoline(Thread*, SP)
2127 move $a0, rSELF # pass Thread::Current
2128 addiu $a1, $sp, ARG_SLOT_SIZE # save $sp (remove arg slots)
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002129 la $t9, artQuickGenericJniTrampoline
2130 jalr $t9 # (Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002131 addiu $sp, $sp, -5120 # reserve space on the stack
2132
2133 # The C call will have registered the complete save-frame on success.
2134 # The result of the call is:
2135 # v0: ptr to native code, 0 on error.
2136 # v1: ptr to the bottom of the used area of the alloca, can restore stack till here.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002137 beq $v0, $zero, 2f # check entry error
Douglas Leung735b8552014-10-31 12:21:40 -07002138 move $t9, $v0 # save the code ptr
2139 move $sp, $v1 # release part of the alloca
2140
2141 # Load parameters from stack into registers
2142 lw $a0, 0($sp)
2143 lw $a1, 4($sp)
2144 lw $a2, 8($sp)
Douglas Leung735b8552014-10-31 12:21:40 -07002145 lw $a3, 12($sp)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002146
2147 # artQuickGenericJniTrampoline sets bit 0 of the native code address to 1
2148 # when the first two arguments are both single precision floats. This lets
2149 # us extract them properly from the stack and load into floating point
2150 # registers.
2151 MTD $a0, $a1, $f12, $f13
2152 andi $t0, $t9, 1
2153 xor $t9, $t9, $t0
2154 bnez $t0, 1f
2155 mtc1 $a1, $f14
2156 MTD $a2, $a3, $f14, $f15
2157
21581:
2159 jalr $t9 # native call
2160 nop
Douglas Leung735b8552014-10-31 12:21:40 -07002161 addiu $sp, $sp, 16 # remove arg slots
2162
2163 move $gp, $s3 # restore $gp from $s3
2164
2165 # result sign extension is handled in C code
2166 # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f)
2167 move $a0, rSELF # pass Thread::Current
2168 move $a2, $v0 # pass result
2169 move $a3, $v1
2170 addiu $sp, $sp, -24 # reserve arg slots
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002171 la $t9, artQuickGenericJniEndTrampoline
2172 jalr $t9
Douglas Leung735b8552014-10-31 12:21:40 -07002173 s.d $f0, 16($sp) # pass result_f
Douglas Leung735b8552014-10-31 12:21:40 -07002174
2175 lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002176 bne $t0, $zero, 2f # check for pending exceptions
Nicolas Geoffray126d6592015-03-03 14:28:35 +00002177
Douglas Leung735b8552014-10-31 12:21:40 -07002178 move $sp, $s8 # tear down the alloca
2179
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002180 # tear down the callee-save frame
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002181 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002182
Duane Sande34652f2014-11-04 11:09:36 -08002183 MTD $v0, $v1, $f0, $f1 # move float value to return value
Andreas Gampe8d365912015-01-13 11:32:32 -08002184 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002185 nop
Douglas Leung735b8552014-10-31 12:21:40 -07002186
Alexey Frunze1b8464d2016-11-12 17:22:05 -080021872:
Alexey Frunzec61c0762017-04-10 13:54:23 -07002188 lw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
2189 move $gp, $s3 # restore $gp from $s3
Nicolas Geoffray126d6592015-03-03 14:28:35 +00002190 # This will create a new save-all frame, required by the runtime.
Douglas Leung735b8552014-10-31 12:21:40 -07002191 DELIVER_PENDING_EXCEPTION
2192END art_quick_generic_jni_trampoline
Andreas Gampe2da88232014-02-27 12:26:20 -08002193
Ian Rogers468532e2013-08-05 10:56:33 -07002194 .extern artQuickToInterpreterBridge
2195ENTRY art_quick_to_interpreter_bridge
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002196 SETUP_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002197 move $a1, rSELF # pass Thread::Current
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002198 la $t9, artQuickToInterpreterBridge
2199 jalr $t9 # (Method* method, Thread*, SP)
Douglas Leung735b8552014-10-31 12:21:40 -07002200 addiu $a2, $sp, ARG_SLOT_SIZE # pass $sp (remove arg slots)
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002201 lw $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002202 RESTORE_SAVE_REFS_AND_ARGS_FRAME
Alexey Frunze1b8464d2016-11-12 17:22:05 -08002203 bnez $t7, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002204 # don't care if $v0 and/or $v1 are modified, when exception branch taken
2205 MTD $v0, $v1, $f0, $f1 # move float value to return value
Andreas Gampe8d365912015-01-13 11:32:32 -08002206 jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002207 nop
Ian Rogers7db619b2013-01-16 18:35:48 -080022081:
2209 DELIVER_PENDING_EXCEPTION
Ian Rogers468532e2013-08-05 10:56:33 -07002210END art_quick_to_interpreter_bridge
Ian Rogers7db619b2013-01-16 18:35:48 -08002211
Alex Lightdb01a092017-04-03 15:39:55 -07002212 .extern artInvokeObsoleteMethod
2213ENTRY art_invoke_obsolete_method_stub
2214 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
2215 la $t9, artInvokeObsoleteMethod
2216 jalr $t9 # (Method* method, Thread* self)
2217 move $a1, rSELF # pass Thread::Current
2218END art_invoke_obsolete_method_stub
2219
buzbee5bc5a7b2012-03-07 15:52:59 -08002220 /*
jeffhao725a9572012-11-13 18:20:12 -08002221 * Routine that intercepts method calls and returns.
buzbee5bc5a7b2012-03-07 15:52:59 -08002222 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002223 .extern artInstrumentationMethodEntryFromCode
2224 .extern artInstrumentationMethodExitFromCode
Ian Rogers468532e2013-08-05 10:56:33 -07002225ENTRY art_quick_instrumentation_entry
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002226 SETUP_SAVE_REFS_AND_ARGS_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002227 sw $a0, 28($sp) # save arg0 in free arg slot
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002228 addiu $a3, $sp, ARG_SLOT_SIZE # Pass $sp.
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002229 la $t9, artInstrumentationMethodEntryFromCode
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002230 jalr $t9 # (Method*, Object*, Thread*, SP)
Ian Rogers62d6c772013-02-27 08:32:07 -08002231 move $a2, rSELF # pass Thread::Current
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002232 beqz $v0, .Ldeliver_instrumentation_entry_exception
jeffhao8161c032012-10-31 15:50:00 -07002233 move $t9, $v0 # $t9 holds reference to code
Douglas Leung735b8552014-10-31 12:21:40 -07002234 lw $a0, 28($sp) # restore arg0 from free arg slot
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002235 RESTORE_SAVE_REFS_AND_ARGS_FRAME
jeffhao8161c032012-10-31 15:50:00 -07002236 jalr $t9 # call method
Ian Rogers62d6c772013-02-27 08:32:07 -08002237 nop
Ian Rogers468532e2013-08-05 10:56:33 -07002238END art_quick_instrumentation_entry
buzbee5bc5a7b2012-03-07 15:52:59 -08002239 /* intentional fallthrough */
Ian Rogers468532e2013-08-05 10:56:33 -07002240 .global art_quick_instrumentation_exit
2241art_quick_instrumentation_exit:
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002242 .cfi_startproc
jeffhao12051ea2013-01-10 11:24:31 -08002243 addiu $t9, $ra, 4 # put current address into $t9 to rebuild $gp
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002244 .cpload $t9
Douglas Leungc3d131e2014-07-16 17:32:41 -07002245 move $ra, $zero # link register is to here, so clobber with 0 for later checks
Douglas Leung735b8552014-10-31 12:21:40 -07002246
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002247 SETUP_SAVE_REFS_ONLY_FRAME
Douglas Leung735b8552014-10-31 12:21:40 -07002248 addiu $sp, $sp, -16 # allocate temp storage on the stack
2249 .cfi_adjust_cfa_offset 16
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002250 sw $v0, ARG_SLOT_SIZE+8($sp)
2251 .cfi_rel_offset 2, ARG_SLOT_SIZE+8
2252 sw $v1, ARG_SLOT_SIZE+12($sp)
2253 .cfi_rel_offset 3, ARG_SLOT_SIZE+12
Douglas Leungf96e8bd2015-03-27 15:38:30 -07002254 s.d $f0, ARG_SLOT_SIZE($sp)
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002255 addiu $a3, $sp, ARG_SLOT_SIZE # Pass fpr_res pointer.
2256 addiu $a2, $sp, ARG_SLOT_SIZE+8 # Pass gpr_res pointer.
2257 addiu $a1, $sp, ARG_SLOT_SIZE+16 # Pass $sp (remove arg slots and temp storage).
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002258 la $t9, artInstrumentationMethodExitFromCode
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002259 jalr $t9 # (Thread*, SP, gpr_res*, fpr_res*)
2260 move $a0, rSELF # Pass Thread::Current.
2261 move $t9, $v0 # Set aside returned link register.
2262 move $ra, $v1 # Set link register for deoptimization.
2263 lw $v0, ARG_SLOT_SIZE+8($sp) # Restore return values.
2264 lw $v1, ARG_SLOT_SIZE+12($sp)
Douglas Leungf96e8bd2015-03-27 15:38:30 -07002265 l.d $f0, ARG_SLOT_SIZE($sp)
Goran Jakovljevic25e4d1e2017-06-14 13:47:44 +02002266 addiu $sp, $sp, 16
2267 .cfi_adjust_cfa_offset -16
2268 RESTORE_SAVE_REFS_ONLY_FRAME
2269 beqz $t9, .Ldo_deliver_instrumentation_exception
2270 nop # Deliver exception if we got nullptr as function.
2271 jalr $zero, $t9 # Otherwise, return.
2272 nop
2273.Ldeliver_instrumentation_entry_exception:
2274 # Deliver exception for art_quick_instrumentation_entry placed after
2275 # art_quick_instrumentation_exit so that the fallthrough works.
2276 RESTORE_SAVE_REFS_AND_ARGS_FRAME
2277.Ldo_deliver_instrumentation_exception:
2278 DELIVER_PENDING_EXCEPTION
Ian Rogers468532e2013-08-05 10:56:33 -07002279END art_quick_instrumentation_exit
buzbee5bc5a7b2012-03-07 15:52:59 -08002280
jeffhao12051ea2013-01-10 11:24:31 -08002281 /*
Ian Rogers62d6c772013-02-27 08:32:07 -08002282 * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
2283 * will long jump to the upcall with a special exception of -1.
jeffhao12051ea2013-01-10 11:24:31 -08002284 */
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002285 .extern artDeoptimize
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002286ENTRY art_quick_deoptimize
Vladimir Markofd36f1f2016-08-03 18:49:58 +01002287 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002288 la $t9, artDeoptimize
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01002289 jalr $t9 # (Thread*)
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002290 move $a0, rSELF # pass Thread::current
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002291END art_quick_deoptimize
jeffhao12051ea2013-01-10 11:24:31 -08002292
buzbee5bc5a7b2012-03-07 15:52:59 -08002293 /*
Sebastien Hertz07474662015-08-25 15:12:33 +00002294 * Compiled code has requested that we deoptimize into the interpreter. The deoptimization
2295 * will long jump to the upcall with a special exception of -1.
2296 */
2297 .extern artDeoptimizeFromCompiledCode
2298ENTRY art_quick_deoptimize_from_compiled_code
Vladimir Marko239d6ea2016-09-05 10:44:04 +01002299 SETUP_SAVE_EVERYTHING_FRAME
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002300 la $t9, artDeoptimizeFromCompiledCode
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01002301 jalr $t9 # (DeoptimizationKind, Thread*)
2302 move $a1, rSELF # pass Thread::current
Sebastien Hertz07474662015-08-25 15:12:33 +00002303END art_quick_deoptimize_from_compiled_code
2304
2305 /*
buzbee5bc5a7b2012-03-07 15:52:59 -08002306 * Long integer shift. This is different from the generic 32/64-bit
2307 * binary operations because vAA/vBB are 64-bit but vCC (the shift
2308 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
2309 * 6 bits.
2310 * On entry:
jeffhao7fbee072012-08-24 17:56:54 -07002311 * $a0: low word
2312 * $a1: high word
2313 * $a2: shift count
buzbee5bc5a7b2012-03-07 15:52:59 -08002314 */
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002315ENTRY_NO_GP art_quick_shl_long
buzbee5bc5a7b2012-03-07 15:52:59 -08002316 /* shl-long vAA, vBB, vCC */
jeffhao7fbee072012-08-24 17:56:54 -07002317 sll $v0, $a0, $a2 # rlo<- alo << (shift&31)
2318 not $v1, $a2 # rhi<- 31-shift (shift is 5b)
2319 srl $a0, 1
2320 srl $a0, $v1 # alo<- alo >> (32-(shift&31))
2321 sll $v1, $a1, $a2 # rhi<- ahi << (shift&31)
jeffhao7fbee072012-08-24 17:56:54 -07002322 andi $a2, 0x20 # shift< shift & 0x20
Duane Sande34652f2014-11-04 11:09:36 -08002323 beqz $a2, 1f
2324 or $v1, $a0 # rhi<- rhi | alo
2325
2326 move $v1, $v0 # rhi<- rlo (if shift&0x20)
2327 move $v0, $zero # rlo<- 0 (if shift&0x20)
2328
Andreas Gampe8d365912015-01-13 11:32:32 -080023291: jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002330 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002331END art_quick_shl_long
buzbee5bc5a7b2012-03-07 15:52:59 -08002332
buzbee5bc5a7b2012-03-07 15:52:59 -08002333 /*
2334 * Long integer shift. This is different from the generic 32/64-bit
2335 * binary operations because vAA/vBB are 64-bit but vCC (the shift
2336 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
2337 * 6 bits.
2338 * On entry:
jeffhao7fbee072012-08-24 17:56:54 -07002339 * $a0: low word
2340 * $a1: high word
2341 * $a2: shift count
buzbee5bc5a7b2012-03-07 15:52:59 -08002342 */
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002343ENTRY_NO_GP art_quick_shr_long
jeffhao7fbee072012-08-24 17:56:54 -07002344 sra $v1, $a1, $a2 # rhi<- ahi >> (shift&31)
2345 srl $v0, $a0, $a2 # rlo<- alo >> (shift&31)
2346 sra $a3, $a1, 31 # $a3<- sign(ah)
2347 not $a0, $a2 # alo<- 31-shift (shift is 5b)
2348 sll $a1, 1
2349 sll $a1, $a0 # ahi<- ahi << (32-(shift&31))
jeffhao7fbee072012-08-24 17:56:54 -07002350 andi $a2, 0x20 # shift & 0x20
Douglas Leung475cfd82014-12-16 20:15:41 -08002351 beqz $a2, 1f
Duane Sande34652f2014-11-04 11:09:36 -08002352 or $v0, $a1 # rlo<- rlo | ahi
2353
2354 move $v0, $v1 # rlo<- rhi (if shift&0x20)
2355 move $v1, $a3 # rhi<- sign(ahi) (if shift&0x20)
2356
Andreas Gampe8d365912015-01-13 11:32:32 -080023571: jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002358 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002359END art_quick_shr_long
buzbee5bc5a7b2012-03-07 15:52:59 -08002360
buzbee5bc5a7b2012-03-07 15:52:59 -08002361 /*
2362 * Long integer shift. This is different from the generic 32/64-bit
2363 * binary operations because vAA/vBB are 64-bit but vCC (the shift
2364 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
2365 * 6 bits.
2366 * On entry:
Goran Jakovljevic590b1362016-03-21 14:24:43 +01002367 * $a0: low word
2368 * $a1: high word
2369 * $a2: shift count
buzbee5bc5a7b2012-03-07 15:52:59 -08002370 */
2371 /* ushr-long vAA, vBB, vCC */
Ian Rogers1d8cdbc2014-09-22 22:51:09 -07002372ENTRY_NO_GP art_quick_ushr_long
jeffhaofc6a30e2012-10-18 18:24:15 -07002373 srl $v1, $a1, $a2 # rhi<- ahi >> (shift&31)
jeffhao7fbee072012-08-24 17:56:54 -07002374 srl $v0, $a0, $a2 # rlo<- alo >> (shift&31)
jeffhao7fbee072012-08-24 17:56:54 -07002375 not $a0, $a2 # alo<- 31-shift (shift is 5b)
2376 sll $a1, 1
2377 sll $a1, $a0 # ahi<- ahi << (32-(shift&31))
jeffhao7fbee072012-08-24 17:56:54 -07002378 andi $a2, 0x20 # shift & 0x20
Duane Sande34652f2014-11-04 11:09:36 -08002379 beqz $a2, 1f
2380 or $v0, $a1 # rlo<- rlo | ahi
2381
2382 move $v0, $v1 # rlo<- rhi (if shift&0x20)
2383 move $v1, $zero # rhi<- 0 (if shift&0x20)
2384
Andreas Gampe8d365912015-01-13 11:32:32 -080023851: jalr $zero, $ra
Duane Sande34652f2014-11-04 11:09:36 -08002386 nop
Jeff Haod4c3f7d2013-02-14 14:14:44 -08002387END art_quick_ushr_long
jeffhao7fbee072012-08-24 17:56:54 -07002388
Chris Larsencf283da2016-01-19 16:45:35 -08002389/* java.lang.String.indexOf(int ch, int fromIndex=0) */
2390ENTRY_NO_GP art_quick_indexof
2391/* $a0 holds address of "this" */
2392/* $a1 holds "ch" */
2393/* $a2 holds "fromIndex" */
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002394#if (STRING_COMPRESSION_FEATURE)
2395 lw $a3, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this
Chris Larsencf283da2016-01-19 16:45:35 -08002396#else
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002397 lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # this.length()
Chris Larsencf283da2016-01-19 16:45:35 -08002398#endif
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002399 slt $t1, $a2, $zero # if fromIndex < 0
Goran Jakovljeviccdb23d62017-02-28 14:58:01 +01002400#if defined(_MIPS_ARCH_MIPS32R6)
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002401 seleqz $a2, $a2, $t1 # fromIndex = 0;
2402#else
2403 movn $a2, $zero, $t1 # fromIndex = 0;
2404#endif
Goran Jakovljeviccdb23d62017-02-28 14:58:01 +01002405
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002406#if (STRING_COMPRESSION_FEATURE)
2407 srl $t0, $a3, 1 # $a3 holds count (with flag) and $t0 holds actual length
2408#endif
2409 subu $t0, $t0, $a2 # this.length() - fromIndex
2410 blez $t0, 6f # if this.length()-fromIndex <= 0
2411 li $v0, -1 # return -1;
Chris Larsencf283da2016-01-19 16:45:35 -08002412
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002413#if (STRING_COMPRESSION_FEATURE)
2414 sll $a3, $a3, 31 # Extract compression flag.
2415 beqz $a3, .Lstring_indexof_compressed
2416 move $t2, $a0 # Save a copy in $t2 to later compute result (in branch delay slot).
2417#endif
2418 sll $v0, $a2, 1 # $a0 += $a2 * 2
2419 addu $a0, $a0, $v0 # " ditto "
2420 move $v0, $a2 # Set i to fromIndex.
Chris Larsencf283da2016-01-19 16:45:35 -08002421
24221:
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002423 lhu $t3, MIRROR_STRING_VALUE_OFFSET($a0) # if this.charAt(i) == ch
2424 beq $t3, $a1, 6f # return i;
2425 addu $a0, $a0, 2 # i++
2426 subu $t0, $t0, 1 # this.length() - i
2427 bnez $t0, 1b # while this.length() - i > 0
2428 addu $v0, $v0, 1 # i++
Chris Larsencf283da2016-01-19 16:45:35 -08002429
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002430 li $v0, -1 # if this.length() - i <= 0
2431 # return -1;
Chris Larsencf283da2016-01-19 16:45:35 -08002432
24336:
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002434 j $ra
2435 nop
2436
2437#if (STRING_COMPRESSION_FEATURE)
2438.Lstring_indexof_compressed:
2439 addu $a0, $a0, $a2 # $a0 += $a2
2440
2441.Lstring_indexof_compressed_loop:
2442 lbu $t3, MIRROR_STRING_VALUE_OFFSET($a0)
2443 beq $t3, $a1, .Lstring_indexof_compressed_matched
2444 subu $t0, $t0, 1
2445 bgtz $t0, .Lstring_indexof_compressed_loop
2446 addu $a0, $a0, 1
2447
2448.Lstring_indexof_nomatch:
2449 jalr $zero, $ra
2450 li $v0, -1 # return -1;
2451
2452.Lstring_indexof_compressed_matched:
2453 jalr $zero, $ra
2454 subu $v0, $a0, $t2 # return (current - start);
2455#endif
Chris Larsencf283da2016-01-19 16:45:35 -08002456END art_quick_indexof
2457
Chris Larsencf283da2016-01-19 16:45:35 -08002458/* java.lang.String.compareTo(String anotherString) */
2459ENTRY_NO_GP art_quick_string_compareto
2460/* $a0 holds address of "this" */
2461/* $a1 holds address of "anotherString" */
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002462 beq $a0, $a1, .Lstring_compareto_length_diff # this and anotherString are the same object
2463 move $a3, $a2 # trick to return 0 (it returns a2 - a3)
Chris Larsencf283da2016-01-19 16:45:35 -08002464
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002465#if (STRING_COMPRESSION_FEATURE)
2466 lw $t0, MIRROR_STRING_COUNT_OFFSET($a0) # 'count' field of this
2467 lw $t1, MIRROR_STRING_COUNT_OFFSET($a1) # 'count' field of anotherString
2468 sra $a2, $t0, 1 # this.length()
2469 sra $a3, $t1, 1 # anotherString.length()
2470#else
2471 lw $a2, MIRROR_STRING_COUNT_OFFSET($a0) # this.length()
2472 lw $a3, MIRROR_STRING_COUNT_OFFSET($a1) # anotherString.length()
2473#endif
Chris Larsencf283da2016-01-19 16:45:35 -08002474
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002475 MINu $t2, $a2, $a3
2476 # $t2 now holds min(this.length(),anotherString.length())
Chris Larsencf283da2016-01-19 16:45:35 -08002477
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002478 # while min(this.length(),anotherString.length())-i != 0
2479 beqz $t2, .Lstring_compareto_length_diff # if $t2==0
2480 nop # return (this.length() - anotherString.length())
2481
2482#if (STRING_COMPRESSION_FEATURE)
2483 # Differ cases:
2484 sll $t3, $t0, 31
2485 beqz $t3, .Lstring_compareto_this_is_compressed
2486 sll $t3, $t1, 31 # In branch delay slot.
2487 beqz $t3, .Lstring_compareto_that_is_compressed
2488 nop
2489 b .Lstring_compareto_both_not_compressed
2490 nop
2491
2492.Lstring_compareto_this_is_compressed:
2493 beqz $t3, .Lstring_compareto_both_compressed
2494 nop
2495 /* If (this->IsCompressed() && that->IsCompressed() == false) */
2496.Lstring_compareto_loop_comparison_this_compressed:
2497 lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2498 lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2499 bne $t0, $t1, .Lstring_compareto_char_diff
2500 addiu $a0, $a0, 1 # point at this.charAt(i++) - compressed
2501 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2502 bnez $t2, .Lstring_compareto_loop_comparison_this_compressed
2503 addiu $a1, $a1, 2 # point at anotherString.charAt(i++) - uncompressed
2504 jalr $zero, $ra
2505 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2506
2507.Lstring_compareto_that_is_compressed:
2508 lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2509 lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2510 bne $t0, $t1, .Lstring_compareto_char_diff
2511 addiu $a0, $a0, 2 # point at this.charAt(i++) - uncompressed
2512 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2513 bnez $t2, .Lstring_compareto_that_is_compressed
2514 addiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed
2515 jalr $zero, $ra
2516 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2517
2518.Lstring_compareto_both_compressed:
2519 lbu $t0, MIRROR_STRING_VALUE_OFFSET($a0)
2520 lbu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2521 bne $t0, $t1, .Lstring_compareto_char_diff
2522 addiu $a0, $a0, 1 # point at this.charAt(i++) - compressed
2523 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2524 bnez $t2, .Lstring_compareto_both_compressed
2525 addiu $a1, $a1, 1 # point at anotherString.charAt(i++) - compressed
2526 jalr $zero, $ra
2527 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2528#endif
2529
2530.Lstring_compareto_both_not_compressed:
2531 lhu $t0, MIRROR_STRING_VALUE_OFFSET($a0) # while this.charAt(i) == anotherString.charAt(i)
2532 lhu $t1, MIRROR_STRING_VALUE_OFFSET($a1)
2533 bne $t0, $t1, .Lstring_compareto_char_diff # if this.charAt(i) != anotherString.charAt(i)
2534 # return (this.charAt(i) - anotherString.charAt(i))
2535 addiu $a0, $a0, 2 # point at this.charAt(i++)
2536 subu $t2, $t2, 1 # new value of min(this.length(),anotherString.length())-i
2537 bnez $t2, .Lstring_compareto_both_not_compressed
2538 addiu $a1, $a1, 2 # point at anotherString.charAt(i++)
2539
2540.Lstring_compareto_length_diff:
2541 jalr $zero, $ra
2542 subu $v0, $a2, $a3 # return (this.length() - anotherString.length())
2543
2544.Lstring_compareto_char_diff:
2545 jalr $zero, $ra
2546 subu $v0, $t0, $t1 # return (this.charAt(i) - anotherString.charAt(i))
Chris Larsencf283da2016-01-19 16:45:35 -08002547END art_quick_string_compareto
Orion Hodsonac141392017-01-13 11:53:47 +00002548
Alexey Frunze15958152017-02-09 19:08:30 -08002549 /*
2550 * Create a function `name` calling the ReadBarrier::Mark routine,
2551 * getting its argument and returning its result through register
2552 * `reg`, saving and restoring all caller-save registers.
2553 */
2554.macro READ_BARRIER_MARK_REG name, reg
2555ENTRY \name
Alexey Frunzea3cb1322017-05-01 18:49:46 -07002556 // Null check so that we can load the lock word.
2557 bnez \reg, .Lnot_null_\name
2558 nop
2559.Lret_rb_\name:
2560 jalr $zero, $ra
2561 nop
2562.Lnot_null_\name:
2563 // Check lock word for mark bit, if marked return.
2564 lw $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET(\reg)
2565 .set push
2566 .set noat
2567 sll $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT # Move mark bit to sign bit.
2568 bltz $at, .Lret_rb_\name
2569#if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
2570 // The below code depends on the lock word state being in the highest bits
2571 // and the "forwarding address" state having all bits set.
2572#error "Unexpected lock word state shift or forwarding address state value."
2573#endif
2574 // Test that both the forwarding state bits are 1.
2575 sll $at, $t9, 1
2576 and $at, $at, $t9 # Sign bit = 1 IFF both bits are 1.
2577 bltz $at, .Lret_forwarding_address\name
2578 nop
2579 .set pop
2580
2581 addiu $sp, $sp, -160 # Includes 16 bytes of space for argument registers a0-a3.
Alexey Frunze15958152017-02-09 19:08:30 -08002582 .cfi_adjust_cfa_offset 160
2583
2584 sw $ra, 156($sp)
2585 .cfi_rel_offset 31, 156
2586 sw $t8, 152($sp)
2587 .cfi_rel_offset 24, 152
2588 sw $t7, 148($sp)
2589 .cfi_rel_offset 15, 148
2590 sw $t6, 144($sp)
2591 .cfi_rel_offset 14, 144
2592 sw $t5, 140($sp)
2593 .cfi_rel_offset 13, 140
2594 sw $t4, 136($sp)
2595 .cfi_rel_offset 12, 136
2596 sw $t3, 132($sp)
2597 .cfi_rel_offset 11, 132
2598 sw $t2, 128($sp)
2599 .cfi_rel_offset 10, 128
2600 sw $t1, 124($sp)
2601 .cfi_rel_offset 9, 124
2602 sw $t0, 120($sp)
2603 .cfi_rel_offset 8, 120
2604 sw $a3, 116($sp)
2605 .cfi_rel_offset 7, 116
2606 sw $a2, 112($sp)
2607 .cfi_rel_offset 6, 112
2608 sw $a1, 108($sp)
2609 .cfi_rel_offset 5, 108
2610 sw $a0, 104($sp)
2611 .cfi_rel_offset 4, 104
2612 sw $v1, 100($sp)
2613 .cfi_rel_offset 3, 100
2614 sw $v0, 96($sp)
2615 .cfi_rel_offset 2, 96
2616
2617 la $t9, artReadBarrierMark
2618
2619 sdc1 $f18, 88($sp)
2620 sdc1 $f16, 80($sp)
2621 sdc1 $f14, 72($sp)
2622 sdc1 $f12, 64($sp)
2623 sdc1 $f10, 56($sp)
2624 sdc1 $f8, 48($sp)
2625 sdc1 $f6, 40($sp)
2626 sdc1 $f4, 32($sp)
2627 sdc1 $f2, 24($sp)
2628
2629 .ifnc \reg, $a0
2630 move $a0, \reg # pass obj from `reg` in a0
2631 .endif
2632 jalr $t9 # v0 <- artReadBarrierMark(obj)
2633 sdc1 $f0, 16($sp) # in delay slot
2634
2635 lw $ra, 156($sp)
2636 .cfi_restore 31
2637 lw $t8, 152($sp)
2638 .cfi_restore 24
2639 lw $t7, 148($sp)
2640 .cfi_restore 15
2641 lw $t6, 144($sp)
2642 .cfi_restore 14
2643 lw $t5, 140($sp)
2644 .cfi_restore 13
2645 lw $t4, 136($sp)
2646 .cfi_restore 12
2647 lw $t3, 132($sp)
2648 .cfi_restore 11
2649 lw $t2, 128($sp)
2650 .cfi_restore 10
2651 lw $t1, 124($sp)
2652 .cfi_restore 9
2653 lw $t0, 120($sp)
2654 .cfi_restore 8
2655 lw $a3, 116($sp)
2656 .cfi_restore 7
2657 lw $a2, 112($sp)
2658 .cfi_restore 6
2659 lw $a1, 108($sp)
2660 .cfi_restore 5
2661 lw $a0, 104($sp)
2662 .cfi_restore 4
2663 lw $v1, 100($sp)
2664 .cfi_restore 3
2665
2666 .ifnc \reg, $v0
2667 move \reg, $v0 # `reg` <- v0
2668 lw $v0, 96($sp)
2669 .cfi_restore 2
2670 .endif
2671
2672 ldc1 $f18, 88($sp)
2673 ldc1 $f16, 80($sp)
2674 ldc1 $f14, 72($sp)
2675 ldc1 $f12, 64($sp)
2676 ldc1 $f10, 56($sp)
2677 ldc1 $f8, 48($sp)
2678 ldc1 $f6, 40($sp)
2679 ldc1 $f4, 32($sp)
2680 ldc1 $f2, 24($sp)
2681 ldc1 $f0, 16($sp)
2682
2683 jalr $zero, $ra
2684 addiu $sp, $sp, 160
2685 .cfi_adjust_cfa_offset -160
Alexey Frunzea3cb1322017-05-01 18:49:46 -07002686
2687.Lret_forwarding_address\name:
2688 jalr $zero, $ra
2689 // Shift left by the forwarding address shift. This clears out the state bits since they are
2690 // in the top 2 bits of the lock word.
2691 sll \reg, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
Alexey Frunze15958152017-02-09 19:08:30 -08002692END \name
2693.endm
2694
2695// Note that art_quick_read_barrier_mark_regXX corresponds to register XX+1.
2696// ZERO (register 0) is reserved.
2697// AT (register 1) is reserved as a temporary/scratch register.
2698READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, $v0
2699READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, $v1
2700READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, $a0
2701READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg04, $a1
2702READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, $a2
2703READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, $a3
2704READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg07, $t0
2705READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg08, $t1
2706READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg09, $t2
2707READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg10, $t3
2708READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg11, $t4
2709READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg12, $t5
2710READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg13, $t6
2711READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg14, $t7
2712// S0 and S1 (registers 16 and 17) are reserved as suspended and thread registers.
2713READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg17, $s2
2714READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, $s3
2715READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg19, $s4
2716READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg20, $s5
2717READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg21, $s6
2718READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg22, $s7
2719// T8 and T9 (registers 24 and 25) are reserved as temporary/scratch registers.
2720// K0, K1, GP, SP (registers 26 - 29) are reserved.
2721READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg29, $s8
2722// RA (register 31) is reserved.
2723
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002724// Caller code:
2725// Short constant offset/index:
2726// R2: | R6:
2727// lw $t9, pReadBarrierMarkReg00
2728// beqz $t9, skip_call | beqzc $t9, skip_call
2729// addiu $t9, $t9, thunk_disp | nop
2730// jalr $t9 | jialc $t9, thunk_disp
2731// nop |
2732// skip_call: | skip_call:
2733// lw `out`, ofs(`obj`) | lw `out`, ofs(`obj`)
2734// [subu `out`, $zero, `out`] | [subu `out`, $zero, `out`] # Unpoison reference.
2735.macro BRB_FIELD_SHORT_OFFSET_ENTRY obj
27361:
2737 # Explicit null check. May be redundant (for array elements or when the field
2738 # offset is larger than the page size, 4KB).
2739 # $ra will be adjusted to point to lw's stack map when throwing NPE.
2740 beqz \obj, .Lintrospection_throw_npe
2741#if defined(_MIPS_ARCH_MIPS32R6)
2742 lapc $gp, .Lintrospection_exits # $gp = address of .Lintrospection_exits.
2743#else
2744 addiu $gp, $t9, (.Lintrospection_exits - 1b) # $gp = address of .Lintrospection_exits.
2745#endif
2746 .set push
2747 .set noat
2748 lw $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
2749 sll $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT # Move barrier state bit
2750 # to sign bit.
2751 bltz $at, .Lintrospection_field_array # If gray, load reference, mark.
2752 move $t8, \obj # Move `obj` to $t8 for common code.
2753 .set pop
2754 jalr $zero, $ra # Otherwise, load-load barrier and return.
2755 sync
2756.endm
2757
2758// Caller code (R2):
2759// Long constant offset/index: | Variable index:
2760// lw $t9, pReadBarrierMarkReg00
2761// lui $t8, ofs_hi | sll $t8, `index`, 2
2762// beqz $t9, skip_call | beqz $t9, skip_call
2763// addiu $t9, $t9, thunk_disp | addiu $t9, $t9, thunk_disp
2764// jalr $t9 | jalr $t9
2765// skip_call: | skip_call:
2766// addu $t8, $t8, `obj` | addu $t8, $t8, `obj`
2767// lw `out`, ofs_lo($t8) | lw `out`, ofs($t8)
2768// [subu `out`, $zero, `out`] | [subu `out`, $zero, `out`] # Unpoison reference.
2769//
2770// Caller code (R6):
2771// Long constant offset/index: | Variable index:
2772// lw $t9, pReadBarrierMarkReg00
2773// beqz $t9, skip_call | beqz $t9, skip_call
2774// aui $t8, `obj`, ofs_hi | lsa $t8, `index`, `obj`, 2
2775// jialc $t9, thunk_disp | jialc $t9, thunk_disp
2776// skip_call: | skip_call:
2777// lw `out`, ofs_lo($t8) | lw `out`, ofs($t8)
2778// [subu `out`, $zero, `out`] | [subu `out`, $zero, `out`] # Unpoison reference.
2779.macro BRB_FIELD_LONG_OFFSET_ENTRY obj
27801:
2781 # No explicit null check for variable indices or large constant indices/offsets
2782 # as it must have been done earlier.
2783#if defined(_MIPS_ARCH_MIPS32R6)
2784 lapc $gp, .Lintrospection_exits # $gp = address of .Lintrospection_exits.
2785#else
2786 addiu $gp, $t9, (.Lintrospection_exits - 1b) # $gp = address of .Lintrospection_exits.
2787#endif
2788 .set push
2789 .set noat
2790 lw $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
2791 sll $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT # Move barrier state bit
2792 # to sign bit.
2793 bltz $at, .Lintrospection_field_array # If gray, load reference, mark.
2794 nop
2795 .set pop
2796 jalr $zero, $ra # Otherwise, load-load barrier and return.
2797 sync
2798 break # Padding to 8 instructions.
2799.endm
2800
2801.macro BRB_GC_ROOT_ENTRY root
28021:
2803#if defined(_MIPS_ARCH_MIPS32R6)
2804 lapc $gp, .Lintrospection_exit_\root # $gp = exit point address.
2805#else
2806 addiu $gp, $t9, (.Lintrospection_exit_\root - 1b) # $gp = exit point address.
2807#endif
2808 bnez \root, .Lintrospection_common
2809 move $t8, \root # Move reference to $t8 for common code.
2810 jalr $zero, $ra # Return if null.
2811 # The next instruction (from the following BRB_GC_ROOT_ENTRY) fills the delay slot.
2812 # This instruction has no effect (actual NOP for the last entry; otherwise changes $gp,
2813 # which is unused after that anyway).
2814.endm
2815
2816.macro BRB_FIELD_EXIT out
2817.Lintrospection_exit_\out:
2818 jalr $zero, $ra
2819 move \out, $t8 # Return reference in expected register.
2820.endm
2821
2822.macro BRB_FIELD_EXIT_BREAK
2823 break
2824 break
2825.endm
2826
2827ENTRY_NO_GP art_quick_read_barrier_mark_introspection
2828 # Entry points for offsets/indices not fitting into int16_t and for variable indices.
2829 BRB_FIELD_LONG_OFFSET_ENTRY $v0
2830 BRB_FIELD_LONG_OFFSET_ENTRY $v1
2831 BRB_FIELD_LONG_OFFSET_ENTRY $a0
2832 BRB_FIELD_LONG_OFFSET_ENTRY $a1
2833 BRB_FIELD_LONG_OFFSET_ENTRY $a2
2834 BRB_FIELD_LONG_OFFSET_ENTRY $a3
2835 BRB_FIELD_LONG_OFFSET_ENTRY $t0
2836 BRB_FIELD_LONG_OFFSET_ENTRY $t1
2837 BRB_FIELD_LONG_OFFSET_ENTRY $t2
2838 BRB_FIELD_LONG_OFFSET_ENTRY $t3
2839 BRB_FIELD_LONG_OFFSET_ENTRY $t4
2840 BRB_FIELD_LONG_OFFSET_ENTRY $t5
2841 BRB_FIELD_LONG_OFFSET_ENTRY $t6
2842 BRB_FIELD_LONG_OFFSET_ENTRY $t7
2843 BRB_FIELD_LONG_OFFSET_ENTRY $s2
2844 BRB_FIELD_LONG_OFFSET_ENTRY $s3
2845 BRB_FIELD_LONG_OFFSET_ENTRY $s4
2846 BRB_FIELD_LONG_OFFSET_ENTRY $s5
2847 BRB_FIELD_LONG_OFFSET_ENTRY $s6
2848 BRB_FIELD_LONG_OFFSET_ENTRY $s7
2849 BRB_FIELD_LONG_OFFSET_ENTRY $s8
2850
2851 # Entry points for offsets/indices fitting into int16_t.
2852 BRB_FIELD_SHORT_OFFSET_ENTRY $v0
2853 BRB_FIELD_SHORT_OFFSET_ENTRY $v1
2854 BRB_FIELD_SHORT_OFFSET_ENTRY $a0
2855 BRB_FIELD_SHORT_OFFSET_ENTRY $a1
2856 BRB_FIELD_SHORT_OFFSET_ENTRY $a2
2857 BRB_FIELD_SHORT_OFFSET_ENTRY $a3
2858 BRB_FIELD_SHORT_OFFSET_ENTRY $t0
2859 BRB_FIELD_SHORT_OFFSET_ENTRY $t1
2860 BRB_FIELD_SHORT_OFFSET_ENTRY $t2
2861 BRB_FIELD_SHORT_OFFSET_ENTRY $t3
2862 BRB_FIELD_SHORT_OFFSET_ENTRY $t4
2863 BRB_FIELD_SHORT_OFFSET_ENTRY $t5
2864 BRB_FIELD_SHORT_OFFSET_ENTRY $t6
2865 BRB_FIELD_SHORT_OFFSET_ENTRY $t7
2866 BRB_FIELD_SHORT_OFFSET_ENTRY $s2
2867 BRB_FIELD_SHORT_OFFSET_ENTRY $s3
2868 BRB_FIELD_SHORT_OFFSET_ENTRY $s4
2869 BRB_FIELD_SHORT_OFFSET_ENTRY $s5
2870 BRB_FIELD_SHORT_OFFSET_ENTRY $s6
2871 BRB_FIELD_SHORT_OFFSET_ENTRY $s7
2872 BRB_FIELD_SHORT_OFFSET_ENTRY $s8
2873
2874 .global art_quick_read_barrier_mark_introspection_gc_roots
2875art_quick_read_barrier_mark_introspection_gc_roots:
2876 # Entry points for GC roots.
2877 BRB_GC_ROOT_ENTRY $v0
2878 BRB_GC_ROOT_ENTRY $v1
2879 BRB_GC_ROOT_ENTRY $a0
2880 BRB_GC_ROOT_ENTRY $a1
2881 BRB_GC_ROOT_ENTRY $a2
2882 BRB_GC_ROOT_ENTRY $a3
2883 BRB_GC_ROOT_ENTRY $t0
2884 BRB_GC_ROOT_ENTRY $t1
2885 BRB_GC_ROOT_ENTRY $t2
2886 BRB_GC_ROOT_ENTRY $t3
2887 BRB_GC_ROOT_ENTRY $t4
2888 BRB_GC_ROOT_ENTRY $t5
2889 BRB_GC_ROOT_ENTRY $t6
2890 BRB_GC_ROOT_ENTRY $t7
2891 BRB_GC_ROOT_ENTRY $s2
2892 BRB_GC_ROOT_ENTRY $s3
2893 BRB_GC_ROOT_ENTRY $s4
2894 BRB_GC_ROOT_ENTRY $s5
2895 BRB_GC_ROOT_ENTRY $s6
2896 BRB_GC_ROOT_ENTRY $s7
2897 BRB_GC_ROOT_ENTRY $s8
2898 .global art_quick_read_barrier_mark_introspection_end_of_entries
2899art_quick_read_barrier_mark_introspection_end_of_entries:
2900 nop # Fill the delay slot of the last BRB_GC_ROOT_ENTRY.
2901
2902.Lintrospection_throw_npe:
2903 b art_quick_throw_null_pointer_exception
2904 addiu $ra, $ra, 4 # Skip lw, make $ra point to lw's stack map.
2905
2906 .set push
2907 .set noat
2908
2909 // Fields and array elements.
2910
2911.Lintrospection_field_array:
2912 // Get the field/element address using $t8 and the offset from the lw instruction.
2913 lh $at, 0($ra) # $ra points to lw: $at = field/element offset.
2914 addiu $ra, $ra, 4 + HEAP_POISON_INSTR_SIZE # Skip lw(+subu).
2915 addu $t8, $t8, $at # $t8 = field/element address.
2916
2917 // Calculate the address of the exit point, store it in $gp and load the reference into $t8.
2918 lb $at, (-HEAP_POISON_INSTR_SIZE - 2)($ra) # $ra-HEAP_POISON_INSTR_SIZE-4 points to
2919 # "lw `out`, ...".
2920 andi $at, $at, 31 # Extract `out` from lw.
2921 sll $at, $at, 3 # Multiply `out` by the exit point size (BRB_FIELD_EXIT* macros).
2922
2923 lw $t8, 0($t8) # $t8 = reference.
2924 UNPOISON_HEAP_REF $t8
2925
2926 // Return if null reference.
2927 bnez $t8, .Lintrospection_common
2928 addu $gp, $gp, $at # $gp = address of the exit point.
2929
2930 // Early return through the exit point.
2931.Lintrospection_return_early:
2932 jalr $zero, $gp # Move $t8 to `out` and return.
2933 nop
2934
2935 // Code common for GC roots, fields and array elements.
2936
2937.Lintrospection_common:
2938 // Check lock word for mark bit, if marked return.
2939 lw $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET($t8)
2940 sll $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT # Move mark bit to sign bit.
2941 bltz $at, .Lintrospection_return_early
2942#if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
2943 // The below code depends on the lock word state being in the highest bits
2944 // and the "forwarding address" state having all bits set.
2945#error "Unexpected lock word state shift or forwarding address state value."
2946#endif
2947 // Test that both the forwarding state bits are 1.
2948 sll $at, $t9, 1
2949 and $at, $at, $t9 # Sign bit = 1 IFF both bits are 1.
2950 bgez $at, .Lintrospection_mark
2951 nop
2952
2953 .set pop
2954
2955 // Shift left by the forwarding address shift. This clears out the state bits since they are
2956 // in the top 2 bits of the lock word.
2957 jalr $zero, $gp # Move $t8 to `out` and return.
2958 sll $t8, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
2959
2960.Lintrospection_mark:
2961 // Partially set up the stack frame preserving only $ra.
2962 addiu $sp, $sp, -160 # Includes 16 bytes of space for argument registers $a0-$a3.
2963 .cfi_adjust_cfa_offset 160
2964 sw $ra, 156($sp)
2965 .cfi_rel_offset 31, 156
2966
2967 // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
2968 bal 1f
2969 sw $gp, 152($sp) # Preserve the exit point address.
29701:
2971 .cpload $ra
2972
2973 // Finalize the stack frame and call.
2974 sw $t7, 148($sp)
2975 .cfi_rel_offset 15, 148
2976 sw $t6, 144($sp)
2977 .cfi_rel_offset 14, 144
2978 sw $t5, 140($sp)
2979 .cfi_rel_offset 13, 140
2980 sw $t4, 136($sp)
2981 .cfi_rel_offset 12, 136
2982 sw $t3, 132($sp)
2983 .cfi_rel_offset 11, 132
2984 sw $t2, 128($sp)
2985 .cfi_rel_offset 10, 128
2986 sw $t1, 124($sp)
2987 .cfi_rel_offset 9, 124
2988 sw $t0, 120($sp)
2989 .cfi_rel_offset 8, 120
2990 sw $a3, 116($sp)
2991 .cfi_rel_offset 7, 116
2992 sw $a2, 112($sp)
2993 .cfi_rel_offset 6, 112
2994 sw $a1, 108($sp)
2995 .cfi_rel_offset 5, 108
2996 sw $a0, 104($sp)
2997 .cfi_rel_offset 4, 104
2998 sw $v1, 100($sp)
2999 .cfi_rel_offset 3, 100
3000 sw $v0, 96($sp)
3001 .cfi_rel_offset 2, 96
3002
3003 la $t9, artReadBarrierMark
3004
3005 sdc1 $f18, 88($sp)
3006 sdc1 $f16, 80($sp)
3007 sdc1 $f14, 72($sp)
3008 sdc1 $f12, 64($sp)
3009 sdc1 $f10, 56($sp)
3010 sdc1 $f8, 48($sp)
3011 sdc1 $f6, 40($sp)
3012 sdc1 $f4, 32($sp)
3013 sdc1 $f2, 24($sp)
3014 sdc1 $f0, 16($sp)
3015
3016 jalr $t9 # $v0 <- artReadBarrierMark(reference)
3017 move $a0, $t8 # Pass reference in $a0.
3018 move $t8, $v0
3019
3020 lw $ra, 156($sp)
3021 .cfi_restore 31
3022 lw $gp, 152($sp) # $gp = address of the exit point.
3023 lw $t7, 148($sp)
3024 .cfi_restore 15
3025 lw $t6, 144($sp)
3026 .cfi_restore 14
3027 lw $t5, 140($sp)
3028 .cfi_restore 13
3029 lw $t4, 136($sp)
3030 .cfi_restore 12
3031 lw $t3, 132($sp)
3032 .cfi_restore 11
3033 lw $t2, 128($sp)
3034 .cfi_restore 10
3035 lw $t1, 124($sp)
3036 .cfi_restore 9
3037 lw $t0, 120($sp)
3038 .cfi_restore 8
3039 lw $a3, 116($sp)
3040 .cfi_restore 7
3041 lw $a2, 112($sp)
3042 .cfi_restore 6
3043 lw $a1, 108($sp)
3044 .cfi_restore 5
3045 lw $a0, 104($sp)
3046 .cfi_restore 4
3047 lw $v1, 100($sp)
3048 .cfi_restore 3
3049 lw $v0, 96($sp)
3050 .cfi_restore 2
3051
3052 ldc1 $f18, 88($sp)
3053 ldc1 $f16, 80($sp)
3054 ldc1 $f14, 72($sp)
3055 ldc1 $f12, 64($sp)
3056 ldc1 $f10, 56($sp)
3057 ldc1 $f8, 48($sp)
3058 ldc1 $f6, 40($sp)
3059 ldc1 $f4, 32($sp)
3060 ldc1 $f2, 24($sp)
3061 ldc1 $f0, 16($sp)
3062
3063 // Return through the exit point.
3064 jalr $zero, $gp # Move $t8 to `out` and return.
3065 addiu $sp, $sp, 160
3066 .cfi_adjust_cfa_offset -160
3067
3068.Lintrospection_exits:
3069 BRB_FIELD_EXIT_BREAK
3070 BRB_FIELD_EXIT_BREAK
3071 BRB_FIELD_EXIT $v0
3072 BRB_FIELD_EXIT $v1
3073 BRB_FIELD_EXIT $a0
3074 BRB_FIELD_EXIT $a1
3075 BRB_FIELD_EXIT $a2
3076 BRB_FIELD_EXIT $a3
3077 BRB_FIELD_EXIT $t0
3078 BRB_FIELD_EXIT $t1
3079 BRB_FIELD_EXIT $t2
3080 BRB_FIELD_EXIT $t3
3081 BRB_FIELD_EXIT $t4
3082 BRB_FIELD_EXIT $t5
3083 BRB_FIELD_EXIT $t6
3084 BRB_FIELD_EXIT $t7
3085 BRB_FIELD_EXIT_BREAK
3086 BRB_FIELD_EXIT_BREAK
3087 BRB_FIELD_EXIT $s2
3088 BRB_FIELD_EXIT $s3
3089 BRB_FIELD_EXIT $s4
3090 BRB_FIELD_EXIT $s5
3091 BRB_FIELD_EXIT $s6
3092 BRB_FIELD_EXIT $s7
3093 BRB_FIELD_EXIT_BREAK
3094 BRB_FIELD_EXIT_BREAK
3095 BRB_FIELD_EXIT_BREAK
3096 BRB_FIELD_EXIT_BREAK
3097 BRB_FIELD_EXIT_BREAK
3098 BRB_FIELD_EXIT_BREAK
3099 BRB_FIELD_EXIT $s8
3100 BRB_FIELD_EXIT_BREAK
3101END art_quick_read_barrier_mark_introspection
3102
Orion Hodsonac141392017-01-13 11:53:47 +00003103.extern artInvokePolymorphic
3104ENTRY art_quick_invoke_polymorphic
3105 SETUP_SAVE_REFS_AND_ARGS_FRAME
3106 move $a2, rSELF # Make $a2 an alias for the current Thread.
Alexey Frunzec480b982017-01-16 19:03:21 -08003107 addiu $a3, $sp, ARG_SLOT_SIZE # Make $a3 a pointer to the saved frame context.
Orion Hodsonac141392017-01-13 11:53:47 +00003108 sw $zero, 20($sp) # Initialize JValue result.
3109 sw $zero, 16($sp)
Orion Hodsonac141392017-01-13 11:53:47 +00003110 la $t9, artInvokePolymorphic
3111 jalr $t9 # (result, receiver, Thread*, context)
Alexey Frunzec480b982017-01-16 19:03:21 -08003112 addiu $a0, $sp, 16 # Make $a0 a pointer to the JValue result
Orion Hodsonac141392017-01-13 11:53:47 +00003113.macro MATCH_RETURN_TYPE c, handler
3114 li $t0, \c
3115 beq $v0, $t0, \handler
3116.endm
3117 MATCH_RETURN_TYPE 'V', .Lcleanup_and_return
3118 MATCH_RETURN_TYPE 'L', .Lstore_int_result
3119 MATCH_RETURN_TYPE 'I', .Lstore_int_result
3120 MATCH_RETURN_TYPE 'J', .Lstore_long_result
3121 MATCH_RETURN_TYPE 'B', .Lstore_int_result
3122 MATCH_RETURN_TYPE 'C', .Lstore_char_result
3123 MATCH_RETURN_TYPE 'D', .Lstore_double_result
3124 MATCH_RETURN_TYPE 'F', .Lstore_float_result
3125 MATCH_RETURN_TYPE 'S', .Lstore_int_result
Alexey Frunzec480b982017-01-16 19:03:21 -08003126 MATCH_RETURN_TYPE 'Z', .Lstore_boolean_result
Orion Hodsonac141392017-01-13 11:53:47 +00003127.purgem MATCH_RETURN_TYPE
3128 nop
3129 b .Lcleanup_and_return
3130 nop
3131.Lstore_boolean_result:
Alexey Frunzec480b982017-01-16 19:03:21 -08003132 b .Lcleanup_and_return
Orion Hodsonac141392017-01-13 11:53:47 +00003133 lbu $v0, 16($sp) # Move byte from JValue result to return value register.
Orion Hodsonac141392017-01-13 11:53:47 +00003134.Lstore_char_result:
Orion Hodsonac141392017-01-13 11:53:47 +00003135 b .Lcleanup_and_return
Alexey Frunzec480b982017-01-16 19:03:21 -08003136 lhu $v0, 16($sp) # Move char from JValue result to return value register.
Orion Hodsonac141392017-01-13 11:53:47 +00003137.Lstore_double_result:
3138.Lstore_float_result:
3139 LDu $f0, $f1, 16, $sp, $t0 # Move double/float from JValue result to return value register.
3140 b .Lcleanup_and_return
3141 nop
3142.Lstore_long_result:
3143 lw $v1, 20($sp) # Move upper bits from JValue result to return value register.
3144 // Fall-through for lower bits.
3145.Lstore_int_result:
3146 lw $v0, 16($sp) # Move lower bits from JValue result to return value register.
3147 // Fall-through to clean up and return.
3148.Lcleanup_and_return:
Orion Hodsonac141392017-01-13 11:53:47 +00003149 lw $t7, THREAD_EXCEPTION_OFFSET(rSELF) # Load Thread::Current()->exception_
3150 RESTORE_SAVE_REFS_AND_ARGS_FRAME
3151 bnez $t7, 1f # Success if no exception is pending.
3152 nop
3153 jalr $zero, $ra
3154 nop
31551:
3156 DELIVER_PENDING_EXCEPTION
3157END art_quick_invoke_polymorphic