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