1/*
2 * ===========================================================================
3 *  Common subroutines and data
4 * ===========================================================================
5 */
6
7    .text
8    .align 2
9
10/*
11 * We've detected a condition that will result in an exception, but the exception
12 * has not yet been thrown.  Just bail out to the reference interpreter to deal with it.
13 * TUNING: for consistency, we may want to just go ahead and handle these here.
14 */
15common_errDivideByZero:
16    EXPORT_PC()
17#if MTERP_LOGGING
18    move  a0, rSELF
19    addu  a1, rFP, OFF_FP_SHADOWFRAME
20    JAL(MterpLogDivideByZeroException)
21#endif
22    b MterpCommonFallback
23
24common_errArrayIndex:
25    EXPORT_PC()
26#if MTERP_LOGGING
27    move  a0, rSELF
28    addu  a1, rFP, OFF_FP_SHADOWFRAME
29    JAL(MterpLogArrayIndexException)
30#endif
31    b MterpCommonFallback
32
33common_errNegativeArraySize:
34    EXPORT_PC()
35#if MTERP_LOGGING
36    move  a0, rSELF
37    addu  a1, rFP, OFF_FP_SHADOWFRAME
38    JAL(MterpLogNegativeArraySizeException)
39#endif
40    b MterpCommonFallback
41
42common_errNoSuchMethod:
43    EXPORT_PC()
44#if MTERP_LOGGING
45    move  a0, rSELF
46    addu  a1, rFP, OFF_FP_SHADOWFRAME
47    JAL(MterpLogNoSuchMethodException)
48#endif
49    b MterpCommonFallback
50
51common_errNullObject:
52    EXPORT_PC()
53#if MTERP_LOGGING
54    move  a0, rSELF
55    addu  a1, rFP, OFF_FP_SHADOWFRAME
56    JAL(MterpLogNullObjectException)
57#endif
58    b MterpCommonFallback
59
60common_exceptionThrown:
61    EXPORT_PC()
62#if MTERP_LOGGING
63    move  a0, rSELF
64    addu  a1, rFP, OFF_FP_SHADOWFRAME
65    JAL(MterpLogExceptionThrownException)
66#endif
67    b MterpCommonFallback
68
69MterpSuspendFallback:
70    EXPORT_PC()
71#if MTERP_LOGGING
72    move  a0, rSELF
73    addu  a1, rFP, OFF_FP_SHADOWFRAME
74    lw    a2, THREAD_FLAGS_OFFSET(rSELF)
75    JAL(MterpLogSuspendFallback)
76#endif
77    b MterpCommonFallback
78
79/*
80 * If we're here, something is out of the ordinary.  If there is a pending
81 * exception, handle it.  Otherwise, roll back and retry with the reference
82 * interpreter.
83 */
84MterpPossibleException:
85    lw      a0, THREAD_EXCEPTION_OFFSET(rSELF)
86    beqz    a0, MterpFallback          # If exception, fall back to reference interpreter.
87    /* intentional fallthrough - handle pending exception. */
88/*
89 * On return from a runtime helper routine, we've found a pending exception.
90 * Can we handle it here - or need to bail out to caller?
91 *
92 */
93MterpException:
94    move    a0, rSELF
95    addu    a1, rFP, OFF_FP_SHADOWFRAME
96    JAL(MterpHandleException)                    # (self, shadow_frame)
97    beqz    v0, MterpExceptionReturn             # no local catch, back to caller.
98    lw      a0, OFF_FP_CODE_ITEM(rFP)
99    lw      a1, OFF_FP_DEX_PC(rFP)
100    lw      rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
101    addu    rPC, a0, CODEITEM_INSNS_OFFSET
102    sll     a1, a1, 1
103    addu    rPC, rPC, a1                         # generate new dex_pc_ptr
104    /* Do we need to switch interpreters? */
105    JAL(MterpShouldSwitchInterpreters)
106    bnez    v0, MterpFallback
107    /* resume execution at catch block */
108    EXPORT_PC()
109    FETCH_INST()
110    GET_INST_OPCODE(t0)
111    GOTO_OPCODE(t0)
112    /* NOTE: no fallthrough */
113
114/*
115 * Check for suspend check request.  Assumes rINST already loaded, rPC advanced and
116 * still needs to get the opcode and branch to it, and flags are in lr.
117 */
118MterpCheckSuspendAndContinue:
119    lw      rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)  # refresh rIBASE
120    and     ra, (THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
121    bnez    ra, 1f
122    GET_INST_OPCODE(t0)                 # extract opcode from rINST
123    GOTO_OPCODE(t0)                     # jump to next instruction
1241:
125    EXPORT_PC()
126    move    a0, rSELF
127    JAL(MterpSuspendCheck)              # (self)
128    bnez    v0, MterpFallback
129    GET_INST_OPCODE(t0)                 # extract opcode from rINST
130    GOTO_OPCODE(t0)                     # jump to next instruction
131
132/*
133 * On-stack replacement has happened, and now we've returned from the compiled method.
134 */
135MterpOnStackReplacement:
136#if MTERP_LOGGING
137    move    a0, rSELF
138    addu    a1, rFP, OFF_FP_SHADOWFRAME
139    move    a2, rINST
140    JAL(MterpLogOSR)
141#endif
142    li      v0, 1                       # Signal normal return
143    b       MterpDone
144
145/*
146 * Bail out to reference interpreter.
147 */
148MterpFallback:
149    EXPORT_PC()
150#if MTERP_LOGGING
151    move  a0, rSELF
152    addu  a1, rFP, OFF_FP_SHADOWFRAME
153    JAL(MterpLogFallback)
154#endif
155MterpCommonFallback:
156    move    v0, zero                    # signal retry with reference interpreter.
157    b       MterpDone
158/*
159 * We pushed some registers on the stack in ExecuteMterpImpl, then saved
160 * SP and LR.  Here we restore SP, restore the registers, and then restore
161 * LR to PC.
162 *
163 * On entry:
164 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
165 */
166MterpExceptionReturn:
167    li      v0, 1                       # signal return to caller.
168    b       MterpDone
169MterpReturn:
170    lw      a2, OFF_FP_RESULT_REGISTER(rFP)
171    sw      v0, 0(a2)
172    sw      v1, 4(a2)
173    li      v0, 1                       # signal return to caller.
174MterpDone:
175/* Restore from the stack and return. Frame size = STACK_SIZE */
176    STACK_LOAD_FULL()
177    jalr    zero, ra
178
179    .end ExecuteMterpImpl
180