]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - assembler/MIPSAssembler.h
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / assembler / MIPSAssembler.h
index 4164fa9db0d9f92434e1ee146492f321bb3ef873..5f7b9b21a75ab3a99cb98410a15af5fcdc5e371f 100644 (file)
@@ -32,6 +32,7 @@
 #if ENABLE(ASSEMBLER) && CPU(MIPS)
 
 #include "AssemblerBuffer.h"
+#include "JITCompilationEffort.h"
 #include <wtf/Assertions.h>
 #include <wtf/SegmentedVector.h>
 
@@ -151,6 +152,8 @@ public:
     typedef SegmentedVector<AssemblerLabel, 64> Jumps;
 
     MIPSAssembler()
+        : m_indexOfLastWatchpoint(INT_MIN)
+        , m_indexOfTailOfLastWatchpoint(INT_MIN)
     {
     }
 
@@ -226,20 +229,17 @@ public:
 
     void addiu(RegisterID rt, RegisterID rs, int imm)
     {
-        emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (imm & 0xffff));
+        emitInst(0x24000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
     }
 
     void addu(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x00000021 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void subu(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x00000023 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void mult(RegisterID rs, RegisterID rt)
@@ -265,8 +265,7 @@ public:
     void mul(RegisterID rd, RegisterID rs, RegisterID rt)
     {
 #if WTF_MIPS_ISA_AT_LEAST(32) 
-        emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x70000002 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
 #else
         mult(rs, rt);
         mflo(rd);
@@ -275,139 +274,139 @@ public:
 
     void andInsn(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x00000024 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void andi(RegisterID rt, RegisterID rs, int imm)
     {
-        emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (imm & 0xffff));
+        emitInst(0x30000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
     }
 
     void nor(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x00000027 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void orInsn(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x00000025 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void ori(RegisterID rt, RegisterID rs, int imm)
     {
-        emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (imm & 0xffff));
+        emitInst(0x34000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
     }
 
     void xorInsn(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x00000026 | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void xori(RegisterID rt, RegisterID rs, int imm)
     {
-        emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (imm & 0xffff));
+        emitInst(0x38000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
     }
 
     void slt(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x0000002a | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void sltu(RegisterID rd, RegisterID rs, RegisterID rt)
     {
-        emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS)
-                 | (rt << OP_SH_RT));
+        emitInst(0x0000002b | (rd << OP_SH_RD) | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
     void sltiu(RegisterID rt, RegisterID rs, int imm)
     {
-        emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (imm & 0xffff));
+        emitInst(0x2c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (imm & 0xffff));
     }
 
     void sll(RegisterID rd, RegisterID rt, int shamt)
     {
-        emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
-                 | ((shamt & 0x1f) << OP_SH_SHAMT));
+        emitInst(0x00000000 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
     }
 
-    void sllv(RegisterID rd, RegisterID rt, int rs)
+    void sllv(RegisterID rd, RegisterID rt, RegisterID rs)
     {
-        emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
-                 | (rs << OP_SH_RS));
+        emitInst(0x00000004 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
     }
 
     void sra(RegisterID rd, RegisterID rt, int shamt)
     {
-        emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
-                 | ((shamt & 0x1f) << OP_SH_SHAMT));
+        emitInst(0x00000003 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
     }
 
     void srav(RegisterID rd, RegisterID rt, RegisterID rs)
     {
-        emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
-                 | (rs << OP_SH_RS));
+        emitInst(0x00000007 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
     }
 
     void srl(RegisterID rd, RegisterID rt, int shamt)
     {
-        emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
-                 | ((shamt & 0x1f) << OP_SH_SHAMT));
+        emitInst(0x00000002 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | ((shamt & 0x1f) << OP_SH_SHAMT));
     }
 
     void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
     {
-        emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
-                 | (rs << OP_SH_RS));
+        emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT) | (rs << OP_SH_RS));
+    }
+
+    void lb(RegisterID rt, RegisterID rs, int offset)
+    {
+        emitInst(0x80000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
+        loadDelayNop();
     }
 
     void lbu(RegisterID rt, RegisterID rs, int offset)
     {
-        emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
         loadDelayNop();
     }
 
     void lw(RegisterID rt, RegisterID rs, int offset)
     {
-        emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0x8c000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
         loadDelayNop();
     }
 
     void lwl(RegisterID rt, RegisterID rs, int offset)
     {
-        emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0x88000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
         loadDelayNop();
     }
 
     void lwr(RegisterID rt, RegisterID rs, int offset)
     {
-        emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0x98000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
+        loadDelayNop();
+    }
+
+    void lh(RegisterID rt, RegisterID rs, int offset)
+    {
+        emitInst(0x84000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
         loadDelayNop();
     }
 
     void lhu(RegisterID rt, RegisterID rs, int offset)
     {
-        emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0x94000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
         loadDelayNop();
     }
 
+    void sb(RegisterID rt, RegisterID rs, int offset)
+    {
+        emitInst(0xa0000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
+    }
+
+    void sh(RegisterID rt, RegisterID rs, int offset)
+    {
+        emitInst(0xa4000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
+    }
+
     void sw(RegisterID rt, RegisterID rs, int offset)
     {
-        emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0xac000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS) | (offset & 0xffff));
     }
 
     void jr(RegisterID rs)
@@ -468,51 +467,43 @@ public:
 
     void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
     {
-        emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
-                 | (ft << OP_SH_FT));
+        emitInst(0x46200000 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
     }
 
     void subd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
     {
-        emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
-                 | (ft << OP_SH_FT));
+        emitInst(0x46200001 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
     }
 
     void muld(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
     {
-        emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
-                 | (ft << OP_SH_FT));
+        emitInst(0x46200002 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
     }
 
     void divd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
     {
-        emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS)
-                 | (ft << OP_SH_FT));
+        emitInst(0x46200003 | (fd << OP_SH_FD) | (fs << OP_SH_FS) | (ft << OP_SH_FT));
     }
 
     void lwc1(FPRegisterID ft, RegisterID rs, int offset)
     {
-        emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
         copDelayNop();
     }
 
     void ldc1(FPRegisterID ft, RegisterID rs, int offset)
     {
-        emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0xd4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
     }
 
     void swc1(FPRegisterID ft, RegisterID rs, int offset)
     {
-        emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0xe4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
     }
 
     void sdc1(FPRegisterID ft, RegisterID rs, int offset)
     {
-        emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
-                 | (offset & 0xffff));
+        emitInst(0xf4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS) | (offset & 0xffff));
     }
 
     void mtc1(RegisterID rt, FPRegisterID fs)
@@ -538,6 +529,16 @@ public:
         emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
     }
 
+    void movd(FPRegisterID fd, FPRegisterID fs)
+    {
+        emitInst(0x46200006 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+    }
+
+    void negd(FPRegisterID fd, FPRegisterID fs)
+    {
+        emitInst(0x46200007 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+    }
+
     void truncwd(FPRegisterID fd, FPRegisterID fs)
     {
         emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
@@ -548,11 +549,21 @@ public:
         emitInst(0x46800021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
     }
 
+    void cvtds(FPRegisterID fd, FPRegisterID fs)
+    {
+        emitInst(0x46000021 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+    }
+
     void cvtwd(FPRegisterID fd, FPRegisterID fs)
     {
         emitInst(0x46200024 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
     }
 
+    void cvtsd(FPRegisterID fd, FPRegisterID fs)
+    {
+        emitInst(0x46200020 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+    }
+
     void ceqd(FPRegisterID fs, FPRegisterID ft)
     {
         emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
@@ -615,11 +626,31 @@ public:
 
     // General helpers
 
-    AssemblerLabel label()
+    AssemblerLabel labelIgnoringWatchpoints()
     {
         return m_buffer.label();
     }
 
+    AssemblerLabel labelForWatchpoint()
+    {
+        AssemblerLabel result = m_buffer.label();
+        if (static_cast<int>(result.m_offset) != m_indexOfLastWatchpoint)
+            result = label();
+        m_indexOfLastWatchpoint = result.m_offset;
+        m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
+        return result;
+    }
+
+    AssemblerLabel label()
+    {
+        AssemblerLabel result = m_buffer.label();
+        while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
+            nop();
+            result = m_buffer.label();
+        }
+        return result;
+    }
+
     AssemblerLabel align(int alignment)
     {
         while (!m_buffer.isAligned(alignment))
@@ -645,19 +676,40 @@ public:
         return m_buffer.codeSize();
     }
 
-    void* executableCopy(JSGlobalData& globalData, ExecutablePool* allocator)
+    PassRefPtr<ExecutableMemoryHandle> executableCopy(VM& vm, void* ownerUID, JITCompilationEffort effort)
     {
-        void *result = m_buffer.executableCopy(globalData, allocator);
+        RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(vm, ownerUID, effort);
         if (!result)
             return 0;
 
-        relocateJumps(m_buffer.data(), result);
-        return result;
+        relocateJumps(m_buffer.data(), result->start());
+        return result.release();
     }
 
-#ifndef NDEBUG
     unsigned debugOffset() { return m_buffer.debugOffset(); }
+
+    // Assembly helpers for moving data between fp and registers.
+    void vmov(RegisterID rd1, RegisterID rd2, FPRegisterID rn)
+    {
+#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
+        mfc1(rd1, rn);
+        mfhc1(rd2, rn);
+#else
+        mfc1(rd1, rn);
+        mfc1(rd2, FPRegisterID(rn + 1));
+#endif
+    }
+
+    void vmov(FPRegisterID rd, RegisterID rn1, RegisterID rn2)
+    {
+#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
+        mtc1(rn1, rd);
+        mthc1(rn2, rd);
+#else
+        mtc1(rn1, rd);
+        mtc1(rn2, FPRegisterID(rd + 1));
 #endif
+    }
 
     static unsigned getCallReturnOffset(AssemblerLabel call)
     {
@@ -668,11 +720,40 @@ public:
     // Linking & patching:
     //
     // 'link' and 'patch' methods are for use on unprotected code - such as the code
-    // within the AssemblerBuffer, and code being patched by the patch buffer.  Once
+    // within the AssemblerBuffer, and code being patched by the patch buffer. Once
     // code has been finalized it is (platform support permitting) within a non-
     // writable region of memory; to modify the code in an execute-only execuable
     // pool the 'repatch' and 'relink' methods should be used.
 
+    static size_t linkDirectJump(void* code, void* to)
+    {
+        MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code));
+        size_t ops = 0;
+        int32_t slotAddr = reinterpret_cast<int>(insn) + 4;
+        int32_t toAddr = reinterpret_cast<int>(to);
+
+        if ((slotAddr & 0xf0000000) != (toAddr & 0xf0000000)) {
+            // lui
+            *insn = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((toAddr >> 16) & 0xffff);
+            ++insn;
+            // ori
+            *insn = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (toAddr & 0xffff);
+            ++insn;
+            // jr
+            *insn = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
+            ++insn;
+            ops = 4 * sizeof(MIPSWord);
+        } else {
+            // j
+            *insn = 0x08000000 | ((toAddr & 0x0fffffff) >> 2);
+            ++insn;
+            ops = 2 * sizeof(MIPSWord);
+        }
+        // nop
+        *insn = 0x00000000;
+        return ops;
+    }
+
     void linkJump(AssemblerLabel from, AssemblerLabel to)
     {
         ASSERT(to.isSet());
@@ -719,7 +800,7 @@ public:
         insn = insn - 6;
         int flushSize = linkWithOffset(insn, to);
 
-        ExecutableAllocator::cacheFlush(insn, flushSize);
+        cacheFlush(insn, flushSize);
     }
 
     static void relinkCall(void* from, void* to)
@@ -731,7 +812,7 @@ public:
         else
             start = reinterpret_cast<void*>(reinterpret_cast<intptr_t>(from) - 4 * sizeof(MIPSWord));
 
-        ExecutableAllocator::cacheFlush(start, size);
+        cacheFlush(start, size);
     }
 
     static void repatchInt32(void* from, int32_t to)
@@ -743,7 +824,7 @@ public:
         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
         *insn = (*insn & 0xffff0000) | (to & 0xffff);
         insn--;
-        ExecutableAllocator::cacheFlush(insn, 2 * sizeof(MIPSWord));
+        cacheFlush(insn, 2 * sizeof(MIPSWord));
     }
 
     static int32_t readInt32(void* from)
@@ -753,7 +834,8 @@ public:
         int32_t result = (*insn & 0x0000ffff) << 16;
         insn++;
         ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
-        result |= *insn & 0x0000ffff
+        result |= *insn & 0x0000ffff;
+        return result;
     }
     
     static void repatchCompact(void* where, int32_t value)
@@ -768,7 +850,99 @@ public:
 
     static void* readPointer(void* from)
     {
-        return static_cast<void*>(readInt32(from));
+        return reinterpret_cast<void*>(readInt32(from));
+    }
+
+    static void* readCallTarget(void* from)
+    {
+        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
+        insn -= 4;
+        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
+        int32_t result = (*insn & 0x0000ffff) << 16;
+        insn++;
+        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
+        result |= *insn & 0x0000ffff;
+        return reinterpret_cast<void*>(result);
+    }
+
+    static void cacheFlush(void* code, size_t size)
+    {
+#if GCC_VERSION_AT_LEAST(4, 3, 0)
+#if WTF_MIPS_ISA_REV(2) && !GCC_VERSION_AT_LEAST(4, 4, 3)
+        int lineSize;
+        asm("rdhwr %0, $1" : "=r" (lineSize));
+        //
+        // Modify "start" and "end" to avoid GCC 4.3.0-4.4.2 bug in
+        // mips_expand_synci_loop that may execute synci one more time.
+        // "start" points to the fisrt byte of the cache line.
+        // "end" points to the last byte of the line before the last cache line.
+        // Because size is always a multiple of 4, this is safe to set
+        // "end" to the last byte.
+        //
+        intptr_t start = reinterpret_cast<intptr_t>(code) & (-lineSize);
+        intptr_t end = ((reinterpret_cast<intptr_t>(code) + size - 1) & (-lineSize)) - 1;
+        __builtin___clear_cache(reinterpret_cast<char*>(start), reinterpret_cast<char*>(end));
+#else
+        intptr_t end = reinterpret_cast<intptr_t>(code) + size;
+        __builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
+#endif
+#else
+        _flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
+#endif
+    }
+
+    static ptrdiff_t maxJumpReplacementSize()
+    {
+        return sizeof(MIPSWord) * 4;
+    }
+
+    static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm)
+    {
+        MIPSWord* insn = static_cast<MIPSWord*>(instructionStart);
+        size_t codeSize = 2 * sizeof(MIPSWord);
+
+        // lui
+        *insn = 0x3c000000 | (rt << OP_SH_RT) | ((imm >> 16) & 0xffff);
+        ++insn;
+        // ori
+        *insn = 0x34000000 | (rt << OP_SH_RS) | (rt << OP_SH_RT) | (imm & 0xffff);
+        ++insn;
+        // if jr $t9
+        if (*insn == 0x03200008) {
+            *insn = 0x00000000;
+            codeSize += sizeof(MIPSWord);
+        }
+        cacheFlush(insn, codeSize);
+    }
+
+    static void replaceWithJump(void* instructionStart, void* to)
+    {
+        ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 3));
+        ASSERT(!(bitwise_cast<uintptr_t>(to) & 3));
+        size_t ops = linkDirectJump(instructionStart, to);
+        cacheFlush(instructionStart, ops);
+    }
+
+    static void replaceWithLoad(void* instructionStart)
+    {
+        MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
+        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
+        insn++;
+        ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
+        insn++;
+        *insn = 0x8c000000 | ((*insn) & 0x3ffffff); // lw
+        cacheFlush(insn, 4);
+    }
+
+    static void replaceWithAddressComputation(void* instructionStart)
+    {
+        MIPSWord* insn = reinterpret_cast<MIPSWord*>(instructionStart);
+        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
+        insn++;
+        ASSERT((*insn & 0xfc0007ff) == 0x00000021); // addu
+        insn++;
+        *insn = 0x24000000 | ((*insn) & 0x3ffffff); // addiu
+        cacheFlush(insn, 4);
     }
 
 private:
