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