1%def header(): 2/* 3 * Copyright (C) 2016 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 Art assembly interpreter notes: 20 21 First validate assembly code by implementing ExecuteXXXImpl() style body (doesn't 22 handle invoke, allows higher-level code to create frame & shadow frame. 23 24 Once that's working, support direct entry code & eliminate shadow frame (and 25 excess locals allocation. 26 27 Some (hopefully) temporary ugliness. We'll treat rFP as pointing to the 28 base of the vreg array within the shadow frame. Access the other fields, 29 dex_pc_, method_ and number_of_vregs_ via negative offsets. For now, we'll continue 30 the shadow frame mechanism of double-storing object references - via rFP & 31 number_of_vregs_. 32 33 */ 34 35/* 36ARM EABI general notes: 37 38r0-r3 hold first 4 args to a method; they are not preserved across method calls 39r4-r8 are available for general use 40r9 is given special treatment in some situations, but not for us 41r10 (sl) seems to be generally available 42r11 (fp) is used by gcc (unless -fomit-frame-pointer is set) 43r12 (ip) is scratch -- not preserved across method calls 44r13 (sp) should be managed carefully in case a signal arrives 45r14 (lr) must be preserved 46r15 (pc) can be tinkered with directly 47 48r0 holds returns of <= 4 bytes 49r0-r1 hold returns of 8 bytes, low word in r0 50 51Callee must save/restore r4+ (except r12) if it modifies them. If VFP 52is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved, 53s0-s15 (d0-d7, q0-a3) do not need to be. 54 55Stack is "full descending". Only the arguments that don't fit in the first 4 56registers are placed on the stack. "sp" points at the first stacked argument 57(i.e. the 5th arg). 58 59VFP: single-precision results in s0, double-precision results in d0. 60 61In the EABI, "sp" must be 64-bit aligned on entry to a function, and any 6264-bit quantities (long long, double) must be 64-bit aligned. 63*/ 64 65/* 66Mterp and ARM notes: 67 68The following registers have fixed assignments: 69 70 reg nick purpose 71 r4 rPC interpreted program counter, used for fetching instructions 72 r5 rFP interpreted frame pointer, used for accessing locals and args 73 r6 rSELF self (Thread) pointer 74 r7 rINST first 16-bit code unit of current instruction 75 r8 rIBASE interpreted instruction base pointer, used for computed goto 76 r10 rPROFILE branch profiling countdown 77 r11 rREFS base of object references in shadow frame (ideally, we'll get rid of this later). 78 79Macros are provided for common operations. Each macro MUST emit only 80one instruction to make instruction-counting easier. They MUST NOT alter 81unspecified registers or condition codes. 82*/ 83 84/* 85 * This is a #include, not a %include, because we want the C pre-processor 86 * to expand the macros into assembler assignment statements. 87 */ 88#include "asm_support.h" 89#include "interpreter/cfi_asm_support.h" 90 91#define MTERP_PROFILE_BRANCHES 1 92#define MTERP_LOGGING 0 93 94/* During bringup, we'll use the shadow frame model instead of rFP */ 95/* single-purpose registers, given names for clarity */ 96#define rPC r4 97#define CFI_DEX 4 // DWARF register number of the register holding dex-pc (xPC). 98#define CFI_TMP 0 // DWARF register number of the first argument register (r0). 99#define rFP r5 100#define rSELF r6 101#define rINST r7 102#define rIBASE r8 103#define rPROFILE r10 104#define rREFS r11 105 106/* 107 * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs. So, 108 * to access other shadow frame fields, we need to use a backwards offset. Define those here. 109 */ 110#define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET) 111#define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET) 112#define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET) 113#define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET) 114#define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET) 115#define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET) 116#define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET) 117#define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET) 118#define OFF_FP_SHADOWFRAME OFF_FP(0) 119 120/* 121 * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects. Must 122 * be done *before* something throws. 123 * 124 * It's okay to do this more than once. 125 * 126 * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped 127 * dex byte codes. However, the rest of the runtime expects dex pc to be an instruction 128 * offset into the code_items_[] array. For effiency, we will "export" the 129 * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC 130 * to convert to a dex pc when needed. 131 */ 132.macro EXPORT_PC 133 str rPC, [rFP, #OFF_FP_DEX_PC_PTR] 134.endm 135 136.macro EXPORT_DEX_PC tmp 137 ldr \tmp, [rFP, #OFF_FP_DEX_INSTRUCTIONS] 138 str rPC, [rFP, #OFF_FP_DEX_PC_PTR] 139 sub \tmp, rPC, \tmp 140 asr \tmp, #1 141 str \tmp, [rFP, #OFF_FP_DEX_PC] 142.endm 143 144/* 145 * Fetch the next instruction from rPC into rINST. Does not advance rPC. 146 */ 147.macro FETCH_INST 148 ldrh rINST, [rPC] 149.endm 150 151/* 152 * Fetch the next instruction from the specified offset. Advances rPC 153 * to point to the next instruction. "_count" is in 16-bit code units. 154 * 155 * Because of the limited size of immediate constants on ARM, this is only 156 * suitable for small forward movements (i.e. don't try to implement "goto" 157 * with this). 158 * 159 * This must come AFTER anything that can throw an exception, or the 160 * exception catch may miss. (This also implies that it must come after 161 * EXPORT_PC.) 162 */ 163.macro FETCH_ADVANCE_INST count 164 ldrh rINST, [rPC, #((\count)*2)]! 165.endm 166 167/* 168 * The operation performed here is similar to FETCH_ADVANCE_INST, except the 169 * src and dest registers are parameterized (not hard-wired to rPC and rINST). 170 */ 171.macro PREFETCH_ADVANCE_INST dreg, sreg, count 172 ldrh \dreg, [\sreg, #((\count)*2)]! 173.endm 174 175/* 176 * Similar to FETCH_ADVANCE_INST, but does not update rPC. Used to load 177 * rINST ahead of possible exception point. Be sure to manually advance rPC 178 * later. 179 */ 180.macro PREFETCH_INST count 181 ldrh rINST, [rPC, #((\count)*2)] 182.endm 183 184/* Advance rPC by some number of code units. */ 185.macro ADVANCE count 186 add rPC, #((\count)*2) 187.endm 188 189/* 190 * Fetch the next instruction from an offset specified by _reg. Updates 191 * rPC to point to the next instruction. "_reg" must specify the distance 192 * in bytes, *not* 16-bit code units, and may be a signed value. 193 * 194 * We want to write "ldrh rINST, [rPC, _reg, lsl #1]!", but some of the 195 * bits that hold the shift distance are used for the half/byte/sign flags. 196 * In some cases we can pre-double _reg for free, so we require a byte offset 197 * here. 198 */ 199.macro FETCH_ADVANCE_INST_RB reg 200 ldrh rINST, [rPC, \reg]! 201.endm 202 203/* 204 * Fetch a half-word code unit from an offset past the current PC. The 205 * "_count" value is in 16-bit code units. Does not advance rPC. 206 * 207 * The "_S" variant works the same but treats the value as signed. 208 */ 209.macro FETCH reg, count 210 ldrh \reg, [rPC, #((\count)*2)] 211.endm 212 213.macro FETCH_S reg, count 214 ldrsh \reg, [rPC, #((\count)*2)] 215.endm 216 217/* 218 * Fetch one byte from an offset past the current PC. Pass in the same 219 * "_count" as you would for FETCH, and an additional 0/1 indicating which 220 * byte of the halfword you want (lo/hi). 221 */ 222.macro FETCH_B reg, count, byte 223 ldrb \reg, [rPC, #((\count)*2+(\byte))] 224.endm 225 226/* 227 * Put the instruction's opcode field into the specified register. 228 */ 229.macro GET_INST_OPCODE reg 230 and \reg, rINST, #255 231.endm 232 233/* 234 * Put the prefetched instruction's opcode field into the specified register. 235 */ 236.macro GET_PREFETCHED_OPCODE oreg, ireg 237 and \oreg, \ireg, #255 238.endm 239 240/* 241 * Begin executing the opcode in _reg. Because this only jumps within the 242 * interpreter, we don't have to worry about pre-ARMv5 THUMB interwork. 243 */ 244.macro GOTO_OPCODE reg 245 add pc, rIBASE, \reg, lsl #${handler_size_bits} 246.endm 247.macro GOTO_OPCODE_BASE base,reg 248 add pc, \base, \reg, lsl #${handler_size_bits} 249.endm 250 251/* 252 * Get/set the 32-bit value from a Dalvik register. 253 */ 254.macro GET_VREG reg, vreg 255 ldr \reg, [rFP, \vreg, lsl #2] 256.endm 257.macro SET_VREG reg, vreg 258 str \reg, [rFP, \vreg, lsl #2] 259 mov \reg, #0 260 str \reg, [rREFS, \vreg, lsl #2] 261.endm 262.macro SET_VREG_WIDE regLo, regHi, vreg 263 add ip, rFP, \vreg, lsl #2 264 strd \regLo, \regHi, [ip] 265 mov \regLo, #0 266 mov \regHi, #0 267 add ip, rREFS, \vreg, lsl #2 268 strd \regLo, \regHi, [ip] 269.endm 270.macro SET_VREG_OBJECT reg, vreg, tmpreg 271 str \reg, [rFP, \vreg, lsl #2] 272 str \reg, [rREFS, \vreg, lsl #2] 273.endm 274.macro SET_VREG_SHADOW reg, vreg 275 str \reg, [rREFS, \vreg, lsl #2] 276.endm 277.macro SET_VREG_FLOAT reg, vreg, tmpreg 278 add \tmpreg, rFP, \vreg, lsl #2 279 fsts \reg, [\tmpreg] 280 mov \tmpreg, #0 281 str \tmpreg, [rREFS, \vreg, lsl #2] 282.endm 283 284/* 285 * Clear the corresponding shadow regs for a vreg pair 286 */ 287.macro CLEAR_SHADOW_PAIR vreg, tmp1, tmp2 288 mov \tmp1, #0 289 add \tmp2, \vreg, #1 290 SET_VREG_SHADOW \tmp1, \vreg 291 SET_VREG_SHADOW \tmp1, \tmp2 292.endm 293 294/* 295 * Convert a virtual register index into an address. 296 */ 297.macro VREG_INDEX_TO_ADDR reg, vreg 298 add \reg, rFP, \vreg, lsl #2 /* WARNING/FIXME: handle shadow frame vreg zero if store */ 299.endm 300 301.macro GET_VREG_WIDE_BY_ADDR reg0, reg1, addr 302 ldmia \addr, {\reg0, \reg1} 303.endm 304.macro SET_VREG_WIDE_BY_ADDR reg0, reg1, addr 305 stmia \addr, {\reg0, \reg1} 306.endm 307.macro GET_VREG_FLOAT_BY_ADDR reg, addr 308 flds \reg, [\addr] 309.endm 310.macro SET_VREG_FLOAT_BY_ADDR reg, addr 311 fsts \reg, [\addr] 312.endm 313.macro GET_VREG_DOUBLE_BY_ADDR reg, addr 314 fldd \reg, [\addr] 315.endm 316.macro SET_VREG_DOUBLE_BY_ADDR reg, addr 317 fstd \reg, [\addr] 318.endm 319 320/* 321 * Refresh handler table. 322 */ 323.macro REFRESH_IBASE 324 ldr rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET] 325.endm 326 327/* 328 * function support macros. 329 */ 330.macro ENTRY name 331 .arm 332 .type \name, #function 333 .hidden \name // Hide this as a global symbol, so we do not incur plt calls. 334 .global \name 335 /* Cache alignment for function entry */ 336 .balign 16 337\name: 338.endm 339 340.macro END name 341 .size \name, .-\name 342.endm 343 344// Macro to unpoison (negate) the reference for heap poisoning. 345.macro UNPOISON_HEAP_REF rRef 346#ifdef USE_HEAP_POISONING 347 rsb \rRef, \rRef, #0 348#endif // USE_HEAP_POISONING 349.endm 350 351%def entry(): 352/* 353 * Copyright (C) 2016 The Android Open Source Project 354 * 355 * Licensed under the Apache License, Version 2.0 (the "License"); 356 * you may not use this file except in compliance with the License. 357 * You may obtain a copy of the License at 358 * 359 * http://www.apache.org/licenses/LICENSE-2.0 360 * 361 * Unless required by applicable law or agreed to in writing, software 362 * distributed under the License is distributed on an "AS IS" BASIS, 363 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 364 * See the License for the specific language governing permissions and 365 * limitations under the License. 366 */ 367/* 368 * Interpreter entry point. 369 */ 370 371 .text 372 .align 2 373 374/* 375 * On entry: 376 * r0 Thread* self/ 377 * r1 insns_ 378 * r2 ShadowFrame 379 * r3 JValue* result_register 380 * 381 */ 382 383ENTRY ExecuteMterpImpl 384 .cfi_startproc 385 stmfd sp!, {r3-r10,fp,lr} @ save 10 regs, (r3 just to align 64) 386 .cfi_adjust_cfa_offset 40 387 .cfi_rel_offset r3, 0 388 .cfi_rel_offset r4, 4 389 .cfi_rel_offset r5, 8 390 .cfi_rel_offset r6, 12 391 .cfi_rel_offset r7, 16 392 .cfi_rel_offset r8, 20 393 .cfi_rel_offset r9, 24 394 .cfi_rel_offset r10, 28 395 .cfi_rel_offset fp, 32 396 .cfi_rel_offset lr, 36 397 398 /* Remember the return register */ 399 str r3, [r2, #SHADOWFRAME_RESULT_REGISTER_OFFSET] 400 401 /* Remember the dex instruction pointer */ 402 str r1, [r2, #SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET] 403 404 /* set up "named" registers */ 405 mov rSELF, r0 406 ldr r0, [r2, #SHADOWFRAME_NUMBER_OF_VREGS_OFFSET] 407 add rFP, r2, #SHADOWFRAME_VREGS_OFFSET @ point to vregs. 408 VREG_INDEX_TO_ADDR rREFS, r0 @ point to reference array in shadow frame 409 ldr r0, [r2, #SHADOWFRAME_DEX_PC_OFFSET] @ Get starting dex_pc. 410 add rPC, r1, r0, lsl #1 @ Create direct pointer to 1st dex opcode 411 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 412 EXPORT_PC 413 414 /* Starting ibase */ 415 ldr rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET] 416 417 /* Set up for backwards branches & osr profiling */ 418 ldr r0, [rFP, #OFF_FP_METHOD] 419 add r1, rFP, #OFF_FP_SHADOWFRAME 420 mov r2, rSELF 421 bl MterpSetUpHotnessCountdown 422 mov rPROFILE, r0 @ Starting hotness countdown to rPROFILE 423 424 /* start executing the instruction at rPC */ 425 FETCH_INST @ load rINST from rPC 426 GET_INST_OPCODE ip @ extract opcode from rINST 427 GOTO_OPCODE ip @ jump to next instruction 428 /* NOTE: no fallthrough */ 429 // cfi info continues, and covers the whole mterp implementation. 430 END ExecuteMterpImpl 431 432%def dchecks_before_helper(): 433 // Call C++ to do debug checks and return to the handler using tail call. 434 .extern MterpCheckBefore 435 mov r0, rSELF 436 add r1, rFP, #OFF_FP_SHADOWFRAME 437 mov r2, rPC 438 b MterpCheckBefore @ (self, shadow_frame, dex_pc_ptr) @ Tail call. 439 440%def opcode_pre(): 441% add_helper(dchecks_before_helper, "mterp_dchecks_before_helper") 442 #if !defined(NDEBUG) 443 bl mterp_dchecks_before_helper 444 #endif 445 446%def fallback(): 447/* Transfer stub to alternate interpreter */ 448 b MterpFallback 449 450%def helpers(): 451 ENTRY MterpHelpers 452 453%def footer(): 454/* 455 * =========================================================================== 456 * Common subroutines and data 457 * =========================================================================== 458 */ 459 460 .text 461 .align 2 462 463/* 464 * We've detected a condition that will result in an exception, but the exception 465 * has not yet been thrown. Just bail out to the reference interpreter to deal with it. 466 * TUNING: for consistency, we may want to just go ahead and handle these here. 467 */ 468common_errDivideByZero: 469 EXPORT_PC 470#if MTERP_LOGGING 471 mov r0, rSELF 472 add r1, rFP, #OFF_FP_SHADOWFRAME 473 bl MterpLogDivideByZeroException 474#endif 475 b MterpCommonFallback 476 477common_errArrayIndex: 478 EXPORT_PC 479#if MTERP_LOGGING 480 mov r0, rSELF 481 add r1, rFP, #OFF_FP_SHADOWFRAME 482 bl MterpLogArrayIndexException 483#endif 484 b MterpCommonFallback 485 486common_errNegativeArraySize: 487 EXPORT_PC 488#if MTERP_LOGGING 489 mov r0, rSELF 490 add r1, rFP, #OFF_FP_SHADOWFRAME 491 bl MterpLogNegativeArraySizeException 492#endif 493 b MterpCommonFallback 494 495common_errNoSuchMethod: 496 EXPORT_PC 497#if MTERP_LOGGING 498 mov r0, rSELF 499 add r1, rFP, #OFF_FP_SHADOWFRAME 500 bl MterpLogNoSuchMethodException 501#endif 502 b MterpCommonFallback 503 504common_errNullObject: 505 EXPORT_PC 506#if MTERP_LOGGING 507 mov r0, rSELF 508 add r1, rFP, #OFF_FP_SHADOWFRAME 509 bl MterpLogNullObjectException 510#endif 511 b MterpCommonFallback 512 513common_exceptionThrown: 514 EXPORT_PC 515#if MTERP_LOGGING 516 mov r0, rSELF 517 add r1, rFP, #OFF_FP_SHADOWFRAME 518 bl MterpLogExceptionThrownException 519#endif 520 b MterpCommonFallback 521 522MterpSuspendFallback: 523 EXPORT_PC 524#if MTERP_LOGGING 525 mov r0, rSELF 526 add r1, rFP, #OFF_FP_SHADOWFRAME 527 ldr r2, [rSELF, #THREAD_FLAGS_OFFSET] 528 bl MterpLogSuspendFallback 529#endif 530 b MterpCommonFallback 531 532/* 533 * If we're here, something is out of the ordinary. If there is a pending 534 * exception, handle it. Otherwise, roll back and retry with the reference 535 * interpreter. 536 */ 537MterpPossibleException: 538 ldr r0, [rSELF, #THREAD_EXCEPTION_OFFSET] 539 cmp r0, #0 @ Exception pending? 540 beq MterpFallback @ If not, fall back to reference interpreter. 541 /* intentional fallthrough - handle pending exception. */ 542/* 543 * On return from a runtime helper routine, we've found a pending exception. 544 * Can we handle it here - or need to bail out to caller? 545 * 546 */ 547MterpException: 548 mov r0, rSELF 549 add r1, rFP, #OFF_FP_SHADOWFRAME 550 bl MterpHandleException @ (self, shadow_frame) 551 cmp r0, #0 552 beq MterpExceptionReturn @ no local catch, back to caller. 553 ldr r0, [rFP, #OFF_FP_DEX_INSTRUCTIONS] 554 ldr r1, [rFP, #OFF_FP_DEX_PC] 555 ldr rIBASE, [rSELF, #THREAD_CURRENT_IBASE_OFFSET] 556 add rPC, r0, r1, lsl #1 @ generate new dex_pc_ptr 557 /* Do we need to switch interpreters? */ 558 ldr r0, [rSELF, #THREAD_USE_MTERP_OFFSET] 559 cmp r0, #0 560 beq MterpFallback 561 /* resume execution at catch block */ 562 EXPORT_PC 563 FETCH_INST 564 GET_INST_OPCODE ip 565 GOTO_OPCODE ip 566 /* NOTE: no fallthrough */ 567 568/* 569 * Common handling for branches with support for Jit profiling. 570 * On entry: 571 * rINST <= signed offset 572 * rPROFILE <= signed hotness countdown (expanded to 32 bits) 573 * condition bits <= set to establish sign of offset (use "NoFlags" entry if not) 574 * 575 * We have quite a few different cases for branch profiling, OSR detection and 576 * suspend check support here. 577 * 578 * Taken backward branches: 579 * If profiling active, do hotness countdown and report if we hit zero. 580 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 581 * Is there a pending suspend request? If so, suspend. 582 * 583 * Taken forward branches and not-taken backward branches: 584 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 585 * 586 * Our most common case is expected to be a taken backward branch with active jit profiling, 587 * but no full OSR check and no pending suspend request. 588 * Next most common case is not-taken branch with no full OSR check. 589 * 590 */ 591MterpCommonTakenBranchNoFlags: 592 cmp rINST, #0 593MterpCommonTakenBranch: 594 bgt .L_forward_branch @ don't add forward branches to hotness 595/* 596 * We need to subtract 1 from positive values and we should not see 0 here, 597 * so we may use the result of the comparison with -1. 598 */ 599#if JIT_CHECK_OSR != -1 600# error "JIT_CHECK_OSR must be -1." 601#endif 602 cmp rPROFILE, #JIT_CHECK_OSR 603 beq .L_osr_check 604 subsgt rPROFILE, #1 605 beq .L_add_batch @ counted down to zero - report 606.L_resume_backward_branch: 607 ldr lr, [rSELF, #THREAD_FLAGS_OFFSET] 608 REFRESH_IBASE 609 add r2, rINST, rINST @ r2<- byte offset 610 FETCH_ADVANCE_INST_RB r2 @ update rPC, load rINST 611 ands lr, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 612 bne .L_suspend_request_pending 613 GET_INST_OPCODE ip @ extract opcode from rINST 614 GOTO_OPCODE ip @ jump to next instruction 615 616.L_suspend_request_pending: 617 EXPORT_PC 618 mov r0, rSELF 619 bl MterpSuspendCheck @ (self) 620 cmp r0, #0 621 bne MterpFallback 622 REFRESH_IBASE @ might have changed during suspend 623 GET_INST_OPCODE ip @ extract opcode from rINST 624 GOTO_OPCODE ip @ jump to next instruction 625 626.L_no_count_backwards: 627 cmp rPROFILE, #JIT_CHECK_OSR @ possible OSR re-entry? 628 bne .L_resume_backward_branch 629.L_osr_check: 630 mov r0, rSELF 631 add r1, rFP, #OFF_FP_SHADOWFRAME 632 mov r2, rINST 633 EXPORT_PC 634 bl MterpMaybeDoOnStackReplacement @ (self, shadow_frame, offset) 635 cmp r0, #0 636 bne MterpOnStackReplacement 637 b .L_resume_backward_branch 638 639.L_forward_branch: 640 cmp rPROFILE, #JIT_CHECK_OSR @ possible OSR re-entry? 641 beq .L_check_osr_forward 642.L_resume_forward_branch: 643 add r2, rINST, rINST @ r2<- byte offset 644 FETCH_ADVANCE_INST_RB r2 @ update rPC, load rINST 645 GET_INST_OPCODE ip @ extract opcode from rINST 646 GOTO_OPCODE ip @ jump to next instruction 647 648.L_check_osr_forward: 649 mov r0, rSELF 650 add r1, rFP, #OFF_FP_SHADOWFRAME 651 mov r2, rINST 652 EXPORT_PC 653 bl MterpMaybeDoOnStackReplacement @ (self, shadow_frame, offset) 654 cmp r0, #0 655 bne MterpOnStackReplacement 656 b .L_resume_forward_branch 657 658.L_add_batch: 659 add r1, rFP, #OFF_FP_SHADOWFRAME 660 strh rPROFILE, [r1, #SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET] 661 ldr r0, [rFP, #OFF_FP_METHOD] 662 mov r2, rSELF 663 bl MterpAddHotnessBatch @ (method, shadow_frame, self) 664 mov rPROFILE, r0 @ restore new hotness countdown to rPROFILE 665 b .L_no_count_backwards 666 667/* 668 * Entered from the conditional branch handlers when OSR check request active on 669 * not-taken path. All Dalvik not-taken conditional branch offsets are 2. 670 */ 671.L_check_not_taken_osr: 672 mov r0, rSELF 673 add r1, rFP, #OFF_FP_SHADOWFRAME 674 mov r2, #2 675 EXPORT_PC 676 bl MterpMaybeDoOnStackReplacement @ (self, shadow_frame, offset) 677 cmp r0, #0 678 bne MterpOnStackReplacement 679 FETCH_ADVANCE_INST 2 680 GET_INST_OPCODE ip @ extract opcode from rINST 681 GOTO_OPCODE ip @ jump to next instruction 682 683/* 684 * On-stack replacement has happened, and now we've returned from the compiled method. 685 */ 686MterpOnStackReplacement: 687#if MTERP_LOGGING 688 mov r0, rSELF 689 add r1, rFP, #OFF_FP_SHADOWFRAME 690 mov r2, rINST 691 bl MterpLogOSR 692#endif 693 mov r0, #1 @ Signal normal return 694 b MterpDone 695 696/* 697 * Bail out to reference interpreter. 698 */ 699MterpFallback: 700 EXPORT_PC 701#if MTERP_LOGGING 702 mov r0, rSELF 703 add r1, rFP, #OFF_FP_SHADOWFRAME 704 bl MterpLogFallback 705#endif 706MterpCommonFallback: 707 mov r0, #0 @ signal retry with reference interpreter. 708 b MterpDone 709 710/* 711 * We pushed some registers on the stack in ExecuteMterpImpl, then saved 712 * SP and LR. Here we restore SP, restore the registers, and then restore 713 * LR to PC. 714 * 715 * On entry: 716 * uint32_t* rFP (should still be live, pointer to base of vregs) 717 */ 718MterpExceptionReturn: 719 mov r0, #1 @ signal return to caller. 720 b MterpDone 721MterpReturn: 722 ldr r2, [rFP, #OFF_FP_RESULT_REGISTER] 723 str r0, [r2] 724 str r1, [r2, #4] 725 mov r0, #1 @ signal return to caller. 726MterpDone: 727/* 728 * At this point, we expect rPROFILE to be non-zero. If negative, hotness is disabled or we're 729 * checking for OSR. If greater than zero, we might have unreported hotness to register 730 * (the difference between the ending rPROFILE and the cached hotness counter). rPROFILE 731 * should only reach zero immediately after a hotness decrement, and is then reset to either 732 * a negative special state or the new non-zero countdown value. 733 */ 734 cmp rPROFILE, #0 735 bgt MterpProfileActive @ if > 0, we may have some counts to report. 736 ldmfd sp!, {r3-r10,fp,pc} @ restore 10 regs and return 737 738MterpProfileActive: 739 mov rINST, r0 @ stash return value 740 /* Report cached hotness counts */ 741 ldr r0, [rFP, #OFF_FP_METHOD] 742 add r1, rFP, #OFF_FP_SHADOWFRAME 743 mov r2, rSELF 744 strh rPROFILE, [r1, #SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET] 745 bl MterpAddHotnessBatch @ (method, shadow_frame, self) 746 mov r0, rINST @ restore return value 747 ldmfd sp!, {r3-r10,fp,pc} @ restore 10 regs and return 748 749 .cfi_endproc 750 END MterpHelpers 751 752%def instruction_end(): 753 754 .type artMterpAsmInstructionEnd, #object 755 .hidden artMterpAsmInstructionEnd 756 .global artMterpAsmInstructionEnd 757artMterpAsmInstructionEnd: 758 759%def instruction_start(): 760 761 .type artMterpAsmInstructionStart, #object 762 .hidden artMterpAsmInstructionStart 763 .global artMterpAsmInstructionStart 764artMterpAsmInstructionStart = .L_op_nop 765 .text 766 767%def default_helper_prefix(): 768% return "mterp_" 769 770%def opcode_start(): 771 ENTRY mterp_${opcode} 772%def opcode_end(): 773 END mterp_${opcode} 774%def helper_start(name): 775 ENTRY ${name} 776%def helper_end(name): 777 END ${name} 778