@@ -781,7 +955,7 @@ private:
             MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(newBase) + pos);
             insn = insn + 2;
             // Need to make sure we have 5 valid instructions after pos
-            if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
+            if ((unsigned)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
                 continue;
 
             if ((*insn & 0xfc000000) == 0x08000000) { // j
@@ -817,11 +991,10 @@ private:
     static int linkWithOffset(MIPSWord* insn, void* to)
     {
         ASSERT((*insn & 0xfc000000) == 0x10000000 // beq
-               || (*insn & 0xfc000000) == 0x14000000 // bne
-               || (*insn & 0xffff0000) == 0x45010000 // bc1t
-               || (*insn & 0xffff0000) == 0x45000000); // bc1f
-        intptr_t diff = (reinterpret_cast<intptr_t>(to)
-                         - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
+            || (*insn & 0xfc000000) == 0x14000000 // bne
+            || (*insn & 0xffff0000) == 0x45010000 // bc1t
+            || (*insn & 0xffff0000) == 0x45000000); // bc1f
+        intptr_t diff = (reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(insn) - 4) >> 2;
 
         if (diff < -32768 || diff > 32767 || *(insn + 2) != 0x10000003) {
             /*
@@ -923,6 +1096,8 @@ private:
 
     AssemblerBuffer m_buffer;
     Jumps m_jumps;
+    int m_indexOfLastWatchpoint;
+    int m_indexOfTailOfLastWatchpoint;
 };
 
 } // namespace JSC