+2008-09-21 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver.
+
+ - speed up === operator by generating inline machine code for the fast paths
+ https://bugs.webkit.org/show_bug.cgi?id=20820
+
+ * VM/CTI.cpp:
+ (JSC::CTI::emitJumpSlowCaseIfNotImmediateNumber):
+ (JSC::CTI::emitJumpSlowCaseIfNotImmediateNumbers):
+ (JSC::CTI::emitJumpSlowCaseIfNotImmediates):
+ (JSC::CTI::emitTagAsBoolImmediate):
+ (JSC::CTI::privateCompileMainPass):
+ (JSC::CTI::privateCompileSlowCases):
+ * VM/CTI.h:
+ * VM/Machine.cpp:
+ (JSC::Machine::cti_op_stricteq):
+ * masm/X86Assembler.h:
+ (JSC::X86Assembler::):
+ (JSC::X86Assembler::sete_r):
+ (JSC::X86Assembler::setz_r):
+ (JSC::X86Assembler::movzbl_rr):
+ (JSC::X86Assembler::emitUnlinkedJnz):
+
2008-09-21 Cameron Zwarich <cwzwarich@uwaterloo.ca>
Reviewed by Maciej Stachowiak.
emitFastArithReTagImmediate(reg);
}
+ALWAYS_INLINE void CTI::emitTagAsBoolImmediate(X86Assembler::RegisterID reg)
+{
+ m_jit.shl_i8r(JSImmediate::ExtendedPayloadShift, reg);
+ m_jit.orl_i32r(JSImmediate::FullTagTypeBool, reg);
+}
+
CTI::CTI(Machine* machine, ExecState* exec, CodeBlock* codeBlock)
: m_jit(machine->jitCodeBuffer())
, m_machine(machine)
CTI_COMPILE_UNARY_OP(op_is_string)
CTI_COMPILE_UNARY_OP(op_is_object)
CTI_COMPILE_UNARY_OP(op_is_function)
- CTI_COMPILE_BINARY_OP(op_stricteq)
CTI_COMPILE_BINARY_OP(op_nstricteq)
+ case op_stricteq: {
+ unsigned dst = instruction[i + 1].u.operand;
+ unsigned src1 = instruction[i + 2].u.operand;
+ unsigned src2 = instruction[i + 3].u.operand;
+
+ emitGetArg(src1, X86::eax);
+ emitGetArg(src2, X86::edx);
+
+ m_jit.testl_i32r(JSImmediate::TagMask, X86::eax);
+ X86Assembler::JmpSrc firstNotImmediate = m_jit.emitUnlinkedJe();
+ m_jit.testl_i32r(JSImmediate::TagMask, X86::edx);
+ X86Assembler::JmpSrc secondNotImmediate = m_jit.emitUnlinkedJe();
+
+ m_jit.cmpl_rr(X86::edx, X86::eax);
+ m_jit.sete_r(X86::eax);
+ m_jit.movzbl_rr(X86::eax, X86::eax);
+ emitTagAsBoolImmediate(X86::eax);
+
+ X86Assembler::JmpSrc bothWereImmediates = m_jit.emitUnlinkedJmp();
+
+ m_jit.link(firstNotImmediate, m_jit.label());
+
+ // check that edx is immediate but not the zero immediate
+
+ m_jit.testl_i32r(JSImmediate::TagMask, X86::edx);
+ m_jit.setz_r(X86::ecx);
+ m_jit.movzbl_rr(X86::ecx, X86::ecx); // ecx is now 1 if edx was nonimmediate
+ m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), X86::edx);
+ m_jit.sete_r(X86::edx);
+ m_jit.movzbl_rr(X86::edx, X86::edx); // edx is now 1 if edx was the 0 immediate
+ m_jit.orl_rr(X86::ecx, X86::edx);
+
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJnz(), i));
+
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(jsBoolean(false)), X86::eax);
+
+ X86Assembler::JmpSrc firstWasNotImmediate = m_jit.emitUnlinkedJmp();
+
+ m_jit.link(secondNotImmediate, m_jit.label());
+ // check that eax is not the zero immediate (we know it must be immediate)
+ m_jit.cmpl_i32r(reinterpret_cast<uint32_t>(JSImmediate::zeroImmediate()), X86::eax);
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i));
+
+ m_jit.movl_i32r(reinterpret_cast<uint32_t>(jsBoolean(false)), X86::eax);
+
+ m_jit.link(bothWereImmediates, m_jit.label());
+ m_jit.link(firstWasNotImmediate, m_jit.label());
+
+ emitPutResult(dst);
+
+ i += 4;
+ break;
+ }
case op_to_jsnumber: {
emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
emitCall(i, Machine::cti_op_to_jsnumber);
i += 4;
break;
}
+ CTI_COMPILE_BINARY_OP_SLOW_CASE(op_stricteq);
+
case op_mod: {
X86Assembler::JmpSrc notImm1 = iter->from;
X86Assembler::JmpSrc notImm2 = (++iter)->from;
JSValue* src1 = ARG_src1;
JSValue* src2 = ARG_src2;
- if (JSImmediate::areBothImmediate(src1, src2))
- return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
- if (JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate()))
- return jsBoolean(false);
+ // handled inline as fast cases
+ ASSERT(!JSImmediate::areBothImmediate(src1, src2));
+ ASSERT(!(JSImmediate::isEitherImmediate(src1, src2) & (src1 != JSImmediate::zeroImmediate()) & (src2 != JSImmediate::zeroImmediate())));
return jsBoolean(strictEqualSlowCaseInline(src1, src2));
}
OP_LEA = 0x8D,
OP_GROUP1A_Ev = 0x8F,
OP_CDQ = 0x99,
+ OP_SETE = 0x94,
OP_GROUP2_EvIb = 0xC1,
OP_RET = 0xC3,
OP_GROUP11_EvIz = 0xC7,
OP2_JGE_rel32 = 0x8D,
OP2_JLE_rel32 = 0x8E,
OP2_IMUL_GvEv = 0xAF,
+ OP2_MOVZX_GvEb = 0xB6,
OP2_MOVZX_GvEw = 0xB7,
GROUP1_OP_ADD = 0,
emitModRm_rmsib(src, base, index, scale);
}
+ void sete_r(RegisterID dst)
+ {
+ m_buffer->putByte(OP_2BYTE_ESCAPE);
+ m_buffer->putByte(OP_SETE);
+ m_buffer->putByte(MODRM(3, 0, dst));
+ }
+
+ void setz_r(RegisterID dst)
+ {
+ sete_r(dst);
+ }
+
void orl_rr(RegisterID src, RegisterID dst)
{
m_buffer->putByte(OP_OR_EvGv);
emitModRm_rmsib(dst, base, index, scale, offset);
}
+ void movzbl_rr(RegisterID src, RegisterID dst)
+ {
+ m_buffer->putByte(OP_2BYTE_ESCAPE);
+ m_buffer->putByte(OP2_MOVZX_GvEb);
+ emitModRm_rr(dst, src);
+ }
+
void movzwl_mr(int offset, RegisterID base, RegisterID dst)
{
m_buffer->putByte(OP_2BYTE_ESCAPE);
return JmpSrc(m_buffer->getOffset());
}
+ JmpSrc emitUnlinkedJnz()
+ {
+ return emitUnlinkedJne();
+ }
+
JmpSrc emitUnlinkedJe()
{
m_buffer->ensureSpace(MAX_INSTRUCTION_SIZE);