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