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_DEX_INSTRUCTIONS(rFP)
99    lw      a1, OFF_FP_DEX_PC(rFP)
100    lw      rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF)
101    EAS1(rPC, a0, a1)                            # generate new dex_pc_ptr
102    /* Do we need to switch interpreters? */
103    JAL(MterpShouldSwitchInterpreters)
104    bnez    v0, MterpFallback
105    /* resume execution at catch block */
106    EXPORT_PC()
107    FETCH_INST()
108    GET_INST_OPCODE(t0)
109    GOTO_OPCODE(t0)
110    /* NOTE: no fallthrough */
111
112/*
113 * Common handling for branches with support for Jit profiling.
114 * On entry:
115 *    rINST          <= signed offset
116 *    rPROFILE       <= signed hotness countdown (expanded to 32 bits)
117 *
118 * We have quite a few different cases for branch profiling, OSR detection and
119 * suspend check support here.
120 *
121 * Taken backward branches:
122 *    If profiling active, do hotness countdown and report if we hit zero.
123 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
124 *    Is there a pending suspend request?  If so, suspend.
125 *
126 * Taken forward branches and not-taken backward branches:
127 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
128 *
129 * Our most common case is expected to be a taken backward branch with active jit profiling,
130 * but no full OSR check and no pending suspend request.
131 * Next most common case is not-taken branch with no full OSR check.
132 */
133MterpCommonTakenBranchNoFlags:
134    bgtz    rINST, .L_forward_branch    # don't add forward branches to hotness
135/*
136 * We need to subtract 1 from positive values and we should not see 0 here,
137 * so we may use the result of the comparison with -1.
138 */
139#if JIT_CHECK_OSR != -1
140#  error "JIT_CHECK_OSR must be -1."
141#endif
142    li      t0, JIT_CHECK_OSR
143    beq     rPROFILE, t0, .L_osr_check
144    blt     rPROFILE, t0, .L_resume_backward_branch
145    subu    rPROFILE, 1
146    beqz    rPROFILE, .L_add_batch      # counted down to zero - report
147.L_resume_backward_branch:
148    lw      ra, THREAD_FLAGS_OFFSET(rSELF)
149    REFRESH_IBASE()
150    addu    a2, rINST, rINST            # a2<- byte offset
151    FETCH_ADVANCE_INST_RB(a2)           # update rPC, load rINST
152    and     ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
153    bnez    ra, .L_suspend_request_pending
154    GET_INST_OPCODE(t0)                 # extract opcode from rINST
155    GOTO_OPCODE(t0)                     # jump to next instruction
156
157.L_suspend_request_pending:
158    EXPORT_PC()
159    move    a0, rSELF
160    JAL(MterpSuspendCheck)              # (self)
161    bnez    v0, MterpFallback
162    REFRESH_IBASE()                     # might have changed during suspend
163    GET_INST_OPCODE(t0)                 # extract opcode from rINST
164    GOTO_OPCODE(t0)                     # jump to next instruction
165
166.L_no_count_backwards:
167    li      t0, JIT_CHECK_OSR           # check for possible OSR re-entry
168    bne     rPROFILE, t0, .L_resume_backward_branch
169.L_osr_check:
170    move    a0, rSELF
171    addu    a1, rFP, OFF_FP_SHADOWFRAME
172    move    a2, rINST
173    EXPORT_PC()
174    JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
175    bnez    v0, MterpOnStackReplacement
176    b       .L_resume_backward_branch
177
178.L_forward_branch:
179    li      t0, JIT_CHECK_OSR           # check for possible OSR re-entry
180    beq     rPROFILE, t0, .L_check_osr_forward
181.L_resume_forward_branch:
182    add     a2, rINST, rINST            # a2<- byte offset
183    FETCH_ADVANCE_INST_RB(a2)           # update rPC, load rINST
184    GET_INST_OPCODE(t0)                 # extract opcode from rINST
185    GOTO_OPCODE(t0)                     # jump to next instruction
186
187.L_check_osr_forward:
188    move    a0, rSELF
189    addu    a1, rFP, OFF_FP_SHADOWFRAME
190    move    a2, rINST
191    EXPORT_PC()
192    JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
193    bnez    v0, MterpOnStackReplacement
194    b       .L_resume_forward_branch
195
196.L_add_batch:
197    addu    a1, rFP, OFF_FP_SHADOWFRAME
198    sh      rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1)
199    lw      a0, OFF_FP_METHOD(rFP)
200    move    a2, rSELF
201    JAL(MterpAddHotnessBatch)           # (method, shadow_frame, self)
202    move    rPROFILE, v0                # restore new hotness countdown to rPROFILE
203    b       .L_no_count_backwards
204
205/*
206 * Entered from the conditional branch handlers when OSR check request active on
207 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
208 */
209.L_check_not_taken_osr:
210    move    a0, rSELF
211    addu    a1, rFP, OFF_FP_SHADOWFRAME
212    li      a2, 2
213    EXPORT_PC()
214    JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
215    bnez    v0, MterpOnStackReplacement
216    FETCH_ADVANCE_INST(2)
217    GET_INST_OPCODE(t0)                 # extract opcode from rINST
218    GOTO_OPCODE(t0)                     # jump to next instruction
219
220/*
221 * On-stack replacement has happened, and now we've returned from the compiled method.
222 */
223MterpOnStackReplacement:
224#if MTERP_LOGGING
225    move    a0, rSELF
226    addu    a1, rFP, OFF_FP_SHADOWFRAME
227    move    a2, rINST
228    JAL(MterpLogOSR)
229#endif
230    li      v0, 1                       # Signal normal return
231    b       MterpDone
232
233/*
234 * Bail out to reference interpreter.
235 */
236MterpFallback:
237    EXPORT_PC()
238#if MTERP_LOGGING
239    move  a0, rSELF
240    addu  a1, rFP, OFF_FP_SHADOWFRAME
241    JAL(MterpLogFallback)
242#endif
243MterpCommonFallback:
244    move    v0, zero                    # signal retry with reference interpreter.
245    b       MterpDone
246/*
247 * We pushed some registers on the stack in ExecuteMterpImpl, then saved
248 * SP and LR.  Here we restore SP, restore the registers, and then restore
249 * LR to PC.
250 *
251 * On entry:
252 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
253 */
254MterpExceptionReturn:
255    li      v0, 1                       # signal return to caller.
256    b       MterpDone
257MterpReturn:
258    lw      a2, OFF_FP_RESULT_REGISTER(rFP)
259    sw      v0, 0(a2)
260    sw      v1, 4(a2)
261    li      v0, 1                       # signal return to caller.
262MterpDone:
263/*
264 * At this point, we expect rPROFILE to be non-zero.  If negative, hotness is disabled or we're
265 * checking for OSR.  If greater than zero, we might have unreported hotness to register
266 * (the difference between the ending rPROFILE and the cached hotness counter).  rPROFILE
267 * should only reach zero immediately after a hotness decrement, and is then reset to either
268 * a negative special state or the new non-zero countdown value.
269 */
270    blez    rPROFILE, .L_pop_and_return # if > 0, we may have some counts to report.
271
272MterpProfileActive:
273    move    rINST, v0                   # stash return value
274    /* Report cached hotness counts */
275    lw      a0, OFF_FP_METHOD(rFP)
276    addu    a1, rFP, OFF_FP_SHADOWFRAME
277    move    a2, rSELF
278    sh      rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1)
279    JAL(MterpAddHotnessBatch)           # (method, shadow_frame, self)
280    move    v0, rINST                   # restore return value
281
282.L_pop_and_return:
283/* Restore from the stack and return. Frame size = STACK_SIZE */
284    STACK_LOAD_FULL()
285    jalr    zero, ra
286
287    .cfi_endproc
288    .end ExecuteMterpImpl
289