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 #define zero $$0 /* always zero */ 19 #define AT $$at /* assembler temp */ 20 #define v0 $$2 /* return value */ 21 #define v1 $$3 22 #define a0 $$4 /* argument registers */ 23 #define a1 $$5 24 #define a2 $$6 25 #define a3 $$7 26 #define a4 $$8 /* expanded register arguments */ 27 #define a5 $$9 28 #define a6 $$10 29 #define a7 $$11 30 #define ta0 $$8 /* alias */ 31 #define ta1 $$9 32 #define ta2 $$10 33 #define ta3 $$11 34 #define t0 $$12 /* temp registers (not saved across subroutine calls) */ 35 #define t1 $$13 36 #define t2 $$14 37 #define t3 $$15 38 39 #define s0 $$16 /* saved across subroutine calls (callee saved) */ 40 #define s1 $$17 41 #define s2 $$18 42 #define s3 $$19 43 #define s4 $$20 44 #define s5 $$21 45 #define s6 $$22 46 #define s7 $$23 47 #define t8 $$24 /* two more temp registers */ 48 #define t9 $$25 49 #define k0 $$26 /* kernel temporary */ 50 #define k1 $$27 51 #define gp $$28 /* global pointer */ 52 #define sp $$29 /* stack pointer */ 53 #define s8 $$30 /* one more callee saved */ 54 #define ra $$31 /* return address */ 55 56 #define f0 $$f0 57 #define f1 $$f1 58 #define f2 $$f2 59 #define f3 $$f3 60 #define f12 $$f12 61 #define f13 $$f13 62 63 /* 64 * It looks like the GNU assembler currently does not support the blec and bgtc 65 * idioms, which should translate into bgec and bltc respectively with swapped 66 * left and right register operands. 67 * TODO: remove these macros when the assembler is fixed. 68 */ 69 .macro blec lreg, rreg, target 70 bgec \rreg, \lreg, \target 71 .endm 72 .macro bgtc lreg, rreg, target 73 bltc \rreg, \lreg, \target 74 .endm 75 76 /* 77 Mterp and MIPS64 notes: 78 79 The following registers have fixed assignments: 80 81 reg nick purpose 82 s0 rPC interpreted program counter, used for fetching instructions 83 s1 rFP interpreted frame pointer, used for accessing locals and args 84 s2 rSELF self (Thread) pointer 85 s3 rINST first 16-bit code unit of current instruction 86 s4 rIBASE interpreted instruction base pointer, used for computed goto 87 s5 rREFS base of object references in shadow frame (ideally, we'll get rid of this later). 88 s6 rPROFILE jit profile hotness countdown 89 */ 90 91 /* During bringup, we'll use the shadow frame model instead of rFP */ 92 /* single-purpose registers, given names for clarity */ 93 #define rPC s0 94 #define CFI_DEX 16 // DWARF register number of the register holding dex-pc (s0). 95 #define CFI_TMP 4 // DWARF register number of the first argument register (a0). 96 #define rFP s1 97 #define rSELF s2 98 #define rINST s3 99 #define rIBASE s4 100 #define rREFS s5 101 #define rPROFILE s6 102 103 /* 104 * This is a #include, not a %include, because we want the C pre-processor 105 * to expand the macros into assembler assignment statements. 106 */ 107 #include "asm_support.h" 108 #include "interpreter/cfi_asm_support.h" 109 110 /* 111 * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs. So, 112 * to access other shadow frame fields, we need to use a backwards offset. Define those here. 113 */ 114 #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET) 115 #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET) 116 #define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET) 117 #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET) 118 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET) 119 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET) 120 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET) 121 #define OFF_FP_DEX_INSTRUCTIONS OFF_FP(SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET) 122 #define OFF_FP_SHADOWFRAME OFF_FP(0) 123 124 #define MTERP_PROFILE_BRANCHES 1 125 #define MTERP_LOGGING 0 126 127 /* 128 * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects. Must 129 * be done *before* something throws. 130 * 131 * It's okay to do this more than once. 132 * 133 * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped 134 * dex byte codes. However, the rest of the runtime expects dex pc to be an instruction 135 * offset into the code_items_[] array. For effiency, we will "export" the 136 * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC 137 * to convert to a dex pc when needed. 138 */ 139 .macro EXPORT_PC 140 sd rPC, OFF_FP_DEX_PC_PTR(rFP) 141 .endm 142 143 /* 144 * Refresh handler table. 145 */ 146 .macro REFRESH_IBASE 147 ld rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF) 148 .endm 149 150 /* 151 * Fetch the next instruction from rPC into rINST. Does not advance rPC. 152 */ 153 .macro FETCH_INST 154 lhu rINST, 0(rPC) 155 .endm 156 157 /* Advance rPC by some number of code units. */ 158 .macro ADVANCE count 159 daddu rPC, rPC, (\count) * 2 160 .endm 161 162 /* 163 * Fetch the next instruction from an offset specified by _reg and advance xPC. 164 * xPC to point to the next instruction. "_reg" must specify the distance 165 * in bytes, *not* 16-bit code units, and may be a signed value. Must not set flags. 166 * 167 */ 168 .macro FETCH_ADVANCE_INST_RB reg 169 daddu rPC, rPC, \reg 170 FETCH_INST 171 .endm 172 173 /* 174 * Fetch the next instruction from the specified offset. Advances rPC 175 * to point to the next instruction. 176 * 177 * This must come AFTER anything that can throw an exception, or the 178 * exception catch may miss. (This also implies that it must come after 179 * EXPORT_PC.) 180 */ 181 .macro FETCH_ADVANCE_INST count 182 ADVANCE \count 183 FETCH_INST 184 .endm 185 186 /* 187 * Similar to FETCH_ADVANCE_INST, but does not update rPC. Used to load 188 * rINST ahead of possible exception point. Be sure to manually advance rPC 189 * later. 190 */ 191 .macro PREFETCH_INST count 192 lhu rINST, ((\count) * 2)(rPC) 193 .endm 194 195 /* 196 * Put the instruction's opcode field into the specified register. 197 */ 198 .macro GET_INST_OPCODE reg 199 and \reg, rINST, 255 200 .endm 201 202 /* 203 * Begin executing the opcode in _reg. 204 */ 205 .macro GOTO_OPCODE reg 206 .set noat 207 sll AT, \reg, 7 208 daddu AT, rIBASE, AT 209 jic AT, 0 210 .set at 211 .endm 212 213 /* 214 * Get/set the 32-bit value from a Dalvik register. 215 * Note, GET_VREG does sign extension to 64 bits while 216 * GET_VREG_U does zero extension to 64 bits. 217 * One is useful for arithmetic while the other is 218 * useful for storing the result value as 64-bit. 219 */ 220 .macro GET_VREG reg, vreg 221 .set noat 222 dlsa AT, \vreg, rFP, 2 223 lw \reg, 0(AT) 224 .set at 225 .endm 226 .macro GET_VREG_U reg, vreg 227 .set noat 228 dlsa AT, \vreg, rFP, 2 229 lwu \reg, 0(AT) 230 .set at 231 .endm 232 .macro GET_VREG_FLOAT reg, vreg 233 .set noat 234 dlsa AT, \vreg, rFP, 2 235 lwc1 \reg, 0(AT) 236 .set at 237 .endm 238 .macro SET_VREG reg, vreg 239 .set noat 240 dlsa AT, \vreg, rFP, 2 241 sw \reg, 0(AT) 242 dlsa AT, \vreg, rREFS, 2 243 sw zero, 0(AT) 244 .set at 245 .endm 246 .macro SET_VREG_OBJECT reg, vreg 247 .set noat 248 dlsa AT, \vreg, rFP, 2 249 sw \reg, 0(AT) 250 dlsa AT, \vreg, rREFS, 2 251 sw \reg, 0(AT) 252 .set at 253 .endm 254 .macro SET_VREG_FLOAT reg, vreg 255 .set noat 256 dlsa AT, \vreg, rFP, 2 257 swc1 \reg, 0(AT) 258 dlsa AT, \vreg, rREFS, 2 259 sw zero, 0(AT) 260 .set at 261 .endm 262 263 /* 264 * Get/set the 64-bit value from a Dalvik register. 265 * Avoid unaligned memory accesses. 266 * Note, SET_VREG_WIDE clobbers the register containing the value being stored. 267 * Note, SET_VREG_DOUBLE clobbers the register containing the Dalvik register number. 268 */ 269 .macro GET_VREG_WIDE reg, vreg 270 .set noat 271 dlsa AT, \vreg, rFP, 2 272 lw \reg, 0(AT) 273 lw AT, 4(AT) 274 dinsu \reg, AT, 32, 32 275 .set at 276 .endm 277 .macro GET_VREG_DOUBLE reg, vreg 278 .set noat 279 dlsa AT, \vreg, rFP, 2 280 lwc1 \reg, 0(AT) 281 lw AT, 4(AT) 282 mthc1 AT, \reg 283 .set at 284 .endm 285 .macro SET_VREG_WIDE reg, vreg 286 .set noat 287 dlsa AT, \vreg, rFP, 2 288 sw \reg, 0(AT) 289 drotr32 \reg, \reg, 0 290 sw \reg, 4(AT) 291 dlsa AT, \vreg, rREFS, 2 292 sw zero, 0(AT) 293 sw zero, 4(AT) 294 .set at 295 .endm 296 .macro SET_VREG_DOUBLE reg, vreg 297 .set noat 298 dlsa AT, \vreg, rREFS, 2 299 sw zero, 0(AT) 300 sw zero, 4(AT) 301 dlsa AT, \vreg, rFP, 2 302 swc1 \reg, 0(AT) 303 mfhc1 \vreg, \reg 304 sw \vreg, 4(AT) 305 .set at 306 .endm 307 308 /* 309 * On-stack offsets for spilling/unspilling callee-saved registers 310 * and the frame size. 311 */ 312 #define STACK_OFFSET_RA 0 313 #define STACK_OFFSET_GP 8 314 #define STACK_OFFSET_S0 16 315 #define STACK_OFFSET_S1 24 316 #define STACK_OFFSET_S2 32 317 #define STACK_OFFSET_S3 40 318 #define STACK_OFFSET_S4 48 319 #define STACK_OFFSET_S5 56 320 #define STACK_OFFSET_S6 64 321 #define STACK_SIZE 80 /* needs 16 byte alignment */ 322 323 /* Constants for float/double_to_int/long conversions */ 324 #define INT_MIN 0x80000000 325 #define INT_MIN_AS_FLOAT 0xCF000000 326 #define INT_MIN_AS_DOUBLE 0xC1E0000000000000 327 #define LONG_MIN 0x8000000000000000 328 #define LONG_MIN_AS_FLOAT 0xDF000000 329 #define LONG_MIN_AS_DOUBLE 0xC3E0000000000000 330 331 %def entry(): 332 /* 333 * Copyright (C) 2016 The Android Open Source Project 334 * 335 * Licensed under the Apache License, Version 2.0 (the "License"); 336 * you may not use this file except in compliance with the License. 337 * You may obtain a copy of the License at 338 * 339 * http://www.apache.org/licenses/LICENSE-2.0 340 * 341 * Unless required by applicable law or agreed to in writing, software 342 * distributed under the License is distributed on an "AS IS" BASIS, 343 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 344 * See the License for the specific language governing permissions and 345 * limitations under the License. 346 */ 347 348 /* 349 * Interpreter entry point. 350 */ 351 352 .set reorder 353 354 .text 355 .global ExecuteMterpImpl 356 .type ExecuteMterpImpl, %function 357 .balign 16 358 /* 359 * On entry: 360 * a0 Thread* self 361 * a1 dex_instructions 362 * a2 ShadowFrame 363 * a3 JValue* result_register 364 * 365 */ 366 ExecuteMterpImpl: 367 .cfi_startproc 368 .cpsetup t9, t8, ExecuteMterpImpl 369 370 .cfi_def_cfa sp, 0 371 daddu sp, sp, -STACK_SIZE 372 .cfi_adjust_cfa_offset STACK_SIZE 373 374 sd t8, STACK_OFFSET_GP(sp) 375 .cfi_rel_offset 28, STACK_OFFSET_GP 376 sd ra, STACK_OFFSET_RA(sp) 377 .cfi_rel_offset 31, STACK_OFFSET_RA 378 379 sd s0, STACK_OFFSET_S0(sp) 380 .cfi_rel_offset 16, STACK_OFFSET_S0 381 sd s1, STACK_OFFSET_S1(sp) 382 .cfi_rel_offset 17, STACK_OFFSET_S1 383 sd s2, STACK_OFFSET_S2(sp) 384 .cfi_rel_offset 18, STACK_OFFSET_S2 385 sd s3, STACK_OFFSET_S3(sp) 386 .cfi_rel_offset 19, STACK_OFFSET_S3 387 sd s4, STACK_OFFSET_S4(sp) 388 .cfi_rel_offset 20, STACK_OFFSET_S4 389 sd s5, STACK_OFFSET_S5(sp) 390 .cfi_rel_offset 21, STACK_OFFSET_S5 391 sd s6, STACK_OFFSET_S6(sp) 392 .cfi_rel_offset 22, STACK_OFFSET_S6 393 394 /* Remember the return register */ 395 sd a3, SHADOWFRAME_RESULT_REGISTER_OFFSET(a2) 396 397 /* Remember the dex instruction pointer */ 398 sd a1, SHADOWFRAME_DEX_INSTRUCTIONS_OFFSET(a2) 399 400 /* set up "named" registers */ 401 move rSELF, a0 402 daddu rFP, a2, SHADOWFRAME_VREGS_OFFSET 403 lw v0, SHADOWFRAME_NUMBER_OF_VREGS_OFFSET(a2) 404 dlsa rREFS, v0, rFP, 2 405 lw v0, SHADOWFRAME_DEX_PC_OFFSET(a2) 406 dlsa rPC, v0, a1, 1 407 CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0) 408 EXPORT_PC 409 410 /* Starting ibase */ 411 REFRESH_IBASE 412 413 /* Set up for backwards branches & osr profiling */ 414 ld a0, OFF_FP_METHOD(rFP) 415 daddu a1, rFP, OFF_FP_SHADOWFRAME 416 move a2, rSELF 417 jal MterpSetUpHotnessCountdown 418 move rPROFILE, v0 # Starting hotness countdown to rPROFILE 419 420 /* start executing the instruction at rPC */ 421 FETCH_INST 422 GET_INST_OPCODE v0 423 GOTO_OPCODE v0 424 425 /* NOTE: no fallthrough */ 426 427 %def dchecks_before_helper(): 428 // Call C++ to do debug checks and return to the handler using tail call. 429 .extern MterpCheckBefore 430 dla t9, MterpCheckBefore 431 move a0, rSELF 432 daddu a1, rFP, OFF_FP_SHADOWFRAME 433 move a2, rPC 434 jalr zero, t9 # (self, shadow_frame, dex_pc_ptr) Note: tail call. 435 436 %def opcode_pre(): 437 % add_helper(dchecks_before_helper, "mterp_dchecks_before_helper") 438 #if !defined(NDEBUG) 439 jal SYMBOL(mterp_dchecks_before_helper) 440 #endif 441 442 %def fallback(): 443 /* Transfer stub to alternate interpreter */ 444 b MterpFallback 445 446 %def helpers(): 447 % pass 448 449 %def footer(): 450 /* 451 * We've detected a condition that will result in an exception, but the exception 452 * has not yet been thrown. Just bail out to the reference interpreter to deal with it. 453 * TUNING: for consistency, we may want to just go ahead and handle these here. 454 */ 455 456 .extern MterpLogDivideByZeroException 457 common_errDivideByZero: 458 EXPORT_PC 459 #if MTERP_LOGGING 460 move a0, rSELF 461 daddu a1, rFP, OFF_FP_SHADOWFRAME 462 jal MterpLogDivideByZeroException 463 #endif 464 b MterpCommonFallback 465 466 .extern MterpLogArrayIndexException 467 common_errArrayIndex: 468 EXPORT_PC 469 #if MTERP_LOGGING 470 move a0, rSELF 471 daddu a1, rFP, OFF_FP_SHADOWFRAME 472 jal MterpLogArrayIndexException 473 #endif 474 b MterpCommonFallback 475 476 .extern MterpLogNullObjectException 477 common_errNullObject: 478 EXPORT_PC 479 #if MTERP_LOGGING 480 move a0, rSELF 481 daddu a1, rFP, OFF_FP_SHADOWFRAME 482 jal MterpLogNullObjectException 483 #endif 484 b MterpCommonFallback 485 486 /* 487 * If we're here, something is out of the ordinary. If there is a pending 488 * exception, handle it. Otherwise, roll back and retry with the reference 489 * interpreter. 490 */ 491 MterpPossibleException: 492 ld a0, THREAD_EXCEPTION_OFFSET(rSELF) 493 beqzc a0, MterpFallback # If not, fall back to reference interpreter. 494 /* intentional fallthrough - handle pending exception. */ 495 /* 496 * On return from a runtime helper routine, we've found a pending exception. 497 * Can we handle it here - or need to bail out to caller? 498 * 499 */ 500 .extern MterpHandleException 501 .extern MterpShouldSwitchInterpreters 502 MterpException: 503 move a0, rSELF 504 daddu a1, rFP, OFF_FP_SHADOWFRAME 505 jal MterpHandleException # (self, shadow_frame) 506 beqzc v0, MterpExceptionReturn # no local catch, back to caller. 507 ld a0, OFF_FP_DEX_INSTRUCTIONS(rFP) 508 lwu a1, OFF_FP_DEX_PC(rFP) 509 REFRESH_IBASE 510 dlsa rPC, a1, a0, 1 # generate new dex_pc_ptr 511 /* Do we need to switch interpreters? */ 512 jal MterpShouldSwitchInterpreters 513 bnezc v0, MterpFallback 514 /* resume execution at catch block */ 515 EXPORT_PC 516 FETCH_INST 517 GET_INST_OPCODE v0 518 GOTO_OPCODE v0 519 /* NOTE: no fallthrough */ 520 521 /* 522 * Common handling for branches with support for Jit profiling. 523 * On entry: 524 * rINST <= signed offset 525 * rPROFILE <= signed hotness countdown (expanded to 64 bits) 526 * 527 * We have quite a few different cases for branch profiling, OSR detection and 528 * suspend check support here. 529 * 530 * Taken backward branches: 531 * If profiling active, do hotness countdown and report if we hit zero. 532 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 533 * Is there a pending suspend request? If so, suspend. 534 * 535 * Taken forward branches and not-taken backward branches: 536 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 537 * 538 * Our most common case is expected to be a taken backward branch with active jit profiling, 539 * but no full OSR check and no pending suspend request. 540 * Next most common case is not-taken branch with no full OSR check. 541 * 542 */ 543 MterpCommonTakenBranchNoFlags: 544 bgtzc rINST, .L_forward_branch # don't add forward branches to hotness 545 /* 546 * We need to subtract 1 from positive values and we should not see 0 here, 547 * so we may use the result of the comparison with -1. 548 */ 549 li v0, JIT_CHECK_OSR 550 beqc rPROFILE, v0, .L_osr_check 551 bltc rPROFILE, v0, .L_resume_backward_branch 552 dsubu rPROFILE, 1 553 beqzc rPROFILE, .L_add_batch # counted down to zero - report 554 .L_resume_backward_branch: 555 lw ra, THREAD_FLAGS_OFFSET(rSELF) 556 REFRESH_IBASE 557 daddu a2, rINST, rINST # a2<- byte offset 558 FETCH_ADVANCE_INST_RB a2 # update rPC, load rINST 559 and ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 560 bnezc ra, .L_suspend_request_pending 561 GET_INST_OPCODE v0 # extract opcode from rINST 562 GOTO_OPCODE v0 # jump to next instruction 563 564 .L_suspend_request_pending: 565 EXPORT_PC 566 move a0, rSELF 567 jal MterpSuspendCheck # (self) 568 bnezc v0, MterpFallback 569 REFRESH_IBASE # might have changed during suspend 570 GET_INST_OPCODE v0 # extract opcode from rINST 571 GOTO_OPCODE v0 # jump to next instruction 572 573 .L_no_count_backwards: 574 li v0, JIT_CHECK_OSR # check for possible OSR re-entry 575 bnec rPROFILE, v0, .L_resume_backward_branch 576 .L_osr_check: 577 move a0, rSELF 578 daddu a1, rFP, OFF_FP_SHADOWFRAME 579 move a2, rINST 580 EXPORT_PC 581 jal MterpMaybeDoOnStackReplacement # (self, shadow_frame, offset) 582 bnezc v0, MterpOnStackReplacement 583 b .L_resume_backward_branch 584 585 .L_forward_branch: 586 li v0, JIT_CHECK_OSR # check for possible OSR re-entry 587 beqc rPROFILE, v0, .L_check_osr_forward 588 .L_resume_forward_branch: 589 daddu a2, rINST, rINST # a2<- byte offset 590 FETCH_ADVANCE_INST_RB a2 # update rPC, load rINST 591 GET_INST_OPCODE v0 # extract opcode from rINST 592 GOTO_OPCODE v0 # jump to next instruction 593 594 .L_check_osr_forward: 595 move a0, rSELF 596 daddu a1, rFP, OFF_FP_SHADOWFRAME 597 move a2, rINST 598 EXPORT_PC 599 jal MterpMaybeDoOnStackReplacement # (self, shadow_frame, offset) 600 bnezc v0, MterpOnStackReplacement 601 b .L_resume_forward_branch 602 603 .L_add_batch: 604 daddu a1, rFP, OFF_FP_SHADOWFRAME 605 sh rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1) 606 ld a0, OFF_FP_METHOD(rFP) 607 move a2, rSELF 608 jal MterpAddHotnessBatch # (method, shadow_frame, self) 609 move rPROFILE, v0 # restore new hotness countdown to rPROFILE 610 b .L_no_count_backwards 611 612 /* 613 * Entered from the conditional branch handlers when OSR check request active on 614 * not-taken path. All Dalvik not-taken conditional branch offsets are 2. 615 */ 616 .L_check_not_taken_osr: 617 move a0, rSELF 618 daddu a1, rFP, OFF_FP_SHADOWFRAME 619 li a2, 2 620 EXPORT_PC 621 jal MterpMaybeDoOnStackReplacement # (self, shadow_frame, offset) 622 bnezc v0, MterpOnStackReplacement 623 FETCH_ADVANCE_INST 2 624 GET_INST_OPCODE v0 # extract opcode from rINST 625 GOTO_OPCODE v0 # jump to next instruction 626 627 /* 628 * On-stack replacement has happened, and now we've returned from the compiled method. 629 */ 630 MterpOnStackReplacement: 631 #if MTERP_LOGGING 632 move a0, rSELF 633 daddu a1, rFP, OFF_FP_SHADOWFRAME 634 move a2, rINST # rINST contains offset 635 jal MterpLogOSR 636 #endif 637 li v0, 1 # Signal normal return 638 b MterpDone 639 640 /* 641 * Bail out to reference interpreter. 642 */ 643 .extern MterpLogFallback 644 MterpFallback: 645 EXPORT_PC 646 #if MTERP_LOGGING 647 move a0, rSELF 648 daddu a1, rFP, OFF_FP_SHADOWFRAME 649 jal MterpLogFallback 650 #endif 651 MterpCommonFallback: 652 li v0, 0 # signal retry with reference interpreter. 653 b MterpDone 654 655 /* 656 * We pushed some registers on the stack in ExecuteMterpImpl, then saved 657 * SP and RA. Here we restore SP, restore the registers, and then restore 658 * RA to PC. 659 * 660 * On entry: 661 * uint32_t* rFP (should still be live, pointer to base of vregs) 662 */ 663 MterpExceptionReturn: 664 li v0, 1 # signal return to caller. 665 b MterpDone 666 /* 667 * Returned value is expected in a0 and if it's not 64-bit, the 32 most 668 * significant bits of a0 must be zero-extended or sign-extended 669 * depending on the return type. 670 */ 671 MterpReturn: 672 ld a2, OFF_FP_RESULT_REGISTER(rFP) 673 sd a0, 0(a2) 674 li v0, 1 # signal return to caller. 675 MterpDone: 676 /* 677 * At this point, we expect rPROFILE to be non-zero. If negative, hotness is disabled or we're 678 * checking for OSR. If greater than zero, we might have unreported hotness to register 679 * (the difference between the ending rPROFILE and the cached hotness counter). rPROFILE 680 * should only reach zero immediately after a hotness decrement, and is then reset to either 681 * a negative special state or the new non-zero countdown value. 682 */ 683 blez rPROFILE, .L_pop_and_return # if > 0, we may have some counts to report. 684 685 MterpProfileActive: 686 move rINST, v0 # stash return value 687 /* Report cached hotness counts */ 688 ld a0, OFF_FP_METHOD(rFP) 689 daddu a1, rFP, OFF_FP_SHADOWFRAME 690 move a2, rSELF 691 sh rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1) 692 jal MterpAddHotnessBatch # (method, shadow_frame, self) 693 move v0, rINST # restore return value 694 695 .L_pop_and_return: 696 ld s6, STACK_OFFSET_S6(sp) 697 .cfi_restore 22 698 ld s5, STACK_OFFSET_S5(sp) 699 .cfi_restore 21 700 ld s4, STACK_OFFSET_S4(sp) 701 .cfi_restore 20 702 ld s3, STACK_OFFSET_S3(sp) 703 .cfi_restore 19 704 ld s2, STACK_OFFSET_S2(sp) 705 .cfi_restore 18 706 ld s1, STACK_OFFSET_S1(sp) 707 .cfi_restore 17 708 ld s0, STACK_OFFSET_S0(sp) 709 .cfi_restore 16 710 711 ld ra, STACK_OFFSET_RA(sp) 712 .cfi_restore 31 713 714 ld t8, STACK_OFFSET_GP(sp) 715 .cpreturn 716 .cfi_restore 28 717 718 .set noreorder 719 jr ra 720 daddu sp, sp, STACK_SIZE 721 .cfi_adjust_cfa_offset -STACK_SIZE 722 723 .cfi_endproc 724 .set reorder 725 .size ExecuteMterpImpl, .-ExecuteMterpImpl 726 727 %def instruction_end(): 728 729 .global artMterpAsmInstructionEnd 730 artMterpAsmInstructionEnd: 731 732 %def instruction_start(): 733 734 .global artMterpAsmInstructionStart 735 artMterpAsmInstructionStart = .L_op_nop 736 .text 737 738 %def opcode_start(): 739 % pass 740 %def opcode_end(): 741 % pass 742 %def helper_start(name): 743 ENTRY ${name} 744 %def helper_end(name): 745 END ${name} 746