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_64.S"
18
19    /*
20     * Jni dlsym lookup stub.
21     */
22DEFINE_FUNCTION art_jni_dlsym_lookup_stub
23    // Save callee and GPR args.
24    PUSH_ARG r9   // Arg.
25    PUSH_ARG r8   // Arg.
26    PUSH_ARG rdi  // Arg. (JniEnv for normal and @FastNative)
27    PUSH_ARG rsi  // Arg.
28    PUSH_ARG rdx  // Arg.
29    PUSH_ARG rcx  // Arg.
30    // Create space for FPR args, plus padding for alignment
31    INCREASE_FRAME 72
32    // Save FPRs.
33    movq %xmm0, 0(%rsp)
34    movq %xmm1, 8(%rsp)
35    movq %xmm2, 16(%rsp)
36    movq %xmm3, 24(%rsp)
37    movq %xmm4, 32(%rsp)
38    movq %xmm5, 40(%rsp)
39    movq %xmm6, 48(%rsp)
40    movq %xmm7, 56(%rsp)
41    // prepare call
42    movq %gs:THREAD_SELF_OFFSET, %rdi      // RDI := Thread::Current()
43    // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable()
44    // for @FastNative or @CriticalNative.
45    movq THREAD_TOP_QUICK_FRAME_OFFSET(%rdi), %rax   // uintptr_t tagged_quick_frame
46    andq LITERAL(0xfffffffffffffffe), %rax           // ArtMethod** sp
47    movq (%rax), %rax                                // ArtMethod* method
48    testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \
49          ART_METHOD_ACCESS_FLAGS_OFFSET(%rax)
50    jne .Llookup_stub_fast_or_critical_native
51    call SYMBOL(artFindNativeMethod)  // (Thread*)
52    jmp .Llookup_stub_continue
53.Llookup_stub_fast_or_critical_native:
54    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
55.Llookup_stub_continue:
56    // restore arguments
57    movq 0(%rsp), %xmm0
58    movq 8(%rsp), %xmm1
59    movq 16(%rsp), %xmm2
60    movq 24(%rsp), %xmm3
61    movq 32(%rsp), %xmm4
62    movq 40(%rsp), %xmm5
63    movq 48(%rsp), %xmm6
64    movq 56(%rsp), %xmm7
65    DECREASE_FRAME 72
66    POP_ARG rcx  // Arg.
67    POP_ARG rdx  // Arg.
68    POP_ARG rsi  // Arg.
69    POP_ARG rdi  // Arg. (JniEnv for normal and @FastNative)
70    POP_ARG r8   // Arg.
71    POP_ARG r9   // Arg.
72    testq %rax, %rax              // check if returned method code is null
73    jz .Lno_native_code_found     // if null, jump to return to handle
74    jmp *%rax                     // otherwise, tail call to intended method
75.Lno_native_code_found:
76    ret
77END_FUNCTION art_jni_dlsym_lookup_stub
78
79DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub
80    // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is RAX.
81    // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
82    testq LITERAL(1), %rax
83    jnz art_jni_dlsym_lookup_stub
84
85    // Save GPR args and method.
86    PUSH_ARG r9
87    PUSH_ARG r8
88    PUSH_ARG rdi
89    PUSH_ARG rsi
90    PUSH_ARG rdx
91    PUSH_ARG rcx
92    PUSH_ARG rax
93    // Create space for FPR args.
94    INCREASE_FRAME 8 * 8
95    // Save FPRs.
96    movq %xmm0, 0(%rsp)
97    movq %xmm1, 8(%rsp)
98    movq %xmm2, 16(%rsp)
99    movq %xmm3, 24(%rsp)
100    movq %xmm4, 32(%rsp)
101    movq %xmm5, 40(%rsp)
102    movq %xmm6, 48(%rsp)
103    movq %xmm7, 56(%rsp)
104    // Note: It's the caller's responsibility to preserve xmm12-xmm15 as the tail call
105    // to native shall always risk clobbering those.
106
107    // Call artCriticalNativeFrameSize(method, caller_pc).
108    movq %rax, %rdi       // Pass the method from hidden arg.
109    movq 120(%rsp), %rsi  // Pass caller PC.
110    call SYMBOL(artCriticalNativeFrameSize)
111
112    // Restore registers.
113    movq 0(%rsp), %xmm0
114    movq 8(%rsp), %xmm1
115    movq 16(%rsp), %xmm2
116    movq 24(%rsp), %xmm3
117    movq 32(%rsp), %xmm4
118    movq 40(%rsp), %xmm5
119    movq 48(%rsp), %xmm6
120    movq 56(%rsp), %xmm7
121    DECREASE_FRAME 8 * 8
122    POP_ARG r10  // Restore method to R10.
123    POP_ARG rcx
124    POP_ARG rdx
125    POP_ARG rsi
126    POP_ARG rdi
127    POP_ARG r8
128    POP_ARG r9
129
130    // Load caller PC to R11 and redefine return PC for CFI.
131    movq (%rsp), %r11
132    CFI_REGISTER(%rip, %r11)
133
134    // Reserve space for a SaveRefsAndArgs managed frame, either for the actual runtime
135    // method or for a GenericJNI frame which is similar but has a native method and a tag.
136    INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__
137
138    // Calculate the number of QWORDs to move.
139    shrq LITERAL(3), %rax
140    jz .Lcritical_skip_copy_args
141
142    // Save RDI, RSI, RCX so that we can use them for moving stack args.
143    PUSH_ARG rdi
144    PUSH_ARG rsi
145    PUSH_ARG rcx
146
147    // Move the stack args.
148    movq %rax, %rcx
149    leaq 3 * __SIZEOF_POINTER__(%rsp), %rdi
150    leaq FRAME_SIZE_SAVE_REFS_AND_ARGS(%rdi), %rsi
151    rep movsq
152
153    // Restore RDI, RSI, RCX.
154    POP_ARG rcx
155    POP_ARG rsi
156    POP_ARG rdi
157
158.Lcritical_skip_copy_args:
159    // Calculate the base address of the managed frame.
160    leaq (%rsp, %rax, 8), %rax
161
162    // Spill registers for the SaveRefsAndArgs frame above the stack args.
163    // Note that the runtime shall not examine the args here, otherwise we would have to
164    // move them in registers and stack to account for the difference between managed and
165    // native ABIs. Do not update CFI while we hold the frame address in RAX and the values
166    // in registers are unchanged.
167    movq %r15, 192(%rax)
168    movq %r14, 184(%rax)
169    movq %r13, 176(%rax)
170    movq %r12, 168(%rax)
171    movq %r9, 160(%rax)
172    movq %r8, 152(%rax)
173    movq %rsi, 144(%rax)
174    movq %rbp, 136(%rax)
175    movq %rbx, 128(%rax)
176    movq %rdx, 120(%rax)
177    movq %rcx, 112(%rax)
178    movq %xmm0, 16(%rax)
179    movq %xmm1, 24(%rax)
180    movq %xmm2, 32(%rax)
181    movq %xmm3, 40(%rax)
182    movq %xmm4, 48(%rax)
183    movq %xmm5, 56(%rax)
184    movq %xmm6, 64(%rax)
185    movq %xmm7, 72(%rax)
186    // Skip managed ABI callee-saves xmm12-xmm15.
187
188    // Move the managed frame address to native callee-save register RBP and update CFI.
189    movq %rax, %rbp
190    CFI_EXPRESSION_BREG CFI_REG(r15), CFI_REG(rbp), 192
191    CFI_EXPRESSION_BREG CFI_REG(r14), CFI_REG(rbp), 184
192    CFI_EXPRESSION_BREG CFI_REG(r13), CFI_REG(rbp), 176
193    CFI_EXPRESSION_BREG CFI_REG(r12), CFI_REG(rbp), 168
194    // Skip args r9, r8, rsi.
195    CFI_EXPRESSION_BREG CFI_REG(rbp), CFI_REG(rbp), 136
196    CFI_EXPRESSION_BREG CFI_REG(rbx), CFI_REG(rbp), 128
197    // Skip args rdx, rcx.
198    // Skip args xmm0-xmm7.
199
200    leaq 1(%rbp), %rax            // Prepare managed SP tagged for a GenericJNI frame.
201    testl LITERAL(ACCESS_FLAGS_METHOD_IS_NATIVE), ART_METHOD_ACCESS_FLAGS_OFFSET(%r10)
202    jnz .Lcritical_skip_prepare_runtime_method
203
204    // Save the return PC for managed stack walk.
205    // (When coming from a compiled stub, the correct return PC is already there.)
206    movq %r11, FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%rbp)
207
208    // Replace the target method with the SaveRefsAndArgs runtime method.
209    LOAD_RUNTIME_INSTANCE r10
210    movq RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET(%r10), %r10
211
212    movq %rbp, %rax               // Prepare untagged managed SP for the runtime method.
213
214.Lcritical_skip_prepare_runtime_method:
215    // Store the method on the bottom of the managed frame.
216    movq %r10, (%rbp)
217
218    // Place (maybe tagged) managed SP in Thread::Current()->top_quick_frame.
219    movq %rax, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
220
221    // Save our return PC in the padding.
222    movq %r11, __SIZEOF_POINTER__(%rbp)
223    CFI_EXPRESSION_BREG CFI_REG(rip), CFI_REG(rbp), __SIZEOF_POINTER__
224
225    // Preserve the native arg register RDI in callee-save register RBX which was saved above.
226    movq %rdi, %rbx
227
228    // Call artFindNativeMethodRunnable()
229    movq %gs:THREAD_SELF_OFFSET, %rdi  // pass Thread::Current()
230    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
231
232    // Check for exception.
233    test %rax, %rax
234    jz .Lcritical_deliver_exception
235
236    CFI_REMEMBER_STATE
237
238    // Restore the native arg register RDI.
239    movq %rbx, %rdi
240
241    // Remember our return PC in R11.
242    movq __SIZEOF_POINTER__(%rbp), %r11
243    CFI_REGISTER(%rip, %r11)
244
245    // Remember the frame base address in r10 but do not redefine CFI.
246    movq %rbp, %r10
247
248    // Restore the frame. We shall not need the method anymore.
249    movq 16(%rbp), %xmm0
250    movq 24(%rbp), %xmm1
251    movq 32(%rbp), %xmm2
252    movq 40(%rbp), %xmm3
253    movq 48(%rbp), %xmm4
254    movq 56(%rbp), %xmm5
255    movq 64(%rbp), %xmm6
256    movq 72(%rbp), %xmm7
257    // Skip managed callee-saves xmm12-xmm15.
258    movq 112(%rbp), %rcx
259    movq 120(%rbp), %rdx
260    RESTORE_REG_BASE rbp, rbx, 128
261    // Delay restoring RBP as it's the managed frame base.
262    movq 144(%rbp), %rsi
263    movq 152(%rbp), %r8
264    movq 160(%rbp), %r9
265    RESTORE_REG_BASE rbp, r12, 168
266    RESTORE_REG_BASE rbp, r13, 176
267    RESTORE_REG_BASE rbp, r14, 184
268    RESTORE_REG_BASE rbp, r15, 192
269    // Restore RBP last.
270    RESTORE_REG_BASE rbp, rbp, 136
271
272    cmp %r10, %rsp
273    je .Lcritical_skip_copy_args_back
274
275    // Save RDI, RSI, RCX so that we can use them for moving stack args.
276    PUSH_ARG rdi
277    PUSH_ARG rsi
278    PUSH_ARG rcx
279
280    // Calculate the number of QWORDs to move.
281    leaq -3 * __SIZEOF_POINTER__(%r10), %rcx
282    subq %rsp, %rcx
283    shrq LITERAL(3), %rcx
284
285    // Move the stack args.
286    leaq -__SIZEOF_POINTER__(%r10), %rsi
287    leaq FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%r10), %rdi
288    std
289    rep movsq
290    cld
291
292    // Restore RDI, RSI, RCX.
293    POP_ARG rcx
294    POP_ARG rsi
295    POP_ARG rdi
296
297.Lcritical_skip_copy_args_back:
298    // Remove the frame reservation.
299    DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__
300
301    // Store our return PC.
302    movq %r11, (%rsp)
303    CFI_REL_OFFSET(%rip, 0)
304
305    // Do the tail call.
306    jmp *%rax
307    CFI_RESTORE_STATE_AND_DEF_CFA(%rbp, FRAME_SIZE_SAVE_REFS_AND_ARGS)
308
309.Lcritical_deliver_exception:
310    DELIVER_PENDING_EXCEPTION_FRAME_READY
311END_FUNCTION art_jni_dlsym_lookup_critical_stub
312