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