1/*
2 * ===========================================================================
3 *  Common subroutines and data
4 * ===========================================================================
5 */
6
7
8/*
9 * We've detected a condition that will result in an exception, but the exception
10 * has not yet been thrown.  Just bail out to the reference interpreter to deal with it.
11 * TUNING: for consistency, we may want to just go ahead and handle these here.
12 */
13common_errDivideByZero:
14    EXPORT_PC
15#if MTERP_LOGGING
16    mov  x0, xSELF
17    add  x1, xFP, #OFF_FP_SHADOWFRAME
18    bl MterpLogDivideByZeroException
19#endif
20    b MterpCommonFallback
21
22common_errArrayIndex:
23    EXPORT_PC
24#if MTERP_LOGGING
25    mov  x0, xSELF
26    add  x1, xFP, #OFF_FP_SHADOWFRAME
27    bl MterpLogArrayIndexException
28#endif
29    b MterpCommonFallback
30
31common_errNegativeArraySize:
32    EXPORT_PC
33#if MTERP_LOGGING
34    mov  x0, xSELF
35    add  x1, xFP, #OFF_FP_SHADOWFRAME
36    bl MterpLogNegativeArraySizeException
37#endif
38    b MterpCommonFallback
39
40common_errNoSuchMethod:
41    EXPORT_PC
42#if MTERP_LOGGING
43    mov  x0, xSELF
44    add  x1, xFP, #OFF_FP_SHADOWFRAME
45    bl MterpLogNoSuchMethodException
46#endif
47    b MterpCommonFallback
48
49common_errNullObject:
50    EXPORT_PC
51#if MTERP_LOGGING
52    mov  x0, xSELF
53    add  x1, xFP, #OFF_FP_SHADOWFRAME
54    bl MterpLogNullObjectException
55#endif
56    b MterpCommonFallback
57
58common_exceptionThrown:
59    EXPORT_PC
60#if MTERP_LOGGING
61    mov  x0, xSELF
62    add  x1, xFP, #OFF_FP_SHADOWFRAME
63    bl MterpLogExceptionThrownException
64#endif
65    b MterpCommonFallback
66
67MterpSuspendFallback:
68    EXPORT_PC
69#if MTERP_LOGGING
70    mov  x0, xSELF
71    add  x1, xFP, #OFF_FP_SHADOWFRAME
72    ldr  x2, [xSELF, #THREAD_FLAGS_OFFSET]
73    bl MterpLogSuspendFallback
74#endif
75    b MterpCommonFallback
76
77/*
78 * If we're here, something is out of the ordinary.  If there is a pending
79 * exception, handle it.  Otherwise, roll back and retry with the reference
80 * interpreter.
81 */
82MterpPossibleException:
83    ldr     x0, [xSELF, #THREAD_EXCEPTION_OFFSET]
84    cbz     x0, MterpFallback                       // If not, fall back to reference interpreter.
85    /* intentional fallthrough - handle pending exception. */
86/*
87 * On return from a runtime helper routine, we've found a pending exception.
88 * Can we handle it here - or need to bail out to caller?
89 *
90 */
91MterpException:
92    mov     x0, xSELF
93    add     x1, xFP, #OFF_FP_SHADOWFRAME
94    bl      MterpHandleException                    // (self, shadow_frame)
95    cbz     w0, MterpExceptionReturn                // no local catch, back to caller.
96    ldr     x0, [xFP, #OFF_FP_CODE_ITEM]
97    ldr     w1, [xFP, #OFF_FP_DEX_PC]
98    ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
99    add     xPC, x0, #CODEITEM_INSNS_OFFSET
100    add     xPC, xPC, x1, lsl #1                    // generate new dex_pc_ptr
101    /* Do we need to switch interpreters? */
102    bl      MterpShouldSwitchInterpreters
103    cbnz    w0, MterpFallback
104    /* resume execution at catch block */
105    EXPORT_PC
106    FETCH_INST
107    GET_INST_OPCODE ip
108    GOTO_OPCODE ip
109    /* NOTE: no fallthrough */
110/*
111 * Common handling for branches with support for Jit profiling.
112 * On entry:
113 *    wINST          <= signed offset
114 *    wPROFILE       <= signed hotness countdown (expanded to 32 bits)
115 *    condition bits <= set to establish sign of offset (use "NoFlags" entry if not)
116 *
117 * We have quite a few different cases for branch profiling, OSR detection and
118 * suspend check support here.
119 *
120 * Taken backward branches:
121 *    If profiling active, do hotness countdown and report if we hit zero.
122 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
123 *    Is there a pending suspend request?  If so, suspend.
124 *
125 * Taken forward branches and not-taken backward branches:
126 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
127 *
128 * Our most common case is expected to be a taken backward branch with active jit profiling,
129 * but no full OSR check and no pending suspend request.
130 * Next most common case is not-taken branch with no full OSR check.
131 *
132 */
133MterpCommonTakenBranchNoFlags:
134    cmp     wINST, #0
135    b.gt    .L_forward_branch           // don't add forward branches to hotness
136    tbnz    wPROFILE, #31, .L_no_count_backwards  // go if negative
137    subs    wPROFILE, wPROFILE, #1      // countdown
138    b.eq    .L_add_batch                // counted down to zero - report
139.L_resume_backward_branch:
140    ldr     lr, [xSELF, #THREAD_FLAGS_OFFSET]
141    add     w2, wINST, wINST            // w2<- byte offset
142    FETCH_ADVANCE_INST_RB w2            // update rPC, load wINST
143    REFRESH_IBASE
144    ands    lr, lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
145    b.ne    .L_suspend_request_pending
146    GET_INST_OPCODE ip                  // extract opcode from wINST
147    GOTO_OPCODE ip                      // jump to next instruction
148
149.L_suspend_request_pending:
150    EXPORT_PC
151    mov     x0, xSELF
152    bl      MterpSuspendCheck           // (self)
153    cbnz    x0, MterpFallback
154    REFRESH_IBASE                       // might have changed during suspend
155    GET_INST_OPCODE ip                  // extract opcode from wINST
156    GOTO_OPCODE ip                      // jump to next instruction
157
158.L_no_count_backwards:
159    cmp     wPROFILE, #JIT_CHECK_OSR    // possible OSR re-entry?
160    b.ne    .L_resume_backward_branch
161    mov     x0, xSELF
162    add     x1, xFP, #OFF_FP_SHADOWFRAME
163    mov     x2, xINST
164    EXPORT_PC
165    bl      MterpMaybeDoOnStackReplacement  // (self, shadow_frame, offset)
166    cbnz    x0, MterpOnStackReplacement
167    b       .L_resume_backward_branch
168
169.L_forward_branch:
170    cmp     wPROFILE, #JIT_CHECK_OSR    // possible OSR re-entry?
171    b.eq    .L_check_osr_forward
172.L_resume_forward_branch:
173    add     w2, wINST, wINST            // w2<- byte offset
174    FETCH_ADVANCE_INST_RB w2            // update rPC, load wINST
175    GET_INST_OPCODE ip                  // extract opcode from wINST
176    GOTO_OPCODE ip                      // jump to next instruction
177
178.L_check_osr_forward:
179    mov     x0, xSELF
180    add     x1, xFP, #OFF_FP_SHADOWFRAME
181    mov     x2, xINST
182    EXPORT_PC
183    bl      MterpMaybeDoOnStackReplacement  // (self, shadow_frame, offset)
184    cbnz    x0, MterpOnStackReplacement
185    b       .L_resume_forward_branch
186
187.L_add_batch:
188    add     x1, xFP, #OFF_FP_SHADOWFRAME
189    strh    wPROFILE, [x1, #SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET]
190    ldr     x0, [xFP, #OFF_FP_METHOD]
191    mov     x2, xSELF
192    bl      MterpAddHotnessBatch        // (method, shadow_frame, self)
193    mov     wPROFILE, w0                // restore new hotness countdown to wPROFILE
194    b       .L_no_count_backwards
195
196/*
197 * Entered from the conditional branch handlers when OSR check request active on
198 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
199 */
200.L_check_not_taken_osr:
201    mov     x0, xSELF
202    add     x1, xFP, #OFF_FP_SHADOWFRAME
203    mov     x2, #2
204    EXPORT_PC
205    bl      MterpMaybeDoOnStackReplacement  // (self, shadow_frame, offset)
206    cbnz    x0, MterpOnStackReplacement
207    FETCH_ADVANCE_INST 2
208    GET_INST_OPCODE ip                  // extract opcode from wINST
209    GOTO_OPCODE ip                      // jump to next instruction
210
211
212/*
213 * Check for suspend check request.  Assumes wINST already loaded, xPC advanced and
214 * still needs to get the opcode and branch to it, and flags are in lr.
215 */
216MterpCheckSuspendAndContinue:
217    ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]  // refresh xIBASE
218    ands    w7, w7, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
219    b.ne    check1
220    GET_INST_OPCODE ip                  // extract opcode from wINST
221    GOTO_OPCODE ip                      // jump to next instruction
222check1:
223    EXPORT_PC
224    mov     x0, xSELF
225    bl      MterpSuspendCheck           // (self)
226    cbnz    x0, MterpFallback           // Something in the environment changed, switch interpreters
227    GET_INST_OPCODE ip                  // extract opcode from wINST
228    GOTO_OPCODE ip                      // jump to next instruction
229
230/*
231 * On-stack replacement has happened, and now we've returned from the compiled method.
232 */
233MterpOnStackReplacement:
234#if MTERP_LOGGING
235    mov  x0, xSELF
236    add  x1, xFP, #OFF_FP_SHADOWFRAME
237    sbfm x2, xINST, 0, 31
238    bl MterpLogOSR
239#endif
240    mov  x0, #1                         // Signal normal return
241    b    MterpDone
242
243/*
244 * Bail out to reference interpreter.
245 */
246MterpFallback:
247    EXPORT_PC
248#if MTERP_LOGGING
249    mov  x0, xSELF
250    add  x1, xFP, #OFF_FP_SHADOWFRAME
251    bl MterpLogFallback
252#endif
253MterpCommonFallback:
254    mov     x0, #0                                  // signal retry with reference interpreter.
255    b       MterpDone
256
257/*
258 * We pushed some registers on the stack in ExecuteMterpImpl, then saved
259 * SP and LR.  Here we restore SP, restore the registers, and then restore
260 * LR to PC.
261 *
262 * On entry:
263 *  uint32_t* xFP  (should still be live, pointer to base of vregs)
264 */
265MterpExceptionReturn:
266    mov     x0, #1                                  // signal return to caller.
267    b MterpDone
268MterpReturn:
269    ldr     x2, [xFP, #OFF_FP_RESULT_REGISTER]
270    ldr     lr, [xSELF, #THREAD_FLAGS_OFFSET]
271    str     x0, [x2]
272    mov     x0, xSELF
273    ands    lr, lr, #(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST)
274    b.eq    check2
275    bl      MterpSuspendCheck                       // (self)
276check2:
277    mov     x0, #1                                  // signal return to caller.
278MterpDone:
279/*
280 * At this point, we expect wPROFILE to be non-zero.  If negative, hotness is disabled or we're
281 * checking for OSR.  If greater than zero, we might have unreported hotness to register
282 * (the difference between the ending wPROFILE and the cached hotness counter).  wPROFILE
283 * should only reach zero immediately after a hotness decrement, and is then reset to either
284 * a negative special state or the new non-zero countdown value.
285 */
286    cmp     wPROFILE, #0
287    bgt     MterpProfileActive                      // if > 0, we may have some counts to report.
288    ldp     fp, lr, [sp, #64]
289    ldp     xPC, xFP, [sp, #48]
290    ldp     xSELF, xINST, [sp, #32]
291    ldp     xIBASE, xREFS, [sp, #16]
292    ldp     xPROFILE, x27, [sp], #80
293    ret
294
295MterpProfileActive:
296    mov     xINST, x0                               // stash return value
297    /* Report cached hotness counts */
298    ldr     x0, [xFP, #OFF_FP_METHOD]
299    add     x1, xFP, #OFF_FP_SHADOWFRAME
300    mov     x2, xSELF
301    strh    wPROFILE, [x1, #SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET]
302    bl      MterpAddHotnessBatch                    // (method, shadow_frame, self)
303    mov     x0, xINST                               // restore return value
304    ldp     fp, lr, [sp, #64]
305    ldp     xPC, xFP, [sp, #48]
306    ldp     xSELF, xINST, [sp, #32]
307    ldp     xIBASE, xREFS, [sp, #16]
308    ldp     xPROFILE, x27, [sp], #80
309    ret
310
311    .cfi_endproc
312    .size   ExecuteMterpImpl, .-ExecuteMterpImpl
313
314