File: jni_entrypoints_x86.S

package info (click to toggle)
android-platform-art 11.0.0%2Br48-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 78,932 kB
  • sloc: cpp: 459,858; java: 163,268; asm: 22,644; python: 9,815; sh: 6,330; ansic: 4,117; xml: 2,855; perl: 77; makefile: 73
file content (223 lines) | stat: -rw-r--r-- 8,586 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "asm_support_x86.S"

    /*
     * Jni dlsym lookup stub.
     */
DEFINE_FUNCTION art_jni_dlsym_lookup_stub
    subl LITERAL(8), %esp         // align stack
    CFI_ADJUST_CFA_OFFSET(8)
    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
    CFI_ADJUST_CFA_OFFSET(4)
    // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable()
    // for @FastNative or @CriticalNative.
    movl (%esp), %eax                                // Thread* self
    movl THREAD_TOP_QUICK_FRAME_OFFSET(%eax), %eax   // uintptr_t tagged_quick_frame
    andl LITERAL(0xfffffffe), %eax                   // ArtMethod** sp
    movl (%eax), %eax                                // ArtMethod* method
    testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \
          ART_METHOD_ACCESS_FLAGS_OFFSET(%eax)
    jne .Llookup_stub_fast_native
    call SYMBOL(artFindNativeMethod)  // (Thread*)
    jmp .Llookup_stub_continue
.Llookup_stub_fast_native:
    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
.Llookup_stub_continue:
    addl LITERAL(12), %esp        // remove argument & padding
    CFI_ADJUST_CFA_OFFSET(-12)
    testl %eax, %eax              // check if returned method code is null
    jz .Lno_native_code_found     // if null, jump to return to handle
    jmp *%eax                     // otherwise, tail call to intended method
.Lno_native_code_found:
    ret
END_FUNCTION art_jni_dlsym_lookup_stub

DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub
    // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is eax.
    // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
    testl LITERAL(1), %eax
    jnz art_jni_dlsym_lookup_stub

    // We need to create a GenericJNI managed frame above the stack args.

    // GenericJNI frame is similar to SaveRegsAndArgs frame with the native method
    // instead of runtime method saved at the bottom. Note that the runtime shall
    // not examine the args here, otherwise we would have to reload them from stack
    // to account for the difference between managed and native ABIs.
    SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
    pushl %eax  // Save the hidden arg as method pointer at the bottom of the stack.
    CFI_ADJUST_CFA_OFFSET(4)

    // Call artCriticalNativeOutArgsSize(method); method is conveniently at the bottom of the stack.
    call SYMBOL(artCriticalNativeOutArgsSize)

    // Check if we have any stack args other than return PC.
    cmp LITERAL(__SIZEOF_POINTER__), %eax
    jnz .Lcritical_has_stack_args

    // Without stack args, the frame is fully constructed.
    // Place tagged managed sp in Thread::Current()->top_quick_frame.
    leal 1(%esp), %eax  // Tag as GenericJNI frame.
    mov %eax, %fs:THREAD_TOP_QUICK_FRAME_OFFSET

    // Call artFindNativeMethodRunnable()
    subl LITERAL(12), %esp         // align stack
    CFI_ADJUST_CFA_OFFSET(12)
    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
    CFI_ADJUST_CFA_OFFSET(4)
    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
    addl LITERAL(16), %esp
    CFI_ADJUST_CFA_OFFSET(-16)

    // Check for exception.
    test %eax, %eax
    jz 1f

    // Restore frame and do the tail call.
    CFI_REMEMBER_STATE
    RESTORE_SAVE_REFS_AND_ARGS_FRAME
    jmp *%eax
    CFI_RESTORE_STATE_AND_DEF_CFA %esp, FRAME_SIZE_SAVE_REFS_AND_ARGS

1:
    DELIVER_PENDING_EXCEPTION_FRAME_READY

