1/*
2 * We've detected a condition that will result in an exception, but the exception
3 * has not yet been thrown.  Just bail out to the reference interpreter to deal with it.
4 * TUNING: for consistency, we may want to just go ahead and handle these here.
5 */
6
7    .extern MterpLogDivideByZeroException
8common_errDivideByZero:
9    EXPORT_PC
10#if MTERP_LOGGING
11    move    a0, rSELF
12    daddu   a1, rFP, OFF_FP_SHADOWFRAME
13    jal     MterpLogDivideByZeroException
14#endif
15    b       MterpCommonFallback
16
17    .extern MterpLogArrayIndexException
18common_errArrayIndex:
19    EXPORT_PC
20#if MTERP_LOGGING
21    move    a0, rSELF
22    daddu   a1, rFP, OFF_FP_SHADOWFRAME
23    jal     MterpLogArrayIndexException
24#endif
25    b       MterpCommonFallback
26
27    .extern MterpLogNullObjectException
28common_errNullObject:
29    EXPORT_PC
30#if MTERP_LOGGING
31    move    a0, rSELF
32    daddu   a1, rFP, OFF_FP_SHADOWFRAME
33    jal     MterpLogNullObjectException
34#endif
35    b       MterpCommonFallback
36
37/*
38 * If we're here, something is out of the ordinary.  If there is a pending
39 * exception, handle it.  Otherwise, roll back and retry with the reference
40 * interpreter.
41 */
42MterpPossibleException:
43    ld      a0, THREAD_EXCEPTION_OFFSET(rSELF)
44    beqzc   a0, MterpFallback                       # If not, fall back to reference interpreter.
45    /* intentional fallthrough - handle pending exception. */
46/*
47 * On return from a runtime helper routine, we've found a pending exception.
48 * Can we handle it here - or need to bail out to caller?
49 *
50 */
51    .extern MterpHandleException
52    .extern MterpShouldSwitchInterpreters
53MterpException:
54    move    a0, rSELF
55    daddu   a1, rFP, OFF_FP_SHADOWFRAME
56    jal     MterpHandleException                    # (self, shadow_frame)
57    beqzc   v0, MterpExceptionReturn                # no local catch, back to caller.
58    ld      a0, OFF_FP_CODE_ITEM(rFP)
59    lwu     a1, OFF_FP_DEX_PC(rFP)
60    REFRESH_IBASE
61    daddu   rPC, a0, CODEITEM_INSNS_OFFSET
62    dlsa    rPC, a1, rPC, 1                         # generate new dex_pc_ptr
63    /* Do we need to switch interpreters? */
64    jal     MterpShouldSwitchInterpreters
65    bnezc   v0, MterpFallback
66    /* resume execution at catch block */
67    EXPORT_PC
68    FETCH_INST
69    GET_INST_OPCODE v0
70    GOTO_OPCODE v0
71    /* NOTE: no fallthrough */
72
73/*
74 * Check for suspend check request.  Assumes rINST already loaded, rPC advanced and
75 * still needs to get the opcode and branch to it, and flags are in ra.
76 */
77    .extern MterpSuspendCheck
78MterpCheckSuspendAndContinue:
79    REFRESH_IBASE
80    and     ra, ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
81    bnez    ra, check1
82    GET_INST_OPCODE v0                              # extract opcode from rINST
83    GOTO_OPCODE v0                                  # jump to next instruction
84check1:
85    EXPORT_PC
86    move    a0, rSELF
87    jal     MterpSuspendCheck                       # (self)
88    bnezc   v0, MterpFallback                       # Something in the environment changed, switch interpreters
89    GET_INST_OPCODE v0                              # extract opcode from rINST
90    GOTO_OPCODE v0                                  # jump to next instruction
91
92/*
93 * On-stack replacement has happened, and now we've returned from the compiled method.
94 */
95MterpOnStackReplacement:
96#if MTERP_LOGGING
97    move    a0, rSELF
98    daddu   a1, rFP, OFF_FP_SHADOWFRAME
99    move    a2, rINST                               # rINST contains offset
100    jal     MterpLogOSR
101#endif
102    li      v0, 1                                   # Signal normal return
103    b       MterpDone
104
105/*
106 * Bail out to reference interpreter.
107 */
108    .extern MterpLogFallback
109MterpFallback:
110    EXPORT_PC
111#if MTERP_LOGGING
112    move    a0, rSELF
113    daddu   a1, rFP, OFF_FP_SHADOWFRAME
114    jal     MterpLogFallback
115#endif
116MterpCommonFallback:
117    li      v0, 0                                   # signal retry with reference interpreter.
118    b       MterpDone
119
120/*
121 * We pushed some registers on the stack in ExecuteMterpImpl, then saved
122 * SP and RA.  Here we restore SP, restore the registers, and then restore
123 * RA to PC.
124 *
125 * On entry:
126 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
127 */
128MterpExceptionReturn:
129    li      v0, 1                                   # signal return to caller.
130    b       MterpDone
131/*
132 * Returned value is expected in a0 and if it's not 64-bit, the 32 most
133 * significant bits of a0 must be 0.
134 */
135MterpReturn:
136    ld      a2, OFF_FP_RESULT_REGISTER(rFP)
137    sd      a0, 0(a2)
138    li      v0, 1                                   # signal return to caller.
139MterpDone:
140    ld      s5, STACK_OFFSET_S5(sp)
141    .cfi_restore 21
142    ld      s4, STACK_OFFSET_S4(sp)
143    .cfi_restore 20
144    ld      s3, STACK_OFFSET_S3(sp)
145    .cfi_restore 19
146    ld      s2, STACK_OFFSET_S2(sp)
147    .cfi_restore 18
148    ld      s1, STACK_OFFSET_S1(sp)
149    .cfi_restore 17
150    ld      s0, STACK_OFFSET_S0(sp)
151    .cfi_restore 16
152
153    ld      ra, STACK_OFFSET_RA(sp)
154    .cfi_restore 31
155
156    ld      t8, STACK_OFFSET_GP(sp)
157    .cpreturn
158    .cfi_restore 28
159
160    .set    noreorder
161    jr      ra
162    daddu   sp, sp, STACK_SIZE
163    .cfi_adjust_cfa_offset -STACK_SIZE
164
165    .cfi_endproc
166    .size ExecuteMterpImpl, .-ExecuteMterpImpl
167