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