.Lcritical_has_stack_args:
    // As mentioned above, the runtime shall not examine the args in the managed frame
    // and since all args for the native call are on the stack, we can use the managed
    // args registers as scratch registers. So, EBX, EDX and ECX are available and we
    // do not need to restore xmm0-xmm3 either.

    // Restore registers as we're about to move stack args over the current SaveRefsAndArgs frame.
    movl (%esp), %edx   // Remember the method in EDX.
    movl 48(%esp), %ebp
    CFI_RESTORE(%ebp)
    movl 52(%esp), %esi
    CFI_RESTORE(%esi)
    movl 56(%esp), %edi
    CFI_RESTORE(%edi)

    // Calculate the address of the end of the move destination and redefine CFI to take
    // ownership of the JNI stub frame. EBX is conveniently callee-save in native ABI.
    leal 0(%esp, %eax, 1), %ebx
    CFI_DEF_CFA(%ebx, FRAME_SIZE_SAVE_REFS_AND_ARGS)

    // Calculate the number of DWORDs to move.
    shrl LITERAL(2), %eax
    leal -1(%eax), %ecx  // Do not move the return PC.

    // Load our return PC to EAX.
    movl FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%esp), %eax

    // Save EDI, ESI so that we can use them for moving stack args.
    pushl %edi  // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
    pushl %esi  // ditto

    // Mov the stack args.
    leal 2 * __SIZEOF_POINTER__(%esp), %edi
    leal FRAME_SIZE_SAVE_REFS_AND_ARGS(%edi), %esi
    rep movsd

    // Save our return PC.
    movl %eax, (%edi)

    // Restore EDI, ESI.
    popl %esi   // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
    popl %edi   // ditto

    // Re-create the SaveRefsAndArgs frame above the args.
    movl %edi, 56(%ebx)
    CFI_REL_OFFSET(%edi, 56)
    movl %esi, 52(%ebx)
    CFI_REL_OFFSET(%esi, 52)
    movl %ebp, 48(%ebx)
    CFI_REL_OFFSET(%ebp, 48)
    // Skip managed ABI args EBX, EDX, ECX and FPRs, see above.
    // (We have already clobbered EBX, EDX, ECX anyway).
    movl %edx, (%ebx)    // Save method pointer.

    // Place tagged managed sp in Thread::Current()->top_quick_frame.
    leal 1(%ebx), %eax  // Tag as GenericJNI frame.
    movl %eax, %fs:THREAD_TOP_QUICK_FRAME_OFFSET

    // Call artFindNativeMethodRunnable()
    subl LITERAL(12), %esp        // align stack, no `CFI_ADJUST_CFA_OFFSET`.
    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
    call SYMBOL(artFindNativeMethodRunnable)  // (Thread*)
    addl LITERAL(16), %esp        // Pop args, no `CFI_ADJUST_CFA_OFFSET`.

    // Check for exception.
    test %eax, %eax
    jz 2f

    // Restore the frame. We shall not need the method anymore.
    CFI_REMEMBER_STATE
    movl 48(%ebx), %ebp
    CFI_RESTORE(%ebp)
    movl 52(%ebx), %esi
    CFI_RESTORE(%esi)
    movl 56(%ebx), %edi
    CFI_RESTORE(%edi)

    // Remember our return PC in EDX.
    movl -__SIZEOF_POINTER__(%ebx), %edx

    // Calculate the number of DWORDs to move.
    leal -__SIZEOF_POINTER__(%ebx), %ecx  // Do not move return PC.
    subl %esp, %ecx
    shrl LITERAL(2), %ecx

    // Save EDI, ESI so that we can use them for moving stack args.
    pushl %edi  // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
    pushl %esi  // ditto

    // Mov stack args to their original place.
    leal -2 * __SIZEOF_POINTER__(%ebx), %esi
    leal FRAME_SIZE_SAVE_REFS_AND_ARGS - 2 * __SIZEOF_POINTER__(%ebx), %edi
    std
    rep movsd
    cld

    // Store our return PC.
    movl %edx, (%edi)

    // Restore EDI, ESI.
    popl %esi   // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP.
    popl %edi   // ditto

    // Redefine CFI to release ownership of the JNI stub frame.
    CFI_DEF_CFA(%esp, FRAME_SIZE_SAVE_REFS_AND_ARGS)

    // Remove the frame reservation.
    addl LITERAL(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__), %esp
    CFI_ADJUST_CFA_OFFSET(-FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__)

    // Do the tail call.
    jmp *%eax
    CFI_RESTORE_STATE_AND_DEF_CFA %ebx, FRAME_SIZE_SAVE_REFS_AND_ARGS

2:
    // Replicate DELIVER_PENDING_EXCEPTION_FRAME_READY without CFI_ADJUST_CFA_OFFSET,
    // CFA register is currently EBX, not ESP.

    // Outgoing argument set up
    subl MACRO_LITERAL(12), %esp               // alignment padding
    pushl %fs:THREAD_SELF_OFFSET               // pass Thread::Current()
    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*)
    UNREACHABLE
END_FUNCTION art_jni_dlsym_lookup_critical_stub