Title: [101964] trunk/Source/_javascript_Core
Revision
101964
Author
[email protected]
Date
2011-12-04 13:16:43 -0800 (Sun, 04 Dec 2011)

Log Message

DFG should optimize strict equality
https://bugs.webkit.org/show_bug.cgi?id=73764

Reviewed by Oliver Hunt.

1% speed-up on V8.

* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compare):
(JSC::DFG::SpeculativeJIT::compileStrictEqForConstant):
(JSC::DFG::SpeculativeJIT::compileStrictEq):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compileIntegerCompare):
(JSC::DFG::SpeculativeJIT::compileDoubleCompare):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileIntegerCompare):
(JSC::DFG::SpeculativeJIT::compileDoubleCompare):
(JSC::DFG::SpeculativeJIT::compile):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (101963 => 101964)


--- trunk/Source/_javascript_Core/ChangeLog	2011-12-04 20:42:05 UTC (rev 101963)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-12-04 21:16:43 UTC (rev 101964)
@@ -1,3 +1,26 @@
+2011-12-04  Filip Pizlo  <[email protected]>
+
+        DFG should optimize strict equality
+        https://bugs.webkit.org/show_bug.cgi?id=73764
+
+        Reviewed by Oliver Hunt.
+        
+        1% speed-up on V8.
+
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compare):
+        (JSC::DFG::SpeculativeJIT::compileStrictEqForConstant):
+        (JSC::DFG::SpeculativeJIT::compileStrictEq):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileIntegerCompare):
+        (JSC::DFG::SpeculativeJIT::compileDoubleCompare):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileIntegerCompare):
+        (JSC::DFG::SpeculativeJIT::compileDoubleCompare):
+        (JSC::DFG::SpeculativeJIT::compile):
+
 2011-12-03  Darin Adler  <[email protected]>
 
         Use HashMap<OwnPtr> for ScriptSampleRecordMap

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (101963 => 101964)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2011-12-04 20:42:05 UTC (rev 101963)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2011-12-04 21:16:43 UTC (rev 101964)
@@ -2189,6 +2189,179 @@
     doubleResult(result.fpr(), m_compileIndex);
 }
 
