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    movl    rSELF, %eax
19    movl    %eax, OUT_ARG0(%esp)
20    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
21    movl    %ecx, OUT_ARG1(%esp)
22    call    SYMBOL(MterpLogDivideByZeroException)
23#endif
24    jmp     MterpCommonFallback
25
26common_errArrayIndex:
27    EXPORT_PC
28#if MTERP_LOGGING
29    movl    rSELF, %eax
30    movl    %eax, OUT_ARG0(%esp)
31    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
32    movl    %ecx, OUT_ARG1(%esp)
33    call    SYMBOL(MterpLogArrayIndexException)
34#endif
35    jmp     MterpCommonFallback
36
37common_errNegativeArraySize:
38    EXPORT_PC
39#if MTERP_LOGGING
40    movl    rSELF, %eax
41    movl    %eax, OUT_ARG0(%esp)
42    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
43    movl    %ecx, OUT_ARG1(%esp)
44    call    SYMBOL(MterpLogNegativeArraySizeException)
45#endif
46    jmp     MterpCommonFallback
47
48common_errNoSuchMethod:
49    EXPORT_PC
50#if MTERP_LOGGING
51    movl    rSELF, %eax
52    movl    %eax, OUT_ARG0(%esp)
53    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
54    movl    %ecx, OUT_ARG1(%esp)
55    call    SYMBOL(MterpLogNoSuchMethodException)
56#endif
57    jmp     MterpCommonFallback
58
59common_errNullObject:
60    EXPORT_PC
61#if MTERP_LOGGING
62    movl    rSELF, %eax
63    movl    %eax, OUT_ARG0(%esp)
64    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
65    movl    %ecx, OUT_ARG1(%esp)
66    call    SYMBOL(MterpLogNullObjectException)
67#endif
68    jmp     MterpCommonFallback
69
70common_exceptionThrown:
71    EXPORT_PC
72#if MTERP_LOGGING
73    movl    rSELF, %eax
74    movl    %eax, OUT_ARG0(%esp)
75    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
76    movl    %ecx, OUT_ARG0(%esp)
77    call    SYMBOL(MterpLogExceptionThrownException)
78#endif
79    jmp     MterpCommonFallback
80
81MterpSuspendFallback:
82    EXPORT_PC
83#if MTERP_LOGGING
84    movl    rSELF, %eax
85    movl    %eax, OUT_ARG0(%esp)
86    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
87    movl    %ecx, OUT_ARG0(%esp)
88    movl    THREAD_FLAGS_OFFSET(%eax), %eax
89    movl    %eax, OUT_ARG2(%esp)
90    call    SYMBOL(MterpLogSuspendFallback)
91#endif
92    jmp     MterpCommonFallback
93
94/*
95 * If we're here, something is out of the ordinary.  If there is a pending
96 * exception, handle it.  Otherwise, roll back and retry with the reference
97 * interpreter.
98 */
99MterpPossibleException:
100    movl    rSELF, %eax
101    testl   $$-1, THREAD_EXCEPTION_OFFSET(%eax)
102    jz      MterpFallback
103    /* intentional fallthrough - handle pending exception. */
104
105/*
106 * On return from a runtime helper routine, we've found a pending exception.
107 * Can we handle it here - or need to bail out to caller?
108 *
109 */
110MterpException:
111    movl    rSELF, %eax
112    movl    %eax, OUT_ARG0(%esp)
113    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
114    movl    %ecx, OUT_ARG1(%esp)
115    call    SYMBOL(MterpHandleException)
116    testb   %al, %al
117    jz      MterpExceptionReturn
118    movl    OFF_FP_CODE_ITEM(rFP), %eax
119    movl    OFF_FP_DEX_PC(rFP), %ecx
120    lea     CODEITEM_INSNS_OFFSET(%eax), rPC
121    lea     (rPC, %ecx, 2), rPC
122    movl    rPC, OFF_FP_DEX_PC_PTR(rFP)
123    /* Do we need to switch interpreters? */
124    call    SYMBOL(MterpShouldSwitchInterpreters)
125    testb   %al, %al
126    jnz     MterpFallback
127    /* resume execution at catch block */
128    REFRESH_IBASE
129    FETCH_INST
130    GOTO_NEXT
131    /* NOTE: no fallthrough */
132
133/*
134 * Common handling for branches with support for Jit profiling.
135 * On entry:
136 *    rINST          <= signed offset
137 *    condition bits <= set to establish sign of offset (use "NoFlags" entry if not)
138 *
139 * We have quite a few different cases for branch profiling, OSR detection and
140 * suspend check support here.
141 *
142 * Taken backward branches:
143 *    If profiling active, do hotness countdown and report if we hit zero.
144 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
145 *    Is there a pending suspend request?  If so, suspend.
146 *
147 * Taken forward branches and not-taken backward branches:
148 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
149 *
150 * Our most common case is expected to be a taken backward branch with active jit profiling,
151 * but no full OSR check and no pending suspend request.
152 * Next most common case is not-taken branch with no full OSR check.
153 *
154 */
155MterpCommonTakenBranch:
156    jg      .L_forward_branch               # don't add forward branches to hotness
157/*
158 * We need to subtract 1 from positive values and we should not see 0 here,
159 * so we may use the result of the comparison with -1.
160 */
161#if JIT_CHECK_OSR != -1
162#  error "JIT_CHECK_OSR must be -1."
163#endif
164    cmpw    $$JIT_CHECK_OSR, rPROFILE
165    je      .L_osr_check
166    decw    rPROFILE
167    je      .L_add_batch                    # counted down to zero - report
168.L_resume_backward_branch:
169    movl    rSELF, %eax
170    testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
171    leal    (rPC, rINST, 2), rPC
172    FETCH_INST
173    jnz     .L_suspend_request_pending
174    REFRESH_IBASE
175    GOTO_NEXT
176
177.L_suspend_request_pending:
178    EXPORT_PC
179    movl    %eax, OUT_ARG0(%esp)            # rSELF in eax
180    call    SYMBOL(MterpSuspendCheck)       # (self)
181    testb   %al, %al
182    jnz     MterpFallback
183    REFRESH_IBASE                           # might have changed during suspend
184    GOTO_NEXT
185
186.L_no_count_backwards:
187    cmpw    $$JIT_CHECK_OSR, rPROFILE         # possible OSR re-entry?
188    jne     .L_resume_backward_branch
189.L_osr_check:
190    EXPORT_PC
191    movl    rSELF, %eax
192    movl    %eax, OUT_ARG0(%esp)
193    leal    OFF_FP_SHADOWFRAME(rFP), %ecx
194    movl    %ecx, OUT_ARG1(%esp)
195    movl    rINST, OUT_ARG2(%esp)
196    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
197    testb   %al, %al
198    jz      .L_resume_backward_branch
199    jmp     MterpOnStackReplacement
200
201.L_forward_branch:
202    cmpw    $$JIT_CHECK_OSR, rPROFILE         # possible OSR re-entry?
203    je      .L_check_osr_forward
204.L_resume_forward_branch:
205    leal    (rPC, rINST, 2), rPC
206    FETCH_INST
207    GOTO_NEXT
208
209.L_check_osr_forward:
210    EXPORT_PC
211    movl    rSELF, %eax
212    movl    %eax, OUT_ARG0(%esp)
213    leal    OFF_FP_SHADOWFRAME(rFP), %ecx
214    movl    %ecx, OUT_ARG1(%esp)
215    movl    rINST, OUT_ARG2(%esp)
216    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
217    testb   %al, %al
218    REFRESH_IBASE
219    jz      .L_resume_forward_branch
220    jmp     MterpOnStackReplacement
221
222.L_add_batch:
223    movl    OFF_FP_METHOD(rFP), %eax
224    movl    %eax, OUT_ARG0(%esp)
225    leal    OFF_FP_SHADOWFRAME(rFP), %ecx
226    movl    %ecx, OUT_ARG1(%esp)
227    movl    rSELF, %eax
228    movl    %eax, OUT_ARG2(%esp)
229    call    SYMBOL(MterpAddHotnessBatch)    # (method, shadow_frame, self)
230    jmp     .L_no_count_backwards
231
232/*
233 * Entered from the conditional branch handlers when OSR check request active on
234 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
235 */
236.L_check_not_taken_osr:
237    EXPORT_PC
238    movl    rSELF, %eax
239    movl    %eax, OUT_ARG0(%esp)
240    leal    OFF_FP_SHADOWFRAME(rFP), %ecx
241    movl    %ecx, OUT_ARG1(%esp)
242    movl    $$2, OUT_ARG2(%esp)
243    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
244    testb   %al, %al
245    REFRESH_IBASE
246    jnz     MterpOnStackReplacement
247    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
248
249/*
250 * On-stack replacement has happened, and now we've returned from the compiled method.
251 */
252MterpOnStackReplacement:
253#if MTERP_LOGGING
254    movl    rSELF, %eax
255    movl    %eax, OUT_ARG0(%esp)
256    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
257    movl    %ecx, OUT_ARG1(%esp)
258    movl    rINST, OUT_ARG2(%esp)
259    call    SYMBOL(MterpLogOSR)
260#endif
261    movl    $$1, %eax
262    jmp     MterpDone
263
264/*
265 * Bail out to reference interpreter.
266 */
267MterpFallback:
268    EXPORT_PC
269#if MTERP_LOGGING
270    movl    rSELF, %eax
271    movl    %eax, OUT_ARG0(%esp)
272    lea     OFF_FP_SHADOWFRAME(rFP), %ecx
273    movl    %ecx, OUT_ARG1(%esp)
274    call    SYMBOL(MterpLogFallback)
275#endif
276MterpCommonFallback:
277    xor     %eax, %eax
278    jmp     MterpDone
279
280/*
281 * On entry:
282 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
283 */
284MterpExceptionReturn:
285    movl    $$1, %eax
286    jmp     MterpDone
287MterpReturn:
288    movl    OFF_FP_RESULT_REGISTER(rFP), %edx
289    movl    %eax, (%edx)
290    movl    %ecx, 4(%edx)
291    mov     $$1, %eax
292MterpDone:
293/*
294 * At this point, we expect rPROFILE to be non-zero.  If negative, hotness is disabled or we're
295 * checking for OSR.  If greater than zero, we might have unreported hotness to register
296 * (the difference between the ending rPROFILE and the cached hotness counter).  rPROFILE
297 * should only reach zero immediately after a hotness decrement, and is then reset to either
298 * a negative special state or the new non-zero countdown value.
299 */
300    cmpw    $$0, rPROFILE
301    jle     MRestoreFrame                   # if > 0, we may have some counts to report.
302
303    movl    %eax, rINST                     # stash return value
304    /* Report cached hotness counts */
305    movl    OFF_FP_METHOD(rFP), %eax
306    movl    %eax, OUT_ARG0(%esp)
307    leal    OFF_FP_SHADOWFRAME(rFP), %ecx
308    movl    %ecx, OUT_ARG1(%esp)
309    movl    rSELF, %eax
310    movl    %eax, OUT_ARG2(%esp)
311    call    SYMBOL(MterpAddHotnessBatch)    # (method, shadow_frame, self)
312    movl    rINST, %eax                     # restore return value
313
314    /* pop up frame */
315MRestoreFrame:
316    addl    $$FRAME_SIZE, %esp
317    .cfi_adjust_cfa_offset -FRAME_SIZE
318
319    /* Restore callee save register */
320    POP     %ebx
321    POP     %esi
322    POP     %edi
323    POP     %ebp
324    ret
325    .cfi_endproc
326    SIZE(ExecuteMterpImpl,ExecuteMterpImpl)
327