1%def header(): 2/* 3 * Copyright (C) 2020 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18/* 19 * This is a #include, not a %include, because we want the C pre-processor 20 * to expand the macros into assembler assignment statements. 21 */ 22#include "asm_support.h" 23#include "arch/arm64/asm_support_arm64.S" 24 25/** 26 * ARM64 Runtime register usage conventions. 27 * 28 * r0 : w0 is 32-bit return register and x0 is 64-bit. 29 * r0-r7 : Argument registers. 30 * r8-r15 : Caller save registers (used as temporary registers). 31 * r16-r17: Also known as ip0-ip1, respectively. Used as scratch registers by 32 * the linker, by the trampolines and other stubs (the compiler uses 33 * these as temporary registers). 34 * r18 : Reserved for platform (SCS, shadow call stack) 35 * r19 : Pointer to thread-local storage. 36 * r20-r29: Callee save registers. 37 * r30 : (lr) is reserved (the link register). 38 * rsp : (sp) is reserved (the stack pointer). 39 * rzr : (zr) is reserved (the zero register). 40 * 41 * Floating-point registers 42 * v0-v31 43 * 44 * v0 : s0 is return register for singles (32-bit) and d0 for doubles (64-bit). 45 * This is analogous to the C/C++ (hard-float) calling convention. 46 * v0-v7 : Floating-point argument registers in both Dalvik and C/C++ conventions. 47 * Also used as temporary and codegen scratch registers. 48 * 49 * v0-v7 and v16-v31 : Caller save registers (used as temporary registers). 50 * v8-v15 : bottom 64-bits preserved across C calls (d8-d15 are preserved). 51 * 52 * v16-v31: Used as codegen temp/scratch. 53 * v8-v15 : Can be used for promotion. 54 * 55 * Must maintain 16-byte stack alignment. 56 * 57 * Nterp notes: 58 * 59 * The following registers have fixed assignments: 60 * 61 * reg nick purpose 62 * x19 xSELF self (Thread) pointer 63 * x20 wMR marking register 64 * x29 xFP interpreted frame pointer, used for accessing locals and args 65 * x22 xPC interpreted program counter, used for fetching instructions 66 * x23 xINST first 16-bit code unit of current instruction 67 * x24 xIBASE interpreted instruction base pointer, used for computed goto 68 * x25 xREFS base of object references of dex registers. 69 * x16 ip scratch reg 70 * x17 ip2 scratch reg (used by macros) 71 * 72 * Macros are provided for common operations. They MUST NOT alter unspecified registers or 73 * condition codes. 74*/ 75 76/* single-purpose registers, given names for clarity */ 77#define xSELF x19 78#define CFI_DEX 22 // DWARF register number of the register holding dex-pc (xPC). 79#define CFI_TMP 0 // DWARF register number of the first argument register (r0). 80#define xPC x22 81#define xINST x23 82#define wINST w23 83#define xIBASE x24 84#define xREFS x25 85#define CFI_REFS 25 86#define ip x16 87#define ip2 x17 88#define wip w16 89#define wip2 w17 90 91// To avoid putting ifdefs arond the use of wMR, make sure it's defined. 92// IsNterpSupported returns false for configurations that don't have wMR (typically CMS). 93#ifndef wMR 94#define wMR w20 95#endif 96 97// Temporary registers while setting up a frame. 98#define xNEW_FP x26 99#define xNEW_REFS x27 100#define CFI_NEW_REFS 27 101 102// +8 for the ArtMethod of the caller. 103#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + 8) 104 105/* 106 * Fetch the next instruction from xPC into wINST. Does not advance xPC. 107 */ 108.macro FETCH_INST 109 ldrh wINST, [xPC] 110.endm 111 112/* 113 * Fetch the next instruction from the specified offset. Advances xPC 114 * to point to the next instruction. "count" is in 16-bit code units. 115 * 116 * Because of the limited size of immediate constants on ARM, this is only 117 * suitable for small forward movements (i.e. don't try to implement "goto" 118 * with this). 119 * 120 * This must come AFTER anything that can throw an exception, or the 121 * exception catch may miss. (This also implies that it must come after 122 * EXPORT_PC.) 123 */ 124.macro FETCH_ADVANCE_INST count 125 ldrh wINST, [xPC, #((\count)*2)]! 126.endm 127 128/* 129 * Similar to FETCH_ADVANCE_INST, but does not update xPC. Used to load 130 * xINST ahead of possible exception point. Be sure to manually advance xPC 131 * later. 132 */ 133.macro PREFETCH_INST count 134 ldrh wINST, [xPC, #((\count)*2)] 135.endm 136 137/* Advance xPC by some number of code units. */ 138.macro ADVANCE count 139 add xPC, xPC, #((\count)*2) 140.endm 141 142/* 143 * Fetch the next instruction from an offset specified by "reg" and advance xPC. 144 * xPC to point to the next instruction. "reg" must specify the distance 145 * in bytes, *not* 16-bit code units, and may be a signed value. 146 * 147 */ 148.macro FETCH_ADVANCE_INST_RB reg 149 add xPC, xPC, \reg, sxtw 150 ldrh wINST, [xPC] 151.endm 152 153/* 154 * Fetch a half-word code unit from an offset past the current PC. The 155 * "count" value is in 16-bit code units. Does not advance xPC. 156 * 157 * The "_S" variant works the same but treats the value as signed. 158 */ 159.macro FETCH reg, count 160 ldrh \reg, [xPC, #((\count)*2)] 161.endm 162 163.macro FETCH_S reg, count 164 ldrsh \reg, [xPC, #((\count)*2)] 165.endm 166 167/* 168 * Fetch one byte from an offset past the current PC. Pass in the same 169 * "count" as you would for FETCH, and an additional 0/1 indicating which 170 * byte of the halfword you want (lo/hi). 171 */ 172.macro FETCH_B reg, count, byte 173 ldrb \reg, [xPC, #((\count)*2+(\byte))] 174.endm 175 176/* 177 * Put the instruction's opcode field into the specified register. 178 */ 179.macro GET_INST_OPCODE reg 180 and \reg, xINST, #255 181.endm 182 183/* 184 * Begin executing the opcode in _reg. Clobbers reg 185 */ 186 187.macro GOTO_OPCODE reg 188 add \reg, xIBASE, \reg, lsl #${handler_size_bits} 189 br \reg 190.endm 191 192/* 193 * Get/set the 32-bit value from a Dalvik register. 194 */ 195.macro GET_VREG reg, vreg 196 ldr \reg, [xFP, \vreg, uxtw #2] 197.endm 198.macro GET_VREG_OBJECT reg, vreg 199 ldr \reg, [xREFS, \vreg, uxtw #2] 200.endm 201.macro SET_VREG reg, vreg 202 str \reg, [xFP, \vreg, uxtw #2] 203 str wzr, [xREFS, \vreg, uxtw #2] 204.endm 205.macro SET_VREG_OBJECT reg, vreg, tmpreg 206 str \reg, [xFP, \vreg, uxtw #2] 207 str \reg, [xREFS, \vreg, uxtw #2] 208.endm 209.macro SET_VREG_FLOAT reg, vreg 210 str \reg, [xFP, \vreg, uxtw #2] 211 str wzr, [xREFS, \vreg, uxtw #2] 212.endm 213 214/* 215 * Get/set the 64-bit value from a Dalvik register. 216 */ 217.macro GET_VREG_WIDE reg, vreg 218 add ip2, xFP, \vreg, uxtw #2 219 ldr \reg, [ip2] 220.endm 221.macro SET_VREG_WIDE reg, vreg 222 add ip2, xFP, \vreg, uxtw #2 223 str \reg, [ip2] 224 add ip2, xREFS, \vreg, uxtw #2 225 str xzr, [ip2] 226.endm 227.macro GET_VREG_DOUBLE reg, vreg 228 add ip2, xFP, \vreg, uxtw #2 229 ldr \reg, [ip2] 230.endm 231.macro SET_VREG_DOUBLE reg, vreg 232 add ip2, xFP, \vreg, uxtw #2 233 str \reg, [ip2] 234 add ip2, xREFS, \vreg, uxtw #2 235 str xzr, [ip2] 236.endm 237 238/* 239 * Get the 32-bit value from a Dalvik register and sign-extend to 64-bit. 240 * Used to avoid an extra instruction in int-to-long. 241 */ 242.macro GET_VREG_S reg, vreg 243 ldrsw \reg, [xFP, \vreg, uxtw #2] 244.endm 245 246// An assembly entry that has a OatQuickMethodHeader prefix. 247.macro OAT_ENTRY name, end 248 .type \name, #function 249 .hidden \name 250 .global \name 251 .balign 16 252 // Padding of 8 bytes to get 16 bytes alignment of code entry. 253 .long 0 254 .long 0 255 // OatQuickMethodHeader. 256 .long 0 257 .long (\end - \name) 258\name: 259.endm 260 261.macro SIZE name 262 .size \name, .-\name 263.endm 264 265.macro NAME_START name 266 .type \name, #function 267 .hidden \name // Hide this as a global symbol, so we do not incur plt calls. 268 .global \name 269 /* Cache alignment for function entry */ 270 .balign 16 271\name: 272.endm 273 274.macro NAME_END name 275 SIZE \name 276.endm 277 278// Macro for defining entrypoints into runtime. We don't need to save registers 279// (we're not holding references there), but there is no 280// kDontSave runtime method. So just use the kSaveRefsOnly runtime method. 281.macro NTERP_TRAMPOLINE name, helper 282ENTRY \name 283 SETUP_SAVE_REFS_ONLY_FRAME 284 bl \helper 285 RESTORE_SAVE_REFS_ONLY_FRAME 286 REFRESH_MARKING_REGISTER 287 RETURN_OR_DELIVER_PENDING_EXCEPTION 288END \name 289.endm 290 291.macro CLEAR_STATIC_VOLATILE_MARKER reg 292 and \reg, \reg, #-2 293.endm 294 295.macro CLEAR_INSTANCE_VOLATILE_MARKER reg 296 neg \reg, \reg 297.endm 298 299.macro EXPORT_PC 300 str xPC, [xREFS, #-16] 301.endm 302 303.macro BRANCH 304 // Update method counter and do a suspend check if the branch is negative. 305 tbnz wINST, #31, 2f 3061: 307 add w2, wINST, wINST // w2<- byte offset 308 FETCH_ADVANCE_INST_RB w2 // update xPC, load wINST 309 GET_INST_OPCODE ip // extract opcode from wINST 310 GOTO_OPCODE ip // jump to next instruction 3112: 312 ldr x0, [sp] 313 ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 314 add x2, x2, #1 315 and w2, w2, #NTERP_HOTNESS_MASK 316 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 317 // If the counter overflows, handle this in the runtime. 318 cbz w2, NterpHandleHotnessOverflow 319 // Otherwise, do a suspend check. 320 ldr x0, [xSELF, #THREAD_FLAGS_OFFSET] 321 ands x0, x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 322 b.eq 1b 323 EXPORT_PC 324 bl art_quick_test_suspend 325 b 1b 326.endm 327 328// Setup the stack to start executing the method. Expects: 329// - x0 to contain the ArtMethod 330// 331// Outputs 332// - ip contains the dex registers size 333// - x13 contains the old stack pointer. 334// 335// Uses ip, ip2, x13, x14 as temporaries. 336.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs 337 // Fetch dex register size. 338 ldrh wip, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET] 339 // Fetch outs size. 340 ldrh wip2, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET] 341 342 // Compute required frame size: ((2 * ip) + ip1) * 4 + 24 343 // 24 is for saving the previous frame, pc, and method being executed. 344 add x14, ip, ip 345 add x14, x14, ip2 346 lsl x14, x14, #2 347 add x14, x14, #24 348 349 // Compute new stack pointer in x14 350 sub x14, sp, x14 351 // Alignment 352 and x14, x14, #-16 353 354 // Set reference and dex registers, align to pointer size for previous frame and dex pc. 355 add \refs, x14, ip2, lsl #2 356 add \refs, \refs, 28 357 and \refs, \refs, #(-__SIZEOF_POINTER__) 358 add \fp, \refs, ip, lsl #2 359 360 // Now setup the stack pointer. 361 mov x13, sp 362 .cfi_def_cfa_register x13 363 mov sp, x14 364 str x13, [\refs, #-8] 365 CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -8, CALLEE_SAVES_SIZE 366 367 // Put nulls in reference frame. 368 cbz ip, 2f 369 mov ip2, \refs 3701: 371 str xzr, [ip2], #8 // May clear vreg[0]. 372 cmp ip2, \fp 373 b.lo 1b 3742: 375 // Save the ArtMethod. 376 str x0, [sp] 377.endm 378 379// Increase method hotness and do suspend check before starting executing the method. 380.macro START_EXECUTING_INSTRUCTIONS 381 ldr x0, [sp] 382 ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 383 add x2, x2, #1 384 and w2, w2, #NTERP_HOTNESS_MASK 385 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 386 // If the counter overflows, handle this in the runtime. 387 cbz w2, 2f 388 ldr x0, [xSELF, #THREAD_FLAGS_OFFSET] 389 tst x0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 390 b.ne 3f 3911: 392 FETCH_INST 393 GET_INST_OPCODE ip 394 GOTO_OPCODE ip 3952: 396 mov x1, xzr 397 mov x2, xFP 398 bl nterp_hot_method 399 b 1b 4003: 401 EXPORT_PC 402 bl art_quick_test_suspend 403 b 1b 404.endm 405 406.macro SPILL_ALL_CALLEE_SAVES 407 INCREASE_FRAME CALLEE_SAVES_SIZE 408 // Note: we technically don't need to save x19 and x20, 409 // but the runtime will expect those values to be there when unwinding 410 // (see Arm64Context::DoLongJump checking for the thread register). 411 SAVE_ALL_CALLEE_SAVES 0 412.endm 413 414.macro RESTORE_ALL_CALLEE_SAVES 415 // FP callee-saves 416 ldp d8, d9, [sp, #0] 417 ldp d10, d11, [sp, #16] 418 ldp d12, d13, [sp, #32] 419 ldp d14, d15, [sp, #48] 420 421 // GP callee-saves. 422 // No need to restore x19 (it's always the thread), and 423 // don't restore x20 (the marking register) as it may have been updated. 424 RESTORE_TWO_REGS x21, x22, 80 425 RESTORE_TWO_REGS x23, x24, 96 426 RESTORE_TWO_REGS x25, x26, 112 427 RESTORE_TWO_REGS x27, x28, 128 428 RESTORE_TWO_REGS x29, lr, 144 429 430 DECREASE_FRAME CALLEE_SAVES_SIZE 431.endm 432 433.macro SPILL_ALL_ARGUMENTS 434 INCREASE_FRAME 128 435 // GP arguments. 436 SAVE_TWO_REGS x0, x1, 0 437 SAVE_TWO_REGS x2, x3, 16 438 SAVE_TWO_REGS x4, x5, 32 439 SAVE_TWO_REGS x6, x7, 48 440 441 // FP arguments 442 stp d0, d1, [sp, #64] 443 stp d2, d3, [sp, #80] 444 stp d4, d5, [sp, #96] 445 stp d6, d7, [sp, #112] 446.endm 447 448.macro RESTORE_ALL_ARGUMENTS 449 // GP arguments. 450 RESTORE_TWO_REGS x0, x1, 0 451 RESTORE_TWO_REGS x2, x3, 16 452 RESTORE_TWO_REGS x4, x5, 32 453 RESTORE_TWO_REGS x6, x7, 48 454 455 // FP arguments 456 ldp d0, d1, [sp, #64] 457 ldp d2, d3, [sp, #80] 458 ldp d4, d5, [sp, #96] 459 ldp d6, d7, [sp, #112] 460 DECREASE_FRAME 128 461.endm 462 463// Helper to setup the stack after doing a nterp to nterp call. This will setup: 464// - xNEW_FP: the new pointer to dex registers 465// - xNEW_REFS: the new pointer to references 466// - xPC: the new PC pointer to execute 467// - x2: value in instruction to decode the number of arguments. 468// - x3: first dex register 469// - x4: top of dex register array 470// 471// The method expects: 472// - x0 to contain the ArtMethod 473// - x8 to contain the code item 474.macro SETUP_STACK_FOR_INVOKE 475 // We do the same stack overflow check as the compiler. See CanMethodUseNterp 476 // in how we limit the maximum nterp frame size. 477 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES 478 ldr wzr, [x16] 479 480 // Spill all callee saves to have a consistent stack frame whether we 481 // are called by compiled code or nterp. 482 SPILL_ALL_CALLEE_SAVES 483 484 // Setup the frame. 485 SETUP_STACK_FRAME x8, xNEW_REFS, xNEW_FP, CFI_NEW_REFS 486 // Make x4 point to the top of the dex register array. 487 add x4, xNEW_FP, ip, uxtx #2 488 489 // Fetch instruction information before replacing xPC. 490 // TODO: move this down to the method that uses it, fetching it directly from wINST. 491 FETCH_B w2, 0, 1 492 // TODO: we could avoid this as instance invokes already fetch it. 493 FETCH w3, 2 494 495 // Set the dex pc pointer. 496 add xPC, x8, #CODE_ITEM_INSNS_OFFSET 497 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 498.endm 499 500// Setup arguments based on a non-range nterp to nterp call, and start executing 501// the method. We expect: 502// - xNEW_FP: the new pointer to dex registers 503// - xNEW_REFS: the new pointer to references 504// - xPC: the new PC pointer to execute 505// - x2: number of arguments (bits 4-7), 5th argument if any (bits 0-3) 506// - x3: first dex register 507// - x4: top of dex register array 508// - x1: receiver if non-static. 509.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 510 // /* op vA, vB, {vC...vG} */ 511 asr ip2, x2, #4 512 cbz ip2, 6f 513 mov ip, #-4 514 cmp ip2, #2 515 b.lt 1f 516 b.eq 2f 517 cmp ip2, #4 518 b.lt 3f 519 b.eq 4f 520 521 // We use a decrementing ip to store references relative 522 // to xNEW_FP and dex registers relative to x4 523 // 524 // TODO: We could set up ip as the number of registers (this can be an additional output from 525 // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg. 526 // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS. 5275: 528 and x2, x2, #15 529 GET_VREG_OBJECT w5, w2 530 str w5, [xNEW_FP, ip] 531 GET_VREG w5, w2 532 str w5, [x4, ip] 533 sub ip, ip, #4 5344: 535 asr x2, x3, #12 536 GET_VREG_OBJECT w5, w2 537 str w5, [xNEW_FP, ip] 538 GET_VREG w5, w2 539 str w5, [x4, ip] 540 sub ip, ip, #4 5413: 542 ubfx x2, x3, #8, #4 543 GET_VREG_OBJECT w5, w2 544 str w5, [xNEW_FP, ip] 545 GET_VREG w5, w2 546 str w5, [x4, ip] 547 sub ip, ip, #4 5482: 549 ubfx x2, x3, #4, #4 550 GET_VREG_OBJECT w5, w2 551 str w5, [xNEW_FP, ip] 552 GET_VREG w5, w2 553 str w5, [x4, ip] 554 .if !\is_string_init 555 sub ip, ip, #4 556 .endif 5571: 558 .if \is_string_init 559 // Ignore the first argument 560 .elseif \is_static 561 and x2, x3, #0xf 562 GET_VREG_OBJECT w5, w2 563 str w5, [xNEW_FP, ip] 564 GET_VREG w5, w2 565 str w5, [x4, ip] 566 .else 567 str w1, [xNEW_FP, ip] 568 str w1, [x4, ip] 569 .endif 570 5716: 572 // Start executing the method. 573 mov xFP, xNEW_FP 574 mov xREFS, xNEW_REFS 575 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE 576 START_EXECUTING_INSTRUCTIONS 577.endm 578 579// Setup arguments based on a range nterp to nterp call, and start executing 580// the method. 581// - xNEW_FP: the new pointer to dex registers 582// - xNEW_REFS: the new pointer to references 583// - xPC: the new PC pointer to execute 584// - x2: number of arguments 585// - x3: first dex register 586// - x4: top of dex register array 587// - x1: receiver if non-static. 588// 589// Uses ip, ip2, x5, x6 as temporaries. 590.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 591 mov ip, #-4 592 .if \is_string_init 593 // Ignore the first argument 594 sub x2, x2, #1 595 add x3, x3, #1 596 .elseif !\is_static 597 sub x2, x2, #1 598 add x3, x3, #1 599 .endif 600 601 cbz x2, 2f 602 add ip2, xREFS, x3, lsl #2 // pointer to first argument in reference array 603 add ip2, ip2, x2, lsl #2 // pointer to last argument in reference array 604 add x5, xFP, x3, lsl #2 // pointer to first argument in register array 605 add x6, x5, x2, lsl #2 // pointer to last argument in register array 6061: 607 ldr w7, [ip2, #-4]! 608 str w7, [xNEW_FP, ip] 609 sub x2, x2, 1 610 ldr w7, [x6, #-4]! 611 str w7, [x4, ip] 612 sub ip, ip, 4 613 cbnz x2, 1b 6142: 615 .if \is_string_init 616 // Ignore first argument 617 .elseif !\is_static 618 str w1, [xNEW_FP, ip] 619 str w1, [x4, ip] 620 .endif 621 mov xFP, xNEW_FP 622 mov xREFS, xNEW_REFS 623 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE 624 START_EXECUTING_INSTRUCTIONS 625.endm 626 627.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom 628 stp x0, x1, [sp, #-16]! 629 .if \is_polymorphic 630 ldr x0, [sp, #16] 631 mov x1, xPC 632 bl NterpGetShortyFromInvokePolymorphic 633 .elseif \is_custom 634 ldr x0, [sp, #16] 635 mov x1, xPC 636 bl NterpGetShortyFromInvokeCustom 637 .elseif \is_interface 638 ldr x0, [sp, #16] 639 FETCH w1, 1 640 bl NterpGetShortyFromMethodId 641 .else 642 bl NterpGetShorty 643 .endif 644 mov \dest, x0 645 ldp x0, x1, [sp], #16 646.endm 647 648// Output: x8 contains the code item 649.macro GET_CODE_ITEM 650 // TODO: Get code item in a better way. 651 stp x0, x1, [sp, #-16]! 652 bl NterpGetCodeItem 653 mov x8, x0 654 ldp x0, x1, [sp], #16 655.endm 656 657.macro DO_ENTRY_POINT_CHECK call_compiled_code 658 // On entry, the method is x0, the instance is x1 659 adr x2, ExecuteNterpImpl 660 ldr x3, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 661 cmp x2, x3 662 b.ne \call_compiled_code 663.endm 664 665.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value 666 mov wip, wzr 6671: 668 GET_VREG_OBJECT wip2, wip 669 cmp wip2, \old_value 670 b.ne 2f 671 SET_VREG_OBJECT \new_value, wip 6722: 673 add wip, wip, #1 674 add ip2, xREFS, wip, uxtw #2 675 cmp ip2, xFP 676 b.ne 1b 677.endm 678 679// Puts the next floating point argument into the expected register, 680// fetching values based on a non-range invoke. 681// Uses ip and ip2. 682.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished 6831: // LOOP 684 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 685 cbz wip, \finished // if (wip == '\0') goto finished 686 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 687 b.eq 2f 688 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 689 b.eq 3f 690 lsr \inst, \inst, #4 691 add \arg_index, \arg_index, #1 692 // Handle extra argument in arg array taken by a long. 693 cmp wip, #74 // if (wip != 'J') goto LOOP 694 b.ne 1b 695 lsr \inst, \inst, #4 696 add \arg_index, \arg_index, #1 697 b 1b // goto LOOP 6982: // FOUND_DOUBLE 699 and ip, \inst, #0xf 700 GET_VREG wip, wip 701 lsr \inst, \inst, #4 702 add \arg_index, \arg_index, #1 703 cmp \arg_index, #4 704 b.eq 5f 705 and ip2, \inst, #0xf 706 lsr \inst, \inst, #4 707 add \arg_index, \arg_index, #1 708 b 6f 7095: 710 // TODO: Extract from wINST here and below? (Requires using a different register 711 // in the COMMON_INVOKE_NON_RANGE.) 712 FETCH_B wip2, 0, 1 713 and wip2, wip2, #0xf 7146: 715 GET_VREG wip2, wip2 716 add ip, ip, ip2, lsl #32 717 fmov \dreg, ip 718 b 4f 7193: // FOUND_FLOAT 720 cmp \arg_index, #4 721 b.eq 7f 722 and ip, \inst, #0xf 723 lsr \inst, \inst, #4 724 add \arg_index, \arg_index, #1 725 b 8f 7267: 727 FETCH_B wip, 0, 1 728 and wip, wip, #0xf 7298: 730 GET_VREG \sreg, wip 7314: 732.endm 733 734// Puts the next int/long/object argument in the expected register, 735// fetching values based on a non-range invoke. 736// Uses ip and ip2. 737.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished 7381: // LOOP 739 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 740 cbz wip, \finished // if (wip == '\0') goto finished 741 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 742 b.eq 2f 743 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 744 b.eq 3f 745 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 746 b.eq 4f 747 cmp \arg_index, #4 748 b.eq 7f 749 and ip, \inst, #0xf 750 lsr \inst, \inst, #4 751 add \arg_index, \arg_index, #1 752 b 8f 7537: 754 FETCH_B wip, 0, 1 755 and wip, wip, #0xf 7568: 757 GET_VREG \gpr_reg32, wip 758 b 5f 7592: // FOUND_LONG 760 and ip, \inst, #0xf 761 GET_VREG wip, wip 762 lsr \inst, \inst, #4 763 add \arg_index, \arg_index, #1 764 cmp \arg_index, #4 765 b.eq 9f 766 and ip2, \inst, #0xf 767 lsr \inst, \inst, #4 768 add \arg_index, \arg_index, #1 769 b 10f 7709: 771 FETCH_B wip2, 0, 1 772 and wip2, wip2, #0xf 77310: 774 GET_VREG wip2, wip2 775 add \gpr_reg64, ip, ip2, lsl #32 776 b 5f 7773: // SKIP_FLOAT 778 lsr \inst, \inst, #4 779 add \arg_index, \arg_index, #1 780 b 1b 7814: // SKIP_DOUBLE 782 lsr \inst, \inst, #4 783 add \arg_index, \arg_index, #1 784 cmp \arg_index, #4 785 b.eq 1b 786 lsr \inst, \inst, #4 787 add \arg_index, \arg_index, #1 788 b 1b 7895: 790.endm 791 792.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 793 .if \is_polymorphic 794 // We always go to compiled code for polymorphic calls. 795 .elseif \is_custom 796 // We always go to compiled code for custom calls. 797 .else 798 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix 799 GET_CODE_ITEM 800 .if \is_string_init 801 bl nterp_to_nterp_string_init_non_range 802 .elseif \is_static 803 bl nterp_to_nterp_static_non_range 804 .else 805 bl nterp_to_nterp_instance_non_range 806 .endif 807 b .Ldone_return_\suffix 808 .endif 809 810.Lcall_compiled_code_\suffix: 811 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom 812 // From this point: 813 // - xINST contains shorty (in callee-save to switch over return value after call). 814 // - x0 contains method 815 // - x1 contains 'this' pointer for instance method. 816 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 817 FETCH w11, 2 // arguments 818 .if \is_string_init 819 lsr x11, x11, #4 820 mov x10, #1 // ignore first argument 821 .elseif \is_static 822 mov x10, xzr // arg_index 823 .else 824 lsr x11, x11, #4 825 mov x10, #1 // ignore first argument 826 .endif 827 LOOP_OVER_SHORTY_LOADING_FPS d0, s0, x11, x9, x10, .Lxmm_setup_finished_\suffix 828 LOOP_OVER_SHORTY_LOADING_FPS d1, s1, x11, x9, x10, .Lxmm_setup_finished_\suffix 829 LOOP_OVER_SHORTY_LOADING_FPS d2, s2, x11, x9, x10, .Lxmm_setup_finished_\suffix 830 LOOP_OVER_SHORTY_LOADING_FPS d3, s3, x11, x9, x10, .Lxmm_setup_finished_\suffix 831 LOOP_OVER_SHORTY_LOADING_FPS d4, s4, x11, x9, x10, .Lxmm_setup_finished_\suffix 832.Lxmm_setup_finished_\suffix: 833 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 834 FETCH w11, 2 // arguments 835 .if \is_string_init 836 lsr x11, x11, #4 837 mov x10, #1 // ignore first argument 838 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix 839 .elseif \is_static 840 mov x10, xzr // arg_index 841 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix 842 .else 843 lsr x11, x11, #4 844 mov x10, #1 // ignore first argument 845 .endif 846 LOOP_OVER_SHORTY_LOADING_GPRS x2, w2, x11, x9, x10, .Lgpr_setup_finished_\suffix 847 LOOP_OVER_SHORTY_LOADING_GPRS x3, w3, x11, x9, x10, .Lgpr_setup_finished_\suffix 848 LOOP_OVER_SHORTY_LOADING_GPRS x4, w4, x11, x9, x10, .Lgpr_setup_finished_\suffix 849 LOOP_OVER_SHORTY_LOADING_GPRS x5, w5, x11, x9, x10, .Lgpr_setup_finished_\suffix 850.Lgpr_setup_finished_\suffix: 851 .if \is_polymorphic 852 bl art_quick_invoke_polymorphic 853 .elseif \is_custom 854 bl art_quick_invoke_custom 855 .else 856 .if \is_interface 857 // Setup hidden argument 858 FETCH wip2, 1 859 .endif 860 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 861 blr lr 862 .endif 863 ldrb wip, [xINST] 864 cmp ip, #68 // Test if result type char == 'D'. 865 b.eq .Lreturn_double_\suffix 866 cmp ip, #70 867 b.ne .Ldone_return_\suffix 868.Lreturn_float_\suffix: 869 fmov w0, s0 870 b .Ldone_return_\suffix 871.Lreturn_double_\suffix: 872 fmov x0, d0 873.Ldone_return_\suffix: 874 /* resume execution of caller */ 875 .if \is_string_init 876 FETCH w11, 2 // arguments 877 and x11, x11, #0xf 878 GET_VREG w1, w11 879 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0 880 .endif 881 882 .if \is_polymorphic 883 FETCH_ADVANCE_INST 4 884 .else 885 FETCH_ADVANCE_INST 3 886 .endif 887 GET_INST_OPCODE ip 888 GOTO_OPCODE ip 889.endm 890 891// Puts the next floating point argument into the expected register, 892// fetching values based on a range invoke. 893// Uses ip as temporary. 894.macro LOOP_RANGE_OVER_SHORTY_LOADING_FPS dreg, sreg, shorty, arg_index, stack_index, finished 8951: // LOOP 896 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 897 cbz wip, \finished // if (wip == '\0') goto finished 898 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 899 b.eq 2f 900 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 901 b.eq 3f 902 add \arg_index, \arg_index, #1 903 add \stack_index, \stack_index, #1 904 // Handle extra argument in arg array taken by a long. 905 cmp wip, #74 // if (wip != 'J') goto LOOP 906 b.ne 1b 907 add \arg_index, \arg_index, #1 908 add \stack_index, \stack_index, #1 909 b 1b // goto LOOP 9102: // FOUND_DOUBLE 911 GET_VREG_DOUBLE \dreg, \arg_index 912 add \arg_index, \arg_index, #2 913 add \stack_index, \stack_index, #2 914 b 4f 9153: // FOUND_FLOAT 916 GET_VREG \sreg, \arg_index 917 add \arg_index, \arg_index, #1 918 add \stack_index, \stack_index, #1 9194: 920.endm 921 922// Puts the next floating point argument into the expected stack slot, 923// fetching values based on a range invoke. 924// Uses ip as temporary. 925// 926// TODO: We could just copy all the vregs to the stack slots in a simple loop 927// without looking at the shorty at all. (We could also drop 928// the "stack_index" from the macros for loading registers.) We could also do 929// that conditionally if argument word count > 6; otherwise we know that all 930// args fit into registers. 931.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished 9321: // LOOP 933 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 934 cbz wip, \finished // if (wip == '\0') goto finished 935 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 936 b.eq 2f 937 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 938 b.eq 3f 939 add \arg_index, \arg_index, #1 940 add \stack_index, \stack_index, #1 941 // Handle extra argument in arg array taken by a long. 942 cmp wip, #74 // if (wip != 'J') goto LOOP 943 b.ne 1b 944 add \arg_index, \arg_index, #1 945 add \stack_index, \stack_index, #1 946 b 1b // goto LOOP 9472: // FOUND_DOUBLE 948 GET_VREG_WIDE ip, \arg_index 949 add ip2, sp, \stack_index, uxtw #2 950 str ip, [ip2] 951 add \arg_index, \arg_index, #2 952 add \stack_index, \stack_index, #2 953 b 1b 9543: // FOUND_FLOAT 955 GET_VREG wip, \arg_index 956 str wip, [sp, \stack_index, uxtw #2] 957 add \arg_index, \arg_index, #1 958 add \stack_index, \stack_index, #1 959 b 1b 960.endm 961 962// Puts the next int/long/object argument in the expected register, 963// fetching values based on a range invoke. 964// Uses ip as temporary. 965.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg64, reg32, shorty, arg_index, stack_index, finished 9661: // LOOP 967 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 968 cbz wip, \finished // if (wip == '\0') goto finished 969 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 970 b.eq 2f 971 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 972 b.eq 3f 973 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 974 b.eq 4f 975 GET_VREG \reg32, \arg_index 976 add \arg_index, \arg_index, #1 977 add \stack_index, \stack_index, #1 978 b 5f 9792: // FOUND_LONG 980 GET_VREG_WIDE \reg64, \arg_index 981 add \arg_index, \arg_index, #2 982 add \stack_index, \stack_index, #2 983 b 5f 9843: // SKIP_FLOAT 985 add \arg_index, \arg_index, #1 986 add \stack_index, \stack_index, #1 987 b 1b 9884: // SKIP_DOUBLE 989 add \arg_index, \arg_index, #2 990 add \stack_index, \stack_index, #2 991 b 1b 9925: 993.endm 994 995// Puts the next int/long/object argument in the expected stack slot, 996// fetching values based on a range invoke. 997// Uses ip as temporary. 998.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished 9991: // LOOP 1000 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1001 cbz wip, \finished // if (wip == '\0') goto finished 1002 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 1003 b.eq 2f 1004 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 1005 b.eq 3f 1006 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 1007 b.eq 4f 1008 GET_VREG wip, \arg_index 1009 str wip, [sp, \stack_index, uxtw #2] 1010 add \arg_index, \arg_index, #1 1011 add \stack_index, \stack_index, #1 1012 b 1b 10132: // FOUND_LONG 1014 GET_VREG_WIDE ip, \arg_index 1015 add ip2, sp, \stack_index, uxtw #2 1016 str ip, [ip2] 1017 add \arg_index, \arg_index, #2 1018 add \stack_index, \stack_index, #2 1019 b 1b 10203: // SKIP_FLOAT 1021 add \arg_index, \arg_index, #1 1022 add \stack_index, \stack_index, #1 1023 b 1b 10244: // SKIP_DOUBLE 1025 add \arg_index, \arg_index, #2 1026 add \stack_index, \stack_index, #2 1027 b 1b 1028.endm 1029 1030.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 1031 .if \is_polymorphic 1032 // We always go to compiled code for polymorphic calls. 1033 .elseif \is_custom 1034 // We always go to compiled code for custom calls. 1035 .else 1036 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix 1037 GET_CODE_ITEM 1038 .if \is_string_init 1039 bl nterp_to_nterp_string_init_range 1040 .elseif \is_static 1041 bl nterp_to_nterp_static_range 1042 .else 1043 bl nterp_to_nterp_instance_range 1044 .endif 1045 b .Ldone_return_range_\suffix 1046 .endif 1047 1048.Lcall_compiled_code_range_\suffix: 1049 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom 1050 // From this point: 1051 // - xINST contains shorty (in callee-save to switch over return value after call). 1052 // - x0 contains method 1053 // - x1 contains 'this' pointer for instance method. 1054 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 1055 FETCH w10, 2 // arguments 1056 .if \is_string_init 1057 add x10, x10, #1 // arg start index 1058 mov x11, #1 // index in stack 1059 .elseif \is_static 1060 mov x11, xzr // index in stack 1061 .else 1062 add x10, x10, #1 // arg start index 1063 mov x11, #1 // index in stack 1064 .endif 1065 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d0, s0, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1066 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d1, s1, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1067 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d2, s2, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1068 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d3, s3, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1069 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d4, s4, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1070 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d5, s5, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1071 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d6, s6, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1072 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d7, s7, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1073 // Store in the outs array (stored above the ArtMethod in the stack) 1074 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs. 1075 LOOP_RANGE_OVER_FPs x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1076.Lxmm_setup_finished_range_\suffix: 1077 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 1078 FETCH w10, 2 // arguments 1079 .if \is_string_init 1080 add x10, x10, #1 // arg start index 1081 mov x11, #1 // index in stack 1082 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11, .Lgpr_setup_finished_\suffix 1083 .elseif \is_static 1084 mov x11, xzr // index in stack 1085 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11 .Lgpr_setup_finished_\suffix 1086 .else 1087 add x10, x10, #1 // arg start index 1088 mov x11, #1 // index in stack 1089 .endif 1090 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x2, w2, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1091 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x3, w3, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1092 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x4, w4, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1093 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x5, w5, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1094 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x6, w6, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1095 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x7, w7, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1096 // Store in the outs array (stored above the ArtMethod in the stack) 1097 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs. 1098 LOOP_RANGE_OVER_INTs x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1099.Lgpr_setup_finished_range_\suffix: 1100 .if \is_polymorphic 1101 bl art_quick_invoke_polymorphic 1102 .elseif \is_custom 1103 bl art_quick_invoke_custom 1104 .else 1105 .if \is_interface 1106 // Setup hidden argument 1107 FETCH wip2, 1 1108 .endif 1109 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 1110 blr lr 1111 .endif 1112 ldrb wip, [xINST] 1113 cmp ip, #68 // Test if result type char == 'D'. 1114 b.eq .Lreturn_double_range_\suffix 1115 cmp ip, #70 1116 b.ne .Ldone_return_\suffix 1117.Lreturn_float_range_\suffix: 1118 fmov w0, s0 1119 b .Ldone_return_range_\suffix 1120.Lreturn_double_range_\suffix: 1121 fmov x0, d0 1122.Ldone_return_range_\suffix: 1123 /* resume execution of caller */ 1124 .if \is_string_init 1125 FETCH w11, 2 // arguments 1126 GET_VREG w1, w11 1127 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0 1128 .endif 1129 1130 .if \is_polymorphic 1131 FETCH_ADVANCE_INST 4 1132 .else 1133 FETCH_ADVANCE_INST 3 1134 .endif 1135 GET_INST_OPCODE ip 1136 GOTO_OPCODE ip 1137.endm 1138 1139// Fetch some information from the thread cache. 1140// Uses ip and ip2 as temporaries. 1141.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path 1142 add ip, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET // cache address 1143 ubfx ip2, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2 // entry index 1144 add ip, ip, ip2, lsl #4 // entry address within the cache 1145 ldp ip, \dest_reg, [ip] // entry key (pc) and value (offset) 1146 cmp ip, xPC 1147 b.ne \slow_path 1148.endm 1149 1150// Helper for static field get. 1151.macro OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide="0" 1152 // Fast-path which gets the field from thread-local cache. 1153 FETCH_FROM_THREAD_CACHE x0, 4f 11541: 1155 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1156 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1157 cbnz wMR, 3f 11582: 1159 lsr w2, wINST, #8 // w2 <- A 1160 .if \wide 1161 ldr x0, [x0, x1] 1162 SET_VREG_WIDE x0, w2 // fp[A] <- value 1163 .else 1164 \load w0, [x0, x1] 1165 SET_VREG w0, w2 // fp[A] <- value 1166 .endif 1167 FETCH_ADVANCE_INST 2 1168 GET_INST_OPCODE ip 1169 GOTO_OPCODE ip 11703: 1171 bl art_quick_read_barrier_mark_reg00 1172 b 2b 11734: 1174 mov x0, xSELF 1175 ldr x1, [sp] 1176 mov x2, xPC 1177 EXPORT_PC 1178 bl nterp_get_static_field 1179 tbz x0, #0, 1b 1180 CLEAR_STATIC_VOLATILE_MARKER x0 1181 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1182 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1183 cbnz wMR, 7f 11845: 1185 lsr w2, wINST, #8 // w2 <- A 1186 add x0, x0, x1 1187 .if \wide 1188 ldar x0, [x0] 1189 SET_VREG_WIDE x0, w2 // fp[A] <- value 1190 .else 1191 \volatile_load w0, [x0] 1192 \maybe_extend 1193 SET_VREG w0, w2 // fp[A] <- value 1194 .endif 1195 FETCH_ADVANCE_INST 2 1196 GET_INST_OPCODE ip 1197 GOTO_OPCODE ip 11987: 1199 bl art_quick_read_barrier_mark_reg00 1200 b 5b 1201.endm 1202 1203// Helper for static field put. 1204.macro OP_SPUT store="str", volatile_store="stlr", wide="0": 1205 // Fast-path which gets the field from thread-local cache. 1206 FETCH_FROM_THREAD_CACHE x0, 4f 12071: 1208 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1209 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1210 cbnz wMR, 3f 12112: 1212 lsr w2, wINST, #8 // w2 <- A 1213 .if \wide 1214 GET_VREG_WIDE x2, w2 // x2 <- v[A] 1215 \store x2, [x0, x1] 1216 .else 1217 GET_VREG w2, w2 // w2 <- v[A] 1218 \store w2, [x0, x1] 1219 .endif 1220 FETCH_ADVANCE_INST 2 1221 GET_INST_OPCODE ip 1222 GOTO_OPCODE ip 12233: 1224 bl art_quick_read_barrier_mark_reg00 1225 b 2b 12264: 1227 mov x0, xSELF 1228 ldr x1, [sp] 1229 mov x2, xPC 1230 EXPORT_PC 1231 bl nterp_get_static_field 1232 tbz x0, #0, 1b 1233 CLEAR_STATIC_VOLATILE_MARKER x0 1234 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1235 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1236 cbnz wMR, 6f 12375: 1238 lsr w2, wINST, #8 // w2 <- A 1239 add x0, x0, x1 1240 .if \wide 1241 GET_VREG_WIDE x2, w2 // x2 <- v[A] 1242 \volatile_store x2, [x0] 1243 .else 1244 GET_VREG w2, w2 // w2 <- v[A] 1245 \volatile_store w2, [x0] 1246 .endif 1247 FETCH_ADVANCE_INST 2 1248 GET_INST_OPCODE ip 1249 GOTO_OPCODE ip 12506: 1251 bl art_quick_read_barrier_mark_reg00 1252 b 5b 1253.endm 1254 1255 1256// Helper for instance field put. 1257.macro OP_IPUT store="str", volatile_store="stlr", wide="0": 1258 // Fast-path which gets the field from thread-local cache. 1259 FETCH_FROM_THREAD_CACHE x0, 2f 12601: 1261 ubfx w1, wINST, #8, #4 // w1<- A 1262 lsr w2, wINST, #12 // w2<- B 1263 GET_VREG w2, w2 // vB (object we're operating on) 1264 cbz w2, common_errNullObject 1265 .if \wide 1266 GET_VREG_WIDE x1, w1 // x1<- fp[A]/fp[A+1] 1267 \store x1, [x2, x0] 1268 .else 1269 GET_VREG w1, w1 // w1 <- v[A] 1270 \store w1, [x2, x0] 1271 .endif 1272 FETCH_ADVANCE_INST 2 1273 GET_INST_OPCODE ip 1274 GOTO_OPCODE ip 12752: 1276 mov x0, xSELF 1277 ldr x1, [sp] 1278 mov x2, xPC 1279 EXPORT_PC 1280 bl nterp_get_instance_field_offset 1281 tbz w0, #31, 1b 1282 CLEAR_INSTANCE_VOLATILE_MARKER w0 1283 ubfx w1, wINST, #8, #4 // w1<- A 1284 lsr w2, wINST, #12 // w2<- B 1285 GET_VREG w2, w2 // vB (object we're operating on) 1286 cbz w2, common_errNullObject 1287 add x2, x2, x0 1288 .if \wide 1289 GET_VREG_WIDE x1, w1 // x1<- fp[A]/fp[A+1] 1290 \volatile_store x1, [x2] 1291 .else 1292 GET_VREG w1, w1 // w1 <- v[A] 1293 \volatile_store w1, [x2] 1294 .endif 1295 FETCH_ADVANCE_INST 2 1296 GET_INST_OPCODE ip 1297 GOTO_OPCODE ip 1298.endm 1299 1300// Helper for instance field get. 1301.macro OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide="0" 1302 // Fast-path which gets the field from thread-local cache. 1303 FETCH_FROM_THREAD_CACHE x0, 2f 13041: 1305 lsr w2, wINST, #12 // w2<- B 1306 GET_VREG w3, w2 // w3<- object we're operating on 1307 ubfx w2, wINST, #8, #4 // w2<- A 1308 cbz w3, common_errNullObject // object was null 1309 .if \wide 1310 \load x0, [x3, x0] 1311 SET_VREG_WIDE x0, w2 // fp[A] <- value 1312 .else 1313 \load w0, [x3, x0] 1314 SET_VREG w0, w2 // fp[A] <- value 1315 .endif 1316 FETCH_ADVANCE_INST 2 1317 GET_INST_OPCODE ip 1318 GOTO_OPCODE ip 13192: 1320 mov x0, xSELF 1321 ldr x1, [sp] 1322 mov x2, xPC 1323 EXPORT_PC 1324 bl nterp_get_instance_field_offset 1325 tbz w0, #31, 1b 1326 CLEAR_INSTANCE_VOLATILE_MARKER w0 1327 lsr w2, wINST, #12 // w2<- B 1328 GET_VREG w3, w2 // w3<- object we're operating on 1329 ubfx w2, wINST, #8, #4 // w2<- A 1330 cbz w3, common_errNullObject // object was null 1331 add x3, x3, x0 1332 .if \wide 1333 \volatile_load x0, [x3] 1334 SET_VREG_WIDE x0, w2 // fp[A] <- value 1335 .else 1336 \volatile_load w0, [x3] 1337 \maybe_extend 1338 SET_VREG w0, w2 // fp[A] <- value 1339 .endif 1340 FETCH_ADVANCE_INST 2 1341 GET_INST_OPCODE ip 1342 GOTO_OPCODE ip 1343.endm 1344 1345// Puts the next int/long/object parameter passed in physical register 1346// in the expected dex register array entry, and in case of object in the 1347// expected reference array entry. 1348.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_64, gpr_32, shorty, arg_offset, regs, refs, finished 13491: // LOOP 1350 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1351 cbz wip, \finished // if (wip == '\0') goto finished 1352 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 1353 b.eq 2f 1354 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 1355 b.eq 3f 1356 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 1357 b.eq 4f 1358 str \gpr_32, [\regs, \arg_offset] 1359 cmp wip, #76 // if (wip != 'L') goto NOT_REFERENCE 1360 b.ne 6f 1361 str \gpr_32, [\refs, \arg_offset] 13626: // NOT_REFERENCE 1363 add \arg_offset, \arg_offset, #4 1364 b 5f 13652: // FOUND_LONG 1366 str \gpr_64, [\regs, \arg_offset] 1367 add \arg_offset, \arg_offset, #8 1368 b 5f 13693: // SKIP_FLOAT 1370 add \arg_offset, \arg_offset, #4 1371 b 1b 13724: // SKIP_DOUBLE 1373 add \arg_offset, \arg_offset, #8 1374 b 1b 13755: 1376.endm 1377 1378// Puts the next floating point parameter passed in physical register 1379// in the expected dex register array entry. 1380// Uses ip as temporary. 1381.macro LOOP_OVER_SHORTY_STORING_FPS dreg, sreg, shorty, arg_offset, fp, finished 13821: // LOOP 1383 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1384 cbz wip, \finished // if (wip == '\0') goto finished 1385 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 1386 b.eq 2f 1387 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 1388 b.eq 3f 1389 add \arg_offset, \arg_offset, #4 1390 // Handle extra argument in arg array taken by a long. 1391 cmp wip, #74 // if (wip != 'J') goto LOOP 1392 b.ne 1b 1393 add \arg_offset, \arg_offset, #4 1394 b 1b // goto LOOP 13952: // FOUND_DOUBLE 1396 str \dreg, [\fp, \arg_offset] 1397 add \arg_offset, \arg_offset, #8 1398 b 4f 13993: // FOUND_FLOAT 1400 str \sreg, [\fp, \arg_offset] 1401 add \arg_offset, \arg_offset, #4 14024: 1403.endm 1404 1405// Puts the next floating point parameter passed in stack 1406// in the expected dex register array entry. 1407// Uses ip as temporary. 1408// 1409// TODO: Or we could just spill regs to the reserved slots in the caller's 1410// frame and copy all regs in a simple loop. This time, however, we would 1411// need to look at the shorty anyway to look for the references. 1412// (The trade-off is different for passing arguments and receiving them.) 1413.macro LOOP_OVER_FPs shorty, arg_offset, regs, stack_ptr, finished 14141: // LOOP 1415 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1416 cbz wip, \finished // if (wip == '\0') goto finished 1417 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 1418 b.eq 2f 1419 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 1420 b.eq 3f 1421 add \arg_offset, \arg_offset, #4 1422 // Handle extra argument in arg array taken by a long. 1423 cmp wip, #74 // if (wip != 'J') goto LOOP 1424 b.ne 1b 1425 add \arg_offset, \arg_offset, #4 1426 b 1b // goto LOOP 14272: // FOUND_DOUBLE 1428 add ip, \stack_ptr, \arg_offset 1429 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1430 str ip, [\regs, \arg_offset] 1431 add \arg_offset, \arg_offset, #8 1432 b 1b 14333: // FOUND_FLOAT 1434 add ip, \stack_ptr, \arg_offset 1435 ldr wip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1436 str wip, [\regs, \arg_offset] 1437 add \arg_offset, \arg_offset, #4 1438 b 1b 1439.endm 1440 1441// Puts the next int/long/object parameter passed in stack 1442// in the expected dex register array entry, and in case of object in the 1443// expected reference array entry. 1444// Uses ip and ip2 as temporary. 1445.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, finished 14461: // LOOP 1447 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1448 cbz wip, \finished // if (wip == '\0') goto finished 1449 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 1450 b.eq 2f 1451 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 1452 b.eq 3f 1453 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 1454 b.eq 4f 1455 add ip2, \stack_ptr, \arg_offset 1456 ldr wip2, [ip2, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1457 str wip2, [\regs, \arg_offset] 1458 cmp wip, #76 // if (wip != 'L') goto loop 1459 b.ne 3f 1460 str wip2, [\refs, \arg_offset] 1461 add \arg_offset, \arg_offset, #4 1462 b 1b 14632: // FOUND_LONG 1464 add ip, \stack_ptr, \arg_offset 1465 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1466 str ip, [\regs, \arg_offset] 1467 add \arg_offset, \arg_offset, #8 1468 b 1b 14693: // SKIP_FLOAT 1470 add \arg_offset, \arg_offset, #4 1471 b 1b 14724: // SKIP_DOUBLE 1473 add \arg_offset, \arg_offset, #8 1474 b 1b 1475.endm 1476 1477%def entry(): 1478/* 1479 * ArtMethod entry point. 1480 * 1481 * On entry: 1482 * x0 ArtMethod* callee 1483 * rest method parameters 1484 */ 1485 1486OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl 1487 .cfi_startproc 1488 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES 1489 ldr wzr, [x16] 1490 /* Spill callee save regs */ 1491 SPILL_ALL_CALLEE_SAVES 1492 1493 // TODO: Get shorty in a better way and remove below 1494 SPILL_ALL_ARGUMENTS 1495 1496 // Save method in callee-save xINST 1497 mov xINST, x0 1498 bl NterpGetShorty 1499 // Save shorty in callee-save xIBASE. 1500 mov xIBASE, x0 1501 mov x0, xINST 1502 bl NterpGetCodeItem 1503 mov xPC, x0 1504 1505 RESTORE_ALL_ARGUMENTS 1506 1507 // Setup the stack for executing the method. 1508 SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS 1509 1510 // Setup the parameters 1511 ldrh wip2, [xPC, #CODE_ITEM_INS_SIZE_OFFSET] 1512 cbz wip2, .Lxmm_setup_finished 1513 1514 sub ip2, ip, ip2 1515 lsl x8, ip2, #2 // x8 is now the offset for inputs into the registers array. 1516 1517 // Setup shorty, pointer to inputs in FP and pointer to inputs in REFS 1518 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character 1519 add x10, xFP, x8 1520 add x11, xREFS, x8 1521 1522 ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1523 // TODO: could be TBNZ but we'd need a constant for log2(ART_METHOD_IS_STATIC_FLAG). 1524 tst wip, #ART_METHOD_IS_STATIC_FLAG 1525 b.ne .Lhandle_static_method 1526 str w1, [x10], #4 1527 str w1, [x11], #4 1528 add x13, x13, #4 1529 mov x12, #0 1530 b .Lcontinue_setup_gprs 1531.Lhandle_static_method: 1532 mov x12, #0 1533 LOOP_OVER_SHORTY_STORING_GPRS x1, w1, x9, x12, x10, x11, .Lgpr_setup_finished 1534.Lcontinue_setup_gprs: 1535 LOOP_OVER_SHORTY_STORING_GPRS x2, w2, x9, x12, x10, x11, .Lgpr_setup_finished 1536 LOOP_OVER_SHORTY_STORING_GPRS x3, w3, x9, x12, x10, x11, .Lgpr_setup_finished 1537 LOOP_OVER_SHORTY_STORING_GPRS x4, w4, x9, x12, x10, x11, .Lgpr_setup_finished 1538 LOOP_OVER_SHORTY_STORING_GPRS x5, w5, x9, x12, x10, x11, .Lgpr_setup_finished 1539 LOOP_OVER_SHORTY_STORING_GPRS x6, w6, x9, x12, x10, x11, .Lgpr_setup_finished 1540 LOOP_OVER_SHORTY_STORING_GPRS x7, w7, x9, x12, x10, x11, .Lgpr_setup_finished 1541 LOOP_OVER_INTs x9, x12, x10, x11, x13, .Lgpr_setup_finished 1542.Lgpr_setup_finished: 1543 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character 1544 mov x12, #0 // reset counter 1545 LOOP_OVER_SHORTY_STORING_FPS d0, s0, x9, x12, x10, .Lxmm_setup_finished 1546 LOOP_OVER_SHORTY_STORING_FPS d1, s1, x9, x12, x10, .Lxmm_setup_finished 1547 LOOP_OVER_SHORTY_STORING_FPS d2, s2, x9, x12, x10, .Lxmm_setup_finished 1548 LOOP_OVER_SHORTY_STORING_FPS d3, s3, x9, x12, x10, .Lxmm_setup_finished 1549 LOOP_OVER_SHORTY_STORING_FPS d4, s4, x9, x12, x10, .Lxmm_setup_finished 1550 LOOP_OVER_SHORTY_STORING_FPS d5, s5, x9, x12, x10, .Lxmm_setup_finished 1551 LOOP_OVER_SHORTY_STORING_FPS d6, s6, x9, x12, x10, .Lxmm_setup_finished 1552 LOOP_OVER_SHORTY_STORING_FPS d7, s7, x9, x12, x10, .Lxmm_setup_finished 1553 LOOP_OVER_FPs x9, x12, x10, x13, .Lxmm_setup_finished 1554.Lxmm_setup_finished: 1555 // Set the dex pc pointer. 1556 add xPC, xPC, #CODE_ITEM_INSNS_OFFSET 1557 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 1558 1559 // Set rIBASE 1560 adr xIBASE, artNterpAsmInstructionStart 1561 /* start executing the instruction at xPC */ 1562 START_EXECUTING_INSTRUCTIONS 1563 /* NOTE: no fallthrough */ 1564 // cfi info continues, and covers the whole nterp implementation. 1565 SIZE ExecuteNterpImpl 1566 1567%def opcode_pre(): 1568 1569%def helpers(): 1570 1571%def footer(): 1572/* 1573 * =========================================================================== 1574 * Common subroutines and data 1575 * =========================================================================== 1576 */ 1577 1578 .text 1579 .align 2 1580 1581// Note: mterp also uses the common_* names below for helpers, but that's OK 1582// as the C compiler compiled each interpreter separately. 1583common_errDivideByZero: 1584 EXPORT_PC 1585 bl art_quick_throw_div_zero 1586 1587// Expect array in w0, index in w1, length in w2 1588common_errArrayIndex: 1589 EXPORT_PC 1590 mov x0, x1 1591 mov x1, x3 1592 bl art_quick_throw_array_bounds 1593 1594common_errNullObject: 1595 EXPORT_PC 1596 bl art_quick_throw_null_pointer_exception 1597 1598NterpCommonInvokeStatic: 1599 COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic" 1600 1601NterpCommonInvokeStaticRange: 1602 COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic" 1603 1604NterpCommonInvokeInstance: 1605 COMMON_INVOKE_NON_RANGE suffix="invokeInstance" 1606 1607NterpCommonInvokeInstanceRange: 1608 COMMON_INVOKE_RANGE suffix="invokeInstance" 1609 1610NterpCommonInvokeInterface: 1611 COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface" 1612 1613NterpCommonInvokeInterfaceRange: 1614 COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface" 1615 1616NterpCommonInvokePolymorphic: 1617 COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1618 1619NterpCommonInvokePolymorphicRange: 1620 COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1621 1622NterpCommonInvokeCustom: 1623 COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1624 1625NterpCommonInvokeCustomRange: 1626 COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1627 1628NterpHandleStringInit: 1629 COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit" 1630 1631NterpHandleStringInitRange: 1632 COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit" 1633 1634NterpNewInstance: 1635 EXPORT_PC 1636 // Fast-path which gets the class from thread-local cache. 1637 FETCH_FROM_THREAD_CACHE x0, 2f 1638 cbnz wMR, 3f 16394: 1640 ldr lr, [xSELF, #THREAD_ALLOC_OBJECT_ENTRYPOINT_OFFSET] 1641 blr lr 16421: 1643 lsr w1, wINST, #8 // w1 <- A 1644 SET_VREG_OBJECT w0, w1 // fp[A] <- value 1645 FETCH_ADVANCE_INST 2 1646 GET_INST_OPCODE ip 1647 GOTO_OPCODE ip 16482: 1649 mov x0, xSELF 1650 ldr x1, [sp] 1651 mov x2, xPC 1652 bl nterp_get_class_or_allocate_object 1653 b 1b 16543: 1655 bl art_quick_read_barrier_mark_reg00 1656 b 4b 1657 1658NterpNewArray: 1659 /* new-array vA, vB, class@CCCC */ 1660 EXPORT_PC 1661 // Fast-path which gets the class from thread-local cache. 1662 FETCH_FROM_THREAD_CACHE x0, 2f 1663 cbnz wMR, 3f 16641: 1665 lsr w1, wINST, #12 // w1<- B 1666 GET_VREG w1, w1 // w1<- vB (array length) 1667 ldr lr, [xSELF, #THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET] 1668 blr lr 1669 ubfx w1, wINST, #8, #4 // w1<- A 1670 SET_VREG_OBJECT w0, w1 1671 FETCH_ADVANCE_INST 2 1672 GET_INST_OPCODE ip 1673 GOTO_OPCODE ip 16742: 1675 mov x0, xSELF 1676 ldr x1, [sp, 0] 1677 mov x2, xPC 1678 bl nterp_get_class_or_allocate_object 1679 b 1b 16803: 1681 bl art_quick_read_barrier_mark_reg00 1682 b 1b 1683 1684NterpPutObjectInstanceField: 1685 // Fast-path which gets the field from thread-local cache. 1686 FETCH_FROM_THREAD_CACHE x0, 3f 16871: 1688 ubfx w1, wINST, #8, #4 // w1<- A 1689 lsr w2, wINST, #12 // w2<- B 1690 GET_VREG w2, w2 // vB (object we're operating on) 1691 cbz w2, common_errNullObject // is object null? 1692 GET_VREG w1, w1 // w1 <- v[A] 1693 str w1, [x2, x0] 1694 cbz w1, 2f 1695 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1696 lsr w3, w2, #CARD_TABLE_CARD_SHIFT 1697 strb w1, [x1, x3] 16982: 1699 FETCH_ADVANCE_INST 2 1700 GET_INST_OPCODE ip 1701 GOTO_OPCODE ip 17023: 1703 mov x0, xSELF 1704 ldr x1, [sp] 1705 mov x2, xPC 1706 EXPORT_PC 1707 bl nterp_get_instance_field_offset 1708 tbz w0, #31, 1b 1709 CLEAR_INSTANCE_VOLATILE_MARKER w0 1710 ubfx w1, wINST, #8, #4 // w1<- A 1711 lsr w2, wINST, #12 // w2<- B 1712 GET_VREG w2, w2 // vB (object we're operating on) 1713 cbz w2, common_errNullObject // is object null? 1714 GET_VREG w1, w1 // w1 <- v[A] 1715 add x3, x2, x0 1716 stlr w1, [x3] 1717 cbz w1, 2b 1718 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1719 lsr w3, w2, #CARD_TABLE_CARD_SHIFT 1720 strb w1, [x1, x3] 1721 b 2b 1722 1723NterpGetObjectInstanceField: 1724 // Fast-path which gets the field from thread-local cache. 1725 FETCH_FROM_THREAD_CACHE x0, 4f 17261: 1727 ubfx w1, wINST, #8, #4 // w1<- A 1728 lsr w2, wINST, #12 // w2<- B 1729 GET_VREG w2, w2 // vB (object we're operating on) 1730 cbz w2, common_errNullObject 1731 ldr w0, [x2, x0] 1732 cbnz wMR, 3f 17332: 1734 SET_VREG_OBJECT w0, w1 // fp[A] <- value 1735 FETCH_ADVANCE_INST 2 1736 GET_INST_OPCODE ip 1737 GOTO_OPCODE ip 17383: 1739 bl art_quick_read_barrier_mark_reg00 1740 b 2b 17414: 1742 mov x0, xSELF 1743 ldr x1, [sp] 1744 mov x2, xPC 1745 EXPORT_PC 1746 bl nterp_get_instance_field_offset 1747 tbz w0, #31, 1b 1748 CLEAR_INSTANCE_VOLATILE_MARKER w0 1749 ubfx w1, wINST, #8, #4 // w1<- A 1750 lsr w2, wINST, #12 // w2<- B 1751 GET_VREG w2, w2 // vB (object we're operating on) 1752 cbz w2, common_errNullObject 1753 add x2, x2, x0 1754 ldar w0, [x2] 1755 cbnz wMR, 6f 17565: 1757 SET_VREG_OBJECT w0, w1 // fp[A] <- value 1758 FETCH_ADVANCE_INST 2 1759 GET_INST_OPCODE ip 1760 GOTO_OPCODE ip 17616: 1762 bl art_quick_read_barrier_mark_reg00 1763 b 5b 1764 1765NterpPutObjectStaticField: 1766 // Fast-path which gets the field from thread-local cache. 1767 FETCH_FROM_THREAD_CACHE x0, 5f 17681: 1769 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1770 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1771 cbnz wMR, 4f 17722: 1773 lsr w2, wINST, #8 // w2 <- A 1774 GET_VREG w2, w2 1775 str w2, [x0, x1] 1776 cbz w2, 3f 1777 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1778 lsr w3, w0, #CARD_TABLE_CARD_SHIFT 1779 strb w1, [x1, x3] 17803: 1781 FETCH_ADVANCE_INST 2 1782 GET_INST_OPCODE ip 1783 GOTO_OPCODE ip 17844: 1785 bl art_quick_read_barrier_mark_reg00 1786 b 2b 17875: 1788 mov x0, xSELF 1789 ldr x1, [sp] 1790 mov x2, xPC 1791 EXPORT_PC 1792 bl nterp_get_static_field 1793 tbz x0, #0, 1b 1794 CLEAR_STATIC_VOLATILE_MARKER x0 1795 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1796 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1797 cbnz wMR, 7f 17986: 1799 lsr w2, wINST, #8 // w1 <- A 1800 GET_VREG w2, w2 1801 add ip, x0, x1 1802 stlr w2, [ip] 1803 cbz w2, 3b 1804 ldr x1, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1805 lsr w3, w0, #CARD_TABLE_CARD_SHIFT 1806 strb w1, [x1, x3] 1807 b 3b 18087: 1809 bl art_quick_read_barrier_mark_reg00 1810 b 6b 1811 1812NterpGetObjectStaticField: 1813 // Fast-path which gets the field from thread-local cache. 1814 FETCH_FROM_THREAD_CACHE x0, 4f 18151: 1816 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1817 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1818 cbnz wMR, 3f 1819 ldr w0, [x0, x1] 1820 // No need to check the marking register, we know it's not set here. 18212: 1822 lsr w1, wINST, #8 // w1 <- A 1823 SET_VREG_OBJECT w0, w1 // fp[A] <- value 1824 FETCH_ADVANCE_INST 2 1825 GET_INST_OPCODE ip 1826 GOTO_OPCODE ip 18273: 1828 bl art_quick_read_barrier_mark_reg00 1829 ldr w0, [x0, x1] 1830 // Here, we know the marking register is set. 1831 bl art_quick_read_barrier_mark_reg00 1832 b 2b 18334: 1834 mov x0, xSELF 1835 ldr x1, [sp] 1836 mov x2, xPC 1837 EXPORT_PC 1838 bl nterp_get_static_field 1839 tbz x0, #0, 1b 1840 CLEAR_STATIC_VOLATILE_MARKER x0 1841 ldr w1, [x0, #ART_FIELD_OFFSET_OFFSET] 1842 ldr w0, [x0, #ART_FIELD_DECLARING_CLASS_OFFSET] 1843 cbnz wMR, 7f 18445: 1845 add x0, x0, x1 1846 ldar w0, [x0] 1847 cbnz wMR, 8f 18486: 1849 lsr w1, wINST, #8 // w1 <- A 1850 SET_VREG_OBJECT w0, w1 // fp[A] <- value 1851 FETCH_ADVANCE_INST 2 1852 GET_INST_OPCODE ip 1853 GOTO_OPCODE ip 18547: 1855 bl art_quick_read_barrier_mark_reg00 1856 b 5b 18578: 1858 bl art_quick_read_barrier_mark_reg00 1859 b 6b 1860 1861NterpGetBooleanStaticField: 1862 OP_SGET load="ldrb", volatile_load="ldarb", maybe_extend="", wide=0 1863 1864NterpGetByteStaticField: 1865 OP_SGET load="ldrsb", volatile_load="ldarb", maybe_extend="sbfx w0, w0, #0, #8", wide=0 1866 1867NterpGetCharStaticField: 1868 OP_SGET load="ldrh", volatile_load="ldarh", maybe_extend="", wide=0 1869 1870NterpGetShortStaticField: 1871 OP_SGET load="ldrsh", volatile_load="ldarh", maybe_extend="sbfx w0, w0, #0, #16", wide=0 1872 1873NterpGetWideStaticField: 1874 OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide=1 1875 1876NterpGetIntStaticField: 1877 OP_SGET load="ldr", volatile_load="ldar", maybe_extend="", wide=0 1878 1879NterpPutStaticField: 1880 OP_SPUT store="str", volatile_store="stlr", wide=0 1881 1882NterpPutBooleanStaticField: 1883NterpPutByteStaticField: 1884 OP_SPUT store="strb", volatile_store="stlrb", wide=0 1885 1886NterpPutCharStaticField: 1887NterpPutShortStaticField: 1888 OP_SPUT store="strh", volatile_store="stlrh", wide=0 1889 1890NterpPutWideStaticField: 1891 OP_SPUT store="str", volatile_store="stlr", wide=1 1892 1893NterpPutInstanceField: 1894 OP_IPUT store="str", volatile_store="stlr", wide=0 1895 1896NterpPutBooleanInstanceField: 1897NterpPutByteInstanceField: 1898 OP_IPUT store="strb", volatile_store="stlrb", wide=0 1899 1900NterpPutCharInstanceField: 1901NterpPutShortInstanceField: 1902 OP_IPUT store="strh", volatile_store="stlrh", wide=0 1903 1904NterpPutWideInstanceField: 1905 OP_IPUT store="str", volatile_store="stlr", wide=1 1906 1907NterpGetBooleanInstanceField: 1908 OP_IGET load="ldrb", volatile_load="ldarb", maybe_extend="", wide=0 1909 1910NterpGetByteInstanceField: 1911 OP_IGET load="ldrsb", volatile_load="ldarb", maybe_extend="sbfx w0, w0, #0, #8", wide=0 1912 1913NterpGetCharInstanceField: 1914 OP_IGET load="ldrh", volatile_load="ldarh", maybe_extend="", wide=0 1915 1916NterpGetShortInstanceField: 1917 OP_IGET load="ldrsh", volatile_load="ldarh", maybe_extend="sbfx w0, w0, #0, #16", wide=0 1918 1919NterpGetWideInstanceField: 1920 OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide=1 1921 1922NterpGetInstanceField: 1923 OP_IGET load="ldr", volatile_load="ldar", maybe_extend="", wide=0 1924 1925NterpInstanceOf: 1926 /* instance-of vA, vB, class@CCCC */ 1927 // Fast-path which gets the class from thread-local cache. 1928 EXPORT_PC 1929 FETCH_FROM_THREAD_CACHE x1, 3f 1930 cbnz wMR, 4f 19311: 1932 lsr w2, wINST, #12 // w2<- B 1933 GET_VREG w0, w2 // w0<- vB (object) 1934 cbz w0, 2f 1935 bl artInstanceOfFromCode 19362: 1937 ubfx w1, wINST, #8, #4 // w1<- A 1938 SET_VREG w0, w1 1939 FETCH_ADVANCE_INST 2 1940 GET_INST_OPCODE ip 1941 GOTO_OPCODE ip 19423: 1943 mov x0, xSELF 1944 ldr x1, [sp] 1945 mov x2, xPC 1946 bl nterp_get_class_or_allocate_object 1947 mov x1, x0 1948 b 1b 19494: 1950 bl art_quick_read_barrier_mark_reg01 1951 b 1b 1952 1953NterpCheckCast: 1954 // Fast-path which gets the class from thread-local cache. 1955 EXPORT_PC 1956 FETCH_FROM_THREAD_CACHE x1, 3f 1957 cbnz wMR, 4f 19581: 1959 lsr w2, wINST, #8 // w2<- A 1960 GET_VREG w0, w2 // w2<- vA (object) 1961 cbz w0, 2f 1962 bl art_quick_check_instance_of 19632: 1964 FETCH_ADVANCE_INST 2 1965 GET_INST_OPCODE ip 1966 GOTO_OPCODE ip 19673: 1968 mov x0, xSELF 1969 ldr x1, [sp] 1970 mov x2, xPC 1971 bl nterp_get_class_or_allocate_object 1972 mov x1, x0 1973 b 1b 19744: 1975 bl art_quick_read_barrier_mark_reg01 1976 b 1b 1977 1978NterpHandleHotnessOverflow: 1979 add x1, xPC, xINST, lsl #1 1980 mov x2, xFP 1981 bl nterp_hot_method 1982 cbnz x0, 1f 1983 add w2, wINST, wINST // w2<- byte offset 1984 FETCH_ADVANCE_INST_RB w2 // update xPC, load wINST 1985 GET_INST_OPCODE ip // extract opcode from wINST 1986 GOTO_OPCODE ip // jump to next instruction 19871: 1988 // Drop the current frame. 1989 ldr ip, [xREFS, #-8] 1990 mov sp, ip 1991 .cfi_def_cfa sp, CALLEE_SAVES_SIZE 1992 1993 // The transition frame of type SaveAllCalleeSaves saves x19 and x20, 1994 // but not managed ABI. So we need to restore callee-saves of the nterp frame, 1995 // and save managed ABI callee saves, which will be restored by the callee upon 1996 // return. 1997 RESTORE_ALL_CALLEE_SAVES 1998 INCREASE_FRAME ((CALLEE_SAVES_SIZE) - 16) 1999 2000 // FP callee-saves 2001 stp d8, d9, [sp, #0] 2002 stp d10, d11, [sp, #16] 2003 stp d12, d13, [sp, #32] 2004 stp d14, d15, [sp, #48] 2005 2006 // GP callee-saves. 2007 SAVE_TWO_REGS x21, x22, 64 2008 SAVE_TWO_REGS x23, x24, 80 2009 SAVE_TWO_REGS x25, x26, 96 2010 SAVE_TWO_REGS x27, x28, 112 2011 SAVE_TWO_REGS x29, lr, 128 2012 2013 // Setup the new frame 2014 ldr x1, [x0, #OSR_DATA_FRAME_SIZE] 2015 // Given stack size contains all callee saved registers, remove them. 2016 sub x1, x1, #(CALLEE_SAVES_SIZE - 16) 2017 2018 // We know x1 cannot be 0, as it at least contains the ArtMethod. 2019 2020 // Remember CFA in a callee-save register. 2021 mov xINST, sp 2022 .cfi_def_cfa_register xINST 2023 2024 sub sp, sp, x1 2025 2026 add x2, x0, #OSR_DATA_MEMORY 20272: 2028 sub x1, x1, #8 2029 ldr ip, [x2, x1] 2030 str ip, [sp, x1] 2031 cbnz x1, 2b 2032 2033 // Fetch the native PC to jump to and save it in a callee-save register. 2034 ldr xFP, [x0, #OSR_DATA_NATIVE_PC] 2035 2036 // Free the memory holding OSR Data. 2037 bl free 2038 2039 // Jump to the compiled code. 2040 br xFP 2041 2042NterpHandleInvokeInterfaceOnObjectMethodRange: 2043 // First argument is the 'this' pointer. 2044 FETCH w1, 2 2045 GET_VREG w1, w1 2046 // Note: x1 is null, this will be handled by our SIGSEGV handler. 2047 ldr w2, [x1, #MIRROR_OBJECT_CLASS_OFFSET] 2048 add w2, w2, #MIRROR_CLASS_VTABLE_OFFSET_64 2049 ldr x0, [x2, w0, sxtw #3] 2050 b NterpCommonInvokeInstanceRange 2051 2052NterpHandleInvokeInterfaceOnObjectMethod: 2053 // First argument is the 'this' pointer. 2054 FETCH w1, 2 2055 and w1, w1, #0xf 2056 GET_VREG w1, w1 2057 // Note: x1 is null, this will be handled by our SIGSEGV handler. 2058 ldr w2, [x1, #MIRROR_OBJECT_CLASS_OFFSET] 2059 add w2, w2, #MIRROR_CLASS_VTABLE_OFFSET_64 2060 ldr x0, [x2, w0, sxtw #3] 2061 b NterpCommonInvokeInstance 2062 2063// This is the logical end of ExecuteNterpImpl, where the frame info applies. 2064// EndExecuteNterpImpl includes the methods below as we want the runtime to 2065// see them as part of the Nterp PCs. 2066.cfi_endproc 2067 2068nterp_to_nterp_static_non_range: 2069 .cfi_startproc 2070 SETUP_STACK_FOR_INVOKE 2071 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0 2072 .cfi_endproc 2073 2074nterp_to_nterp_string_init_non_range: 2075 .cfi_startproc 2076 SETUP_STACK_FOR_INVOKE 2077 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 2078 .cfi_endproc 2079 2080nterp_to_nterp_instance_non_range: 2081 .cfi_startproc 2082 SETUP_STACK_FOR_INVOKE 2083 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 2084 .cfi_endproc 2085 2086nterp_to_nterp_static_range: 2087 .cfi_startproc 2088 SETUP_STACK_FOR_INVOKE 2089 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1 2090 .cfi_endproc 2091 2092nterp_to_nterp_instance_range: 2093 .cfi_startproc 2094 SETUP_STACK_FOR_INVOKE 2095 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0 2096 .cfi_endproc 2097 2098nterp_to_nterp_string_init_range: 2099 .cfi_startproc 2100 SETUP_STACK_FOR_INVOKE 2101 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 2102 .cfi_endproc 2103 2104// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter 2105// entry point. 2106 .type EndExecuteNterpImpl, #function 2107 .hidden EndExecuteNterpImpl 2108 .global EndExecuteNterpImpl 2109EndExecuteNterpImpl: 2110 2111// Entrypoints into runtime. 2112NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField 2113NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset 2114NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray 2115NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange 2116NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject 2117NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod 2118NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod 2119NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject 2120 2121// gen_mterp.py will inline the following definitions 2122// within [ExecuteNterpImpl, EndExecuteNterpImpl). 2123%def instruction_end(): 2124 2125 .type artNterpAsmInstructionEnd, #function 2126 .hidden artNterpAsmInstructionEnd 2127 .global artNterpAsmInstructionEnd 2128artNterpAsmInstructionEnd: 2129 // artNterpAsmInstructionEnd is used as landing pad for exception handling. 2130 FETCH_INST 2131 GET_INST_OPCODE ip 2132 GOTO_OPCODE ip 2133 2134%def instruction_start(): 2135 2136 .type artNterpAsmInstructionStart, #function 2137 .hidden artNterpAsmInstructionStart 2138 .global artNterpAsmInstructionStart 2139artNterpAsmInstructionStart = .L_op_nop 2140 .text 2141 2142%def opcode_start(): 2143 NAME_START nterp_${opcode} 2144%def opcode_end(): 2145 NAME_END nterp_${opcode} 2146%def helper_start(name): 2147 NAME_START ${name} 2148%def helper_end(name): 2149 NAME_END ${name} 2150