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;