Home | History | Annotate | Download | only in mips64
      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