]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/MIPSAssembler.h
JavaScriptCore-903.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<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 void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
649 {
650 void *result = m_buffer.executableCopy(globalData, allocator);
651 if (!result)
652 return 0;
653
654 relocateJumps(m_buffer.data(), result);
655 return result;
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 }
758
759 static void repatchCompact(void* where, int32_t value)
760 {
761 repatchInt32(where, value);
762 }
763
764 static void repatchPointer(void* from, void* to)
765 {
766 repatchInt32(from, reinterpret_cast<int32_t>(to));
767 }
768
769 static void* readPointer(void* from)
770 {
771 return static_cast<void*>(readInt32(from));
772 }
773
774 private:
775 /* Update each jump in the buffer of newBase. */
776 void relocateJumps(void* oldBase, void* newBase)
777 {
778 // Check each jump
779 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
780 int pos = iter->m_offset;
781 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
782 insn = insn + 2;
783 // Need to make sure we have 5 valid instructions after pos
784 if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
785 continue;
786
787 if ((*insn & 0xfc000000) == 0x08000000) { // j
788 int offset = *insn & 0x03ffffff;
789 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
790 int topFourBits = (oldInsnAddress + 4) >> 28;
791 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
792 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
793 int newInsnAddress = (int)insn;
794 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
795 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
796 else {
797 /* lui */
798 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
799 /* ori */
800 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
801 /* jr */
802 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
803 }
804 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
805 int high = (*insn & 0xffff) << 16;
806 int low = *(insn + 1) & 0xffff;
807 int oldTargetAddress = high | low;
808 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
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 }
814 }
815 }
816
817 static int linkWithOffset(MIPSWord* insn, void* to)
818 {
819 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
820 || (*insn & 0xfc000000) == 0x14000000 // bne
821 || (*insn & 0xffff0000) == 0x45010000 // bc1t
822 || (*insn & 0xffff0000) == 0x45000000); // bc1f
823 intptr_t diff = (reinterpret_cast<intptr_t>(to)
824 - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
825
826 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
827 /*
828 Convert the sequence:
829 beq $2, $3, target
830 nop
831 b 1f
832 nop
833 nop
834 nop
835 1:
836
837 to the new sequence if possible:
838 bne $2, $3, 1f
839 nop
840 j target
841 nop
842 nop
843 nop
844 1:
845
846 OR to the new sequence:
847 bne $2, $3, 1f
848 nop
849 lui $25, target >> 16
850 ori $25, $25, target & 0xffff
851 jr $25
852 nop
853 1:
854
855 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
856 */
857
858 if (*(insn + 2) == 0x10000003) {
859 if ((*insn & 0xfc000000) == 0x10000000) // beq
860 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
861 else if ((*insn & 0xfc000000) == 0x14000000) // bne
862 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
863 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
864 *insn = 0x45000005; // bc1f
865 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
866 *insn = 0x45010005; // bc1t
867 else
868 ASSERT(0);
869 }
870
871 insn = insn + 2;
872 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
873 == reinterpret_cast<intptr_t>(to) >> 28) {
874 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
875 *(insn + 1) = 0;
876 return 4 * sizeof(MIPSWord);
877 }
878
879 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
880 /* lui */
881 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
882 /* ori */
883 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
884 /* jr */
885 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
886 return 5 * sizeof(MIPSWord);
887 }
888
889 *insn = (*insn & 0xffff0000) | (diff & 0xffff);
890 return sizeof(MIPSWord);
891 }
892
893 static int linkCallInternal(void* from, void* to)
894 {
895 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
896 insn = insn - 4;
897
898 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
899 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
900 == reinterpret_cast<intptr_t>(to) >> 28) {
901 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
902 return sizeof(MIPSWord);
903 }
904
905 /* lui $25, (to >> 16) & 0xffff */
906 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
907 /* ori $25, $25, to & 0xffff */
908 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
909 /* jalr $25 */
910 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
911 return 3 * sizeof(MIPSWord);
912 }
913
914 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
915 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
916
917 /* lui */
918 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
919 /* ori */
920 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
921 return 2 * sizeof(MIPSWord);
922 }
923
924 AssemblerBuffer m_buffer;
925 Jumps m_jumps;
926 };
927
928 } // namespace JSC
929
930 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
931
932 #endif // MIPSAssembler_h