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 that has a OatQuickMethodHeader prefix. 245.macro OAT_ENTRY name, end 246 .arm 247 .type \name, #function 248 .hidden \name 249 .global \name 250 .balign 16 251 // Padding of 3 * 8 bytes to get 16 bytes alignment of code entry. 252 .long 0 253 .long 0 254 .long 0 255 // OatQuickMethodHeader. Note that the top two bits must be clear. 256 .long (\end - \name) 257\name: 258.endm 259 260.macro SIZE name 261 .size \name, .-\name 262.endm 263 264.macro NAME_START name 265 .arm 266 .type \name, #function 267 .hidden \name // Hide this as a global symbol, so we do not incur plt calls. 268 .global \name 269 /* Cache alignment for function entry */ 270 .balign 16 271\name: 272.endm 273 274.macro NAME_END name 275 SIZE \name 276.endm 277 278// Macro for defining entrypoints into runtime. We don't need to save registers 279// (we're not holding references there), but there is no 280// kDontSave runtime method. So just use the kSaveRefsOnly runtime method. 281.macro NTERP_TRAMPOLINE name, helper 282ENTRY \name 283 SETUP_SAVE_REFS_ONLY_FRAME ip 284 bl \helper 285 RESTORE_SAVE_REFS_ONLY_FRAME 286 REFRESH_MARKING_REGISTER 287 RETURN_OR_DELIVER_PENDING_EXCEPTION 288END \name 289.endm 290 291.macro CLEAR_STATIC_VOLATILE_MARKER reg 292 and \reg, \reg, #-2 293.endm 294 295.macro CLEAR_INSTANCE_VOLATILE_MARKER reg 296 rsb \reg, \reg, #0 297.endm 298 299.macro EXPORT_PC 300 str rPC, [rREFS, #-8] 301.endm 302 303.macro BRANCH 304 // Update method counter and do a suspend check if the branch is negative. 305 cmp rINST, #0 306 blt 2f 3071: 308 add r2, rINST, rINST // r2<- byte offset 309 FETCH_ADVANCE_INST_RB r2 // update xPC, load rINST 310 GET_INST_OPCODE ip // extract opcode from rINST 311 GOTO_OPCODE ip // jump to next instruction 3122: 313 ldr r0, [sp] 314 ldrh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 315 add r2, r2, #1 316 ubfx r2, r2, #0, #NTERP_HOTNESS_BITS 317 strh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 318 // If the counter overflows, handle this in the runtime. 319 cmp r2, #0 320 beq NterpHandleHotnessOverflow 321 // Otherwise, do a suspend check. 322 ldr r0, [rSELF, #THREAD_FLAGS_OFFSET] 323 ands r0, r0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 324 beq 1b 325 EXPORT_PC 326 bl art_quick_test_suspend 327 b 1b 328.endm 329 330// Expects: 331// - ip and lr to be available. 332// Outputs: 333// - \registers contains the dex registers size 334// - \outs contains the outs size 335// - if load_ins is 1, \ins contains the ins 336// - \code_item is replaced with a pointer to the instructions 337.macro FETCH_CODE_ITEM_INFO code_item, registers, outs, ins, load_ins 338 tst \code_item, #1 339 beq 5f 340 bic \code_item, \code_item, #1 // Remove the extra bit that marks it's a compact dex file 341 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FIELDS_OFFSET] 342 ubfx \registers, lr, #COMPACT_CODE_ITEM_REGISTERS_SIZE_SHIFT, #4 343 ubfx \outs, lr, #COMPACT_CODE_ITEM_OUTS_SIZE_SHIFT, #4 344 .if \load_ins 345 ubfx \ins, lr, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4 346 .else 347 ubfx ip, lr, #COMPACT_CODE_ITEM_INS_SIZE_SHIFT, #4 348 add \registers, \registers, ip 349 .endif 350 351 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET] 352 tst lr, #COMPACT_CODE_ITEM_REGISTERS_INS_OUTS_FLAGS 353 beq 4f 354 mov ip, \code_item 355 tst lr, #COMPACT_CODE_ITEM_INSNS_FLAG 356 beq 1f 357 sub ip, ip, #4 3581: 359 tst lr, #COMPACT_CODE_ITEM_REGISTERS_FLAG 360 beq 2f 361 ldrh lr, [ip, #-2]! 362 add \registers, \registers, lr 363 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET] 3642: 365 tst lr, #COMPACT_CODE_ITEM_INS_FLAG 366 beq 3f 367 ldrh lr, [ip, #-2]! 368 .if \load_ins 369 add \ins, \ins, lr 370 .else 371 add \registers, \registers, lr 372 .endif 373 ldrh lr, [\code_item, #COMPACT_CODE_ITEM_FLAGS_OFFSET] 3743: 375 tst lr, #COMPACT_CODE_ITEM_OUTS_FLAG 376 beq 4f 377 ldrh lr, [ip, #-2]! 378 add \outs, \outs, lr 3794: 380 .if \load_ins 381 add \registers, \registers, \ins 382 .endif 383 add \code_item, \code_item, #COMPACT_CODE_ITEM_INSNS_OFFSET 384 b 6f 3855: 386 // Fetch dex register size. 387 ldrh \registers, [\code_item, #CODE_ITEM_REGISTERS_SIZE_OFFSET] 388 // Fetch outs size. 389 ldrh \outs, [\code_item, #CODE_ITEM_OUTS_SIZE_OFFSET] 390 .if \load_ins 391 ldrh \ins, [\code_item, #CODE_ITEM_INS_SIZE_OFFSET] 392 .endif 393 add \code_item, \code_item, #CODE_ITEM_INSNS_OFFSET 3946: 395.endm 396 397// Setup the stack to start executing the method. Expects: 398// - r0 to contain the ArtMethod 399// - \code_item to already contain the code item 400// - rINST, ip, lr to be available 401// 402// Outputs 403// - rINST contains the dex registers size 404// - ip contains the old stack pointer. 405// - \code_item is replaced with a pointer to the instructions 406// - if load_ins is 1, r4 contains the ins 407// 408.macro SETUP_STACK_FRAME code_item, refs, fp, cfi_refs, load_ins 409 FETCH_CODE_ITEM_INFO \code_item, rINST, \refs, r4, \load_ins 410 411 // Compute required frame size: ((2 * rINST) + \refs) * 4 + 12 412 // 12 is for saving the previous frame, pc, and method being executed. 413 add ip, \refs, rINST, lsl #1 414 415 // Compute new stack pointer in lr 416 sub lr, sp, #12 417 sub lr, lr, ip, lsl #2 418 // Alignment 419 and lr, lr, #-16 420 421 // Set reference and dex registers. 422 add \refs, lr, \refs, lsl #2 423 add \refs, \refs, #12 424 add \fp, \refs, rINST, lsl #2 425 426 // Now setup the stack pointer. 427 mov ip, sp 428 .cfi_def_cfa_register ip 429 mov sp, lr 430 str ip, [\refs, #-4] 431 CFI_DEF_CFA_BREG_PLUS_UCONST \cfi_refs, -4, CALLEE_SAVES_SIZE 432 433 // Save the ArtMethod, and use r0 as a temporary. 434 str r0, [sp] 435 436 // Put nulls in reference frame. 437 cmp rINST, #0 438 beq 2f 439 mov lr, \refs 440 mov r0, #0 4411: 442 str r0, [lr], #4 443 str r0, [lr], #4 // May clear vreg[0]. 444 cmp lr, \fp 445 blo 1b 4462: 447 ldr r0, [sp] // Reload the ArtMethod, expected by the callers. 448.endm 449 450// Increase method hotness and do suspend check before starting executing the method. 451.macro START_EXECUTING_INSTRUCTIONS 452 ldr r0, [sp] 453 ldrh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 454 add r2, r2, #1 455 ubfx r2, r2, #0, #NTERP_HOTNESS_BITS 456 strh r2, [r0, #ART_METHOD_HOTNESS_COUNT_OFFSET] 457 // If the counter overflows, handle this in the runtime. 458 cmp r2, #0 459 beq 2f 460 ldr r0, [rSELF, #THREAD_FLAGS_OFFSET] 461 tst r0, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 462 bne 3f 4631: 464 FETCH_INST 465 GET_INST_OPCODE ip 466 GOTO_OPCODE ip 4672: 468 mov r1, #0 469 mov r2, rFP 470 bl nterp_hot_method 471 b 1b 4723: 473 EXPORT_PC 474 bl art_quick_test_suspend 475 b 1b 476.endm 477 478.macro SPILL_ALL_CALLEE_SAVES 479 SPILL_ALL_CALLEE_SAVE_GPRS @ 9 words (36 bytes) of callee saves. 480 vpush {s16-s31} @ 16 words (64 bytes) of floats. 481 .cfi_adjust_cfa_offset 64 482.endm 483 484.macro RESTORE_ALL_CALLEE_SAVES lr_to_pc=0 485 vpop {s16-s31} 486 .cfi_adjust_cfa_offset -64 487 pop {r4-r7} 488 .cfi_adjust_cfa_offset -16 489 .cfi_restore r4 490 .cfi_restore r5 491 .cfi_restore r6 492 .cfi_restore r7 493 // Don't restore r8, the marking register gets updated when coming back from runtime. 494 add sp, sp, #4 495 .cfi_adjust_cfa_offset -4 496 .if \lr_to_pc 497 pop {r9-r11, pc} @ 9 words of callee saves and args. 498 .else 499 pop {r9-r11, lr} @ 9 words of callee saves and args. 500 .cfi_adjust_cfa_offset -16 501 .cfi_restore r9 502 .cfi_restore r10 503 .cfi_restore r11 504 .cfi_restore lr 505 .endif 506.endm 507 508// Helper to setup the stack after doing a nterp to nterp call. This will setup: 509// - rNEW_FP: the new pointer to dex registers 510// - rNEW_REFS: the new pointer to references 511// - rPC: the new PC pointer to execute 512// - r2: value in instruction to decode the number of arguments. 513// - r3: first dex register for range invokes, up to 4 arguments for non-range invokes. 514// - r4: top of dex register array 515// 516// The method expects: 517// - r0 to contain the ArtMethod 518// - r4 to contain the code item 519.macro SETUP_STACK_FOR_INVOKE 520 // We do the same stack overflow check as the compiler. See CanMethodUseNterp 521 // in how we limit the maximum nterp frame size. 522 sub ip, sp, #STACK_OVERFLOW_RESERVED_BYTES 523 ldr ip, [ip] 524 525 // Spill all callee saves to have a consistent stack frame whether we 526 // are called by compiled code or nterp. 527 SPILL_ALL_CALLEE_SAVES 528 529 // Setup the frame. 530 SETUP_STACK_FRAME r4, rNEW_REFS, rNEW_FP, CFI_NEW_REFS, load_ins=0 531 532 // Fetch instruction information before replacing rPC. 533 FETCH_B r2, 0, 1 534 FETCH r3, 2 535 536 // Set the dex pc pointer. 537 mov rPC, r4 538 539 // Make r4 point to the top of the dex register array. 540 add r4, rNEW_FP, rINST, lsl #2 541 542 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 543.endm 544 545// Setup arguments based on a non-range nterp to nterp call, and start executing 546// the method. We expect: 547// - rNEW_FP: the new pointer to dex registers 548// - rPC: the new PC pointer to execute 549// - r2: number of arguments (bits 4-7), 5th argument if any (bits 0-3) 550// - r3: up to four dex register arguments 551// - r4: top of dex register array 552// - r1: receiver if non-static. 553// 554// Uses r0 and rINST as temporaries. 555.macro SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 556 // /* op vA, vB, {vC...vG} */ 557 .if \is_static 558 asrs r0, r2, #4 559 beq 6f 560 .else 561 asr r0, r2, #4 562 .endif 563 mov rINST, #-4 564 cmp r0, #2 565 blt 1f 566 beq 2f 567 cmp r0, #4 568 blt 3f 569 beq 4f 570 571 // We use a decrementing rINST to store references relative 572 // to rNEW_FP and dex registers relative to r4 573 // 574 // TODO: We could set up rINST as the number of registers (this can be an additional output from 575 // SETUP_STACK_FOR_INVOKE) and then just decrement it by one before copying each arg. 576 // Maybe even introduce macros NEW_VREG_ADDRESS/NEW_VREG_REF_ADDRESS. 5775: 578 and r2, r2, #15 579 GET_VREG_OBJECT r0, r2 580 str r0, [rNEW_FP, rINST] 581 GET_VREG r0, r2 582 str r0, [r4, rINST] 583 sub rINST, rINST, #4 5844: 585 asr r2, r3, #12 586 GET_VREG_OBJECT r0, r2 587 str r0, [rNEW_FP, rINST] 588 GET_VREG r0, r2 589 str r0, [r4, rINST] 590 sub rINST, rINST, #4 5913: 592 ubfx r2, r3, #8, #4 593 GET_VREG_OBJECT r0, r2 594 str r0, [rNEW_FP, rINST] 595 GET_VREG r0, r2 596 str r0, [r4, rINST] 597 sub rINST, rINST, #4 5982: 599 ubfx r2, r3, #4, #4 600 GET_VREG_OBJECT r0, r2 601 str r0, [rNEW_FP, rINST] 602 GET_VREG r0, r2 603 str r0, [r4, rINST] 604 .if !\is_string_init 605 sub rINST, rINST, #4 606 .endif 6071: 608 .if \is_string_init 609 // Ignore the first argument 610 .elseif \is_static 611 and r2, r3, #0xf 612 GET_VREG_OBJECT r0, r2 613 str r0, [rNEW_FP, rINST] 614 GET_VREG r0, r2 615 str r0, [r4, rINST] 616 .else 617 str r1, [rNEW_FP, rINST] 618 str r1, [r4, rINST] 619 .endif 620 6216: 622 // Start executing the method. 623 mov rFP, rNEW_FP 624 mov rREFS, rNEW_REFS 625 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE 626 // r8 was used for setting up the frame, restore it now. 627 REFRESH_MARKING_REGISTER 628 // Branch to the main handler, which will reload rIBASE, 629 // that was used for setting up the frame. 630 b .Lexecute_instructions 631.endm 632 633// Setup arguments based on a range nterp to nterp call, and start executing 634// the method. 635// - rNEW_FP: the new pointer to dex registers 636// - rNEW_REFS: the new pointer to references 637// - rPC: the new PC pointer to execute 638// - r2: number of arguments 639// - r3: first dex register 640// - r4: top of dex register array 641// - r1: receiver if non-static. 642// 643// Expects r0 to be available. 644.macro SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 645 mov r0, #-4 646 .if \is_string_init 647 // Ignore the first argument 648 sub r2, r2, #1 649 add r3, r3, #1 650 .elseif !\is_static 651 sub r2, r2, #1 652 add r3, r3, #1 653 .endif 654 655 cmp r2, #0 656 beq 2f 657 add rREFS, rREFS, r3, lsl #2 // pointer to first argument in reference array 658 add rREFS, rREFS, r2, lsl #2 // pointer to last argument in reference array 659 add rFP, rFP, r3, lsl #2 // pointer to first argument in register array 660 add rFP, rFP, r2, lsl #2 // pointer to last argument in register array 6611: 662 ldr r3, [rREFS, #-4]! 663 str r3, [rNEW_FP, r0] 664 subs r2, r2, 1 665 ldr r3, [rFP, #-4]! 666 str r3, [r4, r0] 667 sub r0, r0, 4 668 bne 1b 6692: 670 .if \is_string_init 671 // Ignore first argument 672 .elseif !\is_static 673 str r1, [rNEW_FP, r0] 674 str r1, [r4, r0] 675 .endif 676 mov rFP, rNEW_FP 677 mov rREFS, rNEW_REFS 678 CFI_DEF_CFA_BREG_PLUS_UCONST CFI_REFS, -4, CALLEE_SAVES_SIZE 679 // r8 was used for setting up the frame, restore it now. 680 REFRESH_MARKING_REGISTER 681 // Branch to the main handler, which will reload rIBASE, 682 // that was used for setting up the frame. 683 b .Lexecute_instructions 684.endm 685 686.macro GET_SHORTY dest, is_interface, is_polymorphic, is_custom 687 push {r0-r3} 688 .if \is_polymorphic 689 ldr r0, [sp, #16] 690 mov r1, rPC 691 bl NterpGetShortyFromInvokePolymorphic 692 .elseif \is_custom 693 ldr r0, [sp, #16] 694 mov r1, rPC 695 bl NterpGetShortyFromInvokeCustom 696 .elseif \is_interface 697 ldr r0, [sp, #16] 698 FETCH r1, 1 699 bl NterpGetShortyFromMethodId 700 .else 701 bl NterpGetShorty 702 .endif 703 mov \dest, r0 704 pop {r0-r3} 705.endm 706 707// Input: r0 contains the ArtMethod 708// Output: r4 contains the code item 709.macro GET_CODE_ITEM 710 ldr r4, [r0, #ART_METHOD_DATA_OFFSET_32] 711.endm 712 713.macro DO_ENTRY_POINT_CHECK call_compiled_code, name 714 // On entry, the method is r0, the instance is r1 715 ldr r2, .Lfetch_nterp_\name 716.Lfetch_location_\name: 717 // Note that this won't work for thumb. 718 sub r2, pc, r2 719 ldr r3, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 720 cmp r2, r3 721 bne \call_compiled_code 722.endm 723 724// Expects ip and lr to be available. 725.macro UPDATE_REGISTERS_FOR_STRING_INIT old_value, new_value 726 mov ip, #0 7271: 728 GET_VREG_OBJECT lr, ip 729 cmp lr, \old_value 730 bne 2f 731 SET_VREG_OBJECT \new_value, ip 7322: 733 add ip, ip, #1 734 add lr, rREFS, ip, lsl #2 735 cmp lr, rFP 736 bne 1b 737.endm 738 739// Puts the next floating point argument into the expected register, 740// fetching values based on a non-range invoke. 741// Uses ip and lr. 742.macro LOOP_OVER_SHORTY_LOADING_FPS dreg, sreg, inst, shorty, arg_index, finished, if_double 7431: // LOOP 744 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 745 cmp ip, #0 746 beq \finished // if (ip == '\0') goto finished 747 cmp ip, #68 // if (ip == 'D') goto FOUND_DOUBLE 748 beq 2f 749 cmp ip, #70 // if (ip == 'F') goto FOUND_FLOAT 750 beq 3f 751 lsr \inst, \inst, #4 752 add \arg_index, \arg_index, #1 753 // Handle extra argument in arg array taken by a long. 754 cmp ip, #74 // if (ip != 'J') goto LOOP 755 bne 1b 756 lsr \inst, \inst, #4 757 add \arg_index, \arg_index, #1 758 b 1b // goto LOOP 7592: // FOUND_DOUBLE 760 and ip, \inst, #0xf 761 GET_VREG ip, ip 762 lsr \inst, \inst, #4 763 add \arg_index, \arg_index, #1 764 cmp \arg_index, #4 765 beq 5f 766 and lr, \inst, #0xf 767 lsr \inst, \inst, #4 768 add \arg_index, \arg_index, #1 769 b 6f 7705: 771 FETCH_B lr, 0, 1 772 and lr, lr, #0xf 7736: 774 GET_VREG lr, lr 775 vmov \dreg, ip, lr 776 b \if_double 7773: // FOUND_FLOAT 778 cmp \arg_index, #4 779 beq 7f 780 and ip, \inst, #0xf 781 lsr \inst, \inst, #4 782 add \arg_index, \arg_index, #1 783 b 8f 7847: 785 FETCH_B ip, 0, 1 786 and ip, ip, #0xf 7878: 788 GET_VREG_FLOAT \sreg, ip 789.endm 790 791// Puts the next int/long/object argument in the expected register, 792// fetching values based on a non-range invoke. 793// Uses ip. 794.macro LOOP_OVER_SHORTY_LOADING_GPRS gpr_reg, inst, shorty, arg_index, finished, if_long, is_r3 7951: // LOOP 796 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 797 cmp ip, #0 798 beq \finished // if (ip == '\0') goto finished 799 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 800 beq 2f 801 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 802 beq 3f 803 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 804 beq 4f 805 cmp \arg_index, #4 806 beq 7f 807 and ip, \inst, #0xf 808 lsr \inst, \inst, #4 809 add \arg_index, \arg_index, #1 810 b 8f 8117: 812 FETCH_B ip, 0, 1 813 and ip, ip, #0xf 8148: 815 GET_VREG \gpr_reg, ip 816 b 5f 8172: // FOUND_LONG 818 .if \is_r3 819 // Put back shorty and exit 820 sub \shorty, \shorty, #1 821 b 5f 822 .endif 823 and ip, \inst, #0xf 824 GET_VREG ip, ip 825 // The only one possible for non-range long is r2-r3 826 mov r2, ip 827 lsr \inst, \inst, #4 828 add \arg_index, \arg_index, #1 829 cmp \arg_index, #4 830 beq 9f 831 and ip, \inst, #0xf 832 lsr \inst, \inst, #4 833 b 10f 8349: 835 FETCH_B ip, 0, 1 836 and ip, ip, #0xf 83710: 838 GET_VREG ip, ip 839 // The only one possible for non-range long is r2-r3 840 mov r3, ip 841 add \arg_index, \arg_index, #1 842 b \if_long 8433: // SKIP_FLOAT 844 lsr \inst, \inst, #4 845 add \arg_index, \arg_index, #1 846 b 1b 8474: // SKIP_DOUBLE 848 lsr \inst, \inst, #8 849 add \arg_index, \arg_index, #2 850 b 1b 8515: 852.endm 853 854// Puts the next int/long/object argument in the expected stack slot, 855// fetching values based on a non-range invoke. 856// Uses ip as temporary. 857.macro LOOP_OVER_SHORTY_LOADING_INTs shorty, inst, arg_index, finished, is_string_init 8581: // LOOP 859 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 860 cmp ip, #0 861 beq \finished // if (ip == '\0') goto finished 862 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 863 beq 2f 864 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 865 beq 3f 866 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 867 beq 4f 868 .if \is_string_init 869 cmp \arg_index, #4 870 .else 871 cmp \arg_index, #(4+1) // +1 for ArtMethod 872 .endif 873 beq 7f 874 and ip, \inst, #0xf 875 lsr \inst, \inst, #4 876 b 8f 8777: 878 FETCH_B ip, 0, 1 879 and ip, ip, #0xf 8808: 881 GET_VREG ip, ip 882 str ip, [sp, \arg_index, lsl #2] 883 add \arg_index, \arg_index, #1 884 b 1b 8852: // FOUND_LONG 886 and ip, \inst, #0xf 887 GET_VREG ip, ip 888 str ip, [sp, \arg_index, lsl #2] 889 lsr \inst, \inst, #4 890 add \arg_index, \arg_index, #1 891 .if \is_string_init 892 cmp \arg_index, #4 893 .else 894 cmp \arg_index, #(4+1) // +1 for ArtMethod 895 .endif 896 beq 9f 897 and ip, \inst, #0xf 898 lsr \inst, \inst, #4 899 b 10f 9009: 901 FETCH_B ip, 0, 1 902 and ip, ip, #0xf 90310: 904 GET_VREG ip, ip 905 str ip, [sp, \arg_index, lsl #2] 906 add \arg_index, \arg_index, #1 907 b 1b 9083: // SKIP_FLOAT 909 lsr \inst, \inst, #4 910 add \arg_index, \arg_index, #1 911 b 1b 9124: // SKIP_DOUBLE 913 lsr \inst, \inst, #8 914 add \arg_index, \arg_index, #2 915 b 1b 916.endm 917 918.macro SETUP_RETURN_VALUE shorty 919 ldrb ip, [\shorty] 920 cmp ip, #68 // Test if result type char == 'D'. 921 beq 1f 922 cmp ip, #70 // Test if result type char == 'F'. 923 bne 2f 924 vmov r0, s0 925 b 2f 9261: 927 vmov r0, r1, d0 9282: 929.endm 930 931.macro GET_SHORTY_SLOW_PATH dest, is_interface 932 // Save all registers that can hold arguments in the fast path. 933 vpush {s0} 934 push {r0-r2} 935 .if \is_interface 936 ldr r0, [sp, #16] 937 FETCH r1, 1 938 bl NterpGetShortyFromMethodId 939 .else 940 bl NterpGetShorty 941 .endif 942 mov \dest, r0 943 pop {r0-r2} 944 vpop {s0} 945.endm 946 947.macro COMMON_INVOKE_NON_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 948 .if \is_polymorphic 949 // We always go to compiled code for polymorphic calls. 950 .elseif \is_custom 951 // We always go to compiled code for custom calls. 952 .else 953 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_\suffix, \suffix 954 GET_CODE_ITEM 955 .if \is_string_init 956 bl nterp_to_nterp_string_init_non_range 957 .elseif \is_static 958 bl nterp_to_nterp_static_non_range 959 .else 960 bl nterp_to_nterp_instance_non_range 961 .endif 962 b .Ldone_return_\suffix 963.Lfetch_nterp_\suffix: 964 .word (.Lfetch_location_\suffix+8) - ExecuteNterpImpl 965 .endif 966 967.Lcall_compiled_code_\suffix: 968 .if \is_polymorphic 969 // No fast path for polymorphic calls. 970 .elseif \is_custom 971 // No fast path for custom calls. 972 .elseif \is_string_init 973 // No fast path for string.init. 974 .else 975 ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 976 tst ip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG 977 beq .Lfast_path_with_few_args_\suffix 978 FETCH_B rINST, 0, 1 979 .if \is_static 980 asrs lr, rINST, #4 981 beq .Linvoke_fast_path_\suffix 982 .else 983 asr lr, rINST, #4 984 cmp lr, #1 985 beq .Linvoke_fast_path_\suffix 986 .endif 987 FETCH ip, 2 988 cmp lr, #2 989 .if \is_static 990 blt .Lone_arg_fast_path_\suffix 991 .endif 992 beq .Ltwo_args_fast_path_\suffix 993 cmp lr, #4 994 blt .Lthree_args_fast_path_\suffix 995 beq .Lfour_args_fast_path_\suffix 996 and rINST, rINST, #15 997 GET_VREG rINST, rINST 998 str rINST, [sp, #(4 + 4 * 4)] 999.Lfour_args_fast_path_\suffix: 1000 asr rINST, ip, #12 1001 GET_VREG rINST, rINST 1002 str rINST, [sp, #(4 + 3 * 4)] 1003.Lthree_args_fast_path_\suffix: 1004 ubfx rINST, ip, #8, #4 1005 GET_VREG r3, rINST 1006.Ltwo_args_fast_path_\suffix: 1007 ubfx rINST, ip, #4, #4 1008 GET_VREG r2, rINST 1009.Lone_arg_fast_path_\suffix: 1010 .if \is_static 1011 and rINST, ip, #0xf 1012 GET_VREG r1, rINST 1013 .else 1014 // First argument already in r1. 1015 .endif 1016.Linvoke_fast_path_\suffix: 1017 .if \is_interface 1018 // Setup hidden argument. 1019 mov ip, r4 1020 .endif 1021 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1022 blx lr 1023 FETCH_ADVANCE_INST 3 1024 GET_INST_OPCODE ip 1025 GOTO_OPCODE ip 1026 1027.Lfast_path_with_few_args_\suffix: 1028 // Fast path when we have zero or one argument (modulo 'this'). If there 1029 // is one argument, we can put it in both floating point and core register. 1030 FETCH_B r2, 0, 1 1031 asr r2, r2, #4 // number of arguments 1032 .if \is_static 1033 cmp r2, #1 1034 blt .Linvoke_with_few_args_\suffix 1035 bne .Lget_shorty_\suffix 1036 FETCH r2, 2 1037 and r2, r2, #0xf // dex register of first argument 1038 GET_VREG r1, r2 1039 vmov s0, r1 1040 .else 1041 cmp r2, #2 1042 blt .Linvoke_with_few_args_\suffix 1043 bne .Lget_shorty_\suffix 1044 FETCH r2, 2 1045 ubfx r2, r2, #4, #4 // dex register of second argument 1046 GET_VREG r2, r2 1047 vmov s0, r2 1048 .endif 1049.Linvoke_with_few_args_\suffix: 1050 // Check if the next instruction is move-result or move-result-wide. 1051 // If it is, we fetch the shorty and jump to the regular invocation. 1052 FETCH r3, 3 1053 and r3, r3, #0xfe 1054 cmp r3, #0x0a 1055 beq .Lget_shorty_and_invoke_\suffix 1056 .if \is_interface 1057 // Setup hidden argument. 1058 mov ip, r4 1059 .endif 1060 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1061 blx lr 1062 FETCH_ADVANCE_INST 3 1063 GET_INST_OPCODE ip 1064 GOTO_OPCODE ip 1065.Lget_shorty_and_invoke_\suffix: 1066 .if \is_interface 1067 // Save hidden argument. 1068 vmov s16, r4 1069 .endif 1070 GET_SHORTY_SLOW_PATH rINST, \is_interface 1071 b .Lgpr_setup_finished_\suffix 1072 .endif 1073 1074.Lget_shorty_\suffix: 1075 .if \is_interface 1076 // Save hidden argument. 1077 vmov s16, r4 1078 .endif 1079 GET_SHORTY rINST, \is_interface, \is_polymorphic, \is_custom 1080 // From this point: 1081 // - rINST contains shorty (in callee-save to switch over return value after call). 1082 // - r0 contains method 1083 // - r1 contains 'this' pointer for instance method. 1084 // We need three registers. 1085 add r3, rINST, #1 // shorty + 1 ; ie skip return arg character 1086 FETCH r2, 2 // arguments 1087 .if \is_string_init 1088 lsr r2, r2, #4 1089 mov r4, #1 // ignore first argument 1090 .elseif \is_static 1091 mov r4, #0 // arg_index 1092 .else 1093 lsr r2, r2, #4 1094 mov r4, #1 // ignore first argument 1095 .endif 1096 LOOP_OVER_SHORTY_LOADING_FPS d0, s0, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ld1_s2_\suffix 1097.Ld1_s1_\suffix: 1098 LOOP_OVER_SHORTY_LOADING_FPS d1, s1, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ld2_s1_\suffix 1099.Ld1_s2_\suffix: 1100 LOOP_OVER_SHORTY_LOADING_FPS d1, s2, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Ls4_\suffix 1101.Ld2_s3_\suffix: 1102 LOOP_OVER_SHORTY_LOADING_FPS d2, s3, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix 1103 b .Ls4_\suffix 1104.Ld2_s1_\suffix: 1105 LOOP_OVER_SHORTY_LOADING_FPS d2, s1, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix 1106.Ls4_\suffix: 1107 // If we arrive here, we can only have a float. 1108 LOOP_OVER_SHORTY_LOADING_FPS d2, s4, r2, r3, r4, .Lxmm_setup_finished_\suffix, .Lxmm_setup_finished_\suffix 1109.Lxmm_setup_finished_\suffix: 1110 add r4, rINST, #1 // shorty + 1 ; ie skip return arg character 1111 FETCH r8, 2 // arguments 1112 .if \is_string_init 1113 lsr r8, r8, #4 1114 mov lr, #1 // ignore first argument 1115 LOOP_OVER_SHORTY_LOADING_GPRS r1, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0 1116 .elseif \is_static 1117 mov lr, #0 // arg_index 1118 LOOP_OVER_SHORTY_LOADING_GPRS r1, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0 1119 .else 1120 lsr r8, r8, #4 1121 mov lr, #1 // ignore first argument 1122 .endif 1123 LOOP_OVER_SHORTY_LOADING_GPRS r2, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=0 1124 LOOP_OVER_SHORTY_LOADING_GPRS r3, r8, r4, lr, .Lgpr_setup_finished_\suffix, .Lif_long_\suffix, is_r3=1 1125.Lif_long_\suffix: 1126 // Store in the outs array (stored above the ArtMethod in the stack). We only do this for non-string-init 1127 // calls as the index is already adjusted above. 1128 .if !\is_string_init 1129 add lr, lr, #1 1130 .endif 1131 LOOP_OVER_SHORTY_LOADING_INTs r4, r8, lr, .Lgpr_setup_finished_\suffix, \is_string_init 1132.Lgpr_setup_finished_\suffix: 1133 REFRESH_MARKING_REGISTER // r8 was used when setting parameters, restore it. 1134 .if \is_polymorphic 1135 bl art_quick_invoke_polymorphic 1136 .elseif \is_custom 1137 bl art_quick_invoke_custom 1138 .else 1139 .if \is_interface 1140 // Setup hidden argument. 1141 vmov ip, s16 1142 .endif 1143 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1144 blx lr 1145 .endif 1146 SETUP_RETURN_VALUE rINST 1147.Ldone_return_\suffix: 1148 /* resume execution of caller */ 1149 .if \is_string_init 1150 FETCH ip, 2 // arguments 1151 and ip, ip, #0xf 1152 GET_VREG r1, ip 1153 UPDATE_REGISTERS_FOR_STRING_INIT r1, r0 1154 .endif 1155 1156 .if \is_polymorphic 1157 FETCH_ADVANCE_INST 4 1158 .else 1159 FETCH_ADVANCE_INST 3 1160 .endif 1161 GET_INST_OPCODE ip 1162 GOTO_OPCODE ip 1163.endm 1164 1165// Puts the next int/long/object argument in the expected register, 1166// fetching values based on a range invoke. 1167// Uses ip as temporary. 1168.macro LOOP_RANGE_OVER_SHORTY_LOADING_GPRS reg32, shorty, arg_index, stack_index, finished, if_long, is_r3 11691: // LOOP 1170 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 1171 cmp ip, #0 1172 beq \finished // if (ip == '\0') goto finished 1173 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 1174 beq 2f 1175 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 1176 beq 3f 1177 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 1178 beq 4f 1179 GET_VREG \reg32, \arg_index 1180 add \arg_index, \arg_index, #1 1181 add \stack_index, \stack_index, #1 1182 b 5f 11832: // FOUND_LONG 1184 .if \is_r3 1185 // Put back shorty and jump to \if_long 1186 sub \shorty, \shorty, #1 1187 .else 1188 GET_VREG r2, \arg_index 1189 add \arg_index, \arg_index, #1 1190 add \stack_index, \stack_index, #1 1191 GET_VREG r3, \arg_index 1192 add \arg_index, \arg_index, #1 1193 add \stack_index, \stack_index, #1 1194 .endif 1195 b \if_long 11963: // SKIP_FLOAT 1197 add \arg_index, \arg_index, #1 1198 add \stack_index, \stack_index, #1 1199 b 1b 12004: // SKIP_DOUBLE 1201 add \arg_index, \arg_index, #2 1202 add \stack_index, \stack_index, #2 1203 b 1b 12045: 1205.endm 1206 1207// Puts the next int/long/object argument in the expected stack slot, 1208// fetching values based on a range invoke. 1209// Uses ip as temporary. 1210.macro LOOP_RANGE_OVER_INTs shorty, arg_index, stack_index, finished 12111: // LOOP 1212 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 1213 cmp ip, #0 1214 beq \finished // if (ip == '\0') goto finished 1215 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 1216 beq 2f 1217 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 1218 beq 3f 1219 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 1220 beq 4f 1221 GET_VREG ip, \arg_index 1222 str ip, [sp, \stack_index, lsl #2] 1223 add \arg_index, \arg_index, #1 1224 add \stack_index, \stack_index, #1 1225 b 1b 12262: // FOUND_LONG 1227 GET_VREG ip, \arg_index 1228 str ip, [sp, \stack_index, lsl #2] 1229 add \arg_index, \arg_index, #1 1230 add \stack_index, \stack_index, #1 1231 GET_VREG ip, \arg_index 1232 str ip, [sp, \stack_index, lsl #2] 1233 add \arg_index, \arg_index, #1 1234 add \stack_index, \stack_index, #1 1235 b 1b 12363: // SKIP_FLOAT 1237 add \arg_index, \arg_index, #1 1238 add \stack_index, \stack_index, #1 1239 b 1b 12404: // SKIP_DOUBLE 1241 add \arg_index, \arg_index, #2 1242 add \stack_index, \stack_index, #2 1243 b 1b 1244.endm 1245 1246.macro COMMON_INVOKE_RANGE is_static=0, is_interface=0, suffix="", is_string_init=0, is_polymorphic=0, is_custom=0 1247 .if \is_polymorphic 1248 // We always go to compiled code for polymorphic calls. 1249 .elseif \is_custom 1250 // We always go to compiled code for custom calls. 1251 .else 1252 DO_ENTRY_POINT_CHECK .Lcall_compiled_code_range_\suffix, range_\suffix 1253 GET_CODE_ITEM 1254 .if \is_string_init 1255 bl nterp_to_nterp_string_init_range 1256 .elseif \is_static 1257 bl nterp_to_nterp_static_range 1258 .else 1259 bl nterp_to_nterp_instance_range 1260 .endif 1261 b .Ldone_return_range_\suffix 1262.Lfetch_nterp_range_\suffix: 1263 .word (.Lfetch_location_range_\suffix+8) - ExecuteNterpImpl 1264 .endif 1265 1266.Lcall_compiled_code_range_\suffix: 1267 .if \is_polymorphic 1268 // No fast path for polymorphic calls. 1269 .elseif \is_custom 1270 // No fast path for custom calls. 1271 .elseif \is_string_init 1272 // No fast path for string.init. 1273 .else 1274 ldr ip, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1275 tst ip, #ART_METHOD_NTERP_INVOKE_FAST_PATH_FLAG 1276 beq .Lfast_path_with_few_args_range_\suffix 1277 FETCH_B ip, 0, 1 // Number of arguments 1278 .if \is_static 1279 cmp ip, #0 1280 .else 1281 cmp ip, #1 1282 .endif 1283 beq .Linvoke_fast_path_range_\suffix 1284 FETCH lr, 2 // dex register of first argument 1285 add lr, rFP, lr, lsl #2 // location of first dex register value. 1286 .if \is_static 1287 cmp ip, #2 1288 blt .Lone_arg_fast_path_range_\suffix 1289 beq .Ltwo_args_fast_path_range_\suffix 1290 cmp ip, #3 1291 .else 1292 cmp ip, #3 1293 blt .Ltwo_args_fast_path_range_\suffix 1294 .endif 1295 beq .Lthree_args_fast_path_range_\suffix 1296 add rINST, sp, #4 // Add space for the ArtMethod 1297 1298.Lloop_over_fast_path_range_\suffix: 1299 sub ip, ip, #1 1300 ldr r3, [lr, ip, lsl #2] 1301 str r3, [rINST, ip, lsl #2] 1302 cmp ip, #3 1303 bne .Lloop_over_fast_path_range_\suffix 1304 1305.Lthree_args_fast_path_range_\suffix: 1306 ldr r3, [lr, #8] 1307.Ltwo_args_fast_path_range_\suffix: 1308 ldr r2, [lr, #4] 1309.Lone_arg_fast_path_range_\suffix: 1310 .if \is_static 1311 ldr r1, [lr, #0] 1312 .else 1313 // First argument already in r1. 1314 .endif 1315.Linvoke_fast_path_range_\suffix: 1316 .if \is_interface 1317 // Setup hidden argument. 1318 mov ip, r4 1319 .endif 1320 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1321 blx lr 1322 FETCH_ADVANCE_INST 3 1323 GET_INST_OPCODE ip 1324 GOTO_OPCODE ip 1325 1326.Lfast_path_with_few_args_range_\suffix: 1327 // Fast path when we have zero or one argument (modulo 'this'). If there 1328 // is one argument, we can put it in both floating point and core register. 1329 FETCH_B r2, 0, 1 // number of arguments 1330 .if \is_static 1331 cmp r2, #1 1332 blt .Linvoke_with_few_args_range_\suffix 1333 bne .Lget_shorty_range_\suffix 1334 FETCH r3, 2 // dex register of first argument 1335 GET_VREG r1, r3 1336 vmov s0, r1 1337 .else 1338 cmp r2, #2 1339 blt .Linvoke_with_few_args_range_\suffix 1340 bne .Lget_shorty_range_\suffix 1341 FETCH r3, 2 // dex register of first argument 1342 add r3, r3, #1 // Add 1 for next argument 1343 GET_VREG r2, r3 1344 vmov s0, r2 1345 .endif 1346.Linvoke_with_few_args_range_\suffix: 1347 // Check if the next instruction is move-result or move-result-wide. 1348 // If it is, we fetch the shorty and jump to the regular invocation. 1349 FETCH r3, 3 1350 and r3, r3, #0xfe 1351 cmp r3, #0x0a 1352 beq .Lget_shorty_and_invoke_range_\suffix 1353 .if \is_interface 1354 // Setup hidden argument. 1355 mov ip, r4 1356 .endif 1357 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1358 blx lr 1359 FETCH_ADVANCE_INST 3 1360 GET_INST_OPCODE ip 1361 GOTO_OPCODE ip 1362.Lget_shorty_and_invoke_range_\suffix: 1363 .if \is_interface 1364 // Save hidden argument. 1365 vmov s16, r4 1366 .endif 1367 GET_SHORTY_SLOW_PATH rINST, \is_interface 1368 b .Lgpr_setup_finished_range_\suffix 1369 .endif 1370 1371.Lget_shorty_range_\suffix: 1372 .if \is_interface 1373 // Save hidden argument. 1374 vmov s16, r4 1375 .endif 1376 GET_SHORTY rINST, \is_interface, \is_polymorphic, \is_custom 1377 // From this point: 1378 // - rINST contains shorty (in callee-save to switch over return value after call). 1379 // - r0 contains method 1380 // - r1 contains 'this' pointer for instance method. 1381 // 1382 // Save r0 and r1 before calling NterpSetupArm32Fprs. 1383 push {r0, r1} 1384 add r0, rINST, #1 // shorty + 1 ; ie skip return arg character 1385 FETCH r1, 2 // arguments 1386 .if \is_string_init 1387 add r1, r1, #1 // arg start index 1388 mov r2, #1 // index in stack 1389 .elseif \is_static 1390 mov r2, #0 // index in stack 1391 .else 1392 add r1, r1, #1 // arg start index 1393 mov r2, #1 // index in stack 1394 .endif 1395 vpush {s0-s15} 1396 mov r3, sp 1397 // Pass the stack address for arguments, +16 for fprs, +2 for saved registers, 1398 // +1 for ArtMethod. 1399 add lr, sp, #((16 + 2 + 1) * 4) 1400 push {rFP, lr} 1401 bl NterpSetupArm32Fprs 1402 add sp, sp, #8 1403 vpop {s0-s15} 1404 pop {r0, r1} 1405.Lxmm_setup_finished_range_\suffix: 1406 add r8, rINST, #1 // shorty + 1 ; ie skip return arg character 1407 FETCH lr, 2 // arguments 1408 .if \is_string_init 1409 add lr, lr, #1 // arg start index 1410 mov r4, #0 // index in stack 1411 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r1, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0 1412 .elseif \is_static 1413 mov r4, #0 // index in stack 1414 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r1, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0 1415 .else 1416 add lr, lr, #1 // arg start index 1417 mov r4, #1 // index in stack 1418 .endif 1419 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r2, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=0 1420 LOOP_RANGE_OVER_SHORTY_LOADING_GPRS r3, r8, lr, r4, .Lgpr_setup_finished_range_\suffix, .Lif_long_range_\suffix, is_r3=1 1421.Lif_long_range_\suffix: 1422 // Add 1 word for the ArtMethod stored before the outs. 1423 add r4, r4, #1 1424 LOOP_RANGE_OVER_INTs r8, lr, r4, .Lgpr_setup_finished_range_\suffix 1425.Lgpr_setup_finished_range_\suffix: 1426 REFRESH_MARKING_REGISTER // r8 was used when setting parameters, restore it. 1427 .if \is_polymorphic 1428 bl art_quick_invoke_polymorphic 1429 .elseif \is_custom 1430 bl art_quick_invoke_custom 1431 .else 1432 .if \is_interface 1433 // Setup hidden argument. 1434 vmov ip, s16 1435 .endif 1436 ldr lr, [r0, #ART_METHOD_QUICK_CODE_OFFSET_32] 1437 blx lr 1438 .endif 1439 SETUP_RETURN_VALUE rINST 1440.Ldone_return_range_\suffix: 1441 /* resume execution of caller */ 1442 .if \is_string_init 1443 FETCH ip, 2 // arguments 1444 GET_VREG r1, ip 1445 UPDATE_REGISTERS_FOR_STRING_INIT r1, r0 1446 .endif 1447 1448 .if \is_polymorphic 1449 FETCH_ADVANCE_INST 4 1450 .else 1451 FETCH_ADVANCE_INST 3 1452 .endif 1453 GET_INST_OPCODE ip 1454 GOTO_OPCODE ip 1455.endm 1456 1457.macro WRITE_BARRIER_IF_OBJECT is_object, value, holder, label, tmp 1458 .if \is_object 1459 // In T32, we would use `SMART_CBZ \value, \label` 1460 cmp \value, #0 1461 beq \label 1462 ldr ip, [rSELF, #THREAD_CARD_TABLE_OFFSET] 1463 lsr \tmp, \holder, #CARD_TABLE_CARD_SHIFT 1464 strb ip, [ip, \tmp] 1465\label: 1466 .endif 1467.endm 1468 1469.macro LDREXD_STREXD_LOOP addr, load1, load2, store1, store2, tmp, label 1470\label: 1471 ldrexd \load1, \load2, [\addr] 1472 strexd \tmp, \store1, \store2, [\addr] 1473 cmp \tmp, #0 1474 bne \label 1475.endm 1476 1477.macro ATOMIC_LOAD64 addr, load1, load2, tmp, label 1478 LDREXD_STREXD_LOOP \addr, \load1, \load2, \load1, \load2, \tmp, \label 1479.endm 1480 1481.macro ATOMIC_STORE64 addr, store1, store2, tmp1, tmp2, label 1482 LDREXD_STREXD_LOOP \addr, \tmp1, \tmp2, \store1, \store2, \tmp1, \label 1483.endm 1484 1485// Fetch some information from the thread cache. 1486// Uses ip and lr as temporaries. 1487.macro FETCH_FROM_THREAD_CACHE dest_reg, slow_path 1488 add ip, rSELF, #THREAD_INTERPRETER_CACHE_OFFSET // cache address 1489 ubfx lr, rPC, #2, #THREAD_INTERPRETER_CACHE_SIZE_LOG2 // entry index 1490 add ip, ip, lr, lsl #3 // entry address within the cache 1491 // In T32, we would use `ldrd ip, \dest_reg, [ip]` 1492 ldr \dest_reg, [ip, #4] // value (offset) 1493 ldr ip, [ip] // entry key (pc) 1494 cmp ip, rPC 1495 bne \slow_path 1496.endm 1497 1498// Puts the next int/long/object parameter passed in physical register 1499// in the expected dex register array entry, and in case of object in the 1500// expected reference array entry. 1501// Uses ip as temporary. 1502.macro LOOP_OVER_SHORTY_STORING_GPRS gpr_32, shorty, arg_offset, regs, refs, finished, if_long, is_r3 15031: // LOOP 1504 ldrb ip, [\shorty], #1 // Load next character in shorty, and increment. 1505 cmp ip, #0 1506 beq \finished // if (ip == '\0') goto finished 1507 cmp ip, #74 // if (ip == 'J') goto FOUND_LONG 1508 beq 2f 1509 cmp ip, #70 // if (ip == 'F') goto SKIP_FLOAT 1510 beq 3f 1511 cmp ip, #68 // if (ip == 'D') goto SKIP_DOUBLE 1512 beq 4f 1513 str \gpr_32, [\regs, \arg_offset] 1514 cmp ip, #76 // if (ip != 'L') goto NOT_REFERENCE 1515 bne 6f 1516 str \gpr_32, [\refs, \arg_offset] 15176: // NOT_REFERENCE 1518 add \arg_offset, \arg_offset, #4 1519 b 5f 15202: // FOUND_LONG 1521 .if \is_r3 1522 // Put back shorty and jump to \if_long 1523 sub \shorty, \shorty, #1 1524 .else 1525 // A long can only be in r2, r3 1526 str r2, [\regs, \arg_offset] 1527 add \arg_offset, \arg_offset, #4 1528 str r3, [\regs, \arg_offset] 1529 add \arg_offset, \arg_offset, #4 1530 .endif 1531 b \if_long 15323: // SKIP_FLOAT 1533 add \arg_offset, \arg_offset, #4 1534 b 1b 15354: // SKIP_DOUBLE 1536 add \arg_offset, \arg_offset, #8 1537 b 1b 15385: 1539.endm 1540 1541// Puts the next int/long/object parameter passed in stack 1542// in the expected dex register array entry, and in case of object in the 1543// expected reference array entry. 1544.macro LOOP_OVER_INTs shorty, arg_offset, regs, refs, stack_ptr, tmp1, tmp2, finished 15451: // LOOP 1546 ldrb \tmp1, [\shorty], #1 // Load next character in shorty, and increment. 1547 cmp \tmp1, #0 1548 beq \finished // if (\tmp1 == '\0') goto finished 1549 cmp \tmp1, #74 // if (\tmp1 == 'J') goto FOUND_LONG 1550 beq 2f 1551 cmp \tmp1, #70 // if (\tmp1 == 'F') goto SKIP_FLOAT 1552 beq 3f 1553 cmp \tmp1, #68 // if (\tmp1 == 'D') goto SKIP_DOUBLE 1554 beq 4f 1555 add \tmp2, \stack_ptr, \arg_offset 1556 ldr \tmp2, [\tmp2, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1557 str \tmp2, [\regs, \arg_offset] 1558 cmp \tmp1, #76 // if (\tmp1 != 'L') goto loop 1559 bne 3f 1560 str \tmp2, [\refs, \arg_offset] 1561 add \arg_offset, \arg_offset, #4 1562 b 1b 15632: // FOUND_LONG 1564 add \tmp1, \stack_ptr, \arg_offset 1565 ldr \tmp1, [\tmp1, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1566 str \tmp1, [\regs, \arg_offset] 1567 add \arg_offset, \arg_offset, #4 1568 add \tmp1, \stack_ptr, \arg_offset 1569 ldr \tmp1, [\tmp1, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK] 1570 str \tmp1, [\regs, \arg_offset] 1571 add \arg_offset, \arg_offset, #4 1572 b 1b 15733: // SKIP_FLOAT 1574 add \arg_offset, \arg_offset, #4 1575 b 1b 15764: // SKIP_DOUBLE 1577 add \arg_offset, \arg_offset, #8 1578 b 1b 1579.endm 1580 1581.macro SETUP_REFERENCE_PARAMETER_IN_GPR gpr32, regs, refs, ins, arg_offset, finished 1582 str \gpr32, [\regs, \arg_offset] 1583 subs \ins, \ins, #1 1584 str \gpr32, [\refs, \arg_offset] 1585 add \arg_offset, \arg_offset, #4 1586 beq \finished 1587.endm 1588 1589.macro SETUP_REFERENCE_PARAMETERS_IN_STACK regs, refs, ins, stack_ptr, arg_offset 15901: 1591 ldr ip, [\stack_ptr, \arg_offset] 1592 subs \ins, \ins, #1 1593 str ip, [\regs, \arg_offset] 1594 str ip, [\refs, \arg_offset] 1595 add \arg_offset, \arg_offset, #4 1596 bne 1b 1597.endm 1598 1599%def entry(): 1600/* 1601 * ArtMethod entry point. 1602 * 1603 * On entry: 1604 * r0 ArtMethod* callee 1605 * rest method parameters 1606 */ 1607 1608OAT_ENTRY ExecuteNterpImpl, EndExecuteNterpImpl 1609 .cfi_startproc 1610 sub ip, sp, #STACK_OVERFLOW_RESERVED_BYTES 1611 ldr ip, [ip] 1612 /* Spill callee save regs */ 1613 SPILL_ALL_CALLEE_SAVES 1614 1615 ldr rPC, [r0, #ART_METHOD_DATA_OFFSET_32] 1616 1617 // Setup the stack for executing the method. 1618 SETUP_STACK_FRAME rPC, rREFS, rFP, CFI_REFS, load_ins=1 1619 1620 // Setup the parameters 1621 cmp r4, #0 1622 beq .Lxmm_setup_finished 1623 1624 sub rINST, rINST, r4 1625 ldr r8, [r0, #ART_METHOD_ACCESS_FLAGS_OFFSET] 1626 lsl rINST, rINST, #2 // rINST is now the offset for inputs into the registers array. 1627 mov rIBASE, ip // rIBASE contains the old stack pointer 1628 1629 tst r8, #ART_METHOD_NTERP_ENTRY_POINT_FAST_PATH_FLAG 1630 beq .Lsetup_slow_path 1631 // Setup pointer to inputs in FP and pointer to inputs in REFS 1632 add lr, rFP, rINST 1633 add r8, rREFS, rINST 1634 mov r0, #0 1635 SETUP_REFERENCE_PARAMETER_IN_GPR r1, lr, r8, r4, r0, .Lxmm_setup_finished 1636 SETUP_REFERENCE_PARAMETER_IN_GPR r2, lr, r8, r4, r0, .Lxmm_setup_finished 1637 SETUP_REFERENCE_PARAMETER_IN_GPR r3, lr, r8, r4, r0, .Lxmm_setup_finished 1638 add rIBASE, rIBASE, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK 1639 SETUP_REFERENCE_PARAMETERS_IN_STACK lr, r8, r4, rIBASE, r0 1640 b .Lxmm_setup_finished 1641 1642.Lsetup_slow_path: 1643 // If the method is not static and there is one argument ('this'), we don't need to fetch the 1644 // shorty. 1645 tst r8, #ART_METHOD_IS_STATIC_FLAG 1646 bne .Lsetup_with_shorty 1647 str r1, [rFP, rINST] 1648 str r1, [rREFS, rINST] 1649 cmp r4, #1 1650 beq .Lxmm_setup_finished 1651 1652.Lsetup_with_shorty: 1653 // Save arguments that were passed before calling into the runtime. 1654 // No need to save r0 (ArtMethod) as we're not using it later in this code. 1655 // Save r4 for stack aligment. 1656 // TODO: Get shorty in a better way and remove below 1657 push {r1-r4} 1658 vpush {s0-s15} 1659 bl NterpGetShorty 1660 vpop {s0-s15} 1661 pop {r1-r4} 1662 1663 mov ip, r8 1664 add r8, rREFS, rINST 1665 add r7, rFP, rINST 1666 mov r4, #0 1667 // Setup shorty, pointer to inputs in FP and pointer to inputs in REFS 1668 add lr, r0, #1 // shorty + 1 ; ie skip return arg character 1669 tst ip, #ART_METHOD_IS_STATIC_FLAG 1670 bne .Lhandle_static_method 1671 add r7, r7, #4 1672 add r8, r8, #4 1673 add rIBASE, rIBASE, #4 1674 b .Lcontinue_setup_gprs 1675.Lhandle_static_method: 1676 LOOP_OVER_SHORTY_STORING_GPRS r1, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=0 1677.Lcontinue_setup_gprs: 1678 LOOP_OVER_SHORTY_STORING_GPRS r2, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=0 1679 LOOP_OVER_SHORTY_STORING_GPRS r3, lr, r4, r7, r8, .Lgpr_setup_finished, .Lif_long, is_r3=1 1680.Lif_long: 1681 LOOP_OVER_INTs lr, r4, r7, r8, rIBASE, ip, r1, .Lgpr_setup_finished 1682.Lgpr_setup_finished: 1683 add r0, r0, #1 // shorty + 1 ; ie skip return arg character 1684 mov r1, r7 1685 add r2, rIBASE, #OFFSET_TO_FIRST_ARGUMENT_IN_STACK 1686 vpush {s0-s15} 1687 mov r3, sp 1688 bl NterpStoreArm32Fprs 1689 add sp, sp, #(16 * 4) 1690.Lxmm_setup_finished: 1691 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 1692 // r8 was used for setting up the frame, restore it now. 1693 REFRESH_MARKING_REGISTER 1694.Lexecute_instructions: 1695 // Set rIBASE 1696 adr rIBASE, artNterpAsmInstructionStart 1697 /* start executing the instruction at rPC */ 1698 START_EXECUTING_INSTRUCTIONS 1699 /* NOTE: no fallthrough */ 1700 // cfi info continues, and covers the whole nterp implementation. 1701 SIZE ExecuteNterpImpl 1702 1703%def opcode_pre(): 1704 1705%def helpers(): 1706 1707%def footer(): 1708/* 1709 * =========================================================================== 1710 * Common subroutines and data 1711 * =========================================================================== 1712 */ 1713 1714 .text 1715 .align 2 1716 1717// Enclose all code below in a symbol (which gets printed in backtraces). 1718NAME_START nterp_helper 1719 1720// Note: mterp also uses the common_* names below for helpers, but that's OK 1721// as the assembler compiled each interpreter separately. 1722common_errDivideByZero: 1723 EXPORT_PC 1724 bl art_quick_throw_div_zero 1725 1726// Expect index in r1, length in r3 1727common_errArrayIndex: 1728 EXPORT_PC 1729 mov r0, r1 1730 mov r1, r3 1731 bl art_quick_throw_array_bounds 1732 1733common_errNullObject: 1734 EXPORT_PC 1735 bl art_quick_throw_null_pointer_exception 1736 1737NterpCommonInvokeStatic: 1738 COMMON_INVOKE_NON_RANGE is_static=1, suffix="invokeStatic" 1739 1740NterpCommonInvokeStaticRange: 1741 COMMON_INVOKE_RANGE is_static=1, suffix="invokeStatic" 1742 1743NterpCommonInvokeInstance: 1744 COMMON_INVOKE_NON_RANGE suffix="invokeInstance" 1745 1746NterpCommonInvokeInstanceRange: 1747 COMMON_INVOKE_RANGE suffix="invokeInstance" 1748 1749NterpCommonInvokeInterface: 1750 COMMON_INVOKE_NON_RANGE is_interface=1, suffix="invokeInterface" 1751 1752NterpCommonInvokeInterfaceRange: 1753 COMMON_INVOKE_RANGE is_interface=1, suffix="invokeInterface" 1754 1755NterpCommonInvokePolymorphic: 1756 COMMON_INVOKE_NON_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1757 1758NterpCommonInvokePolymorphicRange: 1759 COMMON_INVOKE_RANGE is_polymorphic=1, suffix="invokePolymorphic" 1760 1761NterpCommonInvokeCustom: 1762 COMMON_INVOKE_NON_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1763 1764NterpCommonInvokeCustomRange: 1765 COMMON_INVOKE_RANGE is_static=1, is_custom=1, suffix="invokeCustom" 1766 1767NterpHandleStringInit: 1768 COMMON_INVOKE_NON_RANGE is_string_init=1, suffix="stringInit" 1769 1770NterpHandleStringInitRange: 1771 COMMON_INVOKE_RANGE is_string_init=1, suffix="stringInit" 1772 1773NterpNewArray: 1774 /* new-array vA, vB, class@CCCC */ 1775 EXPORT_PC 1776 // Fast-path which gets the class from thread-local cache. 1777 FETCH_FROM_THREAD_CACHE r0, 2f 1778 cmp rMR, #0 1779 bne 3f 17801: 1781 lsr r1, rINST, #12 // r1<- B 1782 GET_VREG r1, r1 // r1<- vB (array length) 1783 ldr lr, [rSELF, #THREAD_ALLOC_ARRAY_ENTRYPOINT_OFFSET] 1784 blx lr 1785 ubfx r1, rINST, #8, #4 // r1<- A 1786 SET_VREG_OBJECT r0, r1 1787 FETCH_ADVANCE_INST 2 1788 GET_INST_OPCODE ip 1789 GOTO_OPCODE ip 17902: 1791 mov r0, rSELF 1792 ldr r1, [sp] 1793 mov r2, rPC 1794 bl nterp_get_class_or_allocate_object 1795 b 1b 17963: 1797 bl art_quick_read_barrier_mark_reg00 1798 b 1b 1799 1800 1801NterpHandleHotnessOverflow: 1802 add r1, rPC, rINST, lsl #1 1803 mov r2, rFP 1804 bl nterp_hot_method 1805 cmp r0, #0 1806 bne 1f 1807 add r2, rINST, rINST // w2<- byte offset 1808 FETCH_ADVANCE_INST_RB r2 // update rPC, load rINST 1809 GET_INST_OPCODE ip // extract opcode from rINST 1810 GOTO_OPCODE ip // jump to next instruction 18111: 1812 // Drop the current frame. 1813 ldr ip, [rREFS, #-4] 1814 mov sp, ip 1815 .cfi_def_cfa sp, CALLEE_SAVES_SIZE 1816 1817 // The transition frame of type SaveAllCalleeSaves saves r4, r8, and r9, 1818 // but not managed ABI. So we need to restore callee-saves of the nterp frame, 1819 // and save managed ABI callee saves, which will be restored by the callee upon 1820 // return. 1821 1822 RESTORE_ALL_CALLEE_SAVES 1823 push {r5-r7, r10-r11, lr} 1824 .cfi_adjust_cfa_offset 24 1825 .cfi_rel_offset r5, 0 1826 .cfi_rel_offset r6, 4 1827 .cfi_rel_offset r7, 8 1828 .cfi_rel_offset r10, 12 1829 .cfi_rel_offset r11, 16 1830 .cfi_rel_offset lr, 20 1831 vpush {s16-s31} 1832 .cfi_adjust_cfa_offset 64 1833 1834 // Setup the new frame 1835 ldr r1, [r0, #OSR_DATA_FRAME_SIZE] 1836 // Given stack size contains all callee saved registers, remove them. 1837 sub r1, r1, #(CALLEE_SAVES_SIZE - 12) 1838 1839 // We know r1 cannot be 0, as it at least contains the ArtMethod. 1840 1841 // Remember CFA in a callee-save register. 1842 mov rINST, sp 1843 .cfi_def_cfa_register rINST 1844 1845 sub sp, sp, r1 1846 1847 add r2, r0, #OSR_DATA_MEMORY 18482: 1849 sub r1, r1, #4 1850 ldr ip, [r2, r1] 1851 str ip, [sp, r1] 1852 cmp r1, #0 1853 bne 2b 1854 1855 // Fetch the native PC to jump to and save it in a callee-save register. 1856 ldr rFP, [r0, #OSR_DATA_NATIVE_PC] 1857 1858 // Free the memory holding OSR Data. 1859 bl free 1860 1861 // Jump to the compiled code. 1862 bx rFP 1863// This is the logical end of ExecuteNterpImpl, where the frame info applies. 1864// EndExecuteNterpImpl includes the methods below as we want the runtime to 1865// see them as part of the Nterp PCs. 1866.cfi_endproc 1867 1868nterp_to_nterp_static_non_range: 1869 .cfi_startproc 1870 SETUP_STACK_FOR_INVOKE 1871 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0 1872 .cfi_endproc 1873 1874nterp_to_nterp_string_init_non_range: 1875 .cfi_startproc 1876 SETUP_STACK_FOR_INVOKE 1877 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1878 .cfi_endproc 1879 1880nterp_to_nterp_instance_non_range: 1881 .cfi_startproc 1882 SETUP_STACK_FOR_INVOKE 1883 SETUP_NON_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 1884 .cfi_endproc 1885 1886nterp_to_nterp_static_range: 1887 .cfi_startproc 1888 SETUP_STACK_FOR_INVOKE 1889 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=1, is_string_init=0 1890 .cfi_endproc 1891 1892nterp_to_nterp_string_init_range: 1893 .cfi_startproc 1894 SETUP_STACK_FOR_INVOKE 1895 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=1 1896 .cfi_endproc 1897 1898nterp_to_nterp_instance_range: 1899 .cfi_startproc 1900 SETUP_STACK_FOR_INVOKE 1901 SETUP_RANGE_ARGUMENTS_AND_EXECUTE is_static=0, is_string_init=0 1902 .cfi_endproc 1903 1904NAME_END nterp_helper 1905 1906// This is the end of PCs contained by the OatQuickMethodHeader created for the interpreter 1907// entry point. 1908 .type EndExecuteNterpImpl, #function 1909 .hidden EndExecuteNterpImpl 1910 .global EndExecuteNterpImpl 1911EndExecuteNterpImpl: 1912 1913/* 1914 * Convert the double in r0/r1 to a long in r0/r1. 1915 * 1916 * We have to clip values to long min/max per the specification. The 1917 * expected common case is a "reasonable" value that converts directly 1918 * to modest integer. The EABI convert function isn't doing this for us. 1919 */ 1920nterp_d2l_doconv: 1921 ubfx r2, r1, #20, #11 @ grab the exponent 1922 movw r3, #0x43e 1923 cmp r2, r3 @ MINLONG < x > MAXLONG? 1924 bhs d2l_special_cases 1925 b __aeabi_d2lz @ tail call to convert double to long 1926d2l_special_cases: 1927 movw r3, #0x7ff 1928 cmp r2, r3 1929 beq d2l_maybeNaN @ NaN? 1930d2l_notNaN: 1931 adds r1, r1, r1 @ sign bit to carry 1932 mov r0, #0xffffffff @ assume maxlong for lsw 1933 mov r1, #0x7fffffff @ assume maxlong for msw 1934 adc r0, r0, #0 1935 adc r1, r1, #0 @ convert maxlong to minlong if exp negative 1936 bx lr @ return 1937d2l_maybeNaN: 1938 orrs r3, r0, r1, lsl #12 1939 beq d2l_notNaN @ if fraction is non-zero, it's a NaN 1940 mov r0, #0 1941 mov r1, #0 1942 bx lr @ return 0 for NaN 1943 1944/* 1945 * Convert the float in r0 to a long in r0/r1. 1946 * 1947 * We have to clip values to long min/max per the specification. The 1948 * expected common case is a "reasonable" value that converts directly 1949 * to modest integer. The EABI convert function isn't doing this for us. 1950 */ 1951nterp_f2l_doconv: 1952 ubfx r2, r0, #23, #8 @ grab the exponent 1953 cmp r2, #0xbe @ MININT < x > MAXINT? 1954 bhs f2l_special_cases 1955 b __aeabi_f2lz @ tail call to convert float to long 1956f2l_special_cases: 1957 cmp r2, #0xff @ NaN or infinity? 1958 beq f2l_maybeNaN 1959f2l_notNaN: 1960 adds r0, r0, r0 @ sign bit to carry 1961 mov r0, #0xffffffff @ assume maxlong for lsw 1962 mov r1, #0x7fffffff @ assume maxlong for msw 1963 adc r0, r0, #0 1964 adc r1, r1, #0 @ convert maxlong to minlong if exp negative 1965 bx lr @ return 1966f2l_maybeNaN: 1967 lsls r3, r0, #9 1968 beq f2l_notNaN @ if fraction is non-zero, it's a NaN 1969 mov r0, #0 1970 mov r1, #0 1971 bx lr @ return 0 for NaN 1972 1973// Entrypoints into runtime. 1974NTERP_TRAMPOLINE nterp_get_static_field, NterpGetStaticField 1975NTERP_TRAMPOLINE nterp_get_instance_field_offset, NterpGetInstanceFieldOffset 1976NTERP_TRAMPOLINE nterp_filled_new_array, NterpFilledNewArray 1977NTERP_TRAMPOLINE nterp_filled_new_array_range, NterpFilledNewArrayRange 1978NTERP_TRAMPOLINE nterp_get_class_or_allocate_object, NterpGetClassOrAllocateObject 1979NTERP_TRAMPOLINE nterp_get_method, NterpGetMethod 1980NTERP_TRAMPOLINE nterp_hot_method, NterpHotMethod 1981NTERP_TRAMPOLINE nterp_load_object, NterpLoadObject 1982 1983// gen_mterp.py will inline the following definitions 1984// within [ExecuteNterpImpl, EndExecuteNterpImpl). 1985%def instruction_end(): 1986 1987 .type artNterpAsmInstructionEnd, #object 1988 .hidden artNterpAsmInstructionEnd 1989 .global artNterpAsmInstructionEnd 1990artNterpAsmInstructionEnd: 1991 // artNterpAsmInstructionEnd is used as landing pad for exception handling. 1992 FETCH_INST 1993 GET_INST_OPCODE ip 1994 GOTO_OPCODE ip 1995 1996%def instruction_start(): 1997 1998 .type artNterpAsmInstructionStart, #object 1999 .hidden artNterpAsmInstructionStart 2000 .global artNterpAsmInstructionStart 2001artNterpAsmInstructionStart = .L_op_nop 2002 .text 2003 2004%def default_helper_prefix(): 2005% return "nterp_" 2006 2007%def opcode_start(): 2008 NAME_START nterp_${opcode} 2009%def opcode_end(): 2010 NAME_END nterp_${opcode} 2011%def helper_start(name): 2012 NAME_START ${name} 2013%def helper_end(name): 2014 NAME_END ${name} 2015