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#include "arch/quick_alloc_entrypoints.S" 20 21 /* Deliver the given exception */ 22 .extern artDeliverExceptionFromCode 23 /* Deliver an exception pending on a thread */ 24 .extern artDeliverPendingException 25 26 /* 27 * Macro that sets up the callee save frame to conform with 28 * Runtime::CreateCalleeSaveMethod(kSaveAll) 29 */ 30.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME rTemp1, rTemp2 31 push {r4-r11, lr} @ 9 words (36 bytes) of callee saves. 32 .cfi_adjust_cfa_offset 36 33 .cfi_rel_offset r4, 0 34 .cfi_rel_offset r5, 4 35 .cfi_rel_offset r6, 8 36 .cfi_rel_offset r7, 12 37 .cfi_rel_offset r8, 16 38 .cfi_rel_offset r9, 20 39 .cfi_rel_offset r10, 24 40 .cfi_rel_offset r11, 28 41 .cfi_rel_offset lr, 32 42 vpush {s16-s31} @ 16 words (64 bytes) of floats. 43 .cfi_adjust_cfa_offset 64 44 sub sp, #12 @ 3 words of space, bottom word will hold Method* 45 .cfi_adjust_cfa_offset 12 46 RUNTIME_CURRENT1 \rTemp1, \rTemp2 @ Load Runtime::Current into rTemp1. 47 THIS_LOAD_REQUIRES_READ_BARRIER 48 ldr \rTemp1, [\rTemp1, #RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kSaveAll Method*. 49 str \rTemp1, [sp, #0] @ Place Method* at bottom of stack. 50 str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. 51 52 // Ugly compile-time check, but we only have the preprocessor. 53#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 36 + 64 + 12) 54#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM) size not as expected." 55#endif 56.endm 57 58 /* 59 * Macro that sets up the callee save frame to conform with 60 * Runtime::CreateCalleeSaveMethod(kRefsOnly). 61 */ 62.macro SETUP_REFS_ONLY_CALLEE_SAVE_FRAME rTemp1, rTemp2 63 push {r5-r8, r10-r11, lr} @ 7 words of callee saves 64 .cfi_adjust_cfa_offset 28 65 .cfi_rel_offset r5, 0 66 .cfi_rel_offset r6, 4 67 .cfi_rel_offset r7, 8 68 .cfi_rel_offset r8, 12 69 .cfi_rel_offset r10, 16 70 .cfi_rel_offset r11, 20 71 .cfi_rel_offset lr, 24 72 sub sp, #4 @ bottom word will hold Method* 73 .cfi_adjust_cfa_offset 4 74 RUNTIME_CURRENT2 \rTemp1, \rTemp2 @ Load Runtime::Current into rTemp1. 75 THIS_LOAD_REQUIRES_READ_BARRIER 76 ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET] @ rTemp1 is kRefsOnly Method*. 77 str \rTemp1, [sp, #0] @ Place Method* at bottom of stack. 78 str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. 79 80 // Ugly compile-time check, but we only have the preprocessor. 81#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 28 + 4) 82#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM) size not as expected." 83#endif 84.endm 85 86.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 87 add sp, #4 @ bottom word holds Method* 88 .cfi_adjust_cfa_offset -4 89 pop {r5-r8, r10-r11, lr} @ 7 words of callee saves 90 .cfi_restore r5 91 .cfi_restore r6 92 .cfi_restore r7 93 .cfi_restore r8 94 .cfi_restore r10 95 .cfi_restore r11 96 .cfi_restore lr 97 .cfi_adjust_cfa_offset -28 98.endm 99 100.macro RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 101 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 102 bx lr @ return 103.endm 104 105 /* 106 * Macro that sets up the callee save frame to conform with 107 * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). 108 */ 109.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY 110 push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves and args. 111 .cfi_adjust_cfa_offset 40 112 .cfi_rel_offset r1, 0 113 .cfi_rel_offset r2, 4 114 .cfi_rel_offset r3, 8 115 .cfi_rel_offset r5, 12 116 .cfi_rel_offset r6, 16 117 .cfi_rel_offset r7, 20 118 .cfi_rel_offset r8, 24 119 .cfi_rel_offset r10, 28 120 .cfi_rel_offset r11, 32 121 .cfi_rel_offset lr, 36 122 vpush {s0-s15} @ 16 words of float args. 123 .cfi_adjust_cfa_offset 64 124 sub sp, #8 @ 2 words of space, bottom word will hold Method* 125 .cfi_adjust_cfa_offset 8 126 // Ugly compile-time check, but we only have the preprocessor. 127#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 40 + 64 + 8) 128#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM) size not as expected." 129#endif 130.endm 131 132.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME rTemp1, rTemp2 133 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY 134 RUNTIME_CURRENT3 \rTemp1, \rTemp2 @ Load Runtime::Current into rTemp1. 135 THIS_LOAD_REQUIRES_READ_BARRIER 136 @ rTemp1 is kRefsAndArgs Method*. 137 ldr \rTemp1, [\rTemp1, #RUNTIME_REFS_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET] 138 str \rTemp1, [sp, #0] @ Place Method* at bottom of stack. 139 str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. 140.endm 141 142.macro SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0 143 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_REGISTERS_ONLY 144 str r0, [sp, #0] @ Store ArtMethod* to bottom of stack. 145 str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. 146.endm 147 148.macro RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME 149 add sp, #8 @ rewind sp 150 .cfi_adjust_cfa_offset -8 151 vpop {s0-s15} 152 .cfi_adjust_cfa_offset -64 153 pop {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves 154 .cfi_restore r1 155 .cfi_restore r2 156 .cfi_restore r3 157 .cfi_restore r5 158 .cfi_restore r6 159 .cfi_restore r7 160 .cfi_restore r8 161 .cfi_restore r10 162 .cfi_restore r11 163 .cfi_restore lr 164 .cfi_adjust_cfa_offset -40 165.endm 166 167 168.macro RETURN_IF_RESULT_IS_ZERO 169 cbnz r0, 1f @ result non-zero branch over 170 bx lr @ return 1711: 172.endm 173 174.macro RETURN_IF_RESULT_IS_NON_ZERO 175 cbz r0, 1f @ result zero branch over 176 bx lr @ return 1771: 178.endm 179 180 /* 181 * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending 182 * exception is Thread::Current()->exception_ 183 */ 184.macro DELIVER_PENDING_EXCEPTION 185 .fnend 186 .fnstart 187 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1 @ save callee saves for throw 188 mov r0, r9 @ pass Thread::Current 189 b artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*) 190.endm 191 192.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 193 .extern \cxx_name 194ENTRY \c_name 195 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1 // save all registers as basis for long jump context 196 mov r0, r9 @ pass Thread::Current 197 b \cxx_name @ \cxx_name(Thread*) 198END \c_name 199.endm 200 201.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name 202 .extern \cxx_name 203ENTRY \c_name 204 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r1, r2 // save all registers as basis for long jump context 205 mov r1, r9 @ pass Thread::Current 206 b \cxx_name @ \cxx_name(Thread*) 207END \c_name 208.endm 209 210.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 211 .extern \cxx_name 212ENTRY \c_name 213 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r2, r3 // save all registers as basis for long jump context 214 mov r2, r9 @ pass Thread::Current 215 b \cxx_name @ \cxx_name(Thread*) 216END \c_name 217.endm 218 219.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg 220 ldr \reg, [r9, #THREAD_EXCEPTION_OFFSET] // Get exception field. 221 cbnz \reg, 1f 222 bx lr 2231: 224 DELIVER_PENDING_EXCEPTION 225.endm 226 227.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 228 RETURN_OR_DELIVER_PENDING_EXCEPTION_REG r1 229.endm 230 231.macro RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 232 RETURN_IF_RESULT_IS_ZERO 233 DELIVER_PENDING_EXCEPTION 234.endm 235 236.macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER 237 RETURN_IF_RESULT_IS_NON_ZERO 238 DELIVER_PENDING_EXCEPTION 239.endm 240 241// Macros taking opportunity of code similarities for downcalls with referrer for non-wide fields. 242.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return 243 .extern \entrypoint 244ENTRY \name 245 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 @ save callee saves in case of GC 246 ldr r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] @ pass referrer 247 mov r2, r9 @ pass Thread::Current 248 bl \entrypoint @ (uint32_t field_idx, const Method* referrer, Thread*) 249 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 250 \return 251END \name 252.endm 253 254.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return 255 .extern \entrypoint 256ENTRY \name 257 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3 @ save callee saves in case of GC 258 ldr r2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] @ pass referrer 259 mov r3, r9 @ pass Thread::Current 260 bl \entrypoint @ (field_idx, Object*, referrer, Thread*) 261 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 262 \return 263END \name 264.endm 265 266.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return 267 .extern \entrypoint 268ENTRY \name 269 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r3, r12 @ save callee saves in case of GC 270 ldr r3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] @ pass referrer 271 str r9, [sp, #-16]! @ expand the frame and pass Thread::Current 272 .cfi_adjust_cfa_offset 16 273 bl \entrypoint @ (field_idx, Object*, new_val, referrer, Thread*) 274 add sp, #16 @ release out args 275 .cfi_adjust_cfa_offset -16 276 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here 277 \return 278END \name 279.endm 280 281 /* 282 * Called by managed code, saves callee saves and then calls artThrowException 283 * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception. 284 */ 285ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode 286 287 /* 288 * Called by managed code to create and deliver a NullPointerException. 289 */ 290NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode 291 292 /* 293 * Called by managed code to create and deliver an ArithmeticException. 294 */ 295NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode 296 297 /* 298 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds 299 * index, arg2 holds limit. 300 */ 301TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode 302 303 /* 304 * Called by managed code to create and deliver a StackOverflowError. 305 */ 306NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode 307 308 /* 309 * Called by managed code to create and deliver a NoSuchMethodError. 310 */ 311ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode 312 313 /* 314 * All generated callsites for interface invokes and invocation slow paths will load arguments 315 * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain 316 * the method_idx. This wrapper will save arg1-arg3, load the caller's Method*, align the 317 * stack and call the appropriate C helper. 318 * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1. 319 * 320 * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting 321 * of the target Method* in r0 and method->code_ in r1. 322 * 323 * If unsuccessful, the helper will return null/null. There will bea pending exception in the 324 * thread and we branch to another stub to deliver it. 325 * 326 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr 327 * pointing back to the original caller. 328 */ 329.macro INVOKE_TRAMPOLINE c_name, cxx_name 330 .extern \cxx_name 331ENTRY \c_name 332 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3 @ save callee saves in case allocation triggers GC 333 ldr r2, [sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE] @ pass caller Method* 334 mov r3, r9 @ pass Thread::Current 335 mov r12, sp 336 str r12, [sp, #-16]! @ expand the frame and pass SP 337 .cfi_adjust_cfa_offset 16 338 bl \cxx_name @ (method_idx, this, caller, Thread*, SP) 339 add sp, #16 @ strip the extra frame 340 .cfi_adjust_cfa_offset -16 341 mov r12, r1 @ save Method*->code_ 342 RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME 343 cbz r0, 1f @ did we find the target? if not go to exception delivery 344 bx r12 @ tail call to target 3451: 346 DELIVER_PENDING_EXCEPTION 347END \c_name 348.endm 349 350INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline 351INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck 352 353INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck 354INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck 355INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck 356INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck 357 358 /* 359 * Quick invocation stub internal. 360 * On entry: 361 * r0 = method pointer 362 * r1 = argument array or null for no argument methods 363 * r2 = size of argument array in bytes 364 * r3 = (managed) thread pointer 365 * [sp] = JValue* result 366 * [sp + 4] = result_in_float 367 * [sp + 8] = core register argument array 368 * [sp + 12] = fp register argument array 369 * +-------------------------+ 370 * | uint32_t* fp_reg_args | 371 * | uint32_t* core_reg_args | 372 * | result_in_float | <- Caller frame 373 * | Jvalue* result | 374 * +-------------------------+ 375 * | lr | 376 * | r11 | 377 * | r9 | 378 * | r4 | <- r11 379 * +-------------------------+ 380 * | uint32_t out[n-1] | 381 * | : : | Outs 382 * | uint32_t out[0] | 383 * | StackRef<ArtMethod> | <- SP value=null 384 * +-------------------------+ 385 */ 386ENTRY art_quick_invoke_stub_internal 387 push {r4, r5, r6, r7, r8, r9, r10, r11, lr} @ spill regs 388 .cfi_adjust_cfa_offset 16 389 .cfi_rel_offset r4, 0 390 .cfi_rel_offset r5, 4 391 .cfi_rel_offset r6, 8 392 .cfi_rel_offset r7, 12 393 .cfi_rel_offset r8, 16 394 .cfi_rel_offset r9, 20 395 .cfi_rel_offset r10, 24 396 .cfi_rel_offset r11, 28 397 .cfi_rel_offset lr, 32 398 mov r11, sp @ save the stack pointer 399 .cfi_def_cfa_register r11 400 401 mov r9, r3 @ move managed thread pointer into r9 402 403 add r4, r2, #4 @ create space for method pointer in frame 404 sub r4, sp, r4 @ reserve & align *stack* to 16 bytes: native calling 405 and r4, #0xFFFFFFF0 @ convention only aligns to 8B, so we have to ensure ART 406 mov sp, r4 @ 16B alignment ourselves. 407 408 mov r4, r0 @ save method* 409 add r0, sp, #4 @ pass stack pointer + method ptr as dest for memcpy 410 bl memcpy @ memcpy (dest, src, bytes) 411 mov ip, #0 @ set ip to 0 412 str ip, [sp] @ store null for method* at bottom of frame 413 414 ldr ip, [r11, #48] @ load fp register argument array pointer 415 vldm ip, {s0-s15} @ copy s0 - s15 416 417 ldr ip, [r11, #44] @ load core register argument array pointer 418 mov r0, r4 @ restore method* 419 add ip, ip, #4 @ skip r0 420 ldm ip, {r1-r3} @ copy r1 - r3 421 422#ifdef ARM_R4_SUSPEND_FLAG 423 mov r4, #SUSPEND_CHECK_INTERVAL @ reset r4 to suspend check interval 424#endif 425 426 ldr ip, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] @ get pointer to the code 427 blx ip @ call the method 428 429 mov sp, r11 @ restore the stack pointer 430 .cfi_def_cfa_register sp 431 432 ldr r4, [sp, #40] @ load result_is_float 433 ldr r9, [sp, #36] @ load the result pointer 434 cmp r4, #0 435 ite eq 436 strdeq r0, [r9] @ store r0/r1 into result pointer 437 vstrne d0, [r9] @ store s0-s1/d0 into result pointer 438 439 pop {r4, r5, r6, r7, r8, r9, r10, r11, pc} @ restore spill regs 440END art_quick_invoke_stub_internal 441 442 /* 443 * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_ 444 */ 445ARM_ENTRY art_quick_do_long_jump 446 vldm r1, {s0-s31} @ load all fprs from argument fprs_ 447 ldr r2, [r0, #60] @ r2 = r15 (PC from gprs_ 60=4*15) 448 ldr r14, [r0, #56] @ (LR from gprs_ 56=4*14) 449 add r0, r0, #12 @ increment r0 to skip gprs_[0..2] 12=4*3 450 ldm r0, {r3-r13} @ load remaining gprs from argument gprs_ 451 mov r0, #0 @ clear result registers r0 and r1 452 mov r1, #0 453 bx r2 @ do long jump 454END art_quick_do_long_jump 455 456 /* 457 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on 458 * failure. 459 */ 460TWO_ARG_REF_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 461 462 /* 463 * Entry from managed code that calls artLockObjectFromCode, may block for GC. r0 holds the 464 * possibly null object to lock. 465 */ 466 .extern artLockObjectFromCode 467ENTRY art_quick_lock_object 468 cbz r0, .Lslow_lock 469.Lretry_lock: 470 ldr r2, [r9, #THREAD_ID_OFFSET] 471 ldrex r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 472 mov r3, r1 473 and r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED @ zero the read barrier bits 474 cbnz r3, .Lnot_unlocked @ already thin locked 475 @ unlocked case - r1: original lock word that's zero except for the read barrier bits. 476 orr r2, r1, r2 @ r2 holds thread id with count of 0 with preserved read barrier bits 477 strex r3, r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 478 cbnz r3, .Llock_strex_fail @ store failed, retry 479 dmb ish @ full (LoadLoad|LoadStore) memory barrier 480 bx lr 481.Lnot_unlocked: @ r1: original lock word, r2: thread_id with count of 0 and zero read barrier bits 482 lsr r3, r1, LOCK_WORD_STATE_SHIFT 483 cbnz r3, .Lslow_lock @ if either of the top two bits are set, go slow path 484 eor r2, r1, r2 @ lock_word.ThreadId() ^ self->ThreadId() 485 uxth r2, r2 @ zero top 16 bits 486 cbnz r2, .Lslow_lock @ lock word and self thread id's match -> recursive lock 487 @ else contention, go to slow path 488 mov r3, r1 @ copy the lock word to check count overflow. 489 and r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED @ zero the read barrier bits. 490 add r2, r3, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ increment count in lock word placing in r2 to check overflow 491 lsr r3, r2, LOCK_WORD_READ_BARRIER_STATE_SHIFT @ if either of the upper two bits (28-29) are set, we overflowed. 492 cbnz r3, .Lslow_lock @ if we overflow the count go slow path 493 add r2, r1, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ increment count for real 494 strex r3, r2, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits 495 cbnz r3, .Llock_strex_fail @ strex failed, retry 496 bx lr 497.Llock_strex_fail: 498 b .Lretry_lock @ retry 499.Lslow_lock: 500 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 @ save callee saves in case we block 501 mov r1, r9 @ pass Thread::Current 502 bl artLockObjectFromCode @ (Object* obj, Thread*) 503 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 504 RETURN_IF_RESULT_IS_ZERO 505 DELIVER_PENDING_EXCEPTION 506END art_quick_lock_object 507 508 /* 509 * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure. 510 * r0 holds the possibly null object to lock. 511 */ 512 .extern artUnlockObjectFromCode 513ENTRY art_quick_unlock_object 514 cbz r0, .Lslow_unlock 515.Lretry_unlock: 516#ifndef USE_READ_BARRIER 517 ldr r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 518#else 519 ldrex r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ Need to use atomic instructions for read barrier 520#endif 521 lsr r2, r1, #LOCK_WORD_STATE_SHIFT 522 cbnz r2, .Lslow_unlock @ if either of the top two bits are set, go slow path 523 ldr r2, [r9, #THREAD_ID_OFFSET] 524 mov r3, r1 @ copy lock word to check thread id equality 525 and r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED @ zero the read barrier bits 526 eor r3, r3, r2 @ lock_word.ThreadId() ^ self->ThreadId() 527 uxth r3, r3 @ zero top 16 bits 528 cbnz r3, .Lslow_unlock @ do lock word and self thread id's match? 529 mov r3, r1 @ copy lock word to detect transition to unlocked 530 and r3, #LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED @ zero the read barrier bits 531 cmp r3, #LOCK_WORD_THIN_LOCK_COUNT_ONE 532 bpl .Lrecursive_thin_unlock 533 @ transition to unlocked 534 mov r3, r1 535 and r3, #LOCK_WORD_READ_BARRIER_STATE_MASK @ r3: zero except for the preserved read barrier bits 536 dmb ish @ full (LoadStore|StoreStore) memory barrier 537#ifndef USE_READ_BARRIER 538 str r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 539#else 540 strex r2, r3, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits 541 cbnz r2, .Lunlock_strex_fail @ store failed, retry 542#endif 543 bx lr 544.Lrecursive_thin_unlock: @ r1: original lock word 545 sub r1, r1, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ decrement count 546#ifndef USE_READ_BARRIER 547 str r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 548#else 549 strex r2, r1, [r0, #MIRROR_OBJECT_LOCK_WORD_OFFSET] @ strex necessary for read barrier bits 550 cbnz r2, .Lunlock_strex_fail @ store failed, retry 551#endif 552 bx lr 553.Lunlock_strex_fail: 554 b .Lretry_unlock @ retry 555.Lslow_unlock: 556 @ save callee saves in case exception allocation triggers GC 557 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 558 mov r1, r9 @ pass Thread::Current 559 bl artUnlockObjectFromCode @ (Object* obj, Thread*) 560 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 561 RETURN_IF_RESULT_IS_ZERO 562 DELIVER_PENDING_EXCEPTION 563END art_quick_unlock_object 564 565 /* 566 * Entry from managed code that calls artIsAssignableFromCode and on failure calls 567 * artThrowClassCastException. 568 */ 569 .extern artThrowClassCastException 570ENTRY art_quick_check_cast 571 push {r0-r1, lr} @ save arguments, link register and pad 572 .cfi_adjust_cfa_offset 12 573 .cfi_rel_offset r0, 0 574 .cfi_rel_offset r1, 4 575 .cfi_rel_offset lr, 8 576 sub sp, #4 577 .cfi_adjust_cfa_offset 4 578 bl artIsAssignableFromCode 579 cbz r0, .Lthrow_class_cast_exception 580 add sp, #4 581 .cfi_adjust_cfa_offset -4 582 pop {r0-r1, pc} 583 .cfi_adjust_cfa_offset 4 @ Reset unwind info so following code unwinds. 584.Lthrow_class_cast_exception: 585 add sp, #4 586 .cfi_adjust_cfa_offset -4 587 pop {r0-r1, lr} 588 .cfi_adjust_cfa_offset -12 589 .cfi_restore r0 590 .cfi_restore r1 591 .cfi_restore lr 592 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r2, r3 // save all registers as basis for long jump context 593 mov r2, r9 @ pass Thread::Current 594 b artThrowClassCastException @ (Class*, Class*, Thread*) 595 bkpt 596END art_quick_check_cast 597 598 /* 599 * Entry from managed code for array put operations of objects where the value being stored 600 * needs to be checked for compatibility. 601 * r0 = array, r1 = index, r2 = value 602 */ 603ENTRY art_quick_aput_obj_with_null_and_bound_check 604 tst r0, r0 605 bne art_quick_aput_obj_with_bound_check 606 b art_quick_throw_null_pointer_exception 607END art_quick_aput_obj_with_null_and_bound_check 608 609 .hidden art_quick_aput_obj_with_bound_check 610ENTRY art_quick_aput_obj_with_bound_check 611 ldr r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET] 612 cmp r3, r1 613 bhi art_quick_aput_obj 614 mov r0, r1 615 mov r1, r3 616 b art_quick_throw_array_bounds 617END art_quick_aput_obj_with_bound_check 618 619 .hidden art_quick_aput_obj 620ENTRY art_quick_aput_obj 621 cbz r2, .Ldo_aput_null 622 ldr r3, [r0, #MIRROR_OBJECT_CLASS_OFFSET] 623 ldr ip, [r2, #MIRROR_OBJECT_CLASS_OFFSET] 624 ldr r3, [r3, #MIRROR_CLASS_COMPONENT_TYPE_OFFSET] 625 cmp r3, ip @ value's type == array's component type - trivial assignability 626 bne .Lcheck_assignability 627.Ldo_aput: 628 add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET 629 str r2, [r3, r1, lsl #2] 630 ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET] 631 lsr r0, r0, #7 632 strb r3, [r3, r0] 633 blx lr 634.Ldo_aput_null: 635 add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET 636 str r2, [r3, r1, lsl #2] 637 blx lr 638.Lcheck_assignability: 639 push {r0-r2, lr} @ save arguments 640 .cfi_adjust_cfa_offset 16 641 .cfi_rel_offset r0, 0 642 .cfi_rel_offset r1, 4 643 .cfi_rel_offset r2, 8 644 .cfi_rel_offset lr, 12 645 mov r1, ip 646 mov r0, r3 647 bl artIsAssignableFromCode 648 cbz r0, .Lthrow_array_store_exception 649 pop {r0-r2, lr} 650 .cfi_restore r0 651 .cfi_restore r1 652 .cfi_restore r2 653 .cfi_restore lr 654 .cfi_adjust_cfa_offset -16 655 add r3, r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET 656 str r2, [r3, r1, lsl #2] 657 ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET] 658 lsr r0, r0, #7 659 strb r3, [r3, r0] 660 blx lr 661.Lthrow_array_store_exception: 662 pop {r0-r2, lr} 663 /* No need to repeat restore cfi directives, the ones above apply here. */ 664 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r3, ip 665 mov r1, r2 666 mov r2, r9 @ pass Thread::Current 667 b artThrowArrayStoreException @ (Class*, Class*, Thread*) 668 bkpt @ unreached 669END art_quick_aput_obj 670 671// Macro to facilitate adding new allocation entrypoints. 672.macro ONE_ARG_DOWNCALL name, entrypoint, return 673 .extern \entrypoint 674ENTRY \name 675 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 @ save callee saves in case of GC 676 mov r1, r9 @ pass Thread::Current 677 bl \entrypoint @ (uint32_t type_idx, Method* method, Thread*) 678 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 679 \return 680END \name 681.endm 682 683// Macro to facilitate adding new allocation entrypoints. 684.macro TWO_ARG_DOWNCALL name, entrypoint, return 685 .extern \entrypoint 686ENTRY \name 687 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3 @ save callee saves in case of GC 688 mov r2, r9 @ pass Thread::Current 689 bl \entrypoint @ (uint32_t type_idx, Method* method, Thread*) 690 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 691 \return 692END \name 693.endm 694 695// Macro to facilitate adding new array allocation entrypoints. 696.macro THREE_ARG_DOWNCALL name, entrypoint, return 697 .extern \entrypoint 698ENTRY \name 699 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r3, r12 @ save callee saves in case of GC 700 mov r3, r9 @ pass Thread::Current 701 @ (uint32_t type_idx, Method* method, int32_t component_count, Thread*) 702 bl \entrypoint 703 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 704 \return 705END \name 706.endm 707 708// Macro to facilitate adding new allocation entrypoints. 709.macro FOUR_ARG_DOWNCALL name, entrypoint, return 710 .extern \entrypoint 711ENTRY \name 712 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r3, r12 @ save callee saves in case of GC 713 str r9, [sp, #-16]! @ expand the frame and pass Thread::Current 714 .pad #16 715 .cfi_adjust_cfa_offset 16 716 bl \entrypoint 717 add sp, #16 @ strip the extra frame 718 .cfi_adjust_cfa_offset -16 719 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 720 \return 721END \name 722.endm 723 724ONE_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER 725ONE_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER 726ONE_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER 727 728 /* 729 * Called by managed code to resolve a static field and load a non-wide value. 730 */ 731ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 732ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 733ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 734ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 735ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 736ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 737 /* 738 * Called by managed code to resolve a static field and load a 64-bit primitive value. 739 */ 740 .extern artGet64StaticFromCode 741ENTRY art_quick_get64_static 742 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3 @ save callee saves in case of GC 743 ldr r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] @ pass referrer 744 mov r2, r9 @ pass Thread::Current 745 bl artGet64StaticFromCode @ (uint32_t field_idx, const Method* referrer, Thread*) 746 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 747 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 748 cbnz r2, 1f @ success if no exception pending 749 bx lr @ return on success 7501: 751 DELIVER_PENDING_EXCEPTION 752END art_quick_get64_static 753 754 /* 755 * Called by managed code to resolve an instance field and load a non-wide value. 756 */ 757TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 758TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 759TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 760TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 761TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 762TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_R1 763 /* 764 * Called by managed code to resolve an instance field and load a 64-bit primitive value. 765 */ 766 .extern artGet64InstanceFromCode 767ENTRY art_quick_get64_instance 768 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3 @ save callee saves in case of GC 769 ldr r2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] @ pass referrer 770 mov r3, r9 @ pass Thread::Current 771 bl artGet64InstanceFromCode @ (field_idx, Object*, referrer, Thread*) 772 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 773 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 774 cbnz r2, 1f @ success if no exception pending 775 bx lr @ return on success 7761: 777 DELIVER_PENDING_EXCEPTION 778END art_quick_get64_instance 779 780 /* 781 * Called by managed code to resolve a static field and store a non-wide value. 782 */ 783TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 784TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 785TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 786TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 787 /* 788 * Called by managed code to resolve a static field and store a 64-bit primitive value. 789 * On entry r0 holds field index, r1:r2 hold new_val 790 */ 791 .extern artSet64StaticFromCode 792ENTRY art_quick_set64_static 793 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r3, r12 @ save callee saves in case of GC 794 mov r3, r2 @ pass one half of wide argument 795 mov r2, r1 @ pass other half of wide argument 796 ldr r1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] @ pass referrer 797 str r9, [sp, #-16]! @ expand the frame and pass Thread::Current 798 .cfi_adjust_cfa_offset 16 799 bl artSet64StaticFromCode @ (field_idx, referrer, new_val, Thread*) 800 add sp, #16 @ release out args 801 .cfi_adjust_cfa_offset -16 802 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here 803 RETURN_IF_RESULT_IS_ZERO 804 DELIVER_PENDING_EXCEPTION 805END art_quick_set64_static 806 807 /* 808 * Called by managed code to resolve an instance field and store a non-wide value. 809 */ 810THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 811THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 812THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 813THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_RESULT_IS_ZERO_OR_DELIVER 814 /* 815 * Called by managed code to resolve an instance field and store a 64-bit primitive value. 816 */ 817 .extern artSet64InstanceFromCode 818ENTRY art_quick_set64_instance 819 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r12, lr @ save callee saves in case of GC 820 ldr r12, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] @ pass referrer 821 str r9, [sp, #-12]! @ expand the frame and pass Thread::Current 822 .cfi_adjust_cfa_offset 12 823 str r12, [sp, #-4]! @ expand the frame and pass the referrer 824 .cfi_adjust_cfa_offset 4 825 bl artSet64InstanceFromCode @ (field_idx, Object*, new_val, Method* referrer, Thread*) 826 add sp, #16 @ release out args 827 .cfi_adjust_cfa_offset -16 828 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME @ TODO: we can clearly save an add here 829 RETURN_IF_RESULT_IS_ZERO 830 DELIVER_PENDING_EXCEPTION 831END art_quick_set64_instance 832 833 /* 834 * Entry from managed code to resolve a string, this stub will allocate a String and deliver an 835 * exception on error. On success the String is returned. R0 holds the string index. The fast 836 * path check for hit in strings cache has already been performed. 837 */ 838ONE_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER 839 840// Generate the allocation entrypoints for each allocator. 841GENERATE_ALL_ALLOC_ENTRYPOINTS 842 843 /* 844 * Called by managed code when the value in rSUSPEND has been decremented to 0. 845 */ 846 .extern artTestSuspendFromCode 847ENTRY art_quick_test_suspend 848#ifdef ARM_R4_SUSPEND_FLAG 849 ldrh r0, [rSELF, #THREAD_FLAGS_OFFSET] 850 mov rSUSPEND, #SUSPEND_CHECK_INTERVAL @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL 851 cbnz r0, 1f @ check Thread::Current()->suspend_count_ == 0 852 bx lr @ return if suspend_count_ == 0 8531: 854#endif 855 mov r0, rSELF 856 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 @ save callee saves for GC stack crawl 857 @ TODO: save FPRs to enable access in the debugger? 858 bl artTestSuspendFromCode @ (Thread*) 859 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 860END art_quick_test_suspend 861 862ENTRY art_quick_implicit_suspend 863 mov r0, rSELF 864 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r1, r2 @ save callee saves for stack crawl 865 bl artTestSuspendFromCode @ (Thread*) 866 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 867END art_quick_implicit_suspend 868 869 /* 870 * Called by managed code that is attempting to call a method on a proxy class. On entry 871 * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The 872 * frame size of the invoked proxy method agrees with a ref and args callee save frame. 873 */ 874 .extern artQuickProxyInvokeHandler 875ENTRY art_quick_proxy_invoke_handler 876 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0 877 mov r2, r9 @ pass Thread::Current 878 mov r3, sp @ pass SP 879 blx artQuickProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP) 880 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 881 // Tear down the callee-save frame. Skip arg registers. 882 add sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE) 883 .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE) 884 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 885 cbnz r2, 1f @ success if no exception is pending 886 vmov d0, r0, r1 @ store into fpr, for when it's a fpr return... 887 bx lr @ return on success 8881: 889 DELIVER_PENDING_EXCEPTION 890END art_quick_proxy_invoke_handler 891 892 /* 893 * Called to resolve an imt conflict. r12 is a hidden argument that holds the target method's 894 * dex method index. 895 */ 896ENTRY art_quick_imt_conflict_trampoline 897 ldr r0, [sp, #0] @ load caller Method* 898 ldr r0, [r0, #ART_METHOD_DEX_CACHE_METHODS_OFFSET] @ load dex_cache_resolved_methods 899 add r0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET @ get starting address of data 900 ldr r0, [r0, r12, lsl 2] @ load the target method 901 b art_quick_invoke_interface_trampoline 902END art_quick_imt_conflict_trampoline 903 904 .extern artQuickResolutionTrampoline 905ENTRY art_quick_resolution_trampoline 906 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3 907 mov r2, r9 @ pass Thread::Current 908 mov r3, sp @ pass SP 909 blx artQuickResolutionTrampoline @ (Method* called, receiver, Thread*, SP) 910 cbz r0, 1f @ is code pointer null? goto exception 911 mov r12, r0 912 ldr r0, [sp, #0] @ load resolved method in r0 913 RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME 914 bx r12 @ tail-call into actual code 9151: 916 RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME 917 DELIVER_PENDING_EXCEPTION 918END art_quick_resolution_trampoline 919 920 /* 921 * Called to do a generic JNI down-call 922 */ 923ENTRY art_quick_generic_jni_trampoline 924 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0 925 926 // Save rSELF 927 mov r11, rSELF 928 // Save SP , so we can have static CFI info. r10 is saved in ref_and_args. 929 mov r10, sp 930 .cfi_def_cfa_register r10 931 932 sub sp, sp, #5120 933 934 // prepare for artQuickGenericJniTrampoline call 935 // (Thread*, SP) 936 // r0 r1 <= C calling convention 937 // rSELF r10 <= where they are 938 939 mov r0, rSELF // Thread* 940 mov r1, r10 941 blx artQuickGenericJniTrampoline // (Thread*, sp) 942 943 // The C call will have registered the complete save-frame on success. 944 // The result of the call is: 945 // r0: pointer to native code, 0 on error. 946 // r1: pointer to the bottom of the used area of the alloca, can restore stack till there. 947 948 // Check for error = 0. 949 cbz r0, .Lexception_in_native 950 951 // Release part of the alloca. 952 mov sp, r1 953 954 // Save the code pointer 955 mov r12, r0 956 957 // Load parameters from frame into registers. 958 pop {r0-r3} 959 960 // Softfloat. 961 // TODO: Change to hardfloat when supported. 962 963 blx r12 // native call. 964 965 // result sign extension is handled in C code 966 // prepare for artQuickGenericJniEndTrampoline call 967 // (Thread*, result, result_f) 968 // r0 r2,r3 stack <= C calling convention 969 // r11 r0,r1 r0,r1 <= where they are 970 sub sp, sp, #8 // Stack alignment. 971 972 push {r0-r1} 973 mov r3, r1 974 mov r2, r0 975 mov r0, r11 976 977 blx artQuickGenericJniEndTrampoline 978 979 // Restore self pointer. 980 mov r9, r11 981 982 // Pending exceptions possible. 983 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 984 cbnz r2, .Lexception_in_native 985 986 // Tear down the alloca. 987 mov sp, r10 988 .cfi_def_cfa_register sp 989 990 // Tear down the callee-save frame. Skip arg registers. 991 add sp, #FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 992 .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE) 993 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 994 995 // store into fpr, for when it's a fpr return... 996 vmov d0, r0, r1 997 bx lr // ret 998 // Undo the unwinding information from above since it doesn't apply below. 999 .cfi_def_cfa_register r10 1000 .cfi_adjust_cfa_offset FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE-FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 1001 1002.Lexception_in_native: 1003 ldr sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET] 1004 .cfi_def_cfa_register sp 1005 # This will create a new save-all frame, required by the runtime. 1006 DELIVER_PENDING_EXCEPTION 1007END art_quick_generic_jni_trampoline 1008 1009 .extern artQuickToInterpreterBridge 1010ENTRY art_quick_to_interpreter_bridge 1011 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r1, r2 1012 mov r1, r9 @ pass Thread::Current 1013 mov r2, sp @ pass SP 1014 blx artQuickToInterpreterBridge @ (Method* method, Thread*, SP) 1015 ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_ 1016 // Tear down the callee-save frame. Skip arg registers. 1017 add sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE) 1018 .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE) 1019 RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME 1020 cbnz r2, 1f @ success if no exception is pending 1021 vmov d0, r0, r1 @ store into fpr, for when it's a fpr return... 1022 bx lr @ return on success 10231: 1024 DELIVER_PENDING_EXCEPTION 1025END art_quick_to_interpreter_bridge 1026 1027 /* 1028 * Routine that intercepts method calls and returns. 1029 */ 1030 .extern artInstrumentationMethodEntryFromCode 1031 .extern artInstrumentationMethodExitFromCode 1032ENTRY art_quick_instrumentation_entry 1033 @ Make stack crawlable and clobber r2 and r3 (post saving) 1034 SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME r2, r3 1035 @ preserve r0 (not normally an arg) knowing there is a spare slot in kRefsAndArgs. 1036 str r0, [sp, #4] 1037 mov r2, r9 @ pass Thread::Current 1038 mov r3, lr @ pass LR 1039 blx artInstrumentationMethodEntryFromCode @ (Method*, Object*, Thread*, LR) 1040 mov r12, r0 @ r12 holds reference to code 1041 ldr r0, [sp, #4] @ restore r0 1042 RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME 1043 blx r12 @ call method with lr set to art_quick_instrumentation_exit 1044@ Deliberate fall-through into art_quick_instrumentation_exit. 1045 .type art_quick_instrumentation_exit, #function 1046 .global art_quick_instrumentation_exit 1047art_quick_instrumentation_exit: 1048 mov lr, #0 @ link register is to here, so clobber with 0 for later checks 1049 SETUP_REFS_ONLY_CALLEE_SAVE_FRAME r2, r3 @ set up frame knowing r2 and r3 must be dead on exit 1050 mov r12, sp @ remember bottom of caller's frame 1051 push {r0-r1} @ save return value 1052 .cfi_adjust_cfa_offset 8 1053 .cfi_rel_offset r0, 0 1054 .cfi_rel_offset r1, 4 1055 vpush {d0} @ save fp return value 1056 .cfi_adjust_cfa_offset 8 1057 sub sp, #8 @ space for return value argument. Note: AAPCS stack alignment is 8B, no 1058 @ need to align by 16. 1059 .cfi_adjust_cfa_offset 8 1060 vstr d0, [sp] @ d0 -> [sp] for fpr_res 1061 mov r2, r0 @ pass return value as gpr_res 1062 mov r3, r1 1063 mov r0, r9 @ pass Thread::Current 1064 mov r1, r12 @ pass SP 1065 blx artInstrumentationMethodExitFromCode @ (Thread*, SP, gpr_res, fpr_res) 1066 add sp, #8 1067 .cfi_adjust_cfa_offset -8 1068 1069 mov r2, r0 @ link register saved by instrumentation 1070 mov lr, r1 @ r1 is holding link register if we're to bounce to deoptimize 1071 vpop {d0} @ restore fp return value 1072 .cfi_adjust_cfa_offset -8 1073 pop {r0, r1} @ restore return value 1074 .cfi_adjust_cfa_offset -8 1075 .cfi_restore r0 1076 .cfi_restore r1 1077 add sp, #32 @ remove callee save frame 1078 .cfi_adjust_cfa_offset -32 1079 bx r2 @ return 1080END art_quick_instrumentation_entry 1081 1082 /* 1083 * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization 1084 * will long jump to the upcall with a special exception of -1. 1085 */ 1086 .extern artDeoptimize 1087ENTRY art_quick_deoptimize 1088 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME r0, r1 1089 mov r0, r9 @ Set up args. 1090 blx artDeoptimize @ artDeoptimize(Thread*) 1091END art_quick_deoptimize 1092 1093 /* 1094 * Signed 64-bit integer multiply. 1095 * 1096 * Consider WXxYZ (r1r0 x r3r2) with a long multiply: 1097 * WX 1098 * x YZ 1099 * -------- 1100 * ZW ZX 1101 * YW YX 1102 * 1103 * The low word of the result holds ZX, the high word holds 1104 * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because 1105 * it doesn't fit in the low 64 bits. 1106 * 1107 * Unlike most ARM math operations, multiply instructions have 1108 * restrictions on using the same register more than once (Rd and Rm 1109 * cannot be the same). 1110 */ 1111 /* mul-long vAA, vBB, vCC */ 1112ENTRY art_quick_mul_long 1113 push {r9 - r10} 1114 .cfi_adjust_cfa_offset 8 1115 .cfi_rel_offset r9, 0 1116 .cfi_rel_offset r10, 4 1117 mul ip, r2, r1 @ ip<- ZxW 1118 umull r9, r10, r2, r0 @ r9/r10 <- ZxX 1119 mla r2, r0, r3, ip @ r2<- YxX + (ZxW) 1120 add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX)) 1121 mov r0,r9 1122 mov r1,r10 1123 pop {r9 - r10} 1124 .cfi_adjust_cfa_offset -8 1125 .cfi_restore r9 1126 .cfi_restore r10 1127 bx lr 1128END art_quick_mul_long 1129 1130 /* 1131 * Long integer shift. This is different from the generic 32/64-bit 1132 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1133 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1134 * 6 bits. 1135 * On entry: 1136 * r0: low word 1137 * r1: high word 1138 * r2: shift count 1139 */ 1140 /* shl-long vAA, vBB, vCC */ 1141ARM_ENTRY art_quick_shl_long @ ARM code as thumb code requires spills 1142 and r2, r2, #63 @ r2<- r2 & 0x3f 1143 mov r1, r1, asl r2 @ r1<- r1 << r2 1144 rsb r3, r2, #32 @ r3<- 32 - r2 1145 orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2)) 1146 subs ip, r2, #32 @ ip<- r2 - 32 1147 movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32) 1148 mov r0, r0, asl r2 @ r0<- r0 << r2 1149 bx lr 1150END art_quick_shl_long 1151 1152 /* 1153 * Long integer shift. This is different from the generic 32/64-bit 1154 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1155 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1156 * 6 bits. 1157 * On entry: 1158 * r0: low word 1159 * r1: high word 1160 * r2: shift count 1161 */ 1162 /* shr-long vAA, vBB, vCC */ 1163ARM_ENTRY art_quick_shr_long @ ARM code as thumb code requires spills 1164 and r2, r2, #63 @ r0<- r0 & 0x3f 1165 mov r0, r0, lsr r2 @ r0<- r2 >> r2 1166 rsb r3, r2, #32 @ r3<- 32 - r2 1167 orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2)) 1168 subs ip, r2, #32 @ ip<- r2 - 32 1169 movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32) 1170 mov r1, r1, asr r2 @ r1<- r1 >> r2 1171 bx lr 1172END art_quick_shr_long 1173 1174 /* 1175 * Long integer shift. This is different from the generic 32/64-bit 1176 * binary operations because vAA/vBB are 64-bit but vCC (the shift 1177 * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low 1178 * 6 bits. 1179 * On entry: 1180 * r0: low word 1181 * r1: high word 1182 * r2: shift count 1183 */ 1184 /* ushr-long vAA, vBB, vCC */ 1185ARM_ENTRY art_quick_ushr_long @ ARM code as thumb code requires spills 1186 and r2, r2, #63 @ r0<- r0 & 0x3f 1187 mov r0, r0, lsr r2 @ r0<- r2 >> r2 1188 rsb r3, r2, #32 @ r3<- 32 - r2 1189 orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2)) 1190 subs ip, r2, #32 @ ip<- r2 - 32 1191 movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32) 1192 mov r1, r1, lsr r2 @ r1<- r1 >>> r2 1193 bx lr 1194END art_quick_ushr_long 1195 1196 /* 1197 * String's indexOf. 1198 * 1199 * On entry: 1200 * r0: string object (known non-null) 1201 * r1: char to match (known <= 0xFFFF) 1202 * r2: Starting offset in string data 1203 */ 1204ENTRY art_quick_indexof 1205 push {r4, r10-r11, lr} @ 4 words of callee saves 1206 .cfi_adjust_cfa_offset 16 1207 .cfi_rel_offset r4, 0 1208 .cfi_rel_offset r10, 4 1209 .cfi_rel_offset r11, 8 1210 .cfi_rel_offset lr, 12 1211 ldr r3, [r0, #MIRROR_STRING_COUNT_OFFSET] 1212 add r0, #MIRROR_STRING_VALUE_OFFSET 1213 1214 /* Clamp start to [0..count] */ 1215 cmp r2, #0 1216 it lt 1217 movlt r2, #0 1218 cmp r2, r3 1219 it gt 1220 movgt r2, r3 1221 1222 /* Save a copy in r12 to later compute result */ 1223 mov r12, r0 1224 1225 /* Build pointer to start of data to compare and pre-bias */ 1226 add r0, r0, r2, lsl #1 1227 sub r0, #2 1228 1229 /* Compute iteration count */ 1230 sub r2, r3, r2 1231 1232 /* 1233 * At this point we have: 1234 * r0: start of data to test 1235 * r1: char to compare 1236 * r2: iteration count 1237 * r12: original start of string data 1238 * r3, r4, r10, r11 available for loading string data 1239 */ 1240 1241 subs r2, #4 1242 blt .Lindexof_remainder 1243 1244.Lindexof_loop4: 1245 ldrh r3, [r0, #2]! 1246 ldrh r4, [r0, #2]! 1247 ldrh r10, [r0, #2]! 1248 ldrh r11, [r0, #2]! 1249 cmp r3, r1 1250 beq .Lmatch_0 1251 cmp r4, r1 1252 beq .Lmatch_1 1253 cmp r10, r1 1254 beq .Lmatch_2 1255 cmp r11, r1 1256 beq .Lmatch_3 1257 subs r2, #4 1258 bge .Lindexof_loop4 1259 1260.Lindexof_remainder: 1261 adds r2, #4 1262 beq .Lindexof_nomatch 1263 1264.Lindexof_loop1: 1265 ldrh r3, [r0, #2]! 1266 cmp r3, r1 1267 beq .Lmatch_3 1268 subs r2, #1 1269 bne .Lindexof_loop1 1270 1271.Lindexof_nomatch: 1272 mov r0, #-1 1273 pop {r4, r10-r11, pc} 1274 1275.Lmatch_0: 1276 sub r0, #6 1277 sub r0, r12 1278 asr r0, r0, #1 1279 pop {r4, r10-r11, pc} 1280.Lmatch_1: 1281 sub r0, #4 1282 sub r0, r12 1283 asr r0, r0, #1 1284 pop {r4, r10-r11, pc} 1285.Lmatch_2: 1286 sub r0, #2 1287 sub r0, r12 1288 asr r0, r0, #1 1289 pop {r4, r10-r11, pc} 1290.Lmatch_3: 1291 sub r0, r12 1292 asr r0, r0, #1 1293 pop {r4, r10-r11, pc} 1294END art_quick_indexof 1295 1296 /* 1297 * String's compareTo. 1298 * 1299 * Requires rARG0/rARG1 to have been previously checked for null. Will 1300 * return negative if this's string is < comp, 0 if they are the 1301 * same and positive if >. 1302 * 1303 * On entry: 1304 * r0: this object pointer 1305 * r1: comp object pointer 1306 * 1307 */ 1308 .extern __memcmp16 1309ENTRY art_quick_string_compareto 1310 mov r2, r0 @ this to r2, opening up r0 for return value 1311 sub r0, r2, r1 @ Same? 1312 cbnz r0,1f 1313 bx lr 13141: @ Same strings, return. 1315 1316 push {r4, r7-r12, lr} @ 8 words - keep alignment 1317 .cfi_adjust_cfa_offset 32 1318 .cfi_rel_offset r4, 0 1319 .cfi_rel_offset r7, 4 1320 .cfi_rel_offset r8, 8 1321 .cfi_rel_offset r9, 12 1322 .cfi_rel_offset r10, 16 1323 .cfi_rel_offset r11, 20 1324 .cfi_rel_offset r12, 24 1325 .cfi_rel_offset lr, 28 1326 1327 ldr r7, [r2, #MIRROR_STRING_COUNT_OFFSET] 1328 ldr r10, [r1, #MIRROR_STRING_COUNT_OFFSET] 1329 add r2, #MIRROR_STRING_VALUE_OFFSET 1330 add r1, #MIRROR_STRING_VALUE_OFFSET 1331 1332 /* 1333 * At this point, we have: 1334 * value: r2/r1 1335 * offset: r4/r9 1336 * count: r7/r10 1337 * We're going to compute 1338 * r11 <- countDiff 1339 * r10 <- minCount 1340 */ 1341 subs r11, r7, r10 1342 it ls 1343 movls r10, r7 1344 1345 /* 1346 * Note: data pointers point to previous element so we can use pre-index 1347 * mode with base writeback. 1348 */ 1349 subs r2, #2 @ offset to contents[-1] 1350 subs r1, #2 @ offset to contents[-1] 1351 1352 /* 1353 * At this point we have: 1354 * r2: *this string data 1355 * r1: *comp string data 1356 * r10: iteration count for comparison 1357 * r11: value to return if the first part of the string is equal 1358 * r0: reserved for result 1359 * r3, r4, r7, r8, r9, r12 available for loading string data 1360 */ 1361 1362 subs r10, #2 1363 blt .Ldo_remainder2 1364 1365 /* 1366 * Unroll the first two checks so we can quickly catch early mismatch 1367 * on long strings (but preserve incoming alignment) 1368 */ 1369 1370 ldrh r3, [r2, #2]! 1371 ldrh r4, [r1, #2]! 1372 ldrh r7, [r2, #2]! 1373 ldrh r8, [r1, #2]! 1374 subs r0, r3, r4 1375 it eq 1376 subseq r0, r7, r8 1377 bne .Ldone 1378 cmp r10, #28 1379 bgt .Ldo_memcmp16 1380 subs r10, #3 1381 blt .Ldo_remainder 1382 1383.Lloopback_triple: 1384 ldrh r3, [r2, #2]! 1385 ldrh r4, [r1, #2]! 1386 ldrh r7, [r2, #2]! 1387 ldrh r8, [r1, #2]! 1388 ldrh r9, [r2, #2]! 1389 ldrh r12,[r1, #2]! 1390 subs r0, r3, r4 1391 it eq 1392 subseq r0, r7, r8 1393 it eq 1394 subseq r0, r9, r12 1395 bne .Ldone 1396 subs r10, #3 1397 bge .Lloopback_triple 1398 1399.Ldo_remainder: 1400 adds r10, #3 1401 beq .Lreturn_diff 1402 1403.Lloopback_single: 1404 ldrh r3, [r2, #2]! 1405 ldrh r4, [r1, #2]! 1406 subs r0, r3, r4 1407 bne .Ldone 1408 subs r10, #1 1409 bne .Lloopback_single 1410 1411.Lreturn_diff: 1412 mov r0, r11 1413 pop {r4, r7-r12, pc} 1414 1415.Ldo_remainder2: 1416 adds r10, #2 1417 bne .Lloopback_single 1418 mov r0, r11 1419 pop {r4, r7-r12, pc} 1420 1421 /* Long string case */ 1422.Ldo_memcmp16: 1423 mov r7, r11 1424 add r0, r2, #2 1425 add r1, r1, #2 1426 mov r2, r10 1427 bl __memcmp16 1428 cmp r0, #0 1429 it eq 1430 moveq r0, r7 1431.Ldone: 1432 pop {r4, r7-r12, pc} 1433END art_quick_string_compareto 1434 1435 /* Assembly routines used to handle ABI differences. */ 1436 1437 /* double fmod(double a, double b) */ 1438 .extern fmod 1439ENTRY art_quick_fmod 1440 push {lr} 1441 .cfi_adjust_cfa_offset 4 1442 .cfi_rel_offset lr, 0 1443 sub sp, #4 1444 .cfi_adjust_cfa_offset 4 1445 vmov r0, r1, d0 1446 vmov r2, r3, d1 1447 bl fmod 1448 vmov d0, r0, r1 1449 add sp, #4 1450 .cfi_adjust_cfa_offset -4 1451 pop {pc} 1452END art_quick_fmod 1453 1454 /* float fmodf(float a, float b) */ 1455 .extern fmodf 1456ENTRY art_quick_fmodf 1457 push {lr} 1458 .cfi_adjust_cfa_offset 4 1459 .cfi_rel_offset lr, 0 1460 sub sp, #4 1461 .cfi_adjust_cfa_offset 4 1462 vmov r0, r1, d0 1463 bl fmodf 1464 vmov s0, r0 1465 add sp, #4 1466 .cfi_adjust_cfa_offset -4 1467 pop {pc} 1468END art_quick_fmod 1469 1470 /* int64_t art_d2l(double d) */ 1471 .extern art_d2l 1472ENTRY art_quick_d2l 1473 vmov r0, r1, d0 1474 b art_d2l 1475END art_quick_d2l 1476 1477 /* int64_t art_f2l(float f) */ 1478 .extern art_f2l 1479ENTRY art_quick_f2l 1480 vmov r0, s0 1481 b art_f2l 1482END art_quick_f2l 1483