#if ENABLE(ASSEMBLER) && CPU(MIPS)
#include "AssemblerBuffer.h"
+#include "JITCompilationEffort.h"
#include <wtf/Assertions.h>
#include <wtf/SegmentedVector.h>
public:
typedef MIPSRegisters::RegisterID RegisterID;
typedef MIPSRegisters::FPRegisterID FPRegisterID;
- typedef SegmentedVector<int, 64> Jumps;
+ typedef SegmentedVector<AssemblerLabel, 64> Jumps;
MIPSAssembler()
+ : m_indexOfLastWatchpoint(INT_MIN)
+ , m_indexOfTailOfLastWatchpoint(INT_MIN)
{
}
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();
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)
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));
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);
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));
+ }
+
+ void srlv(RegisterID rd, RegisterID rt, RegisterID 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)
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)
{
- 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));
}
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)
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 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));
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));
// General helpers
- JmpDst label()
+ AssemblerLabel labelIgnoringWatchpoints()
{
- return JmpDst(m_buffer.size());
+ return m_buffer.label();
}
- JmpDst align(int alignment)
+ AssemblerLabel labelForWatchpoint()
{
- while (!m_buffer.isAligned(alignment))
- bkpt();
-
- return label();
+ 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;
}
- static void* getRelocatedAddress(void* code, JmpSrc jump)
+ AssemblerLabel label()
{
- ASSERT(jump.m_offset != -1);
- void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + jump.m_offset);
- return b;
+ AssemblerLabel result = m_buffer.label();
+ while (UNLIKELY(static_cast<int>(result.m_offset) < m_indexOfTailOfLastWatchpoint)) {
+ nop();
+ result = m_buffer.label();
+ }
+ return result;
}
- static void* getRelocatedAddress(void* code, JmpDst label)
+ AssemblerLabel align(int alignment)
{
- void* b = reinterpret_cast<void*>((reinterpret_cast<intptr_t>(code)) + label.m_offset);
- return b;
- }
+ while (!m_buffer.isAligned(alignment))
+ bkpt();
- static int getDifferenceBetweenLabels(JmpDst from, JmpDst to)
- {
- return to.m_offset - from.m_offset;
+ return label();
}
- static int getDifferenceBetweenLabels(JmpDst from, JmpSrc 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(JmpSrc from, JmpDst to)
+ static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
{
- 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(VM& vm, void* ownerUID, JITCompilationEffort effort)
{
- void *result = m_buffer.executableCopy(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();
}
- static unsigned getCallReturnOffset(JmpSrc call)
+ 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)
{
// The return address is after a call and a delay slot instruction
return call.m_offset;
// 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.
- void linkJump(JmpSrc from, JmpDst to)
+ 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.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);
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)));
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
insn = insn - 6;
int flushSize = linkWithOffset(insn, to);
- ExecutableAllocator::cacheFlush(insn, flushSize);
+ cacheFlush(insn, flushSize);
}
static void relinkCall(void* from, void* to)
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)
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)
repatchInt32(from, reinterpret_cast<int32_t>(to));
}
- static void repatchLoadPtrToLEA(void* from)
+ static void* readPointer(void* from)
+ {
+ return reinterpret_cast<void*>(readInt32(from));
+ }
+
+ static void* readCallTarget(void* from)
{
MIPSWord* insn = reinterpret_cast<MIPSWord*>(from);
- insn = insn + 3;
- ASSERT((*insn & 0xfc000000) == 0x8c000000); // lw
- /* lw -> addiu */
- *insn = 0x24000000 | (*insn & 0x03ffffff);
+ 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
+ }
- ExecutableAllocator::cacheFlush(insn, sizeof(MIPSWord));
+ static ptrdiff_t maxJumpReplacementSize()
+ {
+ return sizeof(MIPSWord) * 4;
}
-private:
+ 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:
/* 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)pos >= m_buffer.codeSize() - 5 * sizeof(MIPSWord))
continue;
if ((*insn & 0xfc000000) == 0x08000000) { // j
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) {
/*
AssemblerBuffer m_buffer;
Jumps m_jumps;
+ int m_indexOfLastWatchpoint;
+ int m_indexOfTailOfLastWatchpoint;
};
} // namespace JSC