+// Returns true if the compare is fused with a subsequent branch.
+bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
+{
+    if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
+        return true;
+
+    if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2())))
+        compileIntegerCompare(node, condition);
+    else if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2())))
+        compileDoubleCompare(node, doubleCondition);
+    else if (node.op == CompareEq && Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2())))
+        compileObjectEquality(node, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
+    else if (node.op == CompareEq && Node::shouldSpeculateArray(at(node.child1()), at(node.child2())))
+        compileObjectEquality(node, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
+    else
+        nonSpeculativeNonPeepholeCompare(node, condition, operation);
+    
+    return false;
+}
+
+bool SpeculativeJIT::compileStrictEqForConstant(Node& node, NodeIndex value, JSValue constant)
+{
+    JSValueOperand op1(this, value);
+    
+    NodeIndex branchNodeIndex = detectPeepHoleBranch();
+    if (branchNodeIndex != NoNode) {
+        Node& branchNode = at(branchNodeIndex);
+        BlockIndex taken = branchNode.takenBlockIndex();
+        BlockIndex notTaken = branchNode.notTakenBlockIndex();
+        MacroAssembler::RelationalCondition condition = MacroAssembler::Equal;
+        
+        // The branch instruction will branch to the taken block.
+        // If taken is next, switch taken with notTaken & invert the branch condition so we can fall through.
+        if (taken == (m_block + 1)) {
+            condition = MacroAssembler::NotEqual;
+            BlockIndex tmp = taken;
+            taken = notTaken;
+            notTaken = tmp;
+        }
+
+#if USE(JSVALUE64)
+        addBranch(m_jit.branchPtr(condition, op1.gpr(), MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(constant)))), taken);
+#else
+        GPRReg payloadGPR = op1.payloadGPR();
+        GPRReg tagGPR = op1.tagGPR();
+        if (condition == MacroAssembler::Equal) {
+            // Drop down if not equal, go elsewhere if equal.
+            MacroAssembler::Jump notEqual = m_jit.branch32(MacroAssembler::NotEqual, tagGPR, MacroAssembler::Imm32(constant.tag()));
+            addBranch(m_jit.branch32(MacroAssembler::Equal, payloadGPR, MacroAssembler::Imm32(constant.payload())), taken);
+            notEqual.link(&m_jit);
+        } else {
+            // Drop down if equal, go elsehwere if not equal.
+            addBranch(m_jit.branch32(MacroAssembler::NotEqual, tagGPR, MacroAssembler::Imm32(constant.tag())), taken);
+            addBranch(m_jit.branch32(MacroAssembler::NotEqual, payloadGPR, MacroAssembler::Imm32(constant.payload())), taken);
+        }
+#endif
+        
+        if (notTaken != (m_block + 1))
+            addBranch(m_jit.jump(), notTaken);
+        
+        use(node.child1());
+        use(node.child2());
+        m_compileIndex = branchNodeIndex;
+        return true;
+    }
+    
+    GPRTemporary result(this);
+    
+#if USE(JSVALUE64)
+    GPRReg op1GPR = op1.gpr();
+    GPRReg resultGPR = result.gpr();
+    m_jit.move(MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(ValueFalse)), resultGPR);
+    MacroAssembler::Jump notEqual = m_jit.branchPtr(MacroAssembler::NotEqual, op1GPR, MacroAssembler::TrustedImmPtr(bitwise_cast<void*>(JSValue::encode(constant))));
+    m_jit.or32(MacroAssembler::Imm32(1), resultGPR);
+    notEqual.link(&m_jit);
+    jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
+#else
+    GPRReg op1PayloadGPR = op1.payloadGPR();
+    GPRReg op1TagGPR = op1.tagGPR();
+    GPRReg resultGPR = result.gpr();
+    m_jit.move(Imm32(0), resultGPR);
+    MacroAssembler::JumpList notEqual;
+    notEqual.append(m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, MacroAssembler::Imm32(constant.tag())));
+    notEqual.append(m_jit.branch32(MacroAssembler::NotEqual, op1PayloadGPR, MacroAssembler::Imm32(constant.payload())));
+    m_jit.move(Imm32(1), resultGPR);
+    notEqual.link(&m_jit);
+    booleanResult(resultGPR, m_compileIndex);
+#endif
+    
+    return false;
+}
+
+bool SpeculativeJIT::compileStrictEq(Node& node)
+{
+    // 1) If either operand is a constant and that constant is not a double, integer,
+    //    or string, then do a JSValue comparison.
+    
+    if (isJSConstant(node.child1())) {
+        JSValue value = valueOfJSConstant(node.child1());
+        if (!value.isNumber() && !value.isString())
+            return compileStrictEqForConstant(node, node.child2(), value);
+    }
+    
+    if (isJSConstant(node.child2())) {
+        JSValue value = valueOfJSConstant(node.child2());
+        if (!value.isNumber() && !value.isString())
+            return compileStrictEqForConstant(node, node.child1(), value);
+    }
+    
+    // 2) If the operands are predicted integer, do an integer comparison.
+    
+    if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
+        NodeIndex branchNodeIndex = detectPeepHoleBranch();
+        if (branchNodeIndex != NoNode) {
+            compilePeepHoleIntegerBranch(node, branchNodeIndex, MacroAssembler::Equal);
+            use(node.child1());
+            use(node.child2());
+            m_compileIndex = branchNodeIndex;
+            return true;
+        }
+        compileIntegerCompare(node, MacroAssembler::Equal);
+        return false;
+    }
+    
+    // 3) If the operands are predicted double, do a double comparison.
+    
+    if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
+        NodeIndex branchNodeIndex = detectPeepHoleBranch();
+        if (branchNodeIndex != NoNode) {
+            compilePeepHoleDoubleBranch(node, branchNodeIndex, MacroAssembler::DoubleEqual);
+            use(node.child1());
+            use(node.child2());
+            m_compileIndex = branchNodeIndex;
+            return true;
+        }
+        compileDoubleCompare(node, MacroAssembler::DoubleEqual);
+        return false;
+    }
+    
+    // 4) If the operands are predicted final object or array, then do a final object
+    //    or array comparison.
+    
+    if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2()))) {
+        NodeIndex branchNodeIndex = detectPeepHoleBranch();
+        if (branchNodeIndex != NoNode) {
+            compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
+            use(node.child1());
+            use(node.child2());
+            m_compileIndex = branchNodeIndex;
+            return true;
+        }
+        compileObjectEquality(node, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
+        return false;
+    }
+    
+    if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2()))) {
+        NodeIndex branchNodeIndex = detectPeepHoleBranch();
+        if (branchNodeIndex != NoNode) {
+            compilePeepHoleObjectEquality(node, branchNodeIndex, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
+            use(node.child1());
+            use(node.child2());
+            m_compileIndex = branchNodeIndex;
+            return true;
+        }
+        compileObjectEquality(node, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
+        return false;
+    }
+    
+    // 5) Fall back to non-speculative strict equality.
+    
+    return nonSpeculativeStrictEq(node);
+}
+
 } } // namespace JSC::DFG
 
 #endif

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (101963 => 101964)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2011-12-04 20:42:05 UTC (rev 101963)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2011-12-04 21:16:43 UTC (rev 101964)
@@ -1942,6 +1942,13 @@
     void emitObjectOrOtherBranch(NodeIndex value, BlockIndex taken, BlockIndex notTaken, void *vptr, bool needSpeculationCheck);
     void emitBranch(Node&);
     
