2008-10-08 Maciej Stachowiak <mjs@apple.com>
authormjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Oct 2008 10:53:13 +0000 (10:53 +0000)
committermjs@apple.com <mjs@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Oct 2008 10:53:13 +0000 (10:53 +0000)
        Reviewed by Oliver Hunt.

        Re-landing the following fix with the crashing bug in it fixed (r37405):

        - 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@37417 268f45cc-cd09-0410-ab3c-d52691b4dbfc

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

index a7c02a2dbe4b415f0701f8771bfff395e70964e0..0dd0d1adecf3d51b5ab603b2fff37ba9925de77c 100644 (file)
@@ -1,3 +1,40 @@
+2008-10-08  Maciej Stachowiak  <mjs@apple.com>
+
+        Reviewed by Oliver Hunt.
+
+        Re-landing the following fix with the crashing bug in it fixed (r37405):
+        
+        - 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-08  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Oliver Hunt.
index 0644a6e1f10e0a63696e5c4bd63f1da0ed5cc98f..29d653795fd4f955dd0afe6fd931c6d0d188fde6 100644 (file)
@@ -1767,8 +1767,20 @@ 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();
+
+            emitJumpSlowCaseIfNotJSCell(X86::eax, i);
+
+            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 +2530,17 @@ void CTI::privateCompileSlowCases()
             i += 7;
             break;
         }
+        case op_to_jsnumber: {
+            m_jit.link(iter->from, m_jit.label());
+            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..adac834e036a1ce322d28fa60669207411bb38e4 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..d60554792b4f6383fa43014466ee1d93a350b4a8 100644 (file)
@@ -1424,13 +1424,26 @@ static ExpressionNode* makeBitwiseNotNode(void* globalPtr, ExpressionNode* expr)
 
 static ExpressionNode* makeMultNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
 {
+    expr1 = expr1->stripUnaryPlus();
+    expr2 = expr2->stripUnaryPlus();
+
     if (expr1->isNumber() && expr2->isNumber())
         return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
+
+    if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
+        return new UnaryPlusNode(GLOBAL_DATA, expr2);
+
+    if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
+        return new UnaryPlusNode(GLOBAL_DATA, expr1);
+
     return new MultNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
 }
 
 static ExpressionNode* makeDivNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
 {
+    expr1 = expr1->stripUnaryPlus();
+    expr2 = expr2->stripUnaryPlus();
+
     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 +1458,9 @@ static ExpressionNode* makeAddNode(void* globalPtr, ExpressionNode* expr1, Expre
 
 static ExpressionNode* makeSubNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
 {
+    expr1 = expr1->stripUnaryPlus();
+    expr2 = expr2->stripUnaryPlus();
+
     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; }