quick_entrypoints_x86.S revision 166db04e259ca51838c311891598664deeed85ad
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.h"
18
19#if defined(__APPLE__)
20    // Mac OS' as(1) doesn't let you name macro parameters.
21    #define MACRO0(macro_name) .macro macro_name
22    #define MACRO1(macro_name, macro_arg1) .macro macro_name
23    #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name
24    #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name
25    #define END_MACRO .endmacro
26
27    // Mac OS' as(1) uses $0, $1, and so on for macro arguments, and function names
28    // are mangled with an extra underscore prefix. The use of $x for arguments
29    // mean that literals need to be represented with $$x in macros.
30    #define SYMBOL(name) _ ## name
31    #define VAR(name,index) SYMBOL($index)
32    #define REG_VAR(name,index) %$index
33    #define CALL_MACRO(name,index) $index
34    #define LITERAL(value) $value
35    #define MACRO_LITERAL(value) $$value
36#else
37    // Regular gas(1) lets you name macro parameters.
38    #define MACRO0(macro_name) .macro macro_name
39    #define MACRO1(macro_name, macro_arg1) .macro macro_name macro_arg1
40    #define MACRO2(macro_name, macro_arg1, macro_arg2) .macro macro_name macro_arg1, macro_arg2
41    #define MACRO3(macro_name, macro_arg1, macro_arg2, macro_arg3) .macro macro_name macro_arg1, macro_arg2, macro_arg3
42    #define END_MACRO .endm
43
44    // Regular gas(1) uses \argument_name for macro arguments.
45    // We need to turn on alternate macro syntax so we can use & instead or the preprocessor
46    // will screw us by inserting a space between the \ and the name. Even in this mode there's
47    // no special meaning to $, so literals are still just $x. The use of altmacro means % is a
48    // special character meaning care needs to be taken when passing registers as macro arguments.
49    .altmacro
50    #define SYMBOL(name) name
51    #define VAR(name,index) name&
52    #define REG_VAR(name,index) %name
53    #define CALL_MACRO(name,index) name&
54    #define LITERAL(value) $value
55    #define MACRO_LITERAL(value) $value
56#endif
57
58    /* Cache alignment for function entry */
59MACRO0(ALIGN_FUNCTION_ENTRY)
60    .balign 16
61END_MACRO
62
63MACRO1(DEFINE_FUNCTION, c_name)
64    .type VAR(c_name, 0), @function
65    .globl VAR(c_name, 0)
66    ALIGN_FUNCTION_ENTRY
67VAR(c_name, 0):
68    .cfi_startproc
69END_MACRO
70
71MACRO1(END_FUNCTION, c_name)
72    .cfi_endproc
73    .size \c_name, .-\c_name
74END_MACRO
75
76MACRO1(PUSH, reg)
77  pushl REG_VAR(reg, 0)
78  .cfi_adjust_cfa_offset 4
79  .cfi_rel_offset REG_VAR(reg, 0), 0
80END_MACRO
81
82MACRO1(POP, reg)
83  popl REG_VAR(reg,0)
84  .cfi_adjust_cfa_offset -4
85  .cfi_restore REG_VAR(reg,0)
86END_MACRO
87
88    /*
89     * Macro that sets up the callee save frame to conform with
90     * Runtime::CreateCalleeSaveMethod(kSaveAll)
91     */
92MACRO0(SETUP_SAVE_ALL_CALLEE_SAVE_FRAME)
93    PUSH edi  // Save callee saves (ebx is saved/restored by the upcall)
94    PUSH esi
95    PUSH ebp
96    subl  MACRO_LITERAL(16), %esp  // Grow stack by 4 words, bottom word will hold Method*
97    .cfi_adjust_cfa_offset 16
98END_MACRO
99
100    /*
101     * Macro that sets up the callee save frame to conform with
102     * Runtime::CreateCalleeSaveMethod(kRefsOnly)
103     */
104MACRO0(SETUP_REF_ONLY_CALLEE_SAVE_FRAME)
105    PUSH edi  // Save callee saves (ebx is saved/restored by the upcall)
106    PUSH esi
107    PUSH ebp
108    subl  MACRO_LITERAL(16), %esp  // Grow stack by 4 words, bottom word will hold Method*
109    .cfi_adjust_cfa_offset 16
110END_MACRO
111
112MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
113    addl MACRO_LITERAL(28), %esp  // Unwind stack up to return address
114    .cfi_adjust_cfa_offset -28
115END_MACRO
116
117    /*
118     * Macro that sets up the callee save frame to conform with
119     * Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
120     */
121MACRO0(SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME)
122    PUSH edi  // Save callee saves
123    PUSH esi
124    PUSH ebp
125    PUSH ebx  // Save args
126    PUSH edx
127    PUSH ecx
128    PUSH eax   // Align stack, eax will be clobbered by Method*
129END_MACRO
130
131MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME)
132    addl MACRO_LITERAL(4), %esp  // Remove padding
133    .cfi_adjust_cfa_offset -4
134    POP ecx  // Restore args except eax
135    POP edx
136    POP ebx
137    POP ebp  // Restore callee saves
138    POP esi
139    POP edi
140END_MACRO
141
142    /*
143     * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
144     * exception is Thread::Current()->exception_.
145     */
146MACRO0(DELIVER_PENDING_EXCEPTION)
147    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME         // save callee saves for throw
148    mov %esp, %ecx
149    // Outgoing argument set up
150    subl  MACRO_LITERAL(8), %esp             // Alignment padding
151    .cfi_adjust_cfa_offset 8
152    PUSH ecx                                 // pass SP
153    pushl %fs:THREAD_SELF_OFFSET             // pass Thread::Current()
154    .cfi_adjust_cfa_offset 4
155    call SYMBOL(artDeliverPendingExceptionFromCode)  // artDeliverPendingExceptionFromCode(Thread*, SP)
156    int3                                     // unreached
157END_MACRO
158
159MACRO2(NO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
160    DEFINE_FUNCTION VAR(c_name, 0)
161    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
162    mov %esp, %ecx
163    // Outgoing argument set up
164    subl  MACRO_LITERAL(8), %esp  // alignment padding
165    .cfi_adjust_cfa_offset 8
166    PUSH ecx                      // pass SP
167    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
168    .cfi_adjust_cfa_offset 4
169    call VAR(cxx_name, 1)         // cxx_name(Thread*, SP)
170    int3                          // unreached
171    END_FUNCTION VAR(c_name, 0)
172END_MACRO
173
174MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
175    DEFINE_FUNCTION VAR(c_name, 0)
176    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
177    mov %esp, %ecx
178    // Outgoing argument set up
179    PUSH eax                      // alignment padding
180    PUSH ecx                      // pass SP
181    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
182    .cfi_adjust_cfa_offset 4
183    PUSH eax                      // pass arg1
184    call VAR(cxx_name, 1)         // cxx_name(arg1, Thread*, SP)
185    int3                          // unreached
186    END_FUNCTION VAR(c_name, 0)
187END_MACRO
188
189MACRO2(TWO_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
190    DEFINE_FUNCTION VAR(c_name, 0)
191    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
192    mov %esp, %edx
193    // Outgoing argument set up
194    PUSH edx                      // pass SP
195    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
196    .cfi_adjust_cfa_offset 4
197    PUSH ecx                      // pass arg2
198    PUSH eax                      // pass arg1
199    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, Thread*, SP)
200    int3                          // unreached
201    END_FUNCTION VAR(c_name, 0)
202END_MACRO
203
204    /*
205     * Called by managed code to create and deliver a NullPointerException.
206     */
207NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception_from_code, artThrowNullPointerExceptionFromCode
208
209    /*
210     * Called by managed code to create and deliver an ArithmeticException.
211     */
212NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero_from_code, artThrowDivZeroFromCode
213
214    /*
215     * Called by managed code to create and deliver a StackOverflowError.
216     */
217NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow_from_code, artThrowStackOverflowFromCode
218
219    /*
220     * Called by managed code, saves callee saves and then calls artThrowException
221     * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
222     */
223ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception_from_code, artDeliverExceptionFromCode
224
225    /*
226     * Called by managed code to create and deliver a NoSuchMethodError.
227     */
228ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method_from_code, artThrowNoSuchMethodFromCode
229
230    /*
231     * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
232     * index, arg2 holds limit.
233     */
234TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds_from_code, artThrowArrayBoundsFromCode
235
236    /*
237     * All generated callsites for interface invokes and invocation slow paths will load arguments
238     * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
239     * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
240     * stack and call the appropriate C helper.
241     * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
242     *
243     * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
244     * of the target Method* in r0 and method->code_ in r1.
245     *
246     * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the
247     * thread and we branch to another stub to deliver it.
248     *
249     * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
250     * pointing back to the original caller.
251     */
252MACRO2(INVOKE_TRAMPOLINE, c_name, cxx_name)
253    DEFINE_FUNCTION VAR(c_name, 0)
254    // Set up the callee save frame to conform with Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
255    // return address
256    PUSH edi
257    PUSH esi
258    PUSH ebp
259    PUSH ebx
260    PUSH edx
261    PUSH ecx
262    PUSH eax   // <-- callee save Method* to go here
263    movl %esp, %edx  // remember SP
264    // Outgoing argument set up
265    subl MACRO_LITERAL(12), %esp  // alignment padding
266    .cfi_adjust_cfa_offset 12
267    PUSH edx                      // pass SP
268    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
269    .cfi_adjust_cfa_offset 4
270    pushl 32(%edx)                // pass caller Method*
271    .cfi_adjust_cfa_offset 4
272    PUSH ecx                      // pass arg2
273    PUSH eax                      // pass arg1
274    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, arg3, Thread*, SP)
275    movl %edx, %edi               // save code pointer in EDI
276    addl MACRO_LITERAL(36), %esp  // Pop arguments skip eax
277    .cfi_adjust_cfa_offset -36
278    POP ecx                       // Restore args
279    POP edx
280    POP ebx
281    POP ebp  // Restore callee saves.
282    POP esi
283    // Swap EDI callee save with code pointer.
284    xchgl %edi, (%esp)
285    testl %eax, %eax              // Branch forward if exception pending.
286    jz    1f
287    // Tail call to intended method.
288    ret
2891:
290    addl MACRO_LITERAL(4), %esp   // Pop code pointer off stack
291    .cfi_adjust_cfa_offset -4
292    DELIVER_PENDING_EXCEPTION
293    END_FUNCTION VAR(c_name, 0)
294END_MACRO
295
296INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
297INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
298
299INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
300INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
301INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
302INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
303
304    /*
305     * Portable invocation stub.
306     * On entry:
307     *   [sp] = return address
308     *   [sp + 4] = method pointer
309     *   [sp + 8] = argument array or NULL for no argument methods
310     *   [sp + 12] = size of argument array in bytes
311     *   [sp + 16] = (managed) thread pointer
312     *   [sp + 20] = JValue* result
313     *   [sp + 24] = result type char
314     */
315DEFINE_FUNCTION art_portable_invoke_stub
316    PUSH ebp                      // save ebp
317    PUSH ebx                      // save ebx
318    mov %esp, %ebp                // copy value of stack pointer into base pointer
319    .cfi_def_cfa_register ebp
320    mov 20(%ebp), %ebx            // get arg array size
321    addl LITERAL(28), %ebx        // reserve space for return addr, method*, ebx, and ebp in frame
322    andl LITERAL(0xFFFFFFF0), %ebx    // align frame size to 16 bytes
323    subl LITERAL(12), %ebx        // remove space for return address, ebx, and ebp
324    subl %ebx, %esp               // reserve stack space for argument array
325    lea  4(%esp), %eax            // use stack pointer + method ptr as dest for memcpy
326    pushl 20(%ebp)                // push size of region to memcpy
327    pushl 16(%ebp)                // push arg array as source of memcpy
328    pushl %eax                    // push stack pointer as destination of memcpy
329    call SYMBOL(memcpy)           // (void*, const void*, size_t)
330    addl LITERAL(12), %esp        // pop arguments to memcpy
331    mov 12(%ebp), %eax            // move method pointer into eax
332    mov %eax, (%esp)              // push method pointer onto stack
333    call *METHOD_CODE_OFFSET(%eax) // call the method
334    mov %ebp, %esp                // restore stack pointer
335    POP ebx                       // pop ebx
336    POP ebp                       // pop ebp
337    mov 20(%esp), %ecx            // get result pointer
338    cmpl LITERAL(68), 24(%esp)    // test if result type char == 'D'
339    je return_double_portable
340    cmpl LITERAL(70), 24(%esp)    // test if result type char == 'F'
341    je return_float_portable
342    mov %eax, (%ecx)              // store the result
343    mov %edx, 4(%ecx)             // store the other half of the result
344    ret
345return_double_portable:
346    fstpl (%ecx)                  // store the floating point result as double
347    ret
348return_float_portable:
349    fstps (%ecx)                  // store the floating point result as float
350    ret
351END_FUNCTION art_portable_invoke_stub
352
353    /*
354     * Quick invocation stub.
355     * On entry:
356     *   [sp] = return address
357     *   [sp + 4] = method pointer
358     *   [sp + 8] = argument array or NULL for no argument methods
359     *   [sp + 12] = size of argument array in bytes
360     *   [sp + 16] = (managed) thread pointer
361     *   [sp + 20] = JValue* result
362     *   [sp + 24] = result type char
363     */
364DEFINE_FUNCTION art_quick_invoke_stub
365    PUSH ebp                      // save ebp
366    PUSH ebx                      // save ebx
367    mov %esp, %ebp                // copy value of stack pointer into base pointer
368    .cfi_def_cfa_register ebp
369    mov 20(%ebp), %ebx            // get arg array size
370    addl LITERAL(28), %ebx        // reserve space for return addr, method*, ebx, and ebp in frame
371    andl LITERAL(0xFFFFFFF0), %ebx    // align frame size to 16 bytes
372    subl LITERAL(12), %ebx        // remove space for return address, ebx, and ebp
373    subl %ebx, %esp               // reserve stack space for argument array
374    lea  4(%esp), %eax            // use stack pointer + method ptr as dest for memcpy
375    pushl 20(%ebp)                // push size of region to memcpy
376    pushl 16(%ebp)                // push arg array as source of memcpy
377    pushl %eax                    // push stack pointer as destination of memcpy
378    call SYMBOL(memcpy)           // (void*, const void*, size_t)
379    addl LITERAL(12), %esp        // pop arguments to memcpy
380    movl LITERAL(0), (%esp)       // store NULL for method*
381    mov 12(%ebp), %eax            // move method pointer into eax
382    mov 4(%esp), %ecx             // copy arg1 into ecx
383    mov 8(%esp), %edx             // copy arg2 into edx
384    mov 12(%esp), %ebx            // copy arg3 into ebx
385    call *METHOD_CODE_OFFSET(%eax) // call the method
386    mov %ebp, %esp                // restore stack pointer
387    POP ebx                       // pop ebx
388    POP ebp                       // pop ebp
389    mov 20(%esp), %ecx            // get result pointer
390    cmpl LITERAL(68), 24(%esp)    // test if result type char == 'D'
391    je return_double_quick
392    cmpl LITERAL(70), 24(%esp)    // test if result type char == 'F'
393    je return_float_quick
394    mov %eax, (%ecx)              // store the result
395    mov %edx, 4(%ecx)             // store the other half of the result
396    ret
397return_double_quick:
398return_float_quick:
399    movsd %xmm0, (%ecx)           // store the floating point result
400    ret
401END_FUNCTION art_quick_invoke_stub
402
403MACRO3(NO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
404    DEFINE_FUNCTION VAR(c_name, 0)
405    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
406    mov %esp, %edx                // remember SP
407    // Outgoing argument set up
408    subl MACRO_LITERAL(8), %esp   // push padding
409    .cfi_adjust_cfa_offset 8
410    PUSH edx                      // pass SP
411    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
412    .cfi_adjust_cfa_offset 4
413    call VAR(cxx_name, 1)         // cxx_name(Thread*, SP)
414    addl MACRO_LITERAL(16), %esp  // pop arguments
415    .cfi_adjust_cfa_offset -16
416    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
417    CALL_MACRO(return_macro, 2)   // return or deliver exception
418    END_FUNCTION VAR(c_name, 0)
419END_MACRO
420
421MACRO3(ONE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
422    DEFINE_FUNCTION VAR(c_name, 0)
423    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
424    mov %esp, %edx                // remember SP
425    // Outgoing argument set up
426    PUSH eax                      // push padding
427    PUSH edx                      // pass SP
428    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
429    .cfi_adjust_cfa_offset 4
430    PUSH eax                      // pass arg1
431    call VAR(cxx_name, 1)         // cxx_name(arg1, Thread*, SP)
432    addl MACRO_LITERAL(16), %esp  // pop arguments
433    .cfi_adjust_cfa_offset -16
434    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
435    CALL_MACRO(return_macro, 2)   // return or deliver exception
436    END_FUNCTION VAR(c_name, 0)
437END_MACRO
438
439MACRO3(TWO_ARG_DOWNCALL, c_name, cxx_name, return_macro)
440    DEFINE_FUNCTION VAR(c_name, 0)
441    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
442    mov %esp, %edx                // remember SP
443    // Outgoing argument set up
444    PUSH edx                      // pass SP
445    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
446    .cfi_adjust_cfa_offset 4
447    PUSH ecx                      // pass arg2
448    PUSH eax                      // pass arg1
449    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, Thread*, SP)
450    addl MACRO_LITERAL(16), %esp  // pop arguments
451    .cfi_adjust_cfa_offset -16
452    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
453    CALL_MACRO(return_macro, 2)   // return or deliver exception
454    END_FUNCTION VAR(c_name, 0)
455END_MACRO
456
457MACRO3(THREE_ARG_DOWNCALL, c_name, cxx_name, return_macro)
458    DEFINE_FUNCTION VAR(c_name, 0)
459    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
460    mov %esp, %ebx                // remember SP
461    // Outgoing argument set up
462    subl MACRO_LITERAL(12), %esp  // alignment padding
463    .cfi_adjust_cfa_offset 12
464    PUSH ebx                      // pass SP
465    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
466    .cfi_adjust_cfa_offset 4
467    PUSH edx                      // pass arg3
468    PUSH ecx                      // pass arg2
469    PUSH eax                      // pass arg1
470    call VAR(cxx_name, 1)         // cxx_name(arg1, arg2, arg3, Thread*, SP)
471    addl MACRO_LITERAL(32), %esp  // pop arguments
472    .cfi_adjust_cfa_offset -32
473    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
474    CALL_MACRO(return_macro, 2)   // return or deliver exception
475    END_FUNCTION VAR(c_name, 0)
476END_MACRO
477
478MACRO0(RETURN_IF_EAX_NOT_ZERO)
479    testl %eax, %eax               // eax == 0 ?
480    jz  1f                         // if eax == 0 goto 1
481    ret                            // return
4821:                                 // deliver exception on current thread
483    DELIVER_PENDING_EXCEPTION
484END_MACRO
485
486MACRO0(RETURN_IF_EAX_ZERO)
487    testl %eax, %eax               // eax == 0 ?
488    jnz  1f                        // if eax != 0 goto 1
489    ret                            // return
4901:                                 // deliver exception on current thread
491    DELIVER_PENDING_EXCEPTION
492END_MACRO
493
494MACRO0(RETURN_OR_DELIVER_PENDING_EXCEPTION)
495    mov %fs:THREAD_EXCEPTION_OFFSET, %ebx // get exception field
496    testl %ebx, %ebx               // ebx == 0 ?
497    jnz 1f                         // if ebx != 0 goto 1
498    ret                            // return
4991:                                 // deliver exception on current thread
500    DELIVER_PENDING_EXCEPTION
501END_MACRO
502
503TWO_ARG_DOWNCALL art_quick_alloc_object_from_code, artAllocObjectFromCode, RETURN_IF_EAX_NOT_ZERO
504TWO_ARG_DOWNCALL art_quick_alloc_object_from_code_with_access_check, artAllocObjectFromCodeWithAccessCheck, RETURN_IF_EAX_NOT_ZERO
505THREE_ARG_DOWNCALL art_quick_alloc_array_from_code, artAllocArrayFromCode, RETURN_IF_EAX_NOT_ZERO
506THREE_ARG_DOWNCALL art_quick_alloc_array_from_code_with_access_check, artAllocArrayFromCodeWithAccessCheck, RETURN_IF_EAX_NOT_ZERO
507THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_from_code, artCheckAndAllocArrayFromCode, RETURN_IF_EAX_NOT_ZERO
508THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_from_code_with_access_check, artCheckAndAllocArrayFromCodeWithAccessCheck, RETURN_IF_EAX_NOT_ZERO
509
510TWO_ARG_DOWNCALL art_quick_resolve_string_from_code, artResolveStringFromCode, RETURN_IF_EAX_NOT_ZERO
511TWO_ARG_DOWNCALL art_quick_initialize_static_storage_from_code, artInitializeStaticStorageFromCode, RETURN_IF_EAX_NOT_ZERO
512TWO_ARG_DOWNCALL art_quick_initialize_type_from_code, artInitializeTypeFromCode, RETURN_IF_EAX_NOT_ZERO
513TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access_from_code, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_EAX_NOT_ZERO
514
515ONE_ARG_DOWNCALL art_quick_lock_object_from_code, artLockObjectFromCode, ret
516ONE_ARG_DOWNCALL art_quick_unlock_object_from_code, artUnlockObjectFromCode, RETURN_IF_EAX_ZERO
517
518TWO_ARG_DOWNCALL art_quick_handle_fill_data_from_code, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
519
520DEFINE_FUNCTION art_quick_is_assignable_from_code
521    PUSH eax                     // alignment padding
522    PUSH ecx                    // pass arg2
523    PUSH eax                     // pass arg1
524    call SYMBOL(artIsAssignableFromCode)  // (Class* a, Class* b, Thread*, SP)
525    addl LITERAL(12), %esp        // pop arguments
526    .cfi_adjust_cfa_offset -12
527    ret
528END_FUNCTION art_quick_is_assignable_from_code
529
530DEFINE_FUNCTION art_quick_memcpy
531    PUSH edx                      // pass arg3
532    PUSH ecx                      // pass arg2
533    PUSH eax                      // pass arg1
534    call SYMBOL(memcpy)           // (void*, const void*, size_t)
535    addl LITERAL(12), %esp        // pop arguments
536    .cfi_adjust_cfa_offset -12
537    ret
538END_FUNCTION art_quick_memcpy
539
540TWO_ARG_DOWNCALL art_quick_check_cast_from_code, artCheckCastFromCode, RETURN_IF_EAX_ZERO
541TWO_ARG_DOWNCALL art_quick_can_put_array_element_from_code, artCanPutArrayElementFromCode, RETURN_IF_EAX_ZERO
542
543NO_ARG_DOWNCALL art_quick_test_suspend, artTestSuspendFromCode, ret
544
545DEFINE_FUNCTION art_quick_fmod_from_code
546    subl LITERAL(12), %esp        // alignment padding
547    .cfi_adjust_cfa_offset 12
548    PUSH ebx                      // pass arg4 b.hi
549    PUSH edx                      // pass arg3 b.lo
550    PUSH ecx                      // pass arg2 a.hi
551    PUSH eax                      // pass arg1 a.lo
552    call SYMBOL(fmod)             // (jdouble a, jdouble b)
553    fstpl (%esp)                  // pop return value off fp stack
554    movsd (%esp), %xmm0           // place into %xmm0
555    addl LITERAL(28), %esp        // pop arguments
556    .cfi_adjust_cfa_offset -28
557    ret
558END_FUNCTION art_quick_fmod_from_code
559
560DEFINE_FUNCTION art_quick_fmodf_from_code
561    PUSH eax                      // alignment padding
562    PUSH ecx                      // pass arg2 b
563    PUSH eax                      // pass arg1 a
564    call SYMBOL(fmodf)            // (jfloat a, jfloat b)
565    fstps (%esp)                  // pop return value off fp stack
566    movss (%esp), %xmm0           // place into %xmm0
567    addl LITERAL(12), %esp        // pop arguments
568    .cfi_adjust_cfa_offset -12
569    ret
570END_FUNCTION art_quick_fmodf_from_code
571
572DEFINE_FUNCTION art_quick_l2d_from_code
573    PUSH ecx                      // push arg2 a.hi
574    PUSH eax                      // push arg1 a.lo
575    fildll (%esp)                 // load as integer and push into st0
576    fstpl (%esp)                  // pop value off fp stack as double
577    movsd (%esp), %xmm0           // place into %xmm0
578    addl LITERAL(8), %esp         // pop arguments
579    .cfi_adjust_cfa_offset -8
580    ret
581END_FUNCTION art_quick_l2d_from_code
582
583DEFINE_FUNCTION art_quick_l2f_from_code
584    PUSH ecx                      // push arg2 a.hi
585    PUSH eax                      // push arg1 a.lo
586    fildll (%esp)                 // load as integer and push into st0
587    fstps (%esp)                  // pop value off fp stack as a single
588    movss (%esp), %xmm0           // place into %xmm0
589    addl LITERAL(8), %esp         // pop argument
590    .cfi_adjust_cfa_offset -8
591    ret
592END_FUNCTION art_quick_l2f_from_code
593
594DEFINE_FUNCTION art_quick_d2l_from_code
595    PUSH eax                      // alignment padding
596    PUSH ecx                      // pass arg2 a.hi
597    PUSH eax                      // pass arg1 a.lo
598    call SYMBOL(art_d2l)          // (jdouble a)
599    addl LITERAL(12), %esp        // pop arguments
600    .cfi_adjust_cfa_offset -12
601    ret
602END_FUNCTION art_quick_d2l_from_code
603
604DEFINE_FUNCTION art_quick_f2l_from_code
605    subl LITERAL(8), %esp         // alignment padding
606    .cfi_adjust_cfa_offset 8
607    PUSH eax                      // pass arg1 a
608    call SYMBOL(art_f2l)          // (jfloat a)
609    addl LITERAL(12), %esp        // pop arguments
610    .cfi_adjust_cfa_offset -12
611    ret
612END_FUNCTION art_quick_f2l_from_code
613
614DEFINE_FUNCTION art_quick_idivmod_from_code
615    cmpl LITERAL(0x80000000), %eax
616    je check_arg2  // special case
617args_ok:
618    cdq         // edx:eax = sign extend eax
619    idiv %ecx   // (edx,eax) = (edx:eax % ecx, edx:eax / ecx)
620    ret
621check_arg2:
622    cmpl LITERAL(-1), %ecx
623    jne args_ok
624    xorl %edx, %edx
625    ret         // eax already holds min int
626END_FUNCTION art_quick_idivmod_from_code
627
628DEFINE_FUNCTION art_quick_ldiv_from_code
629    subl LITERAL(12), %esp        // alignment padding
630    .cfi_adjust_cfa_offset 12
631    PUSH ebx                     // pass arg4 b.hi
632    PUSH edx                     // pass arg3 b.lo
633    PUSH ecx                     // pass arg2 a.hi
634    PUSH eax                      // pass arg1 a.lo
635    call SYMBOL(artLdivFromCode)  // (jlong a, jlong b)
636    addl LITERAL(28), %esp        // pop arguments
637    .cfi_adjust_cfa_offset -28
638    ret
639END_FUNCTION art_quick_ldiv_from_code
640
641DEFINE_FUNCTION art_quick_ldivmod_from_code
642    subl LITERAL(12), %esp        // alignment padding
643    .cfi_adjust_cfa_offset 12
644    PUSH ebx                     // pass arg4 b.hi
645    PUSH edx                     // pass arg3 b.lo
646    PUSH ecx                     // pass arg2 a.hi
647    PUSH eax                      // pass arg1 a.lo
648    call SYMBOL(artLdivmodFromCode) // (jlong a, jlong b)
649    addl LITERAL(28), %esp        // pop arguments
650    .cfi_adjust_cfa_offset -28
651    ret
652END_FUNCTION art_quick_ldivmod_from_code
653
654DEFINE_FUNCTION art_quick_lmul_from_code
655    imul %eax, %ebx              // ebx = a.lo(eax) * b.hi(ebx)
656    imul %edx, %ecx              // ecx = b.lo(edx) * a.hi(ecx)
657    mul  %edx                    // edx:eax = a.lo(eax) * b.lo(edx)
658    add  %ebx, %ecx
659    add  %ecx, %edx              // edx += (a.lo * b.hi) + (b.lo * a.hi)
660    ret
661END_FUNCTION art_quick_lmul_from_code
662
663DEFINE_FUNCTION art_quick_lshl_from_code
664    // ecx:eax << edx
665    xchg %edx, %ecx
666    shld %cl,%eax,%edx
667    shl  %cl,%eax
668    test LITERAL(32), %cl
669    jz  1f
670    mov %eax, %edx
671    xor %eax, %eax
6721:
673    ret
674END_FUNCTION art_quick_lshl_from_code
675
676DEFINE_FUNCTION art_quick_lshr_from_code
677    // ecx:eax >> edx
678    xchg %edx, %ecx
679    shrd %cl,%edx,%eax
680    sar  %cl,%edx
681    test LITERAL(32),%cl
682    jz  1f
683    mov %edx, %eax
684    sar LITERAL(31), %edx
6851:
686    ret
687END_FUNCTION art_quick_lshr_from_code
688
689DEFINE_FUNCTION art_quick_lushr_from_code
690    // ecx:eax >>> edx
691    xchg %edx, %ecx
692    shrd %cl,%edx,%eax
693    shr  %cl,%edx
694    test LITERAL(32),%cl
695    jz  1f
696    mov %edx, %eax
697    xor %edx, %edx
6981:
699    ret
700END_FUNCTION art_quick_lushr_from_code
701
702DEFINE_FUNCTION art_quick_set32_instance_from_code
703    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
704    mov %esp, %ebx                // remember SP
705    subl LITERAL(8), %esp         // alignment padding
706    .cfi_adjust_cfa_offset 8
707    PUSH ebx                      // pass SP
708    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
709    .cfi_adjust_cfa_offset 4
710    mov 32(%ebx), %ebx            // get referrer
711    PUSH ebx                      // pass referrer
712    PUSH edx                      // pass new_val
713    PUSH ecx                      // pass object
714    PUSH eax                      // pass field_idx
715    call SYMBOL(artSet32InstanceFromCode)  // (field_idx, Object*, new_val, referrer, Thread*, SP)
716    addl LITERAL(32), %esp        // pop arguments
717    .cfi_adjust_cfa_offset -32
718    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
719    RETURN_IF_EAX_ZERO            // return or deliver exception
720END_FUNCTION art_quick_set32_instance_from_code
721
722DEFINE_FUNCTION art_quick_set64_instance_from_code
723    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
724    subl LITERAL(8), %esp         // alignment padding
725    .cfi_adjust_cfa_offset 8
726    PUSH esp                      // pass SP-8
727    addl LITERAL(8), (%esp)       // fix SP on stack by adding 8
728    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
729    .cfi_adjust_cfa_offset 4
730    PUSH ebx                      // pass high half of new_val
731    PUSH edx                      // pass low half of new_val
732    PUSH ecx                      // pass object
733    PUSH eax                      // pass field_idx
734    call SYMBOL(artSet64InstanceFromCode)  // (field_idx, Object*, new_val, Thread*, SP)
735    addl LITERAL(32), %esp        // pop arguments
736    .cfi_adjust_cfa_offset -32
737    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
738    RETURN_IF_EAX_ZERO            // return or deliver exception
739END_FUNCTION art_quick_set64_instance_from_code
740
741DEFINE_FUNCTION art_quick_set_obj_instance_from_code
742    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
743    mov %esp, %ebx                // remember SP
744    subl LITERAL(8), %esp         // alignment padding
745    .cfi_adjust_cfa_offset 8
746    PUSH ebx                      // pass SP
747    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
748    .cfi_adjust_cfa_offset 4
749    mov 32(%ebx), %ebx            // get referrer
750    PUSH ebx                      // pass referrer
751    PUSH edx                      // pass new_val
752    PUSH ecx                      // pass object
753    PUSH eax                      // pass field_idx
754    call SYMBOL(artSetObjInstanceFromCode) // (field_idx, Object*, new_val, referrer, Thread*, SP)
755    addl LITERAL(32), %esp        // pop arguments
756    .cfi_adjust_cfa_offset -32
757    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
758    RETURN_IF_EAX_ZERO            // return or deliver exception
759END_FUNCTION art_quick_set_obj_instance_from_code
760
761DEFINE_FUNCTION art_quick_get32_instance_from_code
762    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
763    mov %esp, %ebx                // remember SP
764    mov 32(%esp), %edx            // get referrer
765    subl LITERAL(12), %esp        // alignment padding
766    .cfi_adjust_cfa_offset 12
767    PUSH ebx                      // pass SP
768    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
769    .cfi_adjust_cfa_offset 4
770    PUSH edx                      // pass referrer
771    PUSH ecx                      // pass object
772    PUSH eax                      // pass field_idx
773    call SYMBOL(artGet32InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
774    addl LITERAL(32), %esp        // pop arguments
775    .cfi_adjust_cfa_offset -32
776    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
777    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
778END_FUNCTION art_quick_get32_instance_from_code
779
780DEFINE_FUNCTION art_quick_get64_instance_from_code
781    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
782    mov %esp, %ebx                // remember SP
783    mov 32(%esp), %edx            // get referrer
784    subl LITERAL(12), %esp        // alignment padding
785    .cfi_adjust_cfa_offset 12
786    PUSH ebx                      // pass SP
787    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
788    .cfi_adjust_cfa_offset 4
789    PUSH edx                      // pass referrer
790    PUSH ecx                      // pass object
791    PUSH eax                      // pass field_idx
792    call SYMBOL(artGet64InstanceFromCode)  // (field_idx, Object*, referrer, Thread*, SP)
793    addl LITERAL(32), %esp        // pop arguments
794    .cfi_adjust_cfa_offset -32
795    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
796    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
797END_FUNCTION art_quick_get64_instance_from_code
798
799DEFINE_FUNCTION art_quick_get_obj_instance_from_code
800    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
801    mov %esp, %ebx                // remember SP
802    mov 32(%esp), %edx            // get referrer
803    subl LITERAL(12), %esp        // alignment padding
804    .cfi_adjust_cfa_offset 12
805    PUSH ebx                      // pass SP
806    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
807    .cfi_adjust_cfa_offset 4
808    PUSH edx                      // pass referrer
809    PUSH ecx                      // pass object
810    PUSH eax                      // pass field_idx
811    call SYMBOL(artGetObjInstanceFromCode) // (field_idx, Object*, referrer, Thread*, SP)
812    addl LITERAL(32), %esp        // pop arguments
813    .cfi_adjust_cfa_offset -32
814    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
815    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
816END_FUNCTION art_quick_get_obj_instance_from_code
817
818DEFINE_FUNCTION art_quick_set32_static_from_code
819    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
820    mov %esp, %ebx                // remember SP
821    mov 32(%esp), %edx            // get referrer
822    subl LITERAL(12), %esp        // alignment padding
823    .cfi_adjust_cfa_offset 12
824    PUSH ebx                      // pass SP
825    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
826    .cfi_adjust_cfa_offset 4
827    PUSH edx                      // pass referrer
828    PUSH ecx                      // pass new_val
829    PUSH eax                      // pass field_idx
830    call SYMBOL(artSet32StaticFromCode)    // (field_idx, new_val, referrer, Thread*, SP)
831    addl LITERAL(32), %esp        // pop arguments
832    .cfi_adjust_cfa_offset -32
833    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
834    RETURN_IF_EAX_ZERO            // return or deliver exception
835END_FUNCTION art_quick_set32_static_from_code
836
837DEFINE_FUNCTION art_quick_set64_static_from_code
838    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
839    mov %esp, %ebx                // remember SP
840    subl LITERAL(8), %esp         // alignment padding
841    .cfi_adjust_cfa_offset 8
842    PUSH ebx                      // pass SP
843    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
844    .cfi_adjust_cfa_offset 4
845    mov 32(%ebx), %ebx            // get referrer
846    PUSH edx                      // pass high half of new_val
847    PUSH ecx                      // pass low half of new_val
848    PUSH ebx                      // pass referrer
849    PUSH eax                      // pass field_idx
850    call SYMBOL(artSet64StaticFromCode)  // (field_idx, referrer, new_val, Thread*, SP)
851    addl LITERAL(32), %esp        // pop arguments
852    .cfi_adjust_cfa_offset -32
853    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
854    RETURN_IF_EAX_ZERO            // return or deliver exception
855END_FUNCTION art_quick_set64_static_from_code
856
857DEFINE_FUNCTION art_quick_set_obj_static_from_code
858    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
859    mov %esp, %ebx                // remember SP
860    mov 32(%esp), %edx            // get referrer
861    subl LITERAL(12), %esp        // alignment padding
862    .cfi_adjust_cfa_offset 12
863    PUSH ebx                      // pass SP
864    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
865    .cfi_adjust_cfa_offset 4
866    PUSH edx                      // pass referrer
867    PUSH ecx                      // pass new_val
868    PUSH eax                      // pass field_idx
869    call SYMBOL(artSetObjStaticFromCode)  // (field_idx, new_val, referrer, Thread*, SP)
870    addl LITERAL(32), %esp        // pop arguments
871    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME  // restore frame up to return address
872    RETURN_IF_EAX_ZERO            // return or deliver exception
873END_FUNCTION art_quick_set_obj_static_from_code
874
875DEFINE_FUNCTION art_quick_get32_static_from_code
876    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
877    mov %esp, %edx                // remember SP
878    mov 32(%esp), %ecx            // get referrer
879    PUSH edx                      // pass SP
880    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
881    .cfi_adjust_cfa_offset 4
882    PUSH ecx                      // pass referrer
883    PUSH eax                      // pass field_idx
884    call SYMBOL(artGet32StaticFromCode)    // (field_idx, referrer, Thread*, SP)
885    addl LITERAL(16), %esp        // pop arguments
886    .cfi_adjust_cfa_offset -16
887    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
888    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
889END_FUNCTION art_quick_get32_static_from_code
890
891DEFINE_FUNCTION art_quick_get64_static_from_code
892    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  // save ref containing registers for GC
893    mov %esp, %edx                // remember SP
894    mov 32(%esp), %ecx            // get referrer
895    PUSH edx                      // pass SP
896    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
897    .cfi_adjust_cfa_offset 4
898    PUSH ecx                      // pass referrer
899    PUSH eax                      // pass field_idx
900    call SYMBOL(artGet64StaticFromCode)    // (field_idx, referrer, Thread*, SP)
901    addl LITERAL(16), %esp        // pop arguments
902    .cfi_adjust_cfa_offset -16
903    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
904    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
905END_FUNCTION art_quick_get64_static_from_code
906
907DEFINE_FUNCTION art_quick_get_obj_static_from_code
908    SETUP_REF_ONLY_CALLEE_SAVE_FRAME       // save ref containing registers for GC
909    mov %esp, %edx                // remember SP
910    mov 32(%esp), %ecx            // get referrer
911    PUSH edx                      // pass SP
912    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
913    .cfi_adjust_cfa_offset 4
914    PUSH ecx                      // pass referrer
915    PUSH eax                      // pass field_idx
916    call SYMBOL(artGetObjStaticFromCode)   // (field_idx, referrer, Thread*, SP)
917    addl LITERAL(16), %esp        // pop arguments
918    .cfi_adjust_cfa_offset -16
919    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME     // restore frame up to return address
920    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
921END_FUNCTION art_quick_get_obj_static_from_code
922
923DEFINE_FUNCTION art_portable_proxy_invoke_handler
924    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame and Method*
925    PUSH esp                      // pass SP
926    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
927    .cfi_adjust_cfa_offset 4
928    PUSH ecx                      // pass receiver
929    PUSH eax                      // pass proxy method
930    call SYMBOL(artPortableProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
931    movd %eax, %xmm0              // place return value also into floating point return value
932    movd %edx, %xmm1
933    punpckldq %xmm1, %xmm0
934    addl LITERAL(44), %esp        // pop arguments
935    .cfi_adjust_cfa_offset -44
936    ret
937END_FUNCTION art_portable_proxy_invoke_handler
938
939DEFINE_FUNCTION art_quick_proxy_invoke_handler
940    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame and Method*
941    PUSH esp                      // pass SP
942    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
943    .cfi_adjust_cfa_offset 4
944    PUSH ecx                      // pass receiver
945    PUSH eax                      // pass proxy method
946    call SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
947    movd %eax, %xmm0              // place return value also into floating point return value
948    movd %edx, %xmm1
949    punpckldq %xmm1, %xmm0
950    addl LITERAL(44), %esp        // pop arguments
951    .cfi_adjust_cfa_offset -44
952    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
953END_FUNCTION art_quick_proxy_invoke_handler
954
955DEFINE_FUNCTION art_quick_interpreter_entry
956    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME   // save frame
957    mov %esp, %edx                // remember SP
958    PUSH eax                      // alignment padding
959    PUSH edx                      // pass SP
960    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
961    .cfi_adjust_cfa_offset 4
962    PUSH eax                      // pass  method
963    call SYMBOL(artInterpreterEntry)  // (method, Thread*, SP)
964    movd %eax, %xmm0              // place return value also into floating point return value
965    movd %edx, %xmm1
966    punpckldq %xmm1, %xmm0
967    addl LITERAL(44), %esp        // pop arguments
968    .cfi_adjust_cfa_offset -44
969    RETURN_OR_DELIVER_PENDING_EXCEPTION    // return or deliver exception
970END_FUNCTION art_quick_interpreter_entry
971
972    /*
973     * Routine that intercepts method calls and returns.
974     */
975DEFINE_FUNCTION art_quick_instrumentation_entry_from_code
976    SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
977    movl  %esp, %edx              // Save SP.
978    PUSH eax                      // Save eax which will be clobbered by the callee-save method.
979    subl LITERAL(8), %esp         // Align stack.
980    .cfi_adjust_cfa_offset 8
981    pushl 40(%esp)                // Pass LR.
982    .cfi_adjust_cfa_offset 4
983    PUSH edx                      // Pass SP.
984    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
985    .cfi_adjust_cfa_offset 4
986    PUSH ecx                      // Pass receiver.
987    PUSH eax                      // Pass Method*.
988    call  SYMBOL(artInstrumentationMethodEntryFromCode) // (Method*, Object*, Thread*, SP, LR)
989    addl  LITERAL(28), %esp       // Pop arguments upto saved Method*.
990    movl 28(%esp), %edi           // Restore edi.
991    movl %eax, 28(%esp)           // Place code* over edi, just under return pc.
992    movl LITERAL(SYMBOL(art_quick_instrumentation_exit_from_code)), 32(%esp)
993                                  // Place instrumentation exit as return pc.
994    movl (%esp), %eax             // Restore eax.
995    movl 8(%esp), %ecx            // Restore ecx.
996    movl 12(%esp), %edx           // Restore edx.
997    movl 16(%esp), %ebx           // Restore ebx.
998    movl 20(%esp), %ebp           // Restore ebp.
999    movl 24(%esp), %esi           // Restore esi.
1000    addl LITERAL(28), %esp        // Wind stack back upto code*.
1001    ret                           // Call method (and pop).
1002END_FUNCTION art_quick_instrumentation_entry_from_code
1003
1004DEFINE_FUNCTION art_quick_instrumentation_exit_from_code
1005    pushl LITERAL(0)              // Push a fake return PC as there will be none on the stack.
1006    SETUP_REF_ONLY_CALLEE_SAVE_FRAME
1007    mov  %esp, %ecx               // Remember SP
1008    subl LITERAL(8), %esp         // Save float return value.
1009    .cfi_adjust_cfa_offset 8
1010    movd %xmm0, (%esp)
1011    PUSH edx                      // Save gpr return value.
1012    PUSH eax
1013    subl LITERAL(8), %esp         // Align stack
1014    movd %xmm0, (%esp)
1015    subl LITERAL(8), %esp         // Pass float return value.
1016    .cfi_adjust_cfa_offset 8
1017    movd %xmm0, (%esp)
1018    PUSH edx                      // Pass gpr return value.
1019    PUSH eax
1020    PUSH ecx                      // Pass SP.
1021    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current.
1022    .cfi_adjust_cfa_offset 4
1023    call  SYMBOL(artInstrumentationMethodExitFromCode)  // (Thread*, SP, gpr_result, fpr_result)
1024    mov   %eax, %ecx              // Move returned link register.
1025    addl LITERAL(32), %esp        // Pop arguments.
1026    .cfi_adjust_cfa_offset -32
1027    movl %edx, %ebx               // Move returned link register for deopt
1028                                  // (ebx is pretending to be our LR).
1029    POP eax                       // Restore gpr return value.
1030    POP edx
1031    movd (%esp), %xmm0            // Restore fpr return value.
1032    addl LITERAL(8), %esp
1033    .cfi_adjust_cfa_offset -8
1034    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
1035    addl LITERAL(4), %esp         // Remove fake return pc.
1036    jmp   *%ecx                   // Return.
1037END_FUNCTION art_quick_instrumentation_exit_from_code
1038
1039    /*
1040     * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
1041     * will long jump to the upcall with a special exception of -1.
1042     */
1043DEFINE_FUNCTION art_quick_deoptimize
1044    pushl %ebx                    // Fake that we were called.
1045    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
1046    mov  %esp, %ecx               // Remember SP.
1047    subl LITERAL(8), %esp         // Align stack.
1048    .cfi_adjust_cfa_offset 8
1049    PUSH ecx                      // Pass SP.
1050    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
1051    .cfi_adjust_cfa_offset 4
1052    call SYMBOL(artDeoptimize)    // artDeoptimize(Thread*, SP)
1053    int3                          // Unreachable.
1054END_FUNCTION art_quick_deoptimize
1055
1056    /*
1057     * Portable abstract method error stub. method* is at %esp + 4 on entry.
1058     */
1059DEFINE_FUNCTION art_portable_abstract_method_error_stub
1060    PUSH ebp
1061    movl %esp, %ebp               // Remember SP.
1062    .cfi_def_cfa_register ebp
1063    subl LITERAL(12), %esp        // Align stack.
1064    PUSH esp                      // Pass sp (not used).
1065    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
1066    pushl 8(%ebp)                 // Pass Method*.
1067    call SYMBOL(artThrowAbstractMethodErrorFromCode)  // (Method*, Thread*, SP)
1068    leave                         // Restore the stack and %ebp.
1069    .cfi_def_cfa esp, 4
1070    .cfi_restore ebp
1071    ret                           // Return to caller to handle pending exception.
1072END_FUNCTION art_portable_abstract_method_error_stub
1073
1074    /*
1075     * Quick abstract method error stub. %eax contains method* on entry.
1076     */
1077DEFINE_FUNCTION art_quick_abstract_method_error_stub
1078    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
1079    movl %esp, %ecx               // Remember SP.
1080    PUSH eax                      // Align frame.
1081    PUSH ecx                      // Pass SP for Method*.
1082    pushl %fs:THREAD_SELF_OFFSET  // Pass Thread::Current().
1083    .cfi_adjust_cfa_offset 4
1084    PUSH eax                      // Pass Method*.
1085    call SYMBOL(artThrowAbstractMethodErrorFromCode)  // (Method*, Thread*, SP)
1086    int3                          // Unreachable.
1087END_FUNCTION art_quick_abstract_method_error_stub
1088
1089    /*
1090     * Portable resolution trampoline.
1091     */
1092DEFINE_FUNCTION art_jni_dlsym_lookup_stub
1093    subl LITERAL(8), %esp         // align stack
1094    .cfi_adjust_cfa_offset 8
1095    pushl %fs:THREAD_SELF_OFFSET  // pass Thread::Current()
1096    .cfi_adjust_cfa_offset 4
1097    call SYMBOL(artFindNativeMethod)  // (Thread*)
1098    addl LITERAL(12), %esp        // restore the stack
1099    .cfi_adjust_cfa_offset -12
1100    cmpl LITERAL(0), %eax         // check if returned method code is null
1101    je no_native_code_found       // if null, jump to return to handle
1102    jmp *%eax                     // otherwise, tail call to intended method
1103no_native_code_found:
1104    ret
1105END_FUNCTION art_jni_dlsym_lookup_stub
1106
1107    /*
1108     * String's indexOf.
1109     *
1110     * On entry:
1111     *    eax:   string object (known non-null)
1112     *    ecx:   char to match (known <= 0xFFFF)
1113     *    edx:   Starting offset in string data
1114     */
1115DEFINE_FUNCTION art_quick_indexof
1116    PUSH edi                      // push callee save reg
1117    mov STRING_COUNT_OFFSET(%eax), %ebx
1118    mov STRING_VALUE_OFFSET(%eax), %edi
1119    mov STRING_OFFSET_OFFSET(%eax), %eax
1120    testl %edx, %edx              // check if start < 0
1121    jl   clamp_min
1122clamp_done:
1123    cmpl %ebx, %edx               // check if start >= count
1124    jge  not_found
1125    lea  STRING_DATA_OFFSET(%edi, %eax, 2), %edi  // build a pointer to the start of string data
1126    mov  %edi, %eax               // save a copy in eax to later compute result
1127    lea  (%edi, %edx, 2), %edi    // build pointer to start of data to compare
1128    subl  %edx, %ebx              // compute iteration count
1129    /*
1130     * At this point we have:
1131     *   eax: original start of string data
1132     *   ecx: char to compare
1133     *   ebx: length to compare
1134     *   edi: start of data to test
1135     */
1136    mov  %eax, %edx
1137    mov  %ecx, %eax               // put char to match in %eax
1138    mov  %ebx, %ecx               // put length to compare in %ecx
1139    repne scasw                   // find %ax, starting at [%edi], up to length %ecx
1140    jne  not_found
1141    subl %edx, %edi
1142    sar  LITERAL(1), %edi
1143    decl %edi                     // index = ((curr_ptr - orig_ptr) / 2) - 1
1144    mov  %edi, %eax
1145    POP edi                       // pop callee save reg
1146    ret
1147    .balign 16
1148not_found:
1149    mov  LITERAL(-1), %eax        // return -1 (not found)
1150    POP edi                       // pop callee save reg
1151    ret
1152clamp_min:
1153    xor  %edx, %edx               // clamp start to 0
1154    jmp  clamp_done
1155END_FUNCTION art_quick_indexof
1156
1157    /*
1158     * String's compareTo.
1159     *
1160     * On entry:
1161     *    eax:   this string object (known non-null)
1162     *    ecx:   comp string object (known non-null)
1163     */
1164DEFINE_FUNCTION art_quick_string_compareto
1165    PUSH esi                    // push callee save reg
1166    PUSH edi                    // push callee save reg
1167    mov STRING_COUNT_OFFSET(%eax), %edx
1168    mov STRING_COUNT_OFFSET(%ecx), %ebx
1169    mov STRING_VALUE_OFFSET(%eax), %esi
1170    mov STRING_VALUE_OFFSET(%ecx), %edi
1171    mov STRING_OFFSET_OFFSET(%eax), %eax
1172    mov STRING_OFFSET_OFFSET(%ecx), %ecx
1173    /* Build pointers to the start of string data */
1174    lea  STRING_DATA_OFFSET(%esi, %eax, 2), %esi
1175    lea  STRING_DATA_OFFSET(%edi, %ecx, 2), %edi
1176    /* Calculate min length and count diff */
1177    mov   %edx, %ecx
1178    mov   %edx, %eax
1179    subl  %ebx, %eax
1180    cmovg %ebx, %ecx
1181    /*
1182     * At this point we have:
1183     *   eax: value to return if first part of strings are equal
1184     *   ecx: minimum among the lengths of the two strings
1185     *   esi: pointer to this string data
1186     *   edi: pointer to comp string data
1187     */
1188    repe cmpsw                    // find nonmatching chars in [%esi] and [%edi], up to length %ecx
1189    jne not_equal
1190    POP edi                       // pop callee save reg
1191    POP esi                       // pop callee save reg
1192    ret
1193    .balign 16
1194not_equal:
1195    movzwl  -2(%esi), %eax        // get last compared char from this string
1196    movzwl  -2(%edi), %ecx        // get last compared char from comp string
1197    subl  %ecx, %eax              // return the difference
1198    POP edi                       // pop callee save reg
1199    POP esi                       // pop callee save reg
1200    ret
1201END_FUNCTION art_quick_string_compareto
1202
1203MACRO1(UNIMPLEMENTED,name)
1204    .globl VAR(name, 0)
1205    ALIGN_FUNCTION_ENTRY
1206VAR(name, 0):
1207    int3
1208END_MACRO
1209
1210    // TODO: implement these!
1211UNIMPLEMENTED art_quick_memcmp16
1212