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
38namespace JSC {
39
40typedef uint32_t MIPSWord;
41
42namespace MIPSRegisters {
43typedef 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
110typedef 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
147class MIPSAssembler {
148public:
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
818private:
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