]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - assembler/MIPSAssembler.h
JavaScriptCore-1097.13.tar.gz
[apple/javascriptcore.git] / assembler / MIPSAssembler.h
index ea352685115d65315d9746fe60a124ba8dacb2d4..7212a182c6ca0d43cfe23279c5b1ed9e3d28b081 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>
 
@@ -148,7 +149,7 @@ class MIPSAssembler {
 public:
     typedef MIPSRegisters::RegisterID RegisterID;
     typedef MIPSRegisters::FPRegisterID FPRegisterID;
-    typedef SegmentedVector<int, 64> Jumps;
+    typedef SegmentedVector<AssemblerLabel, 64> Jumps;
 
     MIPSAssembler()
     {
@@ -166,46 +167,6 @@ public:
         OP_SH_FT = 16
     };
 
-    class JmpSrc {
-        friend class MIPSAssembler;
-    public:
-        JmpSrc()
-            : m_offset(-1)
-        {
-        }
-
-    private:
-        JmpSrc(int offset)
-            : m_offset(offset)
-        {
-        }
-
-        int m_offset;
-    };
-
-    class JmpDst {
-        friend class MIPSAssembler;
-    public:
-        JmpDst()
-            : m_offset(-1)
-            , m_used(false)
-        {
-        }
-
-        bool isUsed() const { return m_used; }
-        void used() { m_used = true; }
-    private:
-        JmpDst(int offset)
-            : m_offset(offset)
-            , m_used(false)
-        {
-            ASSERT(m_offset == offset);
-        }
-
-        int m_offset : 31;
-        int m_used : 1;
-    };
-
     void emitInst(MIPSWord op)
     {
         void* oldBase = m_buffer.data();
@@ -287,6 +248,11 @@ public:
         emitInst(0x00000018 | (rs << OP_SH_RS) | (rt << OP_SH_RT));
     }
 
+    void div(RegisterID rs, RegisterID rt)
+    {
+        emitInst(0x0000001a | (rs << OP_SH_RS) | (rt << OP_SH_RT));
+    }
+
     void mfhi(RegisterID rd)
     {
         emitInst(0x00000010 | (rd << OP_SH_RD));
@@ -392,6 +358,18 @@ public:
                  | (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));
+    }
+
+    void srlv(RegisterID rd, RegisterID rt, RegisterID rs)
+    {
+        emitInst(0x00000006 | (rd << OP_SH_RD) | (rt << OP_SH_RT)
+                 | (rs << OP_SH_RS));
+    }
+
     void lbu(RegisterID rt, RegisterID rs, int offset)
     {
         emitInst(0x90000000 | (rt << OP_SH_RT) | (rs << OP_SH_RS)
@@ -484,14 +462,9 @@ public:
         emitInst(0x45000000);
     }
 
-    JmpSrc newJmpSrc()
-    {
-        return JmpSrc(m_buffer.size());
-    }
-
     void appendJump()
     {
-        m_jumps.append(m_buffer.size());
+        m_jumps.append(m_buffer.label());
     }
 
     void addd(FPRegisterID fd, FPRegisterID fs, FPRegisterID ft)
@@ -512,6 +485,12 @@ public:
                  | (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));
