Home | History | Annotate | Download | only in mips
      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_mips.S"
     18 
     19 #include "arch/quick_alloc_entrypoints.S"
     20 
     21     .set noreorder
     22     .balign 4
     23 
     24     /* Deliver the given exception */
     25     .extern artDeliverExceptionFromCode
     26     /* Deliver an exception pending on a thread */
     27     .extern artDeliverPendingExceptionFromCode
     28 
     29 #define ARG_SLOT_SIZE   32    // space for a0-a3 plus 4 more words
     30 
     31     /*
     32      * Macro that sets up the callee save frame to conform with
     33      * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves)
     34      * Callee-save: $s0-$s8 + $gp + $ra, 11 total + 1 word for Method*
     35      * Clobbers $t0 and $sp
     36      * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
     37      * Reserves FRAME_SIZE_SAVE_ALL_CALLEE_SAVES + ARG_SLOT_SIZE bytes on the stack
     38      */
     39 .macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
     40     addiu  $sp, $sp, -112
     41     .cfi_adjust_cfa_offset 112
     42 
     43      // Ugly compile-time check, but we only have the preprocessor.
     44 #if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 112)
     45 #error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(MIPS) size not as expected."
     46 #endif
     47 
     48     sw     $ra, 108($sp)
     49     .cfi_rel_offset 31, 108
     50     sw     $s8, 104($sp)
     51     .cfi_rel_offset 30, 104
     52     sw     $gp, 100($sp)
     53     .cfi_rel_offset 28, 100
     54     sw     $s7, 96($sp)
     55     .cfi_rel_offset 23, 96
     56     sw     $s6, 92($sp)
     57     .cfi_rel_offset 22, 92
     58     sw     $s5, 88($sp)
     59     .cfi_rel_offset 21, 88
     60     sw     $s4, 84($sp)
     61     .cfi_rel_offset 20, 84
     62     sw     $s3, 80($sp)
     63     .cfi_rel_offset 19, 80
     64     sw     $s2, 76($sp)
     65     .cfi_rel_offset 18, 76
     66     sw     $s1, 72($sp)
     67     .cfi_rel_offset 17, 72
     68     sw     $s0, 68($sp)
     69     .cfi_rel_offset 16, 68
     70     // 4-byte placeholder for register $zero, serving for alignment
     71     // of the following double precision floating point registers.
     72 
     73     CHECK_ALIGNMENT $sp, $t1
     74     sdc1   $f30, 56($sp)
     75     sdc1   $f28, 48($sp)
     76     sdc1   $f26, 40($sp)
     77     sdc1   $f24, 32($sp)
     78     sdc1   $f22, 24($sp)
     79     sdc1   $f20, 16($sp)
     80 
     81     # 1 word for holding Method* plus 12 bytes padding to keep contents of SP
     82     # a multiple of 16.
     83 
     84     lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
     85     lw $t0, 0($t0)
     86     lw $t0, RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET($t0)
     87     sw $t0, 0($sp)                                # Place Method* at bottom of stack.
     88     sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
     89     addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
     90     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
     91 .endm
     92 
     93     /*
     94      * Macro that sets up the callee save frame to conform with
     95      * Runtime::CreateCalleeSaveMethod(kSaveRefsOnly). Restoration assumes non-moving GC.
     96      * Does not include rSUSPEND or rSELF
     97      * callee-save: $s2-$s8 + $gp + $ra, 9 total + 2 words padding + 1 word to hold Method*
     98      * Clobbers $t0 and $sp
     99      * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
    100      * Reserves FRAME_SIZE_SAVE_REFS_ONLY + ARG_SLOT_SIZE bytes on the stack
    101      */
    102 .macro SETUP_SAVE_REFS_ONLY_FRAME
    103     addiu  $sp, $sp, -48
    104     .cfi_adjust_cfa_offset 48
    105 
    106     // Ugly compile-time check, but we only have the preprocessor.
    107 #if (FRAME_SIZE_SAVE_REFS_ONLY != 48)
    108 #error "FRAME_SIZE_SAVE_REFS_ONLY(MIPS) size not as expected."
    109 #endif
    110 
    111     sw     $ra, 44($sp)
    112     .cfi_rel_offset 31, 44
    113     sw     $s8, 40($sp)
    114     .cfi_rel_offset 30, 40
    115     sw     $gp, 36($sp)
    116     .cfi_rel_offset 28, 36
    117     sw     $s7, 32($sp)
    118     .cfi_rel_offset 23, 32
    119     sw     $s6, 28($sp)
    120     .cfi_rel_offset 22, 28
    121     sw     $s5, 24($sp)
    122     .cfi_rel_offset 21, 24
    123     sw     $s4, 20($sp)
    124     .cfi_rel_offset 20, 20
    125     sw     $s3, 16($sp)
    126     .cfi_rel_offset 19, 16
    127     sw     $s2, 12($sp)
    128     .cfi_rel_offset 18, 12
    129     # 2 words for alignment and bottom word will hold Method*
    130 
    131     lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
    132     lw $t0, 0($t0)
    133     lw $t0, RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET($t0)
    134     sw $t0, 0($sp)                                # Place Method* at bottom of stack.
    135     sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
    136     addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
    137     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
    138 .endm
    139 
    140 .macro RESTORE_SAVE_REFS_ONLY_FRAME
    141     addiu  $sp, $sp, ARG_SLOT_SIZE                # remove argument slots on the stack
    142     .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
    143     lw     $ra, 44($sp)
    144     .cfi_restore 31
    145     lw     $s8, 40($sp)
    146     .cfi_restore 30
    147     lw     $gp, 36($sp)
    148     .cfi_restore 28
    149     lw     $s7, 32($sp)
    150     .cfi_restore 23
    151     lw     $s6, 28($sp)
    152     .cfi_restore 22
    153     lw     $s5, 24($sp)
    154     .cfi_restore 21
    155     lw     $s4, 20($sp)
    156     .cfi_restore 20
    157     lw     $s3, 16($sp)
    158     .cfi_restore 19
    159     lw     $s2, 12($sp)
    160     .cfi_restore 18
    161     addiu  $sp, $sp, 48
    162     .cfi_adjust_cfa_offset -48
    163 .endm
    164 
    165 .macro RESTORE_SAVE_REFS_ONLY_FRAME_AND_RETURN
    166     RESTORE_SAVE_REFS_ONLY_FRAME
    167     jalr   $zero, $ra
    168     nop
    169 .endm
    170 
    171     /*
    172      * Individually usable part of macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY.
    173      */
    174 .macro SETUP_SAVE_REFS_AND_ARGS_FRAME_S4_THRU_S8
    175     sw      $s8, 104($sp)
    176     .cfi_rel_offset 30, 104
    177     sw      $s7, 96($sp)
    178     .cfi_rel_offset 23, 96
    179     sw      $s6, 92($sp)
    180     .cfi_rel_offset 22, 92
    181     sw      $s5, 88($sp)
    182     .cfi_rel_offset 21, 88
    183     sw      $s4, 84($sp)
    184     .cfi_rel_offset 20, 84
    185 .endm
    186 
    187     /*
    188      * Macro that sets up the callee save frame to conform with
    189      * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs).
    190      * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
    191      *              (26 total + 1 word padding + method*)
    192      */
    193 .macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY save_s4_thru_s8=1
    194     addiu   $sp, $sp, -112
    195     .cfi_adjust_cfa_offset 112
    196 
    197     // Ugly compile-time check, but we only have the preprocessor.
    198 #if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 112)
    199 #error "FRAME_SIZE_SAVE_REFS_AND_ARGS(MIPS) size not as expected."
    200 #endif
    201 
    202     sw      $ra, 108($sp)
    203     .cfi_rel_offset 31, 108
    204     sw      $gp, 100($sp)
    205     .cfi_rel_offset 28, 100
    206     .if \save_s4_thru_s8
    207       SETUP_SAVE_REFS_AND_ARGS_FRAME_S4_THRU_S8
    208     .endif
    209     sw      $s3, 80($sp)
    210     .cfi_rel_offset 19, 80
    211     sw      $s2, 76($sp)
    212     .cfi_rel_offset 18, 76
    213     sw      $t1, 72($sp)
    214     .cfi_rel_offset 9, 72
    215     sw      $t0, 68($sp)
    216     .cfi_rel_offset 8, 68
    217     sw      $a3, 64($sp)
    218     .cfi_rel_offset 7, 64
    219     sw      $a2, 60($sp)
    220     .cfi_rel_offset 6, 60
    221     sw      $a1, 56($sp)
    222     .cfi_rel_offset 5, 56
    223     CHECK_ALIGNMENT $sp, $t8
    224     sdc1    $f18, 48($sp)
    225     sdc1    $f16, 40($sp)
    226     sdc1    $f14, 32($sp)
    227     sdc1    $f12, 24($sp)
    228     sdc1    $f10, 16($sp)
    229     sdc1    $f8,   8($sp)
    230     # bottom will hold Method*
    231 .endm
    232 
    233     /*
    234      * Macro that sets up the callee save frame to conform with
    235      * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
    236      * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
    237      *              (26 total + 1 word padding + method*)
    238      * Clobbers $t0 and $sp
    239      * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
    240      * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
    241      */
    242 .macro SETUP_SAVE_REFS_AND_ARGS_FRAME save_s4_thru_s8_only=0
    243     .if \save_s4_thru_s8_only
    244       // It is expected that `SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY /* save_s4_thru_s8 */ 0`
    245       // has been done prior to `SETUP_SAVE_REFS_AND_ARGS_FRAME /* save_s4_thru_s8_only */ 1`.
    246       SETUP_SAVE_REFS_AND_ARGS_FRAME_S4_THRU_S8
    247     .else
    248       SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
    249     .endif
    250     lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
    251     lw $t0, 0($t0)
    252     lw $t0, RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET($t0)
    253     sw $t0, 0($sp)                                # Place Method* at bottom of stack.
    254     sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
    255     addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
    256     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
    257 .endm
    258 
    259     /*
    260      * Macro that sets up the callee save frame to conform with
    261      * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs). Restoration assumes non-moving GC.
    262      * callee-save: $a1-$a3, $t0-$t1, $s2-$s8, $gp, $ra, $f8-$f19
    263      *              (26 total + 1 word padding + method*)
    264      * Clobbers $sp
    265      * Use $a0 as the Method* and loads it into bottom of stack.
    266      * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
    267      * Reserves FRAME_SIZE_SAVE_REFS_AND_ARGS + ARG_SLOT_SIZE bytes on the stack
    268      */
    269 .macro SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
    270     SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
    271     sw $a0, 0($sp)                                # Place Method* at bottom of stack.
    272     sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
    273     addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
    274     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
    275 .endm
    276 
    277     /*
    278      * Individually usable part of macro RESTORE_SAVE_REFS_AND_ARGS_FRAME.
    279      */
    280 .macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP
    281     lw      $gp, 100($sp)
    282     .cfi_restore 28
    283 .endm
    284 
    285     /*
    286      * Individually usable part of macro RESTORE_SAVE_REFS_AND_ARGS_FRAME.
    287      */
    288 .macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_A1
    289     lw      $a1, 56($sp)
    290     .cfi_restore 5
    291 .endm
    292 
    293 .macro RESTORE_SAVE_REFS_AND_ARGS_FRAME restore_s4_thru_s8=1, remove_arg_slots=1
    294     .if \remove_arg_slots
    295       addiu $sp, $sp, ARG_SLOT_SIZE                 # Remove argument slots from the stack.
    296       .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
    297     .endif
    298     lw      $ra, 108($sp)
    299     .cfi_restore 31
    300     .if \restore_s4_thru_s8
    301       lw    $s8, 104($sp)
    302       .cfi_restore 30
    303     .endif
    304     RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP
    305     .if \restore_s4_thru_s8
    306       lw    $s7, 96($sp)
    307       .cfi_restore 23
    308       lw    $s6, 92($sp)
    309       .cfi_restore 22
    310       lw    $s5, 88($sp)
    311       .cfi_restore 21
    312       lw    $s4, 84($sp)
    313       .cfi_restore 20
    314     .endif
    315     lw      $s3, 80($sp)
    316     .cfi_restore 19
    317     lw      $s2, 76($sp)
    318     .cfi_restore 18
    319     lw      $t1, 72($sp)
    320     .cfi_restore 9
    321     lw      $t0, 68($sp)
    322     .cfi_restore 8
    323     lw      $a3, 64($sp)
    324     .cfi_restore 7
    325     lw      $a2, 60($sp)
    326     .cfi_restore 6
    327     RESTORE_SAVE_REFS_AND_ARGS_FRAME_A1
    328     CHECK_ALIGNMENT $sp, $t8
    329     ldc1    $f18, 48($sp)
    330     ldc1    $f16, 40($sp)
    331     ldc1    $f14, 32($sp)
    332     ldc1    $f12, 24($sp)
    333     ldc1    $f10, 16($sp)
    334     ldc1    $f8,   8($sp)
    335     addiu   $sp, $sp, 112                           # Pop frame.
    336     .cfi_adjust_cfa_offset -112
    337 .endm
    338 
    339     /*
    340      * Macro that sets up the callee save frame to conform with
    341      * Runtime::CreateCalleeSaveMethod(kSaveEverything).
    342      * when the $sp has already been decremented by FRAME_SIZE_SAVE_EVERYTHING.
    343      * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
    344      *              28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
    345      * Clobbers $t0 and $t1.
    346      * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
    347      * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
    348      * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
    349      */
    350 .macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
    351      // Ugly compile-time check, but we only have the preprocessor.
    352 #if (FRAME_SIZE_SAVE_EVERYTHING != 256)
    353 #error "FRAME_SIZE_SAVE_EVERYTHING(MIPS) size not as expected."
    354 #endif
    355 
    356     sw     $ra, 252($sp)
    357     .cfi_rel_offset 31, 252
    358     sw     $fp, 248($sp)
    359     .cfi_rel_offset 30, 248
    360     sw     $gp, 244($sp)
    361     .cfi_rel_offset 28, 244
    362     sw     $t9, 240($sp)
    363     .cfi_rel_offset 25, 240
    364     sw     $t8, 236($sp)
    365     .cfi_rel_offset 24, 236
    366     sw     $s7, 232($sp)
    367     .cfi_rel_offset 23, 232
    368     sw     $s6, 228($sp)
    369     .cfi_rel_offset 22, 228
    370     sw     $s5, 224($sp)
    371     .cfi_rel_offset 21, 224
    372     sw     $s4, 220($sp)
    373     .cfi_rel_offset 20, 220
    374     sw     $s3, 216($sp)
    375     .cfi_rel_offset 19, 216
    376     sw     $s2, 212($sp)
    377     .cfi_rel_offset 18, 212
    378     sw     $s1, 208($sp)
    379     .cfi_rel_offset 17, 208
    380     sw     $s0, 204($sp)
    381     .cfi_rel_offset 16, 204
    382     sw     $t7, 200($sp)
    383     .cfi_rel_offset 15, 200
    384     sw     $t6, 196($sp)
    385     .cfi_rel_offset 14, 196
    386     sw     $t5, 192($sp)
    387     .cfi_rel_offset 13, 192
    388     sw     $t4, 188($sp)
    389     .cfi_rel_offset 12, 188
    390     sw     $t3, 184($sp)
    391     .cfi_rel_offset 11, 184
    392     sw     $t2, 180($sp)
    393     .cfi_rel_offset 10, 180
    394     sw     $t1, 176($sp)
    395     .cfi_rel_offset 9, 176
    396     sw     $t0, 172($sp)
    397     .cfi_rel_offset 8, 172
    398     sw     $a3, 168($sp)
    399     .cfi_rel_offset 7, 168
    400     sw     $a2, 164($sp)
    401     .cfi_rel_offset 6, 164
    402     sw     $a1, 160($sp)
    403     .cfi_rel_offset 5, 160
    404     sw     $a0, 156($sp)
    405     .cfi_rel_offset 4, 156
    406     sw     $v1, 152($sp)
    407     .cfi_rel_offset 3, 152
    408     sw     $v0, 148($sp)
    409     .cfi_rel_offset 2, 148
    410 
    411     // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
    412     bal 1f
    413     .set push
    414     .set noat
    415     sw     $at, 144($sp)
    416     .cfi_rel_offset 1, 144
    417     .set pop
    418 1:
    419     .cpload $ra
    420 
    421     CHECK_ALIGNMENT $sp, $t1
    422     sdc1   $f30, 136($sp)
    423     sdc1   $f28, 128($sp)
    424     sdc1   $f26, 120($sp)
    425     sdc1   $f24, 112($sp)
    426     sdc1   $f22, 104($sp)
    427     sdc1   $f20,  96($sp)
    428     sdc1   $f18,  88($sp)
    429     sdc1   $f16,  80($sp)
    430     sdc1   $f14,  72($sp)
    431     sdc1   $f12,  64($sp)
    432     sdc1   $f10,  56($sp)
    433     sdc1   $f8,   48($sp)
    434     sdc1   $f6,   40($sp)
    435     sdc1   $f4,   32($sp)
    436     sdc1   $f2,   24($sp)
    437     sdc1   $f0,   16($sp)
    438 
    439     # 3 words padding and 1 word for holding Method*
    440 
    441     lw $t0, %got(_ZN3art7Runtime9instance_E)($gp)
    442     lw $t0, 0($t0)
    443     lw $t0, \runtime_method_offset($t0)
    444     sw $t0, 0($sp)                                # Place Method* at bottom of stack.
    445     sw $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)  # Place sp in Thread::Current()->top_quick_frame.
    446     addiu  $sp, $sp, -ARG_SLOT_SIZE               # reserve argument slots on the stack
    447     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
    448 .endm
    449 
    450     /*
    451      * Macro that sets up the callee save frame to conform with
    452      * Runtime::CreateCalleeSaveMethod(kSaveEverything).
    453      * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
    454      *              28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
    455      * Clobbers $t0 and $t1.
    456      * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
    457      * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
    458      * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
    459      */
    460 .macro SETUP_SAVE_EVERYTHING_FRAME runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
    461     addiu  $sp, $sp, -(FRAME_SIZE_SAVE_EVERYTHING)
    462     .cfi_adjust_cfa_offset (FRAME_SIZE_SAVE_EVERYTHING)
    463     SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP \runtime_method_offset
    464 .endm
    465 
    466 .macro RESTORE_SAVE_EVERYTHING_FRAME restore_a0=1
    467     addiu  $sp, $sp, ARG_SLOT_SIZE                # remove argument slots on the stack
    468     .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
    469 
    470     CHECK_ALIGNMENT $sp, $t1
    471     ldc1   $f30, 136($sp)
    472     ldc1   $f28, 128($sp)
    473     ldc1   $f26, 120($sp)
    474     ldc1   $f24, 112($sp)
    475     ldc1   $f22, 104($sp)
    476     ldc1   $f20,  96($sp)
    477     ldc1   $f18,  88($sp)
    478     ldc1   $f16,  80($sp)
    479     ldc1   $f14,  72($sp)
    480     ldc1   $f12,  64($sp)
    481     ldc1   $f10,  56($sp)
    482     ldc1   $f8,   48($sp)
    483     ldc1   $f6,   40($sp)
    484     ldc1   $f4,   32($sp)
    485     ldc1   $f2,   24($sp)
    486     ldc1   $f0,   16($sp)
    487 
    488     lw     $ra, 252($sp)
    489     .cfi_restore 31
    490     lw     $fp, 248($sp)
    491     .cfi_restore 30
    492     lw     $gp, 244($sp)
    493     .cfi_restore 28
    494     lw     $t9, 240($sp)
    495     .cfi_restore 25
    496     lw     $t8, 236($sp)
    497     .cfi_restore 24
    498     lw     $s7, 232($sp)
    499     .cfi_restore 23
    500     lw     $s6, 228($sp)
    501     .cfi_restore 22
    502     lw     $s5, 224($sp)
    503     .cfi_restore 21
    504     lw     $s4, 220($sp)
    505     .cfi_restore 20
    506     lw     $s3, 216($sp)
    507     .cfi_restore 19
    508     lw     $s2, 212($sp)
    509     .cfi_restore 18
    510     lw     $s1, 208($sp)
    511     .cfi_restore 17
    512     lw     $s0, 204($sp)
    513     .cfi_restore 16
    514     lw     $t7, 200($sp)
    515     .cfi_restore 15
    516     lw     $t6, 196($sp)
    517     .cfi_restore 14
    518     lw     $t5, 192($sp)
    519     .cfi_restore 13
    520     lw     $t4, 188($sp)
    521     .cfi_restore 12
    522     lw     $t3, 184($sp)
    523     .cfi_restore 11
    524     lw     $t2, 180($sp)
    525     .cfi_restore 10
    526     lw     $t1, 176($sp)
    527     .cfi_restore 9
    528     lw     $t0, 172($sp)
    529     .cfi_restore 8
    530     lw     $a3, 168($sp)
    531     .cfi_restore 7
    532     lw     $a2, 164($sp)
    533     .cfi_restore 6
    534     lw     $a1, 160($sp)
    535     .cfi_restore 5
    536     .if \restore_a0
    537     lw     $a0, 156($sp)
    538     .cfi_restore 4
    539     .endif
    540     lw     $v1, 152($sp)
    541     .cfi_restore 3
    542     lw     $v0, 148($sp)
    543     .cfi_restore 2
    544     .set push
    545     .set noat
    546     lw     $at, 144($sp)
    547     .cfi_restore 1
    548     .set pop
    549 
    550     addiu  $sp, $sp, 256            # pop frame
    551     .cfi_adjust_cfa_offset -256
    552 .endm
    553 
    554     /*
    555      * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
    556      * exception is Thread::Current()->exception_ when the runtime method frame is ready.
    557      * Requires $gp properly set up.
    558      */
    559 .macro DELIVER_PENDING_EXCEPTION_FRAME_READY
    560     la      $t9, artDeliverPendingExceptionFromCode
    561     jalr    $zero, $t9                   # artDeliverPendingExceptionFromCode(Thread*)
    562     move    $a0, rSELF                   # pass Thread::Current
    563 .endm
    564 
    565     /*
    566      * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
    567      * exception is Thread::Current()->exception_.
    568      * Requires $gp properly set up.
    569      */
    570 .macro DELIVER_PENDING_EXCEPTION
    571     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME    # save callee saves for throw
    572     DELIVER_PENDING_EXCEPTION_FRAME_READY
    573 .endm
    574 
    575 .macro RETURN_IF_NO_EXCEPTION
    576     lw     $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
    577     RESTORE_SAVE_REFS_ONLY_FRAME
    578     bnez   $t0, 1f                       # success if no exception is pending
    579     nop
    580     jalr   $zero, $ra
    581     nop
    582 1:
    583     DELIVER_PENDING_EXCEPTION
    584 .endm
    585 
    586 .macro RETURN_IF_ZERO
    587     RESTORE_SAVE_REFS_ONLY_FRAME
    588     bnez   $v0, 1f                       # success?
    589     nop
    590     jalr   $zero, $ra                    # return on success
    591     nop
    592 1:
    593     DELIVER_PENDING_EXCEPTION
    594 .endm
    595 
    596 .macro RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
    597     RESTORE_SAVE_REFS_ONLY_FRAME
    598     beqz   $v0, 1f                       # success?
    599     nop
    600     jalr   $zero, $ra                    # return on success
    601     nop
    602 1:
    603     DELIVER_PENDING_EXCEPTION
    604 .endm
    605 
    606     /*
    607      * On stack replacement stub.
    608      * On entry:
    609      *   a0 = stack to copy
    610      *   a1 = size of stack
    611      *   a2 = pc to call
    612      *   a3 = JValue* result
    613      *   [sp + 16] = shorty
    614      *   [sp + 20] = thread
    615      */
    616 ENTRY art_quick_osr_stub
    617     // Save callee general purpose registers, RA and GP.
    618     addiu  $sp, $sp, -48
    619     .cfi_adjust_cfa_offset 48
    620     sw     $ra, 44($sp)
    621     .cfi_rel_offset 31, 44
    622     sw     $s8, 40($sp)
    623     .cfi_rel_offset 30, 40
    624     sw     $gp, 36($sp)
    625     .cfi_rel_offset 28, 36
    626     sw     $s7, 32($sp)
    627     .cfi_rel_offset 23, 32
    628     sw     $s6, 28($sp)
    629     .cfi_rel_offset 22, 28
    630     sw     $s5, 24($sp)
    631     .cfi_rel_offset 21, 24
    632     sw     $s4, 20($sp)
    633     .cfi_rel_offset 20, 20
    634     sw     $s3, 16($sp)
    635     .cfi_rel_offset 19, 16
    636     sw     $s2, 12($sp)
    637     .cfi_rel_offset 18, 12
    638     sw     $s1, 8($sp)
    639     .cfi_rel_offset 17, 8
    640     sw     $s0, 4($sp)
    641     .cfi_rel_offset 16, 4
    642 
    643     move   $s8, $sp                        # Save the stack pointer
    644     move   $s7, $a1                        # Save size of stack
    645     move   $s6, $a2                        # Save the pc to call
    646     lw     rSELF, 48+20($sp)               # Save managed thread pointer into rSELF
    647     addiu  $t0, $sp, -12                   # Reserve space for stack pointer,
    648                                            #    JValue* result, and ArtMethod* slot.
    649     srl    $t0, $t0, 4                     # Align stack pointer to 16 bytes
    650     sll    $sp, $t0, 4                     # Update stack pointer
    651     sw     $s8, 4($sp)                     # Save old stack pointer
    652     sw     $a3, 8($sp)                     # Save JValue* result
    653     sw     $zero, 0($sp)                   # Store null for ArtMethod* at bottom of frame
    654     subu   $sp, $a1                        # Reserve space for callee stack
    655     move   $a2, $a1
    656     move   $a1, $a0
    657     move   $a0, $sp
    658     la     $t9, memcpy
    659     jalr   $t9                             # memcpy (dest a0, src a1, bytes a2)
    660     addiu  $sp, $sp, -16                   # make space for argument slots for memcpy
    661     bal    .Losr_entry                     # Call the method
    662     addiu  $sp, $sp, 16                    # restore stack after memcpy
    663     lw     $a2, 8($sp)                     # Restore JValue* result
    664     lw     $sp, 4($sp)                     # Restore saved stack pointer
    665     lw     $a0, 48+16($sp)                 # load shorty
    666     lbu    $a0, 0($a0)                     # load return type
    667     li     $a1, 'D'                        # put char 'D' into a1
    668     beq    $a0, $a1, .Losr_fp_result       # Test if result type char == 'D'
    669     li     $a1, 'F'                        # put char 'F' into a1
    670     beq    $a0, $a1, .Losr_fp_result       # Test if result type char == 'F'
    671     nop
    672     sw     $v0, 0($a2)
    673     b      .Losr_exit
    674     sw     $v1, 4($a2)                     # store v0/v1 into result
    675 .Losr_fp_result:
    676     CHECK_ALIGNMENT $a2, $t0, 8
    677     sdc1   $f0, 0($a2)                     # store f0/f1 into result
    678 .Losr_exit:
    679     lw     $ra, 44($sp)
    680     .cfi_restore 31
    681     lw     $s8, 40($sp)
    682     .cfi_restore 30
    683     lw     $gp, 36($sp)
    684     .cfi_restore 28
    685     lw     $s7, 32($sp)
    686     .cfi_restore 23
    687     lw     $s6, 28($sp)
    688     .cfi_restore 22
    689     lw     $s5, 24($sp)
    690     .cfi_restore 21
    691     lw     $s4, 20($sp)
    692     .cfi_restore 20
    693     lw     $s3, 16($sp)
    694     .cfi_restore 19
    695     lw     $s2, 12($sp)
    696     .cfi_restore 18
    697     lw     $s1, 8($sp)
    698     .cfi_restore 17
    699     lw     $s0, 4($sp)
    700     .cfi_restore 16
    701     jalr   $zero, $ra
    702     addiu  $sp, $sp, 48
    703     .cfi_adjust_cfa_offset -48
    704 .Losr_entry:
    705     addiu  $s7, $s7, -4
    706     addu   $t0, $s7, $sp
    707     move   $t9, $s6
    708     jalr   $zero, $t9
    709     sw     $ra, 0($t0)                     # Store RA per the compiler ABI
    710 END art_quick_osr_stub
    711 
    712     /*
    713      * On entry $a0 is uint32_t* gprs_ and $a1 is uint32_t* fprs_.
    714      * Note that fprs_ is expected to be an address that is a multiple of 8.
    715      * FIXME: just guessing about the shape of the jmpbuf.  Where will pc be?
    716      */
    717 ENTRY art_quick_do_long_jump
    718     CHECK_ALIGNMENT $a1, $t1, 8
    719     ldc1    $f0,   0*8($a1)
    720     ldc1    $f2,   1*8($a1)
    721     ldc1    $f4,   2*8($a1)
    722     ldc1    $f6,   3*8($a1)
    723     ldc1    $f8,   4*8($a1)
    724     ldc1    $f10,  5*8($a1)
    725     ldc1    $f12,  6*8($a1)
    726     ldc1    $f14,  7*8($a1)
    727     ldc1    $f16,  8*8($a1)
    728     ldc1    $f18,  9*8($a1)
    729     ldc1    $f20, 10*8($a1)
    730     ldc1    $f22, 11*8($a1)
    731     ldc1    $f24, 12*8($a1)
    732     ldc1    $f26, 13*8($a1)
    733     ldc1    $f28, 14*8($a1)
    734     ldc1    $f30, 15*8($a1)
    735 
    736     .set push
    737     .set nomacro
    738     .set noat
    739     lw      $at, 4($a0)
    740     .set pop
    741     lw      $v0, 8($a0)
    742     lw      $v1, 12($a0)
    743     lw      $a1, 20($a0)
    744     lw      $a2, 24($a0)
    745     lw      $a3, 28($a0)
    746     lw      $t0, 32($a0)
    747     lw      $t1, 36($a0)
    748     lw      $t2, 40($a0)
    749     lw      $t3, 44($a0)
    750     lw      $t4, 48($a0)
    751     lw      $t5, 52($a0)
    752     lw      $t6, 56($a0)
    753     lw      $t7, 60($a0)
    754     lw      $s0, 64($a0)
    755     lw      $s1, 68($a0)
    756     lw      $s2, 72($a0)
    757     lw      $s3, 76($a0)
    758     lw      $s4, 80($a0)
    759     lw      $s5, 84($a0)
    760     lw      $s6, 88($a0)
    761     lw      $s7, 92($a0)
    762     lw      $t8, 96($a0)
    763     lw      $t9, 100($a0)
    764     lw      $gp, 112($a0)
    765     lw      $sp, 116($a0)
    766     lw      $fp, 120($a0)
    767     lw      $ra, 124($a0)
    768     lw      $a0, 16($a0)
    769     move    $v0, $zero          # clear result registers v0 and v1 (in branch delay slot)
    770     jalr    $zero, $t9          # do long jump
    771     move    $v1, $zero
    772 END art_quick_do_long_jump
    773 
    774     /*
    775      * Called by managed code, saves most registers (forms basis of long jump context) and passes
    776      * the bottom of the stack. artDeliverExceptionFromCode will place the callee save Method* at
    777      * the bottom of the thread. On entry a0 holds Throwable*
    778      */
    779 ENTRY art_quick_deliver_exception
    780     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
    781     la   $t9, artDeliverExceptionFromCode
    782     jalr $zero, $t9                 # artDeliverExceptionFromCode(Throwable*, Thread*)
    783     move $a1, rSELF                 # pass Thread::Current
    784 END art_quick_deliver_exception
    785 
    786     /*
    787      * Called by managed code to create and deliver a NullPointerException
    788      */
    789     .extern artThrowNullPointerExceptionFromCode
    790 ENTRY_NO_GP art_quick_throw_null_pointer_exception
    791     // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
    792     // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
    793     SETUP_SAVE_EVERYTHING_FRAME
    794     la   $t9, artThrowNullPointerExceptionFromCode
    795     jalr $zero, $t9                 # artThrowNullPointerExceptionFromCode(Thread*)
    796     move $a0, rSELF                 # pass Thread::Current
    797 END art_quick_throw_null_pointer_exception
    798 
    799 
    800     /*
    801      * Call installed by a signal handler to create and deliver a NullPointerException.
    802      */
    803     .extern artThrowNullPointerExceptionFromSignal
    804 ENTRY_NO_GP_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, FRAME_SIZE_SAVE_EVERYTHING
    805     SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
    806     # Retrieve the fault address from the padding where the signal handler stores it.
    807     lw   $a0, (ARG_SLOT_SIZE + __SIZEOF_POINTER__)($sp)
    808     la   $t9, artThrowNullPointerExceptionFromSignal
    809     jalr $zero, $t9                 # artThrowNullPointerExceptionFromSignal(uintptr_t, Thread*)
    810     move $a1, rSELF                 # pass Thread::Current
    811 END art_quick_throw_null_pointer_exception_from_signal
    812 
    813     /*
    814      * Called by managed code to create and deliver an ArithmeticException
    815      */
    816     .extern artThrowDivZeroFromCode
    817 ENTRY_NO_GP art_quick_throw_div_zero
    818     SETUP_SAVE_EVERYTHING_FRAME
    819     la   $t9, artThrowDivZeroFromCode
    820     jalr $zero, $t9                 # artThrowDivZeroFromCode(Thread*)
    821     move $a0, rSELF                 # pass Thread::Current
    822 END art_quick_throw_div_zero
    823 
    824     /*
    825      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException
    826      */
    827     .extern artThrowArrayBoundsFromCode
    828 ENTRY_NO_GP art_quick_throw_array_bounds
    829     // Note that setting up $gp does not rely on $t9 here, so branching here directly is OK,
    830     // even after clobbering any registers we don't need to preserve, such as $gp or $t0.
    831     SETUP_SAVE_EVERYTHING_FRAME
    832     la   $t9, artThrowArrayBoundsFromCode
    833     jalr $zero, $t9                 # artThrowArrayBoundsFromCode(index, limit, Thread*)
    834     move $a2, rSELF                 # pass Thread::Current
    835 END art_quick_throw_array_bounds
    836 
    837     /*
    838      * Called by managed code to create and deliver a StringIndexOutOfBoundsException
    839      * as if thrown from a call to String.charAt().
    840      */
    841     .extern artThrowStringBoundsFromCode
    842 ENTRY_NO_GP art_quick_throw_string_bounds
    843     SETUP_SAVE_EVERYTHING_FRAME
    844     la   $t9, artThrowStringBoundsFromCode
    845     jalr $zero, $t9                 # artThrowStringBoundsFromCode(index, limit, Thread*)
    846     move $a2, rSELF                 # pass Thread::Current
    847 END art_quick_throw_string_bounds
    848 
    849     /*
    850      * Called by managed code to create and deliver a StackOverflowError.
    851      */
    852     .extern artThrowStackOverflowFromCode
    853 ENTRY art_quick_throw_stack_overflow
    854     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
    855     la   $t9, artThrowStackOverflowFromCode
    856     jalr $zero, $t9                 # artThrowStackOverflowFromCode(Thread*)
    857     move $a0, rSELF                 # pass Thread::Current
    858 END art_quick_throw_stack_overflow
    859 
    860     /*
    861      * All generated callsites for interface invokes and invocation slow paths will load arguments
    862      * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
    863      * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
    864      * NOTE: "this" is first visable argument of the target, and so can be found in arg1/$a1.
    865      *
    866      * The helper will attempt to locate the target and return a 64-bit result in $v0/$v1 consisting
    867      * of the target Method* in $v0 and method->code_ in $v1.
    868      *
    869      * If unsuccessful, the helper will return null/null. There will be a pending exception in the
    870      * thread and we branch to another stub to deliver it.
    871      *
    872      * On success this wrapper will restore arguments and *jump* to the target, leaving the lr
    873      * pointing back to the original caller.
    874      */
    875 .macro INVOKE_TRAMPOLINE_BODY cxx_name, save_s4_thru_s8_only=0
    876     .extern \cxx_name
    877     SETUP_SAVE_REFS_AND_ARGS_FRAME \save_s4_thru_s8_only  # save callee saves in case
    878                                                           # allocation triggers GC
    879     move  $a2, rSELF                       # pass Thread::Current
    880     la    $t9, \cxx_name
    881     jalr  $t9                              # (method_idx, this, Thread*, $sp)
    882     addiu $a3, $sp, ARG_SLOT_SIZE          # pass $sp (remove arg slots)
    883     move  $a0, $v0                         # save target Method*
    884     RESTORE_SAVE_REFS_AND_ARGS_FRAME
    885     beqz  $v0, 1f
    886     move  $t9, $v1                         # save $v0->code_
    887     jalr  $zero, $t9
    888     nop
    889 1:
    890     DELIVER_PENDING_EXCEPTION
    891 .endm
    892 .macro INVOKE_TRAMPOLINE c_name, cxx_name
    893 ENTRY \c_name
    894     INVOKE_TRAMPOLINE_BODY \cxx_name
    895 END \c_name
    896 .endm
    897 
    898 INVOKE_TRAMPOLINE art_quick_invoke_interface_trampoline_with_access_check, artInvokeInterfaceTrampolineWithAccessCheck
    899 
    900 INVOKE_TRAMPOLINE art_quick_invoke_static_trampoline_with_access_check, artInvokeStaticTrampolineWithAccessCheck
    901 INVOKE_TRAMPOLINE art_quick_invoke_direct_trampoline_with_access_check, artInvokeDirectTrampolineWithAccessCheck
    902 INVOKE_TRAMPOLINE art_quick_invoke_super_trampoline_with_access_check, artInvokeSuperTrampolineWithAccessCheck
    903 INVOKE_TRAMPOLINE art_quick_invoke_virtual_trampoline_with_access_check, artInvokeVirtualTrampolineWithAccessCheck
    904 
    905 // Each of the following macros expands into four instructions or 16 bytes.
    906 // They are used to build indexable "tables" of code.
    907 
    908 .macro LOAD_WORD_TO_REG reg, next_arg, index_reg, label
    909     lw    $\reg, -4($\next_arg)   # next_arg points to argument after the current one (offset is 4)
    910     b     \label
    911     addiu $\index_reg, 16
    912     .balign 16
    913 .endm
    914 
    915 .macro LOAD_LONG_TO_REG reg1, reg2, next_arg, index_reg, next_index, label
    916     lw    $\reg1, -8($\next_arg)  # next_arg points to argument after the current one (offset is 8)
    917     lw    $\reg2, -4($\next_arg)
    918     b     \label
    919     li    $\index_reg, \next_index
    920     .balign 16
    921 .endm
    922 
    923 .macro LOAD_FLOAT_TO_REG reg, next_arg, index_reg, label
    924     lwc1  $\reg, -4($\next_arg)   # next_arg points to argument after the current one (offset is 4)
    925     b     \label
    926     addiu $\index_reg, 16
    927     .balign 16
    928 .endm
    929 
    930 #if defined(__mips_isa_rev) && __mips_isa_rev > 2
    931 // LDu expands into 3 instructions for 64-bit FPU, so index_reg cannot be updated here.
    932 .macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
    933     .set reorder                                # force use of the branch delay slot
    934     LDu  $\reg1, $\reg2, -8, $\next_arg, $\tmp  # next_arg points to argument after the current one
    935                                                 # (offset is 8)
    936     b     \label
    937     .set noreorder
    938     .balign 16
    939 .endm
    940 #else
    941 // LDu expands into 2 instructions for 32-bit FPU, so index_reg is updated here.
    942 .macro LOAD_DOUBLE_TO_REG reg1, reg2, next_arg, index_reg, tmp, label
    943     LDu  $\reg1, $\reg2, -8, $\next_arg, $\tmp  # next_arg points to argument after the current one
    944                                                 # (offset is 8)
    945     b     \label
    946     addiu $\index_reg, 16
    947     .balign 16
    948 .endm
    949 #endif
    950 
    951 .macro LOAD_END index_reg, next_index, label
    952     b     \label
    953     li    $\index_reg, \next_index
    954     .balign 16
    955 .endm
    956 
    957 #define SPILL_SIZE    32
    958 
    959     /*
    960      * Invocation stub for quick code.
    961      * On entry:
    962      *   a0 = method pointer
    963      *   a1 = argument array or null for no argument methods
    964      *   a2 = size of argument array in bytes
    965      *   a3 = (managed) thread pointer
    966      *   [sp + 16] = JValue* result
    967      *   [sp + 20] = shorty
    968      */
    969 ENTRY art_quick_invoke_stub
    970     sw    $a0, 0($sp)           # save out a0
    971     addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
    972     .cfi_adjust_cfa_offset SPILL_SIZE
    973     sw    $gp, 16($sp)
    974     sw    $ra, 12($sp)
    975     .cfi_rel_offset 31, 12
    976     sw    $fp, 8($sp)
    977     .cfi_rel_offset 30, 8
    978     sw    $s1, 4($sp)
    979     .cfi_rel_offset 17, 4
    980     sw    $s0, 0($sp)
    981     .cfi_rel_offset 16, 0
    982     move  $fp, $sp              # save sp in fp
    983     .cfi_def_cfa_register 30
    984     move  $s1, $a3              # move managed thread pointer into s1
    985     addiu $t0, $a2, 4           # create space for ArtMethod* in frame.
    986     subu  $t0, $sp, $t0         # reserve & align *stack* to 16 bytes:
    987     srl   $t0, $t0, 4           #   native calling convention only aligns to 8B,
    988     sll   $sp, $t0, 4           #   so we have to ensure ART 16B alignment ourselves.
    989     addiu $a0, $sp, 4           # pass stack pointer + ArtMethod* as dest for memcpy
    990     la    $t9, memcpy
    991     jalr  $t9                   # (dest, src, bytes)
    992     addiu $sp, $sp, -16         # make space for argument slots for memcpy
    993     addiu $sp, $sp, 16          # restore stack after memcpy
    994     lw    $gp, 16($fp)          # restore $gp
    995     lw    $a0, SPILL_SIZE($fp)  # restore ArtMethod*
    996     lw    $a1, 4($sp)           # a1 = this*
    997     addiu $t8, $sp, 8           # t8 = pointer to the current argument (skip ArtMethod* and this*)
    998     li    $t6, 0                # t6 = gpr_index = 0 (corresponds to A2; A0 and A1 are skipped)
    999     li    $t7, 0                # t7 = fp_index = 0
   1000     lw    $t9, 20 + SPILL_SIZE($fp)  # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
   1001                                 # as the $fp is SPILL_SIZE bytes below the $sp on entry)
   1002     addiu $t9, 1                # t9 = shorty + 1 (skip 1 for return type)
   1003 
   1004     // Load the base addresses of tabInt ... tabDouble.
   1005     // We will use the register indices (gpr_index, fp_index) to branch.
   1006     // Note that the indices are scaled by 16, so they can be added to the bases directly.
   1007 #if defined(__mips_isa_rev) && __mips_isa_rev >= 6
   1008     lapc  $t2, tabInt
   1009     lapc  $t3, tabLong
   1010     lapc  $t4, tabSingle
   1011     lapc  $t5, tabDouble
   1012 #else
   1013     bltzal $zero, tabBase       # nal
   1014     addiu $t2, $ra, %lo(tabInt - tabBase)
   1015 tabBase:
   1016     addiu $t3, $ra, %lo(tabLong - tabBase)
   1017     addiu $t4, $ra, %lo(tabSingle - tabBase)
   1018     addiu $t5, $ra, %lo(tabDouble - tabBase)
   1019 #endif
   1020 
   1021 loop:
   1022     lbu   $ra, 0($t9)           # ra = shorty[i]
   1023     beqz  $ra, loopEnd          # finish getting args when shorty[i] == '\0'
   1024     addiu $t9, 1
   1025 
   1026     addiu $ra, -'J'
   1027     beqz  $ra, isLong           # branch if result type char == 'J'
   1028     addiu $ra, 'J' - 'D'
   1029     beqz  $ra, isDouble         # branch if result type char == 'D'
   1030     addiu $ra, 'D' - 'F'
   1031     beqz  $ra, isSingle         # branch if result type char == 'F'
   1032 
   1033     addu  $ra, $t2, $t6
   1034     jalr  $zero, $ra
   1035     addiu $t8, 4                # next_arg = curr_arg + 4
   1036 
   1037 isLong:
   1038     addu  $ra, $t3, $t6
   1039     jalr  $zero, $ra
   1040     addiu $t8, 8                # next_arg = curr_arg + 8
   1041 
   1042 isSingle:
   1043     addu  $ra, $t4, $t7
   1044     jalr  $zero, $ra
   1045     addiu $t8, 4                # next_arg = curr_arg + 4
   1046 
   1047 isDouble:
   1048     addu  $ra, $t5, $t7
   1049 #if defined(__mips_isa_rev) && __mips_isa_rev > 2
   1050     addiu $t7, 16               # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
   1051 #endif
   1052     jalr  $zero, $ra
   1053     addiu $t8, 8                # next_arg = curr_arg + 8
   1054 
   1055 loopEnd:
   1056     lw    $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)  # get pointer to the code
   1057     jalr  $t9                   # call the method
   1058     sw    $zero, 0($sp)         # store null for ArtMethod* at bottom of frame
   1059     move  $sp, $fp              # restore the stack
   1060     lw    $s0, 0($sp)
   1061     .cfi_restore 16
   1062     lw    $s1, 4($sp)
   1063     .cfi_restore 17
   1064     lw    $fp, 8($sp)
   1065     .cfi_restore 30
   1066     lw    $ra, 12($sp)
   1067     .cfi_restore 31
   1068     addiu $sp, $sp, SPILL_SIZE
   1069     .cfi_adjust_cfa_offset -SPILL_SIZE
   1070     lw    $t0, 16($sp)          # get result pointer
   1071     lw    $t1, 20($sp)          # get shorty
   1072     lb    $t1, 0($t1)           # get result type char
   1073     li    $t2, 'D'              # put char 'D' into t2
   1074     beq   $t1, $t2, 5f          # branch if result type char == 'D'
   1075     li    $t3, 'F'              # put char 'F' into t3
   1076     beq   $t1, $t3, 5f          # branch if result type char == 'F'
   1077     sw    $v0, 0($t0)           # store the result
   1078     jalr  $zero, $ra
   1079     sw    $v1, 4($t0)           # store the other half of the result
   1080 5:
   1081     CHECK_ALIGNMENT $t0, $t1, 8
   1082     sdc1  $f0, 0($t0)           # store floating point result
   1083     jalr  $zero, $ra
   1084     nop
   1085 
   1086     // Note that gpr_index is kept within the range of tabInt and tabLong
   1087     // and fp_index is kept within the range of tabSingle and tabDouble.
   1088     .balign 16
   1089 tabInt:
   1090     LOAD_WORD_TO_REG a2, t8, t6, loop             # a2 = current argument, gpr_index += 16
   1091     LOAD_WORD_TO_REG a3, t8, t6, loop             # a3 = current argument, gpr_index += 16
   1092     LOAD_WORD_TO_REG t0, t8, t6, loop             # t0 = current argument, gpr_index += 16
   1093     LOAD_WORD_TO_REG t1, t8, t6, loop             # t1 = current argument, gpr_index += 16
   1094     LOAD_END t6, 4*16, loop                       # no more GPR args, gpr_index = 4*16
   1095 tabLong:
   1096     LOAD_LONG_TO_REG a2, a3, t8, t6, 2*16, loop   # a2_a3 = curr_arg, gpr_index = 2*16
   1097     LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop   # t0_t1 = curr_arg, gpr_index = 4*16
   1098     LOAD_LONG_TO_REG t0, t1, t8, t6, 4*16, loop   # t0_t1 = curr_arg, gpr_index = 4*16
   1099     LOAD_END t6, 4*16, loop                       # no more GPR args, gpr_index = 4*16
   1100     LOAD_END t6, 4*16, loop                       # no more GPR args, gpr_index = 4*16
   1101 tabSingle:
   1102     LOAD_FLOAT_TO_REG f8, t8, t7, loop            # f8 = curr_arg, fp_index += 16
   1103     LOAD_FLOAT_TO_REG f10, t8, t7, loop           # f10 = curr_arg, fp_index += 16
   1104     LOAD_FLOAT_TO_REG f12, t8, t7, loop           # f12 = curr_arg, fp_index += 16
   1105     LOAD_FLOAT_TO_REG f14, t8, t7, loop           # f14 = curr_arg, fp_index += 16
   1106     LOAD_FLOAT_TO_REG f16, t8, t7, loop           # f16 = curr_arg, fp_index += 16
   1107     LOAD_FLOAT_TO_REG f18, t8, t7, loop           # f18 = curr_arg, fp_index += 16
   1108     LOAD_END t7, 6*16, loop                       # no more FPR args, fp_index = 6*16
   1109 tabDouble:
   1110     LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loop   # f8_f9 = curr_arg; if FPU32, fp_index += 16
   1111     LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loop # f10_f11 = curr_arg; if FPU32, fp_index += 16
   1112     LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loop # f12_f13 = curr_arg; if FPU32, fp_index += 16
   1113     LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loop # f14_f15 = curr_arg; if FPU32, fp_index += 16
   1114     LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loop # f16_f17 = curr_arg; if FPU32, fp_index += 16
   1115     LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loop # f18_f19 = curr_arg; if FPU32, fp_index += 16
   1116     LOAD_END t7, 6*16, loop                       # no more FPR args, fp_index = 6*16
   1117 END art_quick_invoke_stub
   1118 
   1119     /*
   1120      * Invocation static stub for quick code.
   1121      * On entry:
   1122      *   a0 = method pointer
   1123      *   a1 = argument array or null for no argument methods
   1124      *   a2 = size of argument array in bytes
   1125      *   a3 = (managed) thread pointer
   1126      *   [sp + 16] = JValue* result
   1127      *   [sp + 20] = shorty
   1128      */
   1129 ENTRY art_quick_invoke_static_stub
   1130     sw    $a0, 0($sp)           # save out a0
   1131     addiu $sp, $sp, -SPILL_SIZE # spill s0, s1, fp, ra and gp
   1132     .cfi_adjust_cfa_offset SPILL_SIZE
   1133     sw    $gp, 16($sp)
   1134     sw    $ra, 12($sp)
   1135     .cfi_rel_offset 31, 12
   1136     sw    $fp, 8($sp)
   1137     .cfi_rel_offset 30, 8
   1138     sw    $s1, 4($sp)
   1139     .cfi_rel_offset 17, 4
   1140     sw    $s0, 0($sp)
   1141     .cfi_rel_offset 16, 0
   1142     move  $fp, $sp              # save sp in fp
   1143     .cfi_def_cfa_register 30
   1144     move  $s1, $a3              # move managed thread pointer into s1
   1145     addiu $t0, $a2, 4           # create space for ArtMethod* in frame.
   1146     subu  $t0, $sp, $t0         # reserve & align *stack* to 16 bytes:
   1147     srl   $t0, $t0, 4           #   native calling convention only aligns to 8B,
   1148     sll   $sp, $t0, 4           #   so we have to ensure ART 16B alignment ourselves.
   1149     addiu $a0, $sp, 4           # pass stack pointer + ArtMethod* as dest for memcpy
   1150     la    $t9, memcpy
   1151     jalr  $t9                   # (dest, src, bytes)
   1152     addiu $sp, $sp, -16         # make space for argument slots for memcpy
   1153     addiu $sp, $sp, 16          # restore stack after memcpy
   1154     lw    $gp, 16($fp)          # restore $gp
   1155     lw    $a0, SPILL_SIZE($fp)  # restore ArtMethod*
   1156     addiu $t8, $sp, 4           # t8 = pointer to the current argument (skip ArtMethod*)
   1157     li    $t6, 0                # t6 = gpr_index = 0 (corresponds to A1; A0 is skipped)
   1158     li    $t7, 0                # t7 = fp_index = 0
   1159     lw    $t9, 20 + SPILL_SIZE($fp)  # get shorty (20 is offset from the $sp on entry + SPILL_SIZE
   1160                                 # as the $fp is SPILL_SIZE bytes below the $sp on entry)
   1161     addiu $t9, 1                # t9 = shorty + 1 (skip 1 for return type)
   1162 
   1163     // Load the base addresses of tabIntS ... tabDoubleS.
   1164     // We will use the register indices (gpr_index, fp_index) to branch.
   1165     // Note that the indices are scaled by 16, so they can be added to the bases directly.
   1166 #if defined(__mips_isa_rev) && __mips_isa_rev >= 6
   1167     lapc  $t2, tabIntS
   1168     lapc  $t3, tabLongS
   1169     lapc  $t4, tabSingleS
   1170     lapc  $t5, tabDoubleS
   1171 #else
   1172     bltzal $zero, tabBaseS      # nal
   1173     addiu $t2, $ra, %lo(tabIntS - tabBaseS)
   1174 tabBaseS:
   1175     addiu $t3, $ra, %lo(tabLongS - tabBaseS)
   1176     addiu $t4, $ra, %lo(tabSingleS - tabBaseS)
   1177     addiu $t5, $ra, %lo(tabDoubleS - tabBaseS)
   1178 #endif
   1179 
   1180 loopS:
   1181     lbu   $ra, 0($t9)           # ra = shorty[i]
   1182     beqz  $ra, loopEndS         # finish getting args when shorty[i] == '\0'
   1183     addiu $t9, 1
   1184 
   1185     addiu $ra, -'J'
   1186     beqz  $ra, isLongS          # branch if result type char == 'J'
   1187     addiu $ra, 'J' - 'D'
   1188     beqz  $ra, isDoubleS        # branch if result type char == 'D'
   1189     addiu $ra, 'D' - 'F'
   1190     beqz  $ra, isSingleS        # branch if result type char == 'F'
   1191 
   1192     addu  $ra, $t2, $t6
   1193     jalr  $zero, $ra
   1194     addiu $t8, 4                # next_arg = curr_arg + 4
   1195 
   1196 isLongS:
   1197     addu  $ra, $t3, $t6
   1198     jalr  $zero, $ra
   1199     addiu $t8, 8                # next_arg = curr_arg + 8
   1200 
   1201 isSingleS:
   1202     addu  $ra, $t4, $t7
   1203     jalr  $zero, $ra
   1204     addiu $t8, 4                # next_arg = curr_arg + 4
   1205 
   1206 isDoubleS:
   1207     addu  $ra, $t5, $t7
   1208 #if defined(__mips_isa_rev) && __mips_isa_rev > 2
   1209     addiu $t7, 16               # fp_index += 16 didn't fit into LOAD_DOUBLE_TO_REG
   1210 #endif
   1211     jalr  $zero, $ra
   1212     addiu $t8, 8                # next_arg = curr_arg + 8
   1213 
   1214 loopEndS:
   1215     lw    $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)  # get pointer to the code
   1216     jalr  $t9                   # call the method
   1217     sw    $zero, 0($sp)         # store null for ArtMethod* at bottom of frame
   1218     move  $sp, $fp              # restore the stack
   1219     lw    $s0, 0($sp)
   1220     .cfi_restore 16
   1221     lw    $s1, 4($sp)
   1222     .cfi_restore 17
   1223     lw    $fp, 8($sp)
   1224     .cfi_restore 30
   1225     lw    $ra, 12($sp)
   1226     .cfi_restore 31
   1227     addiu $sp, $sp, SPILL_SIZE
   1228     .cfi_adjust_cfa_offset -SPILL_SIZE
   1229     lw    $t0, 16($sp)          # get result pointer
   1230     lw    $t1, 20($sp)          # get shorty
   1231     lb    $t1, 0($t1)           # get result type char
   1232     li    $t2, 'D'              # put char 'D' into t2
   1233     beq   $t1, $t2, 6f          # branch if result type char == 'D'
   1234     li    $t3, 'F'              # put char 'F' into t3
   1235     beq   $t1, $t3, 6f          # branch if result type char == 'F'
   1236     sw    $v0, 0($t0)           # store the result
   1237     jalr  $zero, $ra
   1238     sw    $v1, 4($t0)           # store the other half of the result
   1239 6:
   1240     CHECK_ALIGNMENT $t0, $t1, 8
   1241     sdc1  $f0, 0($t0)           # store floating point result
   1242     jalr  $zero, $ra
   1243     nop
   1244 
   1245     // Note that gpr_index is kept within the range of tabIntS and tabLongS
   1246     // and fp_index is kept within the range of tabSingleS and tabDoubleS.
   1247     .balign 16
   1248 tabIntS:
   1249     LOAD_WORD_TO_REG a1, t8, t6, loopS             # a1 = current argument, gpr_index += 16
   1250     LOAD_WORD_TO_REG a2, t8, t6, loopS             # a2 = current argument, gpr_index += 16
   1251     LOAD_WORD_TO_REG a3, t8, t6, loopS             # a3 = current argument, gpr_index += 16
   1252     LOAD_WORD_TO_REG t0, t8, t6, loopS             # t0 = current argument, gpr_index += 16
   1253     LOAD_WORD_TO_REG t1, t8, t6, loopS             # t1 = current argument, gpr_index += 16
   1254     LOAD_END t6, 5*16, loopS                       # no more GPR args, gpr_index = 5*16
   1255 tabLongS:
   1256     LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS   # a2_a3 = curr_arg, gpr_index = 3*16
   1257     LOAD_LONG_TO_REG a2, a3, t8, t6, 3*16, loopS   # a2_a3 = curr_arg, gpr_index = 3*16
   1258     LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS   # t0_t1 = curr_arg, gpr_index = 5*16
   1259     LOAD_LONG_TO_REG t0, t1, t8, t6, 5*16, loopS   # t0_t1 = curr_arg, gpr_index = 5*16
   1260     LOAD_END t6, 5*16, loopS                       # no more GPR args, gpr_index = 5*16
   1261     LOAD_END t6, 5*16, loopS                       # no more GPR args, gpr_index = 5*16
   1262 tabSingleS:
   1263     LOAD_FLOAT_TO_REG f8, t8, t7, loopS            # f8 = curr_arg, fp_index += 16
   1264     LOAD_FLOAT_TO_REG f10, t8, t7, loopS           # f10 = curr_arg, fp_index += 16
   1265     LOAD_FLOAT_TO_REG f12, t8, t7, loopS           # f12 = curr_arg, fp_index += 16
   1266     LOAD_FLOAT_TO_REG f14, t8, t7, loopS           # f14 = curr_arg, fp_index += 16
   1267     LOAD_FLOAT_TO_REG f16, t8, t7, loopS           # f16 = curr_arg, fp_index += 16
   1268     LOAD_FLOAT_TO_REG f18, t8, t7, loopS           # f18 = curr_arg, fp_index += 16
   1269     LOAD_END t7, 6*16, loopS                       # no more FPR args, fp_index = 6*16
   1270 tabDoubleS:
   1271     LOAD_DOUBLE_TO_REG f8, f9, t8, t7, ra, loopS   # f8_f9 = curr_arg; if FPU32, fp_index += 16
   1272     LOAD_DOUBLE_TO_REG f10, f11, t8, t7, ra, loopS # f10_f11 = curr_arg; if FPU32, fp_index += 16
   1273     LOAD_DOUBLE_TO_REG f12, f13, t8, t7, ra, loopS # f12_f13 = curr_arg; if FPU32, fp_index += 16
   1274     LOAD_DOUBLE_TO_REG f14, f15, t8, t7, ra, loopS # f14_f15 = curr_arg; if FPU32, fp_index += 16
   1275     LOAD_DOUBLE_TO_REG f16, f17, t8, t7, ra, loopS # f16_f17 = curr_arg; if FPU32, fp_index += 16
   1276     LOAD_DOUBLE_TO_REG f18, f19, t8, t7, ra, loopS # f18_f19 = curr_arg; if FPU32, fp_index += 16
   1277     LOAD_END t7, 6*16, loopS                       # no more FPR args, fp_index = 6*16
   1278 END art_quick_invoke_static_stub
   1279 
   1280 #undef SPILL_SIZE
   1281 
   1282     /*
   1283      * Entry from managed code that calls artHandleFillArrayDataFromCode and delivers exception on
   1284      * failure.
   1285      */
   1286     .extern artHandleFillArrayDataFromCode
   1287 ENTRY art_quick_handle_fill_data
   1288     lw     $a2, 0($sp)                # pass referrer's Method*
   1289     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case exception allocation triggers GC
   1290     la     $t9, artHandleFillArrayDataFromCode
   1291     jalr   $t9                        # (payload offset, Array*, method, Thread*)
   1292     move   $a3, rSELF                 # pass Thread::Current
   1293     RETURN_IF_ZERO
   1294 END art_quick_handle_fill_data
   1295 
   1296     /*
   1297      * Entry from managed code that calls artLockObjectFromCode, may block for GC.
   1298      */
   1299     .extern artLockObjectFromCode
   1300 ENTRY art_quick_lock_object
   1301     beqz    $a0, art_quick_throw_null_pointer_exception
   1302     li      $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
   1303     li      $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
   1304 .Lretry_lock:
   1305     lw      $t0, THREAD_ID_OFFSET(rSELF)  # TODO: Can the thread ID really change during the loop?
   1306     ll      $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1307     and     $t2, $t1, $t3                 # zero the gc bits
   1308     bnez    $t2, .Lnot_unlocked           # already thin locked
   1309     # Unlocked case - $t1: original lock word that's zero except for the read barrier bits.
   1310     or      $t2, $t1, $t0                 # $t2 holds thread id with count of 0 with preserved read barrier bits
   1311     sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1312     beqz    $t2, .Lretry_lock             # store failed, retry
   1313     nop
   1314     jalr    $zero, $ra
   1315     sync                                  # full (LoadLoad|LoadStore) memory barrier
   1316 .Lnot_unlocked:
   1317     # $t1: original lock word, $t0: thread_id with count of 0 and zero read barrier bits
   1318     srl     $t2, $t1, LOCK_WORD_STATE_SHIFT
   1319     bnez    $t2, .Lslow_lock              # if either of the top two bits are set, go slow path
   1320     xor     $t2, $t1, $t0                 # lock_word.ThreadId() ^ self->ThreadId()
   1321     andi    $t2, $t2, 0xFFFF              # zero top 16 bits
   1322     bnez    $t2, .Lslow_lock              # lock word and self thread id's match -> recursive lock
   1323                                           # otherwise contention, go to slow path
   1324     and     $t2, $t1, $t3                 # zero the gc bits
   1325     addu    $t2, $t2, $t8                 # increment count in lock word
   1326     srl     $t2, $t2, LOCK_WORD_STATE_SHIFT  # if the first gc state bit is set, we overflowed.
   1327     bnez    $t2, .Lslow_lock              # if we overflow the count go slow path
   1328     addu    $t2, $t1, $t8                 # increment count for real
   1329     sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1330     beqz    $t2, .Lretry_lock             # store failed, retry
   1331     nop
   1332     jalr    $zero, $ra
   1333     nop
   1334 .Lslow_lock:
   1335     SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
   1336     la      $t9, artLockObjectFromCode
   1337     jalr    $t9                           # (Object* obj, Thread*)
   1338     move    $a1, rSELF                    # pass Thread::Current
   1339     RETURN_IF_ZERO
   1340 END art_quick_lock_object
   1341 
   1342 ENTRY art_quick_lock_object_no_inline
   1343     beqz    $a0, art_quick_throw_null_pointer_exception
   1344     nop
   1345     SETUP_SAVE_REFS_ONLY_FRAME            # save callee saves in case we block
   1346     la      $t9, artLockObjectFromCode
   1347     jalr    $t9                           # (Object* obj, Thread*)
   1348     move    $a1, rSELF                    # pass Thread::Current
   1349     RETURN_IF_ZERO
   1350 END art_quick_lock_object_no_inline
   1351 
   1352     /*
   1353      * Entry from managed code that calls artUnlockObjectFromCode and delivers exception on failure.
   1354      */
   1355     .extern artUnlockObjectFromCode
   1356 ENTRY art_quick_unlock_object
   1357     beqz    $a0, art_quick_throw_null_pointer_exception
   1358     li      $t8, LOCK_WORD_THIN_LOCK_COUNT_ONE
   1359     li      $t3, LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED
   1360 .Lretry_unlock:
   1361 #ifndef USE_READ_BARRIER
   1362     lw      $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1363 #else
   1364     ll      $t1, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)  # Need to use atomic read-modify-write for read barrier
   1365 #endif
   1366     srl     $t2, $t1, LOCK_WORD_STATE_SHIFT
   1367     bnez    $t2, .Lslow_unlock         # if either of the top two bits are set, go slow path
   1368     lw      $t0, THREAD_ID_OFFSET(rSELF)
   1369     and     $t2, $t1, $t3              # zero the gc bits
   1370     xor     $t2, $t2, $t0              # lock_word.ThreadId() ^ self->ThreadId()
   1371     andi    $t2, $t2, 0xFFFF           # zero top 16 bits
   1372     bnez    $t2, .Lslow_unlock         # do lock word and self thread id's match?
   1373     and     $t2, $t1, $t3              # zero the gc bits
   1374     bgeu    $t2, $t8, .Lrecursive_thin_unlock
   1375     # transition to unlocked
   1376     nor     $t2, $zero, $t3            # $t2 = LOCK_WORD_GC_STATE_MASK_SHIFTED
   1377     and     $t2, $t1, $t2              # $t2: zero except for the preserved gc bits
   1378     sync                               # full (LoadStore|StoreStore) memory barrier
   1379 #ifndef USE_READ_BARRIER
   1380     jalr    $zero, $ra
   1381     sw      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1382 #else
   1383     sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1384     beqz    $t2, .Lretry_unlock        # store failed, retry
   1385     nop
   1386     jalr    $zero, $ra
   1387     nop
   1388 #endif
   1389 .Lrecursive_thin_unlock:
   1390     # t1: original lock word
   1391     subu    $t2, $t1, $t8              # decrement count
   1392 #ifndef USE_READ_BARRIER
   1393     jalr    $zero, $ra
   1394     sw      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1395 #else
   1396     sc      $t2, MIRROR_OBJECT_LOCK_WORD_OFFSET($a0)
   1397     beqz    $t2, .Lretry_unlock        # store failed, retry
   1398     nop
   1399     jalr    $zero, $ra
   1400     nop
   1401 #endif
   1402 .Lslow_unlock:
   1403     SETUP_SAVE_REFS_ONLY_FRAME         # save callee saves in case exception allocation triggers GC
   1404     la      $t9, artUnlockObjectFromCode
   1405     jalr    $t9                        # (Object* obj, Thread*)
   1406     move    $a1, rSELF                 # pass Thread::Current
   1407     RETURN_IF_ZERO
   1408 END art_quick_unlock_object
   1409 
   1410 ENTRY art_quick_unlock_object_no_inline
   1411     beqz    $a0, art_quick_throw_null_pointer_exception
   1412     nop
   1413     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case exception allocation triggers GC
   1414     la      $t9, artUnlockObjectFromCode
   1415     jalr    $t9                       # (Object* obj, Thread*)
   1416     move    $a1, rSELF                # pass Thread::Current
   1417     RETURN_IF_ZERO
   1418 END art_quick_unlock_object_no_inline
   1419 
   1420     /*
   1421      * Entry from managed code that calls artInstanceOfFromCode and delivers exception on failure.
   1422      */
   1423     .extern artInstanceOfFromCode
   1424     .extern artThrowClassCastExceptionForObject
   1425 ENTRY art_quick_check_instance_of
   1426     addiu  $sp, $sp, -32
   1427     .cfi_adjust_cfa_offset 32
   1428     sw     $gp, 16($sp)
   1429     sw     $ra, 12($sp)
   1430     .cfi_rel_offset 31, 12
   1431     sw     $t9, 8($sp)
   1432     sw     $a1, 4($sp)
   1433     sw     $a0, 0($sp)
   1434     la     $t9, artInstanceOfFromCode
   1435     jalr   $t9
   1436     addiu  $sp, $sp, -16             # reserve argument slots on the stack
   1437     addiu  $sp, $sp, 16
   1438     lw     $gp, 16($sp)
   1439     beqz   $v0, .Lthrow_class_cast_exception
   1440     lw     $ra, 12($sp)
   1441     jalr   $zero, $ra
   1442     addiu  $sp, $sp, 32
   1443     .cfi_adjust_cfa_offset -32
   1444 .Lthrow_class_cast_exception:
   1445     lw     $t9, 8($sp)
   1446     lw     $a1, 4($sp)
   1447     lw     $a0, 0($sp)
   1448     addiu  $sp, $sp, 32
   1449     .cfi_adjust_cfa_offset -32
   1450     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
   1451     la   $t9, artThrowClassCastExceptionForObject
   1452     jalr $zero, $t9                 # artThrowClassCastException (Object*, Class*, Thread*)
   1453     move $a2, rSELF                 # pass Thread::Current
   1454 END art_quick_check_instance_of
   1455 
   1456     /*
   1457      * Restore rReg's value from offset($sp) if rReg is not the same as rExclude.
   1458      * nReg is the register number for rReg.
   1459      */
   1460 .macro POP_REG_NE rReg, nReg, offset, rExclude
   1461     .ifnc \rReg, \rExclude
   1462         lw \rReg, \offset($sp)      # restore rReg
   1463         .cfi_restore \nReg
   1464     .endif
   1465 .endm
   1466 
   1467     /*
   1468      * Macro to insert read barrier, only used in art_quick_aput_obj.
   1469      * rObj and rDest are registers, offset is a defined literal such as MIRROR_OBJECT_CLASS_OFFSET.
   1470      * TODO: When read barrier has a fast path, add heap unpoisoning support for the fast path.
   1471      */
   1472 .macro READ_BARRIER rDest, rObj, offset
   1473 #ifdef USE_READ_BARRIER
   1474     # saved registers used in art_quick_aput_obj: a0-a2, t0-t1, t9, ra. 8 words for 16B alignment.
   1475     addiu  $sp, $sp, -32
   1476     .cfi_adjust_cfa_offset 32
   1477     sw     $ra, 28($sp)
   1478     .cfi_rel_offset 31, 28
   1479     sw     $t9, 24($sp)
   1480     .cfi_rel_offset 25, 24
   1481     sw     $t1, 20($sp)
   1482     .cfi_rel_offset 9, 20
   1483     sw     $t0, 16($sp)
   1484     .cfi_rel_offset 8, 16
   1485     sw     $a2, 8($sp)              # padding slot at offset 12 (padding can be any slot in the 32B)
   1486     .cfi_rel_offset 6, 8
   1487     sw     $a1, 4($sp)
   1488     .cfi_rel_offset 5, 4
   1489     sw     $a0, 0($sp)
   1490     .cfi_rel_offset 4, 0
   1491 
   1492     # move $a0, \rRef               # pass ref in a0 (no-op for now since parameter ref is unused)
   1493     .ifnc \rObj, $a1
   1494         move $a1, \rObj             # pass rObj
   1495     .endif
   1496     addiu  $a2, $zero, \offset      # pass offset
   1497     la     $t9, artReadBarrierSlow
   1498     jalr   $t9                      # artReadBarrierSlow(ref, rObj, offset)
   1499     addiu  $sp, $sp, -16            # Use branch delay slot to reserve argument slots on the stack
   1500                                     # before the call to artReadBarrierSlow.
   1501     addiu  $sp, $sp, 16             # restore stack after call to artReadBarrierSlow
   1502     # No need to unpoison return value in v0, artReadBarrierSlow() would do the unpoisoning.
   1503     move \rDest, $v0                # save return value in rDest
   1504                                     # (rDest cannot be v0 in art_quick_aput_obj)
   1505 
   1506     lw     $a0, 0($sp)              # restore registers except rDest
   1507                                     # (rDest can only be t0 or t1 in art_quick_aput_obj)
   1508     .cfi_restore 4
   1509     lw     $a1, 4($sp)
   1510     .cfi_restore 5
   1511     lw     $a2, 8($sp)
   1512     .cfi_restore 6
   1513     POP_REG_NE $t0, 8, 16, \rDest
   1514     POP_REG_NE $t1, 9, 20, \rDest
   1515     lw     $t9, 24($sp)
   1516     .cfi_restore 25
   1517     lw     $ra, 28($sp)             # restore $ra
   1518     .cfi_restore 31
   1519     addiu  $sp, $sp, 32
   1520     .cfi_adjust_cfa_offset -32
   1521 #else
   1522     lw     \rDest, \offset(\rObj)
   1523     UNPOISON_HEAP_REF \rDest
   1524 #endif  // USE_READ_BARRIER
   1525 .endm
   1526 
   1527 #ifdef USE_READ_BARRIER
   1528     .extern artReadBarrierSlow
   1529 #endif
   1530 ENTRY art_quick_aput_obj
   1531     beqz $a2, .Ldo_aput_null
   1532     nop
   1533     READ_BARRIER $t0, $a0, MIRROR_OBJECT_CLASS_OFFSET
   1534     READ_BARRIER $t1, $a2, MIRROR_OBJECT_CLASS_OFFSET
   1535     READ_BARRIER $t0, $t0, MIRROR_CLASS_COMPONENT_TYPE_OFFSET
   1536     bne $t1, $t0, .Lcheck_assignability  # value's type == array's component type - trivial assignability
   1537     nop
   1538 .Ldo_aput:
   1539     sll $a1, $a1, 2
   1540     add $t0, $a0, $a1
   1541     POISON_HEAP_REF $a2
   1542     sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
   1543     lw  $t0, THREAD_CARD_TABLE_OFFSET(rSELF)
   1544     srl $t1, $a0, CARD_TABLE_CARD_SHIFT
   1545     add $t1, $t1, $t0
   1546     sb  $t0, ($t1)
   1547     jalr $zero, $ra
   1548     nop
   1549 .Ldo_aput_null:
   1550     sll $a1, $a1, 2
   1551     add $t0, $a0, $a1
   1552     sw  $a2, MIRROR_OBJECT_ARRAY_DATA_OFFSET($t0)
   1553     jalr $zero, $ra
   1554     nop
   1555 .Lcheck_assignability:
   1556     addiu  $sp, $sp, -32
   1557     .cfi_adjust_cfa_offset 32
   1558     sw     $ra, 28($sp)
   1559     .cfi_rel_offset 31, 28
   1560     sw     $gp, 16($sp)
   1561     sw     $t9, 12($sp)
   1562     sw     $a2, 8($sp)
   1563     sw     $a1, 4($sp)
   1564     sw     $a0, 0($sp)
   1565     move   $a1, $t1
   1566     move   $a0, $t0
   1567     la     $t9, artIsAssignableFromCode
   1568     jalr   $t9               # (Class*, Class*)
   1569     addiu  $sp, $sp, -16     # reserve argument slots on the stack
   1570     addiu  $sp, $sp, 16
   1571     lw     $ra, 28($sp)
   1572     lw     $gp, 16($sp)
   1573     lw     $t9, 12($sp)
   1574     lw     $a2, 8($sp)
   1575     lw     $a1, 4($sp)
   1576     lw     $a0, 0($sp)
   1577     addiu  $sp, 32
   1578     .cfi_adjust_cfa_offset -32
   1579     bnez   $v0, .Ldo_aput
   1580     nop
   1581     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
   1582     move $a1, $a2
   1583     la   $t9, artThrowArrayStoreException
   1584     jalr $zero, $t9                 # artThrowArrayStoreException(Class*, Class*, Thread*)
   1585     move $a2, rSELF                 # pass Thread::Current
   1586 END art_quick_aput_obj
   1587 
   1588 // Macros taking opportunity of code similarities for downcalls.
   1589 .macro ONE_ARG_REF_DOWNCALL name, entrypoint, return
   1590     .extern \entrypoint
   1591 ENTRY \name
   1592     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1593     la      $t9, \entrypoint
   1594     jalr    $t9                       # (field_idx, Thread*)
   1595     move    $a1, rSELF                # pass Thread::Current
   1596     \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
   1597 END \name
   1598 .endm
   1599 
   1600 .macro TWO_ARG_REF_DOWNCALL name, entrypoint, return
   1601     .extern \entrypoint
   1602 ENTRY \name
   1603     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1604     la      $t9, \entrypoint
   1605     jalr    $t9                       # (field_idx, Object*, Thread*) or
   1606                                       # (field_idx, new_val, Thread*)
   1607     move    $a2, rSELF                # pass Thread::Current
   1608     \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
   1609 END \name
   1610 .endm
   1611 
   1612 .macro THREE_ARG_REF_DOWNCALL name, entrypoint, return
   1613     .extern \entrypoint
   1614 ENTRY \name
   1615     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1616     la      $t9, \entrypoint
   1617     jalr    $t9                       # (field_idx, Object*, new_val, Thread*)
   1618     move    $a3, rSELF                # pass Thread::Current
   1619     \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
   1620 END \name
   1621 .endm
   1622 
   1623 .macro FOUR_ARG_REF_DOWNCALL name, entrypoint, return
   1624     .extern \entrypoint
   1625 ENTRY \name
   1626     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1627     la      $t9, \entrypoint
   1628     jalr    $t9                       # (field_idx, Object*, 64-bit new_val, Thread*) or
   1629                                       # (field_idx, 64-bit new_val, Thread*)
   1630                                       # Note that a 64-bit new_val needs to be aligned with
   1631                                       # an even-numbered register, hence A1 may be skipped
   1632                                       # for new_val to reside in A2-A3.
   1633     sw      rSELF, 16($sp)            # pass Thread::Current
   1634     \return                           # RETURN_IF_NO_EXCEPTION or RETURN_IF_ZERO
   1635 END \name
   1636 .endm
   1637 
   1638     /*
   1639      * Called by managed code to resolve a static/instance field and load/store a value.
   1640      *
   1641      * Note: Functions `art{Get,Set}<Kind>{Static,Instance}FromCompiledCode` are
   1642      * defined with a macro in runtime/entrypoints/quick/quick_field_entrypoints.cc.
   1643      */
   1644 ONE_ARG_REF_DOWNCALL art_quick_get_byte_static, artGetByteStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1645 ONE_ARG_REF_DOWNCALL art_quick_get_boolean_static, artGetBooleanStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1646 ONE_ARG_REF_DOWNCALL art_quick_get_short_static, artGetShortStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1647 ONE_ARG_REF_DOWNCALL art_quick_get_char_static, artGetCharStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1648 ONE_ARG_REF_DOWNCALL art_quick_get32_static, artGet32StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1649 ONE_ARG_REF_DOWNCALL art_quick_get_obj_static, artGetObjStaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1650 ONE_ARG_REF_DOWNCALL art_quick_get64_static, artGet64StaticFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1651 TWO_ARG_REF_DOWNCALL art_quick_get_byte_instance, artGetByteInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1652 TWO_ARG_REF_DOWNCALL art_quick_get_boolean_instance, artGetBooleanInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1653 TWO_ARG_REF_DOWNCALL art_quick_get_short_instance, artGetShortInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1654 TWO_ARG_REF_DOWNCALL art_quick_get_char_instance, artGetCharInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1655 TWO_ARG_REF_DOWNCALL art_quick_get32_instance, artGet32InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1656 TWO_ARG_REF_DOWNCALL art_quick_get_obj_instance, artGetObjInstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1657 TWO_ARG_REF_DOWNCALL art_quick_get64_instance, artGet64InstanceFromCompiledCode, RETURN_IF_NO_EXCEPTION
   1658 TWO_ARG_REF_DOWNCALL art_quick_set8_static, artSet8StaticFromCompiledCode, RETURN_IF_ZERO
   1659 TWO_ARG_REF_DOWNCALL art_quick_set16_static, artSet16StaticFromCompiledCode, RETURN_IF_ZERO
   1660 TWO_ARG_REF_DOWNCALL art_quick_set32_static, artSet32StaticFromCompiledCode, RETURN_IF_ZERO
   1661 TWO_ARG_REF_DOWNCALL art_quick_set_obj_static, artSetObjStaticFromCompiledCode, RETURN_IF_ZERO
   1662 FOUR_ARG_REF_DOWNCALL art_quick_set64_static, artSet64StaticFromCompiledCode, RETURN_IF_ZERO
   1663 THREE_ARG_REF_DOWNCALL art_quick_set8_instance, artSet8InstanceFromCompiledCode, RETURN_IF_ZERO
   1664 THREE_ARG_REF_DOWNCALL art_quick_set16_instance, artSet16InstanceFromCompiledCode, RETURN_IF_ZERO
   1665 THREE_ARG_REF_DOWNCALL art_quick_set32_instance, artSet32InstanceFromCompiledCode, RETURN_IF_ZERO
   1666 THREE_ARG_REF_DOWNCALL art_quick_set_obj_instance, artSetObjInstanceFromCompiledCode, RETURN_IF_ZERO
   1667 FOUR_ARG_REF_DOWNCALL art_quick_set64_instance, artSet64InstanceFromCompiledCode, RETURN_IF_ZERO
   1668 
   1669 // Macro to facilitate adding new allocation entrypoints.
   1670 .macro ONE_ARG_DOWNCALL name, entrypoint, return
   1671     .extern \entrypoint
   1672 ENTRY \name
   1673     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1674     la      $t9, \entrypoint
   1675     jalr    $t9
   1676     move    $a1, rSELF                # pass Thread::Current
   1677     \return
   1678 END \name
   1679 .endm
   1680 
   1681 .macro TWO_ARG_DOWNCALL name, entrypoint, return
   1682     .extern \entrypoint
   1683 ENTRY \name
   1684     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1685     la      $t9, \entrypoint
   1686     jalr    $t9
   1687     move    $a2, rSELF                # pass Thread::Current
   1688     \return
   1689 END \name
   1690 .endm
   1691 
   1692 .macro THREE_ARG_DOWNCALL name, entrypoint, return
   1693     .extern \entrypoint
   1694 ENTRY \name
   1695     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1696     la      $t9, \entrypoint
   1697     jalr    $t9
   1698     move    $a3, rSELF                # pass Thread::Current
   1699     \return
   1700 END \name
   1701 .endm
   1702 
   1703 .macro FOUR_ARG_DOWNCALL name, entrypoint, return
   1704     .extern \entrypoint
   1705 ENTRY \name
   1706     SETUP_SAVE_REFS_ONLY_FRAME        # save callee saves in case of GC
   1707     la      $t9, \entrypoint
   1708     jalr    $t9
   1709     sw      rSELF, 16($sp)            # pass Thread::Current
   1710     \return
   1711 END \name
   1712 .endm
   1713 
   1714 // Generate the allocation entrypoints for each allocator.
   1715 GENERATE_ALLOC_ENTRYPOINTS_FOR_NON_TLAB_ALLOCATORS
   1716 // Comment out allocators that have mips specific asm.
   1717 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB)
   1718 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB)
   1719 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_region_tlab, RegionTLAB)
   1720 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_region_tlab, RegionTLAB)
   1721 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_region_tlab, RegionTLAB)
   1722 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_region_tlab, RegionTLAB)
   1723 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_region_tlab, RegionTLAB)
   1724 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_region_tlab, RegionTLAB)
   1725 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_region_tlab, RegionTLAB)
   1726 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_region_tlab, RegionTLAB)
   1727 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_region_tlab, RegionTLAB)
   1728 
   1729 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB)
   1730 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB)
   1731 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_WITH_ACCESS_CHECK(_tlab, TLAB)
   1732 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED(_tlab, TLAB)
   1733 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED8(_tlab, TLAB)
   1734 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED16(_tlab, TLAB)
   1735 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED32(_tlab, TLAB)
   1736 // GENERATE_ALLOC_ENTRYPOINTS_ALLOC_ARRAY_RESOLVED64(_tlab, TLAB)
   1737 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_BYTES(_tlab, TLAB)
   1738 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_CHARS(_tlab, TLAB)
   1739 GENERATE_ALLOC_ENTRYPOINTS_ALLOC_STRING_FROM_STRING(_tlab, TLAB)
   1740 
   1741 // A hand-written override for:
   1742 //   GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc)
   1743 //   GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_rosalloc, RosAlloc)
   1744 .macro ART_QUICK_ALLOC_OBJECT_ROSALLOC c_name, cxx_name, isInitialized
   1745 ENTRY_NO_GP \c_name
   1746     # Fast path rosalloc allocation
   1747     # a0: type
   1748     # s1: Thread::Current
   1749     # -----------------------------
   1750     # t1: object size
   1751     # t2: rosalloc run
   1752     # t3: thread stack top offset
   1753     # t4: thread stack bottom offset
   1754     # v0: free list head
   1755     #
   1756     # t5, t6 : temps
   1757     lw    $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)        # Check if thread local allocation
   1758     lw    $t4, THREAD_LOCAL_ALLOC_STACK_END_OFFSET($s1)        # stack has any room left.
   1759     bgeu  $t3, $t4, .Lslow_path_\c_name
   1760 
   1761     lw    $t1, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0)  # Load object size (t1).
   1762     li    $t5, ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE          # Check if size is for a thread local
   1763                                                                # allocation. Also does the
   1764                                                                # initialized and finalizable checks.
   1765     # When isInitialized == 0, then the class is potentially not yet initialized.
   1766     # If the class is not yet initialized, the object size will be very large to force the branch
   1767     # below to be taken.
   1768     #
   1769     # See InitializeClassVisitors in class-inl.h for more details.
   1770     bgtu  $t1, $t5, .Lslow_path_\c_name
   1771 
   1772     # Compute the rosalloc bracket index from the size. Since the size is already aligned we can
   1773     # combine the two shifts together.
   1774     srl   $t1, $t1, (ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT - POINTER_SIZE_SHIFT)
   1775 
   1776     addu  $t2, $t1, $s1
   1777     lw    $t2, (THREAD_ROSALLOC_RUNS_OFFSET - __SIZEOF_POINTER__)($t2)  # Load rosalloc run (t2).
   1778 
   1779     # Load the free list head (v0).
   1780     # NOTE: this will be the return val.
   1781     lw    $v0, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
   1782     beqz  $v0, .Lslow_path_\c_name
   1783     nop
   1784 
   1785     # Load the next pointer of the head and update the list head with the next pointer.
   1786     lw    $t5, ROSALLOC_SLOT_NEXT_OFFSET($v0)
   1787     sw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)($t2)
   1788 
   1789     # Store the class pointer in the header. This also overwrites the first pointer. The offsets are
   1790     # asserted to match.
   1791 
   1792 #if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
   1793 #error "Class pointer needs to overwrite next pointer."
   1794 #endif
   1795 
   1796     POISON_HEAP_REF $a0
   1797     sw    $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)
   1798 
   1799     # Push the new object onto the thread local allocation stack and increment the thread local
   1800     # allocation stack top.
   1801     sw    $v0, 0($t3)
   1802     addiu $t3, $t3, COMPRESSED_REFERENCE_SIZE
   1803     sw    $t3, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET($s1)
   1804 
   1805     # Decrement the size of the free list.
   1806     lw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
   1807     addiu $t5, $t5, -1
   1808     sw    $t5, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)($t2)
   1809 
   1810 .if \isInitialized == 0
   1811     # This barrier is only necessary when the allocation also requires a class initialization check.
   1812     #
   1813     # If the class is already observably initialized, then new-instance allocations are protected
   1814     # from publishing by the compiler which inserts its own StoreStore barrier.
   1815     sync                                                          # Fence.
   1816 .endif
   1817     jalr  $zero, $ra
   1818     nop
   1819 
   1820   .Lslow_path_\c_name:
   1821     addiu $t9, $t9, (.Lslow_path_\c_name - \c_name) + 4
   1822     .cpload $t9
   1823     SETUP_SAVE_REFS_ONLY_FRAME
   1824     la    $t9, \cxx_name
   1825     jalr  $t9
   1826     move  $a1, $s1                                                # Pass self as argument.
   1827     RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
   1828 END \c_name
   1829 .endm
   1830 
   1831 ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_resolved_rosalloc, artAllocObjectFromCodeResolvedRosAlloc, /* isInitialized */ 0
   1832 ART_QUICK_ALLOC_OBJECT_ROSALLOC art_quick_alloc_object_initialized_rosalloc, artAllocObjectFromCodeInitializedRosAlloc, /* isInitialized */ 1
   1833 
   1834 // The common fast path code for art_quick_alloc_object_resolved/initialized_tlab
   1835 // and art_quick_alloc_object_resolved/initialized_region_tlab.
   1836 //
   1837 // a0: type, s1(rSELF): Thread::Current.
   1838 // Need to preserve a0 to the slow path.
   1839 //
   1840 // If isInitialized=1 then the compiler assumes the object's class has already been initialized.
   1841 // If isInitialized=0 the compiler can only assume it's been at least resolved.
   1842 .macro ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH slowPathLabel isInitialized
   1843     lw    $v0, THREAD_LOCAL_POS_OFFSET(rSELF)          # Load thread_local_pos.
   1844     lw    $a2, THREAD_LOCAL_END_OFFSET(rSELF)          # Load thread_local_end.
   1845     subu  $a3, $a2, $v0                                # Compute the remaining buffer size.
   1846     lw    $t0, MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET($a0)  # Load the object size.
   1847 
   1848     # When isInitialized == 0, then the class is potentially not yet initialized.
   1849     # If the class is not yet initialized, the object size will be very large to force the branch
   1850     # below to be taken.
   1851     #
   1852     # See InitializeClassVisitors in class-inl.h for more details.
   1853     bgtu  $t0, $a3, \slowPathLabel                     # Check if it fits.
   1854     addu  $t1, $v0, $t0                                # Add object size to tlab pos (in branch
   1855                                                        # delay slot).
   1856     # "Point of no slow path". Won't go to the slow path from here on.
   1857     sw    $t1, THREAD_LOCAL_POS_OFFSET(rSELF)          # Store new thread_local_pos.
   1858     lw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)      # Increment thread_local_objects.
   1859     addiu $a2, $a2, 1
   1860     sw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
   1861     POISON_HEAP_REF $a0
   1862     sw    $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)         # Store the class pointer.
   1863 
   1864 .if \isInitialized == 0
   1865     # This barrier is only necessary when the allocation also requires a class initialization check.
   1866     #
   1867     # If the class is already observably initialized, then new-instance allocations are protected
   1868     # from publishing by the compiler which inserts its own StoreStore barrier.
   1869     sync                                               # Fence.
   1870 .endif
   1871     jalr  $zero, $ra
   1872     nop
   1873 .endm
   1874 
   1875 // The common code for art_quick_alloc_object_resolved/initialized_tlab
   1876 // and art_quick_alloc_object_resolved/initialized_region_tlab.
   1877 .macro GENERATE_ALLOC_OBJECT_TLAB name, entrypoint, isInitialized
   1878 ENTRY_NO_GP \name
   1879     # Fast path tlab allocation.
   1880     # a0: type, s1(rSELF): Thread::Current.
   1881     ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lslow_path_\name, \isInitialized
   1882 .Lslow_path_\name:
   1883     addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
   1884     .cpload $t9
   1885     SETUP_SAVE_REFS_ONLY_FRAME                         # Save callee saves in case of GC.
   1886     la    $t9, \entrypoint
   1887     jalr  $t9                                          # (mirror::Class*, Thread*)
   1888     move  $a1, rSELF                                   # Pass Thread::Current.
   1889     RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
   1890 END \name
   1891 .endm
   1892 
   1893 GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_region_tlab, artAllocObjectFromCodeResolvedRegionTLAB, /* isInitialized */ 0
   1894 GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_region_tlab, artAllocObjectFromCodeInitializedRegionTLAB, /* isInitialized */ 1
   1895 GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_resolved_tlab, artAllocObjectFromCodeResolvedTLAB, /* isInitialized */ 0
   1896 GENERATE_ALLOC_OBJECT_TLAB art_quick_alloc_object_initialized_tlab, artAllocObjectFromCodeInitializedTLAB, /* isInitialized */ 1
   1897 
   1898 // The common fast path code for art_quick_alloc_array_resolved/initialized_tlab
   1899 // and art_quick_alloc_array_resolved/initialized_region_tlab.
   1900 //
   1901 // a0: type, a1: component_count, a2: total_size, s1(rSELF): Thread::Current.
   1902 // Need to preserve a0 and a1 to the slow path.
   1903 .macro ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE slowPathLabel
   1904     li    $a3, OBJECT_ALIGNMENT_MASK_TOGGLED           # Apply alignemnt mask
   1905     and   $a2, $a2, $a3                                # (addr + 7) & ~7.
   1906 
   1907     lw    $v0, THREAD_LOCAL_POS_OFFSET(rSELF)          # Load thread_local_pos.
   1908     lw    $t1, THREAD_LOCAL_END_OFFSET(rSELF)          # Load thread_local_end.
   1909     subu  $t2, $t1, $v0                                # Compute the remaining buffer size.
   1910     bgtu  $a2, $t2, \slowPathLabel                     # Check if it fits.
   1911     addu  $a2, $v0, $a2                                # Add object size to tlab pos (in branch
   1912                                                        # delay slot).
   1913 
   1914     # "Point of no slow path". Won't go to the slow path from here on.
   1915     sw    $a2, THREAD_LOCAL_POS_OFFSET(rSELF)          # Store new thread_local_pos.
   1916     lw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)      # Increment thread_local_objects.
   1917     addiu $a2, $a2, 1
   1918     sw    $a2, THREAD_LOCAL_OBJECTS_OFFSET(rSELF)
   1919     POISON_HEAP_REF $a0
   1920     sw    $a0, MIRROR_OBJECT_CLASS_OFFSET($v0)         # Store the class pointer.
   1921     jalr  $zero, $ra
   1922     sw    $a1, MIRROR_ARRAY_LENGTH_OFFSET($v0)         # Store the array length.
   1923 .endm
   1924 
   1925 .macro GENERATE_ALLOC_ARRAY_TLAB name, entrypoint, size_setup
   1926 ENTRY_NO_GP \name
   1927     # Fast path array allocation for region tlab allocation.
   1928     # a0: mirror::Class* type
   1929     # a1: int32_t component_count
   1930     # s1(rSELF): Thread::Current
   1931     \size_setup .Lslow_path_\name
   1932     ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE .Lslow_path_\name
   1933 .Lslow_path_\name:
   1934     # a0: mirror::Class* type
   1935     # a1: int32_t component_count
   1936     # a2: Thread* self
   1937     addiu $t9, $t9, (.Lslow_path_\name - \name) + 4
   1938     .cpload $t9
   1939     SETUP_SAVE_REFS_ONLY_FRAME                         # Save callee saves in case of GC.
   1940     la    $t9, \entrypoint
   1941     jalr  $t9
   1942     move  $a2, rSELF                                   # Pass Thread::Current.
   1943     RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER
   1944 END \name
   1945 .endm
   1946 
   1947 .macro COMPUTE_ARRAY_SIZE_UNKNOWN slow_path
   1948     break                                              # We should never enter here.
   1949                                                        # Code below is for reference.
   1950                                                        # Possibly a large object, go slow.
   1951                                                        # Also does negative array size check.
   1952     li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_WIDE_ARRAY_DATA_OFFSET) / 8)
   1953     bgtu  $a1, $a2, \slow_path
   1954                                                        # Array classes are never finalizable
   1955                                                        # or uninitialized, no need to check.
   1956     lw    $a3, MIRROR_CLASS_COMPONENT_TYPE_OFFSET($a0) # Load component type.
   1957     UNPOISON_HEAP_REF $a3
   1958     lw    $a3, MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET($a3)
   1959     srl   $a3, $a3, PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT    # Component size shift is in high 16 bits.
   1960     sllv  $a2, $a1, $a3                                # Calculate data size.
   1961                                                        # Add array data offset and alignment.
   1962     addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
   1963 #if MIRROR_WIDE_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
   1964 #error Long array data offset must be 4 greater than int array data offset.
   1965 #endif
   1966 
   1967     addiu $a3, $a3, 1                                  # Add 4 to the length only if the component
   1968     andi  $a3, $a3, 4                                  # size shift is 3 (for 64 bit alignment).
   1969     addu  $a2, $a2, $a3
   1970 .endm
   1971 
   1972 .macro COMPUTE_ARRAY_SIZE_8 slow_path
   1973     # Possibly a large object, go slow.
   1974     # Also does negative array size check.
   1975     li    $a2, (MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET)
   1976     bgtu  $a1, $a2, \slow_path
   1977     # Add array data offset and alignment (in branch delay slot).
   1978     addiu $a2, $a1, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
   1979 .endm
   1980 
   1981 .macro COMPUTE_ARRAY_SIZE_16 slow_path
   1982     # Possibly a large object, go slow.
   1983     # Also does negative array size check.
   1984     li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 2)
   1985     bgtu  $a1, $a2, \slow_path
   1986     sll   $a2, $a1, 1
   1987     # Add array data offset and alignment.
   1988     addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
   1989 .endm
   1990 
   1991 .macro COMPUTE_ARRAY_SIZE_32 slow_path
   1992     # Possibly a large object, go slow.
   1993     # Also does negative array size check.
   1994     li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_INT_ARRAY_DATA_OFFSET) / 4)
   1995     bgtu  $a1, $a2, \slow_path
   1996     sll   $a2, $a1, 2
   1997     # Add array data offset and alignment.
   1998     addiu $a2, $a2, (MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
   1999 .endm
   2000 
   2001 .macro COMPUTE_ARRAY_SIZE_64 slow_path
   2002     # Possibly a large object, go slow.
   2003     # Also does negative array size check.
   2004     li    $a2, ((MIN_LARGE_OBJECT_THRESHOLD - MIRROR_LONG_ARRAY_DATA_OFFSET) / 8)
   2005     bgtu  $a1, $a2, \slow_path
   2006     sll   $a2, $a1, 3
   2007     # Add array data offset and alignment.
   2008     addiu $a2, $a2, (MIRROR_WIDE_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK)
   2009 .endm
   2010 
   2011 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
   2012 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_8
   2013 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_16
   2014 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_32
   2015 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_region_tlab, artAllocArrayFromCodeResolvedRegionTLAB, COMPUTE_ARRAY_SIZE_64
   2016 
   2017 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_UNKNOWN
   2018 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved8_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_8
   2019 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved16_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_16
   2020 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved32_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_32
   2021 GENERATE_ALLOC_ARRAY_TLAB art_quick_alloc_array_resolved64_tlab, artAllocArrayFromCodeResolvedTLAB, COMPUTE_ARRAY_SIZE_64
   2022 
   2023 // Macro for string and type resolution and initialization.
   2024 // $a0 is both input and output.
   2025 .macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL name, entrypoint, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET
   2026     .extern \entrypoint
   2027 ENTRY_NO_GP \name
   2028     SETUP_SAVE_EVERYTHING_FRAME \runtime_method_offset  # Save everything in case of GC.
   2029     move    $s2, $gp                  # Preserve $gp across the call for exception delivery.
   2030     la      $t9, \entrypoint
   2031     jalr    $t9                       # (uint32_t index, Thread*)
   2032     move    $a1, rSELF                # Pass Thread::Current (in delay slot).
   2033     beqz    $v0, 1f                   # Success?
   2034     move    $a0, $v0                  # Move result to $a0 (in delay slot).
   2035     RESTORE_SAVE_EVERYTHING_FRAME 0   # Restore everything except $a0.
   2036     jalr    $zero, $ra                # Return on success.
   2037     nop
   2038 1:
   2039     move    $gp, $s2
   2040     DELIVER_PENDING_EXCEPTION_FRAME_READY
   2041 END \name
   2042 .endm
   2043 
   2044 .macro ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT name, entrypoint
   2045     ONE_ARG_SAVE_EVERYTHING_DOWNCALL \name, \entrypoint, RUNTIME_SAVE_EVERYTHING_FOR_CLINIT_METHOD_OFFSET
   2046 .endm
   2047 
   2048     /*
   2049      * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
   2050      * exception on error. On success the String is returned. A0 holds the string index. The fast
   2051      * path check for hit in strings cache has already been performed.
   2052      */
   2053 ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_resolve_string, artResolveStringFromCode
   2054 
   2055     /*
   2056      * Entry from managed code when uninitialized static storage, this stub will run the class
   2057      * initializer and deliver the exception on error. On success the static storage base is
   2058      * returned.
   2059      */
   2060 ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_static_storage, artInitializeStaticStorageFromCode
   2061 
   2062     /*
   2063      * Entry from managed code when dex cache misses for a type_idx.
   2064      */
   2065 ONE_ARG_SAVE_EVERYTHING_DOWNCALL_FOR_CLINIT art_quick_initialize_type, artInitializeTypeFromCode
   2066 
   2067     /*
   2068      * Entry from managed code when type_idx needs to be checked for access and dex cache may also
   2069      * miss.
   2070      */
   2071 ONE_ARG_SAVE_EVERYTHING_DOWNCALL art_quick_initialize_type_and_verify_access, artInitializeTypeAndVerifyAccessFromCode
   2072 
   2073     /*
   2074      * Called by managed code when the value in rSUSPEND has been decremented to 0.
   2075      */
   2076     .extern artTestSuspendFromCode
   2077 ENTRY_NO_GP art_quick_test_suspend
   2078     SETUP_SAVE_EVERYTHING_FRAME RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET
   2079                                                      # save everything for stack crawl
   2080     la     $t9, artTestSuspendFromCode
   2081     jalr   $t9                                       # (Thread*)
   2082     move   $a0, rSELF
   2083     RESTORE_SAVE_EVERYTHING_FRAME
   2084     jalr   $zero, $ra
   2085     nop
   2086 END art_quick_test_suspend
   2087 
   2088     /*
   2089      * Called by managed code that is attempting to call a method on a proxy class. On entry
   2090      * a0 holds the proxy method; a1, a2 and a3 may contain arguments.
   2091      */
   2092     .extern artQuickProxyInvokeHandler
   2093 ENTRY art_quick_proxy_invoke_handler
   2094     SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
   2095     move    $a2, rSELF                  # pass Thread::Current
   2096     la      $t9, artQuickProxyInvokeHandler
   2097     jalr    $t9                         # (Method* proxy method, receiver, Thread*, SP)
   2098     addiu   $a3, $sp, ARG_SLOT_SIZE     # pass $sp (remove arg slots)
   2099     lw      $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
   2100     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   2101     bnez    $t7, 1f
   2102     # don't care if $v0 and/or $v1 are modified, when exception branch taken
   2103     MTD     $v0, $v1, $f0, $f1          # move float value to return value
   2104     jalr    $zero, $ra
   2105     nop
   2106 1:
   2107     DELIVER_PENDING_EXCEPTION
   2108 END art_quick_proxy_invoke_handler
   2109 
   2110     /*
   2111      * Called to resolve an imt conflict.
   2112      * a0 is the conflict ArtMethod.
   2113      * t7 is a hidden argument that holds the target interface method's dex method index.
   2114      *
   2115      * Note that this stub writes to v0-v1, a0, t2-t9, f0-f7.
   2116      */
   2117     .extern artLookupResolvedMethod
   2118     .extern __atomic_load_8         # For int64_t std::atomic::load(std::memory_order).
   2119 ENTRY art_quick_imt_conflict_trampoline
   2120     SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY /* save_s4_thru_s8 */ 0
   2121 
   2122     lw      $t8, FRAME_SIZE_SAVE_REFS_AND_ARGS($sp)  # $t8 = referrer.
   2123     // If the method is obsolete, just go through the dex cache miss slow path.
   2124     // The obsolete flag is set with suspended threads, so we do not need an acquire operation here.
   2125     lw      $t9, ART_METHOD_ACCESS_FLAGS_OFFSET($t8)  # $t9 = access flags.
   2126     sll     $t9, $t9, 31 - ACC_OBSOLETE_METHOD_SHIFT  # Move obsolete method bit to sign bit.
   2127     bltz    $t9, .Limt_conflict_trampoline_dex_cache_miss
   2128     lw      $t8, ART_METHOD_DECLARING_CLASS_OFFSET($t8)  # $t8 = declaring class (no read barrier).
   2129     lw      $t8, MIRROR_CLASS_DEX_CACHE_OFFSET($t8)  # $t8 = dex cache (without read barrier).
   2130     UNPOISON_HEAP_REF $t8
   2131     la      $t9, __atomic_load_8
   2132     addiu   $sp, $sp, -ARG_SLOT_SIZE                # Reserve argument slots on the stack.
   2133     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
   2134     lw      $t8, MIRROR_DEX_CACHE_RESOLVED_METHODS_OFFSET($t8)  # $t8 = dex cache methods array.
   2135 
   2136     move    $s2, $t7                                # $s2 = method index (callee-saved).
   2137     lw      $s3, ART_METHOD_JNI_OFFSET_32($a0)      # $s3 = ImtConflictTable (callee-saved).
   2138 
   2139     sll     $t7, $t7, 32 - METHOD_DEX_CACHE_HASH_BITS  # $t7 = slot index in top bits, zeroes below.
   2140     srl     $t7, $t7, 32 - METHOD_DEX_CACHE_HASH_BITS - (POINTER_SIZE_SHIFT + 1)
   2141                                                     # $t7 = slot offset.
   2142 
   2143     li      $a1, STD_MEMORY_ORDER_RELAXED           # $a1 = std::memory_order_relaxed.
   2144     jalr    $t9                                     # [$v0, $v1] = __atomic_load_8($a0, $a1).
   2145     addu    $a0, $t8, $t7                           # $a0 = DexCache method slot address.
   2146 
   2147     bne     $v1, $s2, .Limt_conflict_trampoline_dex_cache_miss  # Branch if method index miss.
   2148     addiu   $sp, $sp, ARG_SLOT_SIZE                 # Remove argument slots from the stack.
   2149     .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
   2150 
   2151 .Limt_table_iterate:
   2152     lw      $t8, 0($s3)                             # Load next entry in ImtConflictTable.
   2153     # Branch if found.
   2154     beq     $t8, $v0, .Limt_table_found
   2155     nop
   2156     # If the entry is null, the interface method is not in the ImtConflictTable.
   2157     beqz    $t8, .Lconflict_trampoline
   2158     nop
   2159     # Iterate over the entries of the ImtConflictTable.
   2160     b       .Limt_table_iterate
   2161     addiu   $s3, $s3, 2 * __SIZEOF_POINTER__        # Iterate to the next entry.
   2162 
   2163 .Limt_table_found:
   2164     # We successfully hit an entry in the table. Load the target method and jump to it.
   2165     .cfi_remember_state
   2166     lw      $a0, __SIZEOF_POINTER__($s3)
   2167     lw      $t9, ART_METHOD_QUICK_CODE_OFFSET_32($a0)
   2168     RESTORE_SAVE_REFS_AND_ARGS_FRAME /* restore_s4_thru_s8 */ 0, /* remove_arg_slots */ 0
   2169     jalr    $zero, $t9
   2170     nop
   2171     .cfi_restore_state
   2172 
   2173 .Lconflict_trampoline:
   2174     # Call the runtime stub to populate the ImtConflictTable and jump to the resolved method.
   2175     .cfi_remember_state
   2176     RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP             # Restore clobbered $gp.
   2177     RESTORE_SAVE_REFS_AND_ARGS_FRAME_A1             # Restore this.
   2178     move    $a0, $v0                                # Load interface method.
   2179     INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline, /* save_s4_thru_s8_only */ 1
   2180     .cfi_restore_state
   2181 
   2182 .Limt_conflict_trampoline_dex_cache_miss:
   2183     # We're not creating a proper runtime method frame here,
   2184     # artLookupResolvedMethod() is not allowed to walk the stack.
   2185     RESTORE_SAVE_REFS_AND_ARGS_FRAME_GP             # Restore clobbered $gp.
   2186     lw      $a1, FRAME_SIZE_SAVE_REFS_AND_ARGS($sp)  # $a1 = referrer.
   2187     la      $t9, artLookupResolvedMethod
   2188     addiu   $sp, $sp, -ARG_SLOT_SIZE                # Reserve argument slots on the stack.
   2189     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
   2190     jalr    $t9                                     # (uint32_t method_index, ArtMethod* referrer).
   2191     move    $a0, $s2                                # $a0 = method index.
   2192 
   2193     # If the method wasn't resolved, skip the lookup and go to artInvokeInterfaceTrampoline().
   2194     beqz    $v0, .Lconflict_trampoline
   2195     addiu   $sp, $sp, ARG_SLOT_SIZE                 # Remove argument slots from the stack.
   2196     .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
   2197 
   2198     b       .Limt_table_iterate
   2199     nop
   2200 END art_quick_imt_conflict_trampoline
   2201 
   2202     .extern artQuickResolutionTrampoline
   2203 ENTRY art_quick_resolution_trampoline
   2204     SETUP_SAVE_REFS_AND_ARGS_FRAME
   2205     move    $a2, rSELF                    # pass Thread::Current
   2206     la      $t9, artQuickResolutionTrampoline
   2207     jalr    $t9                           # (Method* called, receiver, Thread*, SP)
   2208     addiu   $a3, $sp, ARG_SLOT_SIZE       # pass $sp (remove arg slots)
   2209     beqz    $v0, 1f
   2210     lw      $a0, ARG_SLOT_SIZE($sp)       # load resolved method to $a0
   2211     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   2212     move    $t9, $v0               # code pointer must be in $t9 to generate the global pointer
   2213     jalr    $zero, $t9             # tail call to method
   2214     nop
   2215 1:
   2216     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   2217     DELIVER_PENDING_EXCEPTION
   2218 END art_quick_resolution_trampoline
   2219 
   2220     .extern artQuickGenericJniTrampoline
   2221     .extern artQuickGenericJniEndTrampoline
   2222 ENTRY art_quick_generic_jni_trampoline
   2223     SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_A0
   2224     move    $s8, $sp               # save $sp to $s8
   2225     move    $s3, $gp               # save $gp to $s3
   2226 
   2227     # prepare for call to artQuickGenericJniTrampoline(Thread*, SP)
   2228     move    $a0, rSELF                     # pass Thread::Current
   2229     addiu   $a1, $sp, ARG_SLOT_SIZE        # save $sp (remove arg slots)
   2230     la      $t9, artQuickGenericJniTrampoline
   2231     jalr    $t9                            # (Thread*, SP)
   2232     addiu   $sp, $sp, -5120                # reserve space on the stack
   2233 
   2234     # The C call will have registered the complete save-frame on success.
   2235     # The result of the call is:
   2236     # v0: ptr to native code, 0 on error.
   2237     # v1: ptr to the bottom of the used area of the alloca, can restore stack till here.
   2238     beq     $v0, $zero, 2f         # check entry error
   2239     move    $t9, $v0               # save the code ptr
   2240     move    $sp, $v1               # release part of the alloca
   2241 
   2242     # Load parameters from stack into registers
   2243     lw      $a0,   0($sp)
   2244     lw      $a1,   4($sp)
   2245     lw      $a2,   8($sp)
   2246     lw      $a3,  12($sp)
   2247 
   2248     # artQuickGenericJniTrampoline sets bit 0 of the native code address to 1
   2249     # when the first two arguments are both single precision floats. This lets
   2250     # us extract them properly from the stack and load into floating point
   2251     # registers.
   2252     MTD     $a0, $a1, $f12, $f13
   2253     andi    $t0, $t9, 1
   2254     xor     $t9, $t9, $t0
   2255     bnez    $t0, 1f
   2256     mtc1    $a1, $f14
   2257     MTD     $a2, $a3, $f14, $f15
   2258 
   2259 1:
   2260     jalr    $t9                    # native call
   2261     nop
   2262     addiu   $sp, $sp, 16           # remove arg slots
   2263 
   2264     move    $gp, $s3               # restore $gp from $s3
   2265 
   2266     # result sign extension is handled in C code
   2267     # prepare for call to artQuickGenericJniEndTrampoline(Thread*, result, result_f)
   2268     move    $a0, rSELF             # pass Thread::Current
   2269     move    $a2, $v0               # pass result
   2270     move    $a3, $v1
   2271     addiu   $sp, $sp, -32          # reserve arg slots
   2272     la      $t9, artQuickGenericJniEndTrampoline
   2273     jalr    $t9
   2274     s.d     $f0, 16($sp)           # pass result_f
   2275 
   2276     lw      $t0, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
   2277     bne     $t0, $zero, 2f         # check for pending exceptions
   2278 
   2279     move    $sp, $s8               # tear down the alloca
   2280 
   2281     # tear down the callee-save frame
   2282     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   2283 
   2284     MTD     $v0, $v1, $f0, $f1     # move float value to return value
   2285     jalr    $zero, $ra
   2286     nop
   2287 
   2288 2:
   2289     lw      $t0, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
   2290     addiu   $sp, $t0, -1  // Remove the GenericJNI tag.
   2291     move    $gp, $s3               # restore $gp from $s3
   2292     # This will create a new save-all frame, required by the runtime.
   2293     DELIVER_PENDING_EXCEPTION
   2294 END art_quick_generic_jni_trampoline
   2295 
   2296     .extern artQuickToInterpreterBridge
   2297 ENTRY art_quick_to_interpreter_bridge
   2298     SETUP_SAVE_REFS_AND_ARGS_FRAME
   2299     move    $a1, rSELF                          # pass Thread::Current
   2300     la      $t9, artQuickToInterpreterBridge
   2301     jalr    $t9                                 # (Method* method, Thread*, SP)
   2302     addiu   $a2, $sp, ARG_SLOT_SIZE             # pass $sp (remove arg slots)
   2303     lw      $t7, THREAD_EXCEPTION_OFFSET(rSELF) # load Thread::Current()->exception_
   2304     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   2305     bnez    $t7, 1f
   2306     # don't care if $v0 and/or $v1 are modified, when exception branch taken
   2307     MTD     $v0, $v1, $f0, $f1                  # move float value to return value
   2308     jalr    $zero, $ra
   2309     nop
   2310 1:
   2311     DELIVER_PENDING_EXCEPTION
   2312 END art_quick_to_interpreter_bridge
   2313 
   2314     .extern artInvokeObsoleteMethod
   2315 ENTRY art_invoke_obsolete_method_stub
   2316     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
   2317     la      $t9, artInvokeObsoleteMethod
   2318     jalr    $t9                                 # (Method* method, Thread* self)
   2319     move    $a1, rSELF                          # pass Thread::Current
   2320 END art_invoke_obsolete_method_stub
   2321 
   2322     /*
   2323      * Routine that intercepts method calls and returns.
   2324      */
   2325     .extern artInstrumentationMethodEntryFromCode
   2326     .extern artInstrumentationMethodExitFromCode
   2327 ENTRY art_quick_instrumentation_entry
   2328     SETUP_SAVE_REFS_AND_ARGS_FRAME
   2329     sw      $a0, 28($sp)    # save arg0 in free arg slot
   2330     addiu   $a3, $sp, ARG_SLOT_SIZE     # Pass $sp.
   2331     la      $t9, artInstrumentationMethodEntryFromCode
   2332     jalr    $t9             # (Method*, Object*, Thread*, SP)
   2333     move    $a2, rSELF      # pass Thread::Current
   2334     beqz    $v0, .Ldeliver_instrumentation_entry_exception
   2335     move    $t9, $v0        # $t9 holds reference to code
   2336     lw      $a0, 28($sp)    # restore arg0 from free arg slot
   2337     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   2338     la      $ra, art_quick_instrumentation_exit
   2339     jalr    $zero, $t9      # call method, returning to art_quick_instrumentation_exit
   2340     nop
   2341 .Ldeliver_instrumentation_entry_exception:
   2342     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   2343     DELIVER_PENDING_EXCEPTION
   2344 END art_quick_instrumentation_entry
   2345 
   2346 ENTRY_NO_GP art_quick_instrumentation_exit
   2347     move    $ra, $zero      # RA points here, so clobber with 0 for later checks.
   2348     SETUP_SAVE_EVERYTHING_FRAME  # Allocates ARG_SLOT_SIZE bytes at the bottom of the stack.
   2349     move    $s2, $gp             # Preserve $gp across the call for exception delivery.
   2350 
   2351     addiu   $a3, $sp, ARG_SLOT_SIZE+16  # Pass fpr_res pointer ($f0 in SAVE_EVERYTHING_FRAME).
   2352     addiu   $a2, $sp, ARG_SLOT_SIZE+148 # Pass gpr_res pointer ($v0 in SAVE_EVERYTHING_FRAME).
   2353     addiu   $a1, $sp, ARG_SLOT_SIZE     # Pass $sp.
   2354     la      $t9, artInstrumentationMethodExitFromCode
   2355     jalr    $t9                         # (Thread*, SP, gpr_res*, fpr_res*)
   2356     move    $a0, rSELF                  # Pass Thread::Current.
   2357 
   2358     beqz    $v0, .Ldo_deliver_instrumentation_exception
   2359     move    $gp, $s2        # Deliver exception if we got nullptr as function.
   2360     bnez    $v1, .Ldeoptimize
   2361 
   2362     # Normal return.
   2363     sw      $v0, (ARG_SLOT_SIZE+FRAME_SIZE_SAVE_EVERYTHING-4)($sp)  # Set return pc.
   2364     RESTORE_SAVE_EVERYTHING_FRAME
   2365     jalr    $zero, $ra
   2366     nop
   2367 .Ldo_deliver_instrumentation_exception:
   2368     DELIVER_PENDING_EXCEPTION_FRAME_READY
   2369 .Ldeoptimize:
   2370     b       art_quick_deoptimize
   2371     sw      $v1, (ARG_SLOT_SIZE+FRAME_SIZE_SAVE_EVERYTHING-4)($sp)
   2372                             # Fake a call from instrumentation return pc.
   2373 END art_quick_instrumentation_exit
   2374 
   2375     /*
   2376      * Instrumentation has requested that we deoptimize into the interpreter. The deoptimization
   2377      * will long jump to the upcall with a special exception of -1.
   2378      */
   2379     .extern artDeoptimize
   2380 ENTRY_NO_GP_CUSTOM_CFA art_quick_deoptimize, ARG_SLOT_SIZE+FRAME_SIZE_SAVE_EVERYTHING
   2381     # SETUP_SAVE_EVERYTHING_FRAME has been done by art_quick_instrumentation_exit.
   2382     .cfi_rel_offset 31, ARG_SLOT_SIZE+252
   2383     .cfi_rel_offset 30, ARG_SLOT_SIZE+248
   2384     .cfi_rel_offset 28, ARG_SLOT_SIZE+244
   2385     .cfi_rel_offset 25, ARG_SLOT_SIZE+240
   2386     .cfi_rel_offset 24, ARG_SLOT_SIZE+236
   2387     .cfi_rel_offset 23, ARG_SLOT_SIZE+232
   2388     .cfi_rel_offset 22, ARG_SLOT_SIZE+228
   2389     .cfi_rel_offset 21, ARG_SLOT_SIZE+224
   2390     .cfi_rel_offset 20, ARG_SLOT_SIZE+220
   2391     .cfi_rel_offset 19, ARG_SLOT_SIZE+216
   2392     .cfi_rel_offset 18, ARG_SLOT_SIZE+212
   2393     .cfi_rel_offset 17, ARG_SLOT_SIZE+208
   2394     .cfi_rel_offset 16, ARG_SLOT_SIZE+204
   2395     .cfi_rel_offset 15, ARG_SLOT_SIZE+200
   2396     .cfi_rel_offset 14, ARG_SLOT_SIZE+196
   2397     .cfi_rel_offset 13, ARG_SLOT_SIZE+192
   2398     .cfi_rel_offset 12, ARG_SLOT_SIZE+188
   2399     .cfi_rel_offset 11, ARG_SLOT_SIZE+184
   2400     .cfi_rel_offset 10, ARG_SLOT_SIZE+180
   2401     .cfi_rel_offset 9, ARG_SLOT_SIZE+176
   2402     .cfi_rel_offset 8, ARG_SLOT_SIZE+172
   2403     .cfi_rel_offset 7, ARG_SLOT_SIZE+168
   2404     .cfi_rel_offset 6, ARG_SLOT_SIZE+164
   2405     .cfi_rel_offset 5, ARG_SLOT_SIZE+160
   2406     .cfi_rel_offset 4, ARG_SLOT_SIZE+156
   2407     .cfi_rel_offset 3, ARG_SLOT_SIZE+152
   2408     .cfi_rel_offset 2, ARG_SLOT_SIZE+148
   2409     .cfi_rel_offset 1, ARG_SLOT_SIZE+144
   2410 
   2411     la      $t9, artDeoptimize
   2412     jalr    $t9             # (Thread*)
   2413     move    $a0, rSELF      # pass Thread::current
   2414     break
   2415 END art_quick_deoptimize
   2416 
   2417     /*
   2418      * Compiled code has requested that we deoptimize into the interpreter. The deoptimization
   2419      * will long jump to the upcall with a special exception of -1.
   2420      */
   2421     .extern artDeoptimizeFromCompiledCode
   2422 ENTRY_NO_GP art_quick_deoptimize_from_compiled_code
   2423     SETUP_SAVE_EVERYTHING_FRAME
   2424     la       $t9, artDeoptimizeFromCompiledCode
   2425     jalr     $t9                            # (DeoptimizationKind, Thread*)
   2426     move     $a1, rSELF                     # pass Thread::current
   2427 END art_quick_deoptimize_from_compiled_code
   2428 
   2429     /*
   2430      * Long integer shift.  This is different from the generic 32/64-bit
   2431      * binary operations because vAA/vBB are 64-bit but vCC (the shift
   2432      * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
   2433      * 6 bits.
   2434      * On entry:
   2435      *   $a0: low word
   2436      *   $a1: high word
   2437      *   $a2: shift count
   2438      */
   2439 ENTRY_NO_GP art_quick_shl_long
   2440     /* shl-long vAA, vBB, vCC */
   2441     sll     $v0, $a0, $a2                    #  rlo<- alo << (shift&31)
   2442     not     $v1, $a2                         #  rhi<- 31-shift  (shift is 5b)
   2443     srl     $a0, 1
   2444     srl     $a0, $v1                         #  alo<- alo >> (32-(shift&31))
   2445     sll     $v1, $a1, $a2                    #  rhi<- ahi << (shift&31)
   2446     andi    $a2, 0x20                        #  shift< shift & 0x20
   2447     beqz    $a2, 1f
   2448     or      $v1, $a0                         #  rhi<- rhi | alo
   2449 
   2450     move    $v1, $v0                         #  rhi<- rlo (if shift&0x20)
   2451     move    $v0, $zero                       #  rlo<- 0 (if shift&0x20)
   2452 
   2453 1:  jalr    $zero, $ra
   2454     nop
   2455 END art_quick_shl_long
   2456 
   2457     /*
   2458      * Long integer shift.  This is different from the generic 32/64-bit
   2459      * binary operations because vAA/vBB are 64-bit but vCC (the shift
   2460      * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
   2461      * 6 bits.
   2462      * On entry:
   2463      *   $a0: low word
   2464      *   $a1: high word
   2465      *   $a2: shift count
   2466      */
   2467 ENTRY_NO_GP art_quick_shr_long
   2468     sra     $v1, $a1, $a2                    #  rhi<- ahi >> (shift&31)
   2469     srl     $v0, $a0, $a2                    #  rlo<- alo >> (shift&31)
   2470     sra     $a3, $a1, 31                     #  $a3<- sign(ah)
   2471     not     $a0, $a2                         #  alo<- 31-shift (shift is 5b)
   2472     sll     $a1, 1
   2473     sll     $a1, $a0                         #  ahi<- ahi << (32-(shift&31))
   2474     andi    $a2, 0x20                        #  shift & 0x20
   2475     beqz    $a2, 1f
   2476     or      $v0, $a1                         #  rlo<- rlo | ahi
   2477 
   2478     move    $v0, $v1                         #  rlo<- rhi (if shift&0x20)
   2479     move    $v1, $a3                         #  rhi<- sign(ahi) (if shift&0x20)
   2480 
   2481 1:  jalr    $zero, $ra
   2482     nop
   2483 END art_quick_shr_long
   2484 
   2485     /*
   2486      * Long integer shift.  This is different from the generic 32/64-bit
   2487      * binary operations because vAA/vBB are 64-bit but vCC (the shift
   2488      * distance) is 32-bit.  Also, Dalvik requires us to ignore all but the low
   2489      * 6 bits.
   2490      * On entry:
   2491      *   $a0: low word
   2492      *   $a1: high word
   2493      *   $a2: shift count
   2494      */
   2495     /* ushr-long vAA, vBB, vCC */
   2496 ENTRY_NO_GP art_quick_ushr_long
   2497     srl     $v1, $a1, $a2                    #  rhi<- ahi >> (shift&31)
   2498     srl     $v0, $a0, $a2                    #  rlo<- alo >> (shift&31)
   2499     not     $a0, $a2                         #  alo<- 31-shift (shift is 5b)
   2500     sll     $a1, 1
   2501     sll     $a1, $a0                         #  ahi<- ahi << (32-(shift&31))
   2502     andi    $a2, 0x20                        #  shift & 0x20
   2503     beqz    $a2, 1f
   2504     or      $v0, $a1                         #  rlo<- rlo | ahi
   2505 
   2506     move    $v0, $v1                         #  rlo<- rhi (if shift&0x20)
   2507     move    $v1, $zero                       #  rhi<- 0 (if shift&0x20)
   2508 
   2509 1:  jalr    $zero, $ra
   2510     nop
   2511 END art_quick_ushr_long
   2512 
   2513 /* java.lang.String.indexOf(int ch, int fromIndex=0) */
   2514 ENTRY_NO_GP art_quick_indexof
   2515 /* $a0 holds address of "this" */
   2516 /* $a1 holds "ch" */
   2517 /* $a2 holds "fromIndex" */
   2518 #if (STRING_COMPRESSION_FEATURE)
   2519     lw    $a3, MIRROR_STRING_COUNT_OFFSET($a0)    # 'count' field of this
   2520 #else
   2521     lw    $t0, MIRROR_STRING_COUNT_OFFSET($a0)    # this.length()
   2522 #endif
   2523     slt   $t1, $a2, $zero # if fromIndex < 0
   2524 #if defined(_MIPS_ARCH_MIPS32R6)
   2525     seleqz $a2, $a2, $t1  #     fromIndex = 0;
   2526 #else
   2527     movn   $a2, $zero, $t1 #    fromIndex = 0;
   2528 #endif
   2529 
   2530 #if (STRING_COMPRESSION_FEATURE)
   2531     srl   $t0, $a3, 1     # $a3 holds count (with flag) and $t0 holds actual length
   2532 #endif
   2533     subu  $t0, $t0, $a2   # this.length() - fromIndex
   2534     blez  $t0, 6f         # if this.length()-fromIndex <= 0
   2535     li    $v0, -1         #     return -1;
   2536 
   2537 #if (STRING_COMPRESSION_FEATURE)
   2538     sll   $a3, $a3, 31    # Extract compression flag.
   2539     beqz  $a3, .Lstring_indexof_compressed
   2540     move  $t2, $a0        # Save a copy in $t2 to later compute result (in branch delay slot).
   2541 #endif
   2542     sll   $v0, $a2, 1     # $a0 += $a2 * 2
   2543     addu  $a0, $a0, $v0   #  "  ditto  "
   2544     move  $v0, $a2        # Set i to fromIndex.
   2545 
   2546 1:
   2547     lhu   $t3, MIRROR_STRING_VALUE_OFFSET($a0)    # if this.charAt(i) == ch
   2548     beq   $t3, $a1, 6f                            #     return i;
   2549     addu  $a0, $a0, 2     # i++
   2550     subu  $t0, $t0, 1     # this.length() - i
   2551     bnez  $t0, 1b         # while this.length() - i > 0
   2552     addu  $v0, $v0, 1     # i++
   2553 
   2554     li    $v0, -1         # if this.length() - i <= 0
   2555                           #     return -1;
   2556 
   2557 6:
   2558     j     $ra
   2559     nop
   2560 
   2561 #if (STRING_COMPRESSION_FEATURE)
   2562 .Lstring_indexof_compressed:
   2563     addu  $a0, $a0, $a2   # $a0 += $a2
   2564 
   2565 .Lstring_indexof_compressed_loop:
   2566     lbu   $t3, MIRROR_STRING_VALUE_OFFSET($a0)
   2567     beq   $t3, $a1, .Lstring_indexof_compressed_matched
   2568     subu  $t0, $t0, 1
   2569     bgtz  $t0, .Lstring_indexof_compressed_loop
   2570     addu  $a0, $a0, 1
   2571 
   2572 .Lstring_indexof_nomatch:
   2573     jalr  $zero, $ra
   2574     li    $v0, -1         # return -1;
   2575 
   2576 .Lstring_indexof_compressed_matched:
   2577     jalr  $zero, $ra
   2578     subu  $v0, $a0, $t2   # return (current - start);
   2579 #endif
   2580 END art_quick_indexof
   2581 
   2582 /* java.lang.String.compareTo(String anotherString) */
   2583 ENTRY_NO_GP art_quick_string_compareto
   2584 /* $a0 holds address of "this" */
   2585 /* $a1 holds address of "anotherString" */
   2586     beq    $a0, $a1, .Lstring_compareto_length_diff   # this and anotherString are the same object
   2587     move   $a3, $a2                                   # trick to return 0 (it returns a2 - a3)
   2588 
   2589 #if (STRING_COMPRESSION_FEATURE)
   2590     lw     $t0, MIRROR_STRING_COUNT_OFFSET($a0)   # 'count' field of this
   2591     lw     $t1, MIRROR_STRING_COUNT_OFFSET($a1)   # 'count' field of anotherString
   2592     sra    $a2, $t0, 1                            # this.length()
   2593     sra    $a3, $t1, 1                            # anotherString.length()
   2594 #else
   2595     lw     $a2, MIRROR_STRING_COUNT_OFFSET($a0)   # this.length()
   2596     lw     $a3, MIRROR_STRING_COUNT_OFFSET($a1)   # anotherString.length()
   2597 #endif
   2598 
   2599     MINu   $t2, $a2, $a3
   2600     # $t2 now holds min(this.length(),anotherString.length())
   2601 
   2602     # while min(this.length(),anotherString.length())-i != 0
   2603     beqz   $t2, .Lstring_compareto_length_diff # if $t2==0
   2604     nop                                        #     return (this.length() - anotherString.length())
   2605 
   2606 #if (STRING_COMPRESSION_FEATURE)
   2607     # Differ cases:
   2608     sll    $t3, $t0, 31
   2609     beqz   $t3, .Lstring_compareto_this_is_compressed
   2610     sll    $t3, $t1, 31                           # In branch delay slot.
   2611     beqz   $t3, .Lstring_compareto_that_is_compressed
   2612     nop
   2613     b      .Lstring_compareto_both_not_compressed
   2614     nop
   2615 
   2616 .Lstring_compareto_this_is_compressed:
   2617     beqz   $t3, .Lstring_compareto_both_compressed
   2618     nop
   2619     /* If (this->IsCompressed() && that->IsCompressed() == false) */
   2620 .Lstring_compareto_loop_comparison_this_compressed:
   2621     lbu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)
   2622     lhu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
   2623     bne    $t0, $t1, .Lstring_compareto_char_diff
   2624     addiu  $a0, $a0, 1    # point at this.charAt(i++) - compressed
   2625     subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
   2626     bnez   $t2, .Lstring_compareto_loop_comparison_this_compressed
   2627     addiu  $a1, $a1, 2    # point at anotherString.charAt(i++) - uncompressed
   2628     jalr   $zero, $ra
   2629     subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
   2630 
   2631 .Lstring_compareto_that_is_compressed:
   2632     lhu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)
   2633     lbu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
   2634     bne    $t0, $t1, .Lstring_compareto_char_diff
   2635     addiu  $a0, $a0, 2    # point at this.charAt(i++) - uncompressed
   2636     subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
   2637     bnez   $t2, .Lstring_compareto_that_is_compressed
   2638     addiu  $a1, $a1, 1    # point at anotherString.charAt(i++) - compressed
   2639     jalr   $zero, $ra
   2640     subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
   2641 
   2642 .Lstring_compareto_both_compressed:
   2643     lbu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)
   2644     lbu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
   2645     bne    $t0, $t1, .Lstring_compareto_char_diff
   2646     addiu  $a0, $a0, 1    # point at this.charAt(i++) - compressed
   2647     subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
   2648     bnez   $t2, .Lstring_compareto_both_compressed
   2649     addiu  $a1, $a1, 1    # point at anotherString.charAt(i++) - compressed
   2650     jalr   $zero, $ra
   2651     subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
   2652 #endif
   2653 
   2654 .Lstring_compareto_both_not_compressed:
   2655     lhu    $t0, MIRROR_STRING_VALUE_OFFSET($a0)   # while this.charAt(i) == anotherString.charAt(i)
   2656     lhu    $t1, MIRROR_STRING_VALUE_OFFSET($a1)
   2657     bne    $t0, $t1, .Lstring_compareto_char_diff # if this.charAt(i) != anotherString.charAt(i)
   2658                           #     return (this.charAt(i) - anotherString.charAt(i))
   2659     addiu  $a0, $a0, 2    # point at this.charAt(i++)
   2660     subu   $t2, $t2, 1    # new value of min(this.length(),anotherString.length())-i
   2661     bnez   $t2, .Lstring_compareto_both_not_compressed
   2662     addiu  $a1, $a1, 2    # point at anotherString.charAt(i++)
   2663 
   2664 .Lstring_compareto_length_diff:
   2665     jalr   $zero, $ra
   2666     subu   $v0, $a2, $a3  # return (this.length() - anotherString.length())
   2667 
   2668 .Lstring_compareto_char_diff:
   2669     jalr   $zero, $ra
   2670     subu   $v0, $t0, $t1  # return (this.charAt(i) - anotherString.charAt(i))
   2671 END art_quick_string_compareto
   2672 
   2673     /*
   2674      * Create a function `name` calling the ReadBarrier::Mark routine,
   2675      * getting its argument and returning its result through register
   2676      * `reg`, saving and restoring all caller-save registers.
   2677      */
   2678 .macro READ_BARRIER_MARK_REG name, reg
   2679 ENTRY \name
   2680     // Null check so that we can load the lock word.
   2681     bnez    \reg, .Lnot_null_\name
   2682     nop
   2683 .Lret_rb_\name:
   2684     jalr    $zero, $ra
   2685     nop
   2686 .Lnot_null_\name:
   2687     // Check lock word for mark bit, if marked return.
   2688     lw      $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET(\reg)
   2689     .set push
   2690     .set noat
   2691     sll     $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT     # Move mark bit to sign bit.
   2692     bltz    $at, .Lret_rb_\name
   2693 #if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
   2694     // The below code depends on the lock word state being in the highest bits
   2695     // and the "forwarding address" state having all bits set.
   2696 #error "Unexpected lock word state shift or forwarding address state value."
   2697 #endif
   2698     // Test that both the forwarding state bits are 1.
   2699     sll     $at, $t9, 1
   2700     and     $at, $at, $t9                               # Sign bit = 1 IFF both bits are 1.
   2701     bltz    $at, .Lret_forwarding_address\name
   2702     nop
   2703     .set pop
   2704 
   2705     addiu   $sp, $sp, -160      # Includes 16 bytes of space for argument registers a0-a3.
   2706     .cfi_adjust_cfa_offset 160
   2707 
   2708     sw      $ra, 156($sp)
   2709     .cfi_rel_offset 31, 156
   2710     sw      $t8, 152($sp)
   2711     .cfi_rel_offset 24, 152
   2712     sw      $t7, 148($sp)
   2713     .cfi_rel_offset 15, 148
   2714     sw      $t6, 144($sp)
   2715     .cfi_rel_offset 14, 144
   2716     sw      $t5, 140($sp)
   2717     .cfi_rel_offset 13, 140
   2718     sw      $t4, 136($sp)
   2719     .cfi_rel_offset 12, 136
   2720     sw      $t3, 132($sp)
   2721     .cfi_rel_offset 11, 132
   2722     sw      $t2, 128($sp)
   2723     .cfi_rel_offset 10, 128
   2724     sw      $t1, 124($sp)
   2725     .cfi_rel_offset 9, 124
   2726     sw      $t0, 120($sp)
   2727     .cfi_rel_offset 8, 120
   2728     sw      $a3, 116($sp)
   2729     .cfi_rel_offset 7, 116
   2730     sw      $a2, 112($sp)
   2731     .cfi_rel_offset 6, 112
   2732     sw      $a1, 108($sp)
   2733     .cfi_rel_offset 5, 108
   2734     sw      $a0, 104($sp)
   2735     .cfi_rel_offset 4, 104
   2736     sw      $v1, 100($sp)
   2737     .cfi_rel_offset 3, 100
   2738     sw      $v0, 96($sp)
   2739     .cfi_rel_offset 2, 96
   2740 
   2741     la      $t9, artReadBarrierMark
   2742 
   2743     sdc1    $f18, 88($sp)
   2744     sdc1    $f16, 80($sp)
   2745     sdc1    $f14, 72($sp)
   2746     sdc1    $f12, 64($sp)
   2747     sdc1    $f10, 56($sp)
   2748     sdc1    $f8,  48($sp)
   2749     sdc1    $f6,  40($sp)
   2750     sdc1    $f4,  32($sp)
   2751     sdc1    $f2,  24($sp)
   2752 
   2753     .ifnc \reg, $a0
   2754       move  $a0, \reg           # pass obj from `reg` in a0
   2755     .endif
   2756     jalr    $t9                 # v0 <- artReadBarrierMark(obj)
   2757     sdc1    $f0,  16($sp)       # in delay slot
   2758 
   2759     lw      $ra, 156($sp)
   2760     .cfi_restore 31
   2761     lw      $t8, 152($sp)
   2762     .cfi_restore 24
   2763     lw      $t7, 148($sp)
   2764     .cfi_restore 15
   2765     lw      $t6, 144($sp)
   2766     .cfi_restore 14
   2767     lw      $t5, 140($sp)
   2768     .cfi_restore 13
   2769     lw      $t4, 136($sp)
   2770     .cfi_restore 12
   2771     lw      $t3, 132($sp)
   2772     .cfi_restore 11
   2773     lw      $t2, 128($sp)
   2774     .cfi_restore 10
   2775     lw      $t1, 124($sp)
   2776     .cfi_restore 9
   2777     lw      $t0, 120($sp)
   2778     .cfi_restore 8
   2779     lw      $a3, 116($sp)
   2780     .cfi_restore 7
   2781     lw      $a2, 112($sp)
   2782     .cfi_restore 6
   2783     lw      $a1, 108($sp)
   2784     .cfi_restore 5
   2785     lw      $a0, 104($sp)
   2786     .cfi_restore 4
   2787     lw      $v1, 100($sp)
   2788     .cfi_restore 3
   2789 
   2790     .ifnc \reg, $v0
   2791       move  \reg, $v0           # `reg` <- v0
   2792       lw    $v0, 96($sp)
   2793       .cfi_restore 2
   2794     .endif
   2795 
   2796     ldc1    $f18, 88($sp)
   2797     ldc1    $f16, 80($sp)
   2798     ldc1    $f14, 72($sp)
   2799     ldc1    $f12, 64($sp)
   2800     ldc1    $f10, 56($sp)
   2801     ldc1    $f8,  48($sp)
   2802     ldc1    $f6,  40($sp)
   2803     ldc1    $f4,  32($sp)
   2804     ldc1    $f2,  24($sp)
   2805     ldc1    $f0,  16($sp)
   2806 
   2807     jalr    $zero, $ra
   2808     addiu   $sp, $sp, 160
   2809     .cfi_adjust_cfa_offset -160
   2810 
   2811 .Lret_forwarding_address\name:
   2812     jalr    $zero, $ra
   2813     // Shift left by the forwarding address shift. This clears out the state bits since they are
   2814     // in the top 2 bits of the lock word.
   2815     sll     \reg, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
   2816 END \name
   2817 .endm
   2818 
   2819 // Note that art_quick_read_barrier_mark_regXX corresponds to register XX+1.
   2820 // ZERO (register 0) is reserved.
   2821 // AT (register 1) is reserved as a temporary/scratch register.
   2822 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg01, $v0
   2823 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg02, $v1
   2824 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg03, $a0
   2825 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg04, $a1
   2826 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg05, $a2
   2827 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg06, $a3
   2828 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg07, $t0
   2829 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg08, $t1
   2830 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg09, $t2
   2831 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg10, $t3
   2832 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg11, $t4
   2833 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg12, $t5
   2834 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg13, $t6
   2835 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg14, $t7
   2836 // S0 and S1 (registers 16 and 17) are reserved as suspended and thread registers.
   2837 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg17, $s2
   2838 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg18, $s3
   2839 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg19, $s4
   2840 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg20, $s5
   2841 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg21, $s6
   2842 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg22, $s7
   2843 // T8 and T9 (registers 24 and 25) are reserved as temporary/scratch registers.
   2844 // K0, K1, GP, SP (registers 26 - 29) are reserved.
   2845 READ_BARRIER_MARK_REG art_quick_read_barrier_mark_reg29, $s8
   2846 // RA (register 31) is reserved.
   2847 
   2848 // Caller code:
   2849 // Short constant offset/index:
   2850 // R2:                           | R6:
   2851 //  lw      $t9, pReadBarrierMarkReg00
   2852 //  beqz    $t9, skip_call       |  beqzc   $t9, skip_call
   2853 //  addiu   $t9, $t9, thunk_disp |  nop
   2854 //  jalr    $t9                  |  jialc   $t9, thunk_disp
   2855 //  nop                          |
   2856 // skip_call:                    | skip_call:
   2857 //  lw      `out`, ofs(`obj`)    |  lw      `out`, ofs(`obj`)
   2858 // [subu    `out`, $zero, `out`] | [subu    `out`, $zero, `out`]  # Unpoison reference.
   2859 .macro BRB_FIELD_SHORT_OFFSET_ENTRY obj
   2860 1:
   2861     # Explicit null check. May be redundant (for array elements or when the field
   2862     # offset is larger than the page size, 4KB).
   2863     # $ra will be adjusted to point to lw's stack map when throwing NPE.
   2864     beqz    \obj, .Lintrospection_throw_npe
   2865 #if defined(_MIPS_ARCH_MIPS32R6)
   2866     lapc    $gp, .Lintrospection_exits                  # $gp = address of .Lintrospection_exits.
   2867 #else
   2868     addiu   $gp, $t9, (.Lintrospection_exits - 1b)      # $gp = address of .Lintrospection_exits.
   2869 #endif
   2870     .set push
   2871     .set noat
   2872     lw      $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
   2873     sll     $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT   # Move barrier state bit
   2874                                                                 # to sign bit.
   2875     bltz    $at, .Lintrospection_field_array            # If gray, load reference, mark.
   2876     move    $t8, \obj                                   # Move `obj` to $t8 for common code.
   2877     .set pop
   2878     jalr    $zero, $ra                                  # Otherwise, load-load barrier and return.
   2879     sync
   2880 .endm
   2881 
   2882 // Caller code (R2):
   2883 // Long constant offset/index:   | Variable index:
   2884 //  lw      $t9, pReadBarrierMarkReg00
   2885 //  lui     $t8, ofs_hi          |  sll     $t8, `index`, 2
   2886 //  beqz    $t9, skip_call       |  beqz    $t9, skip_call
   2887 //  addiu   $t9, $t9, thunk_disp |  addiu   $t9, $t9, thunk_disp
   2888 //  jalr    $t9                  |  jalr    $t9
   2889 // skip_call:                    | skip_call:
   2890 //  addu    $t8, $t8, `obj`      |  addu    $t8, $t8, `obj`
   2891 //  lw      `out`, ofs_lo($t8)   |  lw      `out`, ofs($t8)
   2892 // [subu    `out`, $zero, `out`] | [subu    `out`, $zero, `out`]  # Unpoison reference.
   2893 //
   2894 // Caller code (R6):
   2895 // Long constant offset/index:   | Variable index:
   2896 //  lw      $t9, pReadBarrierMarkReg00
   2897 //  beqz    $t9, skip_call       |  beqz    $t9, skip_call
   2898 //  aui     $t8, `obj`, ofs_hi   |  lsa     $t8, `index`, `obj`, 2
   2899 //  jialc   $t9, thunk_disp      |  jialc   $t9, thunk_disp
   2900 // skip_call:                    | skip_call:
   2901 //  lw      `out`, ofs_lo($t8)   |  lw      `out`, ofs($t8)
   2902 // [subu    `out`, $zero, `out`] | [subu    `out`, $zero, `out`]  # Unpoison reference.
   2903 .macro BRB_FIELD_LONG_OFFSET_ENTRY obj
   2904 1:
   2905     # No explicit null check for variable indices or large constant indices/offsets
   2906     # as it must have been done earlier.
   2907 #if defined(_MIPS_ARCH_MIPS32R6)
   2908     lapc    $gp, .Lintrospection_exits                  # $gp = address of .Lintrospection_exits.
   2909 #else
   2910     addiu   $gp, $t9, (.Lintrospection_exits - 1b)      # $gp = address of .Lintrospection_exits.
   2911 #endif
   2912     .set push
   2913     .set noat
   2914     lw      $at, MIRROR_OBJECT_LOCK_WORD_OFFSET(\obj)
   2915     sll     $at, $at, 31 - LOCK_WORD_READ_BARRIER_STATE_SHIFT   # Move barrier state bit
   2916                                                                 # to sign bit.
   2917     bltz    $at, .Lintrospection_field_array            # If gray, load reference, mark.
   2918     nop
   2919     .set pop
   2920     jalr    $zero, $ra                                  # Otherwise, load-load barrier and return.
   2921     sync
   2922     break                                               # Padding to 8 instructions.
   2923 .endm
   2924 
   2925 .macro BRB_GC_ROOT_ENTRY root
   2926 1:
   2927 #if defined(_MIPS_ARCH_MIPS32R6)
   2928     lapc    $gp, .Lintrospection_exit_\root             # $gp = exit point address.
   2929 #else
   2930     addiu   $gp, $t9, (.Lintrospection_exit_\root - 1b)  # $gp = exit point address.
   2931 #endif
   2932     bnez    \root, .Lintrospection_common
   2933     move    $t8, \root                                  # Move reference to $t8 for common code.
   2934     jalr    $zero, $ra                                  # Return if null.
   2935     # The next instruction (from the following BRB_GC_ROOT_ENTRY) fills the delay slot.
   2936     # This instruction has no effect (actual NOP for the last entry; otherwise changes $gp,
   2937     # which is unused after that anyway).
   2938 .endm
   2939 
   2940 .macro BRB_FIELD_EXIT out
   2941 .Lintrospection_exit_\out:
   2942     jalr    $zero, $ra
   2943     move    \out, $t8                                   # Return reference in expected register.
   2944 .endm
   2945 
   2946 .macro BRB_FIELD_EXIT_BREAK
   2947     break
   2948     break
   2949 .endm
   2950 
   2951 ENTRY_NO_GP art_quick_read_barrier_mark_introspection
   2952     # Entry points for offsets/indices not fitting into int16_t and for variable indices.
   2953     BRB_FIELD_LONG_OFFSET_ENTRY $v0
   2954     BRB_FIELD_LONG_OFFSET_ENTRY $v1
   2955     BRB_FIELD_LONG_OFFSET_ENTRY $a0
   2956     BRB_FIELD_LONG_OFFSET_ENTRY $a1
   2957     BRB_FIELD_LONG_OFFSET_ENTRY $a2
   2958     BRB_FIELD_LONG_OFFSET_ENTRY $a3
   2959     BRB_FIELD_LONG_OFFSET_ENTRY $t0
   2960     BRB_FIELD_LONG_OFFSET_ENTRY $t1
   2961     BRB_FIELD_LONG_OFFSET_ENTRY $t2
   2962     BRB_FIELD_LONG_OFFSET_ENTRY $t3
   2963     BRB_FIELD_LONG_OFFSET_ENTRY $t4
   2964     BRB_FIELD_LONG_OFFSET_ENTRY $t5
   2965     BRB_FIELD_LONG_OFFSET_ENTRY $t6
   2966     BRB_FIELD_LONG_OFFSET_ENTRY $t7
   2967     BRB_FIELD_LONG_OFFSET_ENTRY $s2
   2968     BRB_FIELD_LONG_OFFSET_ENTRY $s3
   2969     BRB_FIELD_LONG_OFFSET_ENTRY $s4
   2970     BRB_FIELD_LONG_OFFSET_ENTRY $s5
   2971     BRB_FIELD_LONG_OFFSET_ENTRY $s6
   2972     BRB_FIELD_LONG_OFFSET_ENTRY $s7
   2973     BRB_FIELD_LONG_OFFSET_ENTRY $s8
   2974 
   2975     # Entry points for offsets/indices fitting into int16_t.
   2976     BRB_FIELD_SHORT_OFFSET_ENTRY $v0
   2977     BRB_FIELD_SHORT_OFFSET_ENTRY $v1
   2978     BRB_FIELD_SHORT_OFFSET_ENTRY $a0
   2979     BRB_FIELD_SHORT_OFFSET_ENTRY $a1
   2980     BRB_FIELD_SHORT_OFFSET_ENTRY $a2
   2981     BRB_FIELD_SHORT_OFFSET_ENTRY $a3
   2982     BRB_FIELD_SHORT_OFFSET_ENTRY $t0
   2983     BRB_FIELD_SHORT_OFFSET_ENTRY $t1
   2984     BRB_FIELD_SHORT_OFFSET_ENTRY $t2
   2985     BRB_FIELD_SHORT_OFFSET_ENTRY $t3
   2986     BRB_FIELD_SHORT_OFFSET_ENTRY $t4
   2987     BRB_FIELD_SHORT_OFFSET_ENTRY $t5
   2988     BRB_FIELD_SHORT_OFFSET_ENTRY $t6
   2989     BRB_FIELD_SHORT_OFFSET_ENTRY $t7
   2990     BRB_FIELD_SHORT_OFFSET_ENTRY $s2
   2991     BRB_FIELD_SHORT_OFFSET_ENTRY $s3
   2992     BRB_FIELD_SHORT_OFFSET_ENTRY $s4
   2993     BRB_FIELD_SHORT_OFFSET_ENTRY $s5
   2994     BRB_FIELD_SHORT_OFFSET_ENTRY $s6
   2995     BRB_FIELD_SHORT_OFFSET_ENTRY $s7
   2996     BRB_FIELD_SHORT_OFFSET_ENTRY $s8
   2997 
   2998     .global art_quick_read_barrier_mark_introspection_gc_roots
   2999 art_quick_read_barrier_mark_introspection_gc_roots:
   3000     # Entry points for GC roots.
   3001     BRB_GC_ROOT_ENTRY $v0
   3002     BRB_GC_ROOT_ENTRY $v1
   3003     BRB_GC_ROOT_ENTRY $a0
   3004     BRB_GC_ROOT_ENTRY $a1
   3005     BRB_GC_ROOT_ENTRY $a2
   3006     BRB_GC_ROOT_ENTRY $a3
   3007     BRB_GC_ROOT_ENTRY $t0
   3008     BRB_GC_ROOT_ENTRY $t1
   3009     BRB_GC_ROOT_ENTRY $t2
   3010     BRB_GC_ROOT_ENTRY $t3
   3011     BRB_GC_ROOT_ENTRY $t4
   3012     BRB_GC_ROOT_ENTRY $t5
   3013     BRB_GC_ROOT_ENTRY $t6
   3014     BRB_GC_ROOT_ENTRY $t7
   3015     BRB_GC_ROOT_ENTRY $s2
   3016     BRB_GC_ROOT_ENTRY $s3
   3017     BRB_GC_ROOT_ENTRY $s4
   3018     BRB_GC_ROOT_ENTRY $s5
   3019     BRB_GC_ROOT_ENTRY $s6
   3020     BRB_GC_ROOT_ENTRY $s7
   3021     BRB_GC_ROOT_ENTRY $s8
   3022     .global art_quick_read_barrier_mark_introspection_end_of_entries
   3023 art_quick_read_barrier_mark_introspection_end_of_entries:
   3024     nop                         # Fill the delay slot of the last BRB_GC_ROOT_ENTRY.
   3025 
   3026 .Lintrospection_throw_npe:
   3027     b       art_quick_throw_null_pointer_exception
   3028     addiu   $ra, $ra, 4         # Skip lw, make $ra point to lw's stack map.
   3029 
   3030     .set push
   3031     .set noat
   3032 
   3033     // Fields and array elements.
   3034 
   3035 .Lintrospection_field_array:
   3036     // Get the field/element address using $t8 and the offset from the lw instruction.
   3037     lh      $at, 0($ra)         # $ra points to lw: $at = field/element offset.
   3038     addiu   $ra, $ra, 4 + HEAP_POISON_INSTR_SIZE  # Skip lw(+subu).
   3039     addu    $t8, $t8, $at       # $t8 = field/element address.
   3040 
   3041     // Calculate the address of the exit point, store it in $gp and load the reference into $t8.
   3042     lb      $at, (-HEAP_POISON_INSTR_SIZE - 2)($ra)   # $ra-HEAP_POISON_INSTR_SIZE-4 points to
   3043                                                       # "lw `out`, ...".
   3044     andi    $at, $at, 31        # Extract `out` from lw.
   3045     sll     $at, $at, 3         # Multiply `out` by the exit point size (BRB_FIELD_EXIT* macros).
   3046 
   3047     lw      $t8, 0($t8)         # $t8 = reference.
   3048     UNPOISON_HEAP_REF $t8
   3049 
   3050     // Return if null reference.
   3051     bnez    $t8, .Lintrospection_common
   3052     addu    $gp, $gp, $at       # $gp = address of the exit point.
   3053 
   3054     // Early return through the exit point.
   3055 .Lintrospection_return_early:
   3056     jalr    $zero, $gp          # Move $t8 to `out` and return.
   3057     nop
   3058 
   3059     // Code common for GC roots, fields and array elements.
   3060 
   3061 .Lintrospection_common:
   3062     // Check lock word for mark bit, if marked return.
   3063     lw      $t9, MIRROR_OBJECT_LOCK_WORD_OFFSET($t8)
   3064     sll     $at, $t9, 31 - LOCK_WORD_MARK_BIT_SHIFT     # Move mark bit to sign bit.
   3065     bltz    $at, .Lintrospection_return_early
   3066 #if (LOCK_WORD_STATE_SHIFT != 30) || (LOCK_WORD_STATE_FORWARDING_ADDRESS != 3)
   3067     // The below code depends on the lock word state being in the highest bits
   3068     // and the "forwarding address" state having all bits set.
   3069 #error "Unexpected lock word state shift or forwarding address state value."
   3070 #endif
   3071     // Test that both the forwarding state bits are 1.
   3072     sll     $at, $t9, 1
   3073     and     $at, $at, $t9                               # Sign bit = 1 IFF both bits are 1.
   3074     bgez    $at, .Lintrospection_mark
   3075     nop
   3076 
   3077     .set pop
   3078 
   3079     // Shift left by the forwarding address shift. This clears out the state bits since they are
   3080     // in the top 2 bits of the lock word.
   3081     jalr    $zero, $gp          # Move $t8 to `out` and return.
   3082     sll     $t8, $t9, LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
   3083 
   3084 .Lintrospection_mark:
   3085     // Partially set up the stack frame preserving only $ra.
   3086     addiu   $sp, $sp, -160      # Includes 16 bytes of space for argument registers $a0-$a3.
   3087     .cfi_adjust_cfa_offset 160
   3088     sw      $ra, 156($sp)
   3089     .cfi_rel_offset 31, 156
   3090 
   3091     // Set up $gp, clobbering $ra and using the branch delay slot for a useful instruction.
   3092     bal     1f
   3093     sw      $gp, 152($sp)       # Preserve the exit point address.
   3094 1:
   3095     .cpload $ra
   3096 
   3097     // Finalize the stack frame and call.
   3098     sw      $t7, 148($sp)
   3099     .cfi_rel_offset 15, 148
   3100     sw      $t6, 144($sp)
   3101     .cfi_rel_offset 14, 144
   3102     sw      $t5, 140($sp)
   3103     .cfi_rel_offset 13, 140
   3104     sw      $t4, 136($sp)
   3105     .cfi_rel_offset 12, 136
   3106     sw      $t3, 132($sp)
   3107     .cfi_rel_offset 11, 132
   3108     sw      $t2, 128($sp)
   3109     .cfi_rel_offset 10, 128
   3110     sw      $t1, 124($sp)
   3111     .cfi_rel_offset 9, 124
   3112     sw      $t0, 120($sp)
   3113     .cfi_rel_offset 8, 120
   3114     sw      $a3, 116($sp)
   3115     .cfi_rel_offset 7, 116
   3116     sw      $a2, 112($sp)
   3117     .cfi_rel_offset 6, 112
   3118     sw      $a1, 108($sp)
   3119     .cfi_rel_offset 5, 108
   3120     sw      $a0, 104($sp)
   3121     .cfi_rel_offset 4, 104
   3122     sw      $v1, 100($sp)
   3123     .cfi_rel_offset 3, 100
   3124     sw      $v0, 96($sp)
   3125     .cfi_rel_offset 2, 96
   3126 
   3127     la      $t9, artReadBarrierMark
   3128 
   3129     sdc1    $f18, 88($sp)
   3130     sdc1    $f16, 80($sp)
   3131     sdc1    $f14, 72($sp)
   3132     sdc1    $f12, 64($sp)
   3133     sdc1    $f10, 56($sp)
   3134     sdc1    $f8,  48($sp)
   3135     sdc1    $f6,  40($sp)
   3136     sdc1    $f4,  32($sp)
   3137     sdc1    $f2,  24($sp)
   3138     sdc1    $f0,  16($sp)
   3139 
   3140     jalr    $t9                 # $v0 <- artReadBarrierMark(reference)
   3141     move    $a0, $t8            # Pass reference in $a0.
   3142     move    $t8, $v0
   3143 
   3144     lw      $ra, 156($sp)
   3145     .cfi_restore 31
   3146     lw      $gp, 152($sp)       # $gp = address of the exit point.
   3147     lw      $t7, 148($sp)
   3148     .cfi_restore 15
   3149     lw      $t6, 144($sp)
   3150     .cfi_restore 14
   3151     lw      $t5, 140($sp)
   3152     .cfi_restore 13
   3153     lw      $t4, 136($sp)
   3154     .cfi_restore 12
   3155     lw      $t3, 132($sp)
   3156     .cfi_restore 11
   3157     lw      $t2, 128($sp)
   3158     .cfi_restore 10
   3159     lw      $t1, 124($sp)
   3160     .cfi_restore 9
   3161     lw      $t0, 120($sp)
   3162     .cfi_restore 8
   3163     lw      $a3, 116($sp)
   3164     .cfi_restore 7
   3165     lw      $a2, 112($sp)
   3166     .cfi_restore 6
   3167     lw      $a1, 108($sp)
   3168     .cfi_restore 5
   3169     lw      $a0, 104($sp)
   3170     .cfi_restore 4
   3171     lw      $v1, 100($sp)
   3172     .cfi_restore 3
   3173     lw      $v0, 96($sp)
   3174     .cfi_restore 2
   3175 
   3176     ldc1    $f18, 88($sp)
   3177     ldc1    $f16, 80($sp)
   3178     ldc1    $f14, 72($sp)
   3179     ldc1    $f12, 64($sp)
   3180     ldc1    $f10, 56($sp)
   3181     ldc1    $f8,  48($sp)
   3182     ldc1    $f6,  40($sp)
   3183     ldc1    $f4,  32($sp)
   3184     ldc1    $f2,  24($sp)
   3185     ldc1    $f0,  16($sp)
   3186 
   3187     // Return through the exit point.
   3188     jalr    $zero, $gp          # Move $t8 to `out` and return.
   3189     addiu   $sp, $sp, 160
   3190     .cfi_adjust_cfa_offset -160
   3191 
   3192 .Lintrospection_exits:
   3193     BRB_FIELD_EXIT_BREAK
   3194     BRB_FIELD_EXIT_BREAK
   3195     BRB_FIELD_EXIT $v0
   3196     BRB_FIELD_EXIT $v1
   3197     BRB_FIELD_EXIT $a0
   3198     BRB_FIELD_EXIT $a1
   3199     BRB_FIELD_EXIT $a2
   3200     BRB_FIELD_EXIT $a3
   3201     BRB_FIELD_EXIT $t0
   3202     BRB_FIELD_EXIT $t1
   3203     BRB_FIELD_EXIT $t2
   3204     BRB_FIELD_EXIT $t3
   3205     BRB_FIELD_EXIT $t4
   3206     BRB_FIELD_EXIT $t5
   3207     BRB_FIELD_EXIT $t6
   3208     BRB_FIELD_EXIT $t7
   3209     BRB_FIELD_EXIT_BREAK
   3210     BRB_FIELD_EXIT_BREAK
   3211     BRB_FIELD_EXIT $s2
   3212     BRB_FIELD_EXIT $s3
   3213     BRB_FIELD_EXIT $s4
   3214     BRB_FIELD_EXIT $s5
   3215     BRB_FIELD_EXIT $s6
   3216     BRB_FIELD_EXIT $s7
   3217     BRB_FIELD_EXIT_BREAK
   3218     BRB_FIELD_EXIT_BREAK
   3219     BRB_FIELD_EXIT_BREAK
   3220     BRB_FIELD_EXIT_BREAK
   3221     BRB_FIELD_EXIT_BREAK
   3222     BRB_FIELD_EXIT_BREAK
   3223     BRB_FIELD_EXIT $s8
   3224     BRB_FIELD_EXIT_BREAK
   3225 END art_quick_read_barrier_mark_introspection
   3226 
   3227 .extern artInvokePolymorphic
   3228 ENTRY art_quick_invoke_polymorphic
   3229     SETUP_SAVE_REFS_AND_ARGS_FRAME
   3230     move  $a2, rSELF                          # Make $a2 an alias for the current Thread.
   3231     addiu $a3, $sp, ARG_SLOT_SIZE             # Make $a3 a pointer to the saved frame context.
   3232     sw    $zero, 20($sp)                      # Initialize JValue result.
   3233     sw    $zero, 16($sp)
   3234     la    $t9, artInvokePolymorphic
   3235     jalr  $t9                                 # artInvokePolymorphic(result, receiver, Thread*, context)
   3236     addiu $a0, $sp, 16                        # Make $a0 a pointer to the JValue result
   3237 .macro MATCH_RETURN_TYPE c, handler
   3238     li    $t0, \c
   3239     beq   $v0, $t0, \handler
   3240 .endm
   3241     MATCH_RETURN_TYPE 'V', .Lcleanup_and_return
   3242     MATCH_RETURN_TYPE 'L', .Lstore_int_result
   3243     MATCH_RETURN_TYPE 'I', .Lstore_int_result
   3244     MATCH_RETURN_TYPE 'J', .Lstore_long_result
   3245     MATCH_RETURN_TYPE 'B', .Lstore_int_result
   3246     MATCH_RETURN_TYPE 'C', .Lstore_char_result
   3247     MATCH_RETURN_TYPE 'D', .Lstore_double_result
   3248     MATCH_RETURN_TYPE 'F', .Lstore_float_result
   3249     MATCH_RETURN_TYPE 'S', .Lstore_int_result
   3250     MATCH_RETURN_TYPE 'Z', .Lstore_boolean_result
   3251 .purgem MATCH_RETURN_TYPE
   3252     nop
   3253     b .Lcleanup_and_return
   3254     nop
   3255 .Lstore_boolean_result:
   3256     b .Lcleanup_and_return
   3257     lbu   $v0, 16($sp)                        # Move byte from JValue result to return value register.
   3258 .Lstore_char_result:
   3259     b .Lcleanup_and_return
   3260     lhu   $v0, 16($sp)                        # Move char from JValue result to return value register.
   3261 .Lstore_double_result:
   3262 .Lstore_float_result:
   3263     CHECK_ALIGNMENT $sp, $t0
   3264     ldc1  $f0, 16($sp)                        # Move double/float from JValue result to return value register.
   3265     b .Lcleanup_and_return
   3266     nop
   3267 .Lstore_long_result:
   3268     lw    $v1, 20($sp)                        # Move upper bits from JValue result to return value register.
   3269     // Fall-through for lower bits.
   3270 .Lstore_int_result:
   3271     lw    $v0, 16($sp)                        # Move lower bits from JValue result to return value register.
   3272     // Fall-through to clean up and return.
   3273 .Lcleanup_and_return:
   3274     lw    $t7, THREAD_EXCEPTION_OFFSET(rSELF) # Load Thread::Current()->exception_
   3275     RESTORE_SAVE_REFS_AND_ARGS_FRAME
   3276     bnez  $t7, 1f                             # Success if no exception is pending.
   3277     nop
   3278     jalr  $zero, $ra
   3279     nop
   3280 1:
   3281     DELIVER_PENDING_EXCEPTION
   3282 END art_quick_invoke_polymorphic
   3283