Home | History | Annotate | Download | only in arm
      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_arm.S"
     18 
     19     /* Deliver the given exception */
     20     .extern artDeliverExceptionFromCode
     21     /* Deliver an exception pending on a thread */
     22     .extern artDeliverPendingException
     23 
     24     /*
     25      * Macro that sets up the callee save frame to conform with
     26      * Runtime::CreateCalleeSaveMethod(kSaveAll)
     27      */
     28 .macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     29     push {r4-r11, lr} @ 9 words of callee saves
     30     .save {r4-r11, lr}
     31     .cfi_adjust_cfa_offset 36
     32     .cfi_rel_offset r4, 0
     33     .cfi_rel_offset r5, 4
     34     .cfi_rel_offset r6, 8
     35     .cfi_rel_offset r7, 12
     36     .cfi_rel_offset r8, 16
     37     .cfi_rel_offset r9, 20
     38     .cfi_rel_offset r10, 24
     39     .cfi_rel_offset r11, 28
     40     .cfi_rel_offset lr, 32
     41     vpush {s0-s31}
     42     .pad #128
     43     .cfi_adjust_cfa_offset 128
     44     sub sp, #12       @ 3 words of space, bottom word will hold Method*
     45     .pad #12
     46     .cfi_adjust_cfa_offset 12
     47 .endm
     48 
     49     /*
     50      * Macro that sets up the callee save frame to conform with
     51      * Runtime::CreateCalleeSaveMethod(kRefsOnly). Restoration assumes non-moving GC.
     52      */
     53 .macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
     54     push {r5-r8, r10-r11, lr} @ 7 words of callee saves
     55     .save {r5-r8, r10-r11, lr}
     56     .cfi_adjust_cfa_offset 28
     57     .cfi_rel_offset r5, 0
     58     .cfi_rel_offset r6, 4
     59     .cfi_rel_offset r7, 8
     60     .cfi_rel_offset r8, 12
     61     .cfi_rel_offset r10, 16
     62     .cfi_rel_offset r11, 20
     63     .cfi_rel_offset lr, 24
     64     sub sp, #4                @ bottom word will hold Method*
     65     .pad #4
     66     .cfi_adjust_cfa_offset 4
     67 .endm
     68 
     69 .macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
     70     ldr lr, [sp, #28]  @ restore lr for return
     71     add sp, #32        @ unwind stack
     72     .cfi_adjust_cfa_offset -32
     73 .endm
     74 
     75 .macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
     76     ldr lr, [sp, #28]  @ restore lr for return
     77     add sp, #32        @ unwind stack
     78     .cfi_adjust_cfa_offset -32
     79     bx  lr             @ return
     80 .endm
     81 
     82     /*
     83      * Macro that sets up the callee save frame to conform with
     84      * Runtime::CreateCalleeSaveMethod(kRefsAndArgs). Restoration assumes non-moving GC.
     85      */
     86 .macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     87     push {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves
     88     .save {r1-r3, r5-r8, r10-r11, lr}
     89     .cfi_adjust_cfa_offset 40
     90     .cfi_rel_offset r1, 0
     91     .cfi_rel_offset r2, 4
     92     .cfi_rel_offset r3, 8
     93     .cfi_rel_offset r5, 12
     94     .cfi_rel_offset r6, 16
     95     .cfi_rel_offset r7, 20
     96     .cfi_rel_offset r8, 24
     97     .cfi_rel_offset r10, 28
     98     .cfi_rel_offset r11, 32
     99     .cfi_rel_offset lr, 36
    100     sub sp, #8                        @ 2 words of space, bottom word will hold Method*
    101     .pad #8
    102     .cfi_adjust_cfa_offset 8
    103 .endm
    104 
    105 .macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
    106     ldr  r1, [sp, #8]          @ restore non-callee save r1
    107     ldrd r2, [sp, #12]         @ restore non-callee saves r2-r3
    108     ldr  lr, [sp, #44]         @ restore lr
    109     add  sp, #48               @ rewind sp
    110     .cfi_adjust_cfa_offset -48
    111 .endm
    112 
    113 .macro RETURN_IF_RESULT_IS_ZERO
    114     cbnz   r0, 1f              @ result non-zero branch over
    115     bx     lr                  @ return
    116 1:
    117 .endm
    118 
    119 .macro RETURN_IF_RESULT_IS_NON_ZERO
    120     cbz    r0, 1f              @ result zero branch over
    121     bx     lr                  @ return
    122 1:
    123 .endm
    124 
    125     /*
    126      * Macro that set calls through to artDeliverPendingExceptionFromCode, where the pending
    127      * exception is Thread::Current()->exception_
    128      */
    129 .macro DELIVER_PENDING_EXCEPTION
    130     .fnend
    131     .fnstart
    132     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME           @ save callee saves for throw
    133     mov    r0, r9                              @ pass Thread::Current
    134     mov    r1, sp                              @ pass SP
    135     b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*, SP)
    136 .endm
    137 
    138 .macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
    139     .extern \cxx_name
    140 ENTRY \c_name
    141     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
    142     mov r0, r9                      @ pass Thread::Current
    143     mov r1, sp                      @ pass SP
    144     b   \cxx_name                   @ \cxx_name(Thread*, SP)
    145 END \c_name
    146 .endm
    147 
    148 .macro ONE_ARG_RUNTIME_EXCEPTION c_name, cxx_name
    149     .extern \cxx_name
    150 ENTRY \c_name
    151     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
    152     mov r1, r9                      @ pass Thread::Current
    153     mov r2, sp                      @ pass SP
    154     b   \cxx_name                   @ \cxx_name(Thread*, SP)
    155 END \c_name
    156 .endm
    157 
    158 .macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
    159     .extern \cxx_name
    160 ENTRY \c_name
    161     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
    162     mov r2, r9                      @ pass Thread::Current
    163     mov r3, sp                      @ pass SP
    164     b   \cxx_name                   @ \cxx_name(Thread*, SP)
    165 END \c_name
    166 .endm
    167 
    168     /*
    169      * Called by managed code, saves callee saves and then calls artThrowException
    170      * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception.
    171      */
    172 ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
    173 
    174     /*
    175      * Called by managed code to create and deliver a NullPointerException.
    176      */
    177 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception, artThrowNullPointerExceptionFromCode
    178 
    179     /*
    180      * Called by managed code to create and deliver an ArithmeticException.
    181      */
    182 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode
    183 
    184     /*
    185      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
    186      * index, arg2 holds limit.
    187      */
    188 TWO_ARG_RUNTIME_EXCEPTION art_quick_throw_array_bounds, artThrowArrayBoundsFromCode
    189 
    190     /*
    191      * Called by managed code to create and deliver a StackOverflowError.
    192      */
    193 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
    194 
    195     /*
    196      * Called by managed code to create and deliver a NoSuchMethodError.
    197      */
    198 ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
    199 
    200     /*
    201      * All generated callsites for interface invokes and invocation slow paths will load arguments
    202      * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
    203      * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
    204      * stack and call the appropriate C helper.
    205      * NOTE: "this" is first visible argument of the target, and so can be found in arg1/r1.
    206      *
    207      * The helper will attempt to locate the target and return a 64-bit result in r0/r1 consisting
    208      * of the target Method* in r0 and method->code_ in r1.
    209      *
    210      * If unsuccessful, the helper will return NULL/NULL. There will bea pending exception in the
    211      * thread and we branch to another stub to deliver it.
    212      *
    213      * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
    214      * pointing back to the original caller.
    215      */
    216 .macro INVOKE_TRAMPOLINE c_name, cxx_name
    217     .extern \cxx_name
    218 ENTRY \c_name
    219     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME  @ save callee saves in case allocation triggers GC
    220     ldr    r2, [sp, #48]                  @ pass caller Method*
    221     mov    r3, r9                         @ pass Thread::Current
    222     mov    r12, sp
    223     str    r12, [sp, #-16]!               @ expand the frame and pass SP
    224     .pad #16
    225     .cfi_adjust_cfa_offset 16
    226     bl     \cxx_name                      @ (method_idx, this, caller, Thread*, SP)
    227     add    sp, #16                        @ strip the extra frame
    228     .cfi_adjust_cfa_offset -16
    229     mov    r12, r1                        @ save Method*->code_
    230     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
    231     cbz    r0, 1f                         @ did we find the target? if not go to exception delivery
    232     bx     r12                            @ tail call to target
    233 1:
    234     DELIVER_PENDING_EXCEPTION
    235 END \c_name
    236 .endm
    237 
    238 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline, artInvokeInterfaceTrampoline
    239 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
    240 
    241 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
    242 INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
    243 INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
    244 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
    245 
    246     /*
    247      * Quick invocation stub.
    248      * On entry:
    249      *   r0 = method pointer
    250      *   r1 = argument array or NULL for no argument methods
    251      *   r2 = size of argument array in bytes
    252      *   r3 = (managed) thread pointer
    253      *   [sp] = JValue* result
    254      *   [sp + 4] = result type char
    255      */
    256 ENTRY art_quick_invoke_stub
    257     push   {r0, r4, r5, r9, r11, lr}       @ spill regs
    258     .save  {r0, r4, r5, r9, r11, lr}
    259     .pad #24
    260     .cfi_adjust_cfa_offset 24
    261     .cfi_rel_offset r0, 0
    262     .cfi_rel_offset r4, 4
    263     .cfi_rel_offset r5, 8
    264     .cfi_rel_offset r9, 12
    265     .cfi_rel_offset r11, 16
    266     .cfi_rel_offset lr, 20
    267     mov    r11, sp                         @ save the stack pointer
    268     .cfi_def_cfa_register r11
    269     mov    r9, r3                          @ move managed thread pointer into r9
    270     mov    r4, #SUSPEND_CHECK_INTERVAL     @ reset r4 to suspend check interval
    271     add    r5, r2, #16                     @ create space for method pointer in frame
    272     and    r5, #0xFFFFFFF0                 @ align frame size to 16 bytes
    273     sub    sp, r5                          @ reserve stack space for argument array
    274     add    r0, sp, #4                      @ pass stack pointer + method ptr as dest for memcpy
    275     bl     memcpy                          @ memcpy (dest, src, bytes)
    276     ldr    r0, [r11]                       @ restore method*
    277     ldr    r1, [sp, #4]                    @ copy arg value for r1
    278     ldr    r2, [sp, #8]                    @ copy arg value for r2
    279     ldr    r3, [sp, #12]                   @ copy arg value for r3
    280     mov    ip, #0                          @ set ip to 0
    281     str    ip, [sp]                        @ store NULL for method* at bottom of frame
    282     ldr    ip, [r0, #METHOD_CODE_OFFSET]   @ get pointer to the code
    283     blx    ip                              @ call the method
    284     mov    sp, r11                         @ restore the stack pointer
    285     ldr    ip, [sp, #24]                   @ load the result pointer
    286     strd   r0, [ip]                        @ store r0/r1 into result pointer
    287     pop    {r0, r4, r5, r9, r11, lr}       @ restore spill regs
    288     .cfi_adjust_cfa_offset -24
    289     bx     lr
    290 END art_quick_invoke_stub
    291 
    292     /*
    293      * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_
    294      */
    295 ARM_ENTRY art_quick_do_long_jump
    296     vldm r1, {s0-s31}     @ load all fprs from argument fprs_
    297     ldr  r2, [r0, #60]    @ r2 = r15 (PC from gprs_ 60=4*15)
    298     add  r0, r0, #12      @ increment r0 to skip gprs_[0..2] 12=4*3
    299     ldm  r0, {r3-r14}     @ load remaining gprs from argument gprs_
    300     mov  r0, #0           @ clear result registers r0 and r1
    301     mov  r1, #0
    302     bx   r2               @ do long jump
    303 END art_quick_do_long_jump
    304 
    305     /*
    306      * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
    307      * failure.
    308      */
    309     .extern artHandleFillArrayDataFromCode
    310 ENTRY art_quick_handle_fill_data
    311     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case exception allocation triggers GC
    312     mov    r2, r9                          @ pass Thread::Current
    313     mov    r3, sp                          @ pass SP
    314     bl     artHandleFillArrayDataFromCode  @ (Array*, const DexFile::Payload*, Thread*, SP)
    315     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    316     RETURN_IF_RESULT_IS_ZERO
    317     DELIVER_PENDING_EXCEPTION
    318 END art_quick_handle_fill_data
    319 
    320     /*
    321      * Entry from managed code that calls artLockObjectFromCode, may block for GC.
    322      */
    323     .extern artLockObjectFromCode
    324 ENTRY art_quick_lock_object
    325     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case we block
    326     mov    r1, r9                     @ pass Thread::Current
    327     mov    r2, sp                     @ pass SP
    328     bl     artLockObjectFromCode      @ (Object* obj, Thread*, SP)
    329     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
    330 END art_quick_lock_object
    331 
    332     /*
    333      * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
    334      */
    335     .extern artUnlockObjectFromCode
    336 ENTRY art_quick_unlock_object
    337     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case exception allocation triggers GC
    338     mov    r1, r9                     @ pass Thread::Current
    339     mov    r2, sp                     @ pass SP
    340     bl     artUnlockObjectFromCode    @ (Object* obj, Thread*, SP)
    341     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    342     RETURN_IF_RESULT_IS_ZERO
    343     DELIVER_PENDING_EXCEPTION
    344 END art_quick_unlock_object
    345 
    346     /*
    347      * Entry from managed code that calls artCheckCastFromCode and delivers exception on failure.
    348      */
    349     .extern artCheckCastFromCode
    350 ENTRY art_quick_check_cast
    351     SETUP_REF_ONLY_CALLEE_SAVE_FRAME    @ save callee saves in case exception allocation triggers GC
    352     mov    r2, r9                       @ pass Thread::Current
    353     mov    r3, sp                       @ pass SP
    354     bl     artCheckCastFromCode         @ (Class* a, Class* b, Thread*, SP)
    355     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    356     RETURN_IF_RESULT_IS_ZERO
    357     DELIVER_PENDING_EXCEPTION
    358 END art_quick_check_cast
    359 
    360     /*
    361      * Entry from managed code that calls artCanPutArrayElementFromCode and delivers exception on
    362      * failure.
    363      */
    364     .extern artCanPutArrayElementFromCode
    365 ENTRY art_quick_can_put_array_element
    366     SETUP_REF_ONLY_CALLEE_SAVE_FRAME    @ save callee saves in case exception allocation triggers GC
    367     mov    r2, r9                         @ pass Thread::Current
    368     mov    r3, sp                         @ pass SP
    369     bl     artCanPutArrayElementFromCode  @ (Object* element, Class* array_class, Thread*, SP)
    370     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    371     RETURN_IF_RESULT_IS_ZERO
    372     DELIVER_PENDING_EXCEPTION
    373 END art_quick_can_put_array_element
    374 
    375     /*
    376      * Entry from managed code when uninitialized static storage, this stub will run the class
    377      * initializer and deliver the exception on error. On success the static storage base is
    378      * returned.
    379      */
    380     .extern artInitializeStaticStorageFromCode
    381 ENTRY art_quick_initialize_static_storage
    382     SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
    383     mov    r2, r9                              @ pass Thread::Current
    384     mov    r3, sp                              @ pass SP
    385     @ artInitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
    386     bl     artInitializeStaticStorageFromCode
    387     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    388     RETURN_IF_RESULT_IS_NON_ZERO
    389     DELIVER_PENDING_EXCEPTION
    390 END art_quick_initialize_static_storage
    391 
    392     /*
    393      * Entry from managed code when dex cache misses for a type_idx
    394      */
    395     .extern artInitializeTypeFromCode
    396 ENTRY art_quick_initialize_type
    397     SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
    398     mov    r2, r9                              @ pass Thread::Current
    399     mov    r3, sp                              @ pass SP
    400     @ artInitializeTypeFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
    401     bl     artInitializeTypeFromCode
    402     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    403     RETURN_IF_RESULT_IS_NON_ZERO
    404     DELIVER_PENDING_EXCEPTION
    405 END art_quick_initialize_type
    406 
    407     /*
    408      * Entry from managed code when type_idx needs to be checked for access and dex cache may also
    409      * miss.
    410      */
    411     .extern artInitializeTypeAndVerifyAccessFromCode
    412 ENTRY art_quick_initialize_type_and_verify_access
    413     SETUP_REF_ONLY_CALLEE_SAVE_FRAME           @ save callee saves in case of GC
    414     mov    r2, r9                              @ pass Thread::Current
    415     mov    r3, sp                              @ pass SP
    416     @ artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Method* referrer, Thread*, SP)
    417     bl     artInitializeTypeAndVerifyAccessFromCode
    418     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    419     RETURN_IF_RESULT_IS_NON_ZERO
    420     DELIVER_PENDING_EXCEPTION
    421 END art_quick_initialize_type_and_verify_access
    422 
    423     /*
    424      * Called by managed code to resolve a static field and load a 32-bit primitive value.
    425      */
    426     .extern artGet32StaticFromCode
    427 ENTRY art_quick_get32_static
    428     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    429     ldr    r1, [sp, #32]                 @ pass referrer
    430     mov    r2, r9                        @ pass Thread::Current
    431     mov    r3, sp                        @ pass SP
    432     bl     artGet32StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
    433     ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    434     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    435     cbnz   r1, 1f                        @ success if no exception pending
    436     bx     lr                            @ return on success
    437 1:
    438     DELIVER_PENDING_EXCEPTION
    439 END art_quick_get32_static
    440 
    441     /*
    442      * Called by managed code to resolve a static field and load a 64-bit primitive value.
    443      */
    444     .extern artGet64StaticFromCode
    445 ENTRY art_quick_get64_static
    446     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    447     ldr    r1, [sp, #32]                 @ pass referrer
    448     mov    r2, r9                        @ pass Thread::Current
    449     mov    r3, sp                        @ pass SP
    450     bl     artGet64StaticFromCode        @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
    451     ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    452     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    453     cbnz   r2, 1f                        @ success if no exception pending
    454     bx     lr                            @ return on success
    455 1:
    456     DELIVER_PENDING_EXCEPTION
    457 END art_quick_get64_static
    458 
    459     /*
    460      * Called by managed code to resolve a static field and load an object reference.
    461      */
    462     .extern artGetObjStaticFromCode
    463 ENTRY art_quick_get_obj_static
    464     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    465     ldr    r1, [sp, #32]                 @ pass referrer
    466     mov    r2, r9                        @ pass Thread::Current
    467     mov    r3, sp                        @ pass SP
    468     bl     artGetObjStaticFromCode       @ (uint32_t field_idx, const Method* referrer, Thread*, SP)
    469     ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    470     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    471     cbnz   r1, 1f                        @ success if no exception pending
    472     bx     lr                            @ return on success
    473 1:
    474     DELIVER_PENDING_EXCEPTION
    475 END art_quick_get_obj_static
    476 
    477     /*
    478      * Called by managed code to resolve an instance field and load a 32-bit primitive value.
    479      */
    480     .extern artGet32InstanceFromCode
    481 ENTRY art_quick_get32_instance
    482     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    483     ldr    r2, [sp, #32]                 @ pass referrer
    484     mov    r3, r9                        @ pass Thread::Current
    485     mov    r12, sp
    486     str    r12, [sp, #-16]!              @ expand the frame and pass SP
    487     bl     artGet32InstanceFromCode      @ (field_idx, Object*, referrer, Thread*, SP)
    488     add    sp, #16                       @ strip the extra frame
    489     ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    490     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    491     cbnz   r1, 1f                        @ success if no exception pending
    492     bx     lr                            @ return on success
    493 1:
    494     DELIVER_PENDING_EXCEPTION
    495 END art_quick_get32_instance
    496 
    497     /*
    498      * Called by managed code to resolve an instance field and load a 64-bit primitive value.
    499      */
    500     .extern artGet64InstanceFromCode
    501 ENTRY art_quick_get64_instance
    502     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    503     ldr    r2, [sp, #32]                 @ pass referrer
    504     mov    r3, r9                        @ pass Thread::Current
    505     mov    r12, sp
    506     str    r12, [sp, #-16]!              @ expand the frame and pass SP
    507     .pad #16
    508     .cfi_adjust_cfa_offset 16
    509     bl     artGet64InstanceFromCode      @ (field_idx, Object*, referrer, Thread*, SP)
    510     add    sp, #16                       @ strip the extra frame
    511     .cfi_adjust_cfa_offset -16
    512     ldr    r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    513     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    514     cbnz   r2, 1f                        @ success if no exception pending
    515     bx     lr                            @ return on success
    516 1:
    517     DELIVER_PENDING_EXCEPTION
    518 END art_quick_get64_instance
    519 
    520     /*
    521      * Called by managed code to resolve an instance field and load an object reference.
    522      */
    523     .extern artGetObjInstanceFromCode
    524 ENTRY art_quick_get_obj_instance
    525     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    526     ldr    r2, [sp, #32]                 @ pass referrer
    527     mov    r3, r9                        @ pass Thread::Current
    528     mov    r12, sp
    529     str    r12, [sp, #-16]!              @ expand the frame and pass SP
    530     .pad #16
    531     .cfi_adjust_cfa_offset 16
    532     bl     artGetObjInstanceFromCode     @ (field_idx, Object*, referrer, Thread*, SP)
    533     add    sp, #16                       @ strip the extra frame
    534     .cfi_adjust_cfa_offset -16
    535     ldr    r1, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    536     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    537     cbnz   r1, 1f                        @ success if no exception pending
    538     bx     lr                            @ return on success
    539 1:
    540     DELIVER_PENDING_EXCEPTION
    541 END art_quick_get_obj_instance
    542 
    543     /*
    544      * Called by managed code to resolve a static field and store a 32-bit primitive value.
    545      */
    546     .extern artSet32StaticFromCode
    547 ENTRY art_quick_set32_static
    548     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    549     ldr    r2, [sp, #32]                 @ pass referrer
    550     mov    r3, r9                        @ pass Thread::Current
    551     mov    r12, sp
    552     str    r12, [sp, #-16]!              @ expand the frame and pass SP
    553     .pad #16
    554     .cfi_adjust_cfa_offset 16
    555     bl     artSet32StaticFromCode        @ (field_idx, new_val, referrer, Thread*, SP)
    556     add    sp, #16                       @ strip the extra frame
    557     .cfi_adjust_cfa_offset -16
    558     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    559     RETURN_IF_RESULT_IS_ZERO
    560     DELIVER_PENDING_EXCEPTION
    561 END art_quick_set32_static
    562 
    563     /*
    564      * Called by managed code to resolve a static field and store a 64-bit primitive value.
    565      * On entry r0 holds field index, r1:r2 hold new_val
    566      */
    567     .extern artSet64StaticFromCode
    568 ENTRY art_quick_set64_static
    569     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    570     mov    r3, r2                        @ pass one half of wide argument
    571     mov    r2, r1                        @ pass other half of wide argument
    572     ldr    r1, [sp, #32]                 @ pass referrer
    573     mov    r12, sp                       @ save SP
    574     sub    sp, #8                        @ grow frame for alignment with stack args
    575     .pad #8
    576     .cfi_adjust_cfa_offset 8
    577     push   {r9, r12}                     @ pass Thread::Current and SP
    578     .save {r9, r12}
    579     .cfi_adjust_cfa_offset 8
    580     .cfi_rel_offset r9, 0
    581     bl     artSet64StaticFromCode        @ (field_idx, referrer, new_val, Thread*, SP)
    582     add    sp, #16                       @ release out args
    583     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
    584     RETURN_IF_RESULT_IS_ZERO
    585     DELIVER_PENDING_EXCEPTION
    586 END art_quick_set64_static
    587 
    588     /*
    589      * Called by managed code to resolve a static field and store an object reference.
    590      */
    591     .extern artSetObjStaticFromCode
    592 ENTRY art_quick_set_obj_static
    593     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    594     ldr    r2, [sp, #32]                 @ pass referrer
    595     mov    r3, r9                        @ pass Thread::Current
    596     mov    r12, sp
    597     str    r12, [sp, #-16]!              @ expand the frame and pass SP
    598     .pad #16
    599     .cfi_adjust_cfa_offset 16
    600     bl     artSetObjStaticFromCode       @ (field_idx, new_val, referrer, Thread*, SP)
    601     add    sp, #16                       @ strip the extra frame
    602     .cfi_adjust_cfa_offset -16
    603     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    604     RETURN_IF_RESULT_IS_ZERO
    605     DELIVER_PENDING_EXCEPTION
    606 END art_quick_set_obj_static
    607 
    608     /*
    609      * Called by managed code to resolve an instance field and store a 32-bit primitive value.
    610      */
    611     .extern artSet32InstanceFromCode
    612 ENTRY art_quick_set32_instance
    613     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    614     ldr    r3, [sp, #32]                 @ pass referrer
    615     mov    r12, sp                       @ save SP
    616     sub    sp, #8                        @ grow frame for alignment with stack args
    617     .pad #8
    618     .cfi_adjust_cfa_offset 8
    619     push   {r9, r12}                     @ pass Thread::Current and SP
    620     .save {r9, r12}
    621     .cfi_adjust_cfa_offset 8
    622     .cfi_rel_offset r9, 0
    623     .cfi_rel_offset r12, 4
    624     bl     artSet32InstanceFromCode      @ (field_idx, Object*, new_val, referrer, Thread*, SP)
    625     add    sp, #16                       @ release out args
    626     .cfi_adjust_cfa_offset -16
    627     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
    628     RETURN_IF_RESULT_IS_ZERO
    629     DELIVER_PENDING_EXCEPTION
    630 END art_quick_set32_instance
    631 
    632     /*
    633      * Called by managed code to resolve an instance field and store a 64-bit primitive value.
    634      */
    635     .extern artSet32InstanceFromCode
    636 ENTRY art_quick_set64_instance
    637     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    638     mov    r12, sp                       @ save SP
    639     sub    sp, #8                        @ grow frame for alignment with stack args
    640     .pad #8
    641     .cfi_adjust_cfa_offset 8
    642     push   {r9, r12}                     @ pass Thread::Current and SP
    643     .save {r9, r12}
    644     .cfi_adjust_cfa_offset 8
    645     .cfi_rel_offset r9, 0
    646     bl     artSet64InstanceFromCode      @ (field_idx, Object*, new_val, Thread*, SP)
    647     add    sp, #16                       @ release out args
    648     .cfi_adjust_cfa_offset -16
    649     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
    650     RETURN_IF_RESULT_IS_ZERO
    651     DELIVER_PENDING_EXCEPTION
    652 END art_quick_set64_instance
    653 
    654     /*
    655      * Called by managed code to resolve an instance field and store an object reference.
    656      */
    657     .extern artSetObjInstanceFromCode
    658 ENTRY art_quick_set_obj_instance
    659     SETUP_REF_ONLY_CALLEE_SAVE_FRAME     @ save callee saves in case of GC
    660     ldr    r3, [sp, #32]                 @ pass referrer
    661     mov    r12, sp                       @ save SP
    662     sub    sp, #8                        @ grow frame for alignment with stack args
    663     .pad #8
    664     .cfi_adjust_cfa_offset 8
    665     push   {r9, r12}                     @ pass Thread::Current and SP
    666     .save {r9, r12}
    667     .cfi_adjust_cfa_offset 8
    668     .cfi_rel_offset r9, 0
    669     bl     artSetObjInstanceFromCode     @ (field_idx, Object*, new_val, referrer, Thread*, SP)
    670     add    sp, #16                       @ release out args
    671     .cfi_adjust_cfa_offset -16
    672     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME   @ TODO: we can clearly save an add here
    673     RETURN_IF_RESULT_IS_ZERO
    674     DELIVER_PENDING_EXCEPTION
    675 END art_quick_set_obj_instance
    676 
    677     /*
    678      * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
    679      * exception on error. On success the String is returned. R0 holds the referring method,
    680      * R1 holds the string index. The fast path check for hit in strings cache has already been
    681      * performed.
    682      */
    683     .extern artResolveStringFromCode
    684 ENTRY art_quick_resolve_string
    685     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
    686     mov    r2, r9                     @ pass Thread::Current
    687     mov    r3, sp                     @ pass SP
    688     @ artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*, SP)
    689     bl     artResolveStringFromCode
    690     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    691     RETURN_IF_RESULT_IS_NON_ZERO
    692     DELIVER_PENDING_EXCEPTION
    693 END art_quick_resolve_string
    694 
    695     /*
    696      * Called by managed code to allocate an object
    697      */
    698     .extern artAllocObjectFromCode
    699 ENTRY art_quick_alloc_object
    700     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
    701     mov    r2, r9                     @ pass Thread::Current
    702     mov    r3, sp                     @ pass SP
    703     bl     artAllocObjectFromCode     @ (uint32_t type_idx, Method* method, Thread*, SP)
    704     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    705     RETURN_IF_RESULT_IS_NON_ZERO
    706     DELIVER_PENDING_EXCEPTION
    707 END art_quick_alloc_object
    708 
    709     /*
    710      * Called by managed code to allocate an object when the caller doesn't know whether it has
    711      * access to the created type.
    712      */
    713     .extern artAllocObjectFromCodeWithAccessCheck
    714 ENTRY art_quick_alloc_object_with_access_check
    715     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
    716     mov    r2, r9                     @ pass Thread::Current
    717     mov    r3, sp                     @ pass SP
    718     bl     artAllocObjectFromCodeWithAccessCheck  @ (uint32_t type_idx, Method* method, Thread*, SP)
    719     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    720     RETURN_IF_RESULT_IS_NON_ZERO
    721     DELIVER_PENDING_EXCEPTION
    722 END art_quick_alloc_object_with_access_check
    723 
    724     /*
    725      * Called by managed code to allocate an array.
    726      */
    727     .extern artAllocArrayFromCode
    728 ENTRY art_quick_alloc_array
    729     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
    730     mov    r3, r9                     @ pass Thread::Current
    731     mov    r12, sp
    732     str    r12, [sp, #-16]!           @ expand the frame and pass SP
    733     .pad #16
    734     .cfi_adjust_cfa_offset 16
    735     @ artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count, Thread*, SP)
    736     bl     artAllocArrayFromCode
    737     add    sp, #16                    @ strip the extra frame
    738     .cfi_adjust_cfa_offset -16
    739     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    740     RETURN_IF_RESULT_IS_NON_ZERO
    741     DELIVER_PENDING_EXCEPTION
    742 END art_quick_alloc_array
    743 
    744     /*
    745      * Called by managed code to allocate an array when the caller doesn't know whether it has
    746      * access to the created type.
    747      */
    748     .extern artAllocArrayFromCodeWithAccessCheck
    749 ENTRY art_quick_alloc_array_with_access_check
    750     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
    751     mov    r3, r9                     @ pass Thread::Current
    752     mov    r12, sp
    753     str    r12, [sp, #-16]!           @ expand the frame and pass SP
    754     .pad #16
    755     .cfi_adjust_cfa_offset 16
    756     @ artAllocArrayFromCodeWithAccessCheck(type_idx, method, component_count, Thread*, SP)
    757     bl     artAllocArrayFromCodeWithAccessCheck
    758     add    sp, #16                    @ strip the extra frame
    759     .cfi_adjust_cfa_offset -16
    760     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    761     RETURN_IF_RESULT_IS_NON_ZERO
    762     DELIVER_PENDING_EXCEPTION
    763 END art_quick_alloc_array_with_access_check
    764 
    765     /*
    766      * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
    767      */
    768     .extern artCheckAndAllocArrayFromCode
    769 ENTRY art_quick_check_and_alloc_array
    770     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
    771     mov    r3, r9                     @ pass Thread::Current
    772     mov    r12, sp
    773     str    r12, [sp, #-16]!           @ expand the frame and pass SP
    774     .pad #16
    775     .cfi_adjust_cfa_offset 16
    776     @ artCheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t count, Thread* , SP)
    777     bl     artCheckAndAllocArrayFromCode
    778     add    sp, #16                    @ strip the extra frame
    779     .cfi_adjust_cfa_offset -16
    780     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    781     RETURN_IF_RESULT_IS_NON_ZERO
    782     DELIVER_PENDING_EXCEPTION
    783 END art_quick_check_and_alloc_array
    784 
    785     /*
    786      * Called by managed code to allocate an array in a special case for FILLED_NEW_ARRAY.
    787      */
    788     .extern artCheckAndAllocArrayFromCodeWithAccessCheck
    789 ENTRY art_quick_check_and_alloc_array_with_access_check
    790     SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
    791     mov    r3, r9                     @ pass Thread::Current
    792     mov    r12, sp
    793     str    r12, [sp, #-16]!           @ expand the frame and pass SP
    794     .pad #16
    795     .cfi_adjust_cfa_offset 16
    796     @ artCheckAndAllocArrayFromCodeWithAccessCheck(type_idx, method, count, Thread* , SP)
    797     bl     artCheckAndAllocArrayFromCodeWithAccessCheck
    798     add    sp, #16                    @ strip the extra frame
    799     .cfi_adjust_cfa_offset -16
    800     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
    801     RETURN_IF_RESULT_IS_NON_ZERO
    802     DELIVER_PENDING_EXCEPTION
    803 END art_quick_check_and_alloc_array_with_access_check
    804 
    805     /*
    806      * Called by managed code when the value in rSUSPEND has been decremented to 0.
    807      */
    808     .extern artTestSuspendFromCode
    809 ENTRY art_quick_test_suspend
    810     ldrh    r0, [rSELF, #THREAD_FLAGS_OFFSET]
    811     mov    rSUSPEND, #SUSPEND_CHECK_INTERVAL  @ reset rSUSPEND to SUSPEND_CHECK_INTERVAL
    812     cbnz   r0, 1f                             @ check Thread::Current()->suspend_count_ == 0
    813     bx     lr                                 @ return if suspend_count_ == 0
    814 1:
    815     mov    r0, rSELF
    816     SETUP_REF_ONLY_CALLEE_SAVE_FRAME          @ save callee saves for stack crawl
    817     mov    r1, sp
    818     bl     artTestSuspendFromCode             @ (Thread*, SP)
    819     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME_AND_RETURN
    820 END art_quick_test_suspend
    821 
    822     /*
    823      * Called by managed code that is attempting to call a method on a proxy class. On entry
    824      * r0 holds the proxy method and r1 holds the receiver; r2 and r3 may contain arguments. The
    825      * frame size of the invoked proxy method agrees with a ref and args callee save frame.
    826      */
    827      .extern artQuickProxyInvokeHandler
    828 ENTRY art_quick_proxy_invoke_handler
    829     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
    830     str     r0, [sp, #0]           @ place proxy method at bottom of frame
    831     mov     r2, r9                 @ pass Thread::Current
    832     mov     r3, sp                 @ pass SP
    833     blx     artQuickProxyInvokeHandler  @ (Method* proxy method, receiver, Thread*, SP)
    834     ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    835     ldr     lr,  [sp, #44]         @ restore lr
    836     add     sp,  #48               @ pop frame
    837     .cfi_adjust_cfa_offset -48
    838     cbnz    r2, 1f                 @ success if no exception is pending
    839     bx      lr                     @ return on success
    840 1:
    841     DELIVER_PENDING_EXCEPTION
    842 END art_quick_proxy_invoke_handler
    843 
    844     .extern artQuickResolutionTrampoline
    845 ENTRY art_quick_resolution_trampoline
    846     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
    847     mov     r2, r9                 @ pass Thread::Current
    848     mov     r3, sp                 @ pass SP
    849     blx     artQuickResolutionTrampoline  @ (Method* called, receiver, Thread*, SP)
    850     cbz     r0, 1f                 @ is code pointer null? goto exception
    851     mov     r12, r0
    852     ldr  r0, [sp, #0]              @ load resolved method in r0
    853     ldr  r1, [sp, #8]              @ restore non-callee save r1
    854     ldrd r2, [sp, #12]             @ restore non-callee saves r2-r3
    855     ldr  lr, [sp, #44]             @ restore lr
    856     add  sp, #48                   @ rewind sp
    857     .cfi_adjust_cfa_offset -48
    858     bx      r12                    @ tail-call into actual code
    859 1:
    860     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
    861     DELIVER_PENDING_EXCEPTION
    862 END art_quick_resolution_trampoline
    863 
    864     .extern artQuickToInterpreterBridge
    865 ENTRY art_quick_to_interpreter_bridge
    866     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
    867     mov     r1, r9                 @ pass Thread::Current
    868     mov     r2, sp                 @ pass SP
    869     blx     artQuickToInterpreterBridge    @ (Method* method, Thread*, SP)
    870     ldr     r2, [r9, #THREAD_EXCEPTION_OFFSET]  @ load Thread::Current()->exception_
    871     ldr     lr,  [sp, #44]         @ restore lr
    872     add     sp,  #48               @ pop frame
    873     .cfi_adjust_cfa_offset -48
    874     cbnz    r2, 1f                 @ success if no exception is pending
    875     bx    lr                       @ return on success
    876 1:
    877     DELIVER_PENDING_EXCEPTION
    878 END art_quick_to_interpreter_bridge
    879 
    880     /*
    881      * Routine that intercepts method calls and returns.
    882      */
    883     .extern artInstrumentationMethodEntryFromCode
    884     .extern artInstrumentationMethodExitFromCode
    885 ENTRY art_quick_instrumentation_entry
    886     SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
    887     str   r0, [sp, #4]     @ preserve r0
    888     mov   r12, sp          @ remember sp
    889     str   lr, [sp, #-16]!  @ expand the frame and pass LR
    890     .pad #16
    891     .cfi_adjust_cfa_offset 16
    892     .cfi_rel_offset lr, 0
    893     mov   r2, r9         @ pass Thread::Current
    894     mov   r3, r12        @ pass SP
    895     blx   artInstrumentationMethodEntryFromCode  @ (Method*, Object*, Thread*, SP, LR)
    896     add   sp, #16        @ remove out argument and padding from stack
    897     .cfi_adjust_cfa_offset -16
    898     mov   r12, r0        @ r12 holds reference to code
    899     ldr   r0, [sp, #4]   @ restore r0
    900     RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
    901     blx   r12            @ call method with lr set to art_quick_instrumentation_exit
    902 END art_quick_instrumentation_entry
    903     .type art_quick_instrumentation_exit, #function
    904     .global art_quick_instrumentation_exit
    905 art_quick_instrumentation_exit:
    906     .cfi_startproc
    907     .fnstart
    908     mov   lr, #0         @ link register is to here, so clobber with 0 for later checks
    909     SETUP_REF_ONLY_CALLEE_SAVE_FRAME
    910     mov   r12, sp        @ remember bottom of caller's frame
    911     push  {r0-r1}        @ save return value
    912     .save {r0-r1}
    913     .cfi_adjust_cfa_offset 8
    914     .cfi_rel_offset r0, 0
    915     .cfi_rel_offset r1, 4
    916     sub   sp, #8         @ space for return value argument
    917     .pad #8
    918     .cfi_adjust_cfa_offset 8
    919     strd r0, [sp]        @ r0/r1 -> [sp] for fpr_res
    920     mov   r2, r0         @ pass return value as gpr_res
    921     mov   r3, r1
    922     mov   r0, r9         @ pass Thread::Current
    923     mov   r1, r12        @ pass SP
    924     blx   artInstrumentationMethodExitFromCode  @ (Thread*, SP, gpr_res, fpr_res)
    925     add   sp, #8
    926     .cfi_adjust_cfa_offset -8
    927 
    928     mov   r2, r0         @ link register saved by instrumentation
    929     mov   lr, r1         @ r1 is holding link register if we're to bounce to deoptimize
    930     pop   {r0, r1}       @ restore return value
    931     add sp, #32          @ remove callee save frame
    932     .cfi_adjust_cfa_offset -32
    933     bx    r2             @ return
    934 END art_quick_instrumentation_exit
    935 
    936     /*
    937      * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
    938      * will long jump to the upcall with a special exception of -1.
    939      */
    940     .extern artDeoptimize
    941 ENTRY art_quick_deoptimize
    942     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
    943     mov    r0, r9         @ Set up args.
    944     mov    r1, sp
    945     blx    artDeoptimize  @ artDeoptimize(Thread*, SP)
    946 END art_quick_deoptimize
    947 
    948     /*
    949      * Signed 64-bit integer multiply.
    950      *
    951      * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
    952      *        WX
    953      *      x YZ
    954      *  --------
    955      *     ZW ZX
    956      *  YW YX
    957      *
    958      * The low word of the result holds ZX, the high word holds
    959      * (ZW+YX) + (the high overflow from ZX).  YW doesn't matter because
    960      * it doesn't fit in the low 64 bits.
    961      *
    962      * Unlike most ARM math operations, multiply instructions have
    963      * restrictions on using the same register more than once (Rd and Rm
    964      * cannot be the same).
    965      */
    966     /* mul-long vAA, vBB, vCC */
    967 ENTRY art_quick_mul_long
    968     push    {r9 - r10}
    969     .save {r9 - r10}
    970     .cfi_adjust_cfa_offset 8
    971     .cfi_rel_offset r9, 0
    972     .cfi_rel_offset r10, 4
    973     mul     ip, r2, r1                  @  ip<- ZxW
    974     umull   r9, r10, r2, r0             @  r9/r10 <- ZxX
    975     mla     r2, r0, r3, ip              @  r2<- YxX + (ZxW)
    976     add     r10, r2, r10                @  r10<- r10 + low(ZxW + (YxX))
    977     mov     r0,r9
    978     mov     r1,r10
    979     pop     {r9 - r10}
    980     .cfi_adjust_cfa_offset -8
    981     bx      lr
    982 END art_quick_mul_long
    983 
    984     /*
    985      * Long integer shift.  This is different from the generic 32/64-bit
    986      * binary operations because vAA/vBB are 64-bit but vCC (the shift
    987      * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
    988      * 6 bits.
    989      * On entry:
    990      *   r0: low word
    991      *   r1: high word
    992      *   r2: shift count
    993      */
    994     /* shl-long vAA, vBB, vCC */
    995 ARM_ENTRY art_quick_shl_long            @ ARM code as thumb code requires spills
    996     and     r2, r2, #63                 @ r2<- r2 & 0x3f
    997     mov     r1, r1, asl r2              @  r1<- r1 << r2
    998     rsb     r3, r2, #32                 @  r3<- 32 - r2
    999     orr     r1, r1, r0, lsr r3          @  r1<- r1 | (r0 << (32-r2))
   1000     subs    ip, r2, #32                 @  ip<- r2 - 32
   1001     movpl   r1, r0, asl ip              @  if r2 >= 32, r1<- r0 << (r2-32)
   1002     mov     r0, r0, asl r2              @  r0<- r0 << r2
   1003     bx      lr
   1004 END art_quick_shl_long
   1005 
   1006     /*
   1007      * Long integer shift.  This is different from the generic 32/64-bit
   1008      * binary operations because vAA/vBB are 64-bit but vCC (the shift
   1009      * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
   1010      * 6 bits.
   1011      * On entry:
   1012      *   r0: low word
   1013      *   r1: high word
   1014      *   r2: shift count
   1015      */
   1016     /* shr-long vAA, vBB, vCC */
   1017 ARM_ENTRY art_quick_shr_long            @ ARM code as thumb code requires spills
   1018     and     r2, r2, #63                 @ r0<- r0 & 0x3f
   1019     mov     r0, r0, lsr r2              @  r0<- r2 >> r2
   1020     rsb     r3, r2, #32                 @  r3<- 32 - r2
   1021     orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
   1022     subs    ip, r2, #32                 @  ip<- r2 - 32
   1023     movpl   r0, r1, asr ip              @  if r2 >= 32, r0<-r1 >> (r2-32)
   1024     mov     r1, r1, asr r2              @  r1<- r1 >> r2
   1025     bx      lr
   1026 END art_quick_shr_long
   1027 
   1028     /*
   1029      * Long integer shift.  This is different from the generic 32/64-bit
   1030      * binary operations because vAA/vBB are 64-bit but vCC (the shift
   1031      * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
   1032      * 6 bits.
   1033      * On entry:
   1034      *   r0: low word
   1035      *   r1: high word
   1036      *   r2: shift count
   1037      */
   1038     /* ushr-long vAA, vBB, vCC */
   1039 ARM_ENTRY art_quick_ushr_long           @ ARM code as thumb code requires spills
   1040     and     r2, r2, #63                 @ r0<- r0 & 0x3f
   1041     mov     r0, r0, lsr r2              @  r0<- r2 >> r2
   1042     rsb     r3, r2, #32                 @  r3<- 32 - r2
   1043     orr     r0, r0, r1, asl r3          @  r0<- r0 | (r1 << (32-r2))
   1044     subs    ip, r2, #32                 @  ip<- r2 - 32
   1045     movpl   r0, r1, lsr ip              @  if r2 >= 32, r0<-r1 >>> (r2-32)
   1046     mov     r1, r1, lsr r2              @  r1<- r1 >>> r2
   1047     bx      lr
   1048 END art_quick_ushr_long
   1049 
   1050     /*
   1051      * String's indexOf.
   1052      *
   1053      * On entry:
   1054      *    r0:   string object (known non-null)
   1055      *    r1:   char to match (known <= 0xFFFF)
   1056      *    r2:   Starting offset in string data
   1057      */
   1058 ENTRY art_quick_indexof
   1059     push {r4, r10-r11, lr} @ 4 words of callee saves
   1060     .save {r4, r10-r11, lr}
   1061     .cfi_adjust_cfa_offset 16
   1062     .cfi_rel_offset r4, 0
   1063     .cfi_rel_offset r10, 4
   1064     .cfi_rel_offset r11, 8
   1065     .cfi_rel_offset lr, 12
   1066     ldr   r3, [r0, #STRING_COUNT_OFFSET]
   1067     ldr   r12, [r0, #STRING_OFFSET_OFFSET]
   1068     ldr   r0, [r0, #STRING_VALUE_OFFSET]
   1069 
   1070     /* Clamp start to [0..count] */
   1071     cmp   r2, #0
   1072     it    lt
   1073     movlt r2, #0
   1074     cmp   r2, r3
   1075     it    gt
   1076     movgt r2, r3
   1077 
   1078     /* Build a pointer to the start of string data */
   1079     add   r0, #STRING_DATA_OFFSET
   1080     add   r0, r0, r12, lsl #1
   1081 
   1082     /* Save a copy in r12 to later compute result */
   1083     mov   r12, r0
   1084 
   1085     /* Build pointer to start of data to compare and pre-bias */
   1086     add   r0, r0, r2, lsl #1
   1087     sub   r0, #2
   1088 
   1089     /* Compute iteration count */
   1090     sub   r2, r3, r2
   1091 
   1092     /*
   1093      * At this point we have:
   1094      *   r0: start of data to test
   1095      *   r1: char to compare
   1096      *   r2: iteration count
   1097      *   r12: original start of string data
   1098      *   r3, r4, r10, r11 available for loading string data
   1099      */
   1100 
   1101     subs  r2, #4
   1102     blt   indexof_remainder
   1103 
   1104 indexof_loop4:
   1105     ldrh  r3, [r0, #2]!
   1106     ldrh  r4, [r0, #2]!
   1107     ldrh  r10, [r0, #2]!
   1108     ldrh  r11, [r0, #2]!
   1109     cmp   r3, r1
   1110     beq   match_0
   1111     cmp   r4, r1
   1112     beq   match_1
   1113     cmp   r10, r1
   1114     beq   match_2
   1115     cmp   r11, r1
   1116     beq   match_3
   1117     subs  r2, #4
   1118     bge   indexof_loop4
   1119 
   1120 indexof_remainder:
   1121     adds    r2, #4
   1122     beq     indexof_nomatch
   1123 
   1124 indexof_loop1:
   1125     ldrh  r3, [r0, #2]!
   1126     cmp   r3, r1
   1127     beq   match_3
   1128     subs  r2, #1
   1129     bne   indexof_loop1
   1130 
   1131 indexof_nomatch:
   1132     mov   r0, #-1
   1133     pop {r4, r10-r11, pc}
   1134 
   1135 match_0:
   1136     sub   r0, #6
   1137     sub   r0, r12
   1138     asr   r0, r0, #1
   1139     pop {r4, r10-r11, pc}
   1140 match_1:
   1141     sub   r0, #4
   1142     sub   r0, r12
   1143     asr   r0, r0, #1
   1144     pop {r4, r10-r11, pc}
   1145 match_2:
   1146     sub   r0, #2
   1147     sub   r0, r12
   1148     asr   r0, r0, #1
   1149     pop {r4, r10-r11, pc}
   1150 match_3:
   1151     sub   r0, r12
   1152     asr   r0, r0, #1
   1153     pop {r4, r10-r11, pc}
   1154 END art_quick_indexof
   1155 
   1156    /*
   1157      * String's compareTo.
   1158      *
   1159      * Requires rARG0/rARG1 to have been previously checked for null.  Will
   1160      * return negative if this's string is < comp, 0 if they are the
   1161      * same and positive if >.
   1162      *
   1163      * On entry:
   1164      *    r0:   this object pointer
   1165      *    r1:   comp object pointer
   1166      *
   1167      */
   1168     .extern __memcmp16
   1169 ENTRY art_quick_string_compareto
   1170     mov    r2, r0         @ this to r2, opening up r0 for return value
   1171     sub    r0, r2, r1     @ Same?
   1172     cbnz   r0,1f
   1173     bx     lr
   1174 1:                        @ Same strings, return.
   1175 
   1176     push {r4, r7-r12, lr} @ 8 words - keep alignment
   1177     .save {r4, r7-r12, lr}
   1178     .cfi_adjust_cfa_offset 32
   1179     .cfi_rel_offset r4, 0
   1180     .cfi_rel_offset r7, 4
   1181     .cfi_rel_offset r8, 8
   1182     .cfi_rel_offset r9, 12
   1183     .cfi_rel_offset r10, 16
   1184     .cfi_rel_offset r11, 20
   1185     .cfi_rel_offset r12, 24
   1186     .cfi_rel_offset lr, 28
   1187 
   1188     ldr    r4, [r2, #STRING_OFFSET_OFFSET]
   1189     ldr    r9, [r1, #STRING_OFFSET_OFFSET]
   1190     ldr    r7, [r2, #STRING_COUNT_OFFSET]
   1191     ldr    r10, [r1, #STRING_COUNT_OFFSET]
   1192     ldr    r2, [r2, #STRING_VALUE_OFFSET]
   1193     ldr    r1, [r1, #STRING_VALUE_OFFSET]
   1194 
   1195     /*
   1196      * At this point, we have:
   1197      *    value:  r2/r1
   1198      *    offset: r4/r9
   1199      *    count:  r7/r10
   1200      * We're going to compute
   1201      *    r11 <- countDiff
   1202      *    r10 <- minCount
   1203      */
   1204      subs  r11, r7, r10
   1205      it    ls
   1206      movls r10, r7
   1207 
   1208      /* Now, build pointers to the string data */
   1209      add   r2, r2, r4, lsl #1
   1210      add   r1, r1, r9, lsl #1
   1211      /*
   1212       * Note: data pointers point to previous element so we can use pre-index
   1213       * mode with base writeback.
   1214       */
   1215      add   r2, #STRING_DATA_OFFSET-2   @ offset to contents[-1]
   1216      add   r1, #STRING_DATA_OFFSET-2   @ offset to contents[-1]
   1217 
   1218      /*
   1219       * At this point we have:
   1220       *   r2: *this string data
   1221       *   r1: *comp string data
   1222       *   r10: iteration count for comparison
   1223       *   r11: value to return if the first part of the string is equal
   1224       *   r0: reserved for result
   1225       *   r3, r4, r7, r8, r9, r12 available for loading string data
   1226       */
   1227 
   1228     subs  r10, #2
   1229     blt   do_remainder2
   1230 
   1231       /*
   1232        * Unroll the first two checks so we can quickly catch early mismatch
   1233        * on long strings (but preserve incoming alignment)
   1234        */
   1235 
   1236     ldrh  r3, [r2, #2]!
   1237     ldrh  r4, [r1, #2]!
   1238     ldrh  r7, [r2, #2]!
   1239     ldrh  r8, [r1, #2]!
   1240     subs  r0, r3, r4
   1241     it    eq
   1242     subseq  r0, r7, r8
   1243     bne   done
   1244     cmp   r10, #28
   1245     bgt   do_memcmp16
   1246     subs  r10, #3
   1247     blt   do_remainder
   1248 
   1249 loopback_triple:
   1250     ldrh  r3, [r2, #2]!
   1251     ldrh  r4, [r1, #2]!
   1252     ldrh  r7, [r2, #2]!
   1253     ldrh  r8, [r1, #2]!
   1254     ldrh  r9, [r2, #2]!
   1255     ldrh  r12,[r1, #2]!
   1256     subs  r0, r3, r4
   1257     it    eq
   1258     subseq  r0, r7, r8
   1259     it    eq
   1260     subseq  r0, r9, r12
   1261     bne   done
   1262     subs  r10, #3
   1263     bge   loopback_triple
   1264 
   1265 do_remainder:
   1266     adds  r10, #3
   1267     beq   returnDiff
   1268 
   1269 loopback_single:
   1270     ldrh  r3, [r2, #2]!
   1271     ldrh  r4, [r1, #2]!
   1272     subs  r0, r3, r4
   1273     bne   done
   1274     subs  r10, #1
   1275     bne     loopback_single
   1276 
   1277 returnDiff:
   1278     mov   r0, r11
   1279     pop   {r4, r7-r12, pc}
   1280 
   1281 do_remainder2:
   1282     adds  r10, #2
   1283     bne   loopback_single
   1284     mov   r0, r11
   1285     pop   {r4, r7-r12, pc}
   1286 
   1287     /* Long string case */
   1288 do_memcmp16:
   1289     mov   r7, r11
   1290     add   r0, r2, #2
   1291     add   r1, r1, #2
   1292     mov   r2, r10
   1293     bl    __memcmp16
   1294     cmp   r0, #0
   1295     it    eq
   1296     moveq r0, r7
   1297 done:
   1298     pop   {r4, r7-r12, pc}
   1299 END art_quick_string_compareto
   1300