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