summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r--Source/JavaScriptCore/ChangeLog137
-rw-r--r--Source/JavaScriptCore/assembler/MIPSAssembler.h109
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssembler.h7
-rw-r--r--Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h483
-rw-r--r--Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h19
-rw-r--r--Source/JavaScriptCore/dfg/DFGCCallHelpers.h92
-rw-r--r--Source/JavaScriptCore/dfg/DFGFPRInfo.h68
-rw-r--r--Source/JavaScriptCore/dfg/DFGGPRInfo.h67
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp69
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h4
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.cpp29
-rw-r--r--Source/JavaScriptCore/jit/JITStubs.h2
-rw-r--r--Source/JavaScriptCore/jit/JSInterfaceJIT.h4
-rw-r--r--Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h20
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter.asm12
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm24
-rw-r--r--Source/JavaScriptCore/offlineasm/backends.rb3
-rw-r--r--Source/JavaScriptCore/offlineasm/instructions.rb12
-rw-r--r--Source/JavaScriptCore/offlineasm/mips.rb892
-rw-r--r--Source/JavaScriptCore/offlineasm/risc.rb4
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.h6
21 files changed, 1970 insertions, 93 deletions
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index d21e34a30..df3f15070 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,140 @@
+2013-04-09 Balazs Kilvady <kilvadyb@homejinni.com>
+
+ LLInt conditional branch compilation fault on MIPS.
+ https://bugs.webkit.org/show_bug.cgi?id=114264
+
+ Reviewed by Filip Pizlo.
+
+ Fix conditional branch compilation in LLInt offlineasm.
+
+ * offlineasm/mips.rb:
+
+2013-02-18 Balazs Kilvady <kilvadyb@homejinni.com>
+
+ MIPS DFG implementation.
+ https://bugs.webkit.org/show_bug.cgi?id=101328
+
+ Reviewed by Oliver Hunt.
+
+ DFG implementation for MIPS.
+
+ * assembler/MIPSAssembler.h:
+ (JSC::MIPSAssembler::MIPSAssembler):
+ (JSC::MIPSAssembler::sllv):
+ (JSC::MIPSAssembler::movd):
+ (MIPSAssembler):
+ (JSC::MIPSAssembler::negd):
+ (JSC::MIPSAssembler::labelForWatchpoint):
+ (JSC::MIPSAssembler::label):
+ (JSC::MIPSAssembler::vmov):
+ (JSC::MIPSAssembler::linkDirectJump):
+ (JSC::MIPSAssembler::maxJumpReplacementSize):
+ (JSC::MIPSAssembler::revertJumpToMove):
+ (JSC::MIPSAssembler::replaceWithJump):
+ * assembler/MacroAssembler.h:
+ (MacroAssembler):
+ (JSC::MacroAssembler::poke):
+ * assembler/MacroAssemblerMIPS.h:
+ (JSC::MacroAssemblerMIPS::add32):
+ (MacroAssemblerMIPS):
+ (JSC::MacroAssemblerMIPS::and32):
+ (JSC::MacroAssemblerMIPS::lshift32):
+ (JSC::MacroAssemblerMIPS::mul32):
+ (JSC::MacroAssemblerMIPS::or32):
+ (JSC::MacroAssemblerMIPS::rshift32):
+ (JSC::MacroAssemblerMIPS::urshift32):
+ (JSC::MacroAssemblerMIPS::sub32):
+ (JSC::MacroAssemblerMIPS::xor32):
+ (JSC::MacroAssemblerMIPS::store32):
+ (JSC::MacroAssemblerMIPS::jump):
+ (JSC::MacroAssemblerMIPS::branchAdd32):
+ (JSC::MacroAssemblerMIPS::branchMul32):
+ (JSC::MacroAssemblerMIPS::branchSub32):
+ (JSC::MacroAssemblerMIPS::branchNeg32):
+ (JSC::MacroAssemblerMIPS::call):
+ (JSC::MacroAssemblerMIPS::loadDouble):
+ (JSC::MacroAssemblerMIPS::moveDouble):
+ (JSC::MacroAssemblerMIPS::swapDouble):
+ (JSC::MacroAssemblerMIPS::subDouble):
+ (JSC::MacroAssemblerMIPS::mulDouble):
+ (JSC::MacroAssemblerMIPS::divDouble):
+ (JSC::MacroAssemblerMIPS::negateDouble):
+ (JSC::MacroAssemblerMIPS::branchEqual):
+ (JSC::MacroAssemblerMIPS::branchNotEqual):
+ (JSC::MacroAssemblerMIPS::branchTruncateDoubleToInt32):
+ (JSC::MacroAssemblerMIPS::branchTruncateDoubleToUint32):
+ (JSC::MacroAssemblerMIPS::truncateDoubleToInt32):
+ (JSC::MacroAssemblerMIPS::truncateDoubleToUint32):
+ (JSC::MacroAssemblerMIPS::branchDoubleNonZero):
+ (JSC::MacroAssemblerMIPS::branchDoubleZeroOrNaN):
+ (JSC::MacroAssemblerMIPS::invert):
+ (JSC::MacroAssemblerMIPS::replaceWithJump):
+ (JSC::MacroAssemblerMIPS::maxJumpReplacementSize):
+ * dfg/DFGAssemblyHelpers.h:
+ (AssemblyHelpers):
+ (JSC::DFG::AssemblyHelpers::preserveReturnAddressAfterCall):
+ (JSC::DFG::AssemblyHelpers::restoreReturnAddressBeforeReturn):
+ (JSC::DFG::AssemblyHelpers::debugCall):
+ * dfg/DFGCCallHelpers.h:
+ (CCallHelpers):
+ (JSC::DFG::CCallHelpers::setupArguments):
+ (JSC::DFG::CCallHelpers::setupArgumentsWithExecState):
+ * dfg/DFGFPRInfo.h:
+ (DFG):
+ (FPRInfo):
+ (JSC::DFG::FPRInfo::toRegister):
+ (JSC::DFG::FPRInfo::toIndex):
+ (JSC::DFG::FPRInfo::debugName):
+ * dfg/DFGGPRInfo.h:
+ (DFG):
+ (GPRInfo):
+ (JSC::DFG::GPRInfo::toRegister):
+ (JSC::DFG::GPRInfo::toIndex):
+ (JSC::DFG::GPRInfo::debugName):
+ * dfg/DFGSpeculativeJIT.h:
+ (SpeculativeJIT):
+ * jit/JSInterfaceJIT.h:
+ (JSInterfaceJIT):
+ * runtime/JSGlobalData.h:
+ (JSC::ScratchBuffer::allocationSize):
+ (ScratchBuffer):
+
+2013-02-01 Balazs Kilvady <kilvadyb@homejinni.com>
+
+ offlineasm BaseIndex handling is broken on ARM due to MIPS changes
+ https://bugs.webkit.org/show_bug.cgi?id=108261
+
+ Reviewed by Filip Pizlo.
+
+ offlineasm BaseIndex handling fix on MIPS.
+
+ * offlineasm/mips.rb:
+ * offlineasm/risc.rb:
+
+2013-01-07 Balazs Kilvady <kilvadyb@homejinni.com>
+
+ MIPS LLInt implementation.
+ https://bugs.webkit.org/show_bug.cgi?id=99706
+
+ Reviewed by Filip Pizlo.
+
+ LLInt implementation for MIPS.
+
+ * assembler/MacroAssemblerMIPS.h:
+ (JSC::MacroAssemblerMIPS::jump):
+ * dfg/DFGOperations.cpp:
+ (JSC):
+ * jit/JITStubs.cpp:
+ (JSC):
+ * jit/JITStubs.h:
+ (JITStackFrame):
+ * llint/LLIntOfflineAsmConfig.h:
+ * llint/LowLevelInterpreter.asm:
+ * llint/LowLevelInterpreter32_64.asm:
+ * offlineasm/backends.rb:
+ * offlineasm/instructions.rb:
+ * offlineasm/mips.rb: Added.
+
2013-02-27 Simon Hausmann <simon.hausmann@digia.com>
[Qt][Mac] Fix massive parallel builds
diff --git a/Source/JavaScriptCore/assembler/MIPSAssembler.h b/Source/JavaScriptCore/assembler/MIPSAssembler.h
index 026f87e52..7f553bb9a 100644
--- a/Source/JavaScriptCore/assembler/MIPSAssembler.h
+++ b/Source/JavaScriptCore/assembler/MIPSAssembler.h
@@ -152,6 +152,8 @@ public:
typedef SegmentedVector<AssemblerLabel, 64> Jumps;
MIPSAssembler()
+ : m_indexOfLastWatchpoint(INT_MIN)
+ , m_indexOfTailOfLastWatchpoint(INT_MIN)
{
}
@@ -325,7 +327,7 @@ public:
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));
}
@@ -527,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));
@@ -619,9 +631,24 @@ public:
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()
{
- return m_buffer.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)
@@ -664,14 +691,24 @@ public:
// 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)
@@ -688,6 +725,35 @@ public:
// 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());
@@ -825,29 +891,36 @@ public:
#endif
}
- static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm)
+ static ptrdiff_t maxJumpReplacementSize()
{
- MIPSWord* insn = static_cast<MIPSWord*>(instructionStart) + 1;
- ASSERT((*insn & 0xfc000000) == 0x34000000);
- *insn = (*insn & 0xfc1f0000) | (imm & 0xffff);
- cacheFlush(insn, sizeof(MIPSWord));
+ return sizeof(MIPSWord) * 4;
}
- static void replaceWithJump(void* instructionStart, void* to)
+ static void revertJumpToMove(void* instructionStart, RegisterID rt, int imm)
{
- MIPSWord* instruction = reinterpret_cast<MIPSWord*>(instructionStart);
- intptr_t jumpTo = reinterpret_cast<intptr_t>(to);
+ MIPSWord* insn = static_cast<MIPSWord*>(instructionStart);
+ size_t codeSize = 2 * sizeof(MIPSWord);
// lui
- instruction[0] = 0x3c000000 | (MIPSRegisters::t9 << OP_SH_RT) | ((jumpTo >> 16) & 0xffff);
+ *insn = 0x3c000000 | (rt << OP_SH_RT) | ((imm >> 16) & 0xffff);
+ ++insn;
// ori
- instruction[1] = 0x34000000 | (MIPSRegisters::t9 << OP_SH_RT) | (MIPSRegisters::t9 << OP_SH_RS) | (jumpTo & 0xffff);
- // jr
- instruction[2] = 0x00000008 | (MIPSRegisters::t9 << OP_SH_RS);
- // nop
- instruction[3] = 0x0;
+ *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);
+ }
- cacheFlush(instruction, sizeof(MIPSWord) * 4);
+ 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)
@@ -1023,6 +1096,8 @@ private:
AssemblerBuffer m_buffer;
Jumps m_jumps;
+ int m_indexOfLastWatchpoint;
+ int m_indexOfTailOfLastWatchpoint;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/assembler/MacroAssembler.h b/Source/JavaScriptCore/assembler/MacroAssembler.h
index 3d57340f9..2f26ff281 100644
--- a/Source/JavaScriptCore/assembler/MacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/MacroAssembler.h
@@ -200,6 +200,13 @@ public:
}
#endif
+#if CPU(MIPS)
+ void poke(FPRegisterID src, int index = 0)
+ {
+ ASSERT(!(index & 1));
+ storeDouble(src, addressForPoke(index));
+ }
+#endif
// Backwards banches, these are currently all implemented using existing forwards branch mechanisms.
void branchPtr(RelationalCondition cond, RegisterID op1, TrustedImmPtr imm, Label target)
diff --git a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
index 4f81b4599..f5298a0ab 100644
--- a/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
+++ b/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
@@ -114,6 +114,11 @@ public:
m_assembler.addu(dest, dest, src);
}
+ void add32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.addu(dest, op1, op2);
+ }
+
void add32(TrustedImm32 imm, RegisterID dest)
{
add32(imm, dest, dest);
@@ -249,6 +254,11 @@ public:
m_assembler.andInsn(dest, dest, src);
}
+ void and32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.andInsn(dest, op1, op2);
+ }
+
void and32(TrustedImm32 imm, RegisterID dest)
{
if (!imm.m_value && !m_fixedWidth)
@@ -265,9 +275,16 @@ public:
}
}
- void lshift32(TrustedImm32 imm, RegisterID dest)
+ void and32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
- m_assembler.sll(dest, dest, imm.m_value);
+ if (!imm.m_value && !m_fixedWidth)
+ move(MIPSRegisters::zero, dest);
+ else if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth)
+ m_assembler.andi(dest, src, imm.m_value);
+ else {
+ move(imm, immTempRegister);
+ m_assembler.andInsn(dest, src, immTempRegister);
+ }
}
void lshift32(RegisterID shiftAmount, RegisterID dest)
@@ -275,11 +292,33 @@ public:
m_assembler.sllv(dest, dest, shiftAmount);
}
+ void lshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.sllv(dest, src, shiftAmount);
+ }
+
+ void lshift32(TrustedImm32 imm, RegisterID dest)
+ {
+ move(imm, immTempRegister);
+ m_assembler.sllv(dest, dest, immTempRegister);
+ }
+
+ void lshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ move(imm, immTempRegister);
+ m_assembler.sllv(dest, src, immTempRegister);
+ }
+
void mul32(RegisterID src, RegisterID dest)
{
m_assembler.mul(dest, dest, src);
}
+ void mul32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.mul(dest, op1, op2);
+ }
+
void mul32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
if (!imm.m_value && !m_fixedWidth)
@@ -330,6 +369,24 @@ public:
m_assembler.orInsn(dest, dest, dataTempRegister);
}
+ void or32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (!imm.m_value && !m_fixedWidth)
+ return;
+
+ if (imm.m_value > 0 && imm.m_value < 65535 && !m_fixedWidth) {
+ m_assembler.ori(dest, src, imm.m_value);
+ return;
+ }
+
+ /*
+ li dataTemp, imm
+ or dest, src, dataTemp
+ */
+ move(imm, dataTempRegister);
+ m_assembler.orInsn(dest, src, dataTempRegister);
+ }
+
void or32(RegisterID src, AbsoluteAddress dest)
{
load32(dest.m_ptr, dataTempRegister);
@@ -342,6 +399,11 @@ public:
m_assembler.srav(dest, dest, shiftAmount);
}
+ void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.srav(dest, src, shiftAmount);
+ }
+
void rshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.sra(dest, dest, imm.m_value);
@@ -357,16 +419,31 @@ public:
m_assembler.srlv(dest, dest, shiftAmount);
}
+ void urshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
+ {
+ m_assembler.srlv(dest, src, shiftAmount);
+ }
+
void urshift32(TrustedImm32 imm, RegisterID dest)
{
m_assembler.srl(dest, dest, imm.m_value);
}
+ void urshift32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.srl(dest, src, imm.m_value);
+ }
+
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subu(dest, dest, src);
}
+ void sub32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.subu(dest, op1, op2);
+ }
+
void sub32(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_value >= -32767 && imm.m_value <= 32768
@@ -477,6 +554,11 @@ public:
m_assembler.xorInsn(dest, dest, src);
}
+ void xor32(RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ m_assembler.xorInsn(dest, op1, op2);
+ }
+
void xor32(TrustedImm32 imm, RegisterID dest)
{
if (imm.m_value == -1) {
@@ -492,6 +574,21 @@ public:
m_assembler.xorInsn(dest, dest, immTempRegister);
}
+ void xor32(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ if (imm.m_value == -1) {
+ m_assembler.nor(dest, src, MIPSRegisters::zero);
+ return;
+ }
+
+ /*
+ li immTemp, imm
+ xor dest, dest, immTemp
+ */
+ move(imm, immTempRegister);
+ m_assembler.xorInsn(dest, src, immTempRegister);
+ }
+
void sqrtDouble(FPRegisterID src, FPRegisterID dst)
{
m_assembler.sqrtd(dst, src);
@@ -971,6 +1068,44 @@ public:
}
}
+ void store32(TrustedImm32 imm, BaseIndex address)
+ {
+ if (address.offset >= -32768 && address.offset <= 32767 && !m_fixedWidth) {
+ /*
+ sll addrTemp, address.index, address.scale
+ addu addrTemp, addrTemp, address.base
+ sw src, address.offset(addrTemp)
+ */
+ m_assembler.sll(addrTempRegister, address.index, address.scale);
+ m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
+ if (!imm.m_value)
+ m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
+ else {
+ move(imm, immTempRegister);
+ m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
+ }
+ } else {
+ /*
+ sll addrTemp, address.index, address.scale
+ addu addrTemp, addrTemp, address.base
+ lui immTemp, (address.offset + 0x8000) >> 16
+ addu addrTemp, addrTemp, immTemp
+ sw src, (address.offset & 0xffff)(at)
+ */
+ m_assembler.sll(addrTempRegister, address.index, address.scale);
+ m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
+ m_assembler.lui(immTempRegister, (address.offset + 0x8000) >> 16);
+ m_assembler.addu(addrTempRegister, addrTempRegister, immTempRegister);
+ if (!imm.m_value && !m_fixedWidth)
+ m_assembler.sw(MIPSRegisters::zero, addrTempRegister, address.offset);
+ else {
+ move(imm, immTempRegister);
+ m_assembler.sw(immTempRegister, addrTempRegister, address.offset);
+ }
+ }
+ }
+
+
void store32(RegisterID src, const void* address)
{
/*
@@ -1304,7 +1439,8 @@ public:
void jump(RegisterID target)
{
- m_assembler.jr(target);
+ move(target, MIPSRegisters::t9);
+ m_assembler.jr(MIPSRegisters::t9);
m_assembler.nop();
}
@@ -1317,6 +1453,15 @@ public:
m_fixedWidth = false;
}
+ void jump(AbsoluteAddress address)
+ {
+ m_fixedWidth = true;
+ load32(address.m_ptr, MIPSRegisters::t9);
+ m_assembler.jr(MIPSRegisters::t9);
+ m_assembler.nop();
+ m_fixedWidth = false;
+ }
+
void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
{
m_assembler.vmov(dest1, dest2, src);
@@ -1385,6 +1530,53 @@ public:
return Jump();
}
+ Jump branchAdd32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ move dataTemp, op1
+ xor cmpTemp, dataTemp, op2
+ bltz cmpTemp, No_overflow # diff sign bit -> no overflow
+ addu dest, dataTemp, op2
+ xor cmpTemp, dest, dataTemp
+ bgez cmpTemp, No_overflow # same sign big -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ move(op1, dataTempRegister);
+ m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
+ m_assembler.bltz(cmpTempRegister, 10);
+ m_assembler.addu(dest, dataTempRegister, op2);
+ m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ return jump();
+ }
+ if (cond == Signed) {
+ add32(op1, op2, dest);
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero) {
+ add32(op1, op2, dest);
+ return branchEqual(dest, MIPSRegisters::zero);
+ }
+ if (cond == NonZero) {
+ add32(op1, op2, dest);
+ return branchNotEqual(dest, MIPSRegisters::zero);
+ }
+ ASSERT(0);
+ return Jump();
+ }
+
Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, RegisterID dest)
{
move(imm, immTempRegister);
@@ -1398,6 +1590,111 @@ public:
return branchAdd32(cond, immTempRegister, dest);
}
+ Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ move dataTemp, dest
+ xori cmpTemp, dataTemp, imm
+ bltz cmpTemp, No_overflow # diff sign bit -> no overflow
+ addiu dataTemp, dataTemp, imm
+ move dest, dataTemp
+ xori cmpTemp, dataTemp, imm
+ bgez cmpTemp, No_overflow # same sign big -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ if (imm.m_value >= -32768 && imm.m_value <= 32767 && !m_fixedWidth) {
+ load32(dest.m_ptr, dataTempRegister);
+ m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
+ m_assembler.bltz(cmpTempRegister, 10);
+ m_assembler.addiu(dataTempRegister, dataTempRegister, imm.m_value);
+ store32(dataTempRegister, dest.m_ptr);
+ m_assembler.xori(cmpTempRegister, dataTempRegister, imm.m_value);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ } else {
+ load32(dest.m_ptr, dataTempRegister);
+ move(imm, immTempRegister);
+ m_assembler.xorInsn(cmpTempRegister, dataTempRegister, immTempRegister);
+ m_assembler.bltz(cmpTempRegister, 10);
+ m_assembler.addiu(dataTempRegister, dataTempRegister, immTempRegister);
+ store32(dataTempRegister, dest.m_ptr);
+ m_assembler.xori(cmpTempRegister, dataTempRegister, immTempRegister);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ }
+ return jump();
+ }
+ move(imm, immTempRegister);
+ load32(dest.m_ptr, dataTempRegister);
+ add32(immTempRegister, dataTempRegister);
+ store32(dataTempRegister, dest.m_ptr);
+ if (cond == Signed) {
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dataTempRegister, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero)
+ return branchEqual(dataTempRegister, MIPSRegisters::zero);
+ if (cond == NonZero)
+ return branchNotEqual(dataTempRegister, MIPSRegisters::zero);
+ ASSERT(0);
+ return Jump();
+ }
+
+ Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ mult src, dest
+ mfhi dataTemp
+ mflo dest
+ sra addrTemp, dest, 31
+ beq dataTemp, addrTemp, No_overflow # all sign bits (bit 63 to bit 31) are the same -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ m_assembler.mult(src1, src2);
+ m_assembler.mfhi(dataTempRegister);
+ m_assembler.mflo(dest);
+ m_assembler.sra(addrTempRegister, dest, 31);
+ m_assembler.beq(dataTempRegister, addrTempRegister, 7);
+ m_assembler.nop();
+ return jump();
+ }
+ if (cond == Signed) {
+ mul32(src1, src2, dest);
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero) {
+ mul32(src1, src2, dest);
+ return branchEqual(dest, MIPSRegisters::zero);
+ }
+ if (cond == NonZero) {
+ mul32(src1, src2, dest);
+ return branchNotEqual(dest, MIPSRegisters::zero);
+ }
+ ASSERT(0);
+ return Jump();
+ }
+
Jump branchMul32(ResultCondition cond, RegisterID src, RegisterID dest)
{
ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
@@ -1446,8 +1743,7 @@ public:
Jump branchMul32(ResultCondition cond, TrustedImm32 imm, RegisterID src, RegisterID dest)
{
move(imm, immTempRegister);
- move(src, dest);
- return branchMul32(cond, immTempRegister, dest);
+ return branchMul32(cond, immTempRegister, src, dest);
}
Jump branchSub32(ResultCondition cond, RegisterID src, RegisterID dest)
@@ -1506,8 +1802,60 @@ public:
Jump branchSub32(ResultCondition cond, RegisterID src, TrustedImm32 imm, RegisterID dest)
{
move(imm, immTempRegister);
- move(src, dest);
- return branchSub32(cond, immTempRegister, dest);
+ return branchSub32(cond, src, immTempRegister, dest);
+ }
+
+ Jump branchSub32(ResultCondition cond, RegisterID op1, RegisterID op2, RegisterID dest)
+ {
+ ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero));
+ if (cond == Overflow) {
+ /*
+ move dataTemp, op1
+ xor cmpTemp, dataTemp, op2
+ bgez cmpTemp, No_overflow # same sign bit -> no overflow
+ subu dest, dataTemp, op2
+ xor cmpTemp, dest, dataTemp
+ bgez cmpTemp, No_overflow # same sign bit -> no overflow
+ nop
+ b Overflow
+ nop
+ nop
+ nop
+ nop
+ nop
+ No_overflow:
+ */
+ move(op1, dataTempRegister);
+ m_assembler.xorInsn(cmpTempRegister, dataTempRegister, op2);
+ m_assembler.bgez(cmpTempRegister, 10);
+ m_assembler.subu(dest, dataTempRegister, op2);
+ m_assembler.xorInsn(cmpTempRegister, dest, dataTempRegister);
+ m_assembler.bgez(cmpTempRegister, 7);
+ m_assembler.nop();
+ return jump();
+ }
+ if (cond == Signed) {
+ sub32(op1, op2, dest);
+ // Check if dest is negative.
+ m_assembler.slt(cmpTempRegister, dest, MIPSRegisters::zero);
+ return branchNotEqual(cmpTempRegister, MIPSRegisters::zero);
+ }
+ if (cond == Zero) {
+ sub32(op1, op2, dest);
+ return branchEqual(dest, MIPSRegisters::zero);
+ }
+ if (cond == NonZero) {
+ sub32(op1, op2, dest);
+ return branchNotEqual(dest, MIPSRegisters::zero);
+ }
+ ASSERT(0);
+ return Jump();
+ }
+
+ Jump branchNeg32(ResultCondition cond, RegisterID srcDest)
+ {
+ m_assembler.li(dataTempRegister, -1);
+ return branchMul32(cond, dataTempRegister, srcDest);
}
Jump branchOr32(ResultCondition cond, RegisterID src, RegisterID dest)
@@ -1559,7 +1907,8 @@ public:
Call call(RegisterID target)
{
- m_assembler.jalr(target);
+ move(target, MIPSRegisters::t9);
+ m_assembler.jalr(MIPSRegisters::t9);
m_assembler.nop();
return Call(m_assembler.label(), Call::None);
}
@@ -1803,7 +2152,7 @@ public:
lui immTemp, (address.offset + 0x8000) >> 16
addu addrTemp, addrTemp, immTemp
lwc1 dest, (address.offset & 0xffff)(at)
- lwc1 dest+4, (address.offset & 0xffff + 4)(at)
+ lwc1 dest+1, (address.offset & 0xffff + 4)(at)
*/
m_assembler.sll(addrTempRegister, address.index, address.scale);
m_assembler.addu(addrTempRegister, addrTempRegister, address.base);
@@ -1990,6 +2339,19 @@ public:
#endif
}
+ void moveDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ if (src != dest || m_fixedWidth)
+ m_assembler.movd(dest, src);
+ }
+
+ void swapDouble(FPRegisterID fr1, FPRegisterID fr2)
+ {
+ moveDouble(fr1, fpTempRegister);
+ moveDouble(fr2, fr1);
+ moveDouble(fpTempRegister, fr2);
+ }
+
void addDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.addd(dest, dest, src);
@@ -2017,6 +2379,11 @@ public:
m_assembler.subd(dest, dest, src);
}
+ void subDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.subd(dest, op1, op2);
+ }
+
void subDouble(Address src, FPRegisterID dest)
{
loadDouble(src, fpTempRegister);
@@ -2034,11 +2401,32 @@ public:
m_assembler.muld(dest, dest, fpTempRegister);
}
+ void mulDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.muld(dest, op1, op2);
+ }
+
void divDouble(FPRegisterID src, FPRegisterID dest)
{
m_assembler.divd(dest, dest, src);
}
+ void divDouble(FPRegisterID op1, FPRegisterID op2, FPRegisterID dest)
+ {
+ m_assembler.divd(dest, op1, op2);
+ }
+
+ void divDouble(Address src, FPRegisterID dest)
+ {
+ loadDouble(src, fpTempRegister);
+ m_assembler.divd(dest, dest, fpTempRegister);
+ }
+
+ void negateDouble(FPRegisterID src, FPRegisterID dest)
+ {
+ m_assembler.negd(dest, src);
+ }
+
void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
{
m_assembler.mtc1(src, fpTempRegister);
@@ -2098,6 +2486,8 @@ public:
Jump branchEqual(RegisterID rs, RegisterID rt)
{
+ m_assembler.nop();
+ m_assembler.nop();
m_assembler.appendJump();
m_assembler.beq(rs, rt, 0);
m_assembler.nop();
@@ -2107,6 +2497,8 @@ public:
Jump branchNotEqual(RegisterID rs, RegisterID rt)
{
+ m_assembler.nop();
+ m_assembler.nop();
m_assembler.appendJump();
m_assembler.bne(rs, rt, 0);
m_assembler.nop();
@@ -2173,11 +2565,33 @@ public:
// If the result is not representable as a 32 bit value, branch.
// May also branch for some values that are representable in 32 bits
// (specifically, in this case, INT_MAX 0x7fffffff).
- Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+ enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
+ Jump branchTruncateDoubleToInt32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
+ {
+ m_assembler.truncwd(fpTempRegister, src);
+ m_assembler.mfc1(dest, fpTempRegister);
+ return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0x7fffffff));
+ }
+
+ Jump branchTruncateDoubleToUint32(FPRegisterID src, RegisterID dest, BranchTruncateType branchType = BranchIfTruncateFailed)
+ {
+ m_assembler.truncwd(fpTempRegister, src);
+ m_assembler.mfc1(dest, fpTempRegister);
+ return branch32(branchType == BranchIfTruncateFailed ? Equal : NotEqual, dest, TrustedImm32(0));
+ }
+
+ // Result is undefined if the value is outside of the integer range.
+ void truncateDoubleToInt32(FPRegisterID src, RegisterID dest)
+ {
+ m_assembler.truncwd(fpTempRegister, src);
+ m_assembler.mfc1(dest, fpTempRegister);
+ }
+
+ // Result is undefined if src > 2^31
+ void truncateDoubleToUint32(FPRegisterID src, RegisterID dest)
{
m_assembler.truncwd(fpTempRegister, src);
m_assembler.mfc1(dest, fpTempRegister);
- return branch32(Equal, dest, TrustedImm32(0x7fffffff));
}
// Convert 'src' to an integer, and places the resulting 'dest'.
@@ -2199,28 +2613,43 @@ public:
Jump branchDoubleNonZero(FPRegisterID reg, FPRegisterID scratch)
{
-#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mthc1(MIPSRegisters::zero, scratch);
-#else
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
-#endif
+ m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
return branchDouble(DoubleNotEqual, reg, scratch);
}
Jump branchDoubleZeroOrNaN(FPRegisterID reg, FPRegisterID scratch)
{
-#if WTF_MIPS_ISA_REV(2) && WTF_MIPS_FP64
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mthc1(MIPSRegisters::zero, scratch);
-#else
- m_assembler.mtc1(MIPSRegisters::zero, scratch);
- m_assembler.mtc1(MIPSRegisters::zero, FPRegisterID(scratch + 1));
-#endif
+ m_assembler.vmov(scratch, MIPSRegisters::zero, MIPSRegisters::zero);
return branchDouble(DoubleEqualOrUnordered, reg, scratch);
}
+ // Invert a relational condition, e.g. == becomes !=, < becomes >=, etc.
+ static RelationalCondition invert(RelationalCondition cond)
+ {
+ RelationalCondition r;
+ if (cond == Equal)
+ r = NotEqual;
+ else if (cond == NotEqual)
+ r = Equal;
+ else if (cond == Above)
+ r = BelowOrEqual;
+ else if (cond == AboveOrEqual)
+ r = Below;
+ else if (cond == Below)
+ r = AboveOrEqual;
+ else if (cond == BelowOrEqual)
+ r = Above;
+ else if (cond == GreaterThan)
+ r = LessThanOrEqual;
+ else if (cond == GreaterThanOrEqual)
+ r = LessThan;
+ else if (cond == LessThan)
+ r = GreaterThanOrEqual;
+ else if (cond == LessThanOrEqual)
+ r = GreaterThan;
+ return r;
+ }
+
void nop()
{
m_assembler.nop();
@@ -2233,12 +2662,12 @@ public:
static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
{
- ASSERT_NOT_REACHED();
+ MIPSAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
}
static ptrdiff_t maxJumpReplacementSize()
{
- ASSERT_NOT_REACHED();
+ MIPSAssembler::maxJumpReplacementSize();
return 0;
}
diff --git a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
index 75b9c7072..c060179a8 100644
--- a/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGAssemblyHelpers.h
@@ -93,6 +93,23 @@ public:
}
#endif
+#if CPU(MIPS)
+ ALWAYS_INLINE void preserveReturnAddressAfterCall(RegisterID reg)
+ {
+ move(returnAddressRegister, reg);
+ }
+
+ ALWAYS_INLINE void restoreReturnAddressBeforeReturn(RegisterID reg)
+ {
+ move(reg, returnAddressRegister);
+ }
+
+ ALWAYS_INLINE void restoreReturnAddressBeforeReturn(Address address)
+ {
+ loadPtr(address, returnAddressRegister);
+ }
+#endif
+
void emitGetFromCallFrameHeaderPtr(JSStack::CallFrameHeaderEntry entry, GPRReg to)
{
loadPtr(Address(GPRInfo::callFrameRegister, entry * sizeof(Register)), to);
@@ -193,7 +210,7 @@ public:
move(TrustedImmPtr(scratchBuffer->activeLengthPtr()), GPRInfo::regT0);
storePtr(TrustedImmPtr(scratchSize), GPRInfo::regT0);
-#if CPU(X86_64) || CPU(ARM)
+#if CPU(X86_64) || CPU(ARM) || CPU(MIPS)
move(TrustedImmPtr(argument), GPRInfo::argumentGPR1);
move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
GPRReg scratch = selectScratchGPR(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
diff --git a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
index 8adde0598..3d99f6feb 100644
--- a/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
+++ b/Source/JavaScriptCore/dfg/DFGCCallHelpers.h
@@ -576,6 +576,39 @@ public:
poke(GPRInfo::nonArgGPR0);
}
#endif // CPU(ARM_HARDFP)
+#elif CPU(MIPS)
+ ALWAYS_INLINE void setupArguments(FPRReg arg1)
+ {
+ moveDouble(arg1, FPRInfo::argumentFPR0);
+ }
+
+ ALWAYS_INLINE void setupArguments(FPRReg arg1, FPRReg arg2)
+ {
+ if (arg2 != FPRInfo::argumentFPR0) {
+ moveDouble(arg1, FPRInfo::argumentFPR0);
+ moveDouble(arg2, FPRInfo::argumentFPR1);
+ } else if (arg1 != FPRInfo::argumentFPR1) {
+ moveDouble(arg2, FPRInfo::argumentFPR1);
+ moveDouble(arg1, FPRInfo::argumentFPR0);
+ } else {
+ // Swap arg1, arg2.
+ swapDouble(FPRInfo::argumentFPR0, FPRInfo::argumentFPR1);
+ }
+ }
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(FPRReg arg1, GPRReg arg2)
+ {
+ assembler().vmov(GPRInfo::argumentGPR2, GPRInfo::argumentGPR3, arg1);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ poke(arg2, 4);
+ }
+
+ ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, FPRReg arg3)
+ {
+ setupStubArguments(arg1, arg2);
+ move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+ poke(arg3, 4);
+ }
#else
#error "DFG JIT not supported on this platform."
#endif
@@ -803,119 +836,126 @@ public:
// These methods are suitable for any calling convention that provides for
// exactly 4 argument registers, e.g. ARMv7.
#if NUMBER_OF_ARGUMENT_REGISTERS == 4
+
+#if CPU(MIPS)
+#define POKE_ARGUMENT_OFFSET 4
+#else
+#define POKE_ARGUMENT_OFFSET 0
+#endif
+
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, TrustedImmPtr arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImm32 arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, GPRReg arg3, GPRReg arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, TrustedImmPtr arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, TrustedImm32 arg3, TrustedImmPtr arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4)
{
- poke(arg4);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(GPRReg arg1, GPRReg arg2, TrustedImm32 arg3, GPRReg arg4, TrustedImm32 arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, TrustedImmPtr arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, TrustedImm32 arg4, TrustedImm32 arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, TrustedImm32 arg2, TrustedImm32 arg3, GPRReg arg4, GPRReg arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
ALWAYS_INLINE void setupArgumentsWithExecState(TrustedImm32 arg1, GPRReg arg2, GPRReg arg3, GPRReg arg4, GPRReg arg5)
{
- poke(arg5, 1);
- poke(arg4);
+ poke(arg5, POKE_ARGUMENT_OFFSET + 1);
+ poke(arg4, POKE_ARGUMENT_OFFSET);
setupArgumentsWithExecState(arg1, arg2, arg3);
}
diff --git a/Source/JavaScriptCore/dfg/DFGFPRInfo.h b/Source/JavaScriptCore/dfg/DFGFPRInfo.h
index d6a038a99..6f968e282 100644
--- a/Source/JavaScriptCore/dfg/DFGFPRInfo.h
+++ b/Source/JavaScriptCore/dfg/DFGFPRInfo.h
@@ -164,6 +164,74 @@ public:
#endif
+#if CPU(MIPS)
+
+class FPRInfo {
+public:
+ typedef FPRReg RegisterType;
+ static const unsigned numberOfRegisters = 6;
+
+ // Temporary registers.
+ static const FPRReg fpRegT0 = MIPSRegisters::f0;
+ static const FPRReg fpRegT1 = MIPSRegisters::f4;
+ static const FPRReg fpRegT2 = MIPSRegisters::f6;
+ static const FPRReg fpRegT3 = MIPSRegisters::f8;
+ static const FPRReg fpRegT4 = MIPSRegisters::f10;
+ static const FPRReg fpRegT5 = MIPSRegisters::f18;
+
+ static const FPRReg returnValueFPR = MIPSRegisters::f0;
+
+ static const FPRReg argumentFPR0 = MIPSRegisters::f12;
+ static const FPRReg argumentFPR1 = MIPSRegisters::f14;
+
+ static FPRReg toRegister(unsigned index)
+ {
+ static const FPRReg registerForIndex[numberOfRegisters] = {
+ fpRegT0, fpRegT1, fpRegT2, fpRegT3, fpRegT4, fpRegT5 };
+
+ ASSERT(index < numberOfRegisters);
+ return registerForIndex[index];
+ }
+
+ static unsigned toIndex(FPRReg reg)
+ {
+ ASSERT(reg != InvalidFPRReg);
+ ASSERT(reg < 20);
+ static const unsigned indexForRegister[20] = {
+ 0, InvalidIndex, InvalidIndex, InvalidIndex,
+ 1, InvalidIndex, 2, InvalidIndex,
+ 3, InvalidIndex, 4, InvalidIndex,
+ InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex,
+ InvalidIndex, InvalidIndex, 5, InvalidIndex,
+ };
+ unsigned result = indexForRegister[reg];
+ ASSERT(result != InvalidIndex);
+ return result;
+ }
+
+ static const char* debugName(FPRReg reg)
+ {
+ ASSERT(reg != InvalidFPRReg);
+ ASSERT(reg < 32);
+ static const char* nameForRegister[32] = {
+ "f0", "f1", "f2", "f3",
+ "f4", "f5", "f6", "f7",
+ "f8", "f9", "f10", "f11",
+ "f12", "f13", "f14", "f15"
+ "f16", "f17", "f18", "f19"
+ "f20", "f21", "f22", "f23"
+ "f24", "f25", "f26", "f27"
+ "f28", "f29", "f30", "f31"
+ };
+ return nameForRegister[reg];
+ }
+private:
+
+ static const unsigned InvalidIndex = 0xffffffff;
+};
+
+#endif
+
typedef RegisterBank<FPRInfo>::iterator fpr_iterator;
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGGPRInfo.h b/Source/JavaScriptCore/dfg/DFGGPRInfo.h
index 3d07556cc..aa634cd15 100644
--- a/Source/JavaScriptCore/dfg/DFGGPRInfo.h
+++ b/Source/JavaScriptCore/dfg/DFGGPRInfo.h
@@ -461,6 +461,73 @@ private:
#endif
+#if CPU(MIPS)
+#define NUMBER_OF_ARGUMENT_REGISTERS 4
+
+class GPRInfo {
+public:
+ typedef GPRReg RegisterType;
+ static const unsigned numberOfRegisters = 6;
+
+ // Temporary registers.
+ static const GPRReg regT0 = MIPSRegisters::v0;
+ static const GPRReg regT1 = MIPSRegisters::v1;
+ static const GPRReg regT2 = MIPSRegisters::t4;
+ static const GPRReg regT3 = MIPSRegisters::t5;
+ static const GPRReg regT4 = MIPSRegisters::t6;
+ static const GPRReg regT5 = MIPSRegisters::t7;
+ // These registers match the baseline JIT.
+ static const GPRReg cachedResultRegister = regT0;
+ static const GPRReg cachedResultRegister2 = regT1;
+ static const GPRReg callFrameRegister = MIPSRegisters::s0;
+ // These constants provide the names for the general purpose argument & return value registers.
+ static const GPRReg argumentGPR0 = MIPSRegisters::a0;
+ static const GPRReg argumentGPR1 = MIPSRegisters::a1;
+ static const GPRReg argumentGPR2 = MIPSRegisters::a2;
+ static const GPRReg argumentGPR3 = MIPSRegisters::a3;
+ static const GPRReg nonArgGPR0 = regT2;
+ static const GPRReg nonArgGPR1 = regT3;
+ static const GPRReg nonArgGPR2 = regT4;
+ static const GPRReg returnValueGPR = regT0;
+ static const GPRReg returnValueGPR2 = regT1;
+ static const GPRReg nonPreservedNonReturnGPR = regT5;
+
+ static GPRReg toRegister(unsigned index)
+ {
+ ASSERT(index < numberOfRegisters);
+ static const GPRReg registerForIndex[numberOfRegisters] = { regT0, regT1, regT2, regT3, regT4, regT5 };
+ return registerForIndex[index];
+ }
+
+ static unsigned toIndex(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ ASSERT(reg < 16);
+ static const unsigned indexForRegister[16] = { InvalidIndex, InvalidIndex, 0, 1, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, 2, 3, 4, 5 };
+ unsigned result = indexForRegister[reg];
+ ASSERT(result != InvalidIndex);
+ return result;
+ }
+
+ static const char* debugName(GPRReg reg)
+ {
+ ASSERT(reg != InvalidGPRReg);
+ ASSERT(reg < 16);
+ static const char* nameForRegister[16] = {
+ "zero", "at", "v0", "v1",
+ "a0", "a1", "a2", "a3",
+ "t0", "t1", "t2", "t3",
+ "t4", "t5", "t6", "t7"
+ };
+ return nameForRegister[reg];
+ }
+private:
+
+ static const unsigned InvalidIndex = 0xffffffff;
+};
+
+#endif
+
typedef RegisterBank<GPRInfo>::iterator gpr_iterator;
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index ad595ae1b..bb9ccc37d 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -47,6 +47,18 @@
#if ENABLE(JIT)
+#if CPU(MIPS)
+#if WTF_MIPS_PIC
+#define LOAD_FUNCTION_TO_T9(function) \
+ ".set noreorder" "\n" \
+ ".cpload $25" "\n" \
+ ".set reorder" "\n" \
+ "la $t9, " LOCAL_REFERENCE(function) "\n"
+#else
+#define LOAD_FUNCTION_TO_T9(function) "" "\n"
+#endif
+#endif
+
#if ENABLE(DFG_JIT)
#if COMPILER(GCC) && CPU(X86_64)
@@ -201,6 +213,52 @@
"b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
);
+#elif COMPILER(GCC) && CPU(MIPS)
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \
+ asm( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ SYMBOL_STRING(function) ":" "\n" \
+ LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \
+ "move $a1, $ra" "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \
+ asm( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ SYMBOL_STRING(function) ":" "\n" \
+ LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \
+ "move $a3, $ra" "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \
+ asm( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ SYMBOL_STRING(function) ":" "\n" \
+ LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \
+ "sw $ra, 20($sp)" "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
+#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \
+ asm( \
+ ".text" "\n" \
+ ".globl " SYMBOL_STRING(function) "\n" \
+ HIDE_SYMBOL(function) "\n" \
+ SYMBOL_STRING(function) ":" "\n" \
+ LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \
+ "sw $ra, 24($sp)" "\n" \
+ "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \
+ );
+
#endif
#define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \
@@ -1607,6 +1665,17 @@ SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
"mov r0, r5" "\n"
"b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
);
+#elif COMPILER(GCC) && CPU(MIPS)
+asm(
+".text" "\n"
+".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
+HIDE_SYMBOL(getHostCallReturnValue) "\n"
+SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
+ LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState)
+ "lw $s0, -40($s0)" "\n"
+ "move $a0, $s0" "\n"
+ "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
+);
#endif
extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 5f6fe842c..949ddfe20 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -1528,7 +1528,7 @@ public:
// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]).
// To avoid assemblies from using wrong registers, let's occupy r1 or r3 with a dummy argument when necessary.
-#if COMPILER_SUPPORTS(EABI) && CPU(ARM)
+#if (COMPILER_SUPPORTS(EABI) && CPU(ARM)) || CPU(MIPS)
#define EABI_32BIT_DUMMY_ARG TrustedImm32(0),
#else
#define EABI_32BIT_DUMMY_ARG
@@ -1963,7 +1963,7 @@ public:
}
#endif
-#if !defined(NDEBUG) && !CPU(ARM)
+#if !defined(NDEBUG) && !CPU(ARM) && !CPU(MIPS)
void prepareForExternalCall()
{
// We're about to call out to a "native" helper function. The helper
diff --git a/Source/JavaScriptCore/jit/JITStubs.cpp b/Source/JavaScriptCore/jit/JITStubs.cpp
index 64acfeef5..168769c12 100644
--- a/Source/JavaScriptCore/jit/JITStubs.cpp
+++ b/Source/JavaScriptCore/jit/JITStubs.cpp
@@ -280,11 +280,13 @@ extern "C" {
#define PRESERVED_S0_OFFSET 64
#define PRESERVED_S1_OFFSET 68
#define PRESERVED_S2_OFFSET 72
-#define PRESERVED_RETURN_ADDRESS_OFFSET 76
-#define THUNK_RETURN_ADDRESS_OFFSET 80
-#define REGISTER_FILE_OFFSET 84
-#define GLOBAL_DATA_OFFSET 100
-#define STACK_LENGTH 104
+#define PRESERVED_S3_OFFSET 76
+#define PRESERVED_S4_OFFSET 80
+#define PRESERVED_RETURN_ADDRESS_OFFSET 84
+#define THUNK_RETURN_ADDRESS_OFFSET 88
+#define REGISTER_FILE_OFFSET 92
+#define GLOBAL_DATA_OFFSET 108
+#define STACK_LENGTH 112
#elif CPU(SH4)
#define SYMBOL_STRING(name) #name
/* code (r4), JSStack* (r5), CallFrame* (r6), void* unused1 (r7), void* unused2(sp), JSGlobalData (sp)*/
@@ -527,6 +529,8 @@ asm (
SYMBOL_STRING(ctiTrampoline) ":" "\n"
"addiu $29,$29,-" STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
"sw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
+ "sw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n"
+ "sw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n"
"sw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
"sw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
"sw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
@@ -543,12 +547,17 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n"
"lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
"lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
"lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
+ "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n"
+ "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n"
"lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
"jr $31" "\n"
"addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
".set reorder" "\n"
".set macro" "\n"
".end " SYMBOL_STRING(ctiTrampoline) "\n"
+".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n"
+HIDE_SYMBOL(ctiTrampolineEnd) "\n"
+SYMBOL_STRING(ctiTrampolineEnd) ":" "\n"
);
asm (
@@ -561,8 +570,8 @@ asm (
".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
#if WTF_MIPS_PIC
- "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n"
".set macro" "\n"
+".cpload $31" "\n"
"la $25," SYMBOL_STRING(cti_vm_throw) "\n"
".set nomacro" "\n"
"bal " SYMBOL_STRING(cti_vm_throw) "\n"
@@ -574,6 +583,8 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
"lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
"lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
"lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
+ "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n"
+ "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n"
"lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
"jr $31" "\n"
"addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
@@ -594,6 +605,8 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
"lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET) "($29)" "\n"
"lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET) "($29)" "\n"
"lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET) "($29)" "\n"
+ "lw $19," STRINGIZE_VALUE_OF(PRESERVED_S3_OFFSET) "($29)" "\n"
+ "lw $20," STRINGIZE_VALUE_OF(PRESERVED_S4_OFFSET) "($29)" "\n"
"lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "($29)" "\n"
"jr $31" "\n"
"addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
@@ -1194,9 +1207,9 @@ template<typename T> static T throwExceptionFromOpCall(JITStackFrame& jitStackFr
".globl " SYMBOL_STRING(cti_##op) "\n" \
".ent " SYMBOL_STRING(cti_##op) "\n" \
SYMBOL_STRING(cti_##op) ":" "\n" \
- "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" \
- "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
".set macro" "\n" \
+ ".cpload $25" "\n" \
+ "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
"la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \
".set nomacro" "\n" \
".reloc 1f,R_MIPS_JALR," SYMBOL_STRING(JITStubThunked_##op) "\n" \
diff --git a/Source/JavaScriptCore/jit/JITStubs.h b/Source/JavaScriptCore/jit/JITStubs.h
index fe64cd9bc..c03bc929e 100644
--- a/Source/JavaScriptCore/jit/JITStubs.h
+++ b/Source/JavaScriptCore/jit/JITStubs.h
@@ -256,6 +256,8 @@ namespace JSC {
void* preservedS0;
void* preservedS1;
void* preservedS2;
+ void* preservedS3;
+ void* preservedS4;
void* preservedReturnAddress;
ReturnAddressPtr thunkReturnAddress;
diff --git a/Source/JavaScriptCore/jit/JSInterfaceJIT.h b/Source/JavaScriptCore/jit/JSInterfaceJIT.h
index ad546d963..7afdc06dc 100644
--- a/Source/JavaScriptCore/jit/JSInterfaceJIT.h
+++ b/Source/JavaScriptCore/jit/JSInterfaceJIT.h
@@ -129,6 +129,10 @@ namespace JSC {
static const RegisterID cachedResultRegister = MIPSRegisters::v0;
static const RegisterID firstArgumentRegister = MIPSRegisters::a0;
+#if ENABLE(VALUE_PROFILER)
+ static const RegisterID bucketCounterRegister = MIPSRegisters::s3;
+#endif
+
// regT0 must be v0 for returning a 32-bit value.
static const RegisterID regT0 = MIPSRegisters::v0;
diff --git a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h
index da2d510b5..157521373 100644
--- a/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h
+++ b/Source/JavaScriptCore/llint/LLIntOfflineAsmConfig.h
@@ -38,6 +38,7 @@
#define OFFLINE_ASM_ARMv7 0
#define OFFLINE_ASM_X86_64 0
#define OFFLINE_ASM_ARMv7s 0
+#define OFFLINE_ASM_MIPS 0
#else // !ENABLE(LLINT_C_LOOP)
@@ -67,6 +68,12 @@
#define OFFLINE_ASM_X86_64 0
#endif
+#if CPU(MIPS)
+#define OFFLINE_ASM_MIPS 1
+#else
+#define OFFLINE_ASM_MIPS 0
+#endif
+
#endif // !ENABLE(LLINT_C_LOOP)
#if USE(JSVALUE64)
@@ -111,4 +118,17 @@
#define OFFLINE_ASM_VALUE_PROFILER 0
#endif
+#if CPU(MIPS)
+#ifdef WTF_MIPS_PIC
+#define S(x) #x
+#define SX(x) S(x)
+#define OFFLINE_ASM_CPLOAD(reg) \
+ ".set noreorder\n" \
+ ".cpload " SX(reg) "\n" \
+ ".set reorder\n"
+#else
+#define OFFLINE_ASM_CPLOAD(reg)
+#endif
+#endif
+
#endif // LLIntOfflineAsmConfig_h
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
index 00d5c4f6f..9de48f1f6 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter.asm
@@ -182,10 +182,8 @@ macro assert(assertion)
end
macro preserveReturnAddressAfterCall(destinationRegister)
- if C_LOOP
- # In our case, we're only preserving the bytecode vPC.
- move lr, destinationRegister
- elsif ARMv7
+ if C_LOOP or ARMv7 or MIPS
+ # In C_LOOP case, we're only preserving the bytecode vPC.
move lr, destinationRegister
elsif X86 or X86_64
pop destinationRegister
@@ -195,10 +193,8 @@ macro preserveReturnAddressAfterCall(destinationRegister)
end
macro restoreReturnAddressBeforeReturn(sourceRegister)
- if C_LOOP
- # In our case, we're only restoring the bytecode vPC.
- move sourceRegister, lr
- elsif ARMv7
+ if C_LOOP or ARMv7 or MIPS
+ # In C_LOOP case, we're only restoring the bytecode vPC.
move sourceRegister, lr
elsif X86 or X86_64
push sourceRegister
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index 8d5cdf108..9a17985bc 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -113,6 +113,10 @@ macro cCall2(function, arg1, arg2)
poke arg1, 0
poke arg2, 1
call function
+ elsif MIPS
+ move arg1, a0
+ move arg2, a1
+ call function
elsif C_LOOP
cloopCallSlowPath function, arg1, arg2
else
@@ -134,6 +138,12 @@ macro cCall4(function, arg1, arg2, arg3, arg4)
poke arg3, 2
poke arg4, 3
call function
+ elsif MIPS
+ move arg1, a0
+ move arg2, a1
+ move arg3, a2
+ move arg4, a3
+ call function
elsif C_LOOP
error
else
@@ -1818,6 +1828,20 @@ macro nativeCallTrampoline(executableOffsetToFunction)
call executableOffsetToFunction[t1]
restoreReturnAddressBeforeReturn(t3)
loadp JITStackFrame::globalData[sp], t3
+ elsif MIPS
+ loadp JITStackFrame::globalData[sp], t3
+ storep cfr, JSGlobalData::topCallFrame[t3]
+ move t0, t2
+ preserveReturnAddressAfterCall(t3)
+ storep t3, ReturnPC[cfr]
+ move cfr, t0
+ loadi Callee + PayloadOffset[cfr], t1
+ loadp JSFunction::m_executable[t1], t1
+ move t2, cfr
+ move t0, a0
+ call executableOffsetToFunction[t1]
+ restoreReturnAddressBeforeReturn(t3)
+ loadp JITStackFrame::globalData[sp], t3
elsif C_LOOP
loadp JITStackFrame::globalData[sp], t3
storep cfr, JSGlobalData::topCallFrame[t3]
diff --git a/Source/JavaScriptCore/offlineasm/backends.rb b/Source/JavaScriptCore/offlineasm/backends.rb
index 78e545738..ef9358c0b 100644
--- a/Source/JavaScriptCore/offlineasm/backends.rb
+++ b/Source/JavaScriptCore/offlineasm/backends.rb
@@ -25,6 +25,7 @@ require "config"
require "armv7"
require "ast"
require "x86"
+require "mips"
require "cloop"
BACKENDS =
@@ -32,6 +33,7 @@ BACKENDS =
"X86",
"X86_64",
"ARMv7",
+ "MIPS",
"C_LOOP"
]
@@ -45,6 +47,7 @@ WORKING_BACKENDS =
"X86",
"X86_64",
"ARMv7",
+ "MIPS",
"C_LOOP"
]
diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb
index e047b2a16..4e70625c2 100644
--- a/Source/JavaScriptCore/offlineasm/instructions.rb
+++ b/Source/JavaScriptCore/offlineasm/instructions.rb
@@ -265,6 +265,16 @@ ARMv7_INSTRUCTIONS =
"oris"
]
+MIPS_INSTRUCTIONS =
+ [
+ "movz",
+ "movn",
+ "slt",
+ "sltu",
+ "pichdr",
+ "pichdrra"
+ ]
+
CXX_INSTRUCTIONS =
[
"cloopCrash", # no operands
@@ -281,7 +291,7 @@ CXX_INSTRUCTIONS =
"cloopDo", # no operands
]
-INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS + CXX_INSTRUCTIONS
+INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS + MIPS_INSTRUCTIONS + CXX_INSTRUCTIONS
INSTRUCTION_PATTERN = Regexp.new('\\A((' + INSTRUCTIONS.join(')|(') + '))\\Z')
diff --git a/Source/JavaScriptCore/offlineasm/mips.rb b/Source/JavaScriptCore/offlineasm/mips.rb
new file mode 100644
index 000000000..c6daa3c7d
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/mips.rb
@@ -0,0 +1,892 @@
+# Copyright (C) 2012 Apple Inc. All rights reserved.
+# Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY MIPS TECHNOLOGIES, INC. ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MIPS TECHNOLOGIES, INC. OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+require 'risc'
+
+class Assembler
+ def putStr(str)
+ @outp.puts str
+ end
+end
+
+class Node
+ def mipsSingleHi
+ doubleOperand = mipsOperand
+ raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
+ "$f" + ($~.post_match.to_i + 1).to_s
+ end
+ def mipsSingleLo
+ doubleOperand = mipsOperand
+ raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^\$f/
+ doubleOperand
+ end
+end
+
+class SpecialRegister < NoChildren
+ def mipsOperand
+ @name
+ end
+
+ def dump
+ @name
+ end
+
+ def register?
+ true
+ end
+end
+
+MIPS_TEMP_GPRS = [SpecialRegister.new("$t5"), SpecialRegister.new("$t6"), SpecialRegister.new("$t7"),
+ SpecialRegister.new("$t8")]
+MIPS_ZERO_REG = SpecialRegister.new("$zero")
+MIPS_GP_REG = SpecialRegister.new("$gp")
+MIPS_GPSAVE_REG = SpecialRegister.new("$s4")
+MIPS_JUMP_REG = SpecialRegister.new("$ra")
+MIPS_CALL_REG = SpecialRegister.new("$t9")
+MIPS_TEMP_FPRS = [SpecialRegister.new("$f16")]
+MIPS_SCRATCH_FPR = SpecialRegister.new("$f18")
+
+def mipsMoveImmediate(value, register)
+ if value == 0
+ $asm.puts "add #{register.mipsOperand}, $zero, $zero"
+ else
+ $asm.puts "li #{register.mipsOperand}, #{value}"
+ end
+end
+
+class RegisterID
+ def mipsOperand
+ case name
+ when "a0"
+ "$a0"
+ when "a1"
+ "$a1"
+ when "r0", "t0"
+ "$v0"
+ when "r1", "t1"
+ "$v1"
+ when "t2"
+ "$t2"
+ when "t3"
+ "$s3"
+ when "t4" # PC reg in llint
+ "$s2"
+ when "t5"
+ "$t5"
+ when "t6"
+ "$t6"
+ when "t7"
+ "$t7"
+ when "t8"
+ "$t8"
+ when "cfr"
+ "$s0"
+ when "lr"
+ "$ra"
+ when "sp"
+ "$sp"
+ else
+ raise "Bad register #{name} for MIPS at #{codeOriginString}"
+ end
+ end
+end
+
+class FPRegisterID
+ def mipsOperand
+ case name
+ when "ft0", "fr"
+ "$f0"
+ when "ft1"
+ "$f2"
+ when "ft2"
+ "$f4"
+ when "ft3"
+ "$f6"
+ when "ft4"
+ "$f8"
+ when "ft5"
+ "$f10"
+ when "fa0"
+ "$f12"
+ when "fa1"
+ "$f14"
+ else
+ raise "Bad register #{name} for MIPS at #{codeOriginString}"
+ end
+ end
+end
+
+class Immediate
+ def mipsOperand
+ raise "Invalid immediate #{value} at #{codeOriginString}" if value < -0x7fff or value > 0x7fff
+ "#{value}"
+ end
+end
+
+class Address
+ def mipsOperand
+ raise "Bad offset at #{codeOriginString}" if offset.value < -0x7fff or offset.value > 0x7fff
+ "#{offset.value}(#{base.mipsOperand})"
+ end
+end
+
+class AbsoluteAddress
+ def mipsOperand
+ raise "Unconverted absolute address at #{codeOriginString}"
+ end
+end
+
+#
+# Lower 'and' masked branches
+#
+
+def lowerMIPSCondBranch(list, condOp, node)
+ if node.operands.size == 2
+ list << Instruction.new(node.codeOrigin,
+ condOp,
+ [node.operands[0], MIPS_ZERO_REG, node.operands[-1]],
+ node.annotation)
+ elsif node.operands.size == 3
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ list << Instruction.new(node.codeOrigin,
+ "andi",
+ [node.operands[0], node.operands[1], tmp],
+ node.annotation)
+ list << Instruction.new(node.codeOrigin,
+ condOp,
+ [tmp, MIPS_ZERO_REG, node.operands[-1]])
+ else
+ raise "Expected 2 or 3 operands but got #{node.operands.size} at #{node.codeOriginString}"
+ end
+end
+
+#
+# Lowering of branch ops. For example:
+#
+# baddiz foo, bar, baz
+#
+# will become:
+#
+# addi foo, bar
+# bz baz
+#
+
+def mipsLowerSimpleBranchOps(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ annotation = node.annotation
+ case node.opcode
+ when /^b(addi|subi|ori|addp)/
+ op = $1
+ bc = $~.post_match
+ branch = "b" + bc
+
+ case op
+ when "addi", "addp"
+ op = "addi"
+ when "subi"
+ op = "subi"
+ when "ori"
+ op = "ori"
+ end
+
+ if bc == "o"
+ case op
+ when "addi"
+ # addu $s0, $s1, $s2
+ # xor $t0, $s1, $s2
+ # blt $t0, $zero, no overflow
+ # xor $t0, $s0, $s1
+ # blt $t0, $zero, overflow
+ # no overflow:
+ #
+ tr = Tmp.new(node.codeOrigin, :gpr)
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ noFlow = LocalLabel.unique("noflow")
+ noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow)
+ newList << Instruction.new(node.codeOrigin, op, [node.operands[0], node.operands[1], tr], annotation)
+ newList << Instruction.new(node.codeOrigin, "xori", [node.operands[0], node.operands[1], tmp])
+ newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, noFlowRef])
+ newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[0], tmp])
+ newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]])
+ newList << noFlow
+ newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
+ when "subi"
+ # subu $s0, $s1, $s2
+ # xor $t0, $s1, $s2
+ # bge $t0, $zero, no overflow
+ # xor $t0, $s0, $s1
+ # blt $t0, $zero, overflow
+ # no overflow:
+ #
+ tr = Tmp.new(node.codeOrigin, :gpr)
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ noFlow = LocalLabel.unique("noflow")
+ noFlowRef = LocalLabelReference.new(node.codeOrigin, noFlow)
+ newList << Instruction.new(node.codeOrigin, op, [node.operands[1], node.operands[0], tr], annotation)
+ newList << Instruction.new(node.codeOrigin, "xori", [node.operands[1], node.operands[0], tmp])
+ newList << Instruction.new(node.codeOrigin, "bigteq", [tmp, MIPS_ZERO_REG, noFlowRef])
+ newList << Instruction.new(node.codeOrigin, "xori", [tr, node.operands[1], tmp])
+ newList << Instruction.new(node.codeOrigin, "bilt", [tmp, MIPS_ZERO_REG, node.operands[2]])
+ newList << noFlow
+ newList << Instruction.new(node.codeOrigin, "move", [tr, node.operands[1]])
+ when "ori"
+ # no ovwerflow at ori
+ newList << Instruction.new(node.codeOrigin, op, node.operands[0..1], annotation)
+ end
+ else
+ if node.operands[1].is_a? Address
+ addr = node.operands[1]
+ tr = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "loadp", [addr, tr], annotation)
+ newList << Instruction.new(node.codeOrigin, op, [node.operands[0], tr])
+ newList << Instruction.new(node.codeOrigin, "storep", [tr, addr])
+ else
+ tr = node.operands[1]
+ newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2], annotation)
+ end
+ newList << Instruction.new(node.codeOrigin, branch, [tr, MIPS_ZERO_REG, node.operands[-1]])
+ end
+ when "bia", "bpa", "bba"
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ comp = node.opcode[1] == ?b ? "sltub" : "sltu"
+ newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation)
+ newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]])
+ when "biaeq", "bpaeq", "bbaeq"
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ comp = node.opcode[1] == ?b ? "sltub" : "sltu"
+ newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation)
+ newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]])
+ when "bib", "bpb", "bbb"
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ comp = node.opcode[1] == ?b ? "sltub" : "sltu"
+ newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[0], node.operands[1]], annotation)
+ newList << Instruction.new(node.codeOrigin, "bnz", [tmp, MIPS_ZERO_REG, node.operands[2]])
+ when "bibeq", "bpbeq", "bbbeq"
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ comp = node.opcode[1] == ?b ? "sltub" : "sltu"
+ newList << Instruction.new(node.codeOrigin, comp, [tmp, node.operands[1], node.operands[0]], annotation)
+ newList << Instruction.new(node.codeOrigin, "bz", [tmp, MIPS_ZERO_REG, node.operands[2]])
+ when /^bt(i|p|b)/
+ lowerMIPSCondBranch(newList, "b" + $~.post_match + $1, node)
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Specialization of lowering of malformed BaseIndex addresses.
+#
+
+class Node
+ def mipsLowerMalformedAddressesRecurse(list, topLevelNode, &block)
+ mapChildren {
+ | subNode |
+ subNode.mipsLowerMalformedAddressesRecurse(list, topLevelNode, &block)
+ }
+ end
+end
+
+class Address
+ def mipsLowerMalformedAddressesRecurse(list, node, &block)
+ riscLowerMalformedAddressesRecurse(list, node, &block)
+ end
+end
+
+class BaseIndex
+ def mipsLowerMalformedAddressesRecurse(list, node, &block)
+ if scaleShift == 0
+ tmp0 = Tmp.new(codeOrigin, :gpr)
+ list << Instruction.new(codeOrigin, "addp", [base, index, tmp0])
+ Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value));
+ else
+ tmp0 = Tmp.new(codeOrigin, :gpr)
+ list << Instruction.new(codeOrigin, "lshifti", [index, Immediate.new(codeOrigin, scaleShift), tmp0]);
+ list << Instruction.new(codeOrigin, "addp", [base, tmp0])
+ Address.new(codeOrigin, tmp0, Immediate.new(codeOrigin, offset.value));
+ end
+ end
+end
+
+class AbsoluteAddress
+ def mipsLowerMalformedAddressesRecurse(list, node, &block)
+ riscLowerMalformedAddressesRecurse(list, node, &block)
+ end
+end
+
+def mipsLowerMalformedAddresses(list, &block)
+ newList = []
+ list.each {
+ | node |
+ newList << node.mipsLowerMalformedAddressesRecurse(newList, node, &block)
+ }
+ newList
+end
+
+#
+# Lowering of misplaced immediates of MIPS specific instructions. For example:
+#
+# sltu reg, 4, 2
+#
+# will become:
+#
+# move 4, tmp
+# sltu reg, tmp, 2
+#
+
+def mipsLowerMisplacedImmediates(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "slt", "sltu", "sltb", "sltub"
+ if node.operands[1].is_a? Immediate
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp], node.annotation)
+ newList << Instruction.new(node.codeOrigin, node.opcode,
+ [node.operands[0], tmp, node.operands[2]],
+ node.annotation)
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Specialization of lowering of misplaced addresses.
+#
+
+def mipsLowerMisplacedAddresses(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ postInstructions = []
+ annotation = node.annotation
+ case node.opcode
+ when "jmp"
+ if node.operands[0].address?
+ newList << Instruction.new(node.operands[0].codeOrigin, "loadi", [node.operands[0], MIPS_JUMP_REG])
+ newList << Instruction.new(node.codeOrigin, node.opcode, [MIPS_JUMP_REG])
+ else
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ [riscAsRegister(newList, postInstructions, node.operands[0], "p", false)])
+ end
+ when "call"
+ restoreGP = false;
+ tmp = MIPS_CALL_REG
+ if node.operands[0].address?
+ newList << Instruction.new(node.operands[0].codeOrigin, "loadp", [node.operands[0], MIPS_CALL_REG])
+ restoreGP = true;
+ elsif node.operands[0].is_a? LabelReference
+ tmp = node.operands[0]
+ restoreGP = true;
+ elsif node.operands[0].register?
+ newList << Instruction.new(node.operands[0].codeOrigin, "move", [node.operands[0], MIPS_CALL_REG])
+ restoreGP = true;
+ else
+ tmp = node.operands[0]
+ end
+ newList << Instruction.new(node.codeOrigin, node.opcode, [tmp])
+ if restoreGP
+ newList << Instruction.new(node.codeOrigin, "move", [MIPS_GPSAVE_REG, MIPS_GP_REG])
+ end
+ when "slt", "sltu"
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, [], node.operands, "i"))
+ when "sltub", "sltb"
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, [], node.operands, "b"))
+ when /^(bz|bnz|bs|bo)/
+ tl = $~.post_match == "" ? "i" : $~.post_match
+ newList << Instruction.new(node.codeOrigin,
+ node.opcode,
+ riscAsRegisters(newList, [], node.operands, tl))
+ else
+ newList << node
+ end
+ newList += postInstructions
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lowering compares and tests.
+#
+
+def mipsLowerCompareTemplate(list, node, opCmp, opMov)
+ tmp0 = Tmp.new(node.codeOrigin, :gpr)
+ tmp1 = Tmp.new(node.codeOrigin, :gpr)
+ list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 0), node.operands[2]])
+ list << Instruction.new(node.codeOrigin, opCmp, [node.operands[1], node.operands[0], tmp0])
+ list << Instruction.new(node.codeOrigin, "move", [Immediate.new(nil, 1), tmp1])
+ list << Instruction.new(node.codeOrigin, opMov, [node.operands[2], tmp1, tmp0])
+end
+
+def mipsLowerCompares(list)
+ newList = []
+ list.each {
+ | node |
+ if node.is_a? Instruction
+ case node.opcode
+ when "cieq", "cpeq", "cbeq"
+ mipsLowerCompareTemplate(newList, node, "subp", "movz")
+ when "cineq", "cpneq", "cbneq"
+ mipsLowerCompareTemplate(newList, node, "subp", "movn")
+ when "tiz", "tbz", "tpz"
+ mipsLowerCompareTemplate(newList, node, "andp", "movz")
+ when "tinz", "tbnz", "tpnz"
+ mipsLowerCompareTemplate(newList, node, "andp", "movn")
+ when "tio", "tbo", "tpo"
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp])
+ list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], MIPS_ZERO_REG, tmp])
+ when "tis", "tbs", "tps"
+ tmp = Tmp.new(node.codeOrigin, :gpr)
+ list << Instruction.new(node.codeOrigin, "andp", [node.operands[1], node.operands[0], tmp])
+ list << Instruction.new(node.codeOrigin, "slt", [node.operands[2], tmp, MIPS_ZERO_REG])
+ else
+ newList << node
+ end
+ else
+ newList << node
+ end
+ }
+ newList
+end
+
+#
+# Lea support.
+#
+
+class Address
+ def mipsEmitLea(destination)
+ if destination == base
+ $asm.puts "addiu #{destination.mipsOperand}, #{offset.value}"
+ else
+ $asm.puts "addiu #{destination.mipsOperand}, #{base.mipsOperand}, #{offset.value}"
+ end
+ end
+end
+
+#
+# Add PIC compatible header code to prologue/entry rutins.
+#
+
+def mipsAddPICCode(list)
+ myList = []
+ list.each {
+ | node |
+ myList << node
+ if node.is_a? Label
+ if /_prologue$/.match(node.name) || /^_llint_function_/.match(node.name)
+ # Functions called from trampoline/JIT codes.
+ myList << Instruction.new(node.codeOrigin, "pichdr", [])
+ elsif /_llint_op_catch/.match(node.name)
+ # Exception cactcher entry point function.
+ myList << Instruction.new(node.codeOrigin, "pichdrra", [])
+ end
+ end
+ }
+ myList
+end
+
+#
+# Actual lowering code follows.
+#
+
+class Sequence
+ def getModifiedListMIPS
+ result = @list
+
+ # Verify that we will only see instructions and labels.
+ result.each {
+ | node |
+ unless node.is_a? Instruction or
+ node.is_a? Label or
+ node.is_a? LocalLabel or
+ node.is_a? Skip
+ raise "Unexpected #{node.inspect} at #{node.codeOrigin}"
+ end
+ }
+
+ result = mipsAddPICCode(result)
+ result = mipsLowerSimpleBranchOps(result)
+ result = riscLowerSimpleBranchOps(result)
+ result = riscLowerHardBranchOps(result)
+ result = riscLowerShiftOps(result)
+ result = mipsLowerMalformedAddresses(result) {
+ | node, address |
+ if address.is_a? Address
+ (-0xffff..0xffff).include? address.offset.value
+ else
+ false
+ end
+ }
+ result = riscLowerMalformedAddressesDouble(result)
+ result = riscLowerMisplacedImmediates(result)
+ result = mipsLowerMisplacedImmediates(result)
+ result = riscLowerMalformedImmediates(result, -0xffff..0xffff)
+ result = mipsLowerMisplacedAddresses(result)
+ result = riscLowerMisplacedAddresses(result)
+ result = riscLowerRegisterReuse(result)
+ result = mipsLowerCompares(result)
+ result = assignRegistersToTemporaries(result, :gpr, MIPS_TEMP_GPRS)
+ result = assignRegistersToTemporaries(result, :fpr, MIPS_TEMP_FPRS)
+
+ return result
+ end
+end
+
+def mipsOperands(operands)
+ operands.map{|v| v.mipsOperand}.join(", ")
+end
+
+def mipsFlippedOperands(operands)
+ mipsOperands([operands[-1]] + operands[0..-2])
+end
+
+def getMIPSOpcode(opcode, suffix)
+
+end
+
+def emitMIPSCompact(opcode, opcodei, operands)
+ postfix = ""
+ if opcode == "sub"
+ if operands[0].is_a? Immediate
+ opcode = "add"
+ operands[0] = Immediate.new(operands[0].codeOrigin, -1 * operands[0].value)
+ elsif operands[1].is_a? Immediate
+ opcode = "add"
+ operands[1] = Immediate.new(operands[1].codeOrigin, -1 * operands[1].value)
+ end
+ postfix = "u"
+ elsif opcode == "add"
+ postfix = "u"
+ end
+ if operands.size == 3
+ if operands[0].is_a? Immediate
+ $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
+ elsif operands[1].is_a? Immediate
+ $asm.puts "#{opcode}i#{postfix} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
+ else
+ $asm.puts "#{opcode}#{postfix} #{mipsFlippedOperands(operands)}"
+ end
+ else
+ raise unless operands.size == 2
+ raise unless operands[1].register?
+ if operands[0].is_a? Immediate
+ $asm.puts "#{opcode}i#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ else
+ $asm.puts "#{opcode}#{postfix} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ end
+ end
+end
+
+def emitMIPSShiftCompact(opcode, operands)
+ if operands.size == 3
+ if (operands[1].is_a? Immediate)
+ $asm.puts "#{opcode} #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].value}"
+ else
+ $asm.puts "#{opcode}v #{mipsFlippedOperands(operands)}"
+ end
+ else
+ raise unless operands.size == 2
+ if operands[0].register?
+ $asm.puts "#{opcode}v #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ else
+ $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].value}"
+ end
+ end
+end
+
+def emitMIPS(opcode, operands)
+ if operands.size == 3
+ $asm.puts "#{opcode} #{mipsFlippedOperands(operands)}"
+ else
+ raise unless operands.size == 2
+ $asm.puts "#{opcode} #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ end
+end
+
+def emitMIPSDoubleBranch(branchOpcode, neg, operands)
+ $asm.puts "c.#{branchOpcode}.d #{mipsOperands(operands[0..1])}"
+ if (!neg)
+ $asm.puts "bc1t #{operands[2].asmLabel}"
+ else
+ $asm.puts "bc1f #{operands[2].asmLabel}"
+ end
+end
+
+class Instruction
+ def lowerMIPS
+ $asm.comment codeOriginString
+ case opcode
+ when "addi", "addp", "addis"
+ if operands.size == 3 and operands[0].is_a? Immediate
+ raise unless operands[1].register?
+ raise unless operands[2].register?
+ if operands[0].value == 0 #and suffix.empty?
+ unless operands[1] == operands[2]
+ $asm.puts "move #{operands[2].mipsOperand}, #{operands[1].mipsOperand}"
+ end
+ else
+ $asm.puts "addiu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ end
+ elsif operands.size == 3 and operands[0].register?
+ raise unless operands[1].register?
+ raise unless operands[2].register?
+ $asm.puts "addu #{mipsFlippedOperands(operands)}"
+ else
+ if operands[0].is_a? Immediate
+ unless Immediate.new(nil, 0) == operands[0]
+ $asm.puts "addiu #{operands[1].mipsOperand}, #{mipsFlippedOperands(operands)}"
+ end
+ else
+ $asm.puts "addu #{operands[1].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ end
+ end
+ when "andi", "andp"
+ emitMIPSCompact("and", "and", operands)
+ when "ori", "orp"
+ emitMIPSCompact("or", "orr", operands)
+ when "oris"
+ emitMIPSCompact("or", "orrs", operands)
+ when "xori", "xorp"
+ emitMIPSCompact("xor", "eor", operands)
+ when "lshifti", "lshiftp"
+ emitMIPSShiftCompact("sll", operands)
+ when "rshifti", "rshiftp"
+ emitMIPSShiftCompact("sra", operands)
+ when "urshifti", "urshiftp"
+ emitMIPSShiftCompact("srl", operands)
+ when "muli", "mulp"
+ emitMIPS("mul", operands)
+ when "subi", "subp", "subis"
+ emitMIPSCompact("sub", "subs", operands)
+ when "negi", "negp"
+ $asm.puts "negu #{operands[0].mipsOperand}, #{operands[0].mipsOperand}"
+ when "noti"
+ $asm.puts "nor #{operands[0].mipsOperand}, #{operands[0].mipsOperand}, $zero"
+ when "loadi", "loadis", "loadp"
+ $asm.puts "lw #{mipsFlippedOperands(operands)}"
+ when "storei", "storep"
+ $asm.puts "sw #{mipsOperands(operands)}"
+ when "loadb"
+ $asm.puts "lbu #{mipsFlippedOperands(operands)}"
+ when "loadbs"
+ $asm.puts "lb #{mipsFlippedOperands(operands)}"
+ when "storeb"
+ $asm.puts "sb #{mipsOperands(operands)}"
+ when "loadh"
+ $asm.puts "lhu #{mipsFlippedOperands(operands)}"
+ when "loadhs"
+ $asm.puts "lh #{mipsFlippedOperands(operands)}"
+ when "storeh"
+ $asm.puts "shv #{mipsOperands(operands)}"
+ when "loadd"
+ $asm.puts "ldc1 #{mipsFlippedOperands(operands)}"
+ when "stored"
+ $asm.puts "sdc1 #{mipsOperands(operands)}"
+ when "addd"
+ emitMIPS("add.d", operands)
+ when "divd"
+ emitMIPS("div.d", operands)
+ when "subd"
+ emitMIPS("sub.d", operands)
+ when "muld"
+ emitMIPS("mul.d", operands)
+ when "sqrtd"
+ $asm.puts "sqrt.d #{mipsFlippedOperands(operands)}"
+ when "ci2d"
+ raise "invalid ops of #{self.inspect} at #{codeOriginString}" unless operands[1].is_a? FPRegisterID and operands[0].register?
+ $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
+ $asm.puts "cvt.d.w #{operands[1].mipsOperand}, #{operands[1].mipsOperand}"
+ when "bdeq"
+ emitMIPSDoubleBranch("eq", false, operands)
+ when "bdneq"
+ emitMIPSDoubleBranch("ueq", true, operands)
+ when "bdgt"
+ emitMIPSDoubleBranch("ule", true, operands)
+ when "bdgteq"
+ emitMIPSDoubleBranch("ult", true, operands)
+ when "bdlt"
+ emitMIPSDoubleBranch("olt", false, operands)
+ when "bdlteq"
+ emitMIPSDoubleBranch("ole", false, operands)
+ when "bdequn"
+ emitMIPSDoubleBranch("ueq", false, operands)
+ when "bdnequn"
+ emitMIPSDoubleBranch("eq", true, operands)
+ when "bdgtun"
+ emitMIPSDoubleBranch("ole", true, operands)
+ when "bdgtequn"
+ emitMIPSDoubleBranch("olt", true, operands)
+ when "bdltun"
+ emitMIPSDoubleBranch("ult", false, operands)
+ when "bdltequn"
+ emitMIPSDoubleBranch("ule", false, operands)
+ when "btd2i"
+ # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
+ # currently does not use it.
+ raise "MIPS does not support this opcode yet, #{codeOrigin}"
+ when "td2i"
+ $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
+ $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
+ when "bcd2i"
+ $asm.puts "cvt.w.d #{MIPS_SCRATCH_FPR.mipsSingleLo}, #{operands[0].mipsOperand}"
+ $asm.puts "mfc1 #{operands[1].mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
+ $asm.puts "cvt.d.w #{MIPS_SCRATCH_FPR.mipsOperand}, #{MIPS_SCRATCH_FPR.mipsSingleLo}"
+ emitMIPSDoubleBranch("eq", true, [MIPS_SCRATCH_FPR, operands[0], operands[2]])
+ $asm.puts "beq #{operands[1].mipsOperand}, $zero, #{operands[2].asmLabel}"
+ when "movdz"
+ # FIXME: either support this or remove it.
+ raise "MIPS does not support this opcode yet, #{codeOrigin}"
+ when "pop"
+ $asm.puts "lw #{operands[0].mipsOperand}, 0($sp)"
+ $asm.puts "addiu $sp, $sp, 4"
+ when "push"
+ $asm.puts "addiu $sp, $sp, -4"
+ $asm.puts "sw #{operands[0].mipsOperand}, 0($sp)"
+ when "move", "sxi2p", "zxi2p"
+ if operands[0].is_a? Immediate
+ mipsMoveImmediate(operands[0].value, operands[1])
+ else
+ $asm.puts "move #{mipsFlippedOperands(operands)}"
+ end
+ when "nop"
+ $asm.puts "nop"
+ when "bieq", "bpeq", "bbeq"
+ $asm.puts "beq #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
+ when "bineq", "bpneq", "bbneq"
+ $asm.puts "bne #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
+ when "bigt", "bpgt", "bbgt"
+ $asm.puts "bgt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
+ when "bigteq", "bpgteq", "bbgteq"
+ $asm.puts "bge #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
+ when "bilt", "bplt", "bblt"
+ $asm.puts "blt #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
+ when "bilteq", "bplteq", "bblteq"
+ $asm.puts "ble #{mipsOperands(operands[0..1])}, #{operands[2].asmLabel}"
+ when "jmp"
+ if operands[0].label?
+ $asm.puts "j #{operands[0].asmLabel}"
+ else
+ $asm.puts "jr #{operands[0].mipsOperand}"
+ end
+ when "call"
+ if operands[0].label?
+ $asm.puts "jal #{operands[0].asmLabel}"
+ else
+ $asm.puts "jalr #{operands[0].mipsOperand}"
+ end
+ when "break"
+ $asm.puts "break"
+ when "ret"
+ $asm.puts "jr $ra"
+ when "cia", "cpa", "cba"
+ $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ when "ciaeq", "cpaeq", "cbaeq"
+ $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
+ $asm.puts "xori #{operands[2].mipsOperand}, 1"
+ when "cib", "cpb", "cbb"
+ $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
+ when "cibeq", "cpbeq", "cbbeq"
+ $asm.puts "sltu #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ $asm.puts "xori #{operands[2].mipsOperand}, 1"
+ when "cigt", "cpgt", "cbgt"
+ $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ when "cigteq", "cpgteq", "cbgteq"
+ $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
+ $asm.puts "xori #{operands[2].mipsOperand}, 1"
+ when "cilt", "cplt", "cblt"
+ $asm.puts "slt #{operands[2].mipsOperand}, #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
+ when "cilteq", "cplteq", "cblteq"
+ $asm.puts "slt #{operands[2].mipsOperand}, #{operands[1].mipsOperand}, #{operands[0].mipsOperand}"
+ $asm.puts "xori #{operands[2].mipsOperand}, 1"
+ when "peek"
+ $asm.puts "lw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
+ when "poke"
+ $asm.puts "sw #{operands[1].mipsOperand}, #{operands[0].value * 4}($sp)"
+ when "fii2d"
+ $asm.puts "mtc1 #{operands[0].mipsOperand}, #{operands[2].mipsSingleLo}"
+ $asm.puts "mtc1 #{operands[1].mipsOperand}, #{operands[2].mipsSingleHi}"
+ when "fd2ii"
+ $asm.puts "mfc1 #{operands[1].mipsOperand}, #{operands[0].mipsSingleLo}"
+ $asm.puts "mfc1 #{operands[2].mipsOperand}, #{operands[0].mipsSingleHi}"
+ when /^bo/
+ $asm.puts "bgt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
+ when /^bs/
+ $asm.puts "blt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
+ when /^bz/
+ $asm.puts "beq #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
+ when /^bnz/
+ $asm.puts "bne #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].asmLabel}"
+ when "leai", "leap"
+ operands[0].mipsEmitLea(operands[1])
+ when "smulli"
+ raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4
+ $asm.puts "mult #{operands[0].mipsOperand}, #{operands[1].mipsOperand}"
+ $asm.puts "mflo #{operands[2].mipsOperand}"
+ $asm.puts "mfhi #{operands[3].mipsOperand}"
+ when "movz"
+ $asm.puts "movz #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
+ when "movn"
+ $asm.puts "movn #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
+ when "slt", "sltb"
+ $asm.puts "slt #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
+ when "sltu", "sltub"
+ $asm.puts "sltu #{operands[0].mipsOperand}, #{operands[1].mipsOperand}, #{operands[2].mipsOperand}"
+ when "pichdr"
+ $asm.putStr("OFFLINE_ASM_CPLOAD($25)")
+ $asm.puts "move $s4, $gp"
+ when "pichdrra"
+ $asm.putStr("OFFLINE_ASM_CPLOAD($31)")
+ $asm.puts "move $s4, $gp"
+ else
+ raise "Unhandled opcode #{opcode} at #{codeOriginString}"
+ end
+ end
+end
diff --git a/Source/JavaScriptCore/offlineasm/risc.rb b/Source/JavaScriptCore/offlineasm/risc.rb
index 44b4dbd71..7408253af 100644
--- a/Source/JavaScriptCore/offlineasm/risc.rb
+++ b/Source/JavaScriptCore/offlineasm/risc.rb
@@ -187,7 +187,7 @@ class Node
end
class Address
- def riscLowerMalformedAddressesRecurse(list, node)
+ def riscLowerMalformedAddressesRecurse(list, node, &block)
return self if yield node, self
tmp = Tmp.new(codeOrigin, :gpr)
@@ -208,7 +208,7 @@ class BaseIndex
end
class AbsoluteAddress
- def riscLowerMalformedAddressesRecurse(list, node)
+ def riscLowerMalformedAddressesRecurse(list, node, &block)
return self if yield node, self
tmp = Tmp.new(codeOrigin, :gpr)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h
index 0ffaccb6a..01e6059da 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -129,14 +129,18 @@ namespace JSC {
return result;
}
- static size_t allocationSize(size_t bufferSize) { return sizeof(size_t) + bufferSize; }
+ static size_t allocationSize(size_t bufferSize) { return sizeof(ScratchBuffer) + bufferSize; }
void setActiveLength(size_t activeLength) { m_activeLength = activeLength; }
size_t activeLength() const { return m_activeLength; };
size_t* activeLengthPtr() { return &m_activeLength; };
void* dataBuffer() { return m_buffer; }
size_t m_activeLength;
+#if CPU(MIPS) && (defined WTF_MIPS_ARCH_REV && WTF_MIPS_ARCH_REV == 2)
+ void* m_buffer[0] __attribute__((aligned(8)));
+#else
void* m_buffer[0];
+#endif
};
#if COMPILER(MSVC)
#pragma warning(pop)