-2008-09-14 Sam Weinig <sam@webkit.org>
+2008-09-14 Cameron Zwarich <cwzwarich@uwaterloo.ca>
- Reviewed by Mark Rowe.
+ Reviewed by Oliver Hunt.
- Remove extraneous semicolons.
+ Bug 20816: op_lesseq should be optimized
+ <https://bugs.webkit.org/show_bug.cgi?id=20816>
- * kjs/nodes.cpp:
- (JSC::PrefixResolveNode::emitCode):
- * wtf/FastMalloc.cpp:
- (WTF::TCMalloc_PageHeap::GrowHeap):
+ Add a loop_if_lesseq opcode that is similar to the loop_if_less opcode.
+
+ This is a 9.4% speedup on the V8 Crypto benchmark.
+
+ * VM/CTI.cpp:
+ (JSC::CTI::privateCompileMainPass):
+ (JSC::CTI::privateCompileSlowCases):
+ * VM/CodeBlock.cpp:
+ (JSC::CodeBlock::dump):
+ * VM/CodeGenerator.cpp:
+ (JSC::CodeGenerator::emitJumpIfTrue):
+ * VM/Machine.cpp:
+ (JSC::Machine::privateExecute):
+ (JSC::Machine::cti_op_loop_if_lesseq):
+ * VM/Machine.h:
+ * VM/Opcode.h:
2008-09-14 Sam Weinig <sam@webkit.org>
i += 4;
break;
}
+ case op_loop_if_lesseq: {
+ emitSlowScriptCheck(i);
+
+ unsigned target = instruction[i + 3].u.operand;
+ JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+ if (src2imm) {
+ emitGetArg(instruction[i + 1].u.operand, X86::edx);
+ emitJumpSlowCaseIfNotImm(X86::edx, i);
+ m_jit.cmpl_i32r(reinterpret_cast<unsigned>(src2imm), X86::edx);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJle(), i + 3 + target));
+ } else {
+ emitGetArg(instruction[i + 1].u.operand, X86::eax);
+ emitGetArg(instruction[i + 2].u.operand, X86::edx);
+ emitJumpSlowCaseIfNotImm(X86::eax, i);
+ emitJumpSlowCaseIfNotImm(X86::edx, i);
+ m_jit.cmpl_rr(X86::edx, X86::eax);
+ m_jmpTable.append(JmpTable(m_jit.emitUnlinkedJle(), i + 3 + target));
+ }
+ i += 4;
+ break;
+ }
case op_new_object: {
emitCall(i, Machine::cti_op_new_object);
emitPutResult(instruction[i + 1].u.operand);
i += 4;
break;
}
+ case op_loop_if_lesseq: {
+ emitSlowScriptCheck(i);
+
+ unsigned target = instruction[i + 3].u.operand;
+ JSValue* src2imm = getConstantImmediateNumericArg(instruction[i + 2].u.operand);
+ if (src2imm) {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(X86::edx, 0);
+ emitGetPutArg(instruction[i + 2].u.operand, 4, X86::ecx);
+ emitCall(i, Machine::cti_op_loop_if_lesseq);
+ m_jit.testl_rr(X86::eax, X86::eax);
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
+ } else {
+ m_jit.link(iter->from, m_jit.label());
+ m_jit.link((++iter)->from, m_jit.label());
+ emitPutArg(X86::eax, 0);
+ emitPutArg(X86::edx, 4);
+ emitCall(i, Machine::cti_op_loop_if_lesseq);
+ m_jit.testl_rr(X86::eax, X86::eax);
+ m_jit.link(m_jit.emitUnlinkedJne(), m_labels[i + 3 + target]);
+ }
+ i += 4;
+ break;
+ }
case op_pre_inc: {
unsigned srcDst = instruction[i + 1].u.operand;
X86Assembler::JmpSrc notImm = iter->from;
printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
break;
}
+ case op_loop_if_lesseq: {
+ int r0 = (++it)->u.operand;
+ int r1 = (++it)->u.operand;
+ int offset = (++it)->u.operand;
+ printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset));
+ break;
+ }
case op_switch_imm: {
int tableIndex = (++it)->u.operand;
int defaultTarget = (++it)->u.operand;
instructions().append(target->offsetFrom(instructions().size()));
return target;
}
+ } else if (m_lastOpcodeID == op_lesseq && !target->isForwardLabel()) {
+ int dstIndex;
+ int src1Index;
+ int src2Index;
+
+ retrieveLastBinaryOp(dstIndex, src1Index, src2Index);
+
+ if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) {
+ rewindBinaryOp();
+ emitOpcode(op_loop_if_lesseq);
+ instructions().append(src1Index);
+ instructions().append(src2Index);
+ instructions().append(target->offsetFrom(instructions().size()));
+ return target;
+ }
}
emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true);
++vPC;
NEXT_OPCODE;
}
+ BEGIN_OPCODE(op_loop_if_lesseq) {
+ /* loop_if_lesseq src1(r) src2(r) target(offset)
+
+ Checks whether register src1 is less than or equal to register
+ src2, as with the ECMAScript '<=' operator, and then jumps to
+ offset target from the current instruction, if and only if the
+ result of the comparison is true.
+
+ Additionally this loop instruction may terminate JS execution is
+ the JS timeout is reached.
+ */
+ JSValue* src1 = r[(++vPC)->u.operand].jsValue(exec);
+ JSValue* src2 = r[(++vPC)->u.operand].jsValue(exec);
+ int target = (++vPC)->u.operand;
+
+ bool result = jsLessEq(exec, src1, src2);
+ VM_CHECK_EXCEPTION();
+
+ if (result) {
+ vPC += target;
+ CHECK_FOR_TIMEOUT();
+ NEXT_OPCODE;
+ }
+
+ ++vPC;
+ NEXT_OPCODE;
+ }
BEGIN_OPCODE(op_jnless) {
/* jnless src1(r) src2(r) target(offset)
return result;
}
+int Machine::cti_op_loop_if_lesseq(CTI_ARGS)
+{
+ JSValue* src1 = ARG_src1;
+ JSValue* src2 = ARG_src2;
+ ExecState* exec = ARG_exec;
+
+ bool result = jsLessEq(exec, src1, src2);
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
+}
+
JSValue* Machine::cti_op_new_object(CTI_ARGS)
{
return constructEmptyObject(ARG_exec);;
static JSValue* SFX_CALL cti_op_add(CTI_ARGS);
static JSValue* SFX_CALL cti_op_pre_inc(CTI_ARGS);
static int SFX_CALL cti_op_loop_if_less(CTI_ARGS);
+ static int SFX_CALL cti_op_loop_if_lesseq(CTI_ARGS);
static JSValue* SFX_CALL cti_op_new_object(CTI_ARGS);
static void SFX_CALL cti_op_put_by_id(CTI_ARGS);
static void SFX_CALL cti_op_put_by_id_second(CTI_ARGS);
macro(op_loop) \
macro(op_loop_if_true) \
macro(op_loop_if_less) \
+ macro(op_loop_if_lesseq) \
macro(op_switch_imm) \
macro(op_switch_char) \
macro(op_switch_string) \