2008-10-07 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Oct 2008 03:46:34 +0000 (03:46 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Oct 2008 03:46:34 +0000 (03:46 +0000)
        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

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/nodes.h

index 67af2916d2ce4c33d61ba08c7523465e4d24fd1b..28888bcb47a72eaf15ac06eaf2c269f1afca8ad9 100644 (file)
@@ -1,3 +1,38 @@
+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.
index 183013cf3bb08ef97620cf7e473decef77b46d4d..2639820d3c6d91724942fa648c97557425fc5b3d 100644 (file)
@@ -1767,8 +1767,18 @@ void CTI::privateCompileMainPass()
             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;
@@ -2518,6 +2528,16 @@ void CTI::privateCompileSlowCases()
             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();
index ae35bbeb95b0b480ab0ec75ec21663628e059c63..76120f0b2b5f5d2a01688873f1e559b47e640bda 100644 (file)
@@ -1815,10 +1815,16 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, RegisterFile* registerFile,
         */
         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;
index 81e84b37d31277aa2f5a2a6eac52918861963753..cb5ecb63129265b6b3729ccd4e3c393b42319c6c 100644 (file)
@@ -1424,13 +1424,31 @@ static ExpressionNode* makeBitwiseNotNode(void* globalPtr, ExpressionNode* expr)
 
 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);
@@ -1445,6 +1463,11 @@ static ExpressionNode* makeAddNode(void* globalPtr, ExpressionNode* expr1, Expre
 
 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);
index 69a055fd46a2b1ad418b7b7a9375e972bf0dc1b6..181cc0a5642c38df710feb76fdbce4af10856b02 100644 (file)
@@ -226,6 +226,8 @@ namespace JSC {
         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 
@@ -1179,6 +1181,8 @@ namespace JSC {
         {
         }
 
+        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; }