source: webkit/trunk/JavaScriptCore/assembler/MIPSAssembler.h@ 61324

Last change on this file since 61324 was 59527, checked in by [email protected], 15 years ago

2010-05-15 Chao-ying Fu <[email protected]>

Reviewed by Oliver Hunt.

Update MIPS JIT for unsigned right shift, Math.sqrt, load16
https://bugs.webkit.org/show_bug.cgi?id=38412

Fixed MIPS build failure.

  • assembler/MIPSAssembler.h: (JSC::MIPSAssembler::srl): (JSC::MIPSAssembler::srlv): (JSC::MIPSAssembler::sqrtd):
  • assembler/MacroAssemblerMIPS.h: (JSC::MacroAssemblerMIPS::urshift32): (JSC::MacroAssemblerMIPS::sqrtDouble): (JSC::MacroAssemblerMIPS::load16): (JSC::MacroAssemblerMIPS::supportsFloatingPointSqrt):
  • jit/JSInterfaceJIT.h:
File size: 26.3 KB
Line 
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
38namespace JSC {
39
40typedef uint32_t MIPSWord;
41
42namespace MIPSRegisters {
43typedef 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
110typedef 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
147class MIPSAssembler {
148public:
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 srl(RegisterID rd, RegisterID rt, int shamt)
396 {
397 emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
398 | ((shamt & 0x1f) << OP_SH_SHAMT));
399 }
400
401 void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
402 {
403 emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
404 | (rs << OP_SH_RS));
405 }
406
407 void lbu(RegisterID rt, RegisterID rs, int offset)
408 {
409 emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
410 | (offset & 0xffff));
411 loadDelayNop();
412 }
413
414 void lw(RegisterID rt, RegisterID rs, int offset)
415 {
416 emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
417 | (offset & 0xffff));
418 loadDelayNop();
419 }
420
421 void lwl(RegisterID rt, RegisterID rs, int offset)
422 {
423 emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
424 | (offset & 0xffff));
425 loadDelayNop();
426 }
427
428 void lwr(RegisterID rt, RegisterID rs, int offset)
429 {
430 emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
431 | (offset & 0xffff));
432 loadDelayNop();
433 }
434
435 void lhu(RegisterID rt, RegisterID rs, int offset)
436 {
437 emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
438 | (offset & 0xffff));
439 loadDelayNop();
440 }
441
442 void sw(RegisterID rt, RegisterID rs, int offset)
443 {
444 emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
445 | (offset & 0xffff));
446 }
447
448 void jr(RegisterID rs)
449 {
450 emitInst(0x00000008 | (rs << OP_SH_RS));
451 }
452
453 void jalr(RegisterID rs)
454 {
455 emitInst(0x0000f809 | (rs << OP_SH_RS));
456 }
457
458 void jal()
459 {
460 emitInst(0x0c000000);
461 }
462
463 void bkpt()
464 {
465 int value = 512; /* BRK_BUG */
466 emitInst(0x0000000d | ((value & 0x3ff) << OP_SH_CODE));
467 }
468
469 void bgez(RegisterID rs, int imm)
470 {
471 emitInst(0x04010000 | (rs << OP_SH_RS) | (imm & 0xffff));
472 }
473
474 void bltz(RegisterID rs, int imm)
475 {
476 emitInst(0x04000000 | (rs << OP_SH_RS) | (imm & 0xffff));
477 }
478
479 void beq(RegisterID rs, RegisterID rt, int imm)
480 {
481 emitInst(0x10000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
482 }
483
484 void bne(RegisterID rs, RegisterID rt, int imm)
485 {
486 emitInst(0x14000000 | (rs << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff));
487 }
488
489 void bc1t()
490 {
491 emitInst(0x45010000);
492 }
493
494 void bc1f()
495 {
496 emitInst(0x45000000);
497 }
498
499 JmpSrc newJmpSrc()
500 {
501 return JmpSrc(m_buffer.size());
502 }
503
504 void appendJump()
505 {
506 m_jumps.append(m_buffer.size());
507 }
508
509 void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
510 {
511 emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
512 | (ft << OP_SH_FT));
513 }
514
515 void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
516 {
517 emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
518 | (ft << OP_SH_FT));
519 }
520
521 void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
522 {
523 emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
524 | (ft << OP_SH_FT));
525 }
526
527 void lwc1(FPRegisterID ft, RegisterID rs, int offset)
528 {
529 emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
530 | (offset & 0xffff));
531 copDelayNop();
532 }
533
534 void ldc1(FPRegisterID ft, RegisterID rs, int offset)
535 {
536 emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
537 | (offset & 0xffff));
538 }
539
540 void swc1(FPRegisterID ft, RegisterID rs, int offset)
541 {
542 emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
543 | (offset & 0xffff));
544 }
545
546 void sdc1(FPRegisterID ft, RegisterID rs, int offset)
547 {
548 emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
549 | (offset & 0xffff));
550 }
551
552 void mtc1(RegisterID rt, FPRegisterID fs)
553 {
554 emitInst(0x44800000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
555 copDelayNop();
556 }
557
558 void mfc1(RegisterID rt, FPRegisterID fs)
559 {
560 emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
561 copDelayNop();
562 }
563
564 void sqrtd(FPRegisterID fd, FPRegisterID fs)
565 {
566 emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
567 }
568
569 void truncwd(FPRegisterID fd, FPRegisterID fs)
570 {
571 emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
572 }
573
574 void cvtdw(FPRegisterID fd, FPRegisterID fs)
575 {
576 emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
577 }
578
579 void ceqd(FPRegisterID fs, FPRegisterID ft)
580 {
581 emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
582 copDelayNop();
583 }
584
585 void cngtd(FPRegisterID fs, FPRegisterID ft)
586 {
587 emitInst(0x4620003f | (fs << OP_SH_FS) | (ft << OP_SH_FT));
588 copDelayNop();
589 }
590
591 void cnged(FPRegisterID fs, FPRegisterID ft)
592 {
593 emitInst(0x4620003d | (fs << OP_SH_FS) | (ft << OP_SH_FT));
594 copDelayNop();
595 }
596
597 void cltd(FPRegisterID fs, FPRegisterID ft)
598 {
599 emitInst(0x4620003c | (fs << OP_SH_FS) | (ft << OP_SH_FT));
600 copDelayNop();
601 }
602
603 void cled(FPRegisterID fs, FPRegisterID ft)
604 {
605 emitInst(0x4620003e | (fs << OP_SH_FS) | (ft << OP_SH_FT));
606 copDelayNop();
607 }
608
609 void cueqd(FPRegisterID fs, FPRegisterID ft)
610 {
611 emitInst(0x46200033 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
612 copDelayNop();
613 }
614
615 void coled(FPRegisterID fs, FPRegisterID ft)
616 {
617 emitInst(0x46200036 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
618 copDelayNop();
619 }
620
621 void coltd(FPRegisterID fs, FPRegisterID ft)
622 {
623 emitInst(0x46200034 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
624 copDelayNop();
625 }
626
627 void culed(FPRegisterID fs, FPRegisterID ft)
628 {
629 emitInst(0x46200037 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
630 copDelayNop();
631 }
632
633 void cultd(FPRegisterID fs, FPRegisterID ft)
634 {
635 emitInst(0x46200035 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
636 copDelayNop();
637 }
638
639 // General helpers
640
641 JmpDst label()
642 {
643 return JmpDst(m_buffer.size());
644 }
645
646 JmpDst align(int alignment)
647 {
648 while (!m_buffer.isAligned(alignment))
649 bkpt();
650
651 return label();
652 }
653
654 static void* getRelocatedAddress(void* code, JmpSrc jump)
655 {
656 ASSERT(jump.m_offset != -1);
657 void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
658 return b;
659 }
660
661 static void* getRelocatedAddress(void* code, JmpDst label)
662 {
663 void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
664 return b;
665 }
666
667 static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
668 {
669 return to.m_offset - from.m_offset;
670 }
671
672 static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
673 {
674 return to.m_offset - from.m_offset;
675 }
676
677 static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
678 {
679 return to.m_offset - from.m_offset;
680 }
681
682 // Assembler admin methods:
683
684 size_t size() const
685 {
686 return m_buffer.size();
687 }
688
689 void* executableCopy(ExecutablePool* allocator)
690 {
691 void *result = m_buffer.executableCopy(allocator);
692 if (!result)
693 return 0;
694
695 relocateJumps(m_buffer.data(), result);
696 return result;
697 }
698
699 static unsigned getCallReturnOffset(JmpSrc call)
700 {
701 // The return address is after a call and a delay slot instruction
702 return call.m_offset;
703 }
704
705 // Linking & patching:
706 //
707 // 'link' and 'patch' methods are for use on unprotected code - such as the code
708 // within the AssemblerBuffer, and code being patched by the patch buffer. Once
709 // code has been finalized it is (platform support permitting) within a non-
710 // writable region of memory; to modify the code in an execute-only execuable
711 // pool the 'repatch' and 'relink' methods should be used.
712
713 void linkJump(JmpSrc from, JmpDst to)
714 {
715 ASSERT(to.m_offset != -1);
716 ASSERT(from.m_offset != -1);
717 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
718 MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
719
720 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
721 insn = insn - 6;
722 linkWithOffset(insn, toPos);
723 }
724
725 static void linkJump(void* code, JmpSrc from, void* to)
726 {
727 ASSERT(from.m_offset != -1);
728 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
729
730 ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
731 insn = insn - 6;
732 linkWithOffset(insn, to);
733 }
734
735 static void linkCall(void* code, JmpSrc from, void* to)
736 {
737 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
738 linkCallInternal(insn, to);
739 }
740
741 static void linkPointer(void* code, JmpDst from, void* to)
742 {
743 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
744 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
745 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
746 insn++;
747 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
748 *insn = (*insn & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
749 }
750
751 static void relinkJump(void* from, void* to)
752 {
753 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
754
755 ASSERT(!(*(insn - 1)) && !(*(insn - 5)));
756 insn = insn - 6;
757 int flushSize = linkWithOffset(insn, to);
758
759 ExecutableAllocator::cacheFlush(insn, flushSize);
760 }
761
762 static void relinkCall(void* from, void* to)
763 {
764 void* start;
765 int size = linkCallInternal(from, to);
766 if (size == sizeof(MIPSWord))
767 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 2 * sizeof(MIPSWord));
768 else
769 start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
770
771 ExecutableAllocator::cacheFlush(start, size);
772 }
773
774 static void repatchInt32(void* from, int32_t to)
775 {
776 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
777 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
778 *insn = (*insn & 0xffff0000) | ((to >> 16) & 0xffff);
779 insn++;
780 ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
781 *insn = (*insn & 0xffff0000) | (to & 0xffff);
782 insn--;
783 ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
784 }
785
786 static void repatchPointer(void* from, void* to)
787 {
788 repatchInt32(from, reinterpret_cast<int32_t>(to));
789 }
790
791 static void repatchLoadPtrToLEA(void* from)
792 {
793 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
794 insn = insn + 3;
795 ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw
796 /* lw -> addiu */
797 *insn = 0x24000000 | (*insn & 0x03ffffff);
798
799 ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord));
800 }
801
802private:
803
804 /* Update each jump in the buffer of newBase. */
805 void relocateJumps(void* oldBase, void* newBase)
806 {
807 // Check each jump
808 for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
809 int pos = *iter;
810 MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
811 insn = insn + 2;
812 // Need to make sure we have 5 valid instructions after pos
813 if ((unsigned int)pos >= m_buffer.size() - 5 * sizeof(MIPSWord))
814 continue;
815
816 if ((*insn & 0xfc000000) == 0x08000000) { // j
817 int offset = *insn & 0x03ffffff;
818 int oldInsnAddress = (int)insn - (int)newBase + (int)oldBase;
819 int topFourBits = (oldInsnAddress + 4) >> 28;
820 int oldTargetAddress = (topFourBits << 28) | (offset << 2);
821 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
822 int newInsnAddress = (int)insn;
823 if (((newInsnAddress + 4) >> 28) == (newTargetAddress >> 28))
824 *insn = 0x08000000 | ((newTargetAddress >> 2) & 0x3ffffff);
825 else {
826 /* lui */
827 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
828 /* ori */
829 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
830 /* jr */
831 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
832 }
833 } else if ((*insn & 0xffe00000) == 0x3c000000) { // lui
834 int high = (*insn & 0xffff) << 16;
835 int low = *(insn + 1) & 0xffff;
836 int oldTargetAddress = high | low;
837 int newTargetAddress = oldTargetAddress - (int)oldBase + (int)newBase;
838 /* lui */
839 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
840 /* ori */
841 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
842 }
843 }
844 }
845
846 static int linkWithOffset(MIPSWord* insn, void* to)
847 {
848 ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
849 || (*insn & 0xfc000000) == 0x14000000 // bne
850 || (*insn & 0xffff0000) == 0x45010000 // bc1t
851 || (*insn & 0xffff0000) == 0x45000000); // bc1f
852 intptr_t diff = (reinterpret_cast<intptr_t>(to)
853 - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
854
855 if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
856 /*
857 Convert the sequence:
858 beq $2, $3, target
859 nop
860 b 1f
861 nop
862 nop
863 nop
864 1:
865
866 to the new sequence if possible:
867 bne $2, $3, 1f
868 nop
869 j target
870 nop
871 nop
872 nop
873 1:
874
875 OR to the new sequence:
876 bne $2, $3, 1f
877 nop
878 lui $25, target >> 16
879 ori $25, $25, target & 0xffff
880 jr $25
881 nop
882 1:
883
884 Note: beq/bne/bc1t/bc1f are converted to bne/beq/bc1f/bc1t.
885 */
886
887 if (*(insn + 2) == 0x10000003) {
888 if ((*insn & 0xfc000000) == 0x10000000) // beq
889 *insn = (*insn & 0x03ff0000) | 0x14000005; // bne
890 else if ((*insn & 0xfc000000) == 0x14000000) // bne
891 *insn = (*insn & 0x03ff0000) | 0x10000005; // beq
892 else if ((*insn & 0xffff0000) == 0x45010000) // bc1t
893 *insn = 0x45000005; // bc1f
894 else if ((*insn & 0xffff0000) == 0x45000000) // bc1f
895 *insn = 0x45010005; // bc1t
896 else
897 ASSERT(0);
898 }
899
900 insn = insn + 2;
901 if ((reinterpret_cast<intptr_t>(insn) + 4) >> 28
902 == reinterpret_cast<intptr_t>(to) >> 28) {
903 *insn = 0x08000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
904 *(insn + 1) = 0;
905 return 4 * sizeof(MIPSWord);
906 }
907
908 intptr_t newTargetAddress = reinterpret_cast<intptr_t>(to);
909 /* lui */
910 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((newTargetAddress >> 16) & 0xffff);
911 /* ori */
912 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (newTargetAddress & 0xffff);
913 /* jr */
914 *(insn + 2) = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
915 return 5 * sizeof(MIPSWord);
916 }
917
918 *insn = (*insn & 0xffff0000) | (diff & 0xffff);
919 return sizeof(MIPSWord);
920 }
921
922 static int linkCallInternal(void* from, void* to)
923 {
924 MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
925 insn = insn - 4;
926
927 if ((*(insn + 2) & 0xfc000000) == 0x0c000000) { // jal
928 if ((reinterpret_cast<intptr_t>(from) - 4) >> 28
929 == reinterpret_cast<intptr_t>(to) >> 28) {
930 *(insn + 2) = 0x0c000000 | ((reinterpret_cast<intptr_t>(to) >> 2) & 0x3ffffff);
931 return sizeof(MIPSWord);
932 }
933
934 /* lui $25, (to >> 16) & 0xffff */
935 *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
936 /* ori $25, $25, to & 0xffff */
937 *(insn + 1) = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (reinterpret_cast<intptr_t>(to) & 0xffff);
938 /* jalr $25 */
939 *(insn + 2) = 0x0000f809 | (MIPSRegisters::t9 << OP_SH_RS);
940 return 3 * sizeof(MIPSWord);
941 }
942
943 ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
944 ASSERT((*(insn + 1) & 0xfc000000) == 0x34000000); // ori
945
946 /* lui */
947 *insn = (*insn & 0xffff0000) | ((reinterpret_cast<intptr_t>(to) >> 16) & 0xffff);
948 /* ori */
949 *(insn + 1) = (*(insn + 1) & 0xffff0000) | (reinterpret_cast<intptr_t>(to) & 0xffff);
950 return 2 * sizeof(MIPSWord);
951 }
952
953 AssemblerBuffer m_buffer;
954 Jumps m_jumps;
955};
956
957} // namespace JSC
958
959#endif // ENABLE(ASSEMBLER) && CPU(MIPS)
960
961#endif // MIPSAssembler_h
Note: See TracBrowser for help on using the repository browser.