+    }
+
     void lwc1(FPRegisterID ft, RegisterID rs, int offset)
     {
         emitInst(0xc4000000 | (ft << OP_SH_FT) | (rs << OP_SH_RS)
@@ -543,12 +522,23 @@ public:
         copDelayNop();
     }
 
+    void mthc1(RegisterID rt, FPRegisterID fs)
+    {
+        emitInst(0x44e00000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
+        copDelayNop();
+    }
+
     void mfc1(RegisterID rt, FPRegisterID fs)
     {
         emitInst(0x44000000 | (fs << OP_SH_FS) | (rt << OP_SH_RT));
         copDelayNop();
     }
 
+    void sqrtd(FPRegisterID fd, FPRegisterID fs)
+    {
+        emitInst(0x46200004 | (fd << OP_SH_FD) | (fs << OP_SH_FS));
+    }
+
     void truncwd(FPRegisterID fd, FPRegisterID fs)
     {
         emitInst(0x4620000d | (fd << OP_SH_FD) | (fs << OP_SH_FS));
@@ -559,6 +549,11 @@ public:
         emitInst(0x46800021 | (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 ceqd(FPRegisterID fs, FPRegisterID ft)
     {
         emitInst(0x46200032 | (fs << OP_SH_FS) | (ft << OP_SH_FT));
@@ -621,12 +616,12 @@ public:
 
     // General helpers
 
-    JmpDst label()
+    AssemblerLabel label()
     {
-        return JmpDst(m_buffer.size());
+        return m_buffer.label();
     }
 
-    JmpDst align(int alignment)
+    AssemblerLabel align(int alignment)
     {
         while (!m_buffer.isAligned(alignment))
             bkpt();
@@ -634,52 +629,36 @@ public:
         return label();
     }
 
-    static void* getRelocatedAddress(void* code, JmpSrc jump)
-    {
-        ASSERT(jump.m_offset != -1);
-        void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
-        return b;
-    }
-
-    static void* getRelocatedAddress(void* code, JmpDst label)
-    {
-        void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
-        return b;
-    }
-
-    static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
+    static void* getRelocatedAddress(void* code, AssemblerLabel label)
     {
-        return to.m_offset - from.m_offset;
+        return reinterpret_cast<void*>(reinterpret_cast<char*>(code) + label.m_offset);
     }
 
-    static int getDifferenceBetweenLabels(JmpDst from, JmpSrc to)
+    static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
     {
-        return to.m_offset - from.m_offset;
-    }
-
-    static int getDifferenceBetweenLabels(JmpSrc from, JmpDst to)
-    {
-        return to.m_offset - from.m_offset;
+        return b.m_offset - a.m_offset;
     }
 
     // Assembler admin methods:
 
-    size_t size() const
+    size_t codeSize() const
     {
-        return m_buffer.size();
+        return m_buffer.codeSize();
     }
 
-    void* executableCopy(ExecutablePool* allocator)
+    PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort)
     {
-        void *result = m_buffer.executableCopy(allocator);
+        RefPtr<ExecutableMemoryHandle> result = m_buffer.executableCopy(globalData, ownerUID, effort);
         if (!result)
             return 0;
 
-        relocateJumps(m_buffer.data(), result);
-        return result;
+        relocateJumps(m_buffer.data(), result->start());
+        return result.release();
     }
 
-    static unsigned getCallReturnOffset(JmpSrc call)
+    unsigned debugOffset() { return m_buffer.debugOffset(); }
+
+    static unsigned getCallReturnOffset(AssemblerLabel call)
     {
         // The return address is after a call and a delay slot instruction
         return call.m_offset;
@@ -693,10 +672,10 @@ public:
     // writable region of memory; to modify the code in an execute-only execuable
     // pool the 'repatch' and 'relink' methods should be used.
 
-    void linkJump(JmpSrc from, JmpDst to)
+    void linkJump(AssemblerLabel from, AssemblerLabel to)
     {
-        ASSERT(to.m_offset != -1);
-        ASSERT(from.m_offset != -1);
+        ASSERT(to.isSet());
+        ASSERT(from.isSet());
         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + from.m_offset);
         MIPSWord* toPos = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(m_buffer.data()) + to.m_offset);
 
@@ -705,9 +684,9 @@ public:
         linkWithOffset(insn, toPos);
     }
 
-    static void linkJump(void* code, JmpSrc from, void* to)
+    static void linkJump(void* code, AssemblerLabel from, void* to)
     {
-        ASSERT(from.m_offset != -1);
+        ASSERT(from.isSet());
         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
 
         ASSERT(!(*(insn - 1)) && !(*(insn - 2)) && !(*(insn - 3)) && !(*(insn - 5)));
@@ -715,13 +694,13 @@ public:
         linkWithOffset(insn, to);
     }
 
-    static void linkCall(void* code, JmpSrc from, void* to)
+    static void linkCall(void* code, AssemblerLabel from, void* to)
     {
         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
         linkCallInternal(insn, to);
     }
 
-    static void linkPointer(void* code, JmpDst from, void* to)
+    static void linkPointer(void* code, AssemblerLabel from, void* to)
     {
         MIPSWord* insn = reinterpret_cast<MIPSWord*>(reinterpret_cast<intptr_t>(code) + from.m_offset);
         ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
@@ -739,7 +718,7 @@ public:
         insn = insn - 6;
         int flushSize = linkWithOffset(insn, to);
 
-        ExecutableAllocator::cacheFlush(insn, flushSize);
+        cacheFlush(insn, flushSize);
     }
 
     static void relinkCall(void* from, void* to)
@@ -751,7 +730,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)
@@ -763,7 +742,23 @@ 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)
+    {
+        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
+        ASSERT((*insn & 0xffe00000) == 0x3c000000); // lui
+        int32_t result = (*insn & 0x0000ffff) << 16;
+        insn++;
+        ASSERT((*insn & 0xfc000000) == 0x34000000); // ori
+        result |= *insn & 0x0000ffff;
+        return result;
+    }
+    
+    static void repatchCompact(void* where, int32_t value)
+    {
+        repatchInt32(where, value);
     }
 
     static void repatchPointer(void* from, void* to)
@@ -771,29 +766,60 @@ public:
         repatchInt32(from, reinterpret_cast<int32_t>(to));
     }
 
-    static void repatchLoadPtrToLEA(void* from)
+    static void* readPointer(void* from)
     {
-        MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
-        insn = insn + 3;
-        ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw
-        /* lw -> addiu */
-        *insn = 0x24000000 | (*insn & 0x03ffffff);
+        return reinterpret_cast<void*>(readInt32(from));
+    }
 
-        ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord));
+    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
     }
 
 private:
-
     /* Update each jump in the buffer of newBase.  */
     void relocateJumps(void* oldBase, void* newBase)
     {
         // Check each jump
         for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) {
-            int pos = *iter;
+            int pos = iter->m_offset;
             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.size() - 5 * sizeof(MIPSWord))
+            if ((unsigned int)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
                 continue;
 
             if ((*insn & 0xfc000000) == 0x08000000) { // j