Home | History | Annotate | Download | only in assembler
      1 /*
      2  * Copyright (C) 2009 Apple Inc. All rights reserved.
      3  * Copyright (C) 2009 University of Szeged
      4  * All rights reserved.
      5  * Copyright (C) 2010 MIPS Technologies, Inc. All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #ifndef MIPSAssembler_h
     30 #define MIPSAssembler_h
     31 
     32 #if ENABLE(ASSEMBLER) && CPU(MIPS)
     33 
     34 #include "AssemblerBuffer.h"
     35 #include <wtf/Assertions.h>
     36 #include <wtf/SegmentedVector.h>
     37 
     38 namespace JSC {
     39 
     40 typedef uint32_t MIPSWord;
     41 
     42 namespace MIPSRegisters {
     43 typedef enum {
     44     r0 = 0,
     45     r1,
     46     r2,
     47     r3,
     48     r4,
     49     r5,
     50     r6,
     51     r7,
     52     r8,
     53     r9,
     54     r10,
     55     r11,
     56     r12,
     57     r13,
     58     r14,
     59     r15,
     60     r16,
     61     r17,
     62     r18,
     63     r19,
     64     r20,
     65     r21,
     66     r22,
     67     r23,
     68     r24,
     69     r25,
     70     r26,
     71     r27,
     72     r28,
     73     r29,
     74     r30,
     75     r31,
     76     zero = r0,
     77     at = r1,
     78     v0 = r2,
     79     v1 = r3,
     80     a0 = r4,
     81     a1 = r5,
     82     a2 = r6,
     83     a3 = r7,
     84     t0 = r8,
     85     t1 = r9,
     86     t2 = r10,
     87     t3 = r11,
     88     t4 = r12,
     89     t5 = r13,
     90     t6 = r14,
     91     t7 = r15,
     92     s0 = r16,
     93     s1 = r17,
     94     s2 = r18,
     95     s3 = r19,
     96     s4 = r20,
     97     s5 = r21,
     98     s6 = r22,
     99     s7 = r23,
    100     t8 = r24,
    101     t9 = r25,
    102     k0 = r26,
    103     k1 = r27,
    104     gp = r28,
    105     sp = r29,
    106     fp = r30,
    107     ra = r31
    108 } RegisterID;
    109 
    110 typedef enum {
    111     f0,
    112     f1,
    113     f2,
    114     f3,
    115     f4,
    116     f5,
    117     f6,
    118     f7,
    119     f8,
    120     f9,
    121     f10,
    122     f11,
    123     f12,
    124     f13,
    125     f14,
    126     f15,
    127     f16,
    128     f17,
    129     f18,
    130     f19,
    131     f20,
    132     f21,
    133     f22,
    134     f23,
    135     f24,
    136     f25,
    137     f26,
    138     f27,
    139     f28,
    140     f29,
    141     f30,
    142     f31
    143 } FPRegisterID;
    144 
    145 } // namespace MIPSRegisters
    146 
    147 class MIPSAssembler {
    148 public:
    149     typedef MIPSRegisters::RegisterID RegisterID;
    150     typedef MIPSRegisters::FPRegisterID FPRegisterID;
    151     typedef SegmentedVector<int, 64> Jumps;
    152 
    153     MIPSAssembler()
    154     {
    155     }
    156 
    157     // MIPS instruction opcode field position
    158     enum {
    159         OP_SH_RD = 11,
    160         OP_SH_RT = 16,
    161         OP_SH_RS = 21,
    162         OP_SH_SHAMT = 6,
    163         OP_SH_CODE = 16,
    164         OP_SH_FD = 6,
    165         OP_SH_FS = 11,
    166         OP_SH_FT = 16
    167     };
    168 
    169     class JmpSrc {
    170         friend class MIPSAssembler;
    171     public:
    172         JmpSrc()
    173             : m_offset(-1)
    174         {
    175         }
    176 
    177     private:
    178         JmpSrc(int offset)
    179             : m_offset(offset)
    180         {
    181         }
    182 
    183         int m_offset;
    184     };
    185 
    186     class JmpDst {
    187         friend class MIPSAssembler;
    188     public:
    189         JmpDst()
    190             : m_offset(-1)
    191             , m_used(false)
    192         {
    193         }
    194 
    195         bool isUsed() const { return m_used; }
    196         bool isSet() const { return (m_offset != -1); }
    197         void used() { m_used = true; }
    198     private:
    199         JmpDst(int offset)
    200             : m_offset(offset)
    201             , m_used(false)
    202         {
    203             ASSERT(m_offset == offset);
    204         }
    205 
    206         int m_offset : 31;
    207         int m_used : 1;
    208     };
    209 
    210     void emitInst(MIPSWord op)
    211     {
    212         void* oldBase = m_buffer.data();
    213 
    214         m_buffer.putInt(op);
    215 
    216         void* newBase = m_buffer.data();
    217         if (oldBase != newBase)
    218             relocateJumps(oldBase, newBase);
    219     }
    220 
    221     void nop()
    222     {
    223         emitInst(0x00000000);
    224     }
    225 
    226     /* Need to insert one load data delay nop for mips1.  */
    227     void loadDelayNop()
    228     {
    229 #if WTF_MIPS_ISA(1)
    230         nop();
    231 #endif
    232     }
    233 
    234     /* Need to insert one coprocessor access delay nop for mips1.  */
    235     void copDelayNop()
    236     {
    237 #if WTF_MIPS_ISA(1)
    238         nop();
    239 #endif
    240     }
    241 
    242     void move(RegisterID rd, RegisterID rs)
    243     {
    244         /* addu */
    245         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
    246     }
    247 
    248     /* Set an immediate value to a register.  This may generate 1 or 2
    249        instructions.  */
    250     void li(RegisterID dest, int imm)
    251     {
    252         if (imm >= -32768 && imm <= 32767)
    253             addiu(dest, MIPSRegisters::zero, imm);
    254         else if (imm >= 0 && imm < 65536)
    255             ori(dest, MIPSRegisters::zero, imm);
    256         else {
    257             lui(dest, imm >> 16);
    258             if (imm & 0xffff)
    259                 ori(dest, dest, imm);
    260         }
    261     }
    262 
    263     void lui(RegisterID rt, int imm)
    264     {
    265         emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
    266     }
    267 
    268     void addiu(RegisterID rt, RegisterID rs, int imm)
    269     {
    270         emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    271                  | (imm & 0xffff));
    272     }
    273 
    274     void addu(RegisterID rd, RegisterID rs, RegisterID rt)
    275     {
    276         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    277                  | (rt << OP_SH_RT));
    278     }
    279 
    280     void subu(RegisterID rd, RegisterID rs, RegisterID rt)
    281     {
    282         emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    283                  | (rt << OP_SH_RT));
    284     }
    285 
    286     void mult(RegisterID rs, RegisterID rt)
    287     {
    288         emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
    289     }
    290 
    291     void div(RegisterID rs, RegisterID rt)
    292     {
    293         emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
    294     }
    295 
    296     void mfhi(RegisterID rd)
    297     {
    298         emitInst(0x00000010 | (rd << OP_SH_RD));
    299     }
    300 
    301     void mflo(RegisterID rd)
    302     {
    303         emitInst(0x00000012 | (rd << OP_SH_RD));
    304     }
    305 
    306     void mul(RegisterID rd, RegisterID rs, RegisterID rt)
    307     {
    308 #if WTF_MIPS_ISA_AT_LEAST(32)
    309         emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    310                  | (rt << OP_SH_RT));
    311 #else
    312         mult(rs, rt);
    313         mflo(rd);
    314 #endif
    315     }
    316 
    317     void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
    318     {
    319         emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    320                  | (rt << OP_SH_RT));
    321     }
    322 
    323     void andi(RegisterID rt, RegisterID rs, int imm)
    324     {
    325         emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    326                  | (imm & 0xffff));
    327     }
    328 
    329     void nor(RegisterID rd, RegisterID rs, RegisterID rt)
    330     {
    331         emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    332                  | (rt << OP_SH_RT));
    333     }
    334 
    335     void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
    336     {
    337         emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    338                  | (rt << OP_SH_RT));
    339     }
    340 
    341     void ori(RegisterID rt, RegisterID rs, int imm)
    342     {
    343         emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    344                  | (imm & 0xffff));
    345     }
    346 
    347     void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
    348     {
    349         emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    350                  | (rt << OP_SH_RT));
    351     }
    352 
    353     void xori(RegisterID rt, RegisterID rs, int imm)
    354     {
    355         emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    356                  | (imm & 0xffff));
    357     }
    358 
    359     void slt(RegisterID rd, RegisterID rs, RegisterID rt)
    360     {
    361         emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    362                  | (rt << OP_SH_RT));
    363     }
    364 
    365     void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
    366     {
    367         emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS)
    368                  | (rt << OP_SH_RT));
    369     }
    370 
    371     void sltiu(RegisterID rt, RegisterID rs, int imm)
    372     {
    373         emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    374                  | (imm & 0xffff));
    375     }
    376 
    377     void sll(RegisterID rd, RegisterID rt, int shamt)
    378     {
    379         emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
    380                  | ((shamt & 0x1f) << OP_SH_SHAMT));
    381     }
    382 
    383     void sllv(RegisterID rd, RegisterID rt, int rs)
    384     {
    385         emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
    386                  | (rs << OP_SH_RS));
    387     }
    388 
    389     void sra(RegisterID rd, RegisterID rt, int shamt)
    390     {
    391         emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
    392                  | ((shamt & 0x1f) << OP_SH_SHAMT));
    393     }
    394 
    395     void srav(RegisterID rd, RegisterID rt, RegisterID rs)
    396     {
    397         emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
    398                  | (rs << OP_SH_RS));
    399     }
    400 
    401     void srl(RegisterID rd, RegisterID rt, int shamt)
    402     {
    403         emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
    404                  | ((shamt & 0x1f) << OP_SH_SHAMT));
    405     }
    406 
    407     void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
    408     {
    409         emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
    410                  | (rs << OP_SH_RS));
    411     }
    412 
    413     void lbu(RegisterID rt, RegisterID rs, int offset)
    414     {
    415         emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    416                  | (offset & 0xffff));
    417         loadDelayNop();
    418     }
    419 
    420     void lw(RegisterID rt, RegisterID rs, int offset)
    421     {
    422         emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    423                  | (offset & 0xffff));
    424         loadDelayNop();
    425     }
    426 
    427     void lwl(RegisterID rt, RegisterID rs, int offset)
    428     {
    429         emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    430                  | (offset & 0xffff));
    431         loadDelayNop();
    432     }
    433 
    434     void lwr(RegisterID rt, RegisterID rs, int offset)
    435     {
    436         emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    437                  | (offset & 0xffff));
    438         loadDelayNop();
    439     }
    440 
    441     void lhu(RegisterID rt, RegisterID rs, int offset)
    442     {
    443         emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    444                  | (offset & 0xffff));
    445         loadDelayNop();
    446     }
    447 
    448     void sw(RegisterID rt, RegisterID rs, int offset)
    449     {
    450         emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
    451                  | (offset & 0xffff));
    452     }
    453 
    454     void jr(RegisterID rs)
    455     {
    456         emitInst(0x00000008 | (rs << OP_SH_RS));
    457     }
    458 
    459     void jalr(RegisterID rs)
    460     {
    461         emitInst(0x0000f809 | (rs << OP_SH_RS));
    462     }
    463 
    464     void jal()
    465     {
    466         emitInst(0x0c000000);
    467     }
    468 
    469     void bkpt()
    470     {
    471         int value = 512; /* BRK_BUG */
    472         emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
    473     }
    474 
    475     void bgez(RegisterID rs, int imm)
    476     {
    477         emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
    478     }
    479 
    480     void bltz(RegisterID rs, int imm)
    481     {
    482         emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
    483     }
    484 
    485     void beq(RegisterID rs, RegisterID rt, int imm)
    486     {
    487         emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
    488     }
    489 
    490     void bne(RegisterID rs, RegisterID rt, int imm)
    491     {
    492         emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
    493     }
    494 
    495     void bc1t()
    496     {
    497         emitInst(0x45010000);
    498     }
    499 
    500     void bc1f()
    501     {
    502         emitInst(0x45000000);
    503     }
    504 
    505     JmpSrc newJmpSrc()
    506     {
    507         return JmpSrc(m_buffer.size());
    508     }
    509 
    510     void appendJump()
    511     {
    512         m_jumps.append(m_buffer.size());
    513     }
    514 
    515     void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
    516     {
    517         emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
    518                  | (ft << OP_SH_FT));
    519     }
    520 
    521     void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
    522     {
    523         emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
    524                  | (ft << OP_SH_FT));
    525     }
    526 
    527     void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
    528     {
    529         emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
    530                  | (ft << OP_SH_FT));
    531     }
    532 
    533     void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
    534     {
    535         emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
    536                  | (ft << OP_SH_FT));
    537     }
    538 
    539     void lwc1(FPRegisterID ft, RegisterID rs, int offset)
    540     {
    541         emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
    542                  | (offset & 0xffff));
    543         copDelayNop();
    544     }
    545 
    546     void ldc1(FPRegisterID ft, RegisterID rs, int offset)
    547     {
    548         emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
    549                  | (offset & 0xffff));
    550     }
    551 
    552     void swc1(FPRegisterID ft, RegisterID rs, int offset)
    553     {
    554         emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
    555                  | (offset & 0xffff));
    556     }
    557 
    558     void sdc1(FPRegisterID ft, RegisterID rs, int offset)
    559     {
    560         emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
    561                  | (offset & 0xffff));
    562     }
    563 
    564     void mtc1(RegisterID rt, FPRegisterID fs)
    565     {
    566         emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
    567         copDelayNop();
    568     }
    569 
    570     void mthc1(RegisterID rt, FPRegisterID fs)
    571     {
    572         emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
    573         copDelayNop();
    574     }
    575 
    576     void mfc1(RegisterID rt, FPRegisterID fs)
    577     {
    578         emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
    579         copDelayNop();
    580     }
    581 
    582     void sqrtd(FPRegisterID fd, FPRegisterID fs)
    583     {
    584         emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
    585     }
    586 
    587     void truncwd(FPRegisterID fd, FPRegisterID fs)
    588     {
    589         emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
    590     }
    591 
    592     void cvtdw(FPRegisterID fd, FPRegisterID fs)
    593     {
    594         emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
    595     }
    596 
    597     void cvtwd(FPRegisterID fd, FPRegisterID fs)
    598     {
    599         emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
    600     }
    601 
    602     void ceqd(FPRegisterID fs, FPRegisterID ft)
    603     {
    604         emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    605         copDelayNop();
    606     }
    607 
    608     void cngtd(FPRegisterID fs, FPRegisterID ft)
    609     {
    610         emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    611         copDelayNop();
    612     }
    613 
    614     void cnged(FPRegisterID fs, FPRegisterID ft)
    615     {
    616         emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    617         copDelayNop();
    618     }
    619 
    620     void cltd(FPRegisterID fs, FPRegisterID ft)
    621     {
    622         emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    623         copDelayNop();
    624     }
    625 
    626     void cled(FPRegisterID fs, FPRegisterID ft)
    627     {
    628         emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    629         copDelayNop();
    630     }
    631 
    632     void cueqd(FPRegisterID fs, FPRegisterID ft)
    633     {
    634         emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    635         copDelayNop();
    636     }
    637 
    638     void coled(FPRegisterID fs, FPRegisterID ft)
    639     {
    640         emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    641         copDelayNop();
    642     }
    643 
    644     void coltd(FPRegisterID fs, FPRegisterID ft)
    645     {
    646         emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    647         copDelayNop();
    648     }
    649 
    650     void culed(FPRegisterID fs, FPRegisterID ft)
    651     {
    652         emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    653         copDelayNop();
    654     }
    655 
    656     void cultd(FPRegisterID fs, FPRegisterID ft)
    657     {
    658         emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
    659         copDelayNop();
    660     }
    661 
    662     // General helpers
    663 
    664     JmpDst label()
    665     {
    666         return JmpDst(m_buffer.size());
    667     }
    668 
    669     JmpDst align(int alignment)
    670     {
    671         while (!m_buffer.isAligned(alignment))
    672             bkpt();
    673 
    674         return label();
    675     }
    676 
    677     static void* getRelocatedAddress(void* code, JmpSrc jump)
    678     {
    679         ASSERT(jump.m_offset != -1);
    680         void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
    681         return b;
    682     }
    683 
    684     static void* getRelocatedAddress(void* code, JmpDst label)
    685     {
    686         void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
    687         return b;
    688     }
    689 
    690     static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
    691     {
    692         return to.m_offset - from.m_offset;
    693     }
    694 
    695     static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
    696     {
    697         return to.m_offset - from.m_offset;
    698     }
    699 
    700     static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
    701     {
    702         return to.m_offset - from.m_offset;
    703     }
    704 
    705     // Assembler admin methods:
    706 
    707     size_t size() const
    708     {
    709         return m_buffer.size();
    710     }
    711 
    712     void* executableCopy(ExecutablePool* allocator)
    713     {
    714         void *result = m_buffer.executableCopy(allocator);
    715         if (!result)
    716             return 0;
    717 
    718         relocateJumps(m_buffer.data(), result);
    719         return result;
    720     }
    721 
    722 #ifndef NDEBUG
    723     unsigned debugOffset() { return m_formatter.debugOffset(); }
    724 #endif
    725 
    726     static unsigned getCallReturnOffset(JmpSrc call)
    727     {
    728         // The return address is after a call and a delay slot instruction
    729         return call.m_offset;
    730     }
    731 
    732     // Linking & patching:
    733     //
    734     // 'link' and 'patch' methods are for use on unprotected code - such as the code
    735     // within the AssemblerBuffer, and code being patched by the patch buffer.  Once
    736     // code has been finalized it is (platform support permitting) within a non-
    737     // writable region of memory; to modify the code in an execute-only execuable
    738     // pool the 'repatch' and 'relink' methods should be used.
    739 
    740     void linkJump(JmpSrc from, JmpDst to)
    741     {
    742         ASSERT(to.m_offset != -1);
    743         ASSERT(from.m_offset != -1);
    744         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
    745         MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
    746 
    747         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
    748         insn = insn - 6;
    749         linkWithOffset(insn, toPos);
    750     }
    751 
    752     static void linkJump(void* code, JmpSrc from, void* to)
    753     {
    754         ASSERT(from.m_offset != -1);
    755         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
    756 
    757         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
    758         insn = insn - 6;
    759         linkWithOffset(insn, to);
    760     }
    761 
    762     static void linkCall(void* code, JmpSrc from, void* to)
    763     {
    764         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
    765         linkCallInternal(insn, to);
    766     }
    767 
    768     static void linkPointer(void* code, JmpDst from, void* to)
    769     {
    770         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
    771         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
    772         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
    773         insn++;
    774         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
    775         *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
    776     }
    777 
    778     static void relinkJump(void* from, void* to)
    779     {
    780         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
    781 
    782         ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
    783         insn = insn - 6;
    784         int flushSize = linkWithOffset(insn, to);
    785 
    786         ExecutableAllocator::cacheFlush(insn, flushSize);
    787     }
    788 
    789     static void relinkCall(void* from, void* to)
    790     {
    791         void* start;
    792         int size = linkCallInternal(from, to);
    793         if (size == sizeof(MIPSWord))
    794             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
    795         else
    796             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
    797 
    798         ExecutableAllocator::cacheFlush(start, size);
    799     }
    800 
    801     static void repatchInt32(void* from, int32_t to)
    802     {
    803         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
    804         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
    805         *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
    806         insn++;
    807         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
    808         *insn = (*insn & 0xffff0000) | (to & 0xffff);
    809         insn--;
    810         ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
    811     }
    812 
    813     static void repatchPointer(void* from, void* to)
    814     {
    815         repatchInt32(from, reinterpret_cast<int32_t>(to));
    816     }
    817 
    818 private:
    819     /* Update each jump in the buffer of newBase.  */
    820     void relocateJumps(void* oldBase, void* newBase)
    821     {
    822         // Check each jump
    823         for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
    824             int pos = *iter;
    825             MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
    826             insn = insn + 2;
    827             // Need to make sure we have 5 valid instructions after pos
    828             if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord))
    829                 continue;
    830 
    831             if ((*insn & 0xfc000000) == 0x08000000) { // j
    832                 int offset = *insn & 0x03ffffff;
    833                 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
    834                 int topFourBits = (oldInsnAddress + 4) >> 28;
    835                 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
    836                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
    837                 int newInsnAddress = (int)insn;
    838                 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
    839                     *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
    840                 else {
    841                     /* lui */
    842                     *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
    843                     /* ori */
    844                     *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
    845                     /* jr */
    846                     *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
    847                 }
    848             } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
    849                 int high = (*insn & 0xffff) << 16;
    850                 int low = *(insn + 1) & 0xffff;
    851                 int oldTargetAddress = high | low;
    852                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
    853                 /* lui */
    854                 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
    855                 /* ori */
    856                 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
    857             }
    858         }
    859     }
    860 
    861     static int linkWithOffset(MIPSWord* insn, void* to)
    862     {
    863         ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
    864                || (*insn & 0xfc000000) == 0x14000000 // bne
    865                || (*insn & 0xffff0000) == 0x45010000 // bc1t
    866                || (*insn & 0xffff0000) == 0x45000000); // bc1f
    867         intptr_t diff = (reinterpret_cast<intptr_t>(to)
    868                          - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
    869 
    870         if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
    871             /*
    872                 Convert the sequence:
    873                   beq $2, $3, target
    874                   nop
    875                   b 1f
    876                   nop
    877                   nop
    878                   nop
    879                 1:
    880 
    881                 to the new sequence if possible:
    882                   bne $2, $3, 1f
    883                   nop
    884                   j    target
    885                   nop
    886                   nop
    887                   nop
    888                 1:
    889 
    890                 OR to the new sequence:
    891                   bne $2, $3, 1f
    892                   nop
    893                   lui $25, target >> 16
    894                   ori $25, $25, target & 0xffff
    895                   jr $25
    896                   nop
    897                 1:
    898 
    899                 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
    900             */
    901 
    902             if (*(insn + 2) == 0x10000003) {
    903                 if ((*insn & 0xfc000000) == 0x10000000) // beq
    904                     *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
    905                 else if ((*insn & 0xfc000000) == 0x14000000) // bne
    906                     *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
    907                 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
    908                     *insn = 0x45000005; // bc1f
    909                 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
    910                     *insn = 0x45010005; // bc1t
    911                 else
    912                     ASSERT(0);
    913             }
    914 
    915             insn = insn + 2;
    916             if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
    917                 == reinterpret_cast<intptr_t>(to) >> 28) {
    918                 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
    919                 *(insn + 1) = 0;
    920                 return 4 * sizeof(MIPSWord);
    921             }
    922 
    923             intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
    924             /* lui */
    925             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
    926             /* ori */
    927             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
    928             /* jr */
    929             *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
    930             return 5 * sizeof(MIPSWord);
    931         }
    932 
    933         *insn = (*insn & 0xffff0000) | (diff & 0xffff);
    934         return sizeof(MIPSWord);
    935     }
    936 
    937     static int linkCallInternal(void* from, void* to)
    938     {
    939         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
    940         insn = insn - 4;
    941 
    942         if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
    943             if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
    944                 == reinterpret_cast<intptr_t>(to) >> 28) {
    945                 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
    946                 return sizeof(MIPSWord);
    947             }
    948 
    949             /* lui $25, (to >> 16) & 0xffff */
    950             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
    951             /* ori $25, $25, to & 0xffff */
    952             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
    953             /* jalr $25 */
    954             *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
    955             return 3 * sizeof(MIPSWord);
    956         }
    957 
    958         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
    959         ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
    960 
    961         /* lui */
    962         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
    963         /* ori */
    964         *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
    965         return 2 * sizeof(MIPSWord);
    966     }
    967 
    968     AssemblerBuffer m_buffer;
    969     Jumps m_jumps;
    970 };
    971 
    972 } // namespace JSC
    973 
    974 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
    975 
    976 #endif // MIPSAssembler_h
    977