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