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