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 .set noreorder 20 .balign 4 21 22 /* Deliver the given exception */ 23 .extern artDeliverExceptionFromCode 24 /* Deliver an exception pending on a thread */ 25 .extern artDeliverPendingExceptionFromCode 26 27 /* 28 * Macro that sets up the callee save frame to conform with 29 * Runtime::CreateCalleeSaveMethod(kSaveAll) 30 * callee-save: $s0-$s8 + $gp + $ra, 11 total + 1 word padding + 4 open words for args 31 */ 32.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 33 addiu $sp, $sp, -64 34 .cfi_adjust_cfa_offset 64 35 sw $ra, 60($sp) 36 .cfi_rel_offset 31, 60 37 sw $s8, 56($sp) 38 .cfi_rel_offset 30, 56 39 sw $gp, 52($sp) 40 .cfi_rel_offset 28, 52 41 sw $s7, 48($sp) 42 .cfi_rel_offset 23, 48 43 sw $s6, 44($sp) 44 .cfi_rel_offset 22, 44 45 sw $s5, 40($sp) 46 .cfi_rel_offset 21, 40 47 sw $s4, 36($sp) 48 .cfi_rel_offset 20, 36 49 sw $s3, 32($sp) 50 .cfi_rel_offset 19, 32 51 sw $s2, 28($sp) 52 .cfi_rel_offset 18, 28 53 sw $s1, 24($sp) 54 .cfi_rel_offset 17, 24 55 sw $s0, 20($sp) 56 .cfi_rel_offset 16, 20 57 # 1 word for alignment, 4 open words for args $a0-$a3, bottom will hold Method* 58.endm 59 60 /* 61 * Macro that sets up the callee save frame to conform with 62 * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes non-moving GC. 63 * Does not include rSUSPEND or rSELF 64 * callee-save: $s2-$s8 + $gp + $ra, 9 total + 3 words padding + 4 open words for args 65 */ 66.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME 67 addiu $sp, $sp, -64 68 .cfi_adjust_cfa_offset 64 69 sw $ra, 60($sp) 70 .cfi_rel_offset 31, 60 71 sw $s8, 56($sp) 72 .cfi_rel_offset 30, 56 73 sw $gp, 52($sp) 74 .cfi_rel_offset 28, 52 75 sw $s7, 48($sp) 76 .cfi_rel_offset 23, 48 77 sw $s6, 44($sp) 78 .cfi_rel_offset 22, 44 79 sw $s5, 40($sp) 80 .cfi_rel_offset 21, 40 81 sw $s4, 36($sp) 82 .cfi_rel_offset 20, 36 83 sw $s3, 32($sp) 84 .cfi_rel_offset 19, 32 85 sw $s2, 28($sp) 86 .cfi_rel_offset 18, 28 87 # 3 words for alignment and extra args, 4 open words for args $a0-$a3, bottom will hold Method* 88.endm 89 90.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 91 lw $gp, 52($sp) 92 lw $ra, 60($sp) 93 addiu $sp, $sp, 64 94 .cfi_adjust_cfa_offset -64 95.endm 96 97.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 98 lw $gp, 52($sp) 99 lw $ra, 60($sp) 100 jr $ra 101 addiu $sp, $sp, 64 102 .cfi_adjust_cfa_offset -64 103.endm 104 105 /* 106 * Macro that sets up the callee save frame to conform with 107 * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC. 108 * callee-save: $a1-$a3, $s2-$s8 + $gp + $ra, 12 total + 3 words padding + method* 109 */ 110.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 111 addiu $sp, $sp, -64 112 .cfi_adjust_cfa_offset 64 113 sw $ra, 60($sp) 114 .cfi_rel_offset 31, 60 115 sw $s8, 56($sp) 116 .cfi_rel_offset 30, 56 117 sw $gp, 52($sp) 118 .cfi_rel_offset 28, 52 119 sw $s7, 48($sp) 120 .cfi_rel_offset 23, 48 121 sw $s6, 44($sp) 122 .cfi_rel_offset 22, 44 123 sw $s5, 40($sp) 124 .cfi_rel_offset 21, 40 125 sw $s4, 36($sp) 126 .cfi_rel_offset 20, 36 127 sw $s3, 32($sp) 128 .cfi_rel_offset 19, 32 129 sw $s2, 28($sp) 130 .cfi_rel_offset 18, 28 131 sw $a3, 12($sp) 132 .cfi_rel_offset 7, 12 133 sw $a2, 8($sp) 134 .cfi_rel_offset 6, 8 135 sw $a1, 4($sp) 136 .cfi_rel_offset 5, 4 137 # bottom will hold Method* 138.endm 139 140.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 141 lw $ra, 60($sp) # restore $ra 142 lw $gp, 52($sp) # restore $gp 143 lw $a1, 4($sp) # restore non-callee save $a1 144 lw $a2, 8($sp) # restore non-callee save $a2 145 lw $a3, 12($sp) # restore non-callee save $a3 146 addiu $sp, $sp, 64 # pop frame 147 .cfi_adjust_cfa_offset -64 148.endm 149 150 /* 151 * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending 152 * exception is Thread::Current()->exception_ 153 */ 154.macro DELIVER_PENDING_EXCEPTION 155 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME # save callee saves for throw 156 move $a0, rSELF # pass Thread::Current 157 la $t9, artDeliverPendingExceptionFromCode 158 jr $t9 # artDeliverPendingExceptionFromCode(Thread*, $sp) 159 move $a1, $sp # pass $sp 160.endm 161 162.macro RETURN_IF_NO_EXCEPTION 163 lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_ 164 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 165 bnez $t0, 1f # success if no exception is pending 166 nop 167 jr $ra 168 nop 1691: 170 DELIVER_PENDING_EXCEPTION 171.endm 172 173.macro RETURN_IF_ZERO 174 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 175 bnez $v0, 1f # success? 176 nop 177 jr $ra # return on success 178 nop 1791: 180 DELIVER_PENDING_EXCEPTION 181.endm 182 183.macro RETURN_IF_NONZERO 184 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 185 beqz $v0, 1f # success? 186 nop 187 jr $ra # return on success 188 nop 1891: 190 DELIVER_PENDING_EXCEPTION 191.endm 192 193 /* 194 * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_ 195 * FIXME: just guessing about the shape of the jmpbuf. Where will pc be? 196 */ 197ENTRY art_quick_do_long_jump 198 l.s $f0, 0($a1) 199 l.s $f1, 4($a1) 200 l.s $f2, 8($a1) 201 l.s $f3, 12($a1) 202 l.s $f4, 16($a1) 203 l.s $f5, 20($a1) 204 l.s $f6, 24($a1) 205 l.s $f7, 28($a1) 206 l.s $f8, 32($a1) 207 l.s $f9, 36($a1) 208 l.s $f10, 40($a1) 209 l.s $f11, 44($a1) 210 l.s $f12, 48($a1) 211 l.s $f13, 52($a1) 212 l.s $f14, 56($a1) 213 l.s $f15, 60($a1) 214 l.s $f16, 64($a1) 215 l.s $f17, 68($a1) 216 l.s $f18, 72($a1) 217 l.s $f19, 76($a1) 218 l.s $f20, 80($a1) 219 l.s $f21, 84($a1) 220 l.s $f22, 88($a1) 221 l.s $f23, 92($a1) 222 l.s $f24, 96($a1) 223 l.s $f25, 100($a1) 224 l.s $f26, 104($a1) 225 l.s $f27, 108($a1) 226 l.s $f28, 112($a1) 227 l.s $f29, 116($a1) 228 l.s $f30, 120($a1) 229 l.s $f31, 124($a1) 230 lw $at, 4($a0) 231 lw $v0, 8($a0) 232 lw $v1, 12($a0) 233 lw $a1, 20($a0) 234 lw $a2, 24($a0) 235 lw $a3, 28($a0) 236 lw $t0, 32($a0) 237 lw $t1, 36($a0) 238 lw $t2, 40($a0) 239 lw $t3, 44($a0) 240 lw $t4, 48($a0) 241 lw $t5, 52($a0) 242 lw $t6, 56($a0) 243 lw $t7, 60($a0) 244 lw $s0, 64($a0) 245 lw $s1, 68($a0) 246 lw $s2, 72($a0) 247 lw $s3, 76($a0) 248 lw $s4, 80($a0) 249 lw $s5, 84($a0) 250 lw $s6, 88($a0) 251 lw $s7, 92($a0) 252 lw $t8, 96($a0) 253 lw $t9, 100($a0) 254 lw $k0, 104($a0) 255 lw $k1, 108($a0) 256 lw $gp, 112($a0) 257 lw $sp, 116($a0) 258 lw $fp, 120($a0) 259 lw $ra, 124($a0) 260 lw $a0, 16($a0) 261 move $v0, $zero # clear result registers r0 and r1 262 jr $ra # do long jump 263 move $v1, $zero 264END art_quick_do_long_jump 265 266 /* 267 * Called by managed code, saves most registers (forms basis of long jump context) and passes 268 * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at 269 * the bottom of the thread. On entry r0 holds Throwable* 270 */ 271ENTRY art_quick_deliver_exception 272 GENERATE_GLOBAL_POINTER 273 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 274 move $a1, rSELF # pass Thread::Current 275 la $t9, artDeliverExceptionFromCode 276 jr $t9 # artDeliverExceptionFromCode(Throwable*, Thread*, $sp) 277 move $a2, $sp # pass $sp 278END art_quick_deliver_exception 279 280 /* 281 * Called by managed code to create and deliver a NullPointerException 282 */ 283 .extern artThrowNullPointerExceptionFromCode 284ENTRY art_quick_throw_null_pointer_exception 285 GENERATE_GLOBAL_POINTER 286 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 287 move $a0, rSELF # pass Thread::Current 288 la $t9, artThrowNullPointerExceptionFromCode 289 jr $t9 # artThrowNullPointerExceptionFromCode(Thread*, $sp) 290 move $a1, $sp # pass $sp 291END art_quick_throw_null_pointer_exception 292 293 /* 294 * Called by managed code to create and deliver an ArithmeticException 295 */ 296 .extern artThrowDivZeroFromCode 297ENTRY art_quick_throw_div_zero 298 GENERATE_GLOBAL_POINTER 299 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 300 move $a0, rSELF # pass Thread::Current 301 la $t9, artThrowDivZeroFromCode 302 jr $t9 # artThrowDivZeroFromCode(Thread*, $sp) 303 move $a1, $sp # pass $sp 304END art_quick_throw_div_zero 305 306 /* 307 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException 308 */ 309 .extern artThrowArrayBoundsFromCode 310ENTRY art_quick_throw_array_bounds 311 GENERATE_GLOBAL_POINTER 312 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 313 move $a2, rSELF # pass Thread::Current 314 la $t9, artThrowArrayBoundsFromCode 315 jr $t9 # artThrowArrayBoundsFromCode(index, limit, Thread*, $sp) 316 move $a3, $sp # pass $sp 317END art_quick_throw_array_bounds 318 319 /* 320 * Called by managed code to create and deliver a StackOverflowError. 321 */ 322 .extern artThrowStackOverflowFromCode 323ENTRY art_quick_throw_stack_overflow 324 GENERATE_GLOBAL_POINTER 325 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 326 move $a0, rSELF # pass Thread::Current 327 la $t9, artThrowStackOverflowFromCode 328 jr $t9 # artThrowStackOverflowFromCode(Thread*, $sp) 329 move $a1, $sp # pass $sp 330END art_quick_throw_stack_overflow 331 332 /* 333 * Called by managed code to create and deliver a NoSuchMethodError. 334 */ 335 .extern artThrowNoSuchMethodFromCode 336ENTRY art_quick_throw_no_such_method 337 GENERATE_GLOBAL_POINTER 338 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 339 move $a1, rSELF # pass Thread::Current 340 la $t9, artThrowNoSuchMethodFromCode 341 jr $t9 # artThrowNoSuchMethodFromCode(method_idx, Thread*, $sp) 342 move $a2, $sp # pass $sp 343END art_quick_throw_no_such_method 344 345 /* 346 * All generated callsites for interface invokes and invocation slow paths will load arguments 347 * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain 348 * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the 349 * stack and call the appropriate C helper. 350 * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1. 351 * 352 * The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting 353 * of the target Method* in $v0 and method->code_ in $v1. 354 * 355 * If unsuccessful, the helper will return NULL/NULL. There will be a pending exception in the 356 * thread and we branch to another stub to deliver it. 357 * 358 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr 359 * pointing back to the original caller. 360 */ 361.macro INVOKE_TRAMPOLINE c_name, cxx_name 362 .extern \cxx_name 363ENTRY \c_name 364 GENERATE_GLOBAL_POINTER 365 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME # save callee saves in case allocation triggers GC 366 lw $a2, 64($sp) # pass caller Method* 367 move $t0, $sp # save $sp 368 addiu $sp, $sp, -32 # make space for extra args 369 .cfi_adjust_cfa_offset 32 370 move $a3, rSELF # pass Thread::Current 371 .cfi_rel_offset 28, 12 372 jal \cxx_name # (method_idx, this, caller, Thread*, $sp) 373 sw $t0, 16($sp) # pass $sp 374 addiu $sp, $sp, 32 # release out args 375 .cfi_adjust_cfa_offset -32 376 move $a0, $v0 # save target Method* 377 move $t9, $v1 # save $v0->code_ 378 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 379 beqz $v0, 1f 380 nop 381 jr $t9 382 nop 3831: 384 DELIVER_PENDING_EXCEPTION 385END \c_name 386.endm 387 388INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline 389INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck 390 391INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck 392INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck 393INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck 394INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck 395 396 /* 397 * Common invocation stub for portable and quick. 398 * On entry: 399 * a0 = method pointer 400 * a1 = argument array or NULL for no argument methods 401 * a2 = size of argument array in bytes 402 * a3 = (managed) thread pointer 403 * [sp + 16] = JValue* result 404 * [sp + 20] = result type char 405 */ 406 .type art_portable_invoke_stub, %function 407 .global art_portable_invoke_stub 408art_portable_invoke_stub: 409ENTRY art_quick_invoke_stub 410 GENERATE_GLOBAL_POINTER 411 sw $a0, 0($sp) # save out a0 412 addiu $sp, $sp, -16 # spill s0, s1, fp, ra 413 .cfi_adjust_cfa_offset 16 414 sw $ra, 12($sp) 415 .cfi_rel_offset 31, 12 416 sw $fp, 8($sp) 417 .cfi_rel_offset 30, 8 418 sw $s1, 4($sp) 419 .cfi_rel_offset 17, 4 420 sw $s0, 0($sp) 421 .cfi_rel_offset 16, 0 422 move $fp, $sp # save sp in fp 423 .cfi_def_cfa_register 30 424 move $s1, $a3 # move managed thread pointer into s1 425 addiu $s0, $zero, SUSPEND_CHECK_INTERVAL # reset s0 to suspend check interval 426 addiu $t0, $a2, 16 # create space for method pointer in frame 427 srl $t0, $t0, 3 # shift the frame size right 3 428 sll $t0, $t0, 3 # shift the frame size left 3 to align to 16 bytes 429 subu $sp, $sp, $t0 # reserve stack space for argument array 430 addiu $a0, $sp, 4 # pass stack pointer + method ptr as dest for memcpy 431 jal memcpy # (dest, src, bytes) 432 addiu $sp, $sp, -16 # make space for argument slots for memcpy 433 addiu $sp, $sp, 16 # restore stack after memcpy 434 lw $a0, 16($fp) # restore method* 435 lw $a1, 4($sp) # copy arg value for a1 436 lw $a2, 8($sp) # copy arg value for a2 437 lw $a3, 12($sp) # copy arg value for a3 438 lw $t9, METHOD_CODE_OFFSET($a0) # get pointer to the code 439 jalr $t9 # call the method 440 sw $zero, 0($sp) # store NULL for method* at bottom of frame 441 move $sp, $fp # restore the stack 442 lw $s0, 0($sp) 443 lw $s1, 4($sp) 444 lw $fp, 8($sp) 445 lw $ra, 12($sp) 446 addiu $sp, $sp, 16 447 .cfi_adjust_cfa_offset -16 448 lw $t0, 16($sp) # get result pointer 449 lw $t1, 20($sp) # get result type char 450 li $t2, 68 # put char 'D' into t2 451 beq $t1, $t2, 1f # branch if result type char == 'D' 452 li $t3, 70 # put char 'F' into t3 453 beq $t1, $t3, 1f # branch if result type char == 'F' 454 sw $v0, 0($t0) # store the result 455 jr $ra 456 sw $v1, 4($t0) # store the other half of the result 4571: 458 s.s $f0, 0($t0) # store floating point result 459 jr $ra 460 s.s $f1, 4($t0) # store other half of floating point result 461END art_quick_invoke_stub 462 .size art_portable_invoke_stub, .-art_portable_invoke_stub 463 464 /* 465 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on 466 * failure. 467 */ 468 .extern artHandleFillArrayDataFromCode 469ENTRY art_quick_handle_fill_data 470 GENERATE_GLOBAL_POINTER 471 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC 472 move $a2, rSELF # pass Thread::Current 473 jal artHandleFillArrayDataFromCode # (Array*, const DexFile::Payload*, Thread*, $sp) 474 move $a3, $sp # pass $sp 475 RETURN_IF_ZERO 476END art_quick_handle_fill_data 477 478 /* 479 * Entry from managed code that calls artLockObjectFromCode, may block for GC. 480 */ 481 .extern artLockObjectFromCode 482ENTRY art_quick_lock_object 483 GENERATE_GLOBAL_POINTER 484 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case we block 485 move $a1, rSELF # pass Thread::Current 486 jal artLockObjectFromCode # (Object* obj, Thread*, $sp) 487 move $a2, $sp # pass $sp 488 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 489END art_quick_lock_object 490 491 /* 492 * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure. 493 */ 494 .extern artUnlockObjectFromCode 495ENTRY art_quick_unlock_object 496 GENERATE_GLOBAL_POINTER 497 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC 498 move $a1, rSELF # pass Thread::Current 499 jal artUnlockObjectFromCode # (Object* obj, Thread*, $sp) 500 move $a2, $sp # pass $sp 501 RETURN_IF_ZERO 502END art_quick_unlock_object 503 504 /* 505 * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure. 506 */ 507 .extern artCheckCastFromCode 508ENTRY art_quick_check_cast 509 GENERATE_GLOBAL_POINTER 510 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC 511 move $a2, rSELF # pass Thread::Current 512 jal artCheckCastFromCode # (Class* a, Class* b, Thread*, $sp) 513 move $a3, $sp # pass $sp 514 RETURN_IF_ZERO 515END art_quick_check_cast 516 517 /* 518 * Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on 519 * failure. 520 */ 521 .extern artCanPutArrayElementFromCode 522ENTRY art_quick_can_put_array_element 523 GENERATE_GLOBAL_POINTER 524 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case exception allocation triggers GC 525 move $a2, rSELF # pass Thread::Current 526 jal artCanPutArrayElementFromCode # (Object* element, Class* array_class, Thread*, $sp) 527 move $a3, $sp # pass $sp 528 RETURN_IF_ZERO 529END art_quick_can_put_array_element 530 531 /* 532 * Entry from managed code when uninitialized static storage, this stub will run the class 533 * initializer and deliver the exception on error. On success the static storage base is 534 * returned. 535 */ 536 .extern artInitializeStaticStorageFromCode 537ENTRY art_quick_initialize_static_storage 538 GENERATE_GLOBAL_POINTER 539 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 540 move $a2, rSELF # pass Thread::Current 541 # artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, $sp) 542 jal artInitializeStaticStorageFromCode 543 move $a3, $sp # pass $sp 544 RETURN_IF_NONZERO 545END art_quick_initialize_static_storage 546 547 /* 548 * Entry from managed code when dex cache misses for a type_idx. 549 */ 550 .extern artInitializeTypeFromCode 551ENTRY art_quick_initialize_type 552 GENERATE_GLOBAL_POINTER 553 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 554 move $a2, rSELF # pass Thread::Current 555 # artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, $sp) 556 jal artInitializeTypeFromCode 557 move $a3, $sp # pass $sp 558 RETURN_IF_NONZERO 559END art_quick_initialize_type 560 561 /* 562 * Entry from managed code when type_idx needs to be checked for access and dex cache may also 563 * miss. 564 */ 565 .extern artInitializeTypeAndVerifyAccessFromCode 566ENTRY art_quick_initialize_type_and_verify_access 567 GENERATE_GLOBAL_POINTER 568 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 569 move $a2, rSELF # pass Thread::Current 570 # artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, $sp) 571 jal artInitializeTypeAndVerifyAccessFromCode 572 move $a3, $sp # pass $sp 573 RETURN_IF_NONZERO 574END art_quick_initialize_type_and_verify_access 575 576 /* 577 * Called by managed code to resolve a static field and load a 32-bit primitive value. 578 */ 579 .extern artGet32StaticFromCode 580ENTRY art_quick_get32_static 581 GENERATE_GLOBAL_POINTER 582 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 583 lw $a1, 64($sp) # pass referrer's Method* 584 move $a2, rSELF # pass Thread::Current 585 jal artGet32StaticFromCode # (uint32_t field_idx, const Method* referrer, Thread*, $sp) 586 move $a3, $sp # pass $sp 587 RETURN_IF_NO_EXCEPTION 588END art_quick_get32_static 589 590 /* 591 * Called by managed code to resolve a static field and load a 64-bit primitive value. 592 */ 593 .extern artGet64StaticFromCode 594ENTRY art_quick_get64_static 595 GENERATE_GLOBAL_POINTER 596 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 597 lw $a1, 64($sp) # pass referrer's Method* 598 move $a2, rSELF # pass Thread::Current 599 jal artGet64StaticFromCode # (uint32_t field_idx, const Method* referrer, Thread*, $sp) 600 move $a3, $sp # pass $sp 601 RETURN_IF_NO_EXCEPTION 602END art_quick_get64_static 603 604 /* 605 * Called by managed code to resolve a static field and load an object reference. 606 */ 607 .extern artGetObjStaticFromCode 608ENTRY art_quick_get_obj_static 609 GENERATE_GLOBAL_POINTER 610 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 611 lw $a1, 64($sp) # pass referrer's Method* 612 move $a2, rSELF # pass Thread::Current 613 jal artGetObjStaticFromCode # (uint32_t field_idx, const Method* referrer, Thread*, $sp) 614 move $a3, $sp # pass $sp 615 RETURN_IF_NO_EXCEPTION 616END art_quick_get_obj_static 617 618 /* 619 * Called by managed code to resolve an instance field and load a 32-bit primitive value. 620 */ 621 .extern artGet32InstanceFromCode 622ENTRY art_quick_get32_instance 623 GENERATE_GLOBAL_POINTER 624 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 625 lw $a2, 64($sp) # pass referrer's Method* 626 move $a3, rSELF # pass Thread::Current 627 jal artGet32InstanceFromCode # (field_idx, Object*, referrer, Thread*, $sp) 628 sw $sp, 16($sp) # pass $sp 629 RETURN_IF_NO_EXCEPTION 630END art_quick_get32_instance 631 632 /* 633 * Called by managed code to resolve an instance field and load a 64-bit primitive value. 634 */ 635 .extern artGet64InstanceFromCode 636ENTRY art_quick_get64_instance 637 GENERATE_GLOBAL_POINTER 638 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 639 lw $a2, 64($sp) # pass referrer's Method* 640 move $a3, rSELF # pass Thread::Current 641 jal artGet64InstanceFromCode # (field_idx, Object*, referrer, Thread*, $sp) 642 sw $sp, 16($sp) # pass $sp 643 RETURN_IF_NO_EXCEPTION 644END art_quick_get64_instance 645 646 /* 647 * Called by managed code to resolve an instance field and load an object reference. 648 */ 649 .extern artGetObjInstanceFromCode 650ENTRY art_quick_get_obj_instance 651 GENERATE_GLOBAL_POINTER 652 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 653 lw $a2, 64($sp) # pass referrer's Method* 654 move $a3, rSELF # pass Thread::Current 655 jal artGetObjInstanceFromCode # (field_idx, Object*, referrer, Thread*, $sp) 656 sw $sp, 16($sp) # pass $sp 657 RETURN_IF_NO_EXCEPTION 658END art_quick_get_obj_instance 659 660 /* 661 * Called by managed code to resolve a static field and store a 32-bit primitive value. 662 */ 663 .extern artSet32StaticFromCode 664ENTRY art_quick_set32_static 665 GENERATE_GLOBAL_POINTER 666 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 667 lw $a2, 64($sp) # pass referrer's Method* 668 move $a3, rSELF # pass Thread::Current 669 jal artSet32StaticFromCode # (field_idx, new_val, referrer, Thread*, $sp) 670 sw $sp, 16($sp) # pass $sp 671 RETURN_IF_ZERO 672END art_quick_set32_static 673 674 /* 675 * Called by managed code to resolve a static field and store a 64-bit primitive value. 676 */ 677 .extern artSet32StaticFromCode 678ENTRY art_quick_set64_static 679 GENERATE_GLOBAL_POINTER 680 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 681 lw $a1, 64($sp) # pass referrer's Method* 682 sw rSELF, 16($sp) # pass Thread::Current 683 jal artSet64StaticFromCode # (field_idx, referrer, new_val, Thread*, $sp) 684 sw $sp, 20($sp) # pass $sp 685 RETURN_IF_ZERO 686END art_quick_set64_static 687 688 /* 689 * Called by managed code to resolve a static field and store an object reference. 690 */ 691 .extern artSetObjStaticFromCode 692ENTRY art_quick_set_obj_static 693 GENERATE_GLOBAL_POINTER 694 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 695 lw $a2, 64($sp) # pass referrer's Method* 696 move $a3, rSELF # pass Thread::Current 697 jal artSetObjStaticFromCode # (field_idx, new_val, referrer, Thread*, $sp) 698 sw $sp, 16($sp) # pass $sp 699 RETURN_IF_ZERO 700END art_quick_set_obj_static 701 702 /* 703 * Called by managed code to resolve an instance field and store a 32-bit primitive value. 704 */ 705 .extern artSet32InstanceFromCode 706ENTRY art_quick_set32_instance 707 GENERATE_GLOBAL_POINTER 708 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 709 lw $a3, 64($sp) # pass referrer's Method* 710 sw rSELF, 16($sp) # pass Thread::Current 711 jal artSet32InstanceFromCode # (field_idx, Object*, new_val, referrer, Thread*, $sp) 712 sw $sp, 20($sp) # pass $sp 713 RETURN_IF_ZERO 714END art_quick_set32_instance 715 716 /* 717 * Called by managed code to resolve an instance field and store a 64-bit primitive value. 718 */ 719 .extern artSet32InstanceFromCode 720ENTRY art_quick_set64_instance 721 GENERATE_GLOBAL_POINTER 722 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 723 sw rSELF, 16($sp) # pass Thread::Current 724 jal artSet64InstanceFromCode # (field_idx, Object*, new_val, Thread*, $sp) 725 sw $sp, 20($sp) # pass $sp 726 RETURN_IF_ZERO 727END art_quick_set64_instance 728 729 /* 730 * Called by managed code to resolve an instance field and store an object reference. 731 */ 732 .extern artSetObjInstanceFromCode 733ENTRY art_quick_set_obj_instance 734 GENERATE_GLOBAL_POINTER 735 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 736 lw $a3, 64($sp) # pass referrer's Method* 737 sw rSELF, 16($sp) # pass Thread::Current 738 jal artSetObjInstanceFromCode # (field_idx, Object*, new_val, referrer, Thread*, $sp) 739 sw $sp, 20($sp) # pass $sp 740 RETURN_IF_ZERO 741END art_quick_set_obj_instance 742 743 /* 744 * Entry from managed code to resolve a string, this stub will allocate a String and deliver an 745 * exception on error. On success the String is returned. R0 holds the referring method, 746 * R1 holds the string index. The fast path check for hit in strings cache has already been 747 * performed. 748 */ 749 .extern artResolveStringFromCode 750ENTRY art_quick_resolve_string 751 GENERATE_GLOBAL_POINTER 752 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 753 move $a2, rSELF # pass Thread::Current 754 # artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*, $sp) 755 jal artResolveStringFromCode 756 move $a3, $sp # pass $sp 757 RETURN_IF_NONZERO 758END art_quick_resolve_string 759 760 /* 761 * Called by managed code to allocate an object. 762 */ 763 .extern artAllocObjectFromCode 764ENTRY art_quick_alloc_object 765 GENERATE_GLOBAL_POINTER 766 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 767 move $a2, rSELF # pass Thread::Current 768 jal artAllocObjectFromCode # (uint32_t type_idx, Method* method, Thread*, $sp) 769 move $a3, $sp # pass $sp 770 RETURN_IF_NONZERO 771END art_quick_alloc_object 772 773 /* 774 * Called by managed code to allocate an object when the caller doesn't know whether it has 775 * access to the created type. 776 */ 777 .extern artAllocObjectFromCodeWithAccessCheck 778ENTRY art_quick_alloc_object_with_access_check 779 GENERATE_GLOBAL_POINTER 780 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 781 move $a2, rSELF # pass Thread::Current 782 jal artAllocObjectFromCodeWithAccessCheck # (uint32_t type_idx, Method* method, Thread*, $sp) 783 move $a3, $sp # pass $sp 784 RETURN_IF_NONZERO 785END art_quick_alloc_object_with_access_check 786 787 /* 788 * Called by managed code to allocate an array. 789 */ 790 .extern artAllocArrayFromCode 791ENTRY art_quick_alloc_array 792 GENERATE_GLOBAL_POINTER 793 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 794 move $a3, rSELF # pass Thread::Current 795 # artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count, Thread*, $sp) 796 jal artAllocArrayFromCode 797 sw $sp, 16($sp) # pass $sp 798 RETURN_IF_NONZERO 799END art_quick_alloc_array 800 801 /* 802 * Called by managed code to allocate an array when the caller doesn't know whether it has 803 * access to the created type. 804 */ 805 .extern artAllocArrayFromCodeWithAccessCheck 806ENTRY art_quick_alloc_array_with_access_check 807 GENERATE_GLOBAL_POINTER 808 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 809 move $a3, rSELF # pass Thread::Current 810 # artAllocArrayFromCodeWithAccessCheck(type_idx, method, component_count, Thread*, $sp) 811 jal artAllocArrayFromCodeWithAccessCheck 812 sw $sp, 16($sp) # pass $sp 813 RETURN_IF_NONZERO 814END art_quick_alloc_array_with_access_check 815 816 /* 817 * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY. 818 */ 819 .extern artCheckAndAllocArrayFromCode 820ENTRY art_quick_check_and_alloc_array 821 GENERATE_GLOBAL_POINTER 822 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 823 move $a3, rSELF # pass Thread::Current 824 # artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t count, Thread* , $sp) 825 jal artCheckAndAllocArrayFromCode 826 sw $sp, 16($sp) # pass $sp 827 RETURN_IF_NONZERO 828END art_quick_check_and_alloc_array 829 830 /* 831 * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY. 832 */ 833 .extern artCheckAndAllocArrayFromCodeWithAccessCheck 834ENTRY art_quick_check_and_alloc_array_with_access_check 835 GENERATE_GLOBAL_POINTER 836 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves in case of GC 837 move $a3, rSELF # pass Thread::Current 838 # artCheckAndAllocArrayFromCodeWithAccessCheck(type_idx, method, count, Thread* , $sp) 839 jal artCheckAndAllocArrayFromCodeWithAccessCheck 840 sw $sp, 16($sp) # pass $sp 841 RETURN_IF_NONZERO 842END art_quick_check_and_alloc_array_with_access_check 843 844 /* 845 * Called by managed code when the value in rSUSPEND has been decremented to 0. 846 */ 847 .extern artTestSuspendFromCode 848ENTRY art_quick_test_suspend 849 GENERATE_GLOBAL_POINTER 850 lh $a0, THREAD_FLAGS_OFFSET(rSELF) 851 bnez $a0, 1f 852 addi rSUSPEND, $zero, SUSPEND_CHECK_INTERVAL # reset rSUSPEND to SUSPEND_CHECK_INTERVAL 853 jr $ra 854 nop 8551: 856 move $a0, rSELF 857 SETUP_REF_ONLY_CALLEE_SAVE_FRAME # save callee saves for stack crawl 858 jal artTestSuspendFromCode # (Thread*, $sp) 859 move $a1, $sp 860 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 861END art_quick_test_suspend 862 863 /* 864 * Called by managed code that is attempting to call a method on a proxy class. On entry 865 * r0 holds the proxy method; r1, r2 and r3 may contain arguments. 866 */ 867 .extern artQuickProxyInvokeHandler 868ENTRY art_quick_proxy_invoke_handler 869 GENERATE_GLOBAL_POINTER 870 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 871 sw $a0, 0($sp) # place proxy method at bottom of frame 872 move $a2, rSELF # pass Thread::Current 873 jal artQuickProxyInvokeHandler # (Method* proxy method, receiver, Thread*, SP) 874 move $a3, $sp # pass $sp 875 lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_ 876 lw $gp, 52($sp) # restore $gp 877 lw $ra, 60($sp) # restore $ra 878 bnez $t0, 1f 879 addiu $sp, $sp, 64 # pop frame 880 .cfi_adjust_cfa_offset -64 881 jr $ra 882 nop 8831: 884 DELIVER_PENDING_EXCEPTION 885END art_quick_proxy_invoke_handler 886 887 .extern artQuickResolutionTrampoline 888ENTRY art_quick_resolution_trampoline 889 GENERATE_GLOBAL_POINTER 890 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 891 move $a2, rSELF # pass Thread::Current 892 jal artQuickResolutionTrampoline # (Method* called, receiver, Thread*, SP) 893 move $a3, $sp # pass $sp 894 lw $gp, 52($sp) # restore $gp 895 lw $ra, 60($sp) # restore $ra 896 beqz $v0, 1f 897 lw $a0, 0($sp) # load resolved method to $a0 898 lw $a1, 4($sp) # restore non-callee save $a1 899 lw $a2, 8($sp) # restore non-callee save $a2 900 lw $a3, 12($sp) # restore non-callee save $a3 901 move $t9, $v0 # code pointer must be in $t9 to generate the global pointer 902 jr $v0 # tail call to method 9031: 904 addiu $sp, $sp, 64 # pop frame 905 .cfi_adjust_cfa_offset -64 906 DELIVER_PENDING_EXCEPTION 907END art_quick_resolution_trampoline 908 909 .extern artQuickToInterpreterBridge 910ENTRY art_quick_to_interpreter_bridge 911 GENERATE_GLOBAL_POINTER 912 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 913 move $a1, rSELF # pass Thread::Current 914 jal artQuickToInterpreterBridge # (Method* method, Thread*, SP) 915 move $a2, $sp # pass $sp 916 lw $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_ 917 lw $gp, 52($sp) # restore $gp 918 lw $ra, 60($sp) # restore $ra 919 bnez $t0, 1f 920 addiu $sp, $sp, 64 # pop frame 921 .cfi_adjust_cfa_offset -64 922 jr $ra 923 nop 9241: 925 DELIVER_PENDING_EXCEPTION 926END art_quick_to_interpreter_bridge 927 928 /* 929 * Routine that intercepts method calls and returns. 930 */ 931 .extern artInstrumentationMethodEntryFromCode 932 .extern artInstrumentationMethodExitFromCode 933ENTRY art_quick_instrumentation_entry 934 GENERATE_GLOBAL_POINTER 935 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 936 move $t0, $sp # remember bottom of caller's frame 937 addiu $sp, $sp, -32 # space for args, pad (3 words), arguments (5 words) 938 .cfi_adjust_cfa_offset 32 939 sw $a0, 28($sp) # save arg0 940 sw $ra, 16($sp) # pass $ra 941 move $a3, $t0 # pass $sp 942 jal artInstrumentationMethodEntryFromCode # (Method*, Object*, Thread*, SP, LR) 943 move $a2, rSELF # pass Thread::Current 944 move $t9, $v0 # $t9 holds reference to code 945 lw $a0, 28($sp) # restore arg0 946 addiu $sp, $sp, 32 # remove args 947 .cfi_adjust_cfa_offset -32 948 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 949 jalr $t9 # call method 950 nop 951END art_quick_instrumentation_entry 952 /* intentional fallthrough */ 953 .global art_quick_instrumentation_exit 954art_quick_instrumentation_exit: 955 .cfi_startproc 956 addiu $t9, $ra, 4 # put current address into $t9 to rebuild $gp 957 GENERATE_GLOBAL_POINTER 958 move $t0, $sp # remember bottom of caller's frame 959 SETUP_REF_ONLY_CALLEE_SAVE_FRAME 960 addiu $sp, $sp, -48 # save return values and set up args 961 .cfi_adjust_cfa_offset 48 962 sw $v0, 32($sp) 963 .cfi_rel_offset 2, 0 964 sw $v1, 36($sp) 965 .cfi_rel_offset 3, 4 966 s.s $f0, 40($sp) 967 s.s $f1, 44($sp) 968 s.s $f0, 16($sp) # pass fpr result 969 s.s $f1, 20($sp) 970 move $a2, $v0 # pass gpr result 971 move $a3, $v1 972 move $a1, $t0 # pass $sp 973 jal artInstrumentationMethodExitFromCode # (Thread*, SP, gpr_res, fpr_res) 974 move $a0, rSELF # pass Thread::Current 975 move $t0, $v0 # set aside returned link register 976 move $ra, $v1 # set link register for deoptimization 977 lw $v0, 32($sp) # restore return values 978 lw $v1, 36($sp) 979 l.s $f0, 40($sp) 980 l.s $f1, 44($sp) 981 jr $t0 # return 982 addiu $sp, $sp, 112 # 48 bytes of args + 64 bytes of callee save frame 983 .cfi_adjust_cfa_offset -112 984END art_quick_instrumentation_exit 985 986 /* 987 * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization 988 * will long jump to the upcall with a special exception of -1. 989 */ 990 .extern artDeoptimize 991 .extern artEnterInterpreterFromDeoptimize 992ENTRY art_quick_deoptimize 993 GENERATE_GLOBAL_POINTER 994 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 995 move $a0, rSELF # pass Thread::current 996 jal artDeoptimize # artDeoptimize(Thread*, SP) 997 # Returns caller method's frame size. 998 move $a1, $sp # pass $sp 999END art_quick_deoptimize 1000 1001 /* 1002 * Long integer shift. This is different from the generic 32/64-bit 1003 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1004 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1005 * 6 bits. 1006 * On entry: 1007 * $a0: low word 1008 * $a1: high word 1009 * $a2: shift count 1010 */ 1011ENTRY art_quick_shl_long 1012 /* shl-long vAA, vBB, vCC */ 1013 sll $v0, $a0, $a2 # rlo<- alo << (shift&31) 1014 not $v1, $a2 # rhi<- 31-shift (shift is 5b) 1015 srl $a0, 1 1016 srl $a0, $v1 # alo<- alo >> (32-(shift&31)) 1017 sll $v1, $a1, $a2 # rhi<- ahi << (shift&31) 1018 or $v1, $a0 # rhi<- rhi | alo 1019 andi $a2, 0x20 # shift< shift & 0x20 1020 movn $v1, $v0, $a2 # rhi<- rlo (if shift&0x20) 1021 jr $ra 1022 movn $v0, $zero, $a2 # rlo<- 0 (if shift&0x20) 1023END art_quick_shl_long 1024 1025 /* 1026 * Long integer shift. This is different from the generic 32/64-bit 1027 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1028 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1029 * 6 bits. 1030 * On entry: 1031 * $a0: low word 1032 * $a1: high word 1033 * $a2: shift count 1034 */ 1035 .global art_quick_shr_long 1036ENTRY art_quick_shr_long 1037 sra $v1, $a1, $a2 # rhi<- ahi >> (shift&31) 1038 srl $v0, $a0, $a2 # rlo<- alo >> (shift&31) 1039 sra $a3, $a1, 31 # $a3<- sign(ah) 1040 not $a0, $a2 # alo<- 31-shift (shift is 5b) 1041 sll $a1, 1 1042 sll $a1, $a0 # ahi<- ahi << (32-(shift&31)) 1043 or $v0, $a1 # rlo<- rlo | ahi 1044 andi $a2, 0x20 # shift & 0x20 1045 movn $v0, $v1, $a2 # rlo<- rhi (if shift&0x20) 1046 jr $ra 1047 movn $v1, $a3, $a2 # rhi<- sign(ahi) (if shift&0x20) 1048END art_quick_shr_long 1049 1050 /* 1051 * Long integer shift. This is different from the generic 32/64-bit 1052 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1053 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1054 * 6 bits. 1055 * On entry: 1056 * r0: low word 1057 * r1: high word 1058 * r2: shift count 1059 */ 1060 /* ushr-long vAA, vBB, vCC */ 1061 .global art_quick_ushr_long 1062ENTRY art_quick_ushr_long 1063 srl $v1, $a1, $a2 # rhi<- ahi >> (shift&31) 1064 srl $v0, $a0, $a2 # rlo<- alo >> (shift&31) 1065 not $a0, $a2 # alo<- 31-shift (shift is 5b) 1066 sll $a1, 1 1067 sll $a1, $a0 # ahi<- ahi << (32-(shift&31)) 1068 or $v0, $a1 # rlo<- rlo | ahi 1069 andi $a2, 0x20 # shift & 0x20 1070 movn $v0, $v1, $a2 # rlo<- rhi (if shift&0x20) 1071 jr $ra 1072 movn $v1, $zero, $a2 # rhi<- 0 (if shift&0x20) 1073END art_quick_ushr_long 1074 1075ENTRY art_quick_indexof 1076 jr $ra 1077 nop 1078END art_quick_indexof 1079 1080ENTRY art_quick_string_compareto 1081 jr $ra 1082 nop 1083END art_quick_string_compareto 1084