quick_entrypoints_arm64.S revision 6e4e59c674f4d58421512dbcfc57a99e27b6b5c8
1/* 2 * Copyright (C) 2014 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_arm64.S" 18 19#include "arch/quick_alloc_entrypoints.S" 20 21 22 /* 23 * Macro that sets up the callee save frame to conform with 24 * Runtime::CreateCalleeSaveMethod(kSaveAll) 25 */ 26.macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 27 adrp x9, :got:_ZN3art7Runtime9instance_E 28 ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E] 29 30 // Our registers aren't intermixed - just spill in order. 31 ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) . 32 33 // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] . 34 ldr x9, [x9, RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET ] 35 36 sub sp, sp, #368 37 .cfi_adjust_cfa_offset 368 38 39 // Ugly compile-time check, but we only have the preprocessor. 40#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 368) 41#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM64) size not as expected." 42#endif 43 44 // FP args 45 stp d1, d2, [sp, #8] 46 stp d2, d3, [sp, #24] 47 stp d4, d5, [sp, #40] 48 stp d6, d7, [sp, #56] 49 50 // FP callee-saves 51 stp d8, d9, [sp, #72] 52 stp d10, d11, [sp, #88] 53 stp d12, d13, [sp, #104] 54 stp d14, d15, [sp, #120] 55 56 stp d16, d17, [sp, #136] 57 stp d18, d19, [sp, #152] 58 stp d20, d21, [sp, #168] 59 stp d22, d23, [sp, #184] 60 stp d24, d25, [sp, #200] 61 stp d26, d27, [sp, #216] 62 stp d28, d29, [sp, #232] 63 stp d30, d31, [sp, #248] 64 65 66 // Callee saved. 67 stp xSELF, x19, [sp, #264] 68 .cfi_rel_offset x18, 264 69 .cfi_rel_offset x19, 272 70 71 stp x20, x21, [sp, #280] 72 .cfi_rel_offset x20, 280 73 .cfi_rel_offset x21, 288 74 75 stp x22, x23, [sp, #296] 76 .cfi_rel_offset x22, 296 77 .cfi_rel_offset x23, 304 78 79 stp x24, x25, [sp, #312] 80 .cfi_rel_offset x24, 312 81 .cfi_rel_offset x25, 320 82 83 stp x26, x27, [sp, #328] 84 .cfi_rel_offset x26, 328 85 .cfi_rel_offset x27, 336 86 87 stp x28, xFP, [sp, #344] // Save FP. 88 .cfi_rel_offset x28, 344 89 .cfi_rel_offset x29, 352 90 91 str xLR, [sp, #360] 92 .cfi_rel_offset x30, 360 93 94 // Loads appropriate callee-save-method 95 str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs] 96 97.endm 98 99 /* 100 * Macro that sets up the callee save frame to conform with 101 * Runtime::CreateCalleeSaveMethod(kRefsOnly). 102 */ 103// WIP. 104.macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME 105 adrp x9, :got:_ZN3art7Runtime9instance_E 106 ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E] 107 108 // Our registers aren't intermixed - just spill in order. 109 ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) . 110 111 // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] . 112 ldr x9, [x9, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET ] 113 114 sub sp, sp, #176 115 .cfi_adjust_cfa_offset 176 116 117 // Ugly compile-time check, but we only have the preprocessor. 118#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 176) 119#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM64) size not as expected." 120#endif 121 122 // FP callee-saves 123 stp d8, d9, [sp, #8] 124 stp d10, d11, [sp, #24] 125 stp d12, d13, [sp, #40] 126 stp d14, d15, [sp, #56] 127 128 // Callee saved. 129 stp xSELF, x19, [sp, #72] 130 .cfi_rel_offset x18, 72 131 .cfi_rel_offset x19, 80 132 133 stp x20, x21, [sp, #88] 134 .cfi_rel_offset x20, 88 135 .cfi_rel_offset x21, 96 136 137 stp x22, x23, [sp, #104] 138 .cfi_rel_offset x22, 104 139 .cfi_rel_offset x23, 112 140 141 stp x24, x25, [sp, #120] 142 .cfi_rel_offset x24, 120 143 .cfi_rel_offset x25, 128 144 145 stp x26, x27, [sp, #136] 146 .cfi_rel_offset x26, 136 147 .cfi_rel_offset x27, 144 148 149 stp x28, xFP, [sp, #152] // Save FP. 150 .cfi_rel_offset x28, 152 151 .cfi_rel_offset x29, 160 152 153 str xLR, [sp, #168] 154 .cfi_rel_offset x30, 168 155 156 // Loads appropriate callee-save-method 157 str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs] 158.endm 159 160.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 161 // FP callee saves 162 ldp d8, d9, [sp, #8] 163 ldp d10, d11, [sp, #24] 164 ldp d12, d13, [sp, #40] 165 ldp d14, d15, [sp, #56] 166 167 // Callee saved. 168 ldp xSELF, x19, [sp, #72] 169 .cfi_restore x18 170 .cfi_restore x19 171 172 ldp x20, x21, [sp, #88] 173 .cfi_restore x20 174 .cfi_restore x21 175 176 ldp x22, x23, [sp, #104] 177 .cfi_restore x22 178 .cfi_restore x23 179 180 ldp x24, x25, [sp, #120] 181 .cfi_restore x24 182 .cfi_restore x25 183 184 ldp x26, x27, [sp, #136] 185 .cfi_restore x26 186 .cfi_restore x27 187 188 ldp x28, xFP, [sp, #152] // Save FP. 189 .cfi_restore x28 190 .cfi_restore x29 191 192 ldr xLR, [sp, #168] 193 .cfi_restore x30 194 195 add sp, sp, #176 196 .cfi_adjust_cfa_offset -176 197.endm 198 199.macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN 200 brk 0 201.endm 202 203 204.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL 205 sub sp, sp, #304 206 .cfi_adjust_cfa_offset 304 207 208 // Ugly compile-time check, but we only have the preprocessor. 209#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 304) 210#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM64) size not as expected." 211#endif 212 213 stp d0, d1, [sp, #16] 214 stp d2, d3, [sp, #32] 215 stp d4, d5, [sp, #48] 216 stp d6, d7, [sp, #64] 217 stp d8, d9, [sp, #80] 218 stp d10, d11, [sp, #96] 219 stp d12, d13, [sp, #112] 220 stp d14, d15, [sp, #128] 221 222 stp x1, x2, [sp, #144] 223 .cfi_rel_offset x1, 144 224 .cfi_rel_offset x2, 152 225 226 stp x3, x4, [sp, #160] 227 .cfi_rel_offset x3, 160 228 .cfi_rel_offset x4, 168 229 230 stp x5, x6, [sp, #176] 231 .cfi_rel_offset x5, 176 232 .cfi_rel_offset x6, 184 233 234 stp x7, xSELF, [sp, #192] 235 .cfi_rel_offset x7, 192 236 .cfi_rel_offset x18, 200 237 238 stp x19, x20, [sp, #208] 239 .cfi_rel_offset x19, 208 240 .cfi_rel_offset x20, 216 241 242 stp x21, x22, [sp, #224] 243 .cfi_rel_offset x21, 224 244 .cfi_rel_offset x22, 232 245 246 stp x23, x24, [sp, #240] 247 .cfi_rel_offset x23, 240 248 .cfi_rel_offset x24, 248 249 250 stp x25, x26, [sp, #256] 251 .cfi_rel_offset x25, 256 252 .cfi_rel_offset x26, 264 253 254 stp x27, x28, [sp, #272] 255 .cfi_rel_offset x27, 272 256 .cfi_rel_offset x28, 280 257 258 stp xFP, xLR, [sp, #288] 259 .cfi_rel_offset x29, 288 260 .cfi_rel_offset x30, 296 261.endm 262 263 /* 264 * Macro that sets up the callee save frame to conform with 265 * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). 266 * 267 * TODO This is probably too conservative - saving FP & LR. 268 */ 269.macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 270 adrp x9, :got:_ZN3art7Runtime9instance_E 271 ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E] 272 273 // Our registers aren't intermixed - just spill in order. 274 ldr x9,[x9] // x9 = & (art::Runtime * art::Runtime.instance_) . 275 276 // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs] . 277 ldr x9, [x9, RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET ] 278 279 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL 280 281 str x9, [sp] // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs] 282.endm 283 284.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 285 286 ldp d0, d1, [sp, #16] 287 ldp d2, d3, [sp, #32] 288 ldp d4, d5, [sp, #48] 289 ldp d6, d7, [sp, #64] 290 ldp d8, d9, [sp, #80] 291 ldp d10, d11, [sp, #96] 292 ldp d12, d13, [sp, #112] 293 ldp d14, d15, [sp, #128] 294 295 // args. 296 ldp x1, x2, [sp, #144] 297 .cfi_restore x1 298 .cfi_restore x2 299 300 ldp x3, x4, [sp, #160] 301 .cfi_restore x3 302 .cfi_restore x4 303 304 ldp x5, x6, [sp, #176] 305 .cfi_restore x5 306 .cfi_restore x6 307 308 ldp x7, xSELF, [sp, #192] 309 .cfi_restore x7 310 .cfi_restore x18 311 312 ldp x19, x20, [sp, #208] 313 .cfi_restore x19 314 .cfi_restore x20 315 316 ldp x21, x22, [sp, #224] 317 .cfi_restore x21 318 .cfi_restore x22 319 320 ldp x23, x24, [sp, #240] 321 .cfi_restore x23 322 .cfi_restore x24 323 324 ldp x25, x26, [sp, #256] 325 .cfi_restore x25 326 .cfi_restore x26 327 328 ldp x27, x28, [sp, #272] 329 .cfi_restore x27 330 .cfi_restore x28 331 332 ldp xFP, xLR, [sp, #288] 333 .cfi_restore x29 334 .cfi_restore x30 335 336 add sp, sp, #304 337 .cfi_adjust_cfa_offset -304 338.endm 339 340.macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME_NO_D0 341 342 ldr d1, [sp, #24] 343 ldp d2, d3, [sp, #32] 344 ldp d4, d5, [sp, #48] 345 ldp d6, d7, [sp, #64] 346 ldp d8, d9, [sp, #80] 347 ldp d10, d11, [sp, #96] 348 ldp d12, d13, [sp, #112] 349 ldp d14, d15, [sp, #128] 350 351 // args. 352 ldp x1, x2, [sp, #144] 353 .cfi_restore x1 354 .cfi_restore x2 355 356 ldp x3, x4, [sp, #160] 357 .cfi_restore x3 358 .cfi_restore x4 359 360 ldp x5, x6, [sp, #176] 361 .cfi_restore x5 362 .cfi_restore x6 363 364 ldp x7, xSELF, [sp, #192] 365 .cfi_restore x7 366 .cfi_restore x18 367 368 ldp x19, x20, [sp, #208] 369 .cfi_restore x19 370 .cfi_restore x20 371 372 ldp x21, x22, [sp, #224] 373 .cfi_restore x21 374 .cfi_restore x22 375 376 ldp x23, x24, [sp, #240] 377 .cfi_restore x23 378 .cfi_restore x24 379 380 ldp x25, x26, [sp, #256] 381 .cfi_restore x25 382 .cfi_restore x26 383 384 ldp x27, x28, [sp, #272] 385 .cfi_restore x27 386 .cfi_restore x28 387 388 ldp xFP, xLR, [sp, #288] 389 .cfi_restore x29 390 .cfi_restore x30 391 392 add sp, sp, #304 393 .cfi_adjust_cfa_offset -304 394.endm 395 396.macro RETURN_IF_RESULT_IS_ZERO 397 cbnz x0, 1f // result non-zero branch over 398 ret // return 3991: 400.endm 401 402.macro RETURN_IF_RESULT_IS_NON_ZERO 403 cbz x0, 1f // result zero branch over 404 ret // return 4051: 406.endm 407 408 /* 409 * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending 410 * exception is Thread::Current()->exception_ 411 */ 412.macro DELIVER_PENDING_EXCEPTION 413 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 414 mov x0, xSELF 415 mov x1, sp 416 417 // Point of no return. 418 b artDeliverPendingExceptionFromCode // artDeliverPendingExceptionFromCode(Thread*, SP) 419 brk 0 // Unreached 420.endm 421 422.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg 423 ldr \reg, [xSELF, # THREAD_EXCEPTION_OFFSET] // Get exception field. 424 cbnz \reg, 1f 425 ret 4261: 427 DELIVER_PENDING_EXCEPTION 428.endm 429 430.macro RETURN_OR_DELIVER_PENDING_EXCEPTION 431 RETURN_OR_DELIVER_PENDING_EXCEPTION_REG x9 432.endm 433 434// Same as above with x1. This is helpful in stubs that want to avoid clobbering another register. 435.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 436 RETURN_OR_DELIVER_PENDING_EXCEPTION_REG x1 437.endm 438 439.macro RETURN_IF_W0_IS_ZERO_OR_DELIVER 440 cbnz w0, 1f // result non-zero branch over 441 ret // return 4421: 443 DELIVER_PENDING_EXCEPTION 444.endm 445 446// FIXME: Temporary fix for TR(XSELF). 447.macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 448 .extern \cxx_name 449ENTRY \c_name 450 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 451 mov x0, x19 // pass Thread::Current 452 mov x1, sp // pass SP 453 b \cxx_name // \cxx_name(Thread*, SP) 454END \c_name 455.endm 456 457// FIXME: Temporary fix for TR(XSELF). 458.macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name 459 .extern \cxx_name 460ENTRY \c_name 461 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context. 462 mov x1, x19 // pass Thread::Current. 463 mov x2, sp // pass SP. 464 b \cxx_name // \cxx_name(arg, Thread*, SP). 465 brk 0 466END \c_name 467.endm 468 469// FIXME: Temporary fix for TR(XSELF). 470.macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name 471 .extern \cxx_name 472ENTRY \c_name 473 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 474 mov x2, x19 // pass Thread::Current 475 mov x3, sp // pass SP 476 b \cxx_name // \cxx_name(arg1, arg2, Thread*, SP) 477 brk 0 478END \c_name 479.endm 480 481 /* 482 * Called by managed code, saves callee saves and then calls artThrowException 483 * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception. 484 */ 485ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode 486 487 /* 488 * Called by managed code to create and deliver a NullPointerException. 489 */ 490NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode 491 492 /* 493 * Called by managed code to create and deliver an ArithmeticException. 494 */ 495NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode 496 497 /* 498 * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds 499 * index, arg2 holds limit. 500 */ 501TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode 502 503 /* 504 * Called by managed code to create and deliver a StackOverflowError. 505 */ 506NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode 507 508 /* 509 * Called by managed code to create and deliver a NoSuchMethodError. 510 */ 511ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode 512 513 /* 514 * TODO arm64 specifics need to be fleshed out. 515 * All generated callsites for interface invokes and invocation slow paths will load arguments 516 * as usual - except instead of loading x0 with the target Method*, x0 will contain 517 * the method_idx. This wrapper will save x1-x3, load the caller's Method*, align the 518 * stack and call the appropriate C helper. 519 * NOTE: "this" is first visible argument of the target, and so can be found in x1. 520 * 521 * The helper will attempt to locate the target and return a result in x0 consisting 522 * of the target Method* in x0 and method->code_ in x1. 523 * 524 * If unsuccessful, the helper will return NULL/NULL. There will be a pending exception in the 525 * thread and we branch to another stub to deliver it. 526 * 527 * On success this wrapper will restore arguments and *jump* to the target, leaving the lr 528 * pointing back to the original caller. 529 */ 530.macro INVOKE_TRAMPOLINE c_name, cxx_name 531 .extern \cxx_name 532ENTRY \c_name 533 brk 0 534END \c_name 535.endm 536 537INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline 538INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck 539 540INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck 541INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck 542INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck 543INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck 544 545 546.macro INVOKE_STUB_CREATE_FRAME 547 548SAVE_SIZE=5*8 // x4, x5, SP, LR & FP saved. 549SAVE_SIZE_AND_METHOD=SAVE_SIZE+8 550 551 mov x9, sp // Save stack pointer. 552 .cfi_register sp,x9 553 554 add x10, x2, # SAVE_SIZE_AND_METHOD // calculate size of frame. 555 sub x10, sp, x10 // Calculate SP position - saves + ArtMethod* + args 556 and x10, x10, # ~0xf // Enforce 16 byte stack alignment. 557 mov sp, x10 // Set new SP. 558 559 sub x10, x9, #SAVE_SIZE // Calculate new FP (later). Done here as we must move SP 560 .cfi_def_cfa_register x10 // before this. 561 .cfi_adjust_cfa_offset SAVE_SIZE 562 563 str x9, [x10, #32] // Save old stack pointer. 564 .cfi_rel_offset sp, 32 565 566 stp x4, x5, [x10, #16] // Save result and shorty addresses. 567 .cfi_rel_offset x4, 16 568 .cfi_rel_offset x5, 24 569 570 stp xFP, xLR, [x10] // Store LR & FP. 571 .cfi_rel_offset x29, 0 572 .cfi_rel_offset x30, 8 573 574 mov xFP, x10 // Use xFP now, as it's callee-saved. 575 .cfi_def_cfa_register x29 576 mov xSELF, x3 // Move thread pointer into SELF register. 577 578 // Copy arguments into stack frame. 579 // Use simple copy routine for now. 580 // 4 bytes per slot. 581 // X1 - source address 582 // W2 - args length 583 // X9 - destination address. 584 // W10 - temporary 585 add x9, sp, #8 // Destination address is bottom of stack + NULL. 586 587 // Use \@ to differentiate between macro invocations. 588.LcopyParams\@: 589 cmp w2, #0 590 beq .LendCopyParams\@ 591 sub w2, w2, #4 // Need 65536 bytes of range. 592 ldr w10, [x1, x2] 593 str w10, [x9, x2] 594 595 b .LcopyParams\@ 596 597.LendCopyParams\@: 598 599 // Store NULL into Method* at bottom of frame. 600 str xzr, [sp] 601 602.endm 603 604.macro INVOKE_STUB_CALL_AND_RETURN 605 606 // load method-> METHOD_QUICK_CODE_OFFSET 607 ldr x9, [x0 , #METHOD_QUICK_CODE_OFFSET] 608 // Branch to method. 609 blr x9 610 611 // Restore return value address and shorty address. 612 ldp x4,x5, [xFP, #16] 613 .cfi_restore x4 614 .cfi_restore x5 615 616 // Store result (w0/x0/s0/d0) appropriately, depending on resultType. 617 ldrb w10, [x5] 618 619 // Don't set anything for a void type. 620 cmp w10, #'V' 621 beq .Lexit_art_quick_invoke_stub\@ 622 623 cmp w10, #'D' 624 bne .Lreturn_is_float\@ 625 str d0, [x4] 626 b .Lexit_art_quick_invoke_stub\@ 627 628.Lreturn_is_float\@: 629 cmp w10, #'F' 630 bne .Lreturn_is_int\@ 631 str s0, [x4] 632 b .Lexit_art_quick_invoke_stub\@ 633 634 // Just store x0. Doesn't matter if it is 64 or 32 bits. 635.Lreturn_is_int\@: 636 str x0, [x4] 637 638.Lexit_art_quick_invoke_stub\@: 639 ldr x2, [x29, #32] // Restore stack pointer. 640 mov sp, x2 641 .cfi_restore sp 642 643 ldp x29, x30, [x29] // Restore old frame pointer and link register. 644 .cfi_restore x29 645 .cfi_restore x30 646 647 ret 648 649.endm 650 651 652/* 653 * extern"C" void art_quick_invoke_stub(ArtMethod *method, x0 654 * uint32_t *args, x1 655 * uint32_t argsize, w2 656 * Thread *self, x3 657 * JValue *result, x4 658 * char *shorty); x5 659 * +----------------------+ 660 * | | 661 * | C/C++ frame | 662 * | LR'' | 663 * | FP'' | <- SP' 664 * +----------------------+ 665 * +----------------------+ 666 * | SP' | 667 * | X5 | 668 * | X4 | Saved registers 669 * | LR' | 670 * | FP' | <- FP 671 * +----------------------+ 672 * | uint32_t out[n-1] | 673 * | : : | Outs 674 * | uint32_t out[0] | 675 * | ArtMethod* NULL | <- SP 676 * +----------------------+ 677 * 678 * Outgoing registers: 679 * x0 - Method* 680 * x1-x7 - integer parameters. 681 * d0-d7 - Floating point parameters. 682 * xSELF = self 683 * SP = & of ArtMethod* 684 * x1 = "this" pointer. 685 * 686 */ 687ENTRY art_quick_invoke_stub 688 // Spill registers as per AACPS64 calling convention. 689 INVOKE_STUB_CREATE_FRAME 690 691 // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters. 692 // Parse the passed shorty to determine which register to load. 693 // Load addresses for routines that load WXSD registers. 694 adr x11, .LstoreW2 695 adr x12, .LstoreX2 696 adr x13, .LstoreS0 697 adr x14, .LstoreD0 698 699 // Initialize routine offsets to 0 for integers and floats. 700 // x8 for integers, x15 for floating point. 701 mov x8, #0 702 mov x15, #0 703 704 add x10, x5, #1 // Load shorty address, plus one to skip return value. 705 ldr w1, [x9],#4 // Load "this" parameter, and increment arg pointer. 706 707 // Loop to fill registers. 708.LfillRegisters: 709 ldrb w17, [x10], #1 // Load next character in signature, and increment. 710 cbz w17, .LcallFunction // Exit at end of signature. Shorty 0 terminated. 711 712 cmp w17, #'F' // is this a float? 713 bne .LisDouble 714 715 cmp x15, # 8*12 // Skip this load if all registers full. 716 beq .Ladvance4 717 718 add x17, x13, x15 // Calculate subroutine to jump to. 719 br x17 720 721.LisDouble: 722 cmp w17, #'D' // is this a double? 723 bne .LisLong 724 725 cmp x15, # 8*12 // Skip this load if all registers full. 726 beq .Ladvance8 727 728 add x17, x14, x15 // Calculate subroutine to jump to. 729 br x17 730 731.LisLong: 732 cmp w17, #'J' // is this a long? 733 bne .LisOther 734 735 cmp x8, # 6*12 // Skip this load if all registers full. 736 beq .Ladvance8 737 738 add x17, x12, x8 // Calculate subroutine to jump to. 739 br x17 740 741.LisOther: // Everything else takes one vReg. 742 cmp x8, # 6*12 // Skip this load if all registers full. 743 beq .Ladvance4 744 745 add x17, x11, x8 // Calculate subroutine to jump to. 746 br x17 747 748.Ladvance4: 749 add x9, x9, #4 750 b .LfillRegisters 751 752.Ladvance8: 753 add x9, x9, #8 754 b .LfillRegisters 755 756// Macro for loading a parameter into a register. 757// counter - the register with offset into these tables 758// size - the size of the register - 4 or 8 bytes. 759// register - the name of the register to be loaded. 760.macro LOADREG counter size register return 761 ldr \register , [x9], #\size 762 add \counter, \counter, 12 763 b \return 764.endm 765 766// Store ints. 767.LstoreW2: 768 LOADREG x8 4 w2 .LfillRegisters 769 LOADREG x8 4 w3 .LfillRegisters 770 LOADREG x8 4 w4 .LfillRegisters 771 LOADREG x8 4 w5 .LfillRegisters 772 LOADREG x8 4 w6 .LfillRegisters 773 LOADREG x8 4 w7 .LfillRegisters 774 775// Store longs. 776.LstoreX2: 777 LOADREG x8 8 x2 .LfillRegisters 778 LOADREG x8 8 x3 .LfillRegisters 779 LOADREG x8 8 x4 .LfillRegisters 780 LOADREG x8 8 x5 .LfillRegisters 781 LOADREG x8 8 x6 .LfillRegisters 782 LOADREG x8 8 x7 .LfillRegisters 783 784// Store singles. 785.LstoreS0: 786 LOADREG x15 4 s0 .LfillRegisters 787 LOADREG x15 4 s1 .LfillRegisters 788 LOADREG x15 4 s2 .LfillRegisters 789 LOADREG x15 4 s3 .LfillRegisters 790 LOADREG x15 4 s4 .LfillRegisters 791 LOADREG x15 4 s5 .LfillRegisters 792 LOADREG x15 4 s6 .LfillRegisters 793 LOADREG x15 4 s7 .LfillRegisters 794 795// Store doubles. 796.LstoreD0: 797 LOADREG x15 8 d0 .LfillRegisters 798 LOADREG x15 8 d1 .LfillRegisters 799 LOADREG x15 8 d2 .LfillRegisters 800 LOADREG x15 8 d3 .LfillRegisters 801 LOADREG x15 8 d4 .LfillRegisters 802 LOADREG x15 8 d5 .LfillRegisters 803 LOADREG x15 8 d6 .LfillRegisters 804 LOADREG x15 8 d7 .LfillRegisters 805 806 807.LcallFunction: 808 809 INVOKE_STUB_CALL_AND_RETURN 810 811END art_quick_invoke_stub 812 813/* extern"C" 814 * void art_quick_invoke_static_stub(ArtMethod *method, x0 815 * uint32_t *args, x1 816 * uint32_t argsize, w2 817 * Thread *self, x3 818 * JValue *result, x4 819 * char *shorty); x5 820 */ 821ENTRY art_quick_invoke_static_stub 822 // Spill registers as per AACPS64 calling convention. 823 INVOKE_STUB_CREATE_FRAME 824 825 // Fill registers x/w1 to x/w7 and s/d0 to s/d7 with parameters. 826 // Parse the passed shorty to determine which register to load. 827 // Load addresses for routines that load WXSD registers. 828 adr x11, .LstoreW1_2 829 adr x12, .LstoreX1_2 830 adr x13, .LstoreS0_2 831 adr x14, .LstoreD0_2 832 833 // Initialize routine offsets to 0 for integers and floats. 834 // x8 for integers, x15 for floating point. 835 mov x8, #0 836 mov x15, #0 837 838 add x10, x5, #1 // Load shorty address, plus one to skip return value. 839 840 // Loop to fill registers. 841.LfillRegisters2: 842 ldrb w17, [x10], #1 // Load next character in signature, and increment. 843 cbz w17, .LcallFunction2 // Exit at end of signature. Shorty 0 terminated. 844 845 cmp w17, #'F' // is this a float? 846 bne .LisDouble2 847 848 cmp x15, # 8*12 // Skip this load if all registers full. 849 beq .Ladvance4_2 850 851 add x17, x13, x15 // Calculate subroutine to jump to. 852 br x17 853 854.LisDouble2: 855 cmp w17, #'D' // is this a double? 856 bne .LisLong2 857 858 cmp x15, # 8*12 // Skip this load if all registers full. 859 beq .Ladvance8_2 860 861 add x17, x14, x15 // Calculate subroutine to jump to. 862 br x17 863 864.LisLong2: 865 cmp w17, #'J' // is this a long? 866 bne .LisOther2 867 868 cmp x8, # 7*12 // Skip this load if all registers full. 869 beq .Ladvance8_2 870 871 add x17, x12, x8 // Calculate subroutine to jump to. 872 br x17 873 874.LisOther2: // Everything else takes one vReg. 875 cmp x8, # 7*12 // Skip this load if all registers full. 876 beq .Ladvance4_2 877 878 add x17, x11, x8 // Calculate subroutine to jump to. 879 br x17 880 881.Ladvance4_2: 882 add x9, x9, #4 883 b .LfillRegisters2 884 885.Ladvance8_2: 886 add x9, x9, #8 887 b .LfillRegisters2 888 889// Store ints. 890.LstoreW1_2: 891 LOADREG x8 4 w1 .LfillRegisters2 892 LOADREG x8 4 w2 .LfillRegisters2 893 LOADREG x8 4 w3 .LfillRegisters2 894 LOADREG x8 4 w4 .LfillRegisters2 895 LOADREG x8 4 w5 .LfillRegisters2 896 LOADREG x8 4 w6 .LfillRegisters2 897 LOADREG x8 4 w7 .LfillRegisters2 898 899// Store longs. 900.LstoreX1_2: 901 LOADREG x8 8 x1 .LfillRegisters2 902 LOADREG x8 8 x2 .LfillRegisters2 903 LOADREG x8 8 x3 .LfillRegisters2 904 LOADREG x8 8 x4 .LfillRegisters2 905 LOADREG x8 8 x5 .LfillRegisters2 906 LOADREG x8 8 x6 .LfillRegisters2 907 LOADREG x8 8 x7 .LfillRegisters2 908 909// Store singles. 910.LstoreS0_2: 911 LOADREG x15 4 s0 .LfillRegisters2 912 LOADREG x15 4 s1 .LfillRegisters2 913 LOADREG x15 4 s2 .LfillRegisters2 914 LOADREG x15 4 s3 .LfillRegisters2 915 LOADREG x15 4 s4 .LfillRegisters2 916 LOADREG x15 4 s5 .LfillRegisters2 917 LOADREG x15 4 s6 .LfillRegisters2 918 LOADREG x15 4 s7 .LfillRegisters2 919 920// Store doubles. 921.LstoreD0_2: 922 LOADREG x15 8 d0 .LfillRegisters2 923 LOADREG x15 8 d1 .LfillRegisters2 924 LOADREG x15 8 d2 .LfillRegisters2 925 LOADREG x15 8 d3 .LfillRegisters2 926 LOADREG x15 8 d4 .LfillRegisters2 927 LOADREG x15 8 d5 .LfillRegisters2 928 LOADREG x15 8 d6 .LfillRegisters2 929 LOADREG x15 8 d7 .LfillRegisters2 930 931 932.LcallFunction2: 933 934 INVOKE_STUB_CALL_AND_RETURN 935 936END art_quick_invoke_static_stub 937 938 939 940 /* 941 * On entry x0 is uintptr_t* gprs_ and x1 is uint64_t* fprs_ 942 */ 943 944ENTRY art_quick_do_long_jump 945 // Load FPRs 946 ldp d0, d1, [x1], #16 947 ldp d2, d3, [x1], #16 948 ldp d4, d5, [x1], #16 949 ldp d6, d7, [x1], #16 950 ldp d8, d9, [x1], #16 951 ldp d10, d11, [x1], #16 952 ldp d12, d13, [x1], #16 953 ldp d14, d15, [x1], #16 954 ldp d16, d17, [x1], #16 955 ldp d18, d19, [x1], #16 956 ldp d20, d21, [x1], #16 957 ldp d22, d23, [x1], #16 958 ldp d24, d25, [x1], #16 959 ldp d26, d27, [x1], #16 960 ldp d28, d29, [x1], #16 961 ldp d30, d31, [x1] 962 963 // Load GPRs 964 // TODO: lots of those are smashed, could optimize. 965 add x0, x0, #30*8 966 ldp x30, x1, [x0], #-16 967 ldp x28, x29, [x0], #-16 968 ldp x26, x27, [x0], #-16 969 ldp x24, x25, [x0], #-16 970 ldp x22, x23, [x0], #-16 971 ldp x20, x21, [x0], #-16 972 ldp x18, x19, [x0], #-16 973 ldp x16, x17, [x0], #-16 974 ldp x14, x15, [x0], #-16 975 ldp x12, x13, [x0], #-16 976 ldp x10, x11, [x0], #-16 977 ldp x8, x9, [x0], #-16 978 ldp x6, x7, [x0], #-16 979 ldp x4, x5, [x0], #-16 980 ldp x2, x3, [x0], #-16 981 mov sp, x1 982 983 // TODO: Is it really OK to use LR for the target PC? 984 mov x0, #0 985 mov x1, #0 986 br xLR 987END art_quick_do_long_jump 988 989 /* 990 * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on 991 * failure. 992 */ 993 .extern artHandleFillArrayDataFromCode 994// TODO: xSELF -> x19. 995ENTRY art_quick_handle_fill_data 996 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // Save callee saves in case exception allocation triggers GC. 997 mov x2, xSELF // Pass Thread::Current. 998 mov x3, sp // Pass SP. 999 bl artHandleFillArrayDataFromCode // (Array*, const DexFile::Payload*, Thread*, SP) 1000 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1001 RETURN_IF_RESULT_IS_ZERO 1002 DELIVER_PENDING_EXCEPTION 1003END art_quick_handle_fill_data 1004 1005UNIMPLEMENTED art_quick_lock_object 1006UNIMPLEMENTED art_quick_unlock_object 1007 1008 /* 1009 * Entry from managed code that calls artIsAssignableFromCode and on failure calls 1010 * artThrowClassCastException. 1011 */ 1012 .extern artThrowClassCastException 1013ENTRY art_quick_check_cast 1014 // Store arguments and link register 1015 sub sp, sp, #32 // Stack needs to be 16b aligned on calls 1016 .cfi_adjust_cfa_offset 32 1017 stp x0, x1, [sp] 1018 .cfi_rel_offset x0, 0 1019 .cfi_rel_offset x1, 8 1020 stp xSELF, xLR, [sp, #16] 1021 .cfi_rel_offset x18, 16 1022 .cfi_rel_offset x30, 24 1023 1024 // Call runtime code 1025 bl artIsAssignableFromCode 1026 1027 // Check for exception 1028 cbz x0, .Lthrow_class_cast_exception 1029 1030 // Restore and return 1031 ldp x0, x1, [sp] 1032 .cfi_restore x0 1033 .cfi_restore x1 1034 ldp xSELF, xLR, [sp, #16] 1035 .cfi_restore x18 1036 .cfi_restore x30 1037 add sp, sp, #32 1038 .cfi_adjust_cfa_offset -32 1039 ret 1040 1041.Lthrow_class_cast_exception: 1042 // Restore 1043 ldp x0, x1, [sp] 1044 .cfi_restore x0 1045 .cfi_restore x1 1046 ldp xSELF, xLR, [sp, #16] 1047 .cfi_restore x18 1048 .cfi_restore x30 1049 add sp, sp, #32 1050 .cfi_adjust_cfa_offset -32 1051 1052 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context 1053 mov x2, xSELF // pass Thread::Current 1054 mov x3, sp // pass SP 1055 b artThrowClassCastException // (Class*, Class*, Thread*, SP) 1056 brk 0 // We should not return here... 1057END art_quick_check_cast 1058 1059 /* 1060 * Entry from managed code for array put operations of objects where the value being stored 1061 * needs to be checked for compatibility. 1062 * x0 = array, x1 = index, x2 = value 1063 * 1064 * Currently all values should fit into w0/w1/w2, and w1 always will as indices are 32b. We 1065 * assume, though, that the upper 32b are zeroed out. At least for x1/w1 we can do better by 1066 * using index-zero-extension in load/stores. 1067 * 1068 * Temporaries: x3, x4 1069 * TODO: x4 OK? ip seems wrong here. 1070 */ 1071ENTRY art_quick_aput_obj_with_null_and_bound_check 1072 tst x0, x0 1073 bne art_quick_aput_obj_with_bound_check 1074 b art_quick_throw_null_pointer_exception 1075END art_quick_aput_obj_with_null_and_bound_check 1076 1077ENTRY art_quick_aput_obj_with_bound_check 1078 ldr w3, [x0, #ARRAY_LENGTH_OFFSET] 1079 cmp w3, w1 1080 bhi art_quick_aput_obj 1081 mov x0, x1 1082 mov x1, x3 1083 b art_quick_throw_array_bounds 1084END art_quick_aput_obj_with_bound_check 1085 1086ENTRY art_quick_aput_obj 1087 cbz x2, .Ldo_aput_null 1088 ldr w3, [x0, #CLASS_OFFSET] // Heap reference = 32b 1089 // This also zero-extends to x3 1090 ldr w4, [x2, #CLASS_OFFSET] // Heap reference = 32b 1091 // This also zero-extends to x4 1092 ldr w3, [x3, #CLASS_COMPONENT_TYPE_OFFSET] // Heap reference = 32b 1093 // This also zero-extends to x3 1094 cmp w3, w4 // value's type == array's component type - trivial assignability 1095 bne .Lcheck_assignability 1096.Ldo_aput: 1097 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET 1098 // "Compress" = do nothing 1099 str w2, [x3, x1, lsl #2] // Heap reference = 32b 1100 ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1101 lsr x0, x0, #7 1102 strb w3, [x3, x0] 1103 ret 1104.Ldo_aput_null: 1105 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET 1106 // "Compress" = do nothing 1107 str w2, [x3, x1, lsl #2] // Heap reference = 32b 1108 ret 1109.Lcheck_assignability: 1110 // Store arguments and link register 1111 sub sp, sp, #48 // Stack needs to be 16b aligned on calls 1112 .cfi_adjust_cfa_offset 48 1113 stp x0, x1, [sp] 1114 .cfi_rel_offset x0, 0 1115 .cfi_rel_offset x1, 8 1116 stp x2, xSELF, [sp, #16] 1117 .cfi_rel_offset x2, 16 1118 .cfi_rel_offset x18, 24 1119 str xLR, [sp, #32] 1120 .cfi_rel_offset x30, 32 1121 1122 // Call runtime code 1123 mov x0, x3 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended 1124 mov x1, x4 // Heap reference, 32b, "uncompress" = do nothing, already zero-extended 1125 bl artIsAssignableFromCode 1126 1127 // Check for exception 1128 cbz x0, .Lthrow_array_store_exception 1129 1130 // Restore 1131 ldp x0, x1, [sp] 1132 .cfi_restore x0 1133 .cfi_restore x1 1134 ldp x2, xSELF, [sp, #16] 1135 .cfi_restore x2 1136 .cfi_restore x18 1137 ldr xLR, [sp, #32] 1138 .cfi_restore x30 1139 add sp, sp, #48 1140 .cfi_adjust_cfa_offset -48 1141 1142 add x3, x0, #OBJECT_ARRAY_DATA_OFFSET 1143 // "Compress" = do nothing 1144 str w2, [x3, x1, lsl #2] // Heap reference = 32b 1145 ldr x3, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1146 lsr x0, x0, #7 1147 strb w3, [x3, x0] 1148 ret 1149.Lthrow_array_store_exception: 1150 ldp x0, x1, [sp] 1151 .cfi_restore x0 1152 .cfi_restore x1 1153 ldp x2, xSELF, [sp, #16] 1154 .cfi_restore x2 1155 .cfi_restore x18 1156 ldr xLR, [sp, #32] 1157 .cfi_restore x30 1158 add sp, sp, #48 1159 .cfi_adjust_cfa_offset -48 1160 1161 SETUP_SAVE_ALL_CALLEE_SAVE_FRAME 1162 mov x1, x2 // Pass value. 1163 mov x2, xSELF // Pass Thread::Current. 1164 mov x3, sp // Pass SP. 1165 b artThrowArrayStoreException // (Object*, Object*, Thread*, SP). 1166 brk 0 // Unreached. 1167END art_quick_aput_obj 1168 1169UNIMPLEMENTED art_quick_initialize_static_storage 1170UNIMPLEMENTED art_quick_initialize_type 1171UNIMPLEMENTED art_quick_initialize_type_and_verify_access 1172 1173// Macro to facilitate adding new allocation entrypoints. 1174// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1175.macro TWO_ARG_DOWNCALL name, entrypoint, return 1176 .extern \entrypoint 1177ENTRY \name 1178 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1179 mov x2, xSELF // pass Thread::Current 1180 mov x3, sp // pass SP 1181 bl \entrypoint // (uint32_t type_idx, Method* method, Thread*, SP) 1182 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1183 \return 1184 DELIVER_PENDING_EXCEPTION 1185END \name 1186.endm 1187 1188// Macro to facilitate adding new array allocation entrypoints. 1189// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1190.macro THREE_ARG_DOWNCALL name, entrypoint, return 1191 .extern \entrypoint 1192ENTRY \name 1193 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1194 mov x3, xSELF // pass Thread::Current 1195 mov x4, sp // pass SP 1196 bl \entrypoint 1197 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1198 \return 1199 DELIVER_PENDING_EXCEPTION 1200END \name 1201.endm 1202 1203// Macros taking opportunity of code similarities for downcalls with referrer. 1204 1205// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1206.macro ONE_ARG_REF_DOWNCALL name, entrypoint, return 1207 .extern \entrypoint 1208ENTRY \name 1209 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1210 ldr x1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1211 mov x2, xSELF // pass Thread::Current 1212 mov x3, sp // pass SP 1213 bl \entrypoint // (uint32_t type_idx, Method* method, Thread*, SP) 1214 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1215 \return 1216END \name 1217.endm 1218 1219// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1220.macro TWO_ARG_REF_DOWNCALL name, entrypoint, return 1221 .extern \entrypoint 1222ENTRY \name 1223 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1224 ldr x2, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1225 mov x3, xSELF // pass Thread::Current 1226 mov x4, sp // pass SP 1227 bl \entrypoint 1228 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1229 \return 1230END \name 1231.endm 1232 1233// TODO: xSELF -> x19. Temporarily rely on xSELF being saved in REF_ONLY 1234.macro THREE_ARG_REF_DOWNCALL name, entrypoint, return 1235 .extern \entrypoint 1236ENTRY \name 1237 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1238 ldr x3, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1239 mov x4, xSELF // pass Thread::Current 1240 mov x5, sp // pass SP 1241 bl \entrypoint 1242 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1243 \return 1244END \name 1245.endm 1246 1247ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1248ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1249ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1250 1251TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1252TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1253TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCode, RETURN_OR_DELIVER_PENDING_EXCEPTION_X1 1254 1255TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1256TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1257 1258THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1259THREE_ARG_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1260THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCode, RETURN_IF_W0_IS_ZERO_OR_DELIVER 1261 1262// This is separated out as the argument order is different. 1263 .extern artSet64StaticFromCode 1264ENTRY art_quick_set64_static 1265 SETUP_REF_ONLY_CALLEE_SAVE_FRAME // save callee saves in case of GC 1266 mov x3, x1 // Store value 1267 ldr x1, [sp, #FRAME_SIZE_REFS_ONLY_CALLEE_SAVE] // Load referrer 1268 mov x2, x3 // Put value param 1269 mov x3, xSELF // pass Thread::Current 1270 mov x4, sp // pass SP 1271 bl artSet64StaticFromCode 1272 RESTORE_REF_ONLY_CALLEE_SAVE_FRAME 1273 RETURN_IF_W0_IS_ZERO_OR_DELIVER 1274END art_quick_set64_static 1275 1276 1277UNIMPLEMENTED art_quick_resolve_string 1278 1279// Generate the allocation entrypoints for each allocator. 1280GENERATE_ALL_ALLOC_ENTRYPOINTS 1281 1282UNIMPLEMENTED art_quick_test_suspend 1283 1284 /* 1285 * Called by managed code that is attempting to call a method on a proxy class. On entry 1286 * x0 holds the proxy method and x1 holds the receiver; The frame size of the invoked proxy 1287 * method agrees with a ref and args callee save frame. 1288 */ 1289 .extern artQuickProxyInvokeHandler 1290ENTRY art_quick_proxy_invoke_handler 1291 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 1292 str x0, [sp, #0] // place proxy method at bottom of frame 1293 mov x2, xSELF // pass Thread::Current 1294 mov x3, sp // pass SP 1295 bl artQuickProxyInvokeHandler // (Method* proxy method, receiver, Thread*, SP) 1296 ldr xSELF, [sp, #200] // Restore self pointer. 1297 ldr x2, [xSELF, THREAD_EXCEPTION_OFFSET] 1298 cbnz x2, .Lexception_in_proxy // success if no exception is pending 1299 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME_NO_D0 // keep d0 1300 ret // return on success 1301.Lexception_in_proxy: 1302 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1303 DELIVER_PENDING_EXCEPTION 1304END art_quick_proxy_invoke_handler 1305 1306UNIMPLEMENTED art_quick_imt_conflict_trampoline 1307 1308 1309ENTRY art_quick_resolution_trampoline 1310 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME 1311 mov x19, x0 // save the called method 1312 mov x2, xSELF 1313 mov x3, sp 1314 bl artQuickResolutionTrampoline // (called, receiver, Thread*, SP) 1315 mov x9, x0 // Remember returned code pointer in x9. 1316 mov x0, x19 // Restore the method, before x19 is restored to on-call value 1317 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1318 cbz x9, 1f 1319 br x9 13201: 1321 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1322 DELIVER_PENDING_EXCEPTION 1323END art_quick_resolution_trampoline 1324 1325/* 1326 * Generic JNI frame layout: 1327 * 1328 * #-------------------# 1329 * | | 1330 * | caller method... | 1331 * #-------------------# <--- SP on entry 1332 * | Return X30/LR | 1333 * | X29/FP | callee save 1334 * | X28 | callee save 1335 * | X27 | callee save 1336 * | X26 | callee save 1337 * | X25 | callee save 1338 * | X24 | callee save 1339 * | X23 | callee save 1340 * | X22 | callee save 1341 * | X21 | callee save 1342 * | X20 | callee save 1343 * | X19 | callee save 1344 * | X7 | arg7 1345 * | X6 | arg6 1346 * | X5 | arg5 1347 * | X4 | arg4 1348 * | X3 | arg3 1349 * | X2 | arg2 1350 * | X1 | arg1 1351 * | D15 | float arg 8 1352 * | D14 | float arg 8 1353 * | D13 | float arg 8 1354 * | D12 | callee save 1355 * | D11 | callee save 1356 * | D10 | callee save 1357 * | D9 | callee save 1358 * | D8 | callee save 1359 * | D7 | float arg 8 1360 * | D6 | float arg 7 1361 * | D5 | float arg 6 1362 * | D4 | float arg 5 1363 * | D3 | float arg 4 1364 * | D2 | float arg 3 1365 * | D1 | float arg 2 1366 * | D0 | float arg 1 1367 * | RDI/Method* | <- X0 1368 * #-------------------# 1369 * | local ref cookie | // 4B 1370 * | SIRT size | // 4B 1371 * #-------------------# 1372 * | JNI Call Stack | 1373 * #-------------------# <--- SP on native call 1374 * | | 1375 * | Stack for Regs | The trampoline assembly will pop these values 1376 * | | into registers for native call 1377 * #-------------------# 1378 * | Native code ptr | 1379 * #-------------------# 1380 * | Free scratch | 1381 * #-------------------# 1382 * | Ptr to (1) | <--- SP 1383 * #-------------------# 1384 */ 1385 /* 1386 * Called to do a generic JNI down-call 1387 */ 1388ENTRY art_quick_generic_jni_trampoline 1389 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME_INTERNAL 1390 str x0, [sp, #0] // Store native ArtMethod* to bottom of stack. 1391 1392 // Save SP , so we can have static CFI info. 1393 mov x28, sp 1394 .cfi_def_cfa_register x28 1395 1396 // This looks the same, but is different: this will be updated to point to the bottom 1397 // of the frame when the SIRT is inserted. 1398 mov xFP, sp 1399 1400 mov x8, #5120 1401 sub sp, sp, x8 1402 1403 // prepare for artQuickGenericJniTrampoline call 1404 // (Thread*, SP) 1405 // x0 x1 <= C calling convention 1406 // xSELF xFP <= where they are 1407 1408 mov x0, xSELF // Thread* 1409 mov x1, xFP 1410 bl artQuickGenericJniTrampoline // (Thread*, sp) 1411 1412 // Get the updated pointer. This is the bottom of the frame _with_ SIRT. 1413 ldr xFP, [sp] 1414 add x9, sp, #8 1415 1416 cmp x0, #0 1417 b.mi .Lentry_error // Check for error, negative value. 1418 1419 // release part of the alloca. 1420 add x9, x9, x0 1421 1422 // Get the code pointer 1423 ldr xIP0, [x9, #0] 1424 1425 // Load parameters from frame into registers. 1426 // TODO Check with artQuickGenericJniTrampoline. 1427 // Also, check again APPCS64 - the stack arguments are interleaved. 1428 ldp x0, x1, [x9, #8] 1429 ldp x2, x3, [x9, #24] 1430 ldp x4, x5, [x9, #40] 1431 ldp x6, x7, [x9, #56] 1432 1433 ldp d0, d1, [x9, #72] 1434 ldp d2, d3, [x9, #88] 1435 ldp d4, d5, [x9, #104] 1436 ldp d6, d7, [x9, #120] 1437 1438 add sp, x9, #136 1439 1440 blr xIP0 // native call. 1441 1442 // Restore self pointer. 1443 ldr xSELF, [x28, #200] 1444 1445 // result sign extension is handled in C code 1446 // prepare for artQuickGenericJniEndTrampoline call 1447 // (Thread*, SP, result, result_f) 1448 // x0 x1 x2 x3 <= C calling convention 1449 mov x5, x0 // Save return value 1450 mov x0, xSELF // Thread register 1451 mov x1, xFP // Stack pointer 1452 mov x2, x5 // Result (from saved) 1453 fmov x3, d0 // d0 will contain floating point result, but needs to go into x3 1454 1455 bl artQuickGenericJniEndTrampoline 1456 1457 // Tear down the alloca. 1458 mov sp, x28 1459 .cfi_def_cfa_register sp 1460 1461 // Restore self pointer. 1462 ldr xSELF, [x28, #200] 1463 1464 // Pending exceptions possible. 1465 ldr x1, [xSELF, THREAD_EXCEPTION_OFFSET] 1466 cbnz x1, .Lexception_in_native 1467 1468 // Tear down the callee-save frame. 1469 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1470 1471 // store into fpr, for when it's a fpr return... 1472 fmov d0, x0 1473 ret 1474 1475.Lentry_error: 1476 mov sp, x28 1477 .cfi_def_cfa_register sp 1478 ldr xSELF, [x28, #200] 1479.Lexception_in_native: 1480 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME 1481 DELIVER_PENDING_EXCEPTION 1482 1483END art_quick_generic_jni_trampoline 1484 1485/* 1486 * Called to bridge from the quick to interpreter ABI. On entry the arguments match those 1487 * of a quick call: 1488 * x0 = method being called/to bridge to. 1489 * x1..x7, d0..d7 = arguments to that method. 1490 */ 1491ENTRY art_quick_to_interpreter_bridge 1492 SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME // Set up frame and save arguments. 1493 1494 // x0 will contain mirror::ArtMethod* method. 1495 mov x1, xSELF // How to get Thread::Current() ??? 1496 mov x2, sp 1497 1498 // uint64_t artQuickToInterpreterBridge(mirror::ArtMethod* method, Thread* self, 1499 // mirror::ArtMethod** sp) 1500 bl artQuickToInterpreterBridge 1501 1502 RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME // TODO: no need to restore arguments in this case. 1503 1504 fmov d0, x0 1505 1506 RETURN_OR_DELIVER_PENDING_EXCEPTION 1507END art_quick_to_interpreter_bridge 1508 1509UNIMPLEMENTED art_quick_instrumentation_entry 1510UNIMPLEMENTED art_quick_instrumentation_exit 1511UNIMPLEMENTED art_quick_deoptimize 1512UNIMPLEMENTED art_quick_mul_long 1513UNIMPLEMENTED art_quick_shl_long 1514UNIMPLEMENTED art_quick_shr_long 1515UNIMPLEMENTED art_quick_ushr_long 1516UNIMPLEMENTED art_quick_indexof 1517 1518 /* 1519 * String's compareTo. 1520 * 1521 * TODO: Not very optimized. 1522 * 1523 * On entry: 1524 * x0: this object pointer 1525 * x1: comp object pointer 1526 * 1527 */ 1528 .extern __memcmp16 1529ENTRY art_quick_string_compareto 1530 mov x2, x0 // x0 is return, use x2 for first input. 1531 sub x0, x2, x1 // Same string object? 1532 cbnz x0,1f 1533 ret 15341: // Different string objects. 1535 1536 ldr w6, [x2, #STRING_OFFSET_OFFSET] 1537 ldr w5, [x1, #STRING_OFFSET_OFFSET] 1538 ldr w4, [x2, #STRING_COUNT_OFFSET] 1539 ldr w3, [x1, #STRING_COUNT_OFFSET] 1540 ldr w2, [x2, #STRING_VALUE_OFFSET] 1541 ldr w1, [x1, #STRING_VALUE_OFFSET] 1542 1543 /* 1544 * Now: CharArray* Offset Count 1545 * first arg x2 w6 w4 1546 * second arg x1 w5 w3 1547 */ 1548 1549 // x0 := str1.length(w4) - str2.length(w3). ldr zero-extended w3/w4 into x3/x4. 1550 subs x0, x4, x3 1551 // Min(count1, count2) into w3. 1552 csel x3, x3, x4, ge 1553 1554 // Build pointer into string data. 1555 1556 // Add offset in array (substr etc.) (sign extend and << 1). 1557 add x2, x2, w6, sxtw #1 1558 add x1, x1, w5, sxtw #1 1559 1560 // Add offset in CharArray to array. 1561 add x2, x2, #STRING_DATA_OFFSET 1562 add x1, x1, #STRING_DATA_OFFSET 1563 1564 // Check for long string, do memcmp16 for them. 1565 cmp w3, #28 // Constant from arm32. 1566 bgt .Ldo_memcmp16 1567 1568 /* 1569 * Now: 1570 * x2: *first string data 1571 * x1: *second string data 1572 * w3: iteration count 1573 * x0: return value if comparison equal 1574 * x4, x5, x6, x7: free 1575 */ 1576 1577 // Do a simple unrolled loop. 1578.Lloop: 1579 // At least two more elements? 1580 subs w3, w3, #2 1581 b.lt .Lremainder_or_done 1582 1583 ldrh w4, [x2], #2 1584 ldrh w5, [x1], #2 1585 1586 ldrh w6, [x2], #2 1587 ldrh w7, [x1], #2 1588 1589 subs w4, w4, w5 1590 b.ne .Lw4_result 1591 1592 subs w6, w6, w7 1593 b.ne .Lw6_result 1594 1595 b .Lloop 1596 1597.Lremainder_or_done: 1598 adds w3, w3, #1 1599 b.eq .Lremainder 1600 ret 1601 1602.Lremainder: 1603 ldrh w4, [x2], #2 1604 ldrh w5, [x1], #2 1605 subs w4, w4, w5 1606 b.ne .Lw4_result 1607 ret 1608 1609// Result is in w4 1610.Lw4_result: 1611 sxtw x0, w4 1612 ret 1613 1614// Result is in w6 1615.Lw6_result: 1616 sxtw x0, w6 1617 ret 1618 1619.Ldo_memcmp16: 1620 str x0, [sp,#-16]! // Save x0 1621 1622 mov x0, x2 1623 uxtw x2, w3 1624 bl __memcmp16 1625 1626 ldr x1, [sp], #16 // Restore old x0 = length diff 1627 1628 cmp x0, #0 // Check the memcmp difference 1629 csel x0, x0, x1, ne // x0 := x0 != 0 ? x0 : x1 1630 ret 1631END art_quick_string_compareto 1632