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