1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "asm_support_x86.S"
18
19    /*
20     * Jni dlsym lookup stub.
21     */
22DEFINE_FUNCTION art_jni_dlsym_lookup_stub
23    subl LITERAL(8), %esp         // align stack
24    CFI_ADJUST_CFA_OFFSET(8)
25    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
26    CFI_ADJUST_CFA_OFFSET(4)
27    // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable()
28    // for @FastNative or @CriticalNative.
29    movl (%esp), %eax                                // Thread* self
30    movl THREAD_TOP_QUICK_FRAME_OFFSET(%eax), %eax   // uintptr_t tagged_quick_frame
31    andl LITERAL(0xfffffffe), %eax                   // ArtMethod** sp
32    movl (%eax), %eax                                // ArtMethod* method
33    testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \
34          ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
35    jne .Llookup_stub_fast_native
36    call SYMBOL(artFindNativeMethod)  // (Thread*)
37    jmp .Llookup_stub_continue
38.Llookup_stub_fast_native:
39    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
40.Llookup_stub_continue:
41    addl LITERAL(12), %esp        // remove argument & padding
42    CFI_ADJUST_CFA_OFFSET(-12)
43    testl %eax, %eax              // check if returned method code is null
44    jz .Lno_native_code_found     // if null, jump to return to handle
45    jmp *%eax                     // otherwise, tail call to intended method
46.Lno_native_code_found:
47    ret
48END_FUNCTION art_jni_dlsym_lookup_stub
49
50DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub
51    // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is eax.
52    // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
53    testl LITERAL(1), %eax
54    jnz art_jni_dlsym_lookup_stub
55
56    // We need to create a GenericJNI managed frame above the stack args.
57
58    // GenericJNI frame is similar to SaveRegsAndArgs frame with the native method
59    // instead of runtime method saved at the bottom. Note that the runtime shall
60    // not examine the args here, otherwise we would have to reload them from stack
61    // to account for the difference between managed and native ABIs.
62    SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
63    pushl %eax  // Save the hidden arg as method pointer at the bottom of the stack.
64    CFI_ADJUST_CFA_OFFSET(4)
65
66    // Call artCriticalNativeOutArgsSize(method); method is conveniently at the bottom of the stack.
67    call SYMBOL(artCriticalNativeOutArgsSize)
68
69    // Check if we have any stack args other than return PC.
70    cmp LITERAL(__SIZEOF_POINTER__), %eax
71    jnz .Lcritical_has_stack_args
72
73    // Without stack args, the frame is fully constructed.
74    // Place tagged managed sp in Thread::Current()->top_quick_frame.
75    leal 1(%esp), %eax  // Tag as GenericJNI frame.
76    mov %eax, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
77
78    // Call artFindNativeMethodRunnable()
79    subl LITERAL(12), %esp         // align stack
80    CFI_ADJUST_CFA_OFFSET(12)
81    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
82    CFI_ADJUST_CFA_OFFSET(4)
83    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
84    addl LITERAL(16), %esp
85    CFI_ADJUST_CFA_OFFSET(-16)
86
87    // Check for exception.
88    test %eax, %eax
89    jz 1f
90
91    // Restore frame and do the tail call.
92    CFI_REMEMBER_STATE
93    RESTORE_SAVE_REFS_AND_ARGS_FRAME
94    jmp *%eax
95    CFI_RESTORE_STATE_AND_DEF_CFA(%esp, FRAME_SIZE_SAVE_REFS_AND_ARGS)
96
971:
98    DELIVER_PENDING_EXCEPTION_FRAME_READY
99
100.Lcritical_has_stack_args:
101    // As mentioned above, the runtime shall not examine the args in the managed frame
102    // and since all args for the native call are on the stack, we can use the managed
103    // args registers as scratch registers. So, EBX, EDX and ECX are available and we
104    // do not need to restore xmm0-xmm3 either.
105
106    // Restore registers as we're about to move stack args over the current SaveRefsAndArgs frame.
107    movl (%esp), %edx   // Remember the method in EDX.
108    movl 48(%esp), %ebp
109    CFI_RESTORE(%ebp)
110    movl 52(%esp), %esi
111    CFI_RESTORE(%esi)
112    movl 56(%esp), %edi
113    CFI_RESTORE(%edi)
114
115    // Calculate the address of the end of the move destination and redefine CFI to take
116    // ownership of the JNI stub frame. EBX is conveniently callee-save in native ABI.
117    leal 0(%esp, %eax, 1), %ebx
118    CFI_DEF_CFA(%ebx, FRAME_SIZE_SAVE_REFS_AND_ARGS)
119
120    // Calculate the number of DWORDs to move.
121    shrl LITERAL(2), %eax
122    leal -1(%eax), %ecx  // Do not move the return PC.
123
124    // Load our return PC to EAX.
125    movl FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%esp), %eax
126
127    // Save EDI, ESI so that we can use them for moving stack args.
128    pushl %edi  // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
129    pushl %esi  // ditto
130
131    // Mov the stack args.
132    leal 2 * __SIZEOF_POINTER__(%esp), %edi
133    leal FRAME_SIZE_SAVE_REFS_AND_ARGS(%edi), %esi
134    rep movsd
135
136    // Save our return PC.
137    movl %eax, (%edi)
138
139    // Restore EDI, ESI.
140    popl %esi   // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
141    popl %edi   // ditto
142
143    // Re-create the SaveRefsAndArgs frame above the args.
144    movl %edi, 56(%ebx)
145    CFI_REL_OFFSET(%edi, 56)
146    movl %esi, 52(%ebx)
147    CFI_REL_OFFSET(%esi, 52)
148    movl %ebp, 48(%ebx)
149    CFI_REL_OFFSET(%ebp, 48)
150    // Skip managed ABI args EBX, EDX, ECX and FPRs, see above.
151    // (We have already clobbered EBX, EDX, ECX anyway).
152    movl %edx, (%ebx)    // Save method pointer.
153
154    // Place tagged managed sp in Thread::Current()->top_quick_frame.
155    leal 1(%ebx), %eax  // Tag as GenericJNI frame.
156    movl %eax, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
157
158    // Call artFindNativeMethodRunnable()
159    subl LITERAL(12), %esp        // align stack, no `CFI_ADJUST_CFA_OFFSET`.
160    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
161    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
162    addl LITERAL(16), %esp        // Pop args, no `CFI_ADJUST_CFA_OFFSET`.
163
164    // Check for exception.
165    test %eax, %eax
166    jz 2f
167
168    // Restore the frame. We shall not need the method anymore.
169    CFI_REMEMBER_STATE
170    movl 48(%ebx), %ebp
171    CFI_RESTORE(%ebp)
172    movl 52(%ebx), %esi
173    CFI_RESTORE(%esi)
174    movl 56(%ebx), %edi
175    CFI_RESTORE(%edi)
176
177    // Remember our return PC in EDX.
178    movl -__SIZEOF_POINTER__(%ebx), %edx
179
180    // Calculate the number of DWORDs to move.
181    leal -__SIZEOF_POINTER__(%ebx), %ecx  // Do not move return PC.
182    subl %esp, %ecx
183    shrl LITERAL(2), %ecx
184
185    // Save EDI, ESI so that we can use them for moving stack args.
186    pushl %edi  // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
187    pushl %esi  // ditto
188
189    // Mov stack args to their original place.
190    leal -2 * __SIZEOF_POINTER__(%ebx), %esi
191    leal FRAME_SIZE_SAVE_REFS_AND_ARGS - 2 * __SIZEOF_POINTER__(%ebx), %edi
192    std
193    rep movsd
194    cld
195
196    // Store our return PC.
197    movl %edx, (%edi)
198
199    // Restore EDI, ESI.
200    popl %esi   // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
201    popl %edi   // ditto
202
203    // Redefine CFI to release ownership of the JNI stub frame.
204    CFI_DEF_CFA(%esp, FRAME_SIZE_SAVE_REFS_AND_ARGS)
205
206    // Remove the frame reservation.
207    addl LITERAL(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__), %esp
208    CFI_ADJUST_CFA_OFFSET(-FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__)
209
210    // Do the tail call.
211    jmp *%eax
212    CFI_RESTORE_STATE_AND_DEF_CFA(%ebx, FRAME_SIZE_SAVE_REFS_AND_ARGS)
213
2142:
215    // Replicate DELIVER_PENDING_EXCEPTION_FRAME_READY without CFI_ADJUST_CFA_OFFSET,
216    // CFA register is currently EBX, not ESP.
217
218    // Outgoing argument set up
219    subl MACRO_LITERAL(12), %esp               // alignment padding
220    pushl %fs:THREAD_SELF_OFFSET               // pass Thread::Current()
221    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*)
222    UNREACHABLE
223END_FUNCTION art_jni_dlsym_lookup_critical_stub
224