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    movq    rSELF, OUT_ARG0
19    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
20    call    SYMBOL(MterpLogDivideByZeroException)
21#endif
22    jmp     MterpCommonFallback
23
24common_errArrayIndex:
25    EXPORT_PC
26#if MTERP_LOGGING
27    movq    rSELF, OUT_ARG0
28    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
29    call    SYMBOL(MterpLogArrayIndexException)
30#endif
31    jmp     MterpCommonFallback
32
33common_errNegativeArraySize:
34    EXPORT_PC
35#if MTERP_LOGGING
36    movq    rSELF, OUT_ARG0
37    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
38    call    SYMBOL(MterpLogNegativeArraySizeException)
39#endif
40    jmp     MterpCommonFallback
41
42common_errNoSuchMethod:
43    EXPORT_PC
44#if MTERP_LOGGING
45    movq    rSELF, OUT_ARG0
46    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
47    call    SYMBOL(MterpLogNoSuchMethodException)
48#endif
49    jmp     MterpCommonFallback
50
51common_errNullObject:
52    EXPORT_PC
53#if MTERP_LOGGING
54    movq    rSELF, OUT_ARG0
55    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
56    call    SYMBOL(MterpLogNullObjectException)
57#endif
58    jmp     MterpCommonFallback
59
60common_exceptionThrown:
61    EXPORT_PC
62#if MTERP_LOGGING
63    movq    rSELF, OUT_ARG0
64    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
65    call    SYMBOL(MterpLogExceptionThrownException)
66#endif
67    jmp     MterpCommonFallback
68
69MterpSuspendFallback:
70    EXPORT_PC
71#if MTERP_LOGGING
72    movq    rSELF, OUT_ARG0
73    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
74    movl    THREAD_FLAGS_OFFSET(OUT_ARG0), OUT_32_ARG2
75    call    SYMBOL(MterpLogSuspendFallback)
76#endif
77    jmp     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    movq    rSELF, %rcx
86    cmpq    $$0, THREAD_EXCEPTION_OFFSET(%rcx)
87    jz      MterpFallback
88    /* intentional fallthrough - handle pending exception. */
89
90/*
91 * On return from a runtime helper routine, we've found a pending exception.
92 * Can we handle it here - or need to bail out to caller?
93 *
94 */
95MterpException:
96    movq    rSELF, OUT_ARG0
97    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
98    call    SYMBOL(MterpHandleException)
99    testb   %al, %al
100    jz      MterpExceptionReturn
101    movq    OFF_FP_CODE_ITEM(rFP), %rax
102    mov     OFF_FP_DEX_PC(rFP), %ecx
103    leaq    CODEITEM_INSNS_OFFSET(%rax), rPC
104    leaq    (rPC, %rcx, 2), rPC
105    movq    rPC, OFF_FP_DEX_PC_PTR(rFP)
106    /* Do we need to switch interpreters? */
107    call    SYMBOL(MterpShouldSwitchInterpreters)
108    testb   %al, %al
109    jnz     MterpFallback
110    /* resume execution at catch block */
111    REFRESH_IBASE
112    FETCH_INST
113    GOTO_NEXT
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 */
139MterpCommonTakenBranch:
140    jg      .L_forward_branch               # don't add forward branches to hotness
141/*
142 * We need to subtract 1 from positive values and we should not see 0 here,
143 * so we may use the result of the comparison with -1.
144 */
145#if JIT_CHECK_OSR != -1
146#  error "JIT_CHECK_OSR must be -1."
147#endif
148    cmpl    $$JIT_CHECK_OSR, rPROFILE
149    je      .L_osr_check
150    decl    rPROFILE
151    je      .L_add_batch                    # counted down to zero - report
152.L_resume_backward_branch:
153    movq    rSELF, %rax
154    testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%rax)
155    REFRESH_IBASE
156    leaq    (rPC, rINSTq, 2), rPC
157    FETCH_INST
158    jnz     .L_suspend_request_pending
159    GOTO_NEXT
160
161.L_suspend_request_pending:
162    EXPORT_PC
163    movq    rSELF, OUT_ARG0
164    call    SYMBOL(MterpSuspendCheck)       # (self)
165    testb   %al, %al
166    jnz     MterpFallback
167    REFRESH_IBASE                           # might have changed during suspend
168    GOTO_NEXT
169
170.L_no_count_backwards:
171    cmpl    $$JIT_CHECK_OSR, rPROFILE         # possible OSR re-entry?
172    jne     .L_resume_backward_branch
173.L_osr_check:
174    EXPORT_PC
175    movq    rSELF, OUT_ARG0
176    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
177    movq    rINSTq, OUT_ARG2
178    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
179    testb   %al, %al
180    jz      .L_resume_backward_branch
181    jmp     MterpOnStackReplacement
182
183.L_forward_branch:
184    cmpl    $$JIT_CHECK_OSR, rPROFILE         # possible OSR re-entry?
185    je      .L_check_osr_forward
186.L_resume_forward_branch:
187    leaq    (rPC, rINSTq, 2), rPC
188    FETCH_INST
189    GOTO_NEXT
190
191.L_check_osr_forward:
192    EXPORT_PC
193    movq    rSELF, OUT_ARG0
194    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
195    movq    rINSTq, OUT_ARG2
196    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
197    testb   %al, %al
198    jz      .L_resume_forward_branch
199    jmp     MterpOnStackReplacement
200
201.L_add_batch:
202    movl    rPROFILE, %eax
203    movq    OFF_FP_METHOD(rFP), OUT_ARG0
204    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
205    movw    %ax, OFF_FP_COUNTDOWN_OFFSET(rFP)
206    movq    rSELF, OUT_ARG2
207    call    SYMBOL(MterpAddHotnessBatch)    # (method, shadow_frame, self)
208    movswl  %ax, rPROFILE
209    jmp     .L_no_count_backwards
210
211/*
212 * Entered from the conditional branch handlers when OSR check request active on
213 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
214 */
215.L_check_not_taken_osr:
216    EXPORT_PC
217    movq    rSELF, OUT_ARG0
218    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
219    movl    $$2, OUT_32_ARG2
220    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
221    testb   %al, %al
222    jnz     MterpOnStackReplacement
223    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
224
225/*
226 * On-stack replacement has happened, and now we've returned from the compiled method.
227 */
228MterpOnStackReplacement:
229#if MTERP_LOGGING
230    movq    rSELF, OUT_ARG0
231    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
232    movl    rINST, OUT_32_ARG2
233    call    SYMBOL(MterpLogOSR)
234#endif
235    movl    $$1, %eax
236    jmp     MterpDone
237
238/*
239 * Bail out to reference interpreter.
240 */
241MterpFallback:
242    EXPORT_PC
243#if MTERP_LOGGING
244    movq    rSELF, OUT_ARG0
245    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
246    call    SYMBOL(MterpLogFallback)
247#endif
248MterpCommonFallback:
249    xorl    %eax, %eax
250    jmp     MterpDone
251
252/*
253 * On entry:
254 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
255 */
256MterpExceptionReturn:
257    movl    $$1, %eax
258    jmp     MterpDone
259MterpReturn:
260    movq    OFF_FP_RESULT_REGISTER(rFP), %rdx
261    movq    %rax, (%rdx)
262    movl    $$1, %eax
263MterpDone:
264/*
265 * At this point, we expect rPROFILE to be non-zero.  If negative, hotness is disabled or we're
266 * checking for OSR.  If greater than zero, we might have unreported hotness to register
267 * (the difference between the ending rPROFILE and the cached hotness counter).  rPROFILE
268 * should only reach zero immediately after a hotness decrement, and is then reset to either
269 * a negative special state or the new non-zero countdown value.
270 */
271    testl   rPROFILE, rPROFILE
272    jle     MRestoreFrame                   # if > 0, we may have some counts to report.
273
274    movl    %eax, rINST                     # stash return value
275    /* Report cached hotness counts */
276    movl    rPROFILE, %eax
277    movq    OFF_FP_METHOD(rFP), OUT_ARG0
278    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
279    movw    %ax, OFF_FP_COUNTDOWN_OFFSET(rFP)
280    movq    rSELF, OUT_ARG2
281    call    SYMBOL(MterpAddHotnessBatch)    # (method, shadow_frame, self)
282    movl    rINST, %eax                     # restore return value
283
284    /* pop up frame */
285MRestoreFrame:
286    addq    $$FRAME_SIZE, %rsp
287    .cfi_adjust_cfa_offset -FRAME_SIZE
288
289    /* Restore callee save register */
290    POP %r15
291    POP %r14
292    POP %r13
293    POP %r12
294    POP %rbp
295    POP %rbx
296    ret
297    .cfi_endproc
298    SIZE(ExecuteMterpImpl,ExecuteMterpImpl)
299