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