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    INCREASE_FRAME 8              // Align stack.
24    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
25    CFI_ADJUST_CFA_OFFSET(4)
26    // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable()
27    // for @FastNative or @CriticalNative.
28    movl (%esp), %eax                                // Thread* self
29    movl THREAD_TOP_QUICK_FRAME_OFFSET(%eax), %eax   // uintptr_t tagged_quick_frame
30    andl LITERAL(0xfffffffe), %eax                   // ArtMethod** sp
31    movl (%eax), %eax                                // ArtMethod* method
32    testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \
33          ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
34    jne .Llookup_stub_fast_or_critical_native
35    call SYMBOL(artFindNativeMethod)  // (Thread*)
36    jmp .Llookup_stub_continue
37.Llookup_stub_fast_or_critical_native:
38    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
39.Llookup_stub_continue:
40    DECREASE_FRAME 12             // Remove argument & padding.
41    testl %eax, %eax              // Check if returned method code is null.
42    jz .Lno_native_code_found     // If null, jump to return to handle.
43    jmp *%eax                     // Otherwise, tail call to intended method.
44.Lno_native_code_found:
45    ret
46END_FUNCTION art_jni_dlsym_lookup_stub
47
48DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub
49    // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is eax.
50    // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
51    testl LITERAL(1), %eax
52    jnz art_jni_dlsym_lookup_stub
53
54    // Since the native call args are all on the stack, we can use the managed args
55    // registers as scratch registers. So, EBX, EDX and ECX are available.
56
57    // Load caller PC.
58    movl (%esp), %ecx
59
60    // Save the caller method from the hidden arg.
61    PUSH_ARG eax
62
63    // Call artCriticalNativeFrameSize(method, caller_pc).
64    PUSH_ARG ecx                  // Pass caller PC.
65    PUSH_ARG eax                  // Pass method.
66    call SYMBOL(artCriticalNativeFrameSize)  // (method, caller_pc)
67    DECREASE_FRAME 8              // Remove args.
68
69    // Restore method register to EBX.
70    POP_ARG ebx
71
72    // Load caller PC to EDX and redefine return PC for CFI.
73    movl (%esp), %edx
74    CFI_REGISTER(%eip, %edx)
75
76    // Reserve space for a SaveRefsAndArgs managed frame, either for the actual runtime
77    // method or for a GenericJNI frame which is similar but has a native method and a tag.
78    INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__
79
80    // Calculate the number of DWORDs to move.
81    movl %eax, %ecx
82    shrl LITERAL(2), %ecx
83    jecxz .Lcritical_skip_copy_args
84
85    // Save EDI, ESI so that we can use them for moving stack args.
86    PUSH edi
87    PUSH esi
88
89    // Move the stack args.
90    leal 2 * __SIZEOF_POINTER__(%esp), %edi
91    leal FRAME_SIZE_SAVE_REFS_AND_ARGS(%edi), %esi
92    rep movsd
93
94    // Restore EDI, ESI.
95    POP esi
96    POP edi
97
98.Lcritical_skip_copy_args:
99    // Calculate the base address of the managed frame.
100    leal (%esp, %eax, 1), %eax
101
102    leal 1(%eax), %ecx            // Prepare namaged SP tagged for a GenericJNI frame.
103    testl LITERAL(ACCESS_FLAGS_METHOD_IS_NATIVE), ART_METHOD_ACCESS_FLAGS_OFFSET(%ebx)
104    jnz .Lcritical_skip_prepare_runtime_method
105
106    // Save the return PC for managed stack walk.
107    // (When coming from a compiled stub, the correct return PC is already there.)
108    movl %edx, FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%eax)
109
110    // Replace the target method with the SaveRefsAndArgs runtime method.
111    LOAD_RUNTIME_INSTANCE ecx, ebx
112    movl RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET(%ecx), %ebx
113
114    movl %eax, %ecx               // Prepare untagged managed SP for the runtime method.
115
116.Lcritical_skip_prepare_runtime_method:
117    // Store the method on the bottom of the managed frame.
118    movl %ebx, (%eax)
119
120    // Move the managed frame address to native callee-save register EBX.
121    movl %eax, %ebx
122
123    // Spill registers for the SaveRefsAndArgs frame above the stack args.
124    movl %edi, 56(%ebx)
125    CFI_EXPRESSION_BREG CFI_REG(edi), CFI_REG(ebx), 56
126    movl %esi, 52(%ebx)
127    CFI_EXPRESSION_BREG CFI_REG(esi), CFI_REG(ebx), 52
128    movl %ebp, 48(%ebx)
129    CFI_EXPRESSION_BREG CFI_REG(ebp), CFI_REG(ebx), 48
130    // Skip managed ABI args EBX, EDX, ECX and FPRs. The runtime shall not examine the
131    // args in the managed frame. (We have already clobbered EBX, EDX, ECX anyway.)
132
133    // Place (maybe tagged) managed SP in Thread::Current()->top_quick_frame.
134    movl %ecx, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
135
136    // Save our return PC in a slot reserved for first FP arg in managed ABI.
137    movl %edx, __SIZEOF_POINTER__(%ebx)
138    CFI_EXPRESSION_BREG CFI_REG(eip), CFI_REG(ebx), __SIZEOF_POINTER__
139
140    // Call artFindNativeMethodRunnable()
141    INCREASE_FRAME 12             // Align stack.
142    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
143    CFI_ADJUST_CFA_OFFSET(4)
144    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
145    addl LITERAL(16), %esp
146    CFI_ADJUST_CFA_OFFSET(-16)
147
148    // Check for exception.
149    test %eax, %eax
150    jz .Lcritical_deliver_exception
151
152    CFI_REMEMBER_STATE
153
154    // Remember our return PC in EDX.
155    movl __SIZEOF_POINTER__(%ebx), %edx
156    CFI_REGISTER(%eip, %edx)
157
158    // Restore callee-save registers from the frame. We shall not need the method anymore.
159    movl 48(%ebx), %ebp
160    CFI_RESTORE(%ebp)
161    movl 52(%ebx), %esi
162    CFI_RESTORE(%esi)
163    movl 56(%ebx), %edi
164    CFI_RESTORE(%edi)
165
166    // Calculate the number of DWORDs to move.
167    movl %ebx, %ecx
168    subl %esp, %ecx
169    shrl LITERAL(2), %ecx
170    jecxz .Lcritical_skip_copy_args_back
171
172    // Save EDI, ESI so that we can use them for moving stack args.
173    PUSH edi
174    PUSH esi
175
176    // Move stack args to their original place.
177    leal -__SIZEOF_POINTER__(%ebx), %esi
178    leal FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%ebx), %edi
179    std
180    rep movsd
181    cld
182
183    // Restore EDI, ESI.
184    POP esi
185    POP edi
186
187.Lcritical_skip_copy_args_back:
188    // Remove the frame reservation.
189    DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__
190
191    // Store our return PC.
192    movl %edx, (%esp)
193    CFI_REL_OFFSET(%eip, 0)
194
195    // Do the tail call.
196    jmp *%eax
197    CFI_RESTORE_STATE_AND_DEF_CFA(%esp, FRAME_SIZE_SAVE_REFS_AND_ARGS)
198
199.Lcritical_deliver_exception:
200    DELIVER_PENDING_EXCEPTION_FRAME_READY
201END_FUNCTION art_jni_dlsym_lookup_critical_stub
202