Home | History | Annotate | Download | only in mips
      1 /*
      2  * Copyright (C) 2016 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 /*
     18   Art assembly interpreter notes:
     19 
     20   First validate assembly code by implementing ExecuteXXXImpl() style body (doesn't
     21   handle invoke, allows higher-level code to create frame & shadow frame.
     22 
     23   Once that's working, support direct entry code & eliminate shadow frame (and
     24   excess locals allocation.
     25 
     26   Some (hopefully) temporary ugliness.  We'll treat rFP as pointing to the
     27   base of the vreg array within the shadow frame.  Access the other fields,
     28   dex_pc_, method_ and number_of_vregs_ via negative offsets.  For now, we'll continue
     29   the shadow frame mechanism of double-storing object references - via rFP &
     30   number_of_vregs_.
     31 
     32  */
     33 
     34 #include "asm_support.h"
     35 
     36 #if (__mips==32) && (__mips_isa_rev>=2)
     37 #define MIPS32REVGE2    /* mips32r2 and greater */
     38 #if (__mips==32) && (__mips_isa_rev>=5)
     39 #define FPU64           /* 64 bit FPU */
     40 #if (__mips==32) && (__mips_isa_rev>=6)
     41 #define MIPS32REVGE6    /* mips32r6 and greater */
     42 #endif
     43 #endif
     44 #endif
     45 
     46 /* MIPS definitions and declarations
     47 
     48    reg  nick      purpose
     49    s0   rPC       interpreted program counter, used for fetching instructions
     50    s1   rFP       interpreted frame pointer, used for accessing locals and args
     51    s2   rSELF     self (Thread) pointer
     52    s3   rIBASE    interpreted instruction base pointer, used for computed goto
     53    s4   rINST     first 16-bit code unit of current instruction
     54    s6   rREFS     base of object references in shadow frame (ideally, we'll get rid of this later).
     55 */
     56 
     57 /* single-purpose registers, given names for clarity */
     58 #define rPC s0
     59 #define rFP s1
     60 #define rSELF s2
     61 #define rIBASE s3
     62 #define rINST s4
     63 #define rOBJ s5
     64 #define rREFS s6
     65 #define rTEMP s7
     66 
     67 #define rARG0 a0
     68 #define rARG1 a1
     69 #define rARG2 a2
     70 #define rARG3 a3
     71 #define rRESULT0 v0
     72 #define rRESULT1 v1
     73 
     74 /* GP register definitions */
     75 #define zero    $$0      /* always zero */
     76 #define AT      $$at     /* assembler temp */
     77 #define v0      $$2      /* return value */
     78 #define v1      $$3
     79 #define a0      $$4      /* argument registers */
     80 #define a1      $$5
     81 #define a2      $$6
     82 #define a3      $$7
     83 #define t0      $$8      /* temp registers (not saved across subroutine calls) */
     84 #define t1      $$9
     85 #define t2      $$10
     86 #define t3      $$11
     87 #define t4      $$12
     88 #define t5      $$13
     89 #define t6      $$14
     90 #define t7      $$15
     91 #define ta0     $$12     /* alias */
     92 #define ta1     $$13
     93 #define ta2     $$14
     94 #define ta3     $$15
     95 #define s0      $$16     /* saved across subroutine calls (callee saved) */
     96 #define s1      $$17
     97 #define s2      $$18
     98 #define s3      $$19
     99 #define s4      $$20
    100 #define s5      $$21
    101 #define s6      $$22
    102 #define s7      $$23
    103 #define t8      $$24     /* two more temp registers */
    104 #define t9      $$25
    105 #define k0      $$26     /* kernel temporary */
    106 #define k1      $$27
    107 #define gp      $$28     /* global pointer */
    108 #define sp      $$29     /* stack pointer */
    109 #define s8      $$30     /* one more callee saved */
    110 #define ra      $$31     /* return address */
    111 
    112 /* FP register definitions */
    113 #define fv0    $$f0
    114 #define fv0f   $$f1
    115 #define fv1    $$f2
    116 #define fv1f   $$f3
    117 #define fa0    $$f12
    118 #define fa0f   $$f13
    119 #define fa1    $$f14
    120 #define fa1f   $$f15
    121 #define ft0    $$f4
    122 #define ft0f   $$f5
    123 #define ft1    $$f6
    124 #define ft1f   $$f7
    125 #define ft2    $$f8
    126 #define ft2f   $$f9
    127 #define ft3    $$f10
    128 #define ft3f   $$f11
    129 #define ft4    $$f16
    130 #define ft4f   $$f17
    131 #define ft5    $$f18
    132 #define ft5f   $$f19
    133 #define fs0    $$f20
    134 #define fs0f   $$f21
    135 #define fs1    $$f22
    136 #define fs1f   $$f23
    137 #define fs2    $$f24
    138 #define fs2f   $$f25
    139 #define fs3    $$f26
    140 #define fs3f   $$f27
    141 #define fs4    $$f28
    142 #define fs4f   $$f29
    143 #define fs5    $$f30
    144 #define fs5f   $$f31
    145 
    146 #ifndef MIPS32REVGE6
    147 #define fcc0   $$fcc0
    148 #define fcc1   $$fcc1
    149 #endif
    150 
    151 /*
    152  * Instead of holding a pointer to the shadow frame, we keep rFP at the base of the vregs.  So,
    153  * to access other shadow frame fields, we need to use a backwards offset.  Define those here.
    154  */
    155 #define OFF_FP(a) (a - SHADOWFRAME_VREGS_OFFSET)
    156 #define OFF_FP_NUMBER_OF_VREGS OFF_FP(SHADOWFRAME_NUMBER_OF_VREGS_OFFSET)
    157 #define OFF_FP_DEX_PC OFF_FP(SHADOWFRAME_DEX_PC_OFFSET)
    158 #define OFF_FP_LINK OFF_FP(SHADOWFRAME_LINK_OFFSET)
    159 #define OFF_FP_METHOD OFF_FP(SHADOWFRAME_METHOD_OFFSET)
    160 #define OFF_FP_RESULT_REGISTER OFF_FP(SHADOWFRAME_RESULT_REGISTER_OFFSET)
    161 #define OFF_FP_DEX_PC_PTR OFF_FP(SHADOWFRAME_DEX_PC_PTR_OFFSET)
    162 #define OFF_FP_CODE_ITEM OFF_FP(SHADOWFRAME_CODE_ITEM_OFFSET)
    163 #define OFF_FP_SHADOWFRAME (-SHADOWFRAME_VREGS_OFFSET)
    164 
    165 #define MTERP_PROFILE_BRANCHES 1
    166 #define MTERP_LOGGING 0
    167 
    168 /*
    169  * "export" the PC to dex_pc field in the shadow frame, f/b/o future exception objects.  Must
    170  * be done *before* something throws.
    171  *
    172  * It's okay to do this more than once.
    173  *
    174  * NOTE: the fast interpreter keeps track of dex pc as a direct pointer to the mapped
    175  * dex byte codes.  However, the rest of the runtime expects dex pc to be an instruction
    176  * offset into the code_items_[] array.  For effiency, we will "export" the
    177  * current dex pc as a direct pointer using the EXPORT_PC macro, and rely on GetDexPC
    178  * to convert to a dex pc when needed.
    179  */
    180 #define EXPORT_PC() \
    181     sw        rPC, OFF_FP_DEX_PC_PTR(rFP)
    182 
    183 #define EXPORT_DEX_PC(tmp) \
    184     lw   tmp, OFF_FP_CODE_ITEM(rFP) \
    185     sw   rPC, OFF_FP_DEX_PC_PTR(rFP) \
    186     addu tmp, CODEITEM_INSNS_OFFSET \
    187     subu tmp, rPC, tmp \
    188     sra  tmp, tmp, 1 \
    189     sw   tmp, OFF_FP_DEX_PC(rFP)
    190 
    191 /*
    192  * Fetch the next instruction from rPC into rINST.  Does not advance rPC.
    193  */
    194 #define FETCH_INST() lhu rINST, (rPC)
    195 
    196 /*
    197  * Fetch the next instruction from the specified offset.  Advances rPC
    198  * to point to the next instruction.  "_count" is in 16-bit code units.
    199  *
    200  * This must come AFTER anything that can throw an exception, or the
    201  * exception catch may miss.  (This also implies that it must come after
    202  * EXPORT_PC().)
    203  */
    204 #define FETCH_ADVANCE_INST(_count) lhu rINST, ((_count)*2)(rPC); \
    205     addu      rPC, rPC, ((_count) * 2)
    206 
    207 /*
    208  * The operation performed here is similar to FETCH_ADVANCE_INST, except the
    209  * src and dest registers are parameterized (not hard-wired to rPC and rINST).
    210  */
    211 #define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
    212     lhu       _dreg, ((_count)*2)(_sreg) ;            \
    213     addu      _sreg, _sreg, (_count)*2
    214 
    215 /*
    216  * Similar to FETCH_ADVANCE_INST, but does not update rPC.  Used to load
    217  * rINST ahead of possible exception point.  Be sure to manually advance rPC
    218  * later.
    219  */
    220 #define PREFETCH_INST(_count) lhu rINST, ((_count)*2)(rPC)
    221 
    222 /* Advance rPC by some number of code units. */
    223 #define ADVANCE(_count) addu rPC, rPC, ((_count) * 2)
    224 
    225 /*
    226  * Fetch the next instruction from an offset specified by rd.  Updates
    227  * rPC to point to the next instruction.  "rd" must specify the distance
    228  * in bytes, *not* 16-bit code units, and may be a signed value.
    229  */
    230 #define FETCH_ADVANCE_INST_RB(rd) addu rPC, rPC, rd; \
    231     lhu       rINST, (rPC)
    232 
    233 /*
    234  * Fetch a half-word code unit from an offset past the current PC.  The
    235  * "_count" value is in 16-bit code units.  Does not advance rPC.
    236  *
    237  * The "_S" variant works the same but treats the value as signed.
    238  */
    239 #define FETCH(rd, _count) lhu rd, ((_count) * 2)(rPC)
    240 #define FETCH_S(rd, _count) lh rd, ((_count) * 2)(rPC)
    241 
    242 /*
    243  * Fetch one byte from an offset past the current PC.  Pass in the same
    244  * "_count" as you would for FETCH, and an additional 0/1 indicating which
    245  * byte of the halfword you want (lo/hi).
    246  */
    247 #define FETCH_B(rd, _count, _byte) lbu rd, ((_count) * 2 + _byte)(rPC)
    248 
    249 /*
    250  * Put the instruction's opcode field into the specified register.
    251  */
    252 #define GET_INST_OPCODE(rd) and rd, rINST, 0xFF
    253 
    254 /*
    255  * Put the prefetched instruction's opcode field into the specified register.
    256  */
    257 #define GET_PREFETCHED_OPCODE(dreg, sreg)   andi     dreg, sreg, 255
    258 
    259 /*
    260  * Begin executing the opcode in rd.
    261  */
    262 #define GOTO_OPCODE(rd) sll rd, rd, ${handler_size_bits}; \
    263     addu      rd, rIBASE, rd; \
    264     jalr      zero, rd
    265 
    266 #define GOTO_OPCODE_BASE(_base, rd)  sll rd, rd, ${handler_size_bits}; \
    267     addu      rd, _base, rd; \
    268     jalr      zero, rd
    269 
    270 /*
    271  * Get/set the 32-bit value from a Dalvik register.
    272  */
    273 #define GET_VREG(rd, rix) LOAD_eas2(rd, rFP, rix)
    274 
    275 #define GET_VREG_F(rd, rix) EAS2(AT, rFP, rix); \
    276     .set noat; l.s rd, (AT); .set at
    277 
    278 #define SET_VREG(rd, rix) .set noat; \
    279     sll       AT, rix, 2; \
    280     addu      t8, rFP, AT; \
    281     sw        rd, 0(t8); \
    282     addu      t8, rREFS, AT; \
    283     .set at; \
    284     sw        zero, 0(t8)
    285 
    286 #define SET_VREG64(rlo, rhi, rix) .set noat; \
    287     sll       AT, rix, 2; \
    288     addu      t8, rFP, AT; \
    289     sw        rlo, 0(t8); \
    290     sw        rhi, 4(t8); \
    291     addu      t8, rREFS, AT; \
    292     .set at; \
    293     sw        zero, 0(t8); \
    294     sw        zero, 4(t8)
    295 
    296 #ifdef FPU64
    297 #define SET_VREG64_F(rlo, rhi, rix) .set noat; \
    298     sll       AT, rix, 2; \
    299     addu      t8, rREFS, AT; \
    300     sw        zero, 0(t8); \
    301     sw        zero, 4(t8); \
    302     addu      t8, rFP, AT; \
    303     mfhc1     AT, rlo; \
    304     sw        AT, 4(t8); \
    305     .set at; \
    306     s.s       rlo, 0(t8)
    307 #else
    308 #define SET_VREG64_F(rlo, rhi, rix) .set noat; \
    309     sll       AT, rix, 2; \
    310     addu      t8, rFP, AT; \
    311     s.s       rlo, 0(t8); \
    312     s.s       rhi, 4(t8); \
    313     addu      t8, rREFS, AT; \
    314     .set at; \
    315     sw        zero, 0(t8); \
    316     sw        zero, 4(t8)
    317 #endif
    318 
    319 #define SET_VREG_OBJECT(rd, rix) .set noat; \
    320     sll       AT, rix, 2; \
    321     addu      t8, rFP, AT; \
    322     sw        rd, 0(t8); \
    323     addu      t8, rREFS, AT; \
    324     .set at; \
    325     sw        rd, 0(t8)
    326 
    327 /* Combination of the SET_VREG and GOTO_OPCODE functions to save 1 instruction */
    328 #define SET_VREG_GOTO(rd, rix, dst) .set noreorder; \
    329     sll       dst, dst, ${handler_size_bits}; \
    330     addu      dst, rIBASE, dst; \
    331     .set noat; \
    332     sll       AT, rix, 2; \
    333     addu      t8, rFP, AT; \
    334     sw        rd, 0(t8); \
    335     addu      t8, rREFS, AT; \
    336     .set at; \
    337     jalr      zero, dst; \
    338     sw        zero, 0(t8); \
    339     .set reorder
    340 
    341 /* Combination of the SET_VREG64 and GOTO_OPCODE functions to save 1 instruction */
    342 #define SET_VREG64_GOTO(rlo, rhi, rix, dst) .set noreorder; \
    343     sll       dst, dst, ${handler_size_bits}; \
    344     addu      dst, rIBASE, dst; \
    345     .set noat; \
    346     sll       AT, rix, 2; \
    347     addu      t8, rFP, AT; \
    348     sw        rlo, 0(t8); \
    349     sw        rhi, 4(t8); \
    350     addu      t8, rREFS, AT; \
    351     .set at; \
    352     sw        zero, 0(t8); \
    353     jalr      zero, dst; \
    354     sw        zero, 4(t8); \
    355     .set reorder
    356 
    357 #define SET_VREG_F(rd, rix) .set noat; \
    358     sll       AT, rix, 2; \
    359     addu      t8, rFP, AT; \
    360     s.s       rd, 0(t8); \
    361     addu      t8, rREFS, AT; \
    362     .set at; \
    363     sw        zero, 0(t8)
    364 
    365 #define GET_OPA(rd) srl rd, rINST, 8
    366 #ifdef MIPS32REVGE2
    367 #define GET_OPA4(rd) ext rd, rINST, 8, 4
    368 #else
    369 #define GET_OPA4(rd) GET_OPA(rd); and rd, 0xf
    370 #endif
    371 #define GET_OPB(rd) srl rd, rINST, 12
    372 
    373 /*
    374  * Form an Effective Address rd = rbase + roff<<n;
    375  * Uses reg AT
    376  */
    377 #define EASN(rd, rbase, roff, rshift) .set noat; \
    378     sll       AT, roff, rshift; \
    379     addu      rd, rbase, AT; \
    380     .set at
    381 
    382 #define EAS1(rd, rbase, roff) EASN(rd, rbase, roff, 1)
    383 #define EAS2(rd, rbase, roff) EASN(rd, rbase, roff, 2)
    384 #define EAS3(rd, rbase, roff) EASN(rd, rbase, roff, 3)
    385 #define EAS4(rd, rbase, roff) EASN(rd, rbase, roff, 4)
    386 
    387 /*
    388  * Form an Effective Shift Right rd = rbase + roff>>n;
    389  * Uses reg AT
    390  */
    391 #define ESRN(rd, rbase, roff, rshift) .set noat; \
    392     srl       AT, roff, rshift; \
    393     addu      rd, rbase, AT; \
    394     .set at
    395 
    396 #define LOAD_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
    397     .set noat; lw rd, 0(AT); .set at
    398 
    399 #define STORE_eas2(rd, rbase, roff) EAS2(AT, rbase, roff); \
    400     .set noat; sw rd, 0(AT); .set at
    401 
    402 #define LOAD_RB_OFF(rd, rbase, off) lw rd, off(rbase)
    403 #define STORE_RB_OFF(rd, rbase, off) sw rd, off(rbase)
    404 
    405 #define STORE64_off(rlo, rhi, rbase, off) sw rlo, off(rbase); \
    406     sw        rhi, (off+4)(rbase)
    407 #define LOAD64_off(rlo, rhi, rbase, off) lw rlo, off(rbase); \
    408     lw        rhi, (off+4)(rbase)
    409 
    410 #define STORE64(rlo, rhi, rbase) STORE64_off(rlo, rhi, rbase, 0)
    411 #define LOAD64(rlo, rhi, rbase) LOAD64_off(rlo, rhi, rbase, 0)
    412 
    413 #ifdef FPU64
    414 #define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, off(rbase); \
    415     .set noat; \
    416     mfhc1     AT, rlo; \
    417     sw        AT, (off+4)(rbase); \
    418     .set at
    419 #define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, off(rbase); \
    420     .set noat; \
    421     lw        AT, (off+4)(rbase); \
    422     mthc1     AT, rlo; \
    423     .set at
    424 #else
    425 #define STORE64_off_F(rlo, rhi, rbase, off) s.s rlo, off(rbase); \
    426     s.s       rhi, (off+4)(rbase)
    427 #define LOAD64_off_F(rlo, rhi, rbase, off) l.s rlo, off(rbase); \
    428     l.s       rhi, (off+4)(rbase)
    429 #endif
    430 
    431 #define STORE64_F(rlo, rhi, rbase) STORE64_off_F(rlo, rhi, rbase, 0)
    432 #define LOAD64_F(rlo, rhi, rbase) LOAD64_off_F(rlo, rhi, rbase, 0)
    433 
    434 
    435 #define LOAD_base_offMirrorArray_length(rd, rbase) LOAD_RB_OFF(rd, rbase, MIRROR_ARRAY_LENGTH_OFFSET)
    436 
    437 #define STACK_STORE(rd, off) sw rd, off(sp)
    438 #define STACK_LOAD(rd, off) lw rd, off(sp)
    439 #define CREATE_STACK(n) subu sp, sp, n
    440 #define DELETE_STACK(n) addu sp, sp, n
    441 
    442 #define LOAD_ADDR(dest, addr) la dest, addr
    443 #define LOAD_IMM(dest, imm) li dest, imm
    444 #define MOVE_REG(dest, src) move dest, src
    445 #define STACK_SIZE 128
    446 
    447 #define STACK_OFFSET_ARG04 16
    448 #define STACK_OFFSET_ARG05 20
    449 #define STACK_OFFSET_ARG06 24
    450 #define STACK_OFFSET_ARG07 28
    451 #define STACK_OFFSET_GP    84
    452 
    453 #define JAL(n) jal n
    454 #define BAL(n) bal n
    455 
    456 /*
    457  * FP register usage restrictions:
    458  * 1) We don't use the callee save FP registers so we don't have to save them.
    459  * 2) We don't use the odd FP registers so we can share code with mips32r6.
    460  */
    461 #define STACK_STORE_FULL() CREATE_STACK(STACK_SIZE); \
    462     STACK_STORE(ra, 124); \
    463     STACK_STORE(s8, 120); \
    464     STACK_STORE(s0, 116); \
    465     STACK_STORE(s1, 112); \
    466     STACK_STORE(s2, 108); \
    467     STACK_STORE(s3, 104); \
    468     STACK_STORE(s4, 100); \
    469     STACK_STORE(s5, 96); \
    470     STACK_STORE(s6, 92); \
    471     STACK_STORE(s7, 88);
    472 
    473 #define STACK_LOAD_FULL() STACK_LOAD(gp, STACK_OFFSET_GP); \
    474     STACK_LOAD(s7, 88); \
    475     STACK_LOAD(s6, 92); \
    476     STACK_LOAD(s5, 96); \
    477     STACK_LOAD(s4, 100); \
    478     STACK_LOAD(s3, 104); \
    479     STACK_LOAD(s2, 108); \
    480     STACK_LOAD(s1, 112); \
    481     STACK_LOAD(s0, 116); \
    482     STACK_LOAD(s8, 120); \
    483     STACK_LOAD(ra, 124); \
    484     DELETE_STACK(STACK_SIZE)
    485