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    subq LITERAL(72), %rsp
32    CFI_ADJUST_CFA_OFFSET(72)
33    // Save FPRs.
34    movq %xmm0, 0(%rsp)
35    movq %xmm1, 8(%rsp)
36    movq %xmm2, 16(%rsp)
37    movq %xmm3, 24(%rsp)
38    movq %xmm4, 32(%rsp)
39    movq %xmm5, 40(%rsp)
40    movq %xmm6, 48(%rsp)
41    movq %xmm7, 56(%rsp)
42    // prepare call
43    movq %gs:THREAD_SELF_OFFSET, %rdi      // RDI := Thread::Current()
44    // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable()
45    // for @FastNative or @CriticalNative.
46    movq THREAD_TOP_QUICK_FRAME_OFFSET(%rdi), %rax   // uintptr_t tagged_quick_frame
47    andq LITERAL(0xfffffffffffffffe), %rax           // ArtMethod** sp
48    movq (%rax), %rax                                // ArtMethod* method
49    testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \
50          ART_METHOD_ACCESS_FLAGS_OFFSET(%rax)
51    jne .Llookup_stub_fast_native
52    call SYMBOL(artFindNativeMethod)  // (Thread*)
53    jmp .Llookup_stub_continue
54.Llookup_stub_fast_native:
55    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
56.Llookup_stub_continue:
57    // restore arguments
58    movq 0(%rsp), %xmm0
59    movq 8(%rsp), %xmm1
60    movq 16(%rsp), %xmm2
61    movq 24(%rsp), %xmm3
62    movq 32(%rsp), %xmm4
63    movq 40(%rsp), %xmm5
64    movq 48(%rsp), %xmm6
65    movq 56(%rsp), %xmm7
66    addq LITERAL(72), %rsp
67    CFI_ADJUST_CFA_OFFSET(-72)
68    POP_ARG rcx  // Arg.
69    POP_ARG rdx  // Arg.
70    POP_ARG rsi  // Arg.
71    POP_ARG rdi  // Arg. (JniEnv for normal and @FastNative)
72    POP_ARG r8   // Arg.
73    POP_ARG r9   // Arg.
74    testq %rax, %rax              // check if returned method code is null
75    jz .Lno_native_code_found     // if null, jump to return to handle
76    jmp *%rax                     // otherwise, tail call to intended method
77.Lno_native_code_found:
78    ret
79END_FUNCTION art_jni_dlsym_lookup_stub
80
81DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub
82    // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is r11.
83    // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
84    testq LITERAL(1), %r11
85    jnz art_jni_dlsym_lookup_stub
86
87    // We need to create a GenericJNI managed frame above the stack args.
88
89    // GenericJNI frame is similar to SaveRegsAndArgs frame with the native method
90    // instead of runtime method saved at the bottom.
91
92    // As we always have "stack args" on x86-64 (due to xmm12-xmm15 being callee-save
93    // in managed ABI but caller-save in native ABI), do not create a proper frame yet
94    // as we do on other architectures where it's useful for no stack args case.
95
96    // Reserve space for the frame (return PC is on stack).
97    subq MACRO_LITERAL(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__), %rsp
98    CFI_ADJUST_CFA_OFFSET(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__)
99
100    // Save GPR args.
101    PUSH_ARG r9
102    PUSH_ARG r8
103    PUSH_ARG rdi
104    PUSH_ARG rsi
105    PUSH_ARG rdx
106    PUSH_ARG rcx
107    // Create space for FPR args.
108    subq LITERAL(64), %rsp
109    CFI_ADJUST_CFA_OFFSET(64)
110    // Save FPRs.
111    movq %xmm0, 0(%rsp)
112    movq %xmm1, 8(%rsp)
113    movq %xmm2, 16(%rsp)
114    movq %xmm3, 24(%rsp)
115    movq %xmm4, 32(%rsp)
116    movq %xmm5, 40(%rsp)
117    movq %xmm6, 48(%rsp)
118    movq %xmm7, 56(%rsp)
119
120    // Add alignment padding.
121    subq MACRO_LITERAL(__SIZEOF_POINTER__), %rsp
122    CFI_ADJUST_CFA_OFFSET(__SIZEOF_POINTER__)
123    // Save hidden arg.
124    PUSH_ARG r11
125
126    // Call artCriticalNativeOutArgsSize(method).
127    movq %r11, %rdi  // Pass the method from hidden arg.
128    call SYMBOL(artCriticalNativeOutArgsSize)
129
130    // Calculate the address of the end of the move destination and redefine CFI to take
131    // ownership of the JNI stub frame.
132    leaq 16 * __SIZEOF_POINTER__(%rsp, %rax, 1), %r10  // 16 QWORDs of registers saved above.
133    CFI_DEF_CFA(%r10, FRAME_SIZE_SAVE_REFS_AND_ARGS)
134
135    // Calculate the number of QWORDs to move.
136    shrq LITERAL(3), %rax
137    leaq -1(%rax), %rcx  // Do not move the return PC.
138
139    // Load our return PC to EAX.
140    movq FRAME_SIZE_SAVE_REFS_AND_ARGS + (16 - 1) * __SIZEOF_POINTER__(%rsp), %rax
141
142    // Mov the stack args.
143    leaq 16 * __SIZEOF_POINTER__(%rsp), %rdi
144    leaq FRAME_SIZE_SAVE_REFS_AND_ARGS(%rdi), %rsi
145    rep movsq
146
147    // Save our return PC.
148    movq %rax, (%rdi)
149
150    // Pop the hidden arg and alignment padding.
151    popq %r11    // No `.cfi_adjust_cfa_offset`, CFA register is currently R10, not RSP.
152    addq MACRO_LITERAL(__SIZEOF_POINTER__), %rsp  // ditto
153
154    // Fill the SaveRefsAndArgs frame above the args, without actual args. Note that
155    // the runtime shall not examine the args here, otherwise we would have to move them in
156    // registers and stack to account for the difference between managed and native ABIs.
157    SAVE_REG_BASE r10, r15, 192
158    SAVE_REG_BASE r10, r14, 184
159    SAVE_REG_BASE r10, r13, 176
160    SAVE_REG_BASE r10, r12, 168
161    // Skip args r9, r8, rsi.
162    SAVE_REG_BASE r10, rbp, 136
163    SAVE_REG_BASE r10, rbx, 128
164    // Skip args rdx, rcx.
165    // Skip args xmm0-xmm7.
166    // Copy managed callee-saves xmm12-xmm15 from out args to the managed frame as they
167    // may theoretically store variables or unwinding data. (The compiled stub preserves
168    // them but the artCriticalNativeOutArgsSize() call above may clobber them.)
169    movq -5 * __SIZEOF_POINTER__(%r10), %xmm12
170    movq -4 * __SIZEOF_POINTER__(%r10), %xmm13
171    movq -3 * __SIZEOF_POINTER__(%r10), %xmm14
172    movq -2 * __SIZEOF_POINTER__(%r10), %xmm15
173    movq %xmm12, 80(%r10)
174    movq %xmm13, 88(%r10)
175    movq %xmm14, 96(%r10)
176    movq %xmm15, 104(%r10)
177    // Save the hidden arg as method pointer at the bottom of the stack.
178    movq %r11, (%r10)
179
180    // Move the frame register to a callee-save register.
181    movq %r10, %rbp
182    CFI_DEF_CFA_REGISTER(%rbp)
183
184    // Place tagged managed sp in Thread::Current()->top_quick_frame.
185    leaq 1(%rbp), %rax  // Tag as GenericJNI frame.
186    movq %rax, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
187
188    // Call artFindNativeMethodRunnable()
189    movq %gs:THREAD_SELF_OFFSET, %rdi  // pass Thread::Current()
190    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
191
192    // Check for exception.
193    test %rax, %rax
194    jz 2f
195
196    // Restore the frame. We shall not need the method anymore.
197    .cfi_remember_state
198    movq %rbp, %r10
199    CFI_DEF_CFA_REGISTER(%r10)
200    // Skip args xmm0-xmm7 and managed callee-saves xmm12-xmm15 (not needed for native call).
201    // Skip args rdx, rcx.
202    RESTORE_REG_BASE r10, rbx, 128
203    RESTORE_REG_BASE r10, rbp, 136
204    // Skip args r9, r8, rsi.
205    RESTORE_REG_BASE r10, r12, 168
206    RESTORE_REG_BASE r10, r13, 176
207    RESTORE_REG_BASE r10, r14, 184
208    RESTORE_REG_BASE r10, r15, 192
209
210    // Remember our return PC in R11.
211    movq -__SIZEOF_POINTER__(%r10), %r11
212
213    // Calculate the number of DWORDs to move.
214    leaq -(1 + 14) * __SIZEOF_POINTER__(%r10), %rcx  // Do not move return PC, 14 arg regs saved.
215    subq %rsp, %rcx
216    shrq LITERAL(3), %rcx
217
218    // Mov stack args to their original place.
219    leaq -2 * __SIZEOF_POINTER__(%r10), %rsi
220    leaq FRAME_SIZE_SAVE_REFS_AND_ARGS - 2 * __SIZEOF_POINTER__(%r10), %rdi
221    std
222    rep movsq
223    cld
224
225    // Store our return PC.
226    movq %r11, (%rdi)
227
228    // Redefine CFI to release ownership of the JNI stub frame.
229    CFI_DEF_CFA(%rsp, FRAME_SIZE_SAVE_REFS_AND_ARGS + 14 * __SIZEOF_POINTER__)
230
231    // Restore args.
232    movq 0(%rsp), %xmm0
233    movq 8(%rsp), %xmm1
234    movq 16(%rsp), %xmm2
235    movq 24(%rsp), %xmm3
236    movq 32(%rsp), %xmm4
237    movq 40(%rsp), %xmm5
238    movq 48(%rsp), %xmm6
239    movq 56(%rsp), %xmm7
240    addq LITERAL(64), %rsp
241    CFI_ADJUST_CFA_OFFSET(-64)
242    POP_ARG rcx
243    POP_ARG rdx
244    POP_ARG rsi
245    POP_ARG rdi
246    POP_ARG r8
247    POP_ARG r9
248
249    // Remove the frame reservation.
250    addq LITERAL(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__), %rsp
251    CFI_ADJUST_CFA_OFFSET(-(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__))
252
253    // Do the tail call.
254    jmp *%rax
255    CFI_RESTORE_STATE_AND_DEF_CFA(%rbp, FRAME_SIZE_SAVE_REFS_AND_ARGS)
256
2572:
258    // Drop the args from the stack (the r11 and padding was already removed).
259    addq LITERAL(14 * __SIZEOF_POINTER__), %rsp
260
261    DELIVER_PENDING_EXCEPTION_FRAME_READY
262END_FUNCTION art_jni_dlsym_lookup_critical_stub
263