]> git.saurik.com Git - apple/javascriptcore.git/blob - assembler/MIPSAssembler.h
JavaScriptCore-1097.13.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 "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 label()
620 {
621 return m_buffer.label();
622 }
623
624 AssemblerLabel align(int alignment)
625 {
626 while (!m_buffer.isAligned(alignment))
627 bkpt();
628
629 return label();
630 }
631
632 static void* getRelocatedAddress(void* code, AssemblerLabel label)
633 {
634 return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
635 }
636
637 static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
638 {
639 return b.m_offset - a.m_offset;
640 }
641
642 // Assembler admin methods:
643
644 size_t codeSize() const
645 {
646 return m_buffer.codeSize();
647 }
648
649 PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort)
650 {
651 RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData, ownerUID, effort);
652 if (!result)
653 return 0;
654
655 relocateJumps(m_buffer.data(), result->start());
656 return result.release();
657 }
658
659 unsigned debugOffset() { return m_buffer.debugOffset(); }
660
661 static unsigned getCallReturnOffset(AssemblerLabel call)
662 {
663 // The return address is after a call and a delay slot instruction
664 return call.m_offset;
665 }
666
667 // Linking & patching:
668 //
669 // 'link' and 'patch' methods are for use on unprotected code - such as the code
670 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
671 // code has been finalized it is (platform support permitting) within a non-
672 // writable region of memory; to modify the code in an execute-only execuable
673 // pool the 'repatch' and 'relink' methods should be used.
674
675 void linkJump(AssemblerLabel from, AssemblerLabel to)
676 {
677 ASSERT(to.isSet());
678 ASSERT(from.isSet());
679 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
680 MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
681
682 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
683 insn = insn - 6;
684 linkWithOffset(insn, toPos);
685 }
686
687 static void linkJump(void* code, AssemblerLabel from, void* to)
688 {
689 ASSERT(from.isSet());
690 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
691
692 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
693 insn = insn - 6;
694 linkWithOffset(insn, to);
695 }
696
697 static void linkCall(void* code, AssemblerLabel from, void* to)
698 {
699 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
700 linkCallInternal(insn, to);
701 }
702
703 static void linkPointer(void* code, AssemblerLabel from, void* to)
704 {
705 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
706 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
707 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
708 insn++;
709 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
710 *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
711 }
712
713 static void relinkJump(void* from, void* to)
714 {
715 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
716
717 ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
718 insn = insn - 6;
719 int flushSize = linkWithOffset(insn, to);
720
721 cacheFlush(insn, flushSize);
722 }
723
724 static void relinkCall(void* from, void* to)
725 {
726 void* start;
727 int size = linkCallInternal(from, to);
728 if (size == sizeof(MIPSWord))
729 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
730 else
731 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
732
733 cacheFlush(start, size);
734 }
735
736 static void repatchInt32(void* from, int32_t to)
737 {
738 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
739 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
740 *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
741 insn++;
742 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
743 *insn = (*insn & 0xffff0000) | (to & 0xffff);
744 insn--;
745 cacheFlush(insn, 2 * sizeof(MIPSWord));
746 }
747
748 static int32_t readInt32(void* from)
749 {
750 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
751 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
752 int32_t result = (*insn & 0x0000ffff) << 16;
753 insn++;
754 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
755 result |= *insn & 0x0000ffff;
756 return result;
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 reinterpret_cast<void*>(readInt32(from));
772 }
773
774 static void* readCallTarget(void* from)
775 {
776 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
777 insn -= 4;
778 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
779 int32_t result = (*insn & 0x0000ffff) << 16;
780 insn++;
781 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
782 result |= *insn & 0x0000ffff;
783 return reinterpret_cast<void*>(result);
784 }
785
786 static void cacheFlush(void* code, size_t size)
787 {
788 #if GCC_VERSION_AT_LEAST(4, 3, 0)
789 #if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4, 4, 3)
790 int lineSize;
791 asm("rdhwr %0, $1" : "=r" (lineSize));
792 //
793 // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
794 // mips_expand_synci_loop that may execute synci one more time.
795 // "start" points to the fisrt byte of the cache line.
796 // "end" points to the last byte of the line before the last cache line.
797 // Because size is always a multiple of 4, this is safe to set
798 // "end" to the last byte.
799 //
800 intptr_t start = reinterpret_cast<intptr_t>(code) & (-lineSize);
801 intptr_t end = ((reinterpret_cast<intptr_t>(code) + size - 1) & (-lineSize)) - 1;
802 __builtin___clear_cache(reinterpret_cast<char*>(start), reinterpret_cast<char*>(end));
803 #else
804 intptr_t end = reinterpret_cast<intptr_t>(code) + size;
805 __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
806 #endif
807 #else
808 _flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
809 #endif
810 }
811
812 private:
813 /* Update each jump in the buffer of newBase. */
814 void relocateJumps(void* oldBase, void* newBase)
815 {
816 // Check each jump
817 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
818 int pos = iter->m_offset;
819 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
820 insn = insn + 2;
821 // Need to make sure we have 5 valid instructions after pos
822 if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
823 continue;
824
825 if ((*insn & 0xfc000000) == 0x08000000) { // j
826 int offset = *insn & 0x03ffffff;
827 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
828 int topFourBits = (oldInsnAddress + 4) >> 28;
829 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
830 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
831 int newInsnAddress = (int)insn;
832 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
833 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
834 else {
835 /* lui */
836 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
837 /* ori */
838 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
839 /* jr */
840 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
841 }
842 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
843 int high = (*insn & 0xffff) << 16;
844 int low = *(insn + 1) & 0xffff;
845 int oldTargetAddress = high | low;
846 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
847 /* lui */
848 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
849 /* ori */
850 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
851 }
852 }
853 }
854
855 static int linkWithOffset(MIPSWord* insn, void* to)
856 {
857 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
858 || (*insn & 0xfc000000) == 0x14000000 // bne
859 || (*insn & 0xffff0000) == 0x45010000 // bc1t
860 || (*insn & 0xffff0000) == 0x45000000); // bc1f
861 intptr_t diff = (reinterpret_cast<intptr_t>(to)
862 - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
863
864 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
865 /*
866 Convert the sequence:
867 beq $2, $3, target
868 nop
869 b 1f
870 nop
871 nop
872 nop
873 1:
874
875 to the new sequence if possible:
876 bne $2, $3, 1f
877 nop
878 j target
879 nop
880 nop
881 nop
882 1:
883
884 OR to the new sequence:
885 bne $2, $3, 1f
886 nop
887 lui $25, target >> 16
888 ori $25, $25, target & 0xffff
889 jr $25
890 nop
891 1:
892
893 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
894 */
895
896 if (*(insn + 2) == 0x10000003) {
897 if ((*insn & 0xfc000000) == 0x10000000) // beq
898 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
899 else if ((*insn & 0xfc000000) == 0x14000000) // bne
900 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
901 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
902 *insn = 0x45000005; // bc1f
903 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
904 *insn = 0x45010005; // bc1t
905 else
906 ASSERT(0);
907 }
908
909 insn = insn + 2;
910 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
911 == reinterpret_cast<intptr_t>(to) >> 28) {
912 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
913 *(insn + 1) = 0;
914 return 4 * sizeof(MIPSWord);
915 }
916
917 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
918 /* lui */
919 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
920 /* ori */
921 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
922 /* jr */
923 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
924 return 5 * sizeof(MIPSWord);
925 }
926
927 *insn = (*insn & 0xffff0000) | (diff & 0xffff);
928 return sizeof(MIPSWord);
929 }
930
931 static int linkCallInternal(void* from, void* to)
932 {
933 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
934 insn = insn - 4;
935
936 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
937 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
938 == reinterpret_cast<intptr_t>(to) >> 28) {
939 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
940 return sizeof(MIPSWord);
941 }
942
943 /* lui $25, (to >> 16) & 0xffff */
944 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
945 /* ori $25, $25, to & 0xffff */
946 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
947 /* jalr $25 */
948 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
949 return 3 * sizeof(MIPSWord);
950 }
951
952 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
953 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
954
955 /* lui */
956 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
957 /* ori */
958 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
959 return 2 * sizeof(MIPSWord);
960 }
961
962 AssemblerBuffer m_buffer;
963 Jumps m_jumps;
964 };
965
966 } // namespace JSC
967
968 #endif // ENABLE(ASSEMBLER) && CPU(MIPS)
969
970 #endif // MIPSAssembler_h