initial import
[vuplus_webkit] / Source / JavaScriptCore / assembler / MIPSAssembler.h
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<AssemblerLabel, 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     void emitInst(MIPSWord op)
170     {
171         void* oldBase = m_buffer.data();
172
173         m_buffer.putInt(op);
174
175         void* newBase = m_buffer.data();
176         if (oldBase != newBase)
177             relocateJumps(oldBase, newBase);
178     }
179
180     void nop()
181     {
182         emitInst(0x00000000);
183     }
184
185     /* Need to insert one load data delay nop for mips1.  */
186     void loadDelayNop()
187     {
188 #if WTF_MIPS_ISA(1)
189         nop();
190 #endif
191     }
192
193     /* Need to insert one coprocessor access delay nop for mips1.  */
194     void copDelayNop()
195     {
196 #if WTF_MIPS_ISA(1)
197         nop();
198 #endif
199     }
200
201     void move(RegisterID rd, RegisterID rs)
202     {
203         /* addu */
204         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS));
205     }
206
207     /* Set an immediate value to a register.  This may generate 1 or 2
208        instructions.  */
209     void li(RegisterID dest, int imm)
210     {
211         if (imm >= -32768 && imm <= 32767)
212             addiu(dest, MIPSRegisters::zero, imm);
213         else if (imm >= 0 && imm < 65536)
214             ori(dest, MIPSRegisters::zero, imm);
215         else {
216             lui(dest, imm >> 16);
217             if (imm & 0xffff)
218                 ori(dest, dest, imm);
219         }
220     }
221
222     void lui(RegisterID rt, int imm)
223     {
224         emitInst(0x3c000000 | (rt << OP_SH_RT) | (imm & 0xffff));
225     }
226
227     void addiu(RegisterID rt, RegisterID rs, int imm)
228     {
229         emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
230                  | (imm & 0xffff));
231     }
232
233     void addu(RegisterID rd, RegisterID rs, RegisterID rt)
234     {
235         emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
236                  | (rt << OP_SH_RT));
237     }
238
239     void subu(RegisterID rd, RegisterID rs, RegisterID rt)
240     {
241         emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
242                  | (rt << OP_SH_RT));
243     }
244
245     void mult(RegisterID rs, RegisterID rt)
246     {
247         emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
248     }
249
250     void div(RegisterID rs, RegisterID rt)
251     {
252         emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
253     }
254
255     void mfhi(RegisterID rd)
256     {
257         emitInst(0x00000010 | (rd << OP_SH_RD));
258     }
259
260     void mflo(RegisterID rd)
261     {
262         emitInst(0x00000012 | (rd << OP_SH_RD));
263     }
264
265     void mul(RegisterID rd, RegisterID rs, RegisterID rt)
266     {
267 #if WTF_MIPS_ISA_AT_LEAST(32) 
268         emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
269                  | (rt << OP_SH_RT));
270 #else
271         mult(rs, rt);
272         mflo(rd);
273 #endif
274     }
275
276     void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
277     {
278         emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
279                  | (rt << OP_SH_RT));
280     }
281
282     void andi(RegisterID rt, RegisterID rs, int imm)
283     {
284         emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
285                  | (imm & 0xffff));
286     }
287
288     void nor(RegisterID rd, RegisterID rs, RegisterID rt)
289     {
290         emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
291                  | (rt << OP_SH_RT));
292     }
293
294     void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
295     {
296         emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
297                  | (rt << OP_SH_RT));
298     }
299
300     void ori(RegisterID rt, RegisterID rs, int imm)
301     {
302         emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
303                  | (imm & 0xffff));
304     }
305
306     void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
307     {
308         emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
309                  | (rt << OP_SH_RT));
310     }
311
312     void xori(RegisterID rt, RegisterID rs, int imm)
313     {
314         emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
315                  | (imm & 0xffff));
316     }
317
318     void slt(RegisterID rd, RegisterID rs, RegisterID rt)
319     {
320         emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS)
321                  | (rt << OP_SH_RT));
322     }
323
324     void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
325     {
326         emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS)
327                  | (rt << OP_SH_RT));
328     }
329
330     void sltiu(RegisterID rt, RegisterID rs, int imm)
331     {
332         emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
333                  | (imm & 0xffff));
334     }
335
336     void sll(RegisterID rd, RegisterID rt, int shamt)
337     {
338         emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
339                  | ((shamt & 0x1f) << OP_SH_SHAMT));
340     }
341
342     void sllv(RegisterID rd, RegisterID rt, int rs)
343     {
344         emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
345                  | (rs << OP_SH_RS));
346     }
347
348     void sra(RegisterID rd, RegisterID rt, int shamt)
349     {
350         emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
351                  | ((shamt & 0x1f) << OP_SH_SHAMT));
352     }
353
354     void srav(RegisterID rd, RegisterID rt, RegisterID rs)
355     {
356         emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
357                  | (rs << OP_SH_RS));
358     }
359
360     void srl(RegisterID rd, RegisterID rt, int shamt)
361     {
362         emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
363                  | ((shamt & 0x1f) << OP_SH_SHAMT));
364     }
365
366     void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
367     {
368         emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
369                  | (rs << OP_SH_RS));
370     }
371
372     void lbu(RegisterID rt, RegisterID rs, int offset)
373     {
374         emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
375                  | (offset & 0xffff));
376         loadDelayNop();
377     }
378
379     void lw(RegisterID rt, RegisterID rs, int offset)
380     {
381         emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
382                  | (offset & 0xffff));
383         loadDelayNop();
384     }
385
386     void lwl(RegisterID rt, RegisterID rs, int offset)
387     {
388         emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
389                  | (offset & 0xffff));
390         loadDelayNop();
391     }
392
393     void lwr(RegisterID rt, RegisterID rs, int offset)
394     {
395         emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
396                  | (offset & 0xffff));
397         loadDelayNop();
398     }
399
400     void lhu(RegisterID rt, RegisterID rs, int offset)
401     {
402         emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
403                  | (offset & 0xffff));
404         loadDelayNop();
405     }
406
407     void sw(RegisterID rt, RegisterID rs, int offset)
408     {
409         emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
410                  | (offset & 0xffff));
411     }
412
413     void jr(RegisterID rs)
414     {
415         emitInst(0x00000008 | (rs << OP_SH_RS));
416     }
417
418     void jalr(RegisterID rs)
419     {
420         emitInst(0x0000f809 | (rs << OP_SH_RS));
421     }
422
423     void jal()
424     {
425         emitInst(0x0c000000);
426     }
427
428     void bkpt()
429     {
430         int value = 512; /* BRK_BUG */
431         emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
432     }
433
434     void bgez(RegisterID rs, int imm)
435     {
436         emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
437     }
438
439     void bltz(RegisterID rs, int imm)
440     {
441         emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
442     }
443
444     void beq(RegisterID rs, RegisterID rt, int imm)
445     {
446         emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
447     }
448
449     void bne(RegisterID rs, RegisterID rt, int imm)
450     {
451         emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
452     }
453
454     void bc1t()
455     {
456         emitInst(0x45010000);
457     }
458
459     void bc1f()
460     {
461         emitInst(0x45000000);
462     }
463
464     void appendJump()
465     {
466         m_jumps.append(m_buffer.label());
467     }
468
469     void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
470     {
471         emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
472                  | (ft << OP_SH_FT));
473     }
474
475     void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
476     {
477         emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
478                  | (ft << OP_SH_FT));
479     }
480
481     void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
482     {
483         emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
484                  | (ft << OP_SH_FT));
485     }
486
487     void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
488     {
489         emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
490                  | (ft << OP_SH_FT));
491     }
492
493     void lwc1(FPRegisterID ft, RegisterID rs, int offset)
494     {
495         emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
496                  | (offset & 0xffff));
497         copDelayNop();
498     }
499
500     void ldc1(FPRegisterID ft, RegisterID rs, int offset)
501     {
502         emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
503                  | (offset & 0xffff));
504     }
505
506     void swc1(FPRegisterID ft, RegisterID rs, int offset)
507     {
508         emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
509                  | (offset & 0xffff));
510     }
511
512     void sdc1(FPRegisterID ft, RegisterID rs, int offset)
513     {
514         emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
515                  | (offset & 0xffff));
516     }
517
518     void mtc1(RegisterID rt, FPRegisterID fs)
519     {
520         emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
521         copDelayNop();
522     }
523
524     void mthc1(RegisterID rt, FPRegisterID fs)
525     {
526         emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
527         copDelayNop();
528     }
529
530     void mfc1(RegisterID rt, FPRegisterID fs)
531     {
532         emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
533         copDelayNop();
534     }
535
536     void sqrtd(FPRegisterID fd, FPRegisterID fs)
537     {
538         emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
539     }
540
541     void truncwd(FPRegisterID fd, FPRegisterID fs)
542     {
543         emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
544     }
545
546     void cvtdw(FPRegisterID fd, FPRegisterID fs)
547     {
548         emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
549     }
550
551     void cvtwd(FPRegisterID fd, FPRegisterID fs)
552     {
553         emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
554     }
555
556     void ceqd(FPRegisterID fs, FPRegisterID ft)
557     {
558         emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
559         copDelayNop();
560     }
561
562     void cngtd(FPRegisterID fs, FPRegisterID ft)
563     {
564         emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
565         copDelayNop();
566     }
567
568     void cnged(FPRegisterID fs, FPRegisterID ft)
569     {
570         emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
571         copDelayNop();
572     }
573
574     void cltd(FPRegisterID fs, FPRegisterID ft)
575     {
576         emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
577         copDelayNop();
578     }
579
580     void cled(FPRegisterID fs, FPRegisterID ft)
581     {
582         emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
583         copDelayNop();
584     }
585
586     void cueqd(FPRegisterID fs, FPRegisterID ft)
587     {
588         emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
589         copDelayNop();
590     }
591
592     void coled(FPRegisterID fs, FPRegisterID ft)
593     {
594         emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
595         copDelayNop();
596     }
597
598     void coltd(FPRegisterID fs, FPRegisterID ft)
599     {
600         emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
601         copDelayNop();
602     }
603
604     void culed(FPRegisterID fs, FPRegisterID ft)
605     {
606         emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
607         copDelayNop();
608     }
609
610     void cultd(FPRegisterID fs, FPRegisterID ft)
611     {
612         emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
613         copDelayNop();
614     }
615
616     // General helpers
617
618     AssemblerLabel label()
619     {
620         return m_buffer.label();
621     }
622
623     AssemblerLabel align(int alignment)
624     {
625         while (!m_buffer.isAligned(alignment))
626             bkpt();
627
628         return label();
629     }
630
631     static void* getRelocatedAddress(void* code, AssemblerLabel label)
632     {
633         return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
634     }
635
636     static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
637     {
638         return b.m_offset - a.m_offset;
639     }
640
641     // Assembler admin methods:
642
643     size_t codeSize() const
644     {
645         return m_buffer.codeSize();
646     }
647
648     PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData)
649     {
650         RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData);
651         if (!result)
652             return 0;
653
654         relocateJumps(m_buffer.data(), result->start());
655         return result.release();
656     }
657
658 #ifndef NDEBUG
659     unsigned debugOffset() { return m_buffer.debugOffset(); }
660 #endif
661
662     static unsigned getCallReturnOffset(AssemblerLabel call)
663     {
664         // The return address is after a call and a delay slot instruction
665         return call.m_offset;
666     }
667
668     // Linking & patching:
669     //
670     // 'link' and 'patch' methods are for use on unprotected code - such as the code
671     // within the AssemblerBuffer, and code being patched by the patch buffer.  Once
672     // code has been finalized it is (platform support permitting) within a non-
673     // writable region of memory; to modify the code in an execute-only execuable
674     // pool the 'repatch' and 'relink' methods should be used.
675
676     void linkJump(AssemblerLabel from, AssemblerLabel to)
677     {
678         ASSERT(to.isSet());
679         ASSERT(from.isSet());
680         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
681         MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
682
683         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
684         insn = insn - 6;
685         linkWithOffset(insn, toPos);
686     }
687
688     static void linkJump(void* code, AssemblerLabel from, void* to)
689     {
690         ASSERT(from.isSet());
691         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
692
693         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
694         insn = insn - 6;
695         linkWithOffset(insn, to);
696     }
697
698     static void linkCall(void* code, AssemblerLabel from, void* to)
699     {
700         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
701         linkCallInternal(insn, to);
702     }
703
704     static void linkPointer(void* code, AssemblerLabel from, void* to)
705     {
706         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
707         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
708         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
709         insn++;
710         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
711         *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
712     }
713
714     static void relinkJump(void* from, void* to)
715     {
716         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
717
718         ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
719         insn = insn - 6;
720         int flushSize = linkWithOffset(insn, to);
721
722         ExecutableAllocator::cacheFlush(insn, flushSize);
723     }
724
725     static void relinkCall(void* from, void* to)
726     {
727         void* start;
728         int size = linkCallInternal(from, to);
729         if (size == sizeof(MIPSWord))
730             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
731         else
732             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
733
734         ExecutableAllocator::cacheFlush(start, size);
735     }
736
737     static void repatchInt32(void* from, int32_t to)
738     {
739         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
740         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
741         *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
742         insn++;
743         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
744         *insn = (*insn & 0xffff0000) | (to & 0xffff);
745         insn--;
746         ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
747     }
748
749     static int32_t readInt32(void* from)
750     {
751         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
752         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
753         int32_t result = (*insn & 0x0000ffff) << 16;
754         insn++;
755         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
756         result |= *insn & 0x0000ffff;
757         return result;
758     }
759     
760     static void repatchCompact(void* where, int32_t value)
761     {
762         repatchInt32(where, value);
763     }
764
765     static void repatchPointer(void* from, void* to)
766     {
767         repatchInt32(from, reinterpret_cast<int32_t>(to));
768     }
769
770     static void* readPointer(void* from)
771     {
772         return reinterpret_cast<void*>(readInt32(from));
773     }
774
775 private:
776     /* Update each jump in the buffer of newBase.  */
777     void relocateJumps(void* oldBase, void* newBase)
778     {
779         // Check each jump
780         for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
781             int pos = iter->m_offset;
782             MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
783             insn = insn + 2;
784             // Need to make sure we have 5 valid instructions after pos
785             if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
786                 continue;
787
788             if ((*insn & 0xfc000000) == 0x08000000) { // j
789                 int offset = *insn & 0x03ffffff;
790                 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
791                 int topFourBits = (oldInsnAddress + 4) >> 28;
792                 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
793                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
794                 int newInsnAddress = (int)insn;
795                 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
796                     *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
797                 else {
798                     /* lui */
799                     *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
800                     /* ori */
801                     *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
802                     /* jr */
803                     *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
804                 }
805             } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
806                 int high = (*insn & 0xffff) << 16;
807                 int low = *(insn + 1) & 0xffff;
808                 int oldTargetAddress = high | low;
809                 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
810                 /* lui */
811                 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
812                 /* ori */
813                 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
814             }
815         }
816     }
817
818     static int linkWithOffset(MIPSWord* insn, void* to)
819     {
820         ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
821                || (*insn & 0xfc000000) == 0x14000000 // bne
822                || (*insn & 0xffff0000) == 0x45010000 // bc1t
823                || (*insn & 0xffff0000) == 0x45000000); // bc1f
824         intptr_t diff = (reinterpret_cast<intptr_t>(to)
825                          - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
826
827         if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
828             /*
829                 Convert the sequence:
830                   beq $2, $3, target
831                   nop
832                   b 1f
833                   nop
834                   nop
835                   nop
836                 1:
837
838                 to the new sequence if possible:
839                   bne $2, $3, 1f
840                   nop
841                   j    target
842                   nop
843                   nop
844                   nop
845                 1:
846
847                 OR to the new sequence:
848                   bne $2, $3, 1f
849                   nop
850                   lui $25, target >> 16
851                   ori $25, $25, target & 0xffff
852                   jr $25
853                   nop
854                 1:
855
856                 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
857             */
858
859             if (*(insn + 2) == 0x10000003) {
860                 if ((*insn & 0xfc000000) == 0x10000000) // beq
861                     *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
862                 else if ((*insn & 0xfc000000) == 0x14000000) // bne
863                     *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
864                 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
865                     *insn = 0x45000005; // bc1f
866                 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
867                     *insn = 0x45010005; // bc1t
868                 else
869                     ASSERT(0);
870             }
871
872             insn = insn + 2;
873             if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
874                 == reinterpret_cast<intptr_t>(to) >> 28) {
875                 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
876                 *(insn + 1) = 0;
877                 return 4 * sizeof(MIPSWord);
878             }
879
880             intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
881             /* lui */
882             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
883             /* ori */
884             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
885             /* jr */
886             *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
887             return 5 * sizeof(MIPSWord);
888         }
889
890         *insn = (*insn & 0xffff0000) | (diff & 0xffff);
891         return sizeof(MIPSWord);
892     }
893
894     static int linkCallInternal(void* from, void* to)
895     {
896         MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
897         insn = insn - 4;
898
899         if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
900             if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
901                 == reinterpret_cast<intptr_t>(to) >> 28) {
902                 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
903                 return sizeof(MIPSWord);
904             }
905
906             /* lui $25, (to >> 16) & 0xffff */
907             *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
908             /* ori $25, $25, to & 0xffff */
909             *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
910             /* jalr $25 */
911             *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
912             return 3 * sizeof(MIPSWord);
913         }
914
915         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
916         ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
917
918         /* lui */
919         *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
920         /* ori */
921         *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
922         return 2 * sizeof(MIPSWord);
923     }
924
925     AssemblerBuffer m_buffer;
926     Jumps m_jumps;
927 };
928
929 } // namespace JSC
930
931 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
932
933 #endif // MIPSAssembler_h