+    void compileIntegerCompare(Node&, MacroAssembler::RelationalCondition);
+    void compileDoubleCompare(Node&, MacroAssembler::DoubleCondition);
+    
+    bool compileStrictEqForConstant(Node&, NodeIndex value, JSValue constant);
+    
+    bool compileStrictEq(Node&);
+    
     void compileGetCharCodeAt(Node&);
     void compileGetByValOnString(Node&);
     void compileValueToInt32(Node&);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (101963 => 101964)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2011-12-04 20:42:05 UTC (rev 101963)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2011-12-04 21:16:43 UTC (rev 101964)
@@ -1750,43 +1750,30 @@
     booleanResult(resultPayloadGPR, m_compileIndex);
 }
 
-// Returns true if the compare is fused with a subsequent branch.
-bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
+void SpeculativeJIT::compileIntegerCompare(Node& node, MacroAssembler::RelationalCondition condition)
 {
-    if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
-        return true;
+    SpeculateIntegerOperand op1(this, node.child1());
+    SpeculateIntegerOperand op2(this, node.child2());
+    GPRTemporary resultPayload(this);
+    
+    m_jit.compare32(condition, op1.gpr(), op2.gpr(), resultPayload.gpr());
+    
+    // If we add a DataFormatBool, we should use it here.
+    booleanResult(resultPayload.gpr(), m_compileIndex);
+}
 
