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