Reviewed by Mark Rowe.
- optimize away multiplication by constant 1.0
2.3% speedup on v8 RayTrace benchmark
Apparently it's not uncommon for JavaScript code to multiply by
constant 1.0 in the mistaken belief that this converts integer to
floating point and that there is any operational difference.
* VM/CTI.cpp:
(JSC::CTI::privateCompileMainPass): Optimize to_jsnumber for
case where parameter is already number.
(JSC::CTI::privateCompileSlowCases): ditto
* VM/Machine.cpp:
(JSC::Machine::privateExecute): ditto
* kjs/grammar.y:
(makeMultNode): Transform as follows:
+FOO * BAR ==> FOO * BAR
FOO * +BAR ==> FOO * BAR
FOO * 1 ==> +FOO
1 * FOO ==> +FOO
(makeDivNode): Transform as follows:
+FOO / BAR ==> FOO / BAR
FOO / +BAR ==> FOO / BAR
(makeSubNode): Transform as follows:
+FOO - BAR ==> FOO - BAR
FOO - +BAR ==> FOO - BAR
* kjs/nodes.h:
(JSC::ExpressionNode::stripUnaryPlus): Helper for above
grammar.y changes
(JSC::UnaryPlusNode::stripUnaryPlus): ditto
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@37405
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2008-10-07 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ - optimize away multiplication by constant 1.0
+
+ 2.3% speedup on v8 RayTrace benchmark
+
+ Apparently it's not uncommon for JavaScript code to multiply by
+ constant 1.0 in the mistaken belief that this converts integer to
+ floating point and that there is any operational difference.
+
+ * VM/CTI.cpp:
+ (JSC::CTI::privateCompileMainPass): Optimize to_jsnumber for
+ case where parameter is already number.
+ (JSC::CTI::privateCompileSlowCases): ditto
+ * VM/Machine.cpp:
+ (JSC::Machine::privateExecute): ditto
+ * kjs/grammar.y:
+ (makeMultNode): Transform as follows:
+ +FOO * BAR ==> FOO * BAR
+ FOO * +BAR ==> FOO * BAR
+ FOO * 1 ==> +FOO
+ 1 * FOO ==> +FOO
+ (makeDivNode): Transform as follows:
+ +FOO / BAR ==> FOO / BAR
+ FOO / +BAR ==> FOO / BAR
+ (makeSubNode): Transform as follows:
+ +FOO - BAR ==> FOO - BAR
+ FOO - +BAR ==> FOO - BAR
+ * kjs/nodes.h:
+ (JSC::ExpressionNode::stripUnaryPlus): Helper for above
+ grammar.y changes
+ (JSC::UnaryPlusNode::stripUnaryPlus): ditto
+
2008-10-07 Maciej Stachowiak <mjs@apple.com>
Reviewed by Oliver Hunt.
break;
}
case op_to_jsnumber: {
- emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
- emitCall(i, Machine::cti_op_to_jsnumber);
+ emitGetArg(instruction[i + 2].u.operand, X86::eax);
+
+ m_jit.testl_i32r(JSImmediate::TagBitTypeInteger, X86::eax);
+ X86Assembler::JmpSrc wasImmediate = m_jit.emitUnlinkedJnz();
+
+ m_jit.movl_mr(OBJECT_OFFSET(JSCell, m_structureID), X86::eax, X86::ecx);
+ m_jit.cmpl_i32m(NumberType, OBJECT_OFFSET(StructureID, m_typeInfo.m_type), X86::ecx);
+
+ m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
+
+ m_jit.link(wasImmediate, m_jit.label());
+
emitPutResult(instruction[i + 1].u.operand);
i += 3;
break;
i += 7;
break;
}
+ case op_to_jsnumber: {
+ m_jit.link(iter->from, m_jit.label());
+
+ emitPutArg(X86::eax, 0);
+ emitCall(i, Machine::cti_op_to_jsnumber);
+
+ emitPutResult(instruction[i + 1].u.operand);
+ i += 3;
+ break;
+ }
default:
ASSERT_NOT_REACHED();
*/
int dst = (++vPC)->u.operand;
int src = (++vPC)->u.operand;
- JSValue* result = r[src].jsValue(exec)->toJSNumber(exec);
- VM_CHECK_EXCEPTION();
- r[dst] = result;
+ JSValue* srcVal = r[src].jsValue(exec);
+
+ if (LIKELY(JSImmediate::isNumber(srcVal) || static_cast<JSCell*>(srcVal)->structureID()->typeInfo().type() == NumberType))
+ r[dst] = r[src];
+ else {
+ JSValue* result = srcVal->toJSNumber(exec);
+ VM_CHECK_EXCEPTION();
+ r[dst] = result;
+ }
++vPC;
NEXT_OPCODE;
static ExpressionNode* makeMultNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
{
+ // these transforms are valid because unary + only does a toNumber
+ // conversion, which * does anyway:
+ expr1 = expr1->stripUnaryPlus(); // +FOO * BAR ==> FOO * BAR
+ expr2 = expr2->stripUnaryPlus(); // FOO * +BAR ==> FOO * BAR
+
if (expr1->isNumber() && expr2->isNumber())
return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
+
+ // these transforms are valid because multiplying by 1 has no
+ // effect but toNumber conversion
+ if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
+ return new UnaryPlusNode(GLOBAL_DATA, expr2); // 1 * FOO ==> +FOO
+ if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
+ return new UnaryPlusNode(GLOBAL_DATA, expr1); // FOO * 1 ==> +FOO
+
return new MultNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
}
static ExpressionNode* makeDivNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
{
+ // these transforms are valid because unary + only does a toNumber
+ // conversion, which / does anyway:
+ expr1 = expr1->stripUnaryPlus(); // +FOO / BAR ==> FOO / BAR
+ expr2 = expr2->stripUnaryPlus(); // FOO / +BAR ==> FOO / BAR
+
if (expr1->isNumber() && expr2->isNumber())
return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value());
return new DivNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
static ExpressionNode* makeSubNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
{
+ // these transforms are valid because unary + only does a toNumber
+ // conversion, which - does anyway:
+ expr1 = expr1->stripUnaryPlus(); // +FOO - BAR ==> FOO - BAR
+ expr2 = expr2->stripUnaryPlus(); // FOO - +BAR ==> FOO - BAR
+
if (expr1->isNumber() && expr2->isNumber())
return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value());
return new SubNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return false; }
virtual bool isDotAccessorNode() const JSC_FAST_CALL { return false; }
+ virtual ExpressionNode* stripUnaryPlus() { return this; }
+
ResultType resultDescriptor() const JSC_FAST_CALL { return m_resultDesc; }
// This needs to be in public in order to compile using GCC 3.x
{
}
+ virtual ExpressionNode* stripUnaryPlus() { return m_expr.get(); }
+
virtual OpcodeID opcode() const JSC_FAST_CALL { return op_to_jsnumber; }
virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }