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_DEX_INSTRUCTIONS(rFP), %rax
102    mov     OFF_FP_DEX_PC(rFP), %ecx
103    leaq    (%rax, %rcx, 2), rPC
104    movq    rPC, OFF_FP_DEX_PC_PTR(rFP)
105    /* Do we need to switch interpreters? */
106    call    SYMBOL(MterpShouldSwitchInterpreters)
107    testb   %al, %al
108    jnz     MterpFallback
109    /* resume execution at catch block */
110    REFRESH_IBASE
111    FETCH_INST
112    GOTO_NEXT
113    /* NOTE: no fallthrough */
114
115/*
116 * Common handling for branches with support for Jit profiling.
117 * On entry:
118 *    rINST          <= signed offset
119 *    rPROFILE       <= signed hotness countdown (expanded to 32 bits)
120 *    condition bits <= set to establish sign of offset (use "NoFlags" entry if not)
121 *
122 * We have quite a few different cases for branch profiling, OSR detection and
123 * suspend check support here.
124 *
125 * Taken backward branches:
126 *    If profiling active, do hotness countdown and report if we hit zero.
127 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
128 *    Is there a pending suspend request?  If so, suspend.
129 *
130 * Taken forward branches and not-taken backward branches:
131 *    If in osr check mode, see if our target is a compiled loop header entry and do OSR if so.
132 *
133 * Our most common case is expected to be a taken backward branch with active jit profiling,
134 * but no full OSR check and no pending suspend request.
135 * Next most common case is not-taken branch with no full OSR check.
136 *
137 */
138MterpCommonTakenBranch:
139    jg      .L_forward_branch               # don't add forward branches to hotness
140/*
141 * We need to subtract 1 from positive values and we should not see 0 here,
142 * so we may use the result of the comparison with -1.
143 */
144#if JIT_CHECK_OSR != -1
145#  error "JIT_CHECK_OSR must be -1."
146#endif
147    cmpl    $$JIT_CHECK_OSR, rPROFILE
148    je      .L_osr_check
149    decl    rPROFILE
150    je      .L_add_batch                    # counted down to zero - report
151.L_resume_backward_branch:
152    movq    rSELF, %rax
153    testl   $$(THREAD_SUSPEND_OR_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%rax)
154    REFRESH_IBASE_REG %rax
155    leaq    (rPC, rINSTq, 2), rPC
156    FETCH_INST
157    jnz     .L_suspend_request_pending
158    GOTO_NEXT
159
160.L_suspend_request_pending:
161    EXPORT_PC
162    movq    rSELF, OUT_ARG0
163    call    SYMBOL(MterpSuspendCheck)       # (self)
164    testb   %al, %al
165    jnz     MterpFallback
166    REFRESH_IBASE                           # might have changed during suspend
167    GOTO_NEXT
168
169.L_no_count_backwards:
170    cmpl    $$JIT_CHECK_OSR, rPROFILE         # possible OSR re-entry?
171    jne     .L_resume_backward_branch
172.L_osr_check:
173    EXPORT_PC
174    movq    rSELF, OUT_ARG0
175    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
176    movq    rINSTq, OUT_ARG2
177    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
178    testb   %al, %al
179    jz      .L_resume_backward_branch
180    jmp     MterpOnStackReplacement
181
182.L_forward_branch:
183    cmpl    $$JIT_CHECK_OSR, rPROFILE         # possible OSR re-entry?
184    je      .L_check_osr_forward
185.L_resume_forward_branch:
186    leaq    (rPC, rINSTq, 2), rPC
187    FETCH_INST
188    GOTO_NEXT
189
190.L_check_osr_forward:
191    EXPORT_PC
192    movq    rSELF, OUT_ARG0
193    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
194    movq    rINSTq, OUT_ARG2
195    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
196    testb   %al, %al
197    jz      .L_resume_forward_branch
198    jmp     MterpOnStackReplacement
199
200.L_add_batch:
201    movl    rPROFILE, %eax
202    movq    OFF_FP_METHOD(rFP), OUT_ARG0
203    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
204    movw    %ax, OFF_FP_COUNTDOWN_OFFSET(rFP)
205    movq    rSELF, OUT_ARG2
206    call    SYMBOL(MterpAddHotnessBatch)    # (method, shadow_frame, self)
207    movswl  %ax, rPROFILE
208    jmp     .L_no_count_backwards
209
210/*
211 * Entered from the conditional branch handlers when OSR check request active on
212 * not-taken path.  All Dalvik not-taken conditional branch offsets are 2.
213 */
214.L_check_not_taken_osr:
215    EXPORT_PC
216    movq    rSELF, OUT_ARG0
217    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
218    movl    $$2, OUT_32_ARG2
219    call    SYMBOL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset)
220    testb   %al, %al
221    jnz     MterpOnStackReplacement
222    ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
223
224/*
225 * On-stack replacement has happened, and now we've returned from the compiled method.
226 */
227MterpOnStackReplacement:
228#if MTERP_LOGGING
229    movq    rSELF, OUT_ARG0
230    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
231    movl    rINST, OUT_32_ARG2
232    call    SYMBOL(MterpLogOSR)
233#endif
234    movl    $$1, %eax
235    jmp     MterpDone
236
237/*
238 * Bail out to reference interpreter.
239 */
240MterpFallback:
241    EXPORT_PC
242#if MTERP_LOGGING
243    movq    rSELF, OUT_ARG0
244    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
245    call    SYMBOL(MterpLogFallback)
246#endif
247MterpCommonFallback:
248    xorl    %eax, %eax
249    jmp     MterpDone
250
251/*
252 * On entry:
253 *  uint32_t* rFP  (should still be live, pointer to base of vregs)
254 */
255MterpExceptionReturn:
256    movl    $$1, %eax
257    jmp     MterpDone
258MterpReturn:
259    movq    OFF_FP_RESULT_REGISTER(rFP), %rdx
260    movq    %rax, (%rdx)
261    movl    $$1, %eax
262MterpDone:
263/*
264 * At this point, we expect rPROFILE to be non-zero.  If negative, hotness is disabled or we're
265 * checking for OSR.  If greater than zero, we might have unreported hotness to register
266 * (the difference between the ending rPROFILE and the cached hotness counter).  rPROFILE
267 * should only reach zero immediately after a hotness decrement, and is then reset to either
268 * a negative special state or the new non-zero countdown value.
269 */
270    testl   rPROFILE, rPROFILE
271    jle     MRestoreFrame                   # if > 0, we may have some counts to report.
272
273    movl    %eax, rINST                     # stash return value
274    /* Report cached hotness counts */
275    movl    rPROFILE, %eax
276    movq    OFF_FP_METHOD(rFP), OUT_ARG0
277    leaq    OFF_FP_SHADOWFRAME(rFP), OUT_ARG1
278    movw    %ax, OFF_FP_COUNTDOWN_OFFSET(rFP)
279    movq    rSELF, OUT_ARG2
280    call    SYMBOL(MterpAddHotnessBatch)    # (method, shadow_frame, self)
281    movl    rINST, %eax                     # restore return value
282
283    /* pop up frame */
284MRestoreFrame:
285    addq    $$FRAME_SIZE, %rsp
286    .cfi_adjust_cfa_offset -FRAME_SIZE
287
288    /* Restore callee save register */
289    POP %r15
290    POP %r14
291    POP %r13
292    POP %r12
293    POP %rbp
294    POP %rbx
295    ret
296    .cfi_endproc
297    SIZE(ExecuteMterpImpl,ExecuteMterpImpl)
298