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/arm/asm_support_arm.S" 24 25/** 26 * ARM EABI general notes: 27 * 28 * r0-r3 hold first 4 args to a method; they are not preserved across method calls 29 * r4-r8 are available for general use 30 * r9 is given special treatment in some situations, but not for us 31 * r10 (sl) seems to be generally available 32 * r11 (fp) is used by gcc (unless -fomit-frame-pointer is set) 33 * r12 (ip) is scratch -- not preserved across method calls 34 * r13 (sp) should be managed carefully in case a signal arrives 35 * r14 (lr) must be preserved 36 * r15 (pc) can be tinkered with directly 37 * 38 * r0 holds returns of <= 4 bytes 39 * r0-r1 hold returns of 8 bytes, low word in r0 40 * 41 * Callee must save/restore r4+ (except r12) if it modifies them. If VFP 42 * is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved, 43 * s0-s15 (d0-d7, q0-a3) do not need to be. 44 * 45 * Stack is "full descending". Only the arguments that don't fit in the first 4 46 * registers are placed on the stack. "sp" points at the first stacked argument 47 * (i.e. the 5th arg). 48 * 49 * Native ABI uses soft-float, single-precision results are in r0, 50 * double-precision results in r0-r1. 51 * 52 * In the EABI, "sp" must be 64-bit aligned on entry to a function, and any 53 * 64-bit quantities (long long, double) must be 64-bit aligned. 54 * 55 * Nterp notes: 56 * 57 * The following registers have fixed assignments: 58 * 59 * reg nick purpose 60 * r5 rFP interpreted frame pointer, used for accessing locals and args 61 * r6 rREFS base of object references of dex registers 62 * r7 rINST first 16-bit code unit of current instruction 63 * r8 rMR marking register 64 * r9 rSELF self (Thread) pointer 65 * r10 rIBASE interpreted instruction base pointer, used for computed goto 66 * r11 rPC interpreted program counter, used for fetching instructions 67 * 68 * r4, ip, and lr can be used as temporary 69 * 70 * Note that r4 is a callee-save register in ARM EABI, but not in managed code. 71 * 72 */ 73 74/* single-purpose registers, given names for clarity */ 75#define CFI_DEX 11 // DWARF register number of the register holding dex-pc (rPC). 76#define CFI_TMP 0 // DWARF register number of the first argument register (r0). 77#define CFI_REFS 6 78#define rFP r5 79#define rREFS r6 80#define rINST r7 81#define rSELF r9 82#define rIBASE r10 83#define rPC r11 84 85// To avoid putting ifdefs arond the use of rMR, make sure it's defined. 86// IsNterpSupported returns false for configurations that don't have rMR (typically CMS). 87#ifndef rMR 88#define rMR r8 89#endif 90 91// Temporary registers while setting up a frame. 92#define rNEW_FP r8 93#define rNEW_REFS r10 94#define CFI_NEW_REFS 10 95 96#define CALLEE_SAVES_SIZE (9 * 4 + 16 * 4) 97 98// +4 for the ArtMethod of the caller. 99#define OFFSET_TO_FIRST_ARGUMENT_IN_STACK (CALLEE_SAVES_SIZE + 4) 100 101/* 102 * Fetch the next instruction from rPC into rINST. Does not advance rPC. 103 */ 104.macro FETCH_INST 105 ldrh rINST, [rPC] 106.endm 107 108/* 109 * Fetch the next instruction from the specified offset. Advances rPC 110 * to point to the next instruction. "count" is in 16-bit code units. 111 * 112 * Because of the limited size of immediate constants on ARM, this is only 113 * suitable for small forward movements (i.e. don't try to implement "goto" 114 * with this). 115 * 116 * This must come AFTER anything that can throw an exception, or the 117 * exception catch may miss. (This also implies that it must come after 118 * EXPORT_PC.) 119 */ 120.macro FETCH_ADVANCE_INST count 121 ldrh rINST, [rPC, #((\count)*2)]! 122.endm 123 124/* 125 * Similar to FETCH_ADVANCE_INST, but does not update xPC. Used to load 126 * rINST ahead of possible exception point. Be sure to manually advance xPC 127 * later. 128 */ 129.macro PREFETCH_INST count 130 ldrh rINST, [rPC, #((\count)*2)] 131.endm 132 133/* Advance xPC by some number of code units. */ 134.macro ADVANCE count 135 add rPC, #((\count)*2) 136.endm 137 138/* 139 * Fetch the next instruction from an offset specified by "reg" and advance xPC. 140 * xPC to point to the next instruction. "reg" must specify the distance 141 * in bytes, *not* 16-bit code units, and may be a signed value. 142 */ 143.macro FETCH_ADVANCE_INST_RB reg 144 ldrh rINST, [rPC, \reg]! 145.endm 146 147/* 148 * Fetch a half-word code unit from an offset past the current PC. The 149 * "count" value is in 16-bit code units. Does not advance xPC. 150 * 151 * The "_S" variant works the same but treats the value as signed. 152 */ 153.macro FETCH reg, count 154 ldrh \reg, [rPC, #((\count)*2)] 155.endm 156 157.macro FETCH_S reg, count 158 ldrsh \reg, [rPC, #((\count)*2)] 159.endm 160 161/* 162 * Fetch one byte from an offset past the current PC. Pass in the same 163 * "count" as you would for FETCH, and an additional 0/1 indicating which 164 * byte of the halfword you want (lo/hi). 165 */ 166.macro FETCH_B reg, count, byte 167 ldrb \reg, [rPC, #((\count)*2+(\byte))] 168.endm 169 170/* 171 * Put the instruction's opcode field into the specified register. 172 */ 173.macro GET_INST_OPCODE reg 174 and \reg, rINST, #255 175.endm 176 177/* 178 * Begin executing the opcode in _reg. Clobbers reg 179 */ 180 181.macro GOTO_OPCODE reg 182 add pc, rIBASE, \reg, lsl #${handler_size_bits} 183.endm 184 185/* 186 * Get/set value from a Dalvik register. 187 */ 188.macro GET_VREG reg, vreg 189 ldr \reg, [rFP, \vreg, lsl #2] 190.endm 191.macro GET_VREG_OBJECT reg, vreg 192 ldr \reg, [rREFS, \vreg, lsl #2] 193.endm 194.macro SET_VREG reg, vreg 195 str \reg, [rFP, \vreg, lsl #2] 196 mov \reg, #0 197 str \reg, [rREFS, \vreg, lsl #2] 198.endm 199.macro SET_VREG_OBJECT reg, vreg 200 str \reg, [rFP, \vreg, lsl #2] 201 str \reg, [rREFS, \vreg, lsl #2] 202.endm 203.macro SET_VREG_FLOAT reg, vreg, tmpreg 204 add \tmpreg, rFP, \vreg, lsl #2 205 vstr \reg, [\tmpreg] 206 mov \tmpreg, #0 207 str \tmpreg, [rREFS, \vreg, lsl #2] 208.endm 209.macro GET_VREG_WIDE_BY_ADDR reg0, reg1, addr 210 ldmia \addr, {\reg0, \reg1} 211.endm 212.macro SET_VREG_WIDE_BY_ADDR reg0, reg1, addr 213 stmia \addr, {\reg0, \reg1} 214.endm 215.macro GET_VREG_FLOAT sreg, vreg 216 ldr \vreg, [rFP, \vreg, lsl #2] 217 vmov \sreg, \vreg 218.endm 219.macro GET_VREG_FLOAT_BY_ADDR reg, addr 220 vldr \reg, [\addr] 221.endm 222.macro SET_VREG_FLOAT_BY_ADDR reg, addr 223 vstr \reg, [\addr] 224.endm 225.macro GET_VREG_DOUBLE_BY_ADDR reg, addr 226 vldr \reg, [\addr] 227.endm 228.macro SET_VREG_DOUBLE_BY_ADDR reg, addr 229 vstr \reg, [\addr] 230.endm 231.macro SET_VREG_SHADOW reg, vreg 232 str \reg, [rREFS, \vreg, lsl #2] 233.endm 234.macro CLEAR_SHADOW_PAIR vreg, tmp1, tmp2 235 mov \tmp1, #0 236 add \tmp2, \vreg, #1 237 SET_VREG_SHADOW \tmp1, \vreg 238 SET_VREG_SHADOW \tmp1, \tmp2 239.endm 240.macro VREG_INDEX_TO_ADDR reg, vreg 241 add \reg, rFP, \vreg, lsl #2 242.endm 243 244// An assembly entry for nterp. 245.macro OAT_ENTRY name 246 .arm 247 .type \name, #function 248 .hidden \name 249 .global \name 250 .balign 16 251\name: 252.endm 253 254.macro SIZE name 255 .size \name, .-\name 256.endm 257 258.macro NAME_START name 259 .arm 260 .type \name, #function 261 .hidden \name // Hide this as a global symbol, so we do not incur plt calls. 262 .global \name 263 /* Cache alignment for function entry */ 264 .balign 16 265\name: 266.endm 267 268.macro NAME_END name 269 SIZE \name 270.endm 271 272// Macro for defining entrypoints into runtime. We don't need to save registers 273// (we're not holding references there), but there is no 274// kDontSave runtime method. So just use the kSaveRefsOnly runtime method. 275.macro NTERP_TRAMPOLINE name, helper 276ENTRY \name 277 SETUP_SAVE_REFS_ONLY_FRAME ip 278 bl \helper 279 RESTORE_SAVE_REFS_ONLY_FRAME 280 REFRESH_MARKING_REGISTER 281 ldr ip, [rSELF, #THREAD_EXCEPTION_OFFSET] @ Get exception field. 282 cmp ip, #0 283 bne nterp_deliver_pending_exception 284 bx lr 285END \name 286.endm 287 288.macro CLEAR_STATIC_VOLATILE_MARKER reg 289 and \reg, \reg, #-2 290.endm 291 292.macro CLEAR_INSTANCE_VOLATILE_MARKER reg 293 rsb \reg, \reg, #0 294.endm 295 296.macro EXPORT_PC 297 str rPC, [rREFS, #-8] 298.endm 299 300.macro BRANCH 301 add rPC, rPC, rINST, lsl #1 302 // Update method counter and do a suspend check if the branch is negative or zero. 303 cmp rINST, #0 304 ble 2f 3051: 306 FETCH_INST // load rINST 307 GET_INST_OPCODE ip // extract opcode from rINST 308 GOTO_OPCODE ip // jump to next instruction 3092: 310 ldr r0, [sp] 311 ldrh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 312 cmp r2, #NTERP_HOTNESS_VALUE 313 beq NterpHandleHotnessOverflow 314 add r2, r2, #-1 315 strh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 316 DO_SUSPEND_CHECK continue_label=1b 317 b 1b 318.endm 319 320.macro TEST_IF_MARKING label 321 cmp rMR, #0 322 bne \label 323.endm 324 325// Expects: 326// - ip and lr to be available. 327// Outputs: 328// - \registers contains the dex registers size 329// - \outs contains the outs size 330// - if load_ins is 1, \ins contains the ins 331// - \code_item is replaced with a pointer to the instructions 332.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins 333 tst \code_item, #1 334 beq 5f 335 bic \code_item, \code_item, #1 // Remove the extra bit that marks it's a compact dex file 336 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FIELDS_OFFSET] 337 ubfx \registers, lr, #COMPACT_CODE_ITEM_REGISTERS_SIZE_SHIFT, #4 338 ubfx \outs, lr, #COMPACT_CODE_ITEM_OUTS_SIZE_SHIFT, #4 339 .if \load_ins 340 ubfx \ins, lr, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4 341 .else 342 ubfx ip, lr, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4 343 add \registers, \registers, ip 344 .endif 345 346 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET] 347 tst lr, #COMPACT_CODE_ITEM_REGISTERS_INS_OUTS_FLAGS 348 beq 4f 349 mov ip, \code_item 350 tst lr, #COMPACT_CODE_ITEM_INSNS_FLAG 351 beq 1f 352 sub ip, ip, #4 3531: 354 tst lr, #COMPACT_CODE_ITEM_REGISTERS_FLAG 355 beq 2f 356 ldrh lr, [ip, #-2]! 357 add \registers, \registers, lr 358 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET] 3592: 360 tst lr, #COMPACT_CODE_ITEM_INS_FLAG 361 beq 3f 362 ldrh lr, [ip, #-2]! 363 .if \load_ins 364 add \ins, \ins, lr 365 .else 366 add \registers, \registers, lr 367 .endif 368 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET] 3693: 370 tst lr, #COMPACT_CODE_ITEM_OUTS_FLAG 371 beq 4f 372 ldrh lr, [ip, #-2]! 373 add \outs, \outs, lr 3744: 375 .if \load_ins 376 add \registers, \registers, \ins 377 .endif 378 add \code_item, \code_item, #COMPACT_CODE_ITEM_INSNS_OFFSET 379 b 6f 3805: 381 // Fetch dex register size. 382 ldrh \registers, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET] 383 // Fetch outs size. 384 ldrh \outs, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET] 385 .if \load_ins 386 ldrh \ins, [\code_item, #CODE_ITEM_INS_SIZE_OFFSET] 387 .endif 388 add \code_item, \code_item, #CODE_ITEM_INSNS_OFFSET 3896: 390.endm 391 392// Setup the stack to start executing the method. Expects: 393// - r0 to contain the ArtMethod 394// - \code_item to already contain the code item 395// - rINST, ip, lr to be available 396// 397// Outputs 398// - rINST contains the dex registers size 399// - ip contains the old stack pointer. 400// - \code_item is replaced with a pointer to the instructions 401// - if load_ins is 1, r4 contains the ins 402// 403.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins 404 FETCH_CODE_ITEM_INFO \code_item, rINST, \refs, r4, \load_ins 405 406 // Compute required frame size: ((2 * rINST) + \refs) * 4 + 12 407 // 12 is for saving the previous frame, pc, and method being executed. 408 add ip, \refs, rINST, lsl #1 409 410 // Compute new stack pointer in lr 411 sub lr, sp, #12 412 sub lr, lr, ip, lsl #2 413 // Alignment 414 and lr, lr, #-16 415 416 // Set reference and dex registers. 417 add \refs, lr, \refs, lsl #2 418 add \refs, \refs, #12 419 add \fp, \refs, rINST, lsl #2 420 421 // Now setup the stack pointer. 422 mov ip, sp 423 .cfi_def_cfa_register ip 424 mov sp, lr 425 str ip, [\refs, #-4] 426 CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -4, CALLEE_SAVES_SIZE 427 428 // Save the ArtMethod, and use r0 as a temporary. 429 str r0, [sp] 430 431 // Put nulls in reference frame. 432 cmp rINST, #0 433 beq 2f 434 mov lr, \refs 435 mov r0, #0 4361: 437 str r0, [lr], #4 438 str r0, [lr], #4 // May clear vreg[0]. 439 cmp lr, \fp 440 blo 1b 4412: 442 ldr r0, [sp] // Reload the ArtMethod, expected by the callers. 443.endm 444 445// Increase method hotness and do suspend check before starting executing the method. 446.macro START_EXECUTING_INSTRUCTIONS 447 ldr r0, [sp] 448 ldrh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 449 cmp r2, #NTERP_HOTNESS_VALUE 450 beq 3f 451 add r2, r2, #-1 452 strh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 4531: 454 DO_SUSPEND_CHECK continue_label=2f 4552: 456 FETCH_INST 457 GET_INST_OPCODE ip 458 GOTO_OPCODE ip 4593: 460 CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=4f, if_not_hot=1b 4614: 462 mov r1, #0 463 mov r2, rFP 464 bl nterp_hot_method 465 b 2b 466.endm 467 468.macro SPILL_ALL_CALLEE_SAVES 469 SPILL_ALL_CALLEE_SAVE_GPRS @ 9 words (36 bytes) of callee saves. 470 vpush {s16-s31} @ 16 words (64 bytes) of floats. 471 .cfi_adjust_cfa_offset 64 472.endm 473 474.macro RESTORE_ALL_CALLEE_SAVES lr_to_pc=0 475 vpop {s16-s31} 476 .cfi_adjust_cfa_offset -64 477 pop {r4-r7} 478 .cfi_adjust_cfa_offset -16 479 .cfi_restore r4 480 .cfi_restore r5 481 .cfi_restore r6 482 .cfi_restore r7 483 // Don't restore r8, the marking register gets updated when coming back from runtime. 484 add sp, sp, #4 485 .cfi_adjust_cfa_offset -4 486 .if \lr_to_pc 487 pop {r9-r11, pc} @ 9 words of callee saves and args. 488 .cfi_adjust_cfa_offset -16 489 .else 490 pop {r9-r11, lr} @ 9 words of callee saves and args. 491 .cfi_adjust_cfa_offset -16 492 .cfi_restore r9 493 .cfi_restore r10 494 .cfi_restore r11 495 .cfi_restore lr 496 .endif 497.endm 498 499// Helper to setup the stack after doing a nterp to nterp call. This will setup: 500// - rNEW_FP: the new pointer to dex registers 501// - rNEW_REFS: the new pointer to references 502// - rPC: the new PC pointer to execute 503// - r2: value in instruction to decode the number of arguments. 504// - r3: first dex register for range invokes, up to 4 arguments for non-range invokes. 505// - r4: top of dex register array 506// 507// The method expects: 508// - r0 to contain the ArtMethod 509// - r4 to contain the code item 510.macro SETUP_STACK_FOR_INVOKE 511 // We do the same stack overflow check as the compiler. See CanMethodUseNterp 512 // in how we limit the maximum nterp frame size. 513 sub ip, sp, #STACK_OVERFLOW_RESERVED_BYTES 514 ldr ip, [ip] 515 516 // Spill all callee saves to have a consistent stack frame whether we 517 // are called by compiled code or nterp. 518 SPILL_ALL_CALLEE_SAVES 519 520 // Setup the frame. 521 SETUP_STACK_FRAME r4, rNEW_REFS, rNEW_FP, CFI_NEW_REFS, load_ins=0 522 523 // Fetch instruction information before replacing rPC. 524 FETCH_B r2, 0, 1 525 FETCH r3, 2 526 527 // Set the dex pc pointer. 528 mov rPC, r4 529 530 // Make r4 point to the top of the dex register array. 531 add r4, rNEW_FP, rINST, lsl #2 532 533 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 534.endm 535 536// Setup arguments based on a non-range nterp to nterp call, and start executing 537// the method. We expect: 538// - rNEW_FP: the new pointer to dex registers 539// - rPC: the new PC pointer to execute 540// - r2: number of arguments (bits 4-7), 5th argument if any (bits 0-3) 541// - r3: up to four dex register arguments 542// - r4: top of dex register array 543// - r1: receiver if non-static. 544// 545// Uses r0 and rINST as temporaries. 546.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 547 // /* op vA, vB, {vC...vG} */ 548 .if \is_static 549 asrs r0, r2, #4 550 beq 6f 551 .else 552 asr r0, r2, #4 553 .endif 554 mov rINST, #-4 555 cmp r0, #2 556 blt 1f 557 beq 2f 558 cmp r0, #4 559 blt 3f 560 beq 4f 561 562 // We use a decrementing rINST to store references relative 563 // to rNEW_FP and dex registers relative to r4 564 // 565 // TODO: We could set up rINST as the number of registers (this can be an additional output from 566 // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg. 567 // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS. 5685: 569 and r2, r2, #15 570 GET_VREG_OBJECT r0, r2 571 str r0, [rNEW_FP, rINST] 572 GET_VREG r0, r2 573 str r0, [r4, rINST] 574 sub rINST, rINST, #4 5754: 576 asr r2, r3, #12 577 GET_VREG_OBJECT r0, r2 578 str r0, [rNEW_FP, rINST] 579 GET_VREG r0, r2 580 str r0, [r4, rINST] 581 sub rINST, rINST, #4 5823: 583 ubfx r2, r3, #8, #4 584 GET_VREG_OBJECT r0, r2 585 str r0, [rNEW_FP, rINST] 586 GET_VREG r0, r2 587 str r0, [r4, rINST] 588 sub rINST, rINST, #4 5892: 590 ubfx r2, r3, #4, #4 591 GET_VREG_OBJECT r0, r2 592 str r0, [rNEW_FP, rINST] 593 GET_VREG r0, r2 594 str r0, [r4, rINST] 595 .if !\is_string_init 596 sub rINST, rINST, #4 597 .endif 5981: 599 .if \is_string_init 600 // Ignore the first argument 601 .elseif \is_static 602 and r2, r3, #0xf 603 GET_VREG_OBJECT r0, r2 604 str r0, [rNEW_FP, rINST] 605 GET_VREG r0, r2 606 str r0, [r4, rINST] 607 .else 608 str r1, [rNEW_FP, rINST] 609 str r1, [r4, rINST] 610 .endif 611 6126: 613 // Start executing the method. 614 mov rFP, rNEW_FP 615 mov rREFS, rNEW_REFS 616 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE 617 // r8 was used for setting up the frame, restore it now. 618 REFRESH_MARKING_REGISTER 619 // Branch to the main handler, which will reload rIBASE, 620 // that was used for setting up the frame. 621 b .Lexecute_instructions 622.endm 623 624// Setup arguments based on a range nterp to nterp call, and start executing 625// the method. 626// - rNEW_FP: the new pointer to dex registers 627// - rNEW_REFS: the new pointer to references 628// - rPC: the new PC pointer to execute 629// - r2: number of arguments 630// - r3: first dex register 631// - r4: top of dex register array 632// - r1: receiver if non-static. 633// 634// Expects r0 to be available. 635.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 636 mov r0, #-4 637 .if \is_string_init 638 // Ignore the first argument 639 sub r2, r2, #1 640 add r3, r3, #1 641 .elseif !\is_static 642 sub r2, r2, #1 643 add r3, r3, #1 644 .endif 645 646 cmp r2, #0 647 beq 2f 648 add rREFS, rREFS, r3, lsl #2 // pointer to first argument in reference array 649 add rREFS, rREFS, r2, lsl #2 // pointer to last argument in reference array 650 add rFP, rFP, r3, lsl #2 // pointer to first argument in register array 651 add rFP, rFP, r2, lsl #2 // pointer to last argument in register array 6521: 653 ldr r3, [rREFS, #-4]! 654 str r3, [rNEW_FP, r0] 655 subs r2, r2, 1 656 ldr r3, [rFP, #-4]! 657 str r3, [r4, r0] 658 sub r0, r0, 4 659 bne 1b 6602: 661 .if \is_string_init 662 // Ignore first argument 663 .elseif !\is_static 664 str r1, [rNEW_FP, r0] 665 str r1, [r4, r0] 666 .endif 667 mov rFP, rNEW_FP 668 mov rREFS, rNEW_REFS 669 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE 670 // r8 was used for setting up the frame, restore it now. 671 REFRESH_MARKING_REGISTER 672 // Branch to the main handler, which will reload rIBASE, 673 // that was used for setting up the frame. 674 b .Lexecute_instructions 675.endm 676 677.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom 678 push {r0-r3} 679 .if \is_polymorphic 680 ldr r0, [sp, #16] 681 mov r1, rPC 682 bl NterpGetShortyFromInvokePolymorphic 683 .elseif \is_custom 684 ldr r0, [sp, #16] 685 mov r1, rPC 686 bl NterpGetShortyFromInvokeCustom 687 .elseif \is_interface 688 ldr r0, [sp, #16] 689 FETCH r1, 1 690 bl NterpGetShortyFromMethodId 691 .else 692 bl NterpGetShorty 693 .endif 694 mov \dest, r0 695 pop {r0-r3} 696.endm 697 698// Input: r0 contains the ArtMethod 699// Output: r4 contains the code item 700.macro GET_CODE_ITEM 701 ldr r4, [r0, #ART_METHOD_DATA_OFFSET_32] 702.endm 703 704.macro DO_ENTRY_POINT_CHECK call_compiled_code, name 705 // On entry, the method is r0, the instance is r1 706 ldr r2, .Lfetch_nterp_\name 707.Lfetch_location_\name: 708 // Note that this won't work for thumb. 709 sub r2, pc, r2 710 ldr r3, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 711 cmp r2, r3 712 bne \call_compiled_code 713.endm 714 715// Expects ip and lr to be available. 716.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value 717 mov ip, #0 7181: 719 GET_VREG_OBJECT lr, ip 720 cmp lr, \old_value 721 bne 2f 722 SET_VREG_OBJECT \new_value, ip 7232: 724 add ip, ip, #1 725 add lr, rREFS, ip, lsl #2 726 cmp lr, rFP 727 bne 1b 728.endm 729 730// Puts the next floating point argument into the expected register, 731// fetching values based on a non-range invoke. 732// Uses ip and lr. 733.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished, if_double 7341: // LOOP 735 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 736 cmp ip, #0 737 beq \finished // if (ip == '\0') goto finished 738 cmp ip, #68 // if (ip == 'D') goto FOUND_DOUBLE 739 beq 2f 740 cmp ip, #70 // if (ip == 'F') goto FOUND_FLOAT 741 beq 3f 742 lsr \inst, \inst, #4 743 add \arg_index, \arg_index, #1 744 // Handle extra argument in arg array taken by a long. 745 cmp ip, #74 // if (ip != 'J') goto LOOP 746 bne 1b 747 lsr \inst, \inst, #4 748 add \arg_index, \arg_index, #1 749 b 1b // goto LOOP 7502: // FOUND_DOUBLE 751 and ip, \inst, #0xf 752 GET_VREG ip, ip 753 lsr \inst, \inst, #4 754 add \arg_index, \arg_index, #1 755 cmp \arg_index, #4 756 beq 5f 757 and lr, \inst, #0xf 758 lsr \inst, \inst, #4 759 add \arg_index, \arg_index, #1 760 b 6f 7615: 762 FETCH_B lr, 0, 1 763 and lr, lr, #0xf 7646: 765 GET_VREG lr, lr 766 vmov \dreg, ip, lr 767 b \if_double 7683: // FOUND_FLOAT 769 cmp \arg_index, #4 770 beq 7f 771 and ip, \inst, #0xf 772 lsr \inst, \inst, #4 773 add \arg_index, \arg_index, #1 774 b 8f 7757: 776 FETCH_B ip, 0, 1 777 and ip, ip, #0xf 7788: 779 GET_VREG_FLOAT \sreg, ip 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. 785.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg, inst, shorty, arg_index, finished, if_long, is_r3 7861: // LOOP 787 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 788 cmp ip, #0 789 beq \finished // if (ip == '\0') goto finished 790 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 791 beq 2f 792 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 793 beq 3f 794 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 795 beq 4f 796 cmp \arg_index, #4 797 beq 7f 798 and ip, \inst, #0xf 799 lsr \inst, \inst, #4 800 add \arg_index, \arg_index, #1 801 b 8f 8027: 803 FETCH_B ip, 0, 1 804 and ip, ip, #0xf 8058: 806 GET_VREG \gpr_reg, ip 807 b 5f 8082: // FOUND_LONG 809 .if \is_r3 810 // Put back shorty and exit 811 sub \shorty, \shorty, #1 812 b 5f 813 .endif 814 and ip, \inst, #0xf 815 GET_VREG ip, ip 816 // The only one possible for non-range long is r2-r3 817 mov r2, ip 818 lsr \inst, \inst, #4 819 add \arg_index, \arg_index, #1 820 cmp \arg_index, #4 821 beq 9f 822 and ip, \inst, #0xf 823 lsr \inst, \inst, #4 824 b 10f 8259: 826 FETCH_B ip, 0, 1 827 and ip, ip, #0xf 82810: 829 GET_VREG ip, ip 830 // The only one possible for non-range long is r2-r3 831 mov r3, ip 832 add \arg_index, \arg_index, #1 833 b \if_long 8343: // SKIP_FLOAT 835 lsr \inst, \inst, #4 836 add \arg_index, \arg_index, #1 837 b 1b 8384: // SKIP_DOUBLE 839 lsr \inst, \inst, #8 840 add \arg_index, \arg_index, #2 841 b 1b 8425: 843.endm 844 845// Puts the next int/long/object argument in the expected stack slot, 846// fetching values based on a non-range invoke. 847// Uses ip as temporary. 848.macro LOOP_OVER_SHORTY_LOADING_INTs shorty, inst, arg_index, finished, is_string_init 8491: // LOOP 850 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 851 cmp ip, #0 852 beq \finished // if (ip == '\0') goto finished 853 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 854 beq 2f 855 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 856 beq 3f 857 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 858 beq 4f 859 .if \is_string_init 860 cmp \arg_index, #4 861 .else 862 cmp \arg_index, #(4+1) // +1 for ArtMethod 863 .endif 864 beq 7f 865 and ip, \inst, #0xf 866 lsr \inst, \inst, #4 867 b 8f 8687: 869 FETCH_B ip, 0, 1 870 and ip, ip, #0xf 8718: 872 GET_VREG ip, ip 873 str ip, [sp, \arg_index, lsl #2] 874 add \arg_index, \arg_index, #1 875 b 1b 8762: // FOUND_LONG 877 and ip, \inst, #0xf 878 GET_VREG ip, ip 879 str ip, [sp, \arg_index, lsl #2] 880 lsr \inst, \inst, #4 881 add \arg_index, \arg_index, #1 882 .if \is_string_init 883 cmp \arg_index, #4 884 .else 885 cmp \arg_index, #(4+1) // +1 for ArtMethod 886 .endif 887 beq 9f 888 and ip, \inst, #0xf 889 lsr \inst, \inst, #4 890 b 10f 8919: 892 FETCH_B ip, 0, 1 893 and ip, ip, #0xf 89410: 895 GET_VREG ip, ip 896 str ip, [sp, \arg_index, lsl #2] 897 add \arg_index, \arg_index, #1 898 b 1b 8993: // SKIP_FLOAT 900 lsr \inst, \inst, #4 901 add \arg_index, \arg_index, #1 902 b 1b 9034: // SKIP_DOUBLE 904 lsr \inst, \inst, #8 905 add \arg_index, \arg_index, #2 906 b 1b 907.endm 908 909.macro SETUP_RETURN_VALUE shorty 910 ldrb ip, [\shorty] 911 cmp ip, #68 // Test if result type char == 'D'. 912 beq 1f 913 cmp ip, #70 // Test if result type char == 'F'. 914 bne 2f 915 vmov r0, s0 916 b 2f 9171: 918 vmov r0, r1, d0 9192: 920.endm 921 922.macro GET_SHORTY_SLOW_PATH dest, is_interface 923 // Save all registers that can hold arguments in the fast path. 924 vpush {s0} 925 push {r0-r2} 926 .if \is_interface 927 ldr r0, [sp, #16] 928 FETCH r1, 1 929 bl NterpGetShortyFromMethodId 930 .else 931 bl NterpGetShorty 932 .endif 933 mov \dest, r0 934 pop {r0-r2} 935 vpop {s0} 936.endm 937 938.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 939 .if \is_polymorphic 940 // We always go to compiled code for polymorphic calls. 941 .elseif \is_custom 942 // We always go to compiled code for custom calls. 943 .else 944 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix, \suffix 945 GET_CODE_ITEM 946 .if \is_string_init 947 bl nterp_to_nterp_string_init_non_range 948 .elseif \is_static 949 bl nterp_to_nterp_static_non_range 950 .else 951 bl nterp_to_nterp_instance_non_range 952 .endif 953 b .Ldone_return_\suffix 954.Lfetch_nterp_\suffix: 955 .word (.Lfetch_location_\suffix+8) - ExecuteNterpImpl 956 .endif 957 958.Lcall_compiled_code_\suffix: 959 .if \is_polymorphic 960 // No fast path for polymorphic calls. 961 .elseif \is_custom 962 // No fast path for custom calls. 963 .elseif \is_string_init 964 // No fast path for string.init. 965 .else 966 ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 967 tst ip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG 968 beq .Lfast_path_with_few_args_\suffix 969 FETCH_B rINST, 0, 1 970 .if \is_static 971 asrs lr, rINST, #4 972 beq .Linvoke_fast_path_\suffix 973 .else 974 asr lr, rINST, #4 975 cmp lr, #1 976 beq .Linvoke_fast_path_\suffix 977 .endif 978 FETCH ip, 2 979 cmp lr, #2 980 .if \is_static 981 blt .Lone_arg_fast_path_\suffix 982 .endif 983 beq .Ltwo_args_fast_path_\suffix 984 cmp lr, #4 985 blt .Lthree_args_fast_path_\suffix 986 beq .Lfour_args_fast_path_\suffix 987 and rINST, rINST, #15 988 GET_VREG rINST, rINST 989 str rINST, [sp, #(4 + 4 * 4)] 990.Lfour_args_fast_path_\suffix: 991 asr rINST, ip, #12 992 GET_VREG rINST, rINST 993 str rINST, [sp, #(4 + 3 * 4)] 994.Lthree_args_fast_path_\suffix: 995 ubfx rINST, ip, #8, #4 996 GET_VREG r3, rINST 997.Ltwo_args_fast_path_\suffix: 998 ubfx rINST, ip, #4, #4 999 GET_VREG r2, rINST 1000.Lone_arg_fast_path_\suffix: 1001 .if \is_static 1002 and rINST, ip, #0xf 1003 GET_VREG r1, rINST 1004 .else 1005 // First argument already in r1. 1006 .endif 1007.Linvoke_fast_path_\suffix: 1008 .if \is_interface 1009 // Setup hidden argument. 1010 mov ip, r4 1011 .endif 1012 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1013 blx lr 1014 FETCH_ADVANCE_INST 3 1015 GET_INST_OPCODE ip 1016 GOTO_OPCODE ip 1017 1018.Lfast_path_with_few_args_\suffix: 1019 // Fast path when we have zero or one argument (modulo 'this'). If there 1020 // is one argument, we can put it in both floating point and core register. 1021 FETCH_B r2, 0, 1 1022 asr r2, r2, #4 // number of arguments 1023 .if \is_static 1024 cmp r2, #1 1025 blt .Linvoke_with_few_args_\suffix 1026 bne .Lget_shorty_\suffix 1027 FETCH r2, 2 1028 and r2, r2, #0xf // dex register of first argument 1029 GET_VREG r1, r2 1030 vmov s0, r1 1031 .else 1032 cmp r2, #2 1033 blt .Linvoke_with_few_args_\suffix 1034 bne .Lget_shorty_\suffix 1035 FETCH r2, 2 1036 ubfx r2, r2, #4, #4 // dex register of second argument 1037 GET_VREG r2, r2 1038 vmov s0, r2 1039 .endif 1040.Linvoke_with_few_args_\suffix: 1041 // Check if the next instruction is move-result or move-result-wide. 1042 // If it is, we fetch the shorty and jump to the regular invocation. 1043 FETCH r3, 3 1044 and r3, r3, #0xfe 1045 cmp r3, #0x0a 1046 beq .Lget_shorty_and_invoke_\suffix 1047 .if \is_interface 1048 // Setup hidden argument. 1049 mov ip, r4 1050 .endif 1051 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1052 blx lr 1053 FETCH_ADVANCE_INST 3 1054 GET_INST_OPCODE ip 1055 GOTO_OPCODE ip 1056.Lget_shorty_and_invoke_\suffix: 1057 .if \is_interface 1058 // Save hidden argument. 1059 vmov s16, r4 1060 .endif 1061 GET_SHORTY_SLOW_PATH rINST, \is_interface 1062 b .Lgpr_setup_finished_\suffix 1063 .endif 1064 1065.Lget_shorty_\suffix: 1066 .if \is_interface 1067 // Save hidden argument. 1068 vmov s16, r4 1069 .endif 1070 GET_SHORTY rINST, \is_interface, \is_polymorphic, \is_custom 1071 // From this point: 1072 // - rINST contains shorty (in callee-save to switch over return value after call). 1073 // - r0 contains method 1074 // - r1 contains 'this' pointer for instance method. 1075 // We need three registers. 1076 add r3, rINST, #1 // shorty + 1 ; ie skip return arg character 1077 FETCH r2, 2 // arguments 1078 .if \is_string_init 1079 lsr r2, r2, #4 1080 mov r4, #1 // ignore first argument 1081 .elseif \is_static 1082 mov r4, #0 // arg_index 1083 .else 1084 lsr r2, r2, #4 1085 mov r4, #1 // ignore first argument 1086 .endif 1087 LOOP_OVER_SHORTY_LOADING_FPS d0, s0, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ld1_s2_\suffix 1088.Ld1_s1_\suffix: 1089 LOOP_OVER_SHORTY_LOADING_FPS d1, s1, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ld2_s1_\suffix 1090.Ld1_s2_\suffix: 1091 LOOP_OVER_SHORTY_LOADING_FPS d1, s2, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ls4_\suffix 1092.Ld2_s3_\suffix: 1093 LOOP_OVER_SHORTY_LOADING_FPS d2, s3, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix 1094 b .Ls4_\suffix 1095.Ld2_s1_\suffix: 1096 LOOP_OVER_SHORTY_LOADING_FPS d2, s1, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix 1097.Ls4_\suffix: 1098 // If we arrive here, we can only have a float. 1099 LOOP_OVER_SHORTY_LOADING_FPS d2, s4, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix 1100.Lxmm_setup_finished_\suffix: 1101 add r4, rINST, #1 // shorty + 1 ; ie skip return arg character 1102 FETCH r8, 2 // arguments 1103 .if \is_string_init 1104 lsr r8, r8, #4 1105 mov lr, #1 // ignore first argument 1106 LOOP_OVER_SHORTY_LOADING_GPRS r1, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0 1107 .elseif \is_static 1108 mov lr, #0 // arg_index 1109 LOOP_OVER_SHORTY_LOADING_GPRS r1, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0 1110 .else 1111 lsr r8, r8, #4 1112 mov lr, #1 // ignore first argument 1113 .endif 1114 LOOP_OVER_SHORTY_LOADING_GPRS r2, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0 1115 LOOP_OVER_SHORTY_LOADING_GPRS r3, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=1 1116.Lif_long_\suffix: 1117 // Store in the outs array (stored above the ArtMethod in the stack). We only do this for non-string-init 1118 // calls as the index is already adjusted above. 1119 .if !\is_string_init 1120 add lr, lr, #1 1121 .endif 1122 LOOP_OVER_SHORTY_LOADING_INTs r4, r8, lr, .Lgpr_setup_finished_\suffix, \is_string_init 1123.Lgpr_setup_finished_\suffix: 1124 REFRESH_MARKING_REGISTER // r8 was used when setting parameters, restore it. 1125 .if \is_polymorphic 1126 bl art_quick_invoke_polymorphic 1127 .elseif \is_custom 1128 bl art_quick_invoke_custom 1129 .else 1130 .if \is_interface 1131 // Setup hidden argument. 1132 vmov ip, s16 1133 .endif 1134 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1135 blx lr 1136 .endif 1137 SETUP_RETURN_VALUE rINST 1138.Ldone_return_\suffix: 1139 /* resume execution of caller */ 1140 .if \is_string_init 1141 FETCH ip, 2 // arguments 1142 and ip, ip, #0xf 1143 GET_VREG r1, ip 1144 UPDATE_REGISTERS_FOR_STRING_INIT r1, r0 1145 .endif 1146 1147 .if \is_polymorphic 1148 FETCH_ADVANCE_INST 4 1149 .else 1150 FETCH_ADVANCE_INST 3 1151 .endif 1152 GET_INST_OPCODE ip 1153 GOTO_OPCODE ip 1154.endm 1155 1156// Puts the next int/long/object argument in the expected register, 1157// fetching values based on a range invoke. 1158// Uses ip as temporary. 1159.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg32, shorty, arg_index, stack_index, finished, if_long, is_r3 11601: // LOOP 1161 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 1162 cmp ip, #0 1163 beq \finished // if (ip == '\0') goto finished 1164 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 1165 beq 2f 1166 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 1167 beq 3f 1168 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 1169 beq 4f 1170 GET_VREG \reg32, \arg_index 1171 add \arg_index, \arg_index, #1 1172 add \stack_index, \stack_index, #1 1173 b 5f 11742: // FOUND_LONG 1175 .if \is_r3 1176 // Put back shorty and jump to \if_long 1177 sub \shorty, \shorty, #1 1178 .else 1179 GET_VREG r2, \arg_index 1180 add \arg_index, \arg_index, #1 1181 add \stack_index, \stack_index, #1 1182 GET_VREG r3, \arg_index 1183 add \arg_index, \arg_index, #1 1184 add \stack_index, \stack_index, #1 1185 .endif 1186 b \if_long 11873: // SKIP_FLOAT 1188 add \arg_index, \arg_index, #1 1189 add \stack_index, \stack_index, #1 1190 b 1b 11914: // SKIP_DOUBLE 1192 add \arg_index, \arg_index, #2 1193 add \stack_index, \stack_index, #2 1194 b 1b 11955: 1196.endm 1197 1198// Puts the next int/long/object argument in the expected stack slot, 1199// fetching values based on a range invoke. 1200// Uses ip as temporary. 1201.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished 12021: // LOOP 1203 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 1204 cmp ip, #0 1205 beq \finished // if (ip == '\0') goto finished 1206 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 1207 beq 2f 1208 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 1209 beq 3f 1210 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 1211 beq 4f 1212 GET_VREG ip, \arg_index 1213 str ip, [sp, \stack_index, lsl #2] 1214 add \arg_index, \arg_index, #1 1215 add \stack_index, \stack_index, #1 1216 b 1b 12172: // FOUND_LONG 1218 GET_VREG ip, \arg_index 1219 str ip, [sp, \stack_index, lsl #2] 1220 add \arg_index, \arg_index, #1 1221 add \stack_index, \stack_index, #1 1222 GET_VREG ip, \arg_index 1223 str ip, [sp, \stack_index, lsl #2] 1224 add \arg_index, \arg_index, #1 1225 add \stack_index, \stack_index, #1 1226 b 1b 12273: // SKIP_FLOAT 1228 add \arg_index, \arg_index, #1 1229 add \stack_index, \stack_index, #1 1230 b 1b 12314: // SKIP_DOUBLE 1232 add \arg_index, \arg_index, #2 1233 add \stack_index, \stack_index, #2 1234 b 1b 1235.endm 1236 1237.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 1238 .if \is_polymorphic 1239 // We always go to compiled code for polymorphic calls. 1240 .elseif \is_custom 1241 // We always go to compiled code for custom calls. 1242 .else 1243 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix, range_\suffix 1244 GET_CODE_ITEM 1245 .if \is_string_init 1246 bl nterp_to_nterp_string_init_range 1247 .elseif \is_static 1248 bl nterp_to_nterp_static_range 1249 .else 1250 bl nterp_to_nterp_instance_range 1251 .endif 1252 b .Ldone_return_range_\suffix 1253.Lfetch_nterp_range_\suffix: 1254 .word (.Lfetch_location_range_\suffix+8) - ExecuteNterpImpl 1255 .endif 1256 1257.Lcall_compiled_code_range_\suffix: 1258 .if \is_polymorphic 1259 // No fast path for polymorphic calls. 1260 .elseif \is_custom 1261 // No fast path for custom calls. 1262 .elseif \is_string_init 1263 // No fast path for string.init. 1264 .else 1265 ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1266 tst ip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG 1267 beq .Lfast_path_with_few_args_range_\suffix 1268 FETCH_B ip, 0, 1 // Number of arguments 1269 .if \is_static 1270 cmp ip, #0 1271 .else 1272 cmp ip, #1 1273 .endif 1274 beq .Linvoke_fast_path_range_\suffix 1275 FETCH lr, 2 // dex register of first argument 1276 add lr, rFP, lr, lsl #2 // location of first dex register value. 1277 .if \is_static 1278 cmp ip, #2 1279 blt .Lone_arg_fast_path_range_\suffix 1280 beq .Ltwo_args_fast_path_range_\suffix 1281 cmp ip, #3 1282 .else 1283 cmp ip, #3 1284 blt .Ltwo_args_fast_path_range_\suffix 1285 .endif 1286 beq .Lthree_args_fast_path_range_\suffix 1287 add rINST, sp, #4 // Add space for the ArtMethod 1288 1289.Lloop_over_fast_path_range_\suffix: 1290 sub ip, ip, #1 1291 ldr r3, [lr, ip, lsl #2] 1292 str r3, [rINST, ip, lsl #2] 1293 cmp ip, #3 1294 bne .Lloop_over_fast_path_range_\suffix 1295 1296.Lthree_args_fast_path_range_\suffix: 1297 ldr r3, [lr, #8] 1298.Ltwo_args_fast_path_range_\suffix: 1299 ldr r2, [lr, #4] 1300.Lone_arg_fast_path_range_\suffix: 1301 .if \is_static 1302 ldr r1, [lr, #0] 1303 .else 1304 // First argument already in r1. 1305 .endif 1306.Linvoke_fast_path_range_\suffix: 1307 .if \is_interface 1308 // Setup hidden argument. 1309 mov ip, r4 1310 .endif 1311 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1312 blx lr 1313 FETCH_ADVANCE_INST 3 1314 GET_INST_OPCODE ip 1315 GOTO_OPCODE ip 1316 1317.Lfast_path_with_few_args_range_\suffix: 1318 // Fast path when we have zero or one argument (modulo 'this'). If there 1319 // is one argument, we can put it in both floating point and core register. 1320 FETCH_B r2, 0, 1 // number of arguments 1321 .if \is_static 1322 cmp r2, #1 1323 blt .Linvoke_with_few_args_range_\suffix 1324 bne .Lget_shorty_range_\suffix 1325 FETCH r3, 2 // dex register of first argument 1326 GET_VREG r1, r3 1327 vmov s0, r1 1328 .else 1329 cmp r2, #2 1330 blt .Linvoke_with_few_args_range_\suffix 1331 bne .Lget_shorty_range_\suffix 1332 FETCH r3, 2 // dex register of first argument 1333 add r3, r3, #1 // Add 1 for next argument 1334 GET_VREG r2, r3 1335 vmov s0, r2 1336 .endif 1337.Linvoke_with_few_args_range_\suffix: 1338 // Check if the next instruction is move-result or move-result-wide. 1339 // If it is, we fetch the shorty and jump to the regular invocation. 1340 FETCH r3, 3 1341 and r3, r3, #0xfe 1342 cmp r3, #0x0a 1343 beq .Lget_shorty_and_invoke_range_\suffix 1344 .if \is_interface 1345 // Setup hidden argument. 1346 mov ip, r4 1347 .endif 1348 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1349 blx lr 1350 FETCH_ADVANCE_INST 3 1351 GET_INST_OPCODE ip 1352 GOTO_OPCODE ip 1353.Lget_shorty_and_invoke_range_\suffix: 1354 .if \is_interface 1355 // Save hidden argument. 1356 vmov s16, r4 1357 .endif 1358 GET_SHORTY_SLOW_PATH rINST, \is_interface 1359 b .Lgpr_setup_finished_range_\suffix 1360 .endif 1361 1362.Lget_shorty_range_\suffix: 1363 .if \is_interface 1364 // Save hidden argument. 1365 vmov s16, r4 1366 .endif 1367 GET_SHORTY rINST, \is_interface, \is_polymorphic, \is_custom 1368 // From this point: 1369 // - rINST contains shorty (in callee-save to switch over return value after call). 1370 // - r0 contains method 1371 // - r1 contains 'this' pointer for instance method. 1372 // 1373 // Save r0 and r1 before calling NterpSetupArm32Fprs. 1374 push {r0, r1} 1375 add r0, rINST, #1 // shorty + 1 ; ie skip return arg character 1376 FETCH r1, 2 // arguments 1377 .if \is_string_init 1378 add r1, r1, #1 // arg start index 1379 mov r2, #1 // index in stack 1380 .elseif \is_static 1381 mov r2, #0 // index in stack 1382 .else 1383 add r1, r1, #1 // arg start index 1384 mov r2, #1 // index in stack 1385 .endif 1386 vpush {s0-s15} 1387 mov r3, sp 1388 // Pass the stack address for arguments, +16 for fprs, +2 for saved registers, 1389 // +1 for ArtMethod. 1390 add lr, sp, #((16 + 2 + 1) * 4) 1391 push {rFP, lr} 1392 bl NterpSetupArm32Fprs 1393 add sp, sp, #8 1394 vpop {s0-s15} 1395 pop {r0, r1} 1396.Lxmm_setup_finished_range_\suffix: 1397 add r8, rINST, #1 // shorty + 1 ; ie skip return arg character 1398 FETCH lr, 2 // arguments 1399 .if \is_string_init 1400 add lr, lr, #1 // arg start index 1401 mov r4, #0 // index in stack 1402 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r1, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0 1403 .elseif \is_static 1404 mov r4, #0 // index in stack 1405 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r1, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0 1406 .else 1407 add lr, lr, #1 // arg start index 1408 mov r4, #1 // index in stack 1409 .endif 1410 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r2, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0 1411 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r3, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=1 1412.Lif_long_range_\suffix: 1413 // Add 1 word for the ArtMethod stored before the outs. 1414 add r4, r4, #1 1415 LOOP_RANGE_OVER_INTs r8, lr, r4, .Lgpr_setup_finished_range_\suffix 1416.Lgpr_setup_finished_range_\suffix: 1417 REFRESH_MARKING_REGISTER // r8 was used when setting parameters, restore it. 1418 .if \is_polymorphic 1419 bl art_quick_invoke_polymorphic 1420 .elseif \is_custom 1421 bl art_quick_invoke_custom 1422 .else 1423 .if \is_interface 1424 // Setup hidden argument. 1425 vmov ip, s16 1426 .endif 1427 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1428 blx lr 1429 .endif 1430 SETUP_RETURN_VALUE rINST 1431.Ldone_return_range_\suffix: 1432 /* resume execution of caller */ 1433 .if \is_string_init 1434 FETCH ip, 2 // arguments 1435 GET_VREG r1, ip 1436 UPDATE_REGISTERS_FOR_STRING_INIT r1, r0 1437 .endif 1438 1439 .if \is_polymorphic 1440 FETCH_ADVANCE_INST 4 1441 .else 1442 FETCH_ADVANCE_INST 3 1443 .endif 1444 GET_INST_OPCODE ip 1445 GOTO_OPCODE ip 1446.endm 1447 1448.macro POISON_HEAP_REF_IF_OBJECT is_object, rRef 1449 .if \is_object 1450 POISON_HEAP_REF \rRef 1451 .endif 1452.endm 1453 1454.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label, tmp 1455 .if \is_object 1456 // In T32, we would use `SMART_CBZ \value, \label` 1457 cmp \value, #0 1458 beq \label 1459 ldr ip, [rSELF, #THREAD_CARD_TABLE_OFFSET] 1460 lsr \tmp, \holder, #CARD_TABLE_CARD_SHIFT 1461 strb ip, [ip, \tmp] 1462\label: 1463 .endif 1464.endm 1465 1466.macro LDREXD_STREXD_LOOP addr, load1, load2, store1, store2, tmp, label 1467\label: 1468 ldrexd \load1, \load2, [\addr] 1469 strexd \tmp, \store1, \store2, [\addr] 1470 cmp \tmp, #0 1471 bne \label 1472.endm 1473 1474.macro ATOMIC_LOAD64 addr, load1, load2, tmp, label 1475 LDREXD_STREXD_LOOP \addr, \load1, \load2, \load1, \load2, \tmp, \label 1476.endm 1477 1478.macro ATOMIC_STORE64 addr, store1, store2, tmp1, tmp2, label 1479 LDREXD_STREXD_LOOP \addr, \tmp1, \tmp2, \store1, \store2, \tmp1, \label 1480.endm 1481 1482// Puts the next int/long/object parameter passed in physical register 1483// in the expected dex register array entry, and in case of object in the 1484// expected reference array entry. 1485// Uses ip as temporary. 1486.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_32, shorty, arg_offset, regs, refs, finished, if_long, is_r3 14871: // LOOP 1488 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 1489 cmp ip, #0 1490 beq \finished // if (ip == '\0') goto finished 1491 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 1492 beq 2f 1493 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 1494 beq 3f 1495 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 1496 beq 4f 1497 str \gpr_32, [\regs, \arg_offset] 1498 cmp ip, #76 // if (ip != 'L') goto NOT_REFERENCE 1499 bne 6f 1500 str \gpr_32, [\refs, \arg_offset] 15016: // NOT_REFERENCE 1502 add \arg_offset, \arg_offset, #4 1503 b 5f 15042: // FOUND_LONG 1505 .if \is_r3 1506 // Put back shorty and jump to \if_long 1507 sub \shorty, \shorty, #1 1508 .else 1509 // A long can only be in r2, r3 1510 str r2, [\regs, \arg_offset] 1511 add \arg_offset, \arg_offset, #4 1512 str r3, [\regs, \arg_offset] 1513 add \arg_offset, \arg_offset, #4 1514 .endif 1515 b \if_long 15163: // SKIP_FLOAT 1517 add \arg_offset, \arg_offset, #4 1518 b 1b 15194: // SKIP_DOUBLE 1520 add \arg_offset, \arg_offset, #8 1521 b 1b 15225: 1523.endm 1524 1525// Puts the next int/long/object parameter passed in stack 1526// in the expected dex register array entry, and in case of object in the 1527// expected reference array entry. 1528.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, tmp1, tmp2, finished 15291: // LOOP 1530 ldrb \tmp1, [\shorty], #1 // Load next character in shorty, and increment. 1531 cmp \tmp1, #0 1532 beq \finished // if (\tmp1 == '\0') goto finished 1533 cmp \tmp1, #74 // if (\tmp1 == 'J') goto FOUND_LONG 1534 beq 2f 1535 cmp \tmp1, #70 // if (\tmp1 == 'F') goto SKIP_FLOAT 1536 beq 3f 1537 cmp \tmp1, #68 // if (\tmp1 == 'D') goto SKIP_DOUBLE 1538 beq 4f 1539 add \tmp2, \stack_ptr, \arg_offset 1540 ldr \tmp2, [\tmp2, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1541 str \tmp2, [\regs, \arg_offset] 1542 cmp \tmp1, #76 // if (\tmp1 != 'L') goto loop 1543 bne 3f 1544 str \tmp2, [\refs, \arg_offset] 1545 add \arg_offset, \arg_offset, #4 1546 b 1b 15472: // FOUND_LONG 1548 add \tmp1, \stack_ptr, \arg_offset 1549 ldr \tmp1, [\tmp1, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1550 str \tmp1, [\regs, \arg_offset] 1551 add \arg_offset, \arg_offset, #4 1552 add \tmp1, \stack_ptr, \arg_offset 1553 ldr \tmp1, [\tmp1, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1554 str \tmp1, [\regs, \arg_offset] 1555 add \arg_offset, \arg_offset, #4 1556 b 1b 15573: // SKIP_FLOAT 1558 add \arg_offset, \arg_offset, #4 1559 b 1b 15604: // SKIP_DOUBLE 1561 add \arg_offset, \arg_offset, #8 1562 b 1b 1563.endm 1564 1565.macro SETUP_REFERENCE_PARAMETER_IN_GPR gpr32, regs, refs, ins, arg_offset, finished 1566 str \gpr32, [\regs, \arg_offset] 1567 subs \ins, \ins, #1 1568 str \gpr32, [\refs, \arg_offset] 1569 add \arg_offset, \arg_offset, #4 1570 beq \finished 1571.endm 1572 1573.macro SETUP_REFERENCE_PARAMETERS_IN_STACK regs, refs, ins, stack_ptr, arg_offset 15741: 1575 ldr ip, [\stack_ptr, \arg_offset] 1576 subs \ins, \ins, #1 1577 str ip, [\regs, \arg_offset] 1578 str ip, [\refs, \arg_offset] 1579 add \arg_offset, \arg_offset, #4 1580 bne 1b 1581.endm 1582 1583.macro DO_SUSPEND_CHECK continue_label 1584 // Otherwise, do a suspend check. 1585 ldr ip, [rSELF, #THREAD_FLAGS_OFFSET] 1586 tst ip, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 1587 beq \continue_label 1588 EXPORT_PC 1589 bl art_quick_test_suspend 1590.endm 1591 1592.macro CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot, if_not_hot 1593 ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1594 tst ip, #ART_METHOD_IS_MEMORY_SHARED_FLAG 1595 beq \if_hot 1596 ldr ip, [rSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET] 1597 cmp ip, #0 1598 beq \if_hot 1599 add ip, ip, #-1 1600 str ip, [rSELF, #THREAD_SHARED_METHOD_HOTNESS_OFFSET] 1601 b \if_not_hot 1602.endm 1603 1604 1605%def entry(): 1606/* 1607 * ArtMethod entry point. 1608 * 1609 * On entry: 1610 * r0 ArtMethod* callee 1611 * rest method parameters 1612 */ 1613 1614OAT_ENTRY ExecuteNterpWithClinitImpl 1615 .cfi_startproc 1616 // For simplicity, we don't do a read barrier here, but instead rely 1617 // on art_quick_resolution_trampoline to always have a suspend point before 1618 // calling back here. 1619 ldr r4, [r0, ART_METHOD_DECLARING_CLASS_OFFSET] 1620 ldr ip, [r4, MIRROR_CLASS_STATUS_OFFSET] 1621 cmp ip, #MIRROR_CLASS_STATUS_VISIBLY_INITIALIZED_SHIFTED 1622 bcs ExecuteNterpImpl 1623 cmp ip, #MIRROR_CLASS_STATUS_INITIALIZED_SHIFTED 1624 blo .Linitializing_check 1625 dmb ish 1626 b ExecuteNterpImpl 1627.Linitializing_check: 1628 cmp ip, #MIRROR_CLASS_STATUS_INITIALIZING_SHIFTED 1629 blo art_quick_resolution_trampoline 1630 ldr r4, [r4, #MIRROR_CLASS_CLINIT_THREAD_ID_OFFSET] 1631 ldr ip, [rSELF, #THREAD_TID_OFFSET] 1632 cmp r4, ip 1633 beq ExecuteNterpImpl 1634 b art_quick_resolution_trampoline 1635 .cfi_endproc 1636 .type EndExecuteNterpWithClinitImpl, #function 1637 .hidden EndExecuteNterpWithClinitImpl 1638 .global EndExecuteNterpWithClinitImpl 1639EndExecuteNterpWithClinitImpl: 1640 1641OAT_ENTRY ExecuteNterpImpl 1642 .cfi_startproc 1643 sub ip, sp, #STACK_OVERFLOW_RESERVED_BYTES 1644 ldr ip, [ip] 1645 /* Spill callee save regs */ 1646 SPILL_ALL_CALLEE_SAVES 1647 1648 ldr rPC, [r0, #ART_METHOD_DATA_OFFSET_32] 1649 1650 // Setup the stack for executing the method. 1651 SETUP_STACK_FRAME rPC, rREFS, rFP, CFI_REFS, load_ins=1 1652 1653 // Setup the parameters 1654 cmp r4, #0 1655 beq .Lxmm_setup_finished 1656 1657 sub rINST, rINST, r4 1658 ldr r8, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1659 lsl rINST, rINST, #2 // rINST is now the offset for inputs into the registers array. 1660 mov rIBASE, ip // rIBASE contains the old stack pointer 1661 1662 tst r8, #ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG 1663 beq .Lsetup_slow_path 1664 // Setup pointer to inputs in FP and pointer to inputs in REFS 1665 add lr, rFP, rINST 1666 add r8, rREFS, rINST 1667 mov r0, #0 1668 SETUP_REFERENCE_PARAMETER_IN_GPR r1, lr, r8, r4, r0, .Lxmm_setup_finished 1669 SETUP_REFERENCE_PARAMETER_IN_GPR r2, lr, r8, r4, r0, .Lxmm_setup_finished 1670 SETUP_REFERENCE_PARAMETER_IN_GPR r3, lr, r8, r4, r0, .Lxmm_setup_finished 1671 add rIBASE, rIBASE, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK 1672 SETUP_REFERENCE_PARAMETERS_IN_STACK lr, r8, r4, rIBASE, r0 1673 b .Lxmm_setup_finished 1674 1675.Lsetup_slow_path: 1676 // If the method is not static and there is one argument ('this'), we don't need to fetch the 1677 // shorty. 1678 tst r8, #ART_METHOD_IS_STATIC_FLAG 1679 bne .Lsetup_with_shorty 1680 str r1, [rFP, rINST] 1681 str r1, [rREFS, rINST] 1682 cmp r4, #1 1683 beq .Lxmm_setup_finished 1684 1685.Lsetup_with_shorty: 1686 // Save arguments that were passed before calling into the runtime. 1687 // No need to save r0 (ArtMethod) as we're not using it later in this code. 1688 // Save r4 for stack aligment. 1689 // TODO: Get shorty in a better way and remove below 1690 push {r1-r4} 1691 vpush {s0-s15} 1692 bl NterpGetShorty 1693 vpop {s0-s15} 1694 pop {r1-r4} 1695 1696 mov ip, r8 1697 add r8, rREFS, rINST 1698 add r7, rFP, rINST 1699 mov r4, #0 1700 // Setup shorty, pointer to inputs in FP and pointer to inputs in REFS 1701 add lr, r0, #1 // shorty + 1 ; ie skip return arg character 1702 tst ip, #ART_METHOD_IS_STATIC_FLAG 1703 bne .Lhandle_static_method 1704 add r7, r7, #4 1705 add r8, r8, #4 1706 add rIBASE, rIBASE, #4 1707 b .Lcontinue_setup_gprs 1708.Lhandle_static_method: 1709 LOOP_OVER_SHORTY_STORING_GPRS r1, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=0 1710.Lcontinue_setup_gprs: 1711 LOOP_OVER_SHORTY_STORING_GPRS r2, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=0 1712 LOOP_OVER_SHORTY_STORING_GPRS r3, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=1 1713.Lif_long: 1714 LOOP_OVER_INTs lr, r4, r7, r8, rIBASE, ip, r1, .Lgpr_setup_finished 1715.Lgpr_setup_finished: 1716 add r0, r0, #1 // shorty + 1 ; ie skip return arg character 1717 mov r1, r7 1718 add r2, rIBASE, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK 1719 vpush {s0-s15} 1720 mov r3, sp 1721 bl NterpStoreArm32Fprs 1722 add sp, sp, #(16 * 4) 1723.Lxmm_setup_finished: 1724 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 1725 // r8 was used for setting up the frame, restore it now. 1726 REFRESH_MARKING_REGISTER 1727.Lexecute_instructions: 1728 // Set rIBASE 1729 adr rIBASE, artNterpAsmInstructionStart 1730 /* start executing the instruction at rPC */ 1731 START_EXECUTING_INSTRUCTIONS 1732 /* NOTE: no fallthrough */ 1733 // cfi info continues, and covers the whole nterp implementation. 1734 SIZE ExecuteNterpImpl 1735 1736%def opcode_pre(): 1737 1738%def fetch_from_thread_cache(dest_reg, miss_label): 1739 // Fetch some information from the thread cache. 1740 // Uses ip and lr as temporaries. 1741 add ip, rSELF, #THREAD_INTERPRETER_CACHE_OFFSET // cache address 1742 ubfx lr, rPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2 // entry index 1743 add ip, ip, lr, lsl #3 // entry address within the cache 1744 // In T32, we would use `ldrd ip, \dest_reg, [ip]` 1745 ldr ${dest_reg}, [ip, #4] // value (offset) 1746 ldr ip, [ip] // entry key (pc) 1747 cmp ip, rPC 1748 bne ${miss_label} 1749 1750%def footer(): 1751/* 1752 * =========================================================================== 1753 * Common subroutines and data 1754 * =========================================================================== 1755 */ 1756 1757 .text 1758 .align 2 1759 1760// Enclose all code below in a symbol (which gets printed in backtraces). 1761NAME_START nterp_helper 1762 1763// Note: mterp also uses the common_* names below for helpers, but that's OK 1764// as the assembler compiled each interpreter separately. 1765common_errDivideByZero: 1766 EXPORT_PC 1767 bl art_quick_throw_div_zero 1768 1769// Expect index in r1, length in r3 1770common_errArrayIndex: 1771 EXPORT_PC 1772 mov r0, r1 1773 mov r1, r3 1774 bl art_quick_throw_array_bounds 1775 1776common_errNullObject: 1777 EXPORT_PC 1778 bl art_quick_throw_null_pointer_exception 1779 1780NterpCommonInvokeStatic: 1781 COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic" 1782 1783NterpCommonInvokeStaticRange: 1784 COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic" 1785 1786NterpCommonInvokeInstance: 1787 COMMON_INVOKE_NON_RANGE suffix="invokeInstance" 1788 1789NterpCommonInvokeInstanceRange: 1790 COMMON_INVOKE_RANGE suffix="invokeInstance" 1791 1792NterpCommonInvokeInterface: 1793 COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface" 1794 1795NterpCommonInvokeInterfaceRange: 1796 COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface" 1797 1798NterpCommonInvokePolymorphic: 1799 COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1800 1801NterpCommonInvokePolymorphicRange: 1802 COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1803 1804NterpCommonInvokeCustom: 1805 COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1806 1807NterpCommonInvokeCustomRange: 1808 COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1809 1810NterpHandleStringInit: 1811 COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit" 1812 1813NterpHandleStringInitRange: 1814 COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit" 1815 1816 1817NterpHandleHotnessOverflow: 1818 CHECK_AND_UPDATE_SHARED_MEMORY_METHOD if_hot=1f, if_not_hot=5f 18191: 1820 mov r1, rPC 1821 mov r2, rFP 1822 bl nterp_hot_method 1823 cmp r0, #0 1824 bne 3f 18252: 1826 FETCH_INST // load rINST 1827 GET_INST_OPCODE ip // extract opcode from rINST 1828 GOTO_OPCODE ip // jump to next instruction 18293: 1830 // Drop the current frame. 1831 ldr ip, [rREFS, #-4] 1832 mov sp, ip 1833 .cfi_def_cfa sp, CALLEE_SAVES_SIZE 1834 1835 // The transition frame of type SaveAllCalleeSaves saves r4, r8, and r9, 1836 // but not managed ABI. So we need to restore callee-saves of the nterp frame, 1837 // and save managed ABI callee saves, which will be restored by the callee upon 1838 // return. 1839 1840 RESTORE_ALL_CALLEE_SAVES 1841 push {r5-r7, r10-r11, lr} 1842 .cfi_adjust_cfa_offset 24 1843 .cfi_rel_offset r5, 0 1844 .cfi_rel_offset r6, 4 1845 .cfi_rel_offset r7, 8 1846 .cfi_rel_offset r10, 12 1847 .cfi_rel_offset r11, 16 1848 .cfi_rel_offset lr, 20 1849 vpush {s16-s31} 1850 .cfi_adjust_cfa_offset 64 1851 1852 // Setup the new frame 1853 ldr r1, [r0, #OSR_DATA_FRAME_SIZE] 1854 // Given stack size contains all callee saved registers, remove them. 1855 sub r1, r1, #(CALLEE_SAVES_SIZE - 12) 1856 1857 // We know r1 cannot be 0, as it at least contains the ArtMethod. 1858 1859 // Remember CFA in a callee-save register. 1860 mov rINST, sp 1861 .cfi_def_cfa_register rINST 1862 1863 sub sp, sp, r1 1864 1865 add r2, r0, #OSR_DATA_MEMORY 18664: 1867 sub r1, r1, #4 1868 ldr ip, [r2, r1] 1869 str ip, [sp, r1] 1870 cmp r1, #0 1871 bne 4b 1872 1873 // Fetch the native PC to jump to and save it in a callee-save register. 1874 ldr rFP, [r0, #OSR_DATA_NATIVE_PC] 1875 1876 // Free the memory holding OSR Data. 1877 bl free 1878 1879 // Jump to the compiled code. 1880 bx rFP 18815: 1882 DO_SUSPEND_CHECK continue_label=2b 1883 b 2b 1884 1885// This is the logical end of ExecuteNterpImpl, where the frame info applies. 1886// EndExecuteNterpImpl includes the methods below as we want the runtime to 1887// see them as part of the Nterp PCs. 1888.cfi_endproc 1889 1890nterp_to_nterp_static_non_range: 1891 .cfi_startproc 1892 SETUP_STACK_FOR_INVOKE 1893 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0 1894 .cfi_endproc 1895 1896nterp_to_nterp_string_init_non_range: 1897 .cfi_startproc 1898 SETUP_STACK_FOR_INVOKE 1899 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1900 .cfi_endproc 1901 1902nterp_to_nterp_instance_non_range: 1903 .cfi_startproc 1904 SETUP_STACK_FOR_INVOKE 1905 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 1906 .cfi_endproc 1907 1908nterp_to_nterp_static_range: 1909 .cfi_startproc 1910 SETUP_STACK_FOR_INVOKE 1911 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0 1912 .cfi_endproc 1913 1914nterp_to_nterp_string_init_range: 1915 .cfi_startproc 1916 SETUP_STACK_FOR_INVOKE 1917 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1918 .cfi_endproc 1919 1920nterp_to_nterp_instance_range: 1921 .cfi_startproc 1922 SETUP_STACK_FOR_INVOKE 1923 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 1924 .cfi_endproc 1925 1926NAME_END nterp_helper 1927 1928// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter 1929// entry point. 1930 .type EndExecuteNterpImpl, #function 1931 .hidden EndExecuteNterpImpl 1932 .global EndExecuteNterpImpl 1933EndExecuteNterpImpl: 1934 1935/* 1936 * Convert the double in r0/r1 to a long in r0/r1. 1937 * 1938 * We have to clip values to long min/max per the specification. The 1939 * expected common case is a "reasonable" value that converts directly 1940 * to modest integer. The EABI convert function isn't doing this for us. 1941 */ 1942ENTRY nterp_d2l_doconv 1943 ubfx r2, r1, #20, #11 @ grab the exponent 1944 movw r3, #0x43e 1945 cmp r2, r3 @ MINLONG < x > MAXLONG? 1946 bhs d2l_special_cases 1947 b __aeabi_d2lz @ tail call to convert double to long 1948d2l_special_cases: 1949 movw r3, #0x7ff 1950 cmp r2, r3 1951 beq d2l_maybeNaN @ NaN? 1952d2l_notNaN: 1953 adds r1, r1, r1 @ sign bit to carry 1954 mov r0, #0xffffffff @ assume maxlong for lsw 1955 mov r1, #0x7fffffff @ assume maxlong for msw 1956 adc r0, r0, #0 1957 adc r1, r1, #0 @ convert maxlong to minlong if exp negative 1958 bx lr @ return 1959d2l_maybeNaN: 1960 orrs r3, r0, r1, lsl #12 1961 beq d2l_notNaN @ if fraction is non-zero, it's a NaN 1962 mov r0, #0 1963 mov r1, #0 1964 bx lr @ return 0 for NaN 1965END nterp_d2l_doconv 1966 1967/* 1968 * Convert the float in r0 to a long in r0/r1. 1969 * 1970 * We have to clip values to long min/max per the specification. The 1971 * expected common case is a "reasonable" value that converts directly 1972 * to modest integer. The EABI convert function isn't doing this for us. 1973 */ 1974ENTRY nterp_f2l_doconv 1975 ubfx r2, r0, #23, #8 @ grab the exponent 1976 cmp r2, #0xbe @ MININT < x > MAXINT? 1977 bhs f2l_special_cases 1978 b __aeabi_f2lz @ tail call to convert float to long 1979f2l_special_cases: 1980 cmp r2, #0xff @ NaN or infinity? 1981 beq f2l_maybeNaN 1982f2l_notNaN: 1983 adds r0, r0, r0 @ sign bit to carry 1984 mov r0, #0xffffffff @ assume maxlong for lsw 1985 mov r1, #0x7fffffff @ assume maxlong for msw 1986 adc r0, r0, #0 1987 adc r1, r1, #0 @ convert maxlong to minlong if exp negative 1988 bx lr @ return 1989f2l_maybeNaN: 1990 lsls r3, r0, #9 1991 beq f2l_notNaN @ if fraction is non-zero, it's a NaN 1992 mov r0, #0 1993 mov r1, #0 1994 bx lr @ return 0 for NaN 1995END nterp_f2l_doconv 1996 1997// Entrypoints into runtime. 1998NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField 1999NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset 2000NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray 2001NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange 2002NTERP_TRAMPOLINE nterp_get_class, NterpGetClass 2003NTERP_TRAMPOLINE nterp_allocate_object, NterpAllocateObject 2004NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod 2005NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod 2006NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject 2007 2008ENTRY nterp_deliver_pending_exception 2009 DELIVER_PENDING_EXCEPTION 2010END nterp_deliver_pending_exception 2011 2012// gen_mterp.py will inline the following definitions 2013// within [ExecuteNterpImpl, EndExecuteNterpImpl). 2014%def instruction_end(): 2015 2016 .type artNterpAsmInstructionEnd, #function 2017 .hidden artNterpAsmInstructionEnd 2018 .global artNterpAsmInstructionEnd 2019artNterpAsmInstructionEnd: 2020 // artNterpAsmInstructionEnd is used as landing pad for exception handling. 2021 FETCH_INST 2022 GET_INST_OPCODE ip 2023 GOTO_OPCODE ip 2024 2025%def instruction_start(): 2026 2027 .type artNterpAsmInstructionStart, #function 2028 .hidden artNterpAsmInstructionStart 2029 .global artNterpAsmInstructionStart 2030artNterpAsmInstructionStart = .L_op_nop 2031 .text 2032 2033%def opcode_name_prefix(): 2034% return "nterp_" 2035%def opcode_start(): 2036 NAME_START nterp_${opcode} 2037 # Explicitly restore CFA, just in case the previous opcode clobbered it (by .cfi_def_*). 2038 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE 2039%def opcode_end(): 2040 NAME_END nterp_${opcode} 2041 // Advance to the end of this handler. Causes error if we are past that point. 2042 .org nterp_${opcode} + NTERP_HANDLER_SIZE // ${opcode} handler is too big! 2043%def opcode_slow_path_start(name): 2044 NAME_START ${name} 2045%def opcode_slow_path_end(name): 2046 NAME_END ${name} 2047