+2008-09-24 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ - inline JIT fast case of op_neq
+ - remove extra level of function call indirection from slow cases of eq and neq
+
+ 1% speedup on Richards
+
+ * VM/CTI.cpp:
+ (JSC::CTI::privateCompileMainPass):
+ (JSC::CTI::privateCompileSlowCases):
+ * VM/Machine.cpp:
+ (JSC::Machine::privateExecute):
+ (JSC::Machine::cti_op_eq):
+ (JSC::Machine::cti_op_neq):
+ * kjs/operations.cpp:
+ (JSC::equal):
+ (JSC::equalSlowCase):
+ * kjs/operations.h:
+ (JSC::equalSlowCaseInline):
+
2008-09-24 Sam Weinig <sam@webkit.org>
Reviewed by Darin Adler.
break;
}
CTI_COMPILE_BINARY_OP(op_less)
- CTI_COMPILE_BINARY_OP(op_neq)
+ case op_neq: {
+ emitGetArg(instruction[i + 2].u.operand, X86::eax);
+ emitGetArg(instruction[i + 3].u.operand, X86::edx);
+ emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
+ m_jit.cmpl_rr(X86::eax, X86::edx);
+
+ m_jit.setne_r(X86::eax);
+ m_jit.movzbl_rr(X86::eax, X86::eax);
+ emitTagAsBoolImmediate(X86::eax);
+
+ emitPutResult(instruction[i + 1].u.operand);
+
+ i += 4;
+ break;
+ }
case op_post_dec: {
int srcDst = instruction[i + 2].u.operand;
emitGetArg(srcDst, X86::eax);
i += 4;
break;
}
+ case op_neq: {
+ m_jit.link(iter->from, m_jit.label());
+ emitPutArg(X86::eax, 0);
+ emitPutArg(X86::edx, 4);
+ emitCall(i, Machine::cti_op_neq);
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 4;
+ break;
+ }
CTI_COMPILE_BINARY_OP_SLOW_CASE(op_stricteq);
CTI_COMPILE_BINARY_OP_SLOW_CASE(op_nstricteq);
case op_instanceof: {
if (JSImmediate::areBothImmediateNumbers(src1, src2))
r[dst] = jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2));
else {
- JSValue* result = jsBoolean(equal(exec, src1, src2));
+ JSValue* result = jsBoolean(equalSlowCase(exec, src1, src2));
VM_CHECK_EXCEPTION();
r[dst] = result;
}
if (JSImmediate::areBothImmediateNumbers(src1, src2))
r[dst] = jsBoolean(src1 != src2);
else {
- JSValue* result = jsBoolean(!equal(exec, src1, src2));
+ JSValue* result = jsBoolean(!equalSlowCase(exec, src1, src2));
VM_CHECK_EXCEPTION();
r[dst] = result;
}
ExecState* exec = ARG_exec;
ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
- JSValue* result = jsBoolean(equal(exec, src1, src2));
+ JSValue* result = jsBoolean(equalSlowCaseInline(exec, src1, src2));
VM_CHECK_EXCEPTION_AT_END();
return result;
}
JSValue* src1 = ARG_src1;
JSValue* src2 = ARG_src2;
- if (JSImmediate::areBothImmediateNumbers(src1, src2))
- return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2));
- else {
- ExecState* exec = ARG_exec;
- JSValue* result = jsBoolean(!equal(exec, src1, src2));
- VM_CHECK_EXCEPTION_AT_END();
- return result;
- }
+ ASSERT(!JSImmediate::areBothImmediateNumbers(src1, src2));
+
+ ExecState* exec = ARG_exec;
+ JSValue* result = jsBoolean(!equalSlowCaseInline(exec, src1, src2));
+ VM_CHECK_EXCEPTION_AT_END();
+ return result;
}
JSValue* Machine::cti_op_post_dec(CTI_ARGS)
// ECMA 11.9.3
bool equal(ExecState* exec, JSValue* v1, JSValue* v2)
{
-startOver:
if (JSImmediate::areBothImmediateNumbers(v1, v2))
return v1 == v2;
- if (v1->isNumber() && v2->isNumber())
- return v1->uncheckedGetNumber() == v2->uncheckedGetNumber();
-
- bool s1 = v1->isString();
- bool s2 = v2->isString();
- if (s1 && s2)
- return static_cast<JSString*>(v1)->value() == static_cast<JSString*>(v2)->value();
-
- if (v1->isUndefinedOrNull()) {
- if (v2->isUndefinedOrNull())
- return true;
- if (JSImmediate::isImmediate(v2))
- return false;
- return v2->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
- }
-
- if (v2->isUndefinedOrNull()) {
- if (JSImmediate::isImmediate(v1))
- return false;
- return v1->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
- }
-
- if (v1->isObject()) {
- if (v2->isObject())
- return v1 == v2;
- JSValue* p1 = v1->toPrimitive(exec);
- if (exec->hadException())
- return false;
- v1 = p1;
- goto startOver;
- }
-
- if (v2->isObject()) {
- JSValue* p2 = v2->toPrimitive(exec);
- if (exec->hadException())
- return false;
- v2 = p2;
- goto startOver;
- }
-
- if (s1 || s2) {
- double d1 = v1->toNumber(exec);
- double d2 = v2->toNumber(exec);
- return d1 == d2;
- }
-
- if (v1->isBoolean()) {
- if (v2->isNumber())
- return static_cast<double>(v1->getBoolean()) == v2->uncheckedGetNumber();
- } else if (v2->isBoolean()) {
- if (v1->isNumber())
- return v1->uncheckedGetNumber() == static_cast<double>(v2->getBoolean());
- }
+ return equalSlowCaseInline(exec, v1, v2);
+}
- return v1 == v2;
+bool equalSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+ return equalSlowCaseInline(exec, v1, v2);
}
bool strictEqual(JSValue* v1, JSValue* v2)
class ExecState;
class JSValue;
+ // ECMA 11.9.3
bool equal(ExecState*, JSValue*, JSValue*);
+ bool equalSlowCase(ExecState*, JSValue*, JSValue*);
+
+ ALWAYS_INLINE bool equalSlowCaseInline(ExecState* exec, JSValue* v1, JSValue* v2)
+ {
+ ASSERT(!JSImmediate::areBothImmediateNumbers(v1, v2));
+
+ do {
+ if (v1->isNumber() && v2->isNumber())
+ return v1->uncheckedGetNumber() == v2->uncheckedGetNumber();
+
+ bool s1 = v1->isString();
+ bool s2 = v2->isString();
+ if (s1 && s2)
+ return static_cast<JSString*>(v1)->value() == static_cast<JSString*>(v2)->value();
+
+ if (v1->isUndefinedOrNull()) {
+ if (v2->isUndefinedOrNull())
+ return true;
+ if (JSImmediate::isImmediate(v2))
+ return false;
+ return v2->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
+ }
+
+ if (v2->isUndefinedOrNull()) {
+ if (JSImmediate::isImmediate(v1))
+ return false;
+ return v1->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
+ }
+
+ if (v1->isObject()) {
+ if (v2->isObject())
+ return v1 == v2;
+ JSValue* p1 = v1->toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ v1 = p1;
+ if (JSImmediate::areBothImmediateNumbers(v1, v2))
+ return v1 == v2;
+ continue;
+ }
+
+ if (v2->isObject()) {
+ JSValue* p2 = v2->toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ v2 = p2;
+ if (JSImmediate::areBothImmediateNumbers(v1, v2))
+ return v1 == v2;
+ continue;
+ }
+
+ if (s1 || s2) {
+ double d1 = v1->toNumber(exec);
+ double d2 = v2->toNumber(exec);
+ return d1 == d2;
+ }
+
+ if (v1->isBoolean()) {
+ if (v2->isNumber())
+ return static_cast<double>(v1->getBoolean()) == v2->uncheckedGetNumber();
+ } else if (v2->isBoolean()) {
+ if (v1->isNumber())
+ return v1->uncheckedGetNumber() == static_cast<double>(v2->getBoolean());
+ }
+
+ return v1 == v2;
+ } while (true);
+ }
+
+
bool strictEqual(JSValue*, JSValue*);
bool strictEqualSlowCase(JSValue*, JSValue*);