Home | History | Annotate | Download | only in x86
      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      */
     23 MACRO0(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
     29 END_MACRO
     30 
     31     /*
     32      * Macro that sets up the callee save frame to conform with
     33      * Runtime::CreateCalleeSaveMethod(kRefsOnly)
     34      */
     35 MACRO0(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
     41 END_MACRO
     42 
     43 MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
     44     addl MACRO_LITERAL(28), %esp  // Unwind stack up to return address
     45     .cfi_adjust_cfa_offset -28
     46 END_MACRO
     47 
     48     /*
     49      * Macro that sets up the callee save frame to conform with
     50      * Runtime::CreateCalleeSaveMethod(kRefsAndArgs)
     51      */
     52 MACRO0(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*
     60 END_MACRO
     61 
     62 MACRO0(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
     71 END_MACRO
     72 
     73     /*
     74      * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
     75      * exception is Thread::Current()->exception_.
     76      */
     77 MACRO0(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
     88 END_MACRO
     89 
     90 MACRO2(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)
    103 END_MACRO
    104 
    105 MACRO2(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)
    118 END_MACRO
    119 
    120 MACRO2(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)
    133 END_MACRO
    134 
    135     /*
    136      * Called by managed code to create and deliver a NullPointerException.
    137      */
    138 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
    139 
    140     /*
    141      * Called by managed code to create and deliver an ArithmeticException.
    142      */
    143 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
    144 
    145     /*
    146      * Called by managed code to create and deliver a StackOverflowError.
    147      */
    148 NO_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      */
    154 ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
    155 
    156     /*
    157      * Called by managed code to create and deliver a NoSuchMethodError.
    158      */
    159 ONE_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      */
    165 TWO_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      */
    183 MACRO2(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
    220 1:
    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)
    225 END_MACRO
    226 
    227 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
    228 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
    229 
    230 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
    231 INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
    232 INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
    233 INVOKE_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      */
    246 DEFINE_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
    279 return_double_quick:
    280 return_float_quick:
    281     movsd %xmm0, (%ecx)           // store the floating point result
    282     ret
    283 END_FUNCTION art_quick_invoke_stub
    284 
    285 MACRO3(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)
    301 END_MACRO
    302 
    303 MACRO3(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)
    319 END_MACRO
    320 
    321 MACRO3(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)
    337 END_MACRO
    338 
    339 MACRO3(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)
    358 END_MACRO
    359 
    360 MACRO0(RETURN_IF_EAX_NOT_ZERO)
    361     testl %eax, %eax               // eax == 0 ?
    362     jz  1f                         // if eax == 0 goto 1
    363     ret                            // return
    364 1:                                 // deliver exception on current thread
    365     DELIVER_PENDING_EXCEPTION
    366 END_MACRO
    367 
    368 MACRO0(RETURN_IF_EAX_ZERO)
    369     testl %eax, %eax               // eax == 0 ?
    370     jnz  1f                        // if eax != 0 goto 1
    371     ret                            // return
    372 1:                                 // deliver exception on current thread
    373     DELIVER_PENDING_EXCEPTION
    374 END_MACRO
    375 
    376 MACRO0(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
    381 1:                                 // deliver exception on current thread
    382     DELIVER_PENDING_EXCEPTION
    383 END_MACRO
    384 
    385 TWO_ARG_DOWNCALL art_quick_alloc_object, artAllocObjectFromCode, RETURN_IF_EAX_NOT_ZERO
    386 TWO_ARG_DOWNCALL art_quick_alloc_object_with_access_check, artAllocObjectFromCodeWithAccessCheck, RETURN_IF_EAX_NOT_ZERO
    387 THREE_ARG_DOWNCALL art_quick_alloc_array, artAllocArrayFromCode, RETURN_IF_EAX_NOT_ZERO
    388 THREE_ARG_DOWNCALL art_quick_alloc_array_with_access_check, artAllocArrayFromCodeWithAccessCheck, RETURN_IF_EAX_NOT_ZERO
    389 THREE_ARG_DOWNCALL art_quick_check_and_alloc_array, artCheckAndAllocArrayFromCode, RETURN_IF_EAX_NOT_ZERO
    390 THREE_ARG_DOWNCALL art_quick_check_and_alloc_array_with_access_check, artCheckAndAllocArrayFromCodeWithAccessCheck, RETURN_IF_EAX_NOT_ZERO
    391 
    392 TWO_ARG_DOWNCALL art_quick_resolve_string, artResolveStringFromCode, RETURN_IF_EAX_NOT_ZERO
    393 TWO_ARG_DOWNCALL art_quick_initialize_static_storage, artInitializeStaticStorageFromCode, RETURN_IF_EAX_NOT_ZERO
    394 TWO_ARG_DOWNCALL art_quick_initialize_type, artInitializeTypeFromCode, RETURN_IF_EAX_NOT_ZERO
    395 TWO_ARG_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode, RETURN_IF_EAX_NOT_ZERO
    396 
    397 ONE_ARG_DOWNCALL art_quick_lock_object, artLockObjectFromCode, ret
    398 ONE_ARG_DOWNCALL art_quick_unlock_object, artUnlockObjectFromCode, RETURN_IF_EAX_ZERO
    399 
    400 TWO_ARG_DOWNCALL art_quick_handle_fill_data, artHandleFillArrayDataFromCode, RETURN_IF_EAX_ZERO
    401 
    402 DEFINE_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
    410 END_FUNCTION art_quick_is_assignable
    411 
    412 DEFINE_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
    420 END_FUNCTION art_quick_memcpy
    421 
    422 TWO_ARG_DOWNCALL art_quick_check_cast, artCheckCastFromCode, RETURN_IF_EAX_ZERO
    423 TWO_ARG_DOWNCALL art_quick_can_put_array_element, artCanPutArrayElementFromCode, RETURN_IF_EAX_ZERO
    424 
    425 NO_ARG_DOWNCALL art_quick_test_suspend, artTestSuspendFromCode, ret
    426 
    427 DEFINE_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
    440 END_FUNCTION art_quick_fmod
    441 
    442 DEFINE_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
    452 END_FUNCTION art_quick_fmodf
    453 
    454 DEFINE_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
    463 END_FUNCTION art_quick_l2d
    464 
    465 DEFINE_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
    474 END_FUNCTION art_quick_l2f
    475 
    476 DEFINE_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
    484 END_FUNCTION art_quick_d2l
    485 
    486 DEFINE_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
    494 END_FUNCTION art_quick_f2l
    495 
    496 DEFINE_FUNCTION art_quick_idivmod
    497     cmpl LITERAL(0x80000000), %eax
    498     je check_arg2  // special case
    499 args_ok:
    500     cdq         // edx:eax = sign extend eax
    501     idiv %ecx   // (edx,eax) = (edx:eax % ecx, edx:eax / ecx)
    502     ret
    503 check_arg2:
    504     cmpl LITERAL(-1), %ecx
    505     jne args_ok
    506     xorl %edx, %edx
    507     ret         // eax already holds min int
    508 END_FUNCTION art_quick_idivmod
    509 
    510 DEFINE_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
    521 END_FUNCTION art_quick_ldiv
    522 
    523 DEFINE_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
    534 END_FUNCTION art_quick_ldivmod
    535 
    536 DEFINE_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
    543 END_FUNCTION art_quick_lmul
    544 
    545 DEFINE_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
    554 1:
    555     ret
    556 END_FUNCTION art_quick_lshl
    557 
    558 DEFINE_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
    567 1:
    568     ret
    569 END_FUNCTION art_quick_lshr
    570 
    571 DEFINE_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
    580 1:
    581     ret
    582 END_FUNCTION art_quick_lushr
    583 
    584 DEFINE_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
    602 END_FUNCTION art_quick_set32_instance
    603 
    604 DEFINE_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
    621 END_FUNCTION art_quick_set64_instance
    622 
    623 DEFINE_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
    641 END_FUNCTION art_quick_set_obj_instance
    642 
    643 DEFINE_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
    660 END_FUNCTION art_quick_get32_instance
    661 
    662 DEFINE_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
    679 END_FUNCTION art_quick_get64_instance
    680 
    681 DEFINE_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
    698 END_FUNCTION art_quick_get_obj_instance
    699 
    700 DEFINE_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
    717 END_FUNCTION art_quick_set32_static
    718 
    719 DEFINE_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
    737 END_FUNCTION art_quick_set64_static
    738 
    739 DEFINE_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
    755 END_FUNCTION art_quick_set_obj_static
    756 
    757 DEFINE_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
    771 END_FUNCTION art_quick_get32_static
    772 
    773 DEFINE_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
    787 END_FUNCTION art_quick_get64_static
    788 
    789 DEFINE_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
    803 END_FUNCTION art_quick_get_obj_static
    804 
    805 DEFINE_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
    819 END_FUNCTION art_quick_proxy_invoke_handler
    820 
    821 DEFINE_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
    841 1:
    842     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
    843     DELIVER_PENDING_EXCEPTION
    844 END_FUNCTION art_quick_resolution_trampoline
    845 
    846 DEFINE_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
    861 END_FUNCTION art_quick_to_interpreter_bridge
    862 
    863     /*
    864      * Routine that intercepts method calls and returns.
    865      */
    866 DEFINE_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).
    893 END_FUNCTION art_quick_instrumentation_entry
    894 
    895 DEFINE_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.
    928 END_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      */
    934 DEFINE_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.
    945 END_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      */
    955 DEFINE_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
    962 clamp_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
    988 not_found:
    989     mov  LITERAL(-1), %eax        // return -1 (not found)
    990     POP edi                       // pop callee save reg
    991     ret
    992 clamp_min:
    993     xor  %edx, %edx               // clamp start to 0
    994     jmp  clamp_done
    995 END_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      */
   1004 DEFINE_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
   1034 not_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
   1041 END_FUNCTION art_quick_string_compareto
   1042 
   1043     // TODO: implement these!
   1044 UNIMPLEMENTED art_quick_memcmp16
   1045