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_arm.S" 18 19 /* Deliver the given exception */ 20 .extern artDeliverExceptionFromCode 21 /* Deliver an exception pending on a thread */ 22 .extern artDeliverPendingException 23 24 /* 25 * Macro that sets up the callee save frame to conform with 26 * Runtime::CreateCalleeSaveMethod(kSaveAll) 27 */ 28 .macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 29 push {r4-r11, lr} @ 9 words of callee saves 30 .save {r4-r11, lr} 31 .cfi_adjust_cfa_offset 36 32 .cfi_rel_offset r4, 0 33 .cfi_rel_offset r5, 4 34 .cfi_rel_offset r6, 8 35 .cfi_rel_offset r7, 12 36 .cfi_rel_offset r8, 16 37 .cfi_rel_offset r9, 20 38 .cfi_rel_offset r10, 24 39 .cfi_rel_offset r11, 28 40 .cfi_rel_offset lr, 32 41 vpush {s0-s31} 42 .pad #128 43 .cfi_adjust_cfa_offset 128 44 sub sp, #12 @ 3 words of space, bottom word will hold Method* 45 .pad #12 46 .cfi_adjust_cfa_offset 12 47 .endm 48 49 /* 50 * Macro that sets up the callee save frame to conform with 51 * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes non-moving GC. 52 */ 53 .macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME 54 push {r5-r8, r10-r11, lr} @ 7 words of callee saves 55 .save {r5-r8, r10-r11, lr} 56 .cfi_adjust_cfa_offset 28 57 .cfi_rel_offset r5, 0 58 .cfi_rel_offset r6, 4 59 .cfi_rel_offset r7, 8 60 .cfi_rel_offset r8, 12 61 .cfi_rel_offset r10, 16 62 .cfi_rel_offset r11, 20 63 .cfi_rel_offset lr, 24 64 sub sp, #4 @ bottom word will hold Method* 65 .pad #4 66 .cfi_adjust_cfa_offset 4 67 .endm 68 69 .macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 70 ldr lr, [sp, #28] @ restore lr for return 71 add sp, #32 @ unwind stack 72 .cfi_adjust_cfa_offset -32 73 .endm 74 75 .macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 76 ldr lr, [sp, #28] @ restore lr for return 77 add sp, #32 @ unwind stack 78 .cfi_adjust_cfa_offset -32 79 bx lr @ return 80 .endm 81 82 /* 83 * Macro that sets up the callee save frame to conform with 84 * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC. 85 */ 86 .macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 87 push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves 88 .save {r1-r3, r5-r8, r10-r11, lr} 89 .cfi_adjust_cfa_offset 40 90 .cfi_rel_offset r1, 0 91 .cfi_rel_offset r2, 4 92 .cfi_rel_offset r3, 8 93 .cfi_rel_offset r5, 12 94 .cfi_rel_offset r6, 16 95 .cfi_rel_offset r7, 20 96 .cfi_rel_offset r8, 24 97 .cfi_rel_offset r10, 28 98 .cfi_rel_offset r11, 32 99 .cfi_rel_offset lr, 36 100 sub sp, #8 @ 2 words of space, bottom word will hold Method* 101 .pad #8 102 .cfi_adjust_cfa_offset 8 103 .endm 104 105 .macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 106 ldr r1, [sp, #8] @ restore non-callee save r1 107 ldrd r2, [sp, #12] @ restore non-callee saves r2-r3 108 ldr lr, [sp, #44] @ restore lr 109 add sp, #48 @ rewind sp 110 .cfi_adjust_cfa_offset -48 111 .endm 112 113 .macro RETURN_IF_RESULT_IS_ZERO 114 cbnz r0, 1f @ result non-zero branch over 115 bx lr @ return 116 1: 117 .endm 118 119 .macro RETURN_IF_RESULT_IS_NON_ZERO 120 cbz r0, 1f @ result zero branch over 121 bx lr @ return 122 1: 123 .endm 124 125 /* 126 * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending 127 * exception is Thread::Current()->exception_ 128 */ 129 .macro DELIVER_PENDING_EXCEPTION 130 .fnend 131 .fnstart 132 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME @ save callee saves for throw 133 mov r0, r9 @ pass Thread::Current 134 mov r1, sp @ pass SP 135 b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*, SP) 136 .endm 137 138 .macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 139 .extern \cxx_name 140 ENTRY \c_name 141 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 142 mov r0, r9 @ pass Thread::Current 143 mov r1, sp @ pass SP 144 b \cxx_name @ \cxx_name(Thread*, SP) 145 END \c_name 146 .endm 147 148 .macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name 149 .extern \cxx_name 150 ENTRY \c_name 151 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 152 mov r1, r9 @ pass Thread::Current 153 mov r2, sp @ pass SP 154 b \cxx_name @ \cxx_name(Thread*, SP) 155 END \c_name 156 .endm 157 158 .macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 159 .extern \cxx_name 160 ENTRY \c_name 161 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 162 mov r2, r9 @ pass Thread::Current 163 mov r3, sp @ pass SP 164 b \cxx_name @ \cxx_name(Thread*, SP) 165 END \c_name 166 .endm 167 168 /* 169 * Called by managed code, saves callee saves and then calls artThrowException 170 * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception. 171 */ 172 ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode 173 174 /* 175 * Called by managed code to create and deliver a NullPointerException. 176 */ 177 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode 178 179 /* 180 * Called by managed code to create and deliver an ArithmeticException. 181 */ 182 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode 183 184 /* 185 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds 186 * index, arg2 holds limit. 187 */ 188 TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode 189 190 /* 191 * Called by managed code to create and deliver a StackOverflowError. 192 */ 193 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode 194 195 /* 196 * Called by managed code to create and deliver a NoSuchMethodError. 197 */ 198 ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode 199 200 /* 201 * All generated callsites for interface invokes and invocation slow paths will load arguments 202 * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain 203 * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the 204 * stack and call the appropriate C helper. 205 * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1. 206 * 207 * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting 208 * of the target Method* in r0 and method->code_ in r1. 209 * 210 * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the 211 * thread and we branch to another stub to deliver it. 212 * 213 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr 214 * pointing back to the original caller. 215 */ 216 .macro INVOKE_TRAMPOLINE c_name, cxx_name 217 .extern \cxx_name 218 ENTRY \c_name 219 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC 220 ldr r2, [sp, #48] @ pass caller Method* 221 mov r3, r9 @ pass Thread::Current 222 mov r12, sp 223 str r12, [sp, #-16]! @ expand the frame and pass SP 224 .pad #16 225 .cfi_adjust_cfa_offset 16 226 bl \cxx_name @ (method_idx, this, caller, Thread*, SP) 227 add sp, #16 @ strip the extra frame 228 .cfi_adjust_cfa_offset -16 229 mov r12, r1 @ save Method*->code_ 230 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 231 cbz r0, 1f @ did we find the target? if not go to exception delivery 232 bx r12 @ tail call to target 233 1: 234 DELIVER_PENDING_EXCEPTION 235 END \c_name 236 .endm 237 238 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline 239 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck 240 241 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck 242 INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck 243 INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck 244 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck 245 246 /* 247 * Quick invocation stub. 248 * On entry: 249 * r0 = method pointer 250 * r1 = argument array or NULL for no argument methods 251 * r2 = size of argument array in bytes 252 * r3 = (managed) thread pointer 253 * [sp] = JValue* result 254 * [sp + 4] = result type char 255 */ 256 ENTRY art_quick_invoke_stub 257 push {r0, r4, r5, r9, r11, lr} @ spill regs 258 .save {r0, r4, r5, r9, r11, lr} 259 .pad #24 260 .cfi_adjust_cfa_offset 24 261 .cfi_rel_offset r0, 0 262 .cfi_rel_offset r4, 4 263 .cfi_rel_offset r5, 8 264 .cfi_rel_offset r9, 12 265 .cfi_rel_offset r11, 16 266 .cfi_rel_offset lr, 20 267 mov r11, sp @ save the stack pointer 268 .cfi_def_cfa_register r11 269 mov r9, r3 @ move managed thread pointer into r9 270 mov r4, #SUSPEND_CHECK_INTERVAL @ reset r4 to suspend check interval 271 add r5, r2, #16 @ create space for method pointer in frame 272 and r5, #0xFFFFFFF0 @ align frame size to 16 bytes 273 sub sp, r5 @ reserve stack space for argument array 274 add r0, sp, #4 @ pass stack pointer + method ptr as dest for memcpy 275 bl memcpy @ memcpy (dest, src, bytes) 276 ldr r0, [r11] @ restore method* 277 ldr r1, [sp, #4] @ copy arg value for r1 278 ldr r2, [sp, #8] @ copy arg value for r2 279 ldr r3, [sp, #12] @ copy arg value for r3 280 mov ip, #0 @ set ip to 0 281 str ip, [sp] @ store NULL for method* at bottom of frame 282 ldr ip, [r0, #METHOD_CODE_OFFSET] @ get pointer to the code 283 blx ip @ call the method 284 mov sp, r11 @ restore the stack pointer 285 ldr ip, [sp, #24] @ load the result pointer 286 strd r0, [ip] @ store r0/r1 into result pointer 287 pop {r0, r4, r5, r9, r11, lr} @ restore spill regs 288 .cfi_adjust_cfa_offset -24 289 bx lr 290 END art_quick_invoke_stub 291 292 /* 293 * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_ 294 */ 295 ARM_ENTRY art_quick_do_long_jump 296 vldm r1, {s0-s31} @ load all fprs from argument fprs_ 297 ldr r2, [r0, #60] @ r2 = r15 (PC from gprs_ 60=4*15) 298 add r0, r0, #12 @ increment r0 to skip gprs_[0..2] 12=4*3 299 ldm r0, {r3-r14} @ load remaining gprs from argument gprs_ 300 mov r0, #0 @ clear result registers r0 and r1 301 mov r1, #0 302 bx r2 @ do long jump 303 END art_quick_do_long_jump 304 305 /* 306 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on 307 * failure. 308 */ 309 .extern artHandleFillArrayDataFromCode 310 ENTRY art_quick_handle_fill_data 311 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC 312 mov r2, r9 @ pass Thread::Current 313 mov r3, sp @ pass SP 314 bl artHandleFillArrayDataFromCode @ (Array*, const DexFile::Payload*, Thread*, SP) 315 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 316 RETURN_IF_RESULT_IS_ZERO 317 DELIVER_PENDING_EXCEPTION 318 END art_quick_handle_fill_data 319 320 /* 321 * Entry from managed code that calls artLockObjectFromCode, may block for GC. 322 */ 323 .extern artLockObjectFromCode 324 ENTRY art_quick_lock_object 325 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case we block 326 mov r1, r9 @ pass Thread::Current 327 mov r2, sp @ pass SP 328 bl artLockObjectFromCode @ (Object* obj, Thread*, SP) 329 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 330 END art_quick_lock_object 331 332 /* 333 * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure. 334 */ 335 .extern artUnlockObjectFromCode 336 ENTRY art_quick_unlock_object 337 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC 338 mov r1, r9 @ pass Thread::Current 339 mov r2, sp @ pass SP 340 bl artUnlockObjectFromCode @ (Object* obj, Thread*, SP) 341 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 342 RETURN_IF_RESULT_IS_ZERO 343 DELIVER_PENDING_EXCEPTION 344 END art_quick_unlock_object 345 346 /* 347 * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure. 348 */ 349 .extern artCheckCastFromCode 350 ENTRY art_quick_check_cast 351 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC 352 mov r2, r9 @ pass Thread::Current 353 mov r3, sp @ pass SP 354 bl artCheckCastFromCode @ (Class* a, Class* b, Thread*, SP) 355 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 356 RETURN_IF_RESULT_IS_ZERO 357 DELIVER_PENDING_EXCEPTION 358 END art_quick_check_cast 359 360 /* 361 * Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on 362 * failure. 363 */ 364 .extern artCanPutArrayElementFromCode 365 ENTRY art_quick_can_put_array_element 366 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case exception allocation triggers GC 367 mov r2, r9 @ pass Thread::Current 368 mov r3, sp @ pass SP 369 bl artCanPutArrayElementFromCode @ (Object* element, Class* array_class, Thread*, SP) 370 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 371 RETURN_IF_RESULT_IS_ZERO 372 DELIVER_PENDING_EXCEPTION 373 END art_quick_can_put_array_element 374 375 /* 376 * Entry from managed code when uninitialized static storage, this stub will run the class 377 * initializer and deliver the exception on error. On success the static storage base is 378 * returned. 379 */ 380 .extern artInitializeStaticStorageFromCode 381 ENTRY art_quick_initialize_static_storage 382 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 383 mov r2, r9 @ pass Thread::Current 384 mov r3, sp @ pass SP 385 @ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP) 386 bl artInitializeStaticStorageFromCode 387 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 388 RETURN_IF_RESULT_IS_NON_ZERO 389 DELIVER_PENDING_EXCEPTION 390 END art_quick_initialize_static_storage 391 392 /* 393 * Entry from managed code when dex cache misses for a type_idx 394 */ 395 .extern artInitializeTypeFromCode 396 ENTRY art_quick_initialize_type 397 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 398 mov r2, r9 @ pass Thread::Current 399 mov r3, sp @ pass SP 400 @ artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, SP) 401 bl artInitializeTypeFromCode 402 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 403 RETURN_IF_RESULT_IS_NON_ZERO 404 DELIVER_PENDING_EXCEPTION 405 END art_quick_initialize_type 406 407 /* 408 * Entry from managed code when type_idx needs to be checked for access and dex cache may also 409 * miss. 410 */ 411 .extern artInitializeTypeAndVerifyAccessFromCode 412 ENTRY art_quick_initialize_type_and_verify_access 413 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 414 mov r2, r9 @ pass Thread::Current 415 mov r3, sp @ pass SP 416 @ artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Method* referrer, Thread*, SP) 417 bl artInitializeTypeAndVerifyAccessFromCode 418 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 419 RETURN_IF_RESULT_IS_NON_ZERO 420 DELIVER_PENDING_EXCEPTION 421 END art_quick_initialize_type_and_verify_access 422 423 /* 424 * Called by managed code to resolve a static field and load a 32-bit primitive value. 425 */ 426 .extern artGet32StaticFromCode 427 ENTRY art_quick_get32_static 428 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 429 ldr r1, [sp, #32] @ pass referrer 430 mov r2, r9 @ pass Thread::Current 431 mov r3, sp @ pass SP 432 bl artGet32StaticFromCode @ (uint32_t field_idx, const Method* referrer, Thread*, SP) 433 ldr r1, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 434 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 435 cbnz r1, 1f @ success if no exception pending 436 bx lr @ return on success 437 1: 438 DELIVER_PENDING_EXCEPTION 439 END art_quick_get32_static 440 441 /* 442 * Called by managed code to resolve a static field and load a 64-bit primitive value. 443 */ 444 .extern artGet64StaticFromCode 445 ENTRY art_quick_get64_static 446 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 447 ldr r1, [sp, #32] @ pass referrer 448 mov r2, r9 @ pass Thread::Current 449 mov r3, sp @ pass SP 450 bl artGet64StaticFromCode @ (uint32_t field_idx, const Method* referrer, Thread*, SP) 451 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 452 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 453 cbnz r2, 1f @ success if no exception pending 454 bx lr @ return on success 455 1: 456 DELIVER_PENDING_EXCEPTION 457 END art_quick_get64_static 458 459 /* 460 * Called by managed code to resolve a static field and load an object reference. 461 */ 462 .extern artGetObjStaticFromCode 463 ENTRY art_quick_get_obj_static 464 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 465 ldr r1, [sp, #32] @ pass referrer 466 mov r2, r9 @ pass Thread::Current 467 mov r3, sp @ pass SP 468 bl artGetObjStaticFromCode @ (uint32_t field_idx, const Method* referrer, Thread*, SP) 469 ldr r1, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 470 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 471 cbnz r1, 1f @ success if no exception pending 472 bx lr @ return on success 473 1: 474 DELIVER_PENDING_EXCEPTION 475 END art_quick_get_obj_static 476 477 /* 478 * Called by managed code to resolve an instance field and load a 32-bit primitive value. 479 */ 480 .extern artGet32InstanceFromCode 481 ENTRY art_quick_get32_instance 482 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 483 ldr r2, [sp, #32] @ pass referrer 484 mov r3, r9 @ pass Thread::Current 485 mov r12, sp 486 str r12, [sp, #-16]! @ expand the frame and pass SP 487 bl artGet32InstanceFromCode @ (field_idx, Object*, referrer, Thread*, SP) 488 add sp, #16 @ strip the extra frame 489 ldr r1, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 490 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 491 cbnz r1, 1f @ success if no exception pending 492 bx lr @ return on success 493 1: 494 DELIVER_PENDING_EXCEPTION 495 END art_quick_get32_instance 496 497 /* 498 * Called by managed code to resolve an instance field and load a 64-bit primitive value. 499 */ 500 .extern artGet64InstanceFromCode 501 ENTRY art_quick_get64_instance 502 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 503 ldr r2, [sp, #32] @ pass referrer 504 mov r3, r9 @ pass Thread::Current 505 mov r12, sp 506 str r12, [sp, #-16]! @ expand the frame and pass SP 507 .pad #16 508 .cfi_adjust_cfa_offset 16 509 bl artGet64InstanceFromCode @ (field_idx, Object*, referrer, Thread*, SP) 510 add sp, #16 @ strip the extra frame 511 .cfi_adjust_cfa_offset -16 512 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 513 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 514 cbnz r2, 1f @ success if no exception pending 515 bx lr @ return on success 516 1: 517 DELIVER_PENDING_EXCEPTION 518 END art_quick_get64_instance 519 520 /* 521 * Called by managed code to resolve an instance field and load an object reference. 522 */ 523 .extern artGetObjInstanceFromCode 524 ENTRY art_quick_get_obj_instance 525 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 526 ldr r2, [sp, #32] @ pass referrer 527 mov r3, r9 @ pass Thread::Current 528 mov r12, sp 529 str r12, [sp, #-16]! @ expand the frame and pass SP 530 .pad #16 531 .cfi_adjust_cfa_offset 16 532 bl artGetObjInstanceFromCode @ (field_idx, Object*, referrer, Thread*, SP) 533 add sp, #16 @ strip the extra frame 534 .cfi_adjust_cfa_offset -16 535 ldr r1, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 536 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 537 cbnz r1, 1f @ success if no exception pending 538 bx lr @ return on success 539 1: 540 DELIVER_PENDING_EXCEPTION 541 END art_quick_get_obj_instance 542 543 /* 544 * Called by managed code to resolve a static field and store a 32-bit primitive value. 545 */ 546 .extern artSet32StaticFromCode 547 ENTRY art_quick_set32_static 548 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 549 ldr r2, [sp, #32] @ pass referrer 550 mov r3, r9 @ pass Thread::Current 551 mov r12, sp 552 str r12, [sp, #-16]! @ expand the frame and pass SP 553 .pad #16 554 .cfi_adjust_cfa_offset 16 555 bl artSet32StaticFromCode @ (field_idx, new_val, referrer, Thread*, SP) 556 add sp, #16 @ strip the extra frame 557 .cfi_adjust_cfa_offset -16 558 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 559 RETURN_IF_RESULT_IS_ZERO 560 DELIVER_PENDING_EXCEPTION 561 END art_quick_set32_static 562 563 /* 564 * Called by managed code to resolve a static field and store a 64-bit primitive value. 565 * On entry r0 holds field index, r1:r2 hold new_val 566 */ 567 .extern artSet64StaticFromCode 568 ENTRY art_quick_set64_static 569 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 570 mov r3, r2 @ pass one half of wide argument 571 mov r2, r1 @ pass other half of wide argument 572 ldr r1, [sp, #32] @ pass referrer 573 mov r12, sp @ save SP 574 sub sp, #8 @ grow frame for alignment with stack args 575 .pad #8 576 .cfi_adjust_cfa_offset 8 577 push {r9, r12} @ pass Thread::Current and SP 578 .save {r9, r12} 579 .cfi_adjust_cfa_offset 8 580 .cfi_rel_offset r9, 0 581 bl artSet64StaticFromCode @ (field_idx, referrer, new_val, Thread*, SP) 582 add sp, #16 @ release out args 583 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here 584 RETURN_IF_RESULT_IS_ZERO 585 DELIVER_PENDING_EXCEPTION 586 END art_quick_set64_static 587 588 /* 589 * Called by managed code to resolve a static field and store an object reference. 590 */ 591 .extern artSetObjStaticFromCode 592 ENTRY art_quick_set_obj_static 593 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 594 ldr r2, [sp, #32] @ pass referrer 595 mov r3, r9 @ pass Thread::Current 596 mov r12, sp 597 str r12, [sp, #-16]! @ expand the frame and pass SP 598 .pad #16 599 .cfi_adjust_cfa_offset 16 600 bl artSetObjStaticFromCode @ (field_idx, new_val, referrer, Thread*, SP) 601 add sp, #16 @ strip the extra frame 602 .cfi_adjust_cfa_offset -16 603 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 604 RETURN_IF_RESULT_IS_ZERO 605 DELIVER_PENDING_EXCEPTION 606 END art_quick_set_obj_static 607 608 /* 609 * Called by managed code to resolve an instance field and store a 32-bit primitive value. 610 */ 611 .extern artSet32InstanceFromCode 612 ENTRY art_quick_set32_instance 613 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 614 ldr r3, [sp, #32] @ pass referrer 615 mov r12, sp @ save SP 616 sub sp, #8 @ grow frame for alignment with stack args 617 .pad #8 618 .cfi_adjust_cfa_offset 8 619 push {r9, r12} @ pass Thread::Current and SP 620 .save {r9, r12} 621 .cfi_adjust_cfa_offset 8 622 .cfi_rel_offset r9, 0 623 .cfi_rel_offset r12, 4 624 bl artSet32InstanceFromCode @ (field_idx, Object*, new_val, referrer, Thread*, SP) 625 add sp, #16 @ release out args 626 .cfi_adjust_cfa_offset -16 627 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here 628 RETURN_IF_RESULT_IS_ZERO 629 DELIVER_PENDING_EXCEPTION 630 END art_quick_set32_instance 631 632 /* 633 * Called by managed code to resolve an instance field and store a 64-bit primitive value. 634 */ 635 .extern artSet32InstanceFromCode 636 ENTRY art_quick_set64_instance 637 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 638 mov r12, sp @ save SP 639 sub sp, #8 @ grow frame for alignment with stack args 640 .pad #8 641 .cfi_adjust_cfa_offset 8 642 push {r9, r12} @ pass Thread::Current and SP 643 .save {r9, r12} 644 .cfi_adjust_cfa_offset 8 645 .cfi_rel_offset r9, 0 646 bl artSet64InstanceFromCode @ (field_idx, Object*, new_val, Thread*, SP) 647 add sp, #16 @ release out args 648 .cfi_adjust_cfa_offset -16 649 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here 650 RETURN_IF_RESULT_IS_ZERO 651 DELIVER_PENDING_EXCEPTION 652 END art_quick_set64_instance 653 654 /* 655 * Called by managed code to resolve an instance field and store an object reference. 656 */ 657 .extern artSetObjInstanceFromCode 658 ENTRY art_quick_set_obj_instance 659 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 660 ldr r3, [sp, #32] @ pass referrer 661 mov r12, sp @ save SP 662 sub sp, #8 @ grow frame for alignment with stack args 663 .pad #8 664 .cfi_adjust_cfa_offset 8 665 push {r9, r12} @ pass Thread::Current and SP 666 .save {r9, r12} 667 .cfi_adjust_cfa_offset 8 668 .cfi_rel_offset r9, 0 669 bl artSetObjInstanceFromCode @ (field_idx, Object*, new_val, referrer, Thread*, SP) 670 add sp, #16 @ release out args 671 .cfi_adjust_cfa_offset -16 672 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here 673 RETURN_IF_RESULT_IS_ZERO 674 DELIVER_PENDING_EXCEPTION 675 END art_quick_set_obj_instance 676 677 /* 678 * Entry from managed code to resolve a string, this stub will allocate a String and deliver an 679 * exception on error. On success the String is returned. R0 holds the referring method, 680 * R1 holds the string index. The fast path check for hit in strings cache has already been 681 * performed. 682 */ 683 .extern artResolveStringFromCode 684 ENTRY art_quick_resolve_string 685 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 686 mov r2, r9 @ pass Thread::Current 687 mov r3, sp @ pass SP 688 @ artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*, SP) 689 bl artResolveStringFromCode 690 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 691 RETURN_IF_RESULT_IS_NON_ZERO 692 DELIVER_PENDING_EXCEPTION 693 END art_quick_resolve_string 694 695 /* 696 * Called by managed code to allocate an object 697 */ 698 .extern artAllocObjectFromCode 699 ENTRY art_quick_alloc_object 700 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 701 mov r2, r9 @ pass Thread::Current 702 mov r3, sp @ pass SP 703 bl artAllocObjectFromCode @ (uint32_t type_idx, Method* method, Thread*, SP) 704 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 705 RETURN_IF_RESULT_IS_NON_ZERO 706 DELIVER_PENDING_EXCEPTION 707 END art_quick_alloc_object 708 709 /* 710 * Called by managed code to allocate an object when the caller doesn't know whether it has 711 * access to the created type. 712 */ 713 .extern artAllocObjectFromCodeWithAccessCheck 714 ENTRY art_quick_alloc_object_with_access_check 715 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 716 mov r2, r9 @ pass Thread::Current 717 mov r3, sp @ pass SP 718 bl artAllocObjectFromCodeWithAccessCheck @ (uint32_t type_idx, Method* method, Thread*, SP) 719 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 720 RETURN_IF_RESULT_IS_NON_ZERO 721 DELIVER_PENDING_EXCEPTION 722 END art_quick_alloc_object_with_access_check 723 724 /* 725 * Called by managed code to allocate an array. 726 */ 727 .extern artAllocArrayFromCode 728 ENTRY art_quick_alloc_array 729 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 730 mov r3, r9 @ pass Thread::Current 731 mov r12, sp 732 str r12, [sp, #-16]! @ expand the frame and pass SP 733 .pad #16 734 .cfi_adjust_cfa_offset 16 735 @ artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count, Thread*, SP) 736 bl artAllocArrayFromCode 737 add sp, #16 @ strip the extra frame 738 .cfi_adjust_cfa_offset -16 739 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 740 RETURN_IF_RESULT_IS_NON_ZERO 741 DELIVER_PENDING_EXCEPTION 742 END art_quick_alloc_array 743 744 /* 745 * Called by managed code to allocate an array when the caller doesn't know whether it has 746 * access to the created type. 747 */ 748 .extern artAllocArrayFromCodeWithAccessCheck 749 ENTRY art_quick_alloc_array_with_access_check 750 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 751 mov r3, r9 @ pass Thread::Current 752 mov r12, sp 753 str r12, [sp, #-16]! @ expand the frame and pass SP 754 .pad #16 755 .cfi_adjust_cfa_offset 16 756 @ artAllocArrayFromCodeWithAccessCheck(type_idx, method, component_count, Thread*, SP) 757 bl artAllocArrayFromCodeWithAccessCheck 758 add sp, #16 @ strip the extra frame 759 .cfi_adjust_cfa_offset -16 760 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 761 RETURN_IF_RESULT_IS_NON_ZERO 762 DELIVER_PENDING_EXCEPTION 763 END art_quick_alloc_array_with_access_check 764 765 /* 766 * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY. 767 */ 768 .extern artCheckAndAllocArrayFromCode 769 ENTRY art_quick_check_and_alloc_array 770 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 771 mov r3, r9 @ pass Thread::Current 772 mov r12, sp 773 str r12, [sp, #-16]! @ expand the frame and pass SP 774 .pad #16 775 .cfi_adjust_cfa_offset 16 776 @ artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t count, Thread* , SP) 777 bl artCheckAndAllocArrayFromCode 778 add sp, #16 @ strip the extra frame 779 .cfi_adjust_cfa_offset -16 780 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 781 RETURN_IF_RESULT_IS_NON_ZERO 782 DELIVER_PENDING_EXCEPTION 783 END art_quick_check_and_alloc_array 784 785 /* 786 * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY. 787 */ 788 .extern artCheckAndAllocArrayFromCodeWithAccessCheck 789 ENTRY art_quick_check_and_alloc_array_with_access_check 790 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC 791 mov r3, r9 @ pass Thread::Current 792 mov r12, sp 793 str r12, [sp, #-16]! @ expand the frame and pass SP 794 .pad #16 795 .cfi_adjust_cfa_offset 16 796 @ artCheckAndAllocArrayFromCodeWithAccessCheck(type_idx, method, count, Thread* , SP) 797 bl artCheckAndAllocArrayFromCodeWithAccessCheck 798 add sp, #16 @ strip the extra frame 799 .cfi_adjust_cfa_offset -16 800 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 801 RETURN_IF_RESULT_IS_NON_ZERO 802 DELIVER_PENDING_EXCEPTION 803 END art_quick_check_and_alloc_array_with_access_check 804 805 /* 806 * Called by managed code when the value in rSUSPEND has been decremented to 0. 807 */ 808 .extern artTestSuspendFromCode 809 ENTRY art_quick_test_suspend 810 ldrh r0, [rSELF, #THREAD_FLAGS_OFFSET] 811 mov rSUSPEND, #SUSPEND_CHECK_INTERVAL @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL 812 cbnz r0, 1f @ check Thread::Current()->suspend_count_ == 0 813 bx lr @ return if suspend_count_ == 0 814 1: 815 mov r0, rSELF 816 SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves for stack crawl 817 mov r1, sp 818 bl artTestSuspendFromCode @ (Thread*, SP) 819 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 820 END art_quick_test_suspend 821 822 /* 823 * Called by managed code that is attempting to call a method on a proxy class. On entry 824 * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The 825 * frame size of the invoked proxy method agrees with a ref and args callee save frame. 826 */ 827 .extern artQuickProxyInvokeHandler 828 ENTRY art_quick_proxy_invoke_handler 829 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 830 str r0, [sp, #0] @ place proxy method at bottom of frame 831 mov r2, r9 @ pass Thread::Current 832 mov r3, sp @ pass SP 833 blx artQuickProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP) 834 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 835 ldr lr, [sp, #44] @ restore lr 836 add sp, #48 @ pop frame 837 .cfi_adjust_cfa_offset -48 838 cbnz r2, 1f @ success if no exception is pending 839 bx lr @ return on success 840 1: 841 DELIVER_PENDING_EXCEPTION 842 END art_quick_proxy_invoke_handler 843 844 .extern artQuickResolutionTrampoline 845 ENTRY art_quick_resolution_trampoline 846 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 847 mov r2, r9 @ pass Thread::Current 848 mov r3, sp @ pass SP 849 blx artQuickResolutionTrampoline @ (Method* called, receiver, Thread*, SP) 850 cbz r0, 1f @ is code pointer null? goto exception 851 mov r12, r0 852 ldr r0, [sp, #0] @ load resolved method in r0 853 ldr r1, [sp, #8] @ restore non-callee save r1 854 ldrd r2, [sp, #12] @ restore non-callee saves r2-r3 855 ldr lr, [sp, #44] @ restore lr 856 add sp, #48 @ rewind sp 857 .cfi_adjust_cfa_offset -48 858 bx r12 @ tail-call into actual code 859 1: 860 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 861 DELIVER_PENDING_EXCEPTION 862 END art_quick_resolution_trampoline 863 864 .extern artQuickToInterpreterBridge 865 ENTRY art_quick_to_interpreter_bridge 866 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 867 mov r1, r9 @ pass Thread::Current 868 mov r2, sp @ pass SP 869 blx artQuickToInterpreterBridge @ (Method* method, Thread*, SP) 870 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 871 ldr lr, [sp, #44] @ restore lr 872 add sp, #48 @ pop frame 873 .cfi_adjust_cfa_offset -48 874 cbnz r2, 1f @ success if no exception is pending 875 bx lr @ return on success 876 1: 877 DELIVER_PENDING_EXCEPTION 878 END art_quick_to_interpreter_bridge 879 880 /* 881 * Routine that intercepts method calls and returns. 882 */ 883 .extern artInstrumentationMethodEntryFromCode 884 .extern artInstrumentationMethodExitFromCode 885 ENTRY art_quick_instrumentation_entry 886 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 887 str r0, [sp, #4] @ preserve r0 888 mov r12, sp @ remember sp 889 str lr, [sp, #-16]! @ expand the frame and pass LR 890 .pad #16 891 .cfi_adjust_cfa_offset 16 892 .cfi_rel_offset lr, 0 893 mov r2, r9 @ pass Thread::Current 894 mov r3, r12 @ pass SP 895 blx artInstrumentationMethodEntryFromCode @ (Method*, Object*, Thread*, SP, LR) 896 add sp, #16 @ remove out argument and padding from stack 897 .cfi_adjust_cfa_offset -16 898 mov r12, r0 @ r12 holds reference to code 899 ldr r0, [sp, #4] @ restore r0 900 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 901 blx r12 @ call method with lr set to art_quick_instrumentation_exit 902 END art_quick_instrumentation_entry 903 .type art_quick_instrumentation_exit, #function 904 .global art_quick_instrumentation_exit 905 art_quick_instrumentation_exit: 906 .cfi_startproc 907 .fnstart 908 mov lr, #0 @ link register is to here, so clobber with 0 for later checks 909 SETUP_REF_ONLY_CALLEE_SAVE_FRAME 910 mov r12, sp @ remember bottom of caller's frame 911 push {r0-r1} @ save return value 912 .save {r0-r1} 913 .cfi_adjust_cfa_offset 8 914 .cfi_rel_offset r0, 0 915 .cfi_rel_offset r1, 4 916 sub sp, #8 @ space for return value argument 917 .pad #8 918 .cfi_adjust_cfa_offset 8 919 strd r0, [sp] @ r0/r1 -> [sp] for fpr_res 920 mov r2, r0 @ pass return value as gpr_res 921 mov r3, r1 922 mov r0, r9 @ pass Thread::Current 923 mov r1, r12 @ pass SP 924 blx artInstrumentationMethodExitFromCode @ (Thread*, SP, gpr_res, fpr_res) 925 add sp, #8 926 .cfi_adjust_cfa_offset -8 927 928 mov r2, r0 @ link register saved by instrumentation 929 mov lr, r1 @ r1 is holding link register if we're to bounce to deoptimize 930 pop {r0, r1} @ restore return value 931 add sp, #32 @ remove callee save frame 932 .cfi_adjust_cfa_offset -32 933 bx r2 @ return 934 END art_quick_instrumentation_exit 935 936 /* 937 * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization 938 * will long jump to the upcall with a special exception of -1. 939 */ 940 .extern artDeoptimize 941 ENTRY art_quick_deoptimize 942 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 943 mov r0, r9 @ Set up args. 944 mov r1, sp 945 blx artDeoptimize @ artDeoptimize(Thread*, SP) 946 END art_quick_deoptimize 947 948 /* 949 * Signed 64-bit integer multiply. 950 * 951 * Consider WXxYZ (r1r0 x r3r2) with a long multiply: 952 * WX 953 * x YZ 954 * -------- 955 * ZW ZX 956 * YW YX 957 * 958 * The low word of the result holds ZX, the high word holds 959 * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because 960 * it doesn't fit in the low 64 bits. 961 * 962 * Unlike most ARM math operations, multiply instructions have 963 * restrictions on using the same register more than once (Rd and Rm 964 * cannot be the same). 965 */ 966 /* mul-long vAA, vBB, vCC */ 967 ENTRY art_quick_mul_long 968 push {r9 - r10} 969 .save {r9 - r10} 970 .cfi_adjust_cfa_offset 8 971 .cfi_rel_offset r9, 0 972 .cfi_rel_offset r10, 4 973 mul ip, r2, r1 @ ip<- ZxW 974 umull r9, r10, r2, r0 @ r9/r10 <- ZxX 975 mla r2, r0, r3, ip @ r2<- YxX + (ZxW) 976 add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX)) 977 mov r0,r9 978 mov r1,r10 979 pop {r9 - r10} 980 .cfi_adjust_cfa_offset -8 981 bx lr 982 END art_quick_mul_long 983 984 /* 985 * Long integer shift. This is different from the generic 32/64-bit 986 * binary operations because vAA/vBB are 64-bit but vCC (the shift 987 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 988 * 6 bits. 989 * On entry: 990 * r0: low word 991 * r1: high word 992 * r2: shift count 993 */ 994 /* shl-long vAA, vBB, vCC */ 995 ARM_ENTRY art_quick_shl_long @ ARM code as thumb code requires spills 996 and r2, r2, #63 @ r2<- r2 & 0x3f 997 mov r1, r1, asl r2 @ r1<- r1 << r2 998 rsb r3, r2, #32 @ r3<- 32 - r2 999 orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2)) 1000 subs ip, r2, #32 @ ip<- r2 - 32 1001 movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32) 1002 mov r0, r0, asl r2 @ r0<- r0 << r2 1003 bx lr 1004 END art_quick_shl_long 1005 1006 /* 1007 * Long integer shift. This is different from the generic 32/64-bit 1008 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1009 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1010 * 6 bits. 1011 * On entry: 1012 * r0: low word 1013 * r1: high word 1014 * r2: shift count 1015 */ 1016 /* shr-long vAA, vBB, vCC */ 1017 ARM_ENTRY art_quick_shr_long @ ARM code as thumb code requires spills 1018 and r2, r2, #63 @ r0<- r0 & 0x3f 1019 mov r0, r0, lsr r2 @ r0<- r2 >> r2 1020 rsb r3, r2, #32 @ r3<- 32 - r2 1021 orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2)) 1022 subs ip, r2, #32 @ ip<- r2 - 32 1023 movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32) 1024 mov r1, r1, asr r2 @ r1<- r1 >> r2 1025 bx lr 1026 END art_quick_shr_long 1027 1028 /* 1029 * Long integer shift. This is different from the generic 32/64-bit 1030 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1031 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1032 * 6 bits. 1033 * On entry: 1034 * r0: low word 1035 * r1: high word 1036 * r2: shift count 1037 */ 1038 /* ushr-long vAA, vBB, vCC */ 1039 ARM_ENTRY art_quick_ushr_long @ ARM code as thumb code requires spills 1040 and r2, r2, #63 @ r0<- r0 & 0x3f 1041 mov r0, r0, lsr r2 @ r0<- r2 >> r2 1042 rsb r3, r2, #32 @ r3<- 32 - r2 1043 orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2)) 1044 subs ip, r2, #32 @ ip<- r2 - 32 1045 movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32) 1046 mov r1, r1, lsr r2 @ r1<- r1 >>> r2 1047 bx lr 1048 END art_quick_ushr_long 1049 1050 /* 1051 * String's indexOf. 1052 * 1053 * On entry: 1054 * r0: string object (known non-null) 1055 * r1: char to match (known <= 0xFFFF) 1056 * r2: Starting offset in string data 1057 */ 1058 ENTRY art_quick_indexof 1059 push {r4, r10-r11, lr} @ 4 words of callee saves 1060 .save {r4, r10-r11, lr} 1061 .cfi_adjust_cfa_offset 16 1062 .cfi_rel_offset r4, 0 1063 .cfi_rel_offset r10, 4 1064 .cfi_rel_offset r11, 8 1065 .cfi_rel_offset lr, 12 1066 ldr r3, [r0, #STRING_COUNT_OFFSET] 1067 ldr r12, [r0, #STRING_OFFSET_OFFSET] 1068 ldr r0, [r0, #STRING_VALUE_OFFSET] 1069 1070 /* Clamp start to [0..count] */ 1071 cmp r2, #0 1072 it lt 1073 movlt r2, #0 1074 cmp r2, r3 1075 it gt 1076 movgt r2, r3 1077 1078 /* Build a pointer to the start of string data */ 1079 add r0, #STRING_DATA_OFFSET 1080 add r0, r0, r12, lsl #1 1081 1082 /* Save a copy in r12 to later compute result */ 1083 mov r12, r0 1084 1085 /* Build pointer to start of data to compare and pre-bias */ 1086 add r0, r0, r2, lsl #1 1087 sub r0, #2 1088 1089 /* Compute iteration count */ 1090 sub r2, r3, r2 1091 1092 /* 1093 * At this point we have: 1094 * r0: start of data to test 1095 * r1: char to compare 1096 * r2: iteration count 1097 * r12: original start of string data 1098 * r3, r4, r10, r11 available for loading string data 1099 */ 1100 1101 subs r2, #4 1102 blt indexof_remainder 1103 1104 indexof_loop4: 1105 ldrh r3, [r0, #2]! 1106 ldrh r4, [r0, #2]! 1107 ldrh r10, [r0, #2]! 1108 ldrh r11, [r0, #2]! 1109 cmp r3, r1 1110 beq match_0 1111 cmp r4, r1 1112 beq match_1 1113 cmp r10, r1 1114 beq match_2 1115 cmp r11, r1 1116 beq match_3 1117 subs r2, #4 1118 bge indexof_loop4 1119 1120 indexof_remainder: 1121 adds r2, #4 1122 beq indexof_nomatch 1123 1124 indexof_loop1: 1125 ldrh r3, [r0, #2]! 1126 cmp r3, r1 1127 beq match_3 1128 subs r2, #1 1129 bne indexof_loop1 1130 1131 indexof_nomatch: 1132 mov r0, #-1 1133 pop {r4, r10-r11, pc} 1134 1135 match_0: 1136 sub r0, #6 1137 sub r0, r12 1138 asr r0, r0, #1 1139 pop {r4, r10-r11, pc} 1140 match_1: 1141 sub r0, #4 1142 sub r0, r12 1143 asr r0, r0, #1 1144 pop {r4, r10-r11, pc} 1145 match_2: 1146 sub r0, #2 1147 sub r0, r12 1148 asr r0, r0, #1 1149 pop {r4, r10-r11, pc} 1150 match_3: 1151 sub r0, r12 1152 asr r0, r0, #1 1153 pop {r4, r10-r11, pc} 1154 END art_quick_indexof 1155 1156 /* 1157 * String's compareTo. 1158 * 1159 * Requires rARG0/rARG1 to have been previously checked for null. Will 1160 * return negative if this's string is < comp, 0 if they are the 1161 * same and positive if >. 1162 * 1163 * On entry: 1164 * r0: this object pointer 1165 * r1: comp object pointer 1166 * 1167 */ 1168 .extern __memcmp16 1169 ENTRY art_quick_string_compareto 1170 mov r2, r0 @ this to r2, opening up r0 for return value 1171 sub r0, r2, r1 @ Same? 1172 cbnz r0,1f 1173 bx lr 1174 1: @ Same strings, return. 1175 1176 push {r4, r7-r12, lr} @ 8 words - keep alignment 1177 .save {r4, r7-r12, lr} 1178 .cfi_adjust_cfa_offset 32 1179 .cfi_rel_offset r4, 0 1180 .cfi_rel_offset r7, 4 1181 .cfi_rel_offset r8, 8 1182 .cfi_rel_offset r9, 12 1183 .cfi_rel_offset r10, 16 1184 .cfi_rel_offset r11, 20 1185 .cfi_rel_offset r12, 24 1186 .cfi_rel_offset lr, 28 1187 1188 ldr r4, [r2, #STRING_OFFSET_OFFSET] 1189 ldr r9, [r1, #STRING_OFFSET_OFFSET] 1190 ldr r7, [r2, #STRING_COUNT_OFFSET] 1191 ldr r10, [r1, #STRING_COUNT_OFFSET] 1192 ldr r2, [r2, #STRING_VALUE_OFFSET] 1193 ldr r1, [r1, #STRING_VALUE_OFFSET] 1194 1195 /* 1196 * At this point, we have: 1197 * value: r2/r1 1198 * offset: r4/r9 1199 * count: r7/r10 1200 * We're going to compute 1201 * r11 <- countDiff 1202 * r10 <- minCount 1203 */ 1204 subs r11, r7, r10 1205 it ls 1206 movls r10, r7 1207 1208 /* Now, build pointers to the string data */ 1209 add r2, r2, r4, lsl #1 1210 add r1, r1, r9, lsl #1 1211 /* 1212 * Note: data pointers point to previous element so we can use pre-index 1213 * mode with base writeback. 1214 */ 1215 add r2, #STRING_DATA_OFFSET-2 @ offset to contents[-1] 1216 add r1, #STRING_DATA_OFFSET-2 @ offset to contents[-1] 1217 1218 /* 1219 * At this point we have: 1220 * r2: *this string data 1221 * r1: *comp string data 1222 * r10: iteration count for comparison 1223 * r11: value to return if the first part of the string is equal 1224 * r0: reserved for result 1225 * r3, r4, r7, r8, r9, r12 available for loading string data 1226 */ 1227 1228 subs r10, #2 1229 blt do_remainder2 1230 1231 /* 1232 * Unroll the first two checks so we can quickly catch early mismatch 1233 * on long strings (but preserve incoming alignment) 1234 */ 1235 1236 ldrh r3, [r2, #2]! 1237 ldrh r4, [r1, #2]! 1238 ldrh r7, [r2, #2]! 1239 ldrh r8, [r1, #2]! 1240 subs r0, r3, r4 1241 it eq 1242 subseq r0, r7, r8 1243 bne done 1244 cmp r10, #28 1245 bgt do_memcmp16 1246 subs r10, #3 1247 blt do_remainder 1248 1249 loopback_triple: 1250 ldrh r3, [r2, #2]! 1251 ldrh r4, [r1, #2]! 1252 ldrh r7, [r2, #2]! 1253 ldrh r8, [r1, #2]! 1254 ldrh r9, [r2, #2]! 1255 ldrh r12,[r1, #2]! 1256 subs r0, r3, r4 1257 it eq 1258 subseq r0, r7, r8 1259 it eq 1260 subseq r0, r9, r12 1261 bne done 1262 subs r10, #3 1263 bge loopback_triple 1264 1265 do_remainder: 1266 adds r10, #3 1267 beq returnDiff 1268 1269 loopback_single: 1270 ldrh r3, [r2, #2]! 1271 ldrh r4, [r1, #2]! 1272 subs r0, r3, r4 1273 bne done 1274 subs r10, #1 1275 bne loopback_single 1276 1277 returnDiff: 1278 mov r0, r11 1279 pop {r4, r7-r12, pc} 1280 1281 do_remainder2: 1282 adds r10, #2 1283 bne loopback_single 1284 mov r0, r11 1285 pop {r4, r7-r12, pc} 1286 1287 /* Long string case */ 1288 do_memcmp16: 1289 mov r7, r11 1290 add r0, r2, #2 1291 add r1, r1, #2 1292 mov r2, r10 1293 bl __memcmp16 1294 cmp r0, #0 1295 it eq 1296 moveq r0, r7 1297 done: 1298 pop {r4, r7-r12, pc} 1299 END art_quick_string_compareto 1300