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_DEX_INSTRUCTIONS]
97    ldr     w1, [xFP, #OFF_FP_DEX_PC]
98    ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]
99    add     xPC, x0, x1, lsl #1                     // generate new dex_pc_ptr
100    /* Do we need to switch interpreters? */
101    bl      MterpShouldSwitchInterpreters
102    cbnz    w0, MterpFallback
103    /* resume execution at catch block */
104    EXPORT_PC
105    FETCH_INST
106    GET_INST_OPCODE ip
107    GOTO_OPCODE ip
108    /* NOTE: no fallthrough */
109/*
110 * Common handling for branches with support for Jit profiling.
111 * On entry:
112 *    wINST          <= signed offset
113 *    wPROFILE       <= signed hotness countdown (expanded to 32 bits)
114 *    condition bits <= set to establish sign of offset (use "NoFlags" entry if not)
115 *
116 * We have quite a few different cases for branch profiling, OSR detection and
117 * suspend check support here.
118 *
119 * Taken backward branches:
120 *    If profiling active, do hotness countdown and report if we hit zero.
121 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
122 *    Is there a pending suspend request?  If so, suspend.
123 *
124 * Taken forward branches and not-taken backward branches:
125 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
126 *
127 * Our most common case is expected to be a taken backward branch with active jit profiling,
128 * but no full OSR check and no pending suspend request.
129 * Next most common case is not-taken branch with no full OSR check.
130 *
131 */
132MterpCommonTakenBranchNoFlags:
133    cmp     wINST, #0
134    b.gt    .L_forward_branch           // don't add forward branches to hotness
135    tbnz    wPROFILE, #31, .L_no_count_backwards  // go if negative
136    subs    wPROFILE, wPROFILE, #1      // countdown
137    b.eq    .L_add_batch                // counted down to zero - report
138.L_resume_backward_branch:
139    ldr     lr, [xSELF, #THREAD_FLAGS_OFFSET]
140    add     w2, wINST, wINST            // w2<- byte offset
141    FETCH_ADVANCE_INST_RB w2            // update rPC, load wINST
142    REFRESH_IBASE
143    ands    lr, lr, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
144    b.ne    .L_suspend_request_pending
145    GET_INST_OPCODE ip                  // extract opcode from wINST
146    GOTO_OPCODE ip                      // jump to next instruction
147
148.L_suspend_request_pending:
149    EXPORT_PC
150    mov     x0, xSELF
151    bl      MterpSuspendCheck           // (self)
152    cbnz    x0, MterpFallback
153    REFRESH_IBASE                       // might have changed during suspend
154    GET_INST_OPCODE ip                  // extract opcode from wINST
155    GOTO_OPCODE ip                      // jump to next instruction
156
157.L_no_count_backwards:
158    cmp     wPROFILE, #JIT_CHECK_OSR    // possible OSR re-entry?
159    b.ne    .L_resume_backward_branch
160    mov     x0, xSELF
161    add     x1, xFP, #OFF_FP_SHADOWFRAME
162    mov     x2, xINST
163    EXPORT_PC
164    bl      MterpMaybeDoOnStackReplacement  // (self, shadow_frame, offset)
165    cbnz    x0, MterpOnStackReplacement
166    b       .L_resume_backward_branch
167
168.L_forward_branch:
169    cmp     wPROFILE, #JIT_CHECK_OSR    // possible OSR re-entry?
170    b.eq    .L_check_osr_forward
171.L_resume_forward_branch:
172    add     w2, wINST, wINST            // w2<- byte offset
173    FETCH_ADVANCE_INST_RB w2            // update rPC, load wINST
174    GET_INST_OPCODE ip                  // extract opcode from wINST
175    GOTO_OPCODE ip                      // jump to next instruction
176
177.L_check_osr_forward:
178    mov     x0, xSELF
179    add     x1, xFP, #OFF_FP_SHADOWFRAME
180    mov     x2, xINST
181    EXPORT_PC
182    bl      MterpMaybeDoOnStackReplacement  // (self, shadow_frame, offset)
183    cbnz    x0, MterpOnStackReplacement
184    b       .L_resume_forward_branch
185
186.L_add_batch:
187    add     x1, xFP, #OFF_FP_SHADOWFRAME
188    strh    wPROFILE, [x1, #SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET]
189    ldr     x0, [xFP, #OFF_FP_METHOD]
190    mov     x2, xSELF
191    bl      MterpAddHotnessBatch        // (method, shadow_frame, self)
192    mov     wPROFILE, w0                // restore new hotness countdown to wPROFILE
193    b       .L_no_count_backwards
194
195/*
196 * Entered from the conditional branch handlers when OSR check request active on
197 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
198 */
199.L_check_not_taken_osr:
200    mov     x0, xSELF
201    add     x1, xFP, #OFF_FP_SHADOWFRAME
202    mov     x2, #2
203    EXPORT_PC
204    bl      MterpMaybeDoOnStackReplacement  // (self, shadow_frame, offset)
205    cbnz    x0, MterpOnStackReplacement
206    FETCH_ADVANCE_INST 2
207    GET_INST_OPCODE ip                  // extract opcode from wINST
208    GOTO_OPCODE ip                      // jump to next instruction
209
210
211/*
212 * Check for suspend check request.  Assumes wINST already loaded, xPC advanced and
213 * still needs to get the opcode and branch to it, and flags are in lr.
214 */
215MterpCheckSuspendAndContinue:
216    ldr     xIBASE, [xSELF, #THREAD_CURRENT_IBASE_OFFSET]  // refresh xIBASE
217    ands    w7, w7, #THREAD_SUSPEND_OR_CHECKPOINT_REQUEST
218    b.ne    check1
219    GET_INST_OPCODE ip                  // extract opcode from wINST
220    GOTO_OPCODE ip                      // jump to next instruction
221check1:
222    EXPORT_PC
223    mov     x0, xSELF
224    bl      MterpSuspendCheck           // (self)
225    cbnz    x0, MterpFallback           // Something in the environment changed, switch interpreters
226    GET_INST_OPCODE ip                  // extract opcode from wINST
227    GOTO_OPCODE ip                      // jump to next instruction
228
229/*
230 * On-stack replacement has happened, and now we've returned from the compiled method.
231 */
232MterpOnStackReplacement:
233#if MTERP_LOGGING
234    mov  x0, xSELF
235    add  x1, xFP, #OFF_FP_SHADOWFRAME
236    sxtw x2, wINST
237    bl MterpLogOSR
238#endif
239    mov  x0, #1                         // Signal normal return
240    b    MterpDone
241
242/*
243 * Bail out to reference interpreter.
244 */
245MterpFallback:
246    EXPORT_PC
247#if MTERP_LOGGING
248    mov  x0, xSELF
249    add  x1, xFP, #OFF_FP_SHADOWFRAME
250    bl MterpLogFallback
251#endif
252MterpCommonFallback:
253    mov     x0, #0                                  // signal retry with reference interpreter.
254    b       MterpDone
255
256/*
257 * We pushed some registers on the stack in ExecuteMterpImpl, then saved
258 * SP and LR.  Here we restore SP, restore the registers, and then restore
259 * LR to PC.
260 *
261 * On entry:
262 *  uint32_t* xFP  (should still be live, pointer to base of vregs)
263 */
264MterpExceptionReturn:
265    mov     x0, #1                                  // signal return to caller.
266    b MterpDone
267MterpReturn:
268    ldr     x2, [xFP, #OFF_FP_RESULT_REGISTER]
269    str     x0, [x2]
270    mov     x0, #1                                  // signal return to caller.
271MterpDone:
272/*
273 * At this point, we expect wPROFILE to be non-zero.  If negative, hotness is disabled or we're
274 * checking for OSR.  If greater than zero, we might have unreported hotness to register
275 * (the difference between the ending wPROFILE and the cached hotness counter).  wPROFILE
276 * should only reach zero immediately after a hotness decrement, and is then reset to either
277 * a negative special state or the new non-zero countdown value.
278 */
279    cmp     wPROFILE, #0
280    bgt     MterpProfileActive                      // if > 0, we may have some counts to report.
281    .cfi_remember_state
282    RESTORE_TWO_REGS                fp, lr, 64
283    RESTORE_TWO_REGS                xPC, xFP, 48
284    RESTORE_TWO_REGS                xSELF, xINST, 32
285    RESTORE_TWO_REGS                xIBASE, xREFS, 16
286    RESTORE_TWO_REGS_DECREASE_FRAME xPROFILE, x27, 80
287    ret
288    .cfi_restore_state                              // Reset unwind info so following code unwinds.
289    .cfi_def_cfa_offset 80                          // workaround for clang bug: 31975598
290
291MterpProfileActive:
292    mov     xINST, x0                               // stash return value
293    /* Report cached hotness counts */
294    ldr     x0, [xFP, #OFF_FP_METHOD]
295    add     x1, xFP, #OFF_FP_SHADOWFRAME
296    mov     x2, xSELF
297    strh    wPROFILE, [x1, #SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET]
298    bl      MterpAddHotnessBatch                    // (method, shadow_frame, self)
299    mov     x0, xINST                               // restore return value
300    RESTORE_TWO_REGS                fp, lr, 64
301    RESTORE_TWO_REGS                xPC, xFP, 48
302    RESTORE_TWO_REGS                xSELF, xINST, 32
303    RESTORE_TWO_REGS                xIBASE, xREFS, 16
304    RESTORE_TWO_REGS_DECREASE_FRAME xPROFILE, x27, 80
305    ret
306
307