-    if (Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2())))
-        compileObjectEquality(node, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
-    else if (Node::shouldSpeculateArray(at(node.child1()), at(node.child2())))
-        compileObjectEquality(node, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
-    else if (!at(node.child1()).shouldSpeculateNumber() && !at(node.child2()).shouldSpeculateNumber())
-        nonSpeculativeNonPeepholeCompare(node, condition, operation);
-    else if ((at(node.child1()).shouldSpeculateNumber() || at(node.child2()).shouldSpeculateNumber()) && !Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
-        // Normal case, not fused to branch.
-        SpeculateDoubleOperand op1(this, node.child1());
-        SpeculateDoubleOperand op2(this, node.child2());
-        GPRTemporary resultPayload(this);
-        
-        m_jit.move(Imm32(1), resultPayload.gpr());
-        MacroAssembler::Jump trueCase = m_jit.branchDouble(doubleCondition, op1.fpr(), op2.fpr());
-        m_jit.move(Imm32(0), resultPayload.gpr());
-        trueCase.link(&m_jit);
-
-        booleanResult(resultPayload.gpr(), m_compileIndex);
-    } else {
-        // Normal case, not fused to branch.
-        SpeculateIntegerOperand op1(this, node.child1());
-        SpeculateIntegerOperand op2(this, node.child2());
-        GPRTemporary resultPayload(this);
-        
-        m_jit.compare32(condition, op1.gpr(), op2.gpr(), resultPayload.gpr());
-        
-        // If we add a DataFormatBool, we should use it here.
-        booleanResult(resultPayload.gpr(), m_compileIndex);
-    }
+void SpeculativeJIT::compileDoubleCompare(Node& node, MacroAssembler::DoubleCondition condition)
+{
+    SpeculateDoubleOperand op1(this, node.child1());
+    SpeculateDoubleOperand op2(this, node.child2());
+    GPRTemporary resultPayload(this);
     
-    return false;
+    m_jit.move(Imm32(1), resultPayload.gpr());
+    MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
+    m_jit.move(Imm32(0), resultPayload.gpr());
+    trueCase.link(&m_jit);
+    
+    booleanResult(resultPayload.gpr(), m_compileIndex);
 }
 
 void SpeculativeJIT::compileValueAdd(Node& node)
@@ -2593,7 +2580,7 @@
         break;
 
     case CompareStrictEq:
-        if (nonSpeculativeStrictEq(node))
+        if (compileStrictEq(node))
             return;
         break;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (101963 => 101964)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2011-12-04 20:42:05 UTC (rev 101963)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2011-12-04 21:16:43 UTC (rev 101964)
@@ -1775,41 +1775,31 @@
     jsValueResult(resultGPR, m_compileIndex, DataFormatJSBoolean);
 }
 
-// Returns true if the compare is fused with a subsequent branch.
-bool SpeculativeJIT::compare(Node& node, MacroAssembler::RelationalCondition condition, MacroAssembler::DoubleCondition doubleCondition, S_DFGOperation_EJJ operation)
+void SpeculativeJIT::compileIntegerCompare(Node& node, MacroAssembler::RelationalCondition condition)
 {
-    if (compilePeepHoleBranch(node, condition, doubleCondition, operation))
-        return true;
+    SpeculateIntegerOperand op1(this, node.child1());
+    SpeculateIntegerOperand op2(this, node.child2());
+    GPRTemporary result(this, op1, op2);
+    
+    m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
+    
+    // If we add a DataFormatBool, we should use it here.
+    m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
+    jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
+}
 
-    if (Node::shouldSpeculateInteger(at(node.child1()), at(node.child2()))) {
-        SpeculateIntegerOperand op1(this, node.child1());
-        SpeculateIntegerOperand op2(this, node.child2());
-        GPRTemporary result(this, op1, op2);
-        
-        m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
-        
-        // If we add a DataFormatBool, we should use it here.
-        m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
-        jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
-    } else if (Node::shouldSpeculateNumber(at(node.child1()), at(node.child2()))) {
-        SpeculateDoubleOperand op1(this, node.child1());
-        SpeculateDoubleOperand op2(this, node.child2());
-        GPRTemporary result(this);
-        
-        m_jit.move(TrustedImm32(ValueTrue), result.gpr());
-        MacroAssembler::Jump trueCase = m_jit.branchDouble(doubleCondition, op1.fpr(), op2.fpr());
-        m_jit.xorPtr(Imm32(true), result.gpr());
-        trueCase.link(&m_jit);
-
-        jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
-    } else if (node.op == CompareEq && Node::shouldSpeculateFinalObject(at(node.child1()), at(node.child2())))
-        compileObjectEquality(node, m_jit.globalData()->jsFinalObjectVPtr, isFinalObjectPrediction);
-    else if (node.op == CompareEq && Node::shouldSpeculateArray(at(node.child1()), at(node.child2())))
-        compileObjectEquality(node, m_jit.globalData()->jsArrayVPtr, isArrayPrediction);
-    else
-        nonSpeculativeNonPeepholeCompare(node, condition, operation);
+void SpeculativeJIT::compileDoubleCompare(Node& node, MacroAssembler::DoubleCondition condition)
+{
+    SpeculateDoubleOperand op1(this, node.child1());
+    SpeculateDoubleOperand op2(this, node.child2());
+    GPRTemporary result(this);
     
-    return false;
+    m_jit.move(TrustedImm32(ValueTrue), result.gpr());
+    MacroAssembler::Jump trueCase = m_jit.branchDouble(condition, op1.fpr(), op2.fpr());
+    m_jit.xorPtr(Imm32(true), result.gpr());
+    trueCase.link(&m_jit);
+    
+    jsValueResult(result.gpr(), m_compileIndex, DataFormatJSBoolean);
 }
 
 void SpeculativeJIT::compileValueAdd(Node& node)
@@ -2598,7 +2588,7 @@
         break;
 
     case CompareStrictEq:
-        if (nonSpeculativeStrictEq(node))
+        if (compileStrictEq(node))
             return;
         break;
 
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to