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 * x21 xSUSPEND suspend check register 65 * x29 xFP interpreted frame pointer, used for accessing locals and args 66 * x22 xPC interpreted program counter, used for fetching instructions 67 * x23 xINST first 16-bit code unit of current instruction 68 * x24 xIBASE interpreted instruction base pointer, used for computed goto 69 * x25 xREFS base of object references of dex registers. 70 * x16 ip scratch reg 71 * x17 ip2 scratch reg (used by macros) 72 * 73 * Macros are provided for common operations. They MUST NOT alter unspecified registers or 74 * condition codes. 75*/ 76 77/* single-purpose registers, given names for clarity */ 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 a half-word code unit from an offset past the current PC. The 144 * "count" value is in 16-bit code units. Does not advance xPC. 145 * 146 * The "_S" variant works the same but treats the value as signed. 147 */ 148.macro FETCH reg, count 149 ldrh \reg, [xPC, #((\count)*2)] 150.endm 151 152.macro FETCH_S reg, count 153 ldrsh \reg, [xPC, #((\count)*2)] 154.endm 155 156/* 157 * Fetch one byte from an offset past the current PC. Pass in the same 158 * "count" as you would for FETCH, and an additional 0/1 indicating which 159 * byte of the halfword you want (lo/hi). 160 */ 161.macro FETCH_B reg, count, byte 162 ldrb \reg, [xPC, #((\count)*2+(\byte))] 163.endm 164 165/* 166 * Put the instruction's opcode field into the specified register. 167 */ 168.macro GET_INST_OPCODE reg 169 and \reg, xINST, #255 170.endm 171 172/* 173 * Begin executing the opcode in _reg. Clobbers reg 174 */ 175 176.macro GOTO_OPCODE reg 177 add \reg, xIBASE, \reg, lsl #${handler_size_bits} 178 br \reg 179.endm 180 181/* 182 * Get/set the 32-bit value from a Dalvik register. 183 */ 184.macro GET_VREG reg, vreg 185 ldr \reg, [xFP, \vreg, uxtw #2] 186.endm 187.macro GET_VREG_OBJECT reg, vreg 188 ldr \reg, [xREFS, \vreg, uxtw #2] 189.endm 190.macro SET_VREG reg, vreg 191 str \reg, [xFP, \vreg, uxtw #2] 192 str wzr, [xREFS, \vreg, uxtw #2] 193.endm 194.macro SET_VREG_OBJECT reg, vreg 195 str \reg, [xFP, \vreg, uxtw #2] 196 str \reg, [xREFS, \vreg, uxtw #2] 197.endm 198.macro SET_VREG_FLOAT reg, vreg 199 str \reg, [xFP, \vreg, uxtw #2] 200 str wzr, [xREFS, \vreg, uxtw #2] 201.endm 202 203/* 204 * Get/set the 64-bit value from a Dalvik register. 205 */ 206.macro LOAD_SCALED_VREG_MASK scaled_mask_reg, unscaled_mask 207 mov \scaled_mask_reg, \unscaled_mask << 2 208.endm 209.macro EXTRACT_SCALED_VREG scaled_vreg, scaled_mask_reg, src_reg, lsb 210 .if \lsb < 2 211 and \scaled_vreg, \scaled_mask_reg, \src_reg, lsl #(2 - \lsb) 212 .else 213 and \scaled_vreg, \scaled_mask_reg, \src_reg, lsr #(\lsb - 2) 214 .endif 215.endm 216.macro GET_VREG_WIDE_PRESCALED reg, scaled_vreg 217 ldr \reg, [xFP, \scaled_vreg, uxtw] 218.endm 219.macro GET_VREG_WIDE reg, vreg 220 lsl wip2, \vreg, #2 221 GET_VREG_WIDE_PRESCALED \reg, wip2 222.endm 223.macro SET_VREG_WIDE_PRESCALED reg, scaled_vreg 224 str \reg, [xFP, \scaled_vreg, uxtw] 225 str xzr, [xREFS, \scaled_vreg, uxtw] 226.endm 227.macro SET_VREG_WIDE reg, vreg 228 lsl wip2, \vreg, #2 229 SET_VREG_WIDE_PRESCALED \reg, wip2 230.endm 231.macro GET_VREG_DOUBLE_PRESCALED reg, scaled_vreg 232 GET_VREG_WIDE_PRESCALED \reg, \scaled_vreg 233.endm 234.macro GET_VREG_DOUBLE reg, vreg 235 GET_VREG_WIDE \reg, \vreg 236.endm 237.macro SET_VREG_DOUBLE reg, vreg 238 SET_VREG_WIDE \reg, \vreg 239.endm 240 241/* 242 * Get the 32-bit value from a Dalvik register and sign-extend to 64-bit. 243 * Used to avoid an extra instruction in int-to-long. 244 */ 245.macro GET_VREG_S reg, vreg 246 ldrsw \reg, [xFP, \vreg, uxtw #2] 247.endm 248 249// An assembly entry for nterp. 250.macro OAT_ENTRY name 251 .type \name, #function 252 .hidden \name 253 .global \name 254 .balign 16 255\name: 256.endm 257 258.macro SIZE name 259 .size \name, .-\name 260.endm 261 262.macro NAME_START name 263 .type \name, #function 264 .hidden \name // Hide this as a global symbol, so we do not incur plt calls. 265 .global \name 266 /* Cache alignment for function entry */ 267 .balign 16 268\name: 269.endm 270 271.macro NAME_END name 272 SIZE \name 273.endm 274 275// Macro for defining entrypoints into runtime. We don't need to save registers 276// (we're not holding references there), but there is no 277// kDontSave runtime method. So just use the kSaveRefsOnly runtime method. 278.macro NTERP_TRAMPOLINE name, helper 279ENTRY \name 280 SETUP_SAVE_REFS_ONLY_FRAME 281 bl \helper 282 RESTORE_SAVE_REFS_ONLY_FRAME 283 REFRESH_MARKING_REGISTER 284 ldr xIP0, [xSELF, # THREAD_EXCEPTION_OFFSET] // Get exception field. 285 cbnz xIP0, nterp_deliver_pending_exception 286 ret 287END \name 288.endm 289 290.macro CLEAR_STATIC_VOLATILE_MARKER reg 291 and \reg, \reg, #-2 292.endm 293 294.macro CLEAR_INSTANCE_VOLATILE_MARKER reg 295 neg \reg, \reg 296.endm 297 298.macro EXPORT_PC 299 str xPC, [xREFS, #-16] 300.endm 301 302.macro BRANCH 303 add xPC, xPC, wINST, sxtw #1 // update xPC 304 // Update method counter and do a suspend check if the branch is negative or zero. 305 cmp wINST, #0 306 b.le 2f 3071: 308 FETCH wINST, 0 // 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#if (NTERP_HOTNESS_VALUE != 0) 315#error Expected 0 for hotness value 316#endif 317 // If the counter is at zero, handle this in the runtime. 318 cbz w2, NterpHandleHotnessOverflow 319 add x2, x2, #-1 320 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 321 DO_SUSPEND_CHECK continue_label=1b 322 b 1b 323.endm 324 325// Uses x12, x13, and x14 as temporaries. 326.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins 327 // Fetch dex register size. 328 ldrh \registers, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET] 329 // Fetch outs size. 330 ldrh \outs, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET] 331 .if \load_ins 332 ldrh \ins, [\code_item, #CODE_ITEM_INS_SIZE_OFFSET] 333 .endif 334 add \code_item, \code_item, #CODE_ITEM_INSNS_OFFSET 335.endm 336 337.macro TEST_IF_MARKING label 338 cbnz wMR, \label 339.endm 340 341// Setup the stack to start executing the method. Expects: 342// - x0 to contain the ArtMethod 343// 344// Outputs 345// - ip contains the dex registers size 346// - x28 contains the old stack pointer. 347// - \code_item is replaced with a pointer to the instructions 348// - if load_ins is 1, w15 contains the ins 349// 350// Uses ip, ip2, x12, x13, x14 as temporaries. 351.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins 352 FETCH_CODE_ITEM_INFO \code_item, wip, wip2, w15, \load_ins 353 354 // Compute required frame size: ((2 * ip) + ip2) * 4 + 24 355 // 24 is for saving the previous frame, pc, and method being executed. 356 add x14, ip, ip 357 add x14, x14, ip2 358 lsl x14, x14, #2 359 add x14, x14, #24 360 361 // Compute new stack pointer in x14 362 sub x14, sp, x14 363 // Alignment 364 and x14, x14, #-16 365 366 // Set reference and dex registers, align to pointer size for previous frame and dex pc. 367 add \refs, x14, ip2, lsl #2 368 add \refs, \refs, 28 369 and \refs, \refs, #(-__SIZEOF_POINTER__) 370 add \fp, \refs, ip, lsl #2 371 372 // Now setup the stack pointer. 373 mov x28, sp 374 .cfi_def_cfa_register x28 375 mov sp, x14 376 str x28, [\refs, #-8] 377 CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -8, CALLEE_SAVES_SIZE 378 379 // Put nulls in reference frame. 380 cbz ip, 2f 381 mov ip2, \refs 3821: 383 str xzr, [ip2], #8 // May clear vreg[0]. 384 cmp ip2, \fp 385 b.lo 1b 3862: 387 // Save the ArtMethod. 388 str x0, [sp] 389.endm 390 391// Increase method hotness and do suspend check before starting executing the method. 392.macro START_EXECUTING_INSTRUCTIONS 393 ldr x0, [sp] 394 ldrh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 395#if (NTERP_HOTNESS_VALUE != 0) 396#error Expected 0 for hotness value 397#endif 398 // If the counter is at zero, handle this in the runtime. 399 cbz w2, 3f 400 add x2, x2, #-1 401 strh w2, [x0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 4021: 403 DO_SUSPEND_CHECK continue_label=2f 4042: 405 FETCH_INST 406 GET_INST_OPCODE ip 407 GOTO_OPCODE ip 4083: 409 CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b 4104: 411 mov x1, xzr 412 mov x2, xFP 413 bl nterp_hot_method 414 b 2b 415.endm 416 417.macro SPILL_ALL_CALLEE_SAVES 418 INCREASE_FRAME CALLEE_SAVES_SIZE 419 // Note: we technically don't need to save x19 and x20, 420 // but the runtime will expect those values to be there when unwinding 421 // (see Arm64Context::DoLongJump checking for the thread register). 422 SAVE_ALL_CALLEE_SAVES 0 423.endm 424 425.macro RESTORE_ALL_CALLEE_SAVES 426 // FP callee-saves 427 ldp d8, d9, [sp, #0] 428 ldp d10, d11, [sp, #16] 429 ldp d12, d13, [sp, #32] 430 ldp d14, d15, [sp, #48] 431 432 // GP callee-saves. 433 // No need to restore x19 (it's always the thread), and 434 // don't restore x20 (the marking register) as it may have been updated, 435 // don't restore x21 (the suspend check register) as it may have been updated. 436 RESTORE_REG x22, 88 437 RESTORE_TWO_REGS x23, x24, 96 438 RESTORE_TWO_REGS x25, x26, 112 439 RESTORE_TWO_REGS x27, x28, 128 440 RESTORE_TWO_REGS x29, lr, 144 441 442 DECREASE_FRAME CALLEE_SAVES_SIZE 443.endm 444 445.macro SPILL_ALL_ARGUMENTS 446 stp x0, x1, [sp, #-128]! 447 stp x2, x3, [sp, #16] 448 stp x4, x5, [sp, #32] 449 stp x6, x7, [sp, #48] 450 stp d0, d1, [sp, #64] 451 stp d2, d3, [sp, #80] 452 stp d4, d5, [sp, #96] 453 stp d6, d7, [sp, #112] 454.endm 455 456.macro RESTORE_ALL_ARGUMENTS 457 ldp x2, x3, [sp, #16] 458 ldp x4, x5, [sp, #32] 459 ldp x6, x7, [sp, #48] 460 ldp d0, d1, [sp, #64] 461 ldp d2, d3, [sp, #80] 462 ldp d4, d5, [sp, #96] 463 ldp d6, d7, [sp, #112] 464 ldp x0, x1, [sp], #128 465.endm 466 467// Helper to setup the stack after doing a nterp to nterp call. This will setup: 468// - xNEW_FP: the new pointer to dex registers 469// - xNEW_REFS: the new pointer to references 470// - xPC: the new PC pointer to execute 471// - x2: value in instruction to decode the number of arguments. 472// - x3: first dex register 473// - x4: top of dex register array 474// 475// The method expects: 476// - x0 to contain the ArtMethod 477// - x8 to contain the code item 478.macro SETUP_STACK_FOR_INVOKE 479 // We do the same stack overflow check as the compiler. See CanMethodUseNterp 480 // in how we limit the maximum nterp frame size. 481 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES 482 ldr wzr, [x16] 483 484 // Spill all callee saves to have a consistent stack frame whether we 485 // are called by compiled code or nterp. 486 SPILL_ALL_CALLEE_SAVES 487 488 // Setup the frame. 489 SETUP_STACK_FRAME x8, xNEW_REFS, xNEW_FP, CFI_NEW_REFS, load_ins=0 490 // Make x4 point to the top of the dex register array. 491 add x4, xNEW_FP, ip, uxtx #2 492 493 // Fetch instruction information before replacing xPC. 494 // TODO: move this down to the method that uses it, fetching it directly from wINST. 495 FETCH_B w2, 0, 1 496 // TODO: we could avoid this as instance invokes already fetch it. 497 FETCH w3, 2 498 499 // Set the dex pc pointer. 500 mov xPC, x8 501 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 502.endm 503 504// Setup arguments based on a non-range nterp to nterp call, and start executing 505// the method. We expect: 506// - xNEW_FP: the new pointer to dex registers 507// - xNEW_REFS: the new pointer to references 508// - xPC: the new PC pointer to execute 509// - x2: number of arguments (bits 4-7), 5th argument if any (bits 0-3) 510// - x3: first dex register 511// - x4: top of dex register array 512// - x1: receiver if non-static. 513.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 514 // /* op vA, vB, {vC...vG} */ 515 asr ip2, x2, #4 516 cbz ip2, 6f 517 mov ip, #-4 518 cmp ip2, #2 519 b.lt 1f 520 b.eq 2f 521 cmp ip2, #4 522 b.lt 3f 523 b.eq 4f 524 525 // We use a decrementing ip to store references relative 526 // to xNEW_FP and dex registers relative to x4 527 // 528 // TODO: We could set up ip as the number of registers (this can be an additional output from 529 // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg. 530 // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS. 5315: 532 and x2, x2, #15 533 GET_VREG_OBJECT w5, w2 534 str w5, [xNEW_FP, ip] 535 GET_VREG w5, w2 536 str w5, [x4, ip] 537 sub ip, ip, #4 5384: 539 asr x2, x3, #12 540 GET_VREG_OBJECT w5, w2 541 str w5, [xNEW_FP, ip] 542 GET_VREG w5, w2 543 str w5, [x4, ip] 544 sub ip, ip, #4 5453: 546 ubfx x2, x3, #8, #4 547 GET_VREG_OBJECT w5, w2 548 str w5, [xNEW_FP, ip] 549 GET_VREG w5, w2 550 str w5, [x4, ip] 551 sub ip, ip, #4 5522: 553 ubfx x2, x3, #4, #4 554 GET_VREG_OBJECT w5, w2 555 str w5, [xNEW_FP, ip] 556 GET_VREG w5, w2 557 str w5, [x4, ip] 558 .if !\is_string_init 559 sub ip, ip, #4 560 .endif 5611: 562 .if \is_string_init 563 // Ignore the first argument 564 .elseif \is_static 565 and x2, x3, #0xf 566 GET_VREG_OBJECT w5, w2 567 str w5, [xNEW_FP, ip] 568 GET_VREG w5, w2 569 str w5, [x4, ip] 570 .else 571 str w1, [xNEW_FP, ip] 572 str w1, [x4, ip] 573 .endif 574 5756: 576 // Start executing the method. 577 mov xFP, xNEW_FP 578 mov xREFS, xNEW_REFS 579 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE 580 START_EXECUTING_INSTRUCTIONS 581.endm 582 583// Setup arguments based on a range nterp to nterp call, and start executing 584// the method. 585// - xNEW_FP: the new pointer to dex registers 586// - xNEW_REFS: the new pointer to references 587// - xPC: the new PC pointer to execute 588// - x2: number of arguments 589// - x3: first dex register 590// - x4: top of dex register array 591// - x1: receiver if non-static. 592// 593// Uses ip, ip2, x5, x6 as temporaries. 594.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 595 mov ip, #-4 596 .if \is_string_init 597 // Ignore the first argument 598 sub x2, x2, #1 599 add x3, x3, #1 600 .elseif !\is_static 601 sub x2, x2, #1 602 add x3, x3, #1 603 .endif 604 605 cbz x2, 2f 606 add ip2, xREFS, x3, lsl #2 // pointer to first argument in reference array 607 add ip2, ip2, x2, lsl #2 // pointer to last argument in reference array 608 add x5, xFP, x3, lsl #2 // pointer to first argument in register array 609 add x6, x5, x2, lsl #2 // pointer to last argument in register array 6101: 611 ldr w7, [ip2, #-4]! 612 str w7, [xNEW_FP, ip] 613 sub x2, x2, 1 614 ldr w7, [x6, #-4]! 615 str w7, [x4, ip] 616 sub ip, ip, 4 617 cbnz x2, 1b 6182: 619 .if \is_string_init 620 // Ignore first argument 621 .elseif !\is_static 622 str w1, [xNEW_FP, ip] 623 str w1, [x4, ip] 624 .endif 625 mov xFP, xNEW_FP 626 mov xREFS, xNEW_REFS 627 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE 628 START_EXECUTING_INSTRUCTIONS 629.endm 630 631.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom 632 stp x0, x1, [sp, #-16]! 633 .if \is_polymorphic 634 ldr x0, [sp, #16] 635 mov x1, xPC 636 bl NterpGetShortyFromInvokePolymorphic 637 .elseif \is_custom 638 ldr x0, [sp, #16] 639 mov x1, xPC 640 bl NterpGetShortyFromInvokeCustom 641 .elseif \is_interface 642 ldr x0, [sp, #16] 643 FETCH w1, 1 644 bl NterpGetShortyFromMethodId 645 .else 646 bl NterpGetShorty 647 .endif 648 mov \dest, x0 649 ldp x0, x1, [sp], #16 650.endm 651 652.macro GET_SHORTY_SLOW_PATH dest, is_interface 653 // Save all registers that can hold arguments in the fast path. 654 stp x0, x1, [sp, #-32]! 655 str w2, [sp, #16] 656 str s0, [sp, #20] 657 .if \is_interface 658 ldr x0, [sp, #32] 659 FETCH w1, 1 660 bl NterpGetShortyFromMethodId 661 .else 662 bl NterpGetShorty 663 .endif 664 mov \dest, x0 665 ldr w2, [sp, #16] 666 ldr s0, [sp, #20] 667 ldp x0, x1, [sp], #32 668.endm 669 670// Input: x0 contains the ArtMethod 671// Output: x8 contains the code item 672.macro GET_CODE_ITEM 673 ldr x8, [x0, #ART_METHOD_DATA_OFFSET_64] 674.endm 675 676.macro DO_ENTRY_POINT_CHECK call_compiled_code 677 // On entry, the method is x0, the instance is x1 678 adr x2, ExecuteNterpImpl 679 ldr x3, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 680 cmp x2, x3 681 b.ne \call_compiled_code 682.endm 683 684.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value 685 mov wip, wzr 6861: 687 GET_VREG_OBJECT wip2, wip 688 cmp wip2, \old_value 689 b.ne 2f 690 SET_VREG_OBJECT \new_value, wip 6912: 692 add wip, wip, #1 693 add ip2, xREFS, wip, uxtw #2 694 cmp ip2, xFP 695 b.ne 1b 696.endm 697 698// Puts the next floating point argument into the expected register, 699// fetching values based on a non-range invoke. 700// Uses ip and ip2. 701.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished 7021: // LOOP 703 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 704 cbz wip, \finished // if (wip == '\0') goto finished 705 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 706 b.eq 2f 707 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 708 b.eq 3f 709 lsr \inst, \inst, #4 710 add \arg_index, \arg_index, #1 711 // Handle extra argument in arg array taken by a long. 712 cmp wip, #74 // if (wip != 'J') goto LOOP 713 b.ne 1b 714 lsr \inst, \inst, #4 715 add \arg_index, \arg_index, #1 716 b 1b // goto LOOP 7172: // FOUND_DOUBLE 718 and ip, \inst, #0xf 719 GET_VREG wip, wip 720 lsr \inst, \inst, #4 721 add \arg_index, \arg_index, #1 722 cmp \arg_index, #4 723 b.eq 5f 724 and ip2, \inst, #0xf 725 lsr \inst, \inst, #4 726 add \arg_index, \arg_index, #1 727 b 6f 7285: 729 // TODO: Extract from wINST here and below? (Requires using a different register 730 // in the COMMON_INVOKE_NON_RANGE.) 731 FETCH_B wip2, 0, 1 732 and wip2, wip2, #0xf 7336: 734 GET_VREG wip2, wip2 735 add ip, ip, ip2, lsl #32 736 fmov \dreg, ip 737 b 4f 7383: // FOUND_FLOAT 739 cmp \arg_index, #4 740 b.eq 7f 741 and ip, \inst, #0xf 742 lsr \inst, \inst, #4 743 add \arg_index, \arg_index, #1 744 b 8f 7457: 746 FETCH_B wip, 0, 1 747 and wip, wip, #0xf 7488: 749 GET_VREG \sreg, wip 7504: 751.endm 752 753// Puts the next int/long/object argument in the expected register, 754// fetching values based on a non-range invoke. 755// Uses ip and ip2. 756.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg64, gpr_reg32, inst, shorty, arg_index, finished 7571: // LOOP 758 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 759 cbz wip, \finished // if (wip == '\0') goto finished 760 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 761 b.eq 2f 762 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 763 b.eq 3f 764 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 765 b.eq 4f 766 cmp \arg_index, #4 767 b.eq 7f 768 and ip, \inst, #0xf 769 lsr \inst, \inst, #4 770 add \arg_index, \arg_index, #1 771 b 8f 7727: 773 FETCH_B wip, 0, 1 774 and wip, wip, #0xf 7758: 776 GET_VREG \gpr_reg32, wip 777 b 5f 7782: // FOUND_LONG 779 and ip, \inst, #0xf 780 GET_VREG wip, wip 781 lsr \inst, \inst, #4 782 add \arg_index, \arg_index, #1 783 cmp \arg_index, #4 784 b.eq 9f 785 and ip2, \inst, #0xf 786 lsr \inst, \inst, #4 787 add \arg_index, \arg_index, #1 788 b 10f 7899: 790 FETCH_B wip2, 0, 1 791 and wip2, wip2, #0xf 79210: 793 GET_VREG wip2, wip2 794 add \gpr_reg64, ip, ip2, lsl #32 795 b 5f 7963: // SKIP_FLOAT 797 lsr \inst, \inst, #4 798 add \arg_index, \arg_index, #1 799 b 1b 8004: // SKIP_DOUBLE 801 lsr \inst, \inst, #4 802 add \arg_index, \arg_index, #1 803 cmp \arg_index, #4 804 b.eq 1b 805 lsr \inst, \inst, #4 806 add \arg_index, \arg_index, #1 807 b 1b 8085: 809.endm 810 811.macro SETUP_RETURN_VALUE shorty 812 ldrb wip, [\shorty] 813 cmp ip, #68 // Test if result type char == 'D'. 814 b.eq 1f 815 cmp ip, #70 // Test if result type char == 'F'. 816 b.ne 2f 817 fmov w0, s0 818 b 2f 8191: 820 fmov x0, d0 8212: 822.endm 823 824.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 825 .if \is_polymorphic 826 // We always go to compiled code for polymorphic calls. 827 .elseif \is_custom 828 // We always go to compiled code for custom calls. 829 .else 830 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix 831 GET_CODE_ITEM 832 .if \is_string_init 833 bl nterp_to_nterp_string_init_non_range 834 .elseif \is_static 835 bl nterp_to_nterp_static_non_range 836 .else 837 bl nterp_to_nterp_instance_non_range 838 .endif 839 b .Ldone_return_\suffix 840 .endif 841 842.Lcall_compiled_code_\suffix: 843 .if \is_polymorphic 844 // No fast path for polymorphic calls. 845 .elseif \is_custom 846 // No fast path for custom calls. 847 .elseif \is_string_init 848 // No fast path for string.init. 849 .else 850 ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 851 tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_\suffix 852 FETCH_B wip2, 0, 1 853 asr ip, ip2, #4 854 .if \is_static 855 cbz ip, .Linvoke_fast_path_\suffix 856 .else 857 cmp ip, #1 858 b.eq .Linvoke_fast_path_\suffix 859 .endif 860 FETCH w8, 2 861 cmp ip, #2 862 .if \is_static 863 b.lt .Lone_arg_fast_path_\suffix 864 .endif 865 b.eq .Ltwo_args_fast_path_\suffix 866 cmp ip, #4 867 b.lt .Lthree_args_fast_path_\suffix 868 b.eq .Lfour_args_fast_path_\suffix 869 870 and ip, ip2, #15 871 GET_VREG w5, wip 872.Lfour_args_fast_path_\suffix: 873 asr ip, x8, #12 874 GET_VREG w4, wip 875.Lthree_args_fast_path_\suffix: 876 ubfx ip, x8, #8, #4 877 GET_VREG w3, wip 878.Ltwo_args_fast_path_\suffix: 879 ubfx ip, x8, #4, #4 880 GET_VREG w2, wip 881.Lone_arg_fast_path_\suffix: 882 .if \is_static 883 and ip, x8, #0xf 884 GET_VREG w1, wip 885 .else 886 // First argument already in w1. 887 .endif 888.Linvoke_fast_path_\suffix: 889 .if \is_interface 890 // Setup hidden argument. 891 mov ip2, x26 892 .endif 893 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 894 blr lr 895 FETCH_ADVANCE_INST 3 896 GET_INST_OPCODE ip 897 GOTO_OPCODE ip 898 899.Lfast_path_with_few_args_\suffix: 900 // Fast path when we have zero or one argument (modulo 'this'). If there 901 // is one argument, we can put it in both floating point and core register. 902 FETCH_B w2, 0, 1 903 .if \is_static 904 cmp w2, #(2 << 4) 905 .else 906 cmp w2, #(3 << 4) 907 .endif 908 b.ge .Lget_shorty_\suffix 909 .if \is_static 910 tbz w2, #4, .Linvoke_with_few_args_\suffix 911 .else 912 tbnz w2, #4, .Linvoke_with_few_args_\suffix 913 .endif 914 FETCH w2, 2 915 .if \is_static 916 and w2, w2, #0xf // dex register of first argument 917 GET_VREG w1, w2 918 fmov s0, w1 919 .else 920 ubfx x2, x2, #4, #4 // dex register of second argument 921 GET_VREG w2, w2 922 fmov s0, w2 923 .endif 924.Linvoke_with_few_args_\suffix: 925 // Check if the next instruction is move-result or move-result-wide. 926 // If it is, we fetch the shorty and jump to the regular invocation. 927 FETCH w27, 3 928 and ip, x27, #0xfe 929 cmp ip, #0x0a 930 b.eq .Lget_shorty_and_invoke_\suffix 931 .if \is_interface 932 // Setup hidden argument. 933 mov ip2, x26 934 .endif 935 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 936 blr lr 937 # TODO: Use some other register for shorty and prefetch the instruction directly to wINST. 938 mov xINST, x27 939 ADVANCE 3 940 GET_INST_OPCODE ip 941 GOTO_OPCODE ip 942.Lget_shorty_and_invoke_\suffix: 943 GET_SHORTY_SLOW_PATH xINST, \is_interface 944 b .Lgpr_setup_finished_\suffix 945 .endif 946 947.Lget_shorty_\suffix: 948 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom 949 // From this point: 950 // - xINST contains shorty (in callee-save to switch over return value after call). 951 // - x0 contains method 952 // - x1 contains 'this' pointer for instance method. 953 // - for interface calls, x26 contains the interface method. 954 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 955 FETCH w11, 2 // arguments 956 .if \is_string_init 957 lsr x11, x11, #4 958 mov x10, #1 // ignore first argument 959 .elseif \is_static 960 mov x10, xzr // arg_index 961 .else 962 lsr x11, x11, #4 963 mov x10, #1 // ignore first argument 964 .endif 965 LOOP_OVER_SHORTY_LOADING_FPS d0, s0, x11, x9, x10, .Lxmm_setup_finished_\suffix 966 LOOP_OVER_SHORTY_LOADING_FPS d1, s1, x11, x9, x10, .Lxmm_setup_finished_\suffix 967 LOOP_OVER_SHORTY_LOADING_FPS d2, s2, x11, x9, x10, .Lxmm_setup_finished_\suffix 968 LOOP_OVER_SHORTY_LOADING_FPS d3, s3, x11, x9, x10, .Lxmm_setup_finished_\suffix 969 LOOP_OVER_SHORTY_LOADING_FPS d4, s4, x11, x9, x10, .Lxmm_setup_finished_\suffix 970.Lxmm_setup_finished_\suffix: 971 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 972 FETCH w11, 2 // arguments 973 .if \is_string_init 974 lsr x11, x11, #4 975 mov x10, #1 // ignore first argument 976 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix 977 .elseif \is_static 978 mov x10, xzr // arg_index 979 LOOP_OVER_SHORTY_LOADING_GPRS x1, w1, x11, x9, x10, .Lgpr_setup_finished_\suffix 980 .else 981 lsr x11, x11, #4 982 mov x10, #1 // ignore first argument 983 .endif 984 LOOP_OVER_SHORTY_LOADING_GPRS x2, w2, x11, x9, x10, .Lgpr_setup_finished_\suffix 985 LOOP_OVER_SHORTY_LOADING_GPRS x3, w3, x11, x9, x10, .Lgpr_setup_finished_\suffix 986 LOOP_OVER_SHORTY_LOADING_GPRS x4, w4, x11, x9, x10, .Lgpr_setup_finished_\suffix 987 LOOP_OVER_SHORTY_LOADING_GPRS x5, w5, x11, x9, x10, .Lgpr_setup_finished_\suffix 988.Lgpr_setup_finished_\suffix: 989 .if \is_polymorphic 990 bl art_quick_invoke_polymorphic 991 .elseif \is_custom 992 bl art_quick_invoke_custom 993 .else 994 .if \is_interface 995 // Setup hidden argument. 996 mov ip2, x26 997 .endif 998 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 999 blr lr 1000 .endif 1001 SETUP_RETURN_VALUE xINST 1002.Ldone_return_\suffix: 1003 /* resume execution of caller */ 1004 .if \is_string_init 1005 FETCH w11, 2 // arguments 1006 and x11, x11, #0xf 1007 GET_VREG w1, w11 1008 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0 1009 .endif 1010 1011 .if \is_polymorphic 1012 FETCH_ADVANCE_INST 4 1013 .else 1014 FETCH_ADVANCE_INST 3 1015 .endif 1016 GET_INST_OPCODE ip 1017 GOTO_OPCODE ip 1018.endm 1019 1020// Puts the next floating point argument into the expected register, 1021// fetching values based on a range invoke. 1022// Uses ip as temporary. 1023.macro LOOP_RANGE_OVER_SHORTY_LOADING_FPS dreg, sreg, shorty, arg_index, stack_index, finished 10241: // LOOP 1025 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1026 cbz wip, \finished // if (wip == '\0') goto finished 1027 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 1028 b.eq 2f 1029 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 1030 b.eq 3f 1031 add \arg_index, \arg_index, #1 1032 add \stack_index, \stack_index, #1 1033 // Handle extra argument in arg array taken by a long. 1034 cmp wip, #74 // if (wip != 'J') goto LOOP 1035 b.ne 1b 1036 add \arg_index, \arg_index, #1 1037 add \stack_index, \stack_index, #1 1038 b 1b // goto LOOP 10392: // FOUND_DOUBLE 1040 GET_VREG_DOUBLE \dreg, \arg_index 1041 add \arg_index, \arg_index, #2 1042 add \stack_index, \stack_index, #2 1043 b 4f 10443: // FOUND_FLOAT 1045 GET_VREG \sreg, \arg_index 1046 add \arg_index, \arg_index, #1 1047 add \stack_index, \stack_index, #1 10484: 1049.endm 1050 1051// Puts the next floating point argument into the expected stack slot, 1052// fetching values based on a range invoke. 1053// Uses ip as temporary. 1054// 1055// TODO: We could just copy all the vregs to the stack slots in a simple loop 1056// without looking at the shorty at all. (We could also drop 1057// the "stack_index" from the macros for loading registers.) We could also do 1058// that conditionally if argument word count > 6; otherwise we know that all 1059// args fit into registers. 1060.macro LOOP_RANGE_OVER_FPs shorty, arg_index, stack_index, finished 10611: // LOOP 1062 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1063 cbz wip, \finished // if (wip == '\0') goto finished 1064 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 1065 b.eq 2f 1066 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 1067 b.eq 3f 1068 add \arg_index, \arg_index, #1 1069 add \stack_index, \stack_index, #1 1070 // Handle extra argument in arg array taken by a long. 1071 cmp wip, #74 // if (wip != 'J') goto LOOP 1072 b.ne 1b 1073 add \arg_index, \arg_index, #1 1074 add \stack_index, \stack_index, #1 1075 b 1b // goto LOOP 10762: // FOUND_DOUBLE 1077 GET_VREG_WIDE ip, \arg_index 1078 add ip2, sp, \stack_index, uxtw #2 1079 str ip, [ip2] 1080 add \arg_index, \arg_index, #2 1081 add \stack_index, \stack_index, #2 1082 b 1b 10833: // FOUND_FLOAT 1084 GET_VREG wip, \arg_index 1085 str wip, [sp, \stack_index, uxtw #2] 1086 add \arg_index, \arg_index, #1 1087 add \stack_index, \stack_index, #1 1088 b 1b 1089.endm 1090 1091// Puts the next int/long/object argument in the expected register, 1092// fetching values based on a range invoke. 1093// Uses ip as temporary. 1094.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg64, reg32, shorty, arg_index, stack_index, finished 10951: // LOOP 1096 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1097 cbz wip, \finished // if (wip == '\0') goto finished 1098 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 1099 b.eq 2f 1100 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 1101 b.eq 3f 1102 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 1103 b.eq 4f 1104 GET_VREG \reg32, \arg_index 1105 add \arg_index, \arg_index, #1 1106 add \stack_index, \stack_index, #1 1107 b 5f 11082: // FOUND_LONG 1109 GET_VREG_WIDE \reg64, \arg_index 1110 add \arg_index, \arg_index, #2 1111 add \stack_index, \stack_index, #2 1112 b 5f 11133: // SKIP_FLOAT 1114 add \arg_index, \arg_index, #1 1115 add \stack_index, \stack_index, #1 1116 b 1b 11174: // SKIP_DOUBLE 1118 add \arg_index, \arg_index, #2 1119 add \stack_index, \stack_index, #2 1120 b 1b 11215: 1122.endm 1123 1124// Puts the next int/long/object argument in the expected stack slot, 1125// fetching values based on a range invoke. 1126// Uses ip as temporary. 1127.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished 11281: // LOOP 1129 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1130 cbz wip, \finished // if (wip == '\0') goto finished 1131 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 1132 b.eq 2f 1133 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 1134 b.eq 3f 1135 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 1136 b.eq 4f 1137 GET_VREG wip, \arg_index 1138 str wip, [sp, \stack_index, uxtw #2] 1139 add \arg_index, \arg_index, #1 1140 add \stack_index, \stack_index, #1 1141 b 1b 11422: // FOUND_LONG 1143 GET_VREG_WIDE ip, \arg_index 1144 add ip2, sp, \stack_index, uxtw #2 1145 str ip, [ip2] 1146 add \arg_index, \arg_index, #2 1147 add \stack_index, \stack_index, #2 1148 b 1b 11493: // SKIP_FLOAT 1150 add \arg_index, \arg_index, #1 1151 add \stack_index, \stack_index, #1 1152 b 1b 11534: // SKIP_DOUBLE 1154 add \arg_index, \arg_index, #2 1155 add \stack_index, \stack_index, #2 1156 b 1b 1157.endm 1158 1159.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 1160 .if \is_polymorphic 1161 // We always go to compiled code for polymorphic calls. 1162 .elseif \is_custom 1163 // We always go to compiled code for custom calls. 1164 .else 1165 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix 1166 GET_CODE_ITEM 1167 .if \is_string_init 1168 bl nterp_to_nterp_string_init_range 1169 .elseif \is_static 1170 bl nterp_to_nterp_static_range 1171 .else 1172 bl nterp_to_nterp_instance_range 1173 .endif 1174 b .Ldone_return_range_\suffix 1175 .endif 1176 1177.Lcall_compiled_code_range_\suffix: 1178 .if \is_polymorphic 1179 // No fast path for polymorphic calls. 1180 .elseif \is_custom 1181 // No fast path for custom calls. 1182 .elseif \is_string_init 1183 // No fast path for string.init. 1184 .else 1185 ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1186 tbz wip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG_BIT, .Lfast_path_with_few_args_range_\suffix 1187 FETCH_B wip2, 0, 1 // Number of arguments 1188 .if \is_static 1189 cbz ip2, .Linvoke_fast_path_range_\suffix 1190 .else 1191 cmp ip2, #1 1192 b.eq .Linvoke_fast_path_range_\suffix 1193 .endif 1194 FETCH wip, 2 // dex register of first argument 1195 add x8, xFP, wip, uxtw #2 // location of first dex register value 1196 cmp ip2, #2 1197 .if \is_static 1198 b.lt .Lone_arg_fast_path_range_\suffix 1199 .endif 1200 b.eq .Ltwo_args_fast_path_range_\suffix 1201 cmp ip2, #4 1202 b.lt .Lthree_args_fast_path_range_\suffix 1203 b.eq .Lfour_args_fast_path_range_\suffix 1204 cmp ip2, #6 1205 b.lt .Lfive_args_fast_path_range_\suffix 1206 b.eq .Lsix_args_fast_path_range_\suffix 1207 cmp ip2, #7 1208 b.eq .Lseven_args_fast_path_range_\suffix 1209 // Setup x8 to point to the stack location of parameters we do not need 1210 // to put parameters in. 1211 add x9, sp, #8 // Add space for the ArtMethod 1212 1213.Lloop_over_fast_path_range_\suffix: 1214 sub ip2, ip2, #1 1215 ldr wip, [x8, ip2, lsl #2] 1216 str wip, [x9, ip2, lsl #2] 1217 cmp ip2, #7 1218 b.ne .Lloop_over_fast_path_range_\suffix 1219 1220.Lseven_args_fast_path_range_\suffix: 1221 ldr w7, [x8, #24] 1222.Lsix_args_fast_path_range_\suffix: 1223 ldr w6, [x8, #20] 1224.Lfive_args_fast_path_range_\suffix: 1225 ldr w5, [x8, #16] 1226.Lfour_args_fast_path_range_\suffix: 1227 ldr w4, [x8, #12] 1228.Lthree_args_fast_path_range_\suffix: 1229 ldr w3, [x8, #8] 1230.Ltwo_args_fast_path_range_\suffix: 1231 ldr w2, [x8, #4] 1232.Lone_arg_fast_path_range_\suffix: 1233 .if \is_static 1234 ldr w1, [x8, #0] 1235 .else 1236 // First argument already in w1. 1237 .endif 1238.Linvoke_fast_path_range_\suffix: 1239 .if \is_interface 1240 // Setup hidden argument. 1241 mov ip2, x26 1242 .endif 1243 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 1244 blr lr 1245 FETCH_ADVANCE_INST 3 1246 GET_INST_OPCODE ip 1247 GOTO_OPCODE ip 1248 1249.Lfast_path_with_few_args_range_\suffix: 1250 // Fast path when we have zero or one argument (modulo 'this'). If there 1251 // is one argument, we can put it in both floating point and core register. 1252 FETCH_B w2, 0, 1 // number of arguments 1253 .if \is_static 1254 cmp w2, #1 1255 .else 1256 cmp w2, #2 1257 .endif 1258 b.lt .Linvoke_with_few_args_range_\suffix 1259 b.ne .Lget_shorty_range_\suffix 1260 FETCH w3, 2 // dex register of first argument 1261 .if \is_static 1262 GET_VREG w1, w3 1263 fmov s0, w1 1264 .else 1265 add w3, w3, #1 // Add 1 for next argument 1266 GET_VREG w2, w3 1267 fmov s0, w2 1268 .endif 1269.Linvoke_with_few_args_range_\suffix: 1270 // Check if the next instruction is move-result or move-result-wide. 1271 // If it is, we fetch the shorty and jump to the regular invocation. 1272 FETCH w27, 3 1273 and ip, x27, #0xfe 1274 cmp ip, #0x0a 1275 b.eq .Lget_shorty_and_invoke_range_\suffix 1276 .if \is_interface 1277 // Setup hidden argument. 1278 mov ip2, x26 1279 .endif 1280 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 1281 blr lr 1282 mov xINST, x27 1283 ADVANCE 3 1284 GET_INST_OPCODE ip 1285 GOTO_OPCODE ip 1286.Lget_shorty_and_invoke_range_\suffix: 1287 GET_SHORTY_SLOW_PATH xINST, \is_interface 1288 b .Lgpr_setup_finished_range_\suffix 1289 .endif 1290 1291.Lget_shorty_range_\suffix: 1292 GET_SHORTY xINST, \is_interface, \is_polymorphic, \is_custom 1293 // From this point: 1294 // - xINST contains shorty (in callee-save to switch over return value after call). 1295 // - x0 contains method 1296 // - x1 contains 'this' pointer for instance method. 1297 // - for interface calls, x26 contains the interface method. 1298 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 1299 FETCH w10, 2 // arguments 1300 .if \is_string_init 1301 add x10, x10, #1 // arg start index 1302 mov x11, #1 // index in stack 1303 .elseif \is_static 1304 mov x11, xzr // index in stack 1305 .else 1306 add x10, x10, #1 // arg start index 1307 mov x11, #1 // index in stack 1308 .endif 1309 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d0, s0, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1310 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d1, s1, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1311 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d2, s2, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1312 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d3, s3, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1313 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d4, s4, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1314 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d5, s5, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1315 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d6, s6, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1316 LOOP_RANGE_OVER_SHORTY_LOADING_FPS d7, s7, x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1317 // Store in the outs array (stored above the ArtMethod in the stack) 1318 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs. 1319 LOOP_RANGE_OVER_FPs x9, w10, w11, .Lxmm_setup_finished_range_\suffix 1320.Lxmm_setup_finished_range_\suffix: 1321 add x9, xINST, #1 // shorty + 1 ; ie skip return arg character 1322 FETCH w10, 2 // arguments 1323 .if \is_string_init 1324 add x10, x10, #1 // arg start index 1325 mov x11, #1 // index in stack 1326 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1327 .elseif \is_static 1328 mov x11, xzr // index in stack 1329 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x1, w1, x9, w10, w11 .Lgpr_setup_finished_range_\suffix 1330 .else 1331 add x10, x10, #1 // arg start index 1332 mov x11, #1 // index in stack 1333 .endif 1334 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x2, w2, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1335 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x3, w3, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1336 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x4, w4, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1337 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x5, w5, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1338 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x6, w6, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1339 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS x7, w7, x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1340 // Store in the outs array (stored above the ArtMethod in the stack) 1341 add x11, x11, #2 // Add two words for the ArtMethod stored before the outs. 1342 LOOP_RANGE_OVER_INTs x9, w10, w11, .Lgpr_setup_finished_range_\suffix 1343.Lgpr_setup_finished_range_\suffix: 1344 .if \is_polymorphic 1345 bl art_quick_invoke_polymorphic 1346 .elseif \is_custom 1347 bl art_quick_invoke_custom 1348 .else 1349 .if \is_interface 1350 // Setup hidden argument. 1351 mov ip2, x26 1352 .endif 1353 ldr lr, [x0, #ART_METHOD_QUICK_CODE_OFFSET_64] 1354 blr lr 1355 .endif 1356 SETUP_RETURN_VALUE xINST 1357.Ldone_return_range_\suffix: 1358 /* resume execution of caller */ 1359 .if \is_string_init 1360 FETCH w11, 2 // arguments 1361 GET_VREG w1, w11 1362 UPDATE_REGISTERS_FOR_STRING_INIT w1, w0 1363 .endif 1364 1365 .if \is_polymorphic 1366 FETCH_ADVANCE_INST 4 1367 .else 1368 FETCH_ADVANCE_INST 3 1369 .endif 1370 GET_INST_OPCODE ip 1371 GOTO_OPCODE ip 1372.endm 1373 1374.macro POISON_HEAP_REF_IF_OBJECT is_object, rRef 1375 .if \is_object 1376 POISON_HEAP_REF \rRef 1377 .endif 1378.endm 1379 1380.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label 1381 .if \is_object 1382 cbz \value, \label 1383 ldr ip, [xSELF, #THREAD_CARD_TABLE_OFFSET] 1384 lsr wip2, \holder, #CARD_TABLE_CARD_SHIFT 1385 strb wip, [ip, ip2] 1386\label: 1387 .endif 1388.endm 1389 1390// Puts the next int/long/object parameter passed in physical register 1391// in the expected dex register array entry, and in case of object in the 1392// expected reference array entry. 1393.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_64, gpr_32, shorty, arg_offset, regs, refs, finished 13941: // LOOP 1395 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1396 cbz wip, \finished // if (wip == '\0') goto finished 1397 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 1398 b.eq 2f 1399 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 1400 b.eq 3f 1401 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 1402 b.eq 4f 1403 str \gpr_32, [\regs, \arg_offset] 1404 cmp wip, #76 // if (wip != 'L') goto NOT_REFERENCE 1405 b.ne 6f 1406 str \gpr_32, [\refs, \arg_offset] 14076: // NOT_REFERENCE 1408 add \arg_offset, \arg_offset, #4 1409 b 5f 14102: // FOUND_LONG 1411 str \gpr_64, [\regs, \arg_offset] 1412 add \arg_offset, \arg_offset, #8 1413 b 5f 14143: // SKIP_FLOAT 1415 add \arg_offset, \arg_offset, #4 1416 b 1b 14174: // SKIP_DOUBLE 1418 add \arg_offset, \arg_offset, #8 1419 b 1b 14205: 1421.endm 1422 1423// Puts the next floating point parameter passed in physical register 1424// in the expected dex register array entry. 1425// Uses ip as temporary. 1426.macro LOOP_OVER_SHORTY_STORING_FPS dreg, sreg, shorty, arg_offset, fp, finished 14271: // LOOP 1428 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1429 cbz wip, \finished // if (wip == '\0') goto finished 1430 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 1431 b.eq 2f 1432 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 1433 b.eq 3f 1434 add \arg_offset, \arg_offset, #4 1435 // Handle extra argument in arg array taken by a long. 1436 cmp wip, #74 // if (wip != 'J') goto LOOP 1437 b.ne 1b 1438 add \arg_offset, \arg_offset, #4 1439 b 1b // goto LOOP 14402: // FOUND_DOUBLE 1441 str \dreg, [\fp, \arg_offset] 1442 add \arg_offset, \arg_offset, #8 1443 b 4f 14443: // FOUND_FLOAT 1445 str \sreg, [\fp, \arg_offset] 1446 add \arg_offset, \arg_offset, #4 14474: 1448.endm 1449 1450// Puts the next floating point parameter passed in stack 1451// in the expected dex register array entry. 1452// Uses ip as temporary. 1453// 1454// TODO: Or we could just spill regs to the reserved slots in the caller's 1455// frame and copy all regs in a simple loop. This time, however, we would 1456// need to look at the shorty anyway to look for the references. 1457// (The trade-off is different for passing arguments and receiving them.) 1458.macro LOOP_OVER_FPs shorty, arg_offset, regs, stack_ptr, finished 14591: // LOOP 1460 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1461 cbz wip, \finished // if (wip == '\0') goto finished 1462 cmp wip, #68 // if (wip == 'D') goto FOUND_DOUBLE 1463 b.eq 2f 1464 cmp wip, #70 // if (wip == 'F') goto FOUND_FLOAT 1465 b.eq 3f 1466 add \arg_offset, \arg_offset, #4 1467 // Handle extra argument in arg array taken by a long. 1468 cmp wip, #74 // if (wip != 'J') goto LOOP 1469 b.ne 1b 1470 add \arg_offset, \arg_offset, #4 1471 b 1b // goto LOOP 14722: // FOUND_DOUBLE 1473 add ip, \stack_ptr, \arg_offset 1474 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1475 str ip, [\regs, \arg_offset] 1476 add \arg_offset, \arg_offset, #8 1477 b 1b 14783: // FOUND_FLOAT 1479 add ip, \stack_ptr, \arg_offset 1480 ldr wip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1481 str wip, [\regs, \arg_offset] 1482 add \arg_offset, \arg_offset, #4 1483 b 1b 1484.endm 1485 1486// Puts the next int/long/object parameter passed in stack 1487// in the expected dex register array entry, and in case of object in the 1488// expected reference array entry. 1489// Uses ip and ip2 as temporary. 1490.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, finished 14911: // LOOP 1492 ldrb wip, [\shorty], #1 // Load next character in shorty, and increment. 1493 cbz wip, \finished // if (wip == '\0') goto finished 1494 cmp wip, #74 // if (wip == 'J') goto FOUND_LONG 1495 b.eq 2f 1496 cmp wip, #70 // if (wip == 'F') goto SKIP_FLOAT 1497 b.eq 3f 1498 cmp wip, #68 // if (wip == 'D') goto SKIP_DOUBLE 1499 b.eq 4f 1500 add ip2, \stack_ptr, \arg_offset 1501 ldr wip2, [ip2, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1502 str wip2, [\regs, \arg_offset] 1503 cmp wip, #76 // if (wip != 'L') goto loop 1504 b.ne 3f 1505 str wip2, [\refs, \arg_offset] 1506 add \arg_offset, \arg_offset, #4 1507 b 1b 15082: // FOUND_LONG 1509 add ip, \stack_ptr, \arg_offset 1510 ldr ip, [ip, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1511 str ip, [\regs, \arg_offset] 1512 add \arg_offset, \arg_offset, #8 1513 b 1b 15143: // SKIP_FLOAT 1515 add \arg_offset, \arg_offset, #4 1516 b 1b 15174: // SKIP_DOUBLE 1518 add \arg_offset, \arg_offset, #8 1519 b 1b 1520.endm 1521 1522.macro SETUP_REFERENCE_PARAMETER_IN_GPR gpr32, regs, refs, ins, arg_offset, finished 1523 str \gpr32, [\regs, \arg_offset] 1524 sub \ins, \ins, #1 1525 str \gpr32, [\refs, \arg_offset] 1526 add \arg_offset, \arg_offset, #4 1527 cbz \ins, \finished 1528.endm 1529 1530// Uses ip2 as temporary. 1531.macro SETUP_REFERENCE_PARAMETERS_IN_STACK regs, refs, ins, stack_ptr, arg_offset 15321: 1533 ldr wip2, [\stack_ptr, \arg_offset] 1534 sub \ins, \ins, #1 1535 str wip2, [\regs, \arg_offset] 1536 str wip2, [\refs, \arg_offset] 1537 add \arg_offset, \arg_offset, #4 1538 cbnz \ins, 1b 1539.endm 1540 1541.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot 1542 ldr wip, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1543 tbz wip, #ART_METHOD_IS_MEMORY_SHARED_FLAG_BIT, \if_hot 1544 // Intrinsics are always in the boot image and considered hot. 1545 tbnz wip, #ART_METHOD_IS_INTRINSIC_FLAG_BIT, \if_hot 1546 ldr wip, [xSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET] 1547 cbz wip, \if_hot 1548 add wip, wip, #-1 1549 str wip, [xSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET] 1550 b \if_not_hot 1551.endm 1552 1553.macro DO_SUSPEND_CHECK continue_label 1554 ldr wip, [xSELF, #THREAD_FLAGS_OFFSET] 1555 tst wip, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 1556 b.eq \continue_label 1557 EXPORT_PC 1558 bl art_quick_test_suspend 1559.endm 1560 1561%def entry(): 1562/* 1563 * ArtMethod entry point. 1564 * 1565 * On entry: 1566 * x0 ArtMethod* callee 1567 * rest method parameters 1568 */ 1569 1570OAT_ENTRY ExecuteNterpWithClinitImpl 1571 .cfi_startproc 1572 // For simplicity, we don't do a read barrier here, but instead rely 1573 // on art_quick_resolution_trampoline to always have a suspend point before 1574 // calling back here. 1575 ldr wip, [x0, #ART_METHOD_DECLARING_CLASS_OFFSET] 1576 ldr wip2, [ip, #MIRROR_CLASS_STATUS_OFFSET] 1577 lsr wip2, wip2, #MIRROR_CLASS_STATUS_SHIFT 1578 cmp wip2, #MIRROR_CLASS_STATUS_VISIBLY_INITIALIZED 1579 b.hs ExecuteNterpImpl 1580 cmp wip2, #MIRROR_CLASS_STATUS_INITIALIZED 1581 b.lo .Linitializing_check 1582 dmb ish 1583 b ExecuteNterpImpl 1584.Linitializing_check: 1585 cmp wip2, #MIRROR_CLASS_STATUS_INITIALIZING 1586 b.lo .Lresolution_trampoline 1587 ldr wip2, [ip, #MIRROR_CLASS_CLINIT_THREAD_ID_OFFSET] 1588 ldr wip, [xSELF, #THREAD_TID_OFFSET] 1589 cmp wip, wip2 1590 b.eq ExecuteNterpImpl 1591.Lresolution_trampoline: 1592 b art_quick_resolution_trampoline 1593 .cfi_endproc 1594 .type EndExecuteNterpWithClinitImpl, #function 1595 .hidden EndExecuteNterpWithClinitImpl 1596 .global EndExecuteNterpWithClinitImpl 1597EndExecuteNterpWithClinitImpl: 1598 1599OAT_ENTRY ExecuteNterpImpl 1600 .cfi_startproc 1601 sub x16, sp, #STACK_OVERFLOW_RESERVED_BYTES 1602 ldr wzr, [x16] 1603 /* Spill callee save regs */ 1604 SPILL_ALL_CALLEE_SAVES 1605 1606 ldr xPC, [x0, #ART_METHOD_DATA_OFFSET_64] 1607 // Setup the stack for executing the method. 1608 SETUP_STACK_FRAME xPC, xREFS, xFP, CFI_REFS, load_ins=1 1609 1610 // Setup the parameters 1611 cbz w15, .Lxmm_setup_finished 1612 1613 sub ip2, ip, x15 1614 ldr w26, [x0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1615 lsl x27, ip2, #2 // x27 is now the offset for inputs into the registers array. 1616 1617 tbz w26, #ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG_BIT, .Lsetup_slow_path 1618 // Setup pointer to inputs in FP and pointer to inputs in REFS 1619 add x10, xFP, x27 1620 add x11, xREFS, x27 1621 mov x12, #0 1622 SETUP_REFERENCE_PARAMETER_IN_GPR w1, x10, x11, w15, x12, .Lxmm_setup_finished 1623 SETUP_REFERENCE_PARAMETER_IN_GPR w2, x10, x11, w15, x12, .Lxmm_setup_finished 1624 SETUP_REFERENCE_PARAMETER_IN_GPR w3, x10, x11, w15, x12, .Lxmm_setup_finished 1625 SETUP_REFERENCE_PARAMETER_IN_GPR w4, x10, x11, w15, x12, .Lxmm_setup_finished 1626 SETUP_REFERENCE_PARAMETER_IN_GPR w5, x10, x11, w15, x12, .Lxmm_setup_finished 1627 SETUP_REFERENCE_PARAMETER_IN_GPR w6, x10, x11, w15, x12, .Lxmm_setup_finished 1628 SETUP_REFERENCE_PARAMETER_IN_GPR w7, x10, x11, w15, x12, .Lxmm_setup_finished 1629 add x28, x28, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK 1630 SETUP_REFERENCE_PARAMETERS_IN_STACK x10, x11, w15, x28, x12 1631 b .Lxmm_setup_finished 1632 1633.Lsetup_slow_path: 1634 // If the method is not static and there is one argument ('this'), we don't need to fetch the 1635 // shorty. 1636 tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lsetup_with_shorty 1637 str w1, [xFP, x27] 1638 str w1, [xREFS, x27] 1639 cmp w15, #1 1640 b.eq .Lxmm_setup_finished 1641 1642.Lsetup_with_shorty: 1643 // TODO: Get shorty in a better way and remove below 1644 SPILL_ALL_ARGUMENTS 1645 bl NterpGetShorty 1646 // Save shorty in callee-save xIBASE. 1647 mov xIBASE, x0 1648 RESTORE_ALL_ARGUMENTS 1649 1650 // Setup pointer to inputs in FP and pointer to inputs in REFS 1651 add x10, xFP, x27 1652 add x11, xREFS, x27 1653 mov x12, #0 1654 1655 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character 1656 tbnz w26, #ART_METHOD_IS_STATIC_FLAG_BIT, .Lhandle_static_method 1657 add x10, x10, #4 1658 add x11, x11, #4 1659 add x28, x28, #4 1660 b .Lcontinue_setup_gprs 1661.Lhandle_static_method: 1662 LOOP_OVER_SHORTY_STORING_GPRS x1, w1, x9, x12, x10, x11, .Lgpr_setup_finished 1663.Lcontinue_setup_gprs: 1664 LOOP_OVER_SHORTY_STORING_GPRS x2, w2, x9, x12, x10, x11, .Lgpr_setup_finished 1665 LOOP_OVER_SHORTY_STORING_GPRS x3, w3, x9, x12, x10, x11, .Lgpr_setup_finished 1666 LOOP_OVER_SHORTY_STORING_GPRS x4, w4, x9, x12, x10, x11, .Lgpr_setup_finished 1667 LOOP_OVER_SHORTY_STORING_GPRS x5, w5, x9, x12, x10, x11, .Lgpr_setup_finished 1668 LOOP_OVER_SHORTY_STORING_GPRS x6, w6, x9, x12, x10, x11, .Lgpr_setup_finished 1669 LOOP_OVER_SHORTY_STORING_GPRS x7, w7, x9, x12, x10, x11, .Lgpr_setup_finished 1670 LOOP_OVER_INTs x9, x12, x10, x11, x28, .Lgpr_setup_finished 1671.Lgpr_setup_finished: 1672 add x9, xIBASE, #1 // shorty + 1 ; ie skip return arg character 1673 mov x12, #0 // reset counter 1674 LOOP_OVER_SHORTY_STORING_FPS d0, s0, x9, x12, x10, .Lxmm_setup_finished 1675 LOOP_OVER_SHORTY_STORING_FPS d1, s1, x9, x12, x10, .Lxmm_setup_finished 1676 LOOP_OVER_SHORTY_STORING_FPS d2, s2, x9, x12, x10, .Lxmm_setup_finished 1677 LOOP_OVER_SHORTY_STORING_FPS d3, s3, x9, x12, x10, .Lxmm_setup_finished 1678 LOOP_OVER_SHORTY_STORING_FPS d4, s4, x9, x12, x10, .Lxmm_setup_finished 1679 LOOP_OVER_SHORTY_STORING_FPS d5, s5, x9, x12, x10, .Lxmm_setup_finished 1680 LOOP_OVER_SHORTY_STORING_FPS d6, s6, x9, x12, x10, .Lxmm_setup_finished 1681 LOOP_OVER_SHORTY_STORING_FPS d7, s7, x9, x12, x10, .Lxmm_setup_finished 1682 LOOP_OVER_FPs x9, x12, x10, x28, .Lxmm_setup_finished 1683.Lxmm_setup_finished: 1684 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 1685 1686 // Set rIBASE 1687 adr xIBASE, artNterpAsmInstructionStart 1688 /* start executing the instruction at xPC */ 1689 START_EXECUTING_INSTRUCTIONS 1690 /* NOTE: no fallthrough */ 1691 // cfi info continues, and covers the whole nterp implementation. 1692 SIZE ExecuteNterpImpl 1693 1694%def opcode_pre(): 1695 1696%def fetch_from_thread_cache(dest_reg, miss_label): 1697 // Fetch some information from the thread cache. 1698 // Uses ip and ip2 as temporaries. 1699 add ip, xSELF, #THREAD_INTERPRETER_CACHE_OFFSET // cache address 1700 ubfx ip2, xPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2 // entry index 1701 add ip, ip, ip2, lsl #4 // entry address within the cache 1702 ldp ip, ${dest_reg}, [ip] // entry key (pc) and value (offset) 1703 cmp ip, xPC 1704 b.ne ${miss_label} 1705 1706%def footer(): 1707/* 1708 * =========================================================================== 1709 * Common subroutines and data 1710 * =========================================================================== 1711 */ 1712 1713 .text 1714 .align 2 1715 1716// Enclose all code below in a symbol (which gets printed in backtraces). 1717NAME_START nterp_helper 1718 1719// Note: mterp also uses the common_* names below for helpers, but that's OK 1720// as the assembler compiled each interpreter separately. 1721common_errDivideByZero: 1722 EXPORT_PC 1723 bl art_quick_throw_div_zero 1724 1725// Expect index in w1, length in w3. 1726common_errArrayIndex: 1727 EXPORT_PC 1728 mov x0, x1 1729 mov x1, x3 1730 bl art_quick_throw_array_bounds 1731 1732common_errNullObject: 1733 EXPORT_PC 1734 bl art_quick_throw_null_pointer_exception 1735 1736NterpCommonInvokeStatic: 1737 COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic" 1738 1739NterpCommonInvokeStaticRange: 1740 COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic" 1741 1742NterpCommonInvokeInstance: 1743 COMMON_INVOKE_NON_RANGE suffix="invokeInstance" 1744 1745NterpCommonInvokeInstanceRange: 1746 COMMON_INVOKE_RANGE suffix="invokeInstance" 1747 1748NterpCommonInvokeInterface: 1749 COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface" 1750 1751NterpCommonInvokeInterfaceRange: 1752 COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface" 1753 1754NterpCommonInvokePolymorphic: 1755 COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1756 1757NterpCommonInvokePolymorphicRange: 1758 COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1759 1760NterpCommonInvokeCustom: 1761 COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1762 1763NterpCommonInvokeCustomRange: 1764 COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1765 1766NterpHandleStringInit: 1767 COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit" 1768 1769NterpHandleStringInitRange: 1770 COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit" 1771 1772NterpHandleHotnessOverflow: 1773 CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=1f, if_not_hot=5f 17741: 1775 mov x1, xPC 1776 mov x2, xFP 1777 bl nterp_hot_method 1778 cbnz x0, 3f 17792: 1780 FETCH wINST, 0 // load wINST 1781 GET_INST_OPCODE ip // extract opcode from wINST 1782 GOTO_OPCODE ip // jump to next instruction 17833: 1784 // Drop the current frame. 1785 ldr ip, [xREFS, #-8] 1786 mov sp, ip 1787 .cfi_def_cfa sp, CALLEE_SAVES_SIZE 1788 1789 // The transition frame of type SaveAllCalleeSaves saves x19 and x20, 1790 // but not managed ABI. So we need to restore callee-saves of the nterp frame, 1791 // and save managed ABI callee saves, which will be restored by the callee upon 1792 // return. 1793 RESTORE_ALL_CALLEE_SAVES 1794 INCREASE_FRAME ((CALLEE_SAVES_SIZE) - 16) 1795 1796 // FP callee-saves 1797 stp d8, d9, [sp, #0] 1798 stp d10, d11, [sp, #16] 1799 stp d12, d13, [sp, #32] 1800 stp d14, d15, [sp, #48] 1801 1802 // GP callee-saves. 1803 SAVE_TWO_REGS x21, x22, 64 1804 SAVE_TWO_REGS x23, x24, 80 1805 SAVE_TWO_REGS x25, x26, 96 1806 SAVE_TWO_REGS x27, x28, 112 1807 SAVE_TWO_REGS x29, lr, 128 1808 1809 // Setup the new frame 1810 ldr x1, [x0, #OSR_DATA_FRAME_SIZE] 1811 // Given stack size contains all callee saved registers, remove them. 1812 sub x1, x1, #(CALLEE_SAVES_SIZE - 16) 1813 1814 // We know x1 cannot be 0, as it at least contains the ArtMethod. 1815 1816 // Remember CFA in a callee-save register. 1817 mov xINST, sp 1818 .cfi_def_cfa_register xINST 1819 1820 sub sp, sp, x1 1821 1822 add x2, x0, #OSR_DATA_MEMORY 18234: 1824 sub x1, x1, #8 1825 ldr ip, [x2, x1] 1826 str ip, [sp, x1] 1827 cbnz x1, 4b 1828 1829 // Fetch the native PC to jump to and save it in a callee-save register. 1830 ldr xFP, [x0, #OSR_DATA_NATIVE_PC] 1831 1832 // Free the memory holding OSR Data. 1833 bl free 1834 1835 // Jump to the compiled code. 1836 br xFP 18375: 1838 DO_SUSPEND_CHECK continue_label=2b 1839 b 2b 1840 1841// This is the logical end of ExecuteNterpImpl, where the frame info applies. 1842// EndExecuteNterpImpl includes the methods below as we want the runtime to 1843// see them as part of the Nterp PCs. 1844.cfi_endproc 1845 1846nterp_to_nterp_static_non_range: 1847 .cfi_startproc 1848 SETUP_STACK_FOR_INVOKE 1849 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0 1850 .cfi_endproc 1851 1852nterp_to_nterp_string_init_non_range: 1853 .cfi_startproc 1854 SETUP_STACK_FOR_INVOKE 1855 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1856 .cfi_endproc 1857 1858nterp_to_nterp_instance_non_range: 1859 .cfi_startproc 1860 SETUP_STACK_FOR_INVOKE 1861 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 1862 .cfi_endproc 1863 1864nterp_to_nterp_static_range: 1865 .cfi_startproc 1866 SETUP_STACK_FOR_INVOKE 1867 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1 1868 .cfi_endproc 1869 1870nterp_to_nterp_instance_range: 1871 .cfi_startproc 1872 SETUP_STACK_FOR_INVOKE 1873 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0 1874 .cfi_endproc 1875 1876nterp_to_nterp_string_init_range: 1877 .cfi_startproc 1878 SETUP_STACK_FOR_INVOKE 1879 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1880 .cfi_endproc 1881 1882NAME_END nterp_helper 1883 1884// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter 1885// entry point. 1886 .type EndExecuteNterpImpl, #function 1887 .hidden EndExecuteNterpImpl 1888 .global EndExecuteNterpImpl 1889EndExecuteNterpImpl: 1890 1891// Entrypoints into runtime. 1892NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField 1893NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset 1894NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray 1895NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange 1896NTERP_TRAMPOLINE nterp_get_class, NterpGetClass 1897NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject 1898NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod 1899NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod 1900NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject 1901 1902ENTRY nterp_deliver_pending_exception 1903 DELIVER_PENDING_EXCEPTION 1904END nterp_deliver_pending_exception 1905 1906// gen_mterp.py will inline the following definitions 1907// within [ExecuteNterpImpl, EndExecuteNterpImpl). 1908%def instruction_end(): 1909 1910 .type artNterpAsmInstructionEnd, #function 1911 .hidden artNterpAsmInstructionEnd 1912 .global artNterpAsmInstructionEnd 1913artNterpAsmInstructionEnd: 1914 // artNterpAsmInstructionEnd is used as landing pad for exception handling. 1915 FETCH_INST 1916 GET_INST_OPCODE ip 1917 GOTO_OPCODE ip 1918 1919%def instruction_start(): 1920 1921 .type artNterpAsmInstructionStart, #function 1922 .hidden artNterpAsmInstructionStart 1923 .global artNterpAsmInstructionStart 1924artNterpAsmInstructionStart = .L_op_nop 1925 .text 1926 1927%def opcode_name_prefix(): 1928% return "nterp_" 1929%def opcode_start(): 1930 NAME_START nterp_${opcode} 1931 # Explicitly restore CFA, just in case the previous opcode clobbered it (by .cfi_def_*). 1932 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -8, CALLEE_SAVES_SIZE 1933%def opcode_end(): 1934 NAME_END nterp_${opcode} 1935 // Advance to the end of this handler. Causes error if we are past that point. 1936 .org nterp_${opcode} + NTERP_HANDLER_SIZE // ${opcode} handler is too big! 1937%def opcode_slow_path_start(name): 1938 NAME_START ${name} 1939%def opcode_slow_path_end(name): 1940 NAME_END ${name} 1941