Add CompareStrictEq(StringIdent:, NotStringVar:) and CompareStrictEq(String:, Untyped:)
https://bugs.webkit.org/show_bug.cgi?id=130300
Reviewed by Mark Hahnenberg.
We can quickly strictly compare StringIdent's to NotStringVar's and String's to Untyped's.
This makes the DFG aware of this.
Also adds StringIdent-to-StringIdent and StringIdent-to-NotStringVar strict comparisons to
the FTL. Also adds StringIdent-to-StringIdent non-strict comparisons to the FTL.
This also gives the DFG some abstractions for checking something is a cell or is other.
This made this patch easier to write and also simplified a bunch of other stuff.
1% speed-up on Octane.
* assembler/AbstractMacroAssembler.h:
(JSC::AbstractMacroAssembler::JumpList::JumpList):
* bytecode/SpeculatedType.h:
(JSC::isNotStringVarSpeculation):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::childFor):
(JSC::DFG::Node::shouldSpeculateNotStringVar):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileIn):
(JSC::DFG::SpeculativeJIT::compileValueToInt32):
(JSC::DFG::SpeculativeJIT::compileInstanceOfForObject):
(JSC::DFG::SpeculativeJIT::compileInstanceOf):
(JSC::DFG::SpeculativeJIT::compileStrictEq):
(JSC::DFG::SpeculativeJIT::compileBooleanCompare):
(JSC::DFG::SpeculativeJIT::compileStringEquality):
(JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality):
(JSC::DFG::SpeculativeJIT::compileStringIdentEquality):
(JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality):
(JSC::DFG::SpeculativeJIT::compileStringZeroLength):
(JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
(JSC::DFG::SpeculativeJIT::speculateString):
(JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage):
(JSC::DFG::SpeculativeJIT::speculateNotStringVar):
(JSC::DFG::SpeculativeJIT::speculateNotCell):
(JSC::DFG::SpeculativeJIT::speculateOther):
(JSC::DFG::SpeculativeJIT::speculate):
(JSC::DFG::SpeculativeJIT::emitSwitchChar):
(JSC::DFG::SpeculativeJIT::emitSwitchString):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::blessedBooleanResult):
(JSC::DFG::SpeculativeJIT::unblessedBooleanResult):
(JSC::DFG::SpeculativeJIT::booleanResult):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::branchIsCell):
(JSC::DFG::branchNotCell):
(JSC::DFG::SpeculativeJIT::branchIsOther):
(JSC::DFG::SpeculativeJIT::branchNotOther):
(JSC::DFG::SpeculativeJIT::moveTrueTo):
(JSC::DFG::SpeculativeJIT::moveFalseTo):
(JSC::DFG::SpeculativeJIT::blessBoolean):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
(JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
(JSC::DFG::SpeculativeJIT::fillSpeculateCell):
(JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
(JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
(JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
(JSC::DFG::SpeculativeJIT::compile):
(JSC::DFG::SpeculativeJIT::writeBarrier):
(JSC::DFG::SpeculativeJIT::branchIsCell):
(JSC::DFG::SpeculativeJIT::branchNotCell):
(JSC::DFG::SpeculativeJIT::branchIsOther):
(JSC::DFG::SpeculativeJIT::branchNotOther):
(JSC::DFG::SpeculativeJIT::moveTrueTo):
(JSC::DFG::SpeculativeJIT::moveFalseTo):
(JSC::DFG::SpeculativeJIT::blessBoolean):
* dfg/DFGUseKind.cpp:
(WTF::printInternal):
* dfg/DFGUseKind.h:
(JSC::DFG::typeFilterFor):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
(JSC::FTL::LowerDFGToLLVM::lowString):
(JSC::FTL::LowerDFGToLLVM::lowStringIdent):
(JSC::FTL::LowerDFGToLLVM::speculate):
(JSC::FTL::LowerDFGToLLVM::speculateString):
(JSC::FTL::LowerDFGToLLVM::speculateStringIdent):
(JSC::FTL::LowerDFGToLLVM::speculateNotStringVar):
* runtime/JSCJSValue.h:
* tests/stress/string-ident-to-not-string-var-equality.js: Added.
(foo):
(bar):
(test):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@165842 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 44a1d48..592e8fa 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,111 @@
+2014-03-17 Filip Pizlo <fpizlo@apple.com>
+
+ Add CompareStrictEq(StringIdent:, NotStringVar:) and CompareStrictEq(String:, Untyped:)
+ https://bugs.webkit.org/show_bug.cgi?id=130300
+
+ Reviewed by Mark Hahnenberg.
+
+ We can quickly strictly compare StringIdent's to NotStringVar's and String's to Untyped's.
+ This makes the DFG aware of this.
+
+ Also adds StringIdent-to-StringIdent and StringIdent-to-NotStringVar strict comparisons to
+ the FTL. Also adds StringIdent-to-StringIdent non-strict comparisons to the FTL.
+
+ This also gives the DFG some abstractions for checking something is a cell or is other.
+ This made this patch easier to write and also simplified a bunch of other stuff.
+
+ 1% speed-up on Octane.
+
+ * assembler/AbstractMacroAssembler.h:
+ (JSC::AbstractMacroAssembler::JumpList::JumpList):
+ * bytecode/SpeculatedType.h:
+ (JSC::isNotStringVarSpeculation):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::childFor):
+ (JSC::DFG::Node::shouldSpeculateNotStringVar):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::SafeToExecuteEdge::operator()):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileIn):
+ (JSC::DFG::SpeculativeJIT::compileValueToInt32):
+ (JSC::DFG::SpeculativeJIT::compileInstanceOfForObject):
+ (JSC::DFG::SpeculativeJIT::compileInstanceOf):
+ (JSC::DFG::SpeculativeJIT::compileStrictEq):
+ (JSC::DFG::SpeculativeJIT::compileBooleanCompare):
+ (JSC::DFG::SpeculativeJIT::compileStringEquality):
+ (JSC::DFG::SpeculativeJIT::compileStringToUntypedEquality):
+ (JSC::DFG::SpeculativeJIT::compileStringIdentEquality):
+ (JSC::DFG::SpeculativeJIT::compileStringIdentToNotStringVarEquality):
+ (JSC::DFG::SpeculativeJIT::compileStringZeroLength):
+ (JSC::DFG::SpeculativeJIT::speculateObjectOrOther):
+ (JSC::DFG::SpeculativeJIT::speculateString):
+ (JSC::DFG::SpeculativeJIT::speculateStringIdentAndLoadStorage):
+ (JSC::DFG::SpeculativeJIT::speculateNotStringVar):
+ (JSC::DFG::SpeculativeJIT::speculateNotCell):
+ (JSC::DFG::SpeculativeJIT::speculateOther):
+ (JSC::DFG::SpeculativeJIT::speculate):
+ (JSC::DFG::SpeculativeJIT::emitSwitchChar):
+ (JSC::DFG::SpeculativeJIT::emitSwitchString):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::blessedBooleanResult):
+ (JSC::DFG::SpeculativeJIT::unblessedBooleanResult):
+ (JSC::DFG::SpeculativeJIT::booleanResult):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
+ (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+ (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
+ (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
+ (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
+ (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
+ (JSC::DFG::SpeculativeJIT::compile):
+ (JSC::DFG::branchIsCell):
+ (JSC::DFG::branchNotCell):
+ (JSC::DFG::SpeculativeJIT::branchIsOther):
+ (JSC::DFG::SpeculativeJIT::branchNotOther):
+ (JSC::DFG::SpeculativeJIT::moveTrueTo):
+ (JSC::DFG::SpeculativeJIT::moveFalseTo):
+ (JSC::DFG::SpeculativeJIT::blessBoolean):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNull):
+ (JSC::DFG::SpeculativeJIT::nonSpeculativePeepholeBranchNull):
+ (JSC::DFG::SpeculativeJIT::fillSpeculateCell):
+ (JSC::DFG::SpeculativeJIT::compileObjectToObjectOrOtherEquality):
+ (JSC::DFG::SpeculativeJIT::compilePeepHoleObjectToObjectOrOtherEquality):
+ (JSC::DFG::SpeculativeJIT::compileObjectOrOtherLogicalNot):
+ (JSC::DFG::SpeculativeJIT::emitObjectOrOtherBranch):
+ (JSC::DFG::SpeculativeJIT::compile):
+ (JSC::DFG::SpeculativeJIT::writeBarrier):
+ (JSC::DFG::SpeculativeJIT::branchIsCell):
+ (JSC::DFG::SpeculativeJIT::branchNotCell):
+ (JSC::DFG::SpeculativeJIT::branchIsOther):
+ (JSC::DFG::SpeculativeJIT::branchNotOther):
+ (JSC::DFG::SpeculativeJIT::moveTrueTo):
+ (JSC::DFG::SpeculativeJIT::moveFalseTo):
+ (JSC::DFG::SpeculativeJIT::blessBoolean):
+ * dfg/DFGUseKind.cpp:
+ (WTF::printInternal):
+ * dfg/DFGUseKind.h:
+ (JSC::DFG::typeFilterFor):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToLLVM.cpp:
+ (JSC::FTL::LowerDFGToLLVM::compileCompareStrictEq):
+ (JSC::FTL::LowerDFGToLLVM::lowString):
+ (JSC::FTL::LowerDFGToLLVM::lowStringIdent):
+ (JSC::FTL::LowerDFGToLLVM::speculate):
+ (JSC::FTL::LowerDFGToLLVM::speculateString):
+ (JSC::FTL::LowerDFGToLLVM::speculateStringIdent):
+ (JSC::FTL::LowerDFGToLLVM::speculateNotStringVar):
+ * runtime/JSCJSValue.h:
+ * tests/stress/string-ident-to-not-string-var-equality.js: Added.
+ (foo):
+ (bar):
+ (test):
+
2014-03-18 Joseph Pecoraro <pecoraro@apple.com>
Add Copyright to framework.sb
diff --git a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
index ff17247..cedfab8 100644
--- a/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
+++ b/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h
@@ -693,7 +693,8 @@
JumpList(Jump jump)
{
- append(jump);
+ if (jump.isSet())
+ append(jump);
}
void link(AbstractMacroAssembler<AssemblerType>* masm)
diff --git a/Source/JavaScriptCore/bytecode/SpeculatedType.h b/Source/JavaScriptCore/bytecode/SpeculatedType.h
index f2454f8..c14ba36 100644
--- a/Source/JavaScriptCore/bytecode/SpeculatedType.h
+++ b/Source/JavaScriptCore/bytecode/SpeculatedType.h
@@ -120,6 +120,11 @@
return value == SpecStringIdent;
}
+inline bool isNotStringVarSpeculation(SpeculatedType value)
+{
+ return !(value & SpecStringVar);
+}
+
inline bool isStringSpeculation(SpeculatedType value)
{
return !!value && (value & SpecString) == value;
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index e9f7154..c50f3a0 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -436,6 +436,26 @@
fixEdge<MiscUse>(node->child2());
break;
}
+ if (node->child1()->shouldSpeculateStringIdent()
+ && node->child2()->shouldSpeculateNotStringVar()) {
+ fixEdge<StringIdentUse>(node->child1());
+ fixEdge<NotStringVarUse>(node->child2());
+ break;
+ }
+ if (node->child2()->shouldSpeculateStringIdent()
+ && node->child1()->shouldSpeculateNotStringVar()) {
+ fixEdge<StringIdentUse>(node->child2());
+ fixEdge<NotStringVarUse>(node->child1());
+ break;
+ }
+ if (node->child1()->shouldSpeculateString()) {
+ fixEdge<StringUse>(node->child1());
+ break;
+ }
+ if (node->child2()->shouldSpeculateString()) {
+ fixEdge<StringUse>(node->child2());
+ break;
+ }
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index 2c59c38..1120d6a 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -1340,6 +1340,17 @@
return isBinaryUseKind(useKind, useKind);
}
+ Edge childFor(UseKind useKind)
+ {
+ if (child1().useKind() == useKind)
+ return child1();
+ if (child2().useKind() == useKind)
+ return child2();
+ if (child3().useKind() == useKind)
+ return child3();
+ return Edge();
+ }
+
SpeculatedType prediction()
{
return m_prediction;
@@ -1419,6 +1430,11 @@
{
return isStringIdentSpeculation(prediction());
}
+
+ bool shouldSpeculateNotStringVar()
+ {
+ return isNotStringVarSpeculation(prediction());
+ }
bool shouldSpeculateString()
{
diff --git a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
index 23c4ac2..508a589 100644
--- a/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
+++ b/Source/JavaScriptCore/dfg/DFGSafeToExecute.h
@@ -57,6 +57,7 @@
case StringUse:
case StringObjectUse:
case StringOrStringObjectUse:
+ case NotStringVarUse:
case NotCellUse:
case OtherUse:
case MiscUse:
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index 8b87c1c..71a7196 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -886,13 +886,8 @@
addSlowPathGenerator(slowPath.release());
base.use();
-
-#if USE(JSVALUE64)
- jsValueResult(
- resultGPR, node, DataFormatJSBoolean, UseChildrenCalledExplicitly);
-#else
- booleanResult(resultGPR, node, UseChildrenCalledExplicitly);
-#endif
+
+ blessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
return;
}
}
@@ -910,11 +905,7 @@
callOperation(
operationGenericIn, extractResult(JSValueRegs::payloadOnly(resultGPR)),
baseGPR, regs);
-#if USE(JSVALUE64)
- jsValueResult(resultGPR, node, DataFormatJSBoolean, UseChildrenCalledExplicitly);
-#else
- booleanResult(resultGPR, node, UseChildrenCalledExplicitly);
-#endif
+ blessedBooleanResult(resultGPR, node, UseChildrenCalledExplicitly);
}
bool SpeculativeJIT::nonSpeculativeCompare(Node* node, MacroAssembler::RelationalCondition cond, S_JITOperation_EJJ helperFunction)
@@ -1939,9 +1930,7 @@
JITCompiler::Jump isNumber = m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagTypeNumberRegister);
DFG_TYPE_CHECK(
- JSValueRegs(gpr), node->child1(), ~SpecCell,
- m_jit.branchTest64(
- JITCompiler::Zero, gpr, GPRInfo::tagMaskRegister));
+ JSValueRegs(gpr), node->child1(), ~SpecCell, branchIsCell(JSValueRegs(gpr)));
// It's not a cell: so true turns into 1 and all else turns into 0.
m_jit.compare64(JITCompiler::Equal, gpr, TrustedImm32(ValueTrue), resultGpr);
@@ -1988,7 +1977,7 @@
if (node->child1().useKind() == NumberUse) {
DFG_TYPE_CHECK(
- JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecFullNumber,
+ op1.jsValueRegs(), node->child1(), SpecFullNumber,
m_jit.branch32(
MacroAssembler::AboveOrEqual, tagGPR,
TrustedImm32(JSValue::LowestTag)));
@@ -1996,9 +1985,8 @@
JITCompiler::Jump isNumber = m_jit.branch32(MacroAssembler::Below, tagGPR, TrustedImm32(JSValue::LowestTag));
DFG_TYPE_CHECK(
- JSValueRegs(tagGPR, payloadGPR), node->child1(), ~SpecCell,
- m_jit.branch32(
- JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::CellTag)));
+ op1.jsValueRegs(), node->child1(), ~SpecCell,
+ branchIsCell(op1.jsValueRegs()));
// It's not a cell: so true turns into 1 and all else turns into 0.
JITCompiler::Jump isBoolean = m_jit.branch32(JITCompiler::Equal, tagGPR, TrustedImm32(JSValue::BooleanTag));
@@ -2542,14 +2530,12 @@
// Walk up the prototype chain of the value (in scratchReg), comparing to prototypeReg.
MacroAssembler::Label loop(&m_jit);
m_jit.emitLoadStructure(scratchReg, scratchReg, scratch2Reg);
-#if USE(JSVALUE64)
- m_jit.load64(MacroAssembler::Address(scratchReg, Structure::prototypeOffset()), scratchReg);
- MacroAssembler::Jump isInstance = m_jit.branch64(MacroAssembler::Equal, scratchReg, prototypeReg);
- m_jit.branchTest64(MacroAssembler::Zero, scratchReg, GPRInfo::tagMaskRegister).linkTo(loop, &m_jit);
-#else
- m_jit.load32(MacroAssembler::Address(scratchReg, Structure::prototypeOffset() + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), scratchReg);
+ m_jit.loadPtr(MacroAssembler::Address(scratchReg, Structure::prototypeOffset() + CellPayloadOffset), scratchReg);
MacroAssembler::Jump isInstance = m_jit.branchPtr(MacroAssembler::Equal, scratchReg, prototypeReg);
- m_jit.branchTest32(MacroAssembler::NonZero, scratchReg).linkTo(loop, &m_jit);
+#if USE(JSVALUE64)
+ branchIsCell(JSValueRegs(scratchReg)).linkTo(loop, &m_jit);
+#else
+ m_jit.branchTestPtr(MacroAssembler::NonZero, scratchReg).linkTo(loop, &m_jit);
#endif
// No match - result is false.
@@ -2586,16 +2572,9 @@
GPRReg scratchReg = scratch.gpr();
GPRReg scratch2Reg = scratch2.gpr();
-#if USE(JSVALUE64)
- GPRReg valueReg = value.gpr();
- MacroAssembler::Jump isCell = m_jit.branchTest64(MacroAssembler::Zero, valueReg, GPRInfo::tagMaskRegister);
- m_jit.move(MacroAssembler::TrustedImm64(JSValue::encode(jsBoolean(false))), scratchReg);
-#else
- GPRReg valueTagReg = value.tagGPR();
- GPRReg valueReg = value.payloadGPR();
- MacroAssembler::Jump isCell = m_jit.branch32(MacroAssembler::Equal, valueTagReg, TrustedImm32(JSValue::CellTag));
- m_jit.move(MacroAssembler::TrustedImm32(0), scratchReg);
-#endif
+ MacroAssembler::Jump isCell = branchIsCell(value.jsValueRegs());
+ GPRReg valueReg = value.jsValueRegs().payloadGPR();
+ moveFalseTo(scratchReg);
MacroAssembler::Jump done = m_jit.jump();
@@ -2605,11 +2584,7 @@
done.link(&m_jit);
-#if USE(JSVALUE64)
- jsValueResult(scratchReg, node, DataFormatJSBoolean);
-#else
- booleanResult(scratchReg, node);
-#endif
+ blessedBooleanResult(scratchReg, node);
return;
}
@@ -2626,11 +2601,7 @@
compileInstanceOfForObject(node, valueReg, prototypeReg, scratchReg, scratch2Reg);
-#if USE(JSVALUE64)
- jsValueResult(scratchReg, node, DataFormatJSBoolean);
-#else
- booleanResult(scratchReg, node);
-#endif
+ blessedBooleanResult(scratchReg, node);
}
void SpeculativeJIT::compileAdd(Node* node)
@@ -3731,6 +3702,26 @@
return false;
}
+ if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse)) {
+ compileStringIdentToNotStringVarEquality(node, node->child1(), node->child2());
+ return false;
+ }
+
+ if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) {
+ compileStringIdentToNotStringVarEquality(node, node->child2(), node->child1());
+ return false;
+ }
+
+ if (node->isBinaryUseKind(StringUse, UntypedUse)) {
+ compileStringToUntypedEquality(node, node->child1(), node->child2());
+ return false;
+ }
+
+ if (node->isBinaryUseKind(UntypedUse, StringUse)) {
+ compileStringToUntypedEquality(node, node->child2(), node->child1());
+ return false;
+ }
+
RELEASE_ASSERT(node->isBinaryUseKind(UntypedUse));
return nonSpeculativeStrictEq(node);
}
@@ -3743,44 +3734,20 @@
m_jit.compare32(condition, op1.gpr(), op2.gpr(), result.gpr());
- // If we add a DataFormatBool, we should use it here.
-#if USE(JSVALUE32_64)
- booleanResult(result.gpr(), node);
-#else
- m_jit.or32(TrustedImm32(ValueFalse), result.gpr());
- jsValueResult(result.gpr(), m_currentNode, DataFormatJSBoolean);
-#endif
+ unblessedBooleanResult(result.gpr(), node);
}
-void SpeculativeJIT::compileStringEquality(Node* node)
+void SpeculativeJIT::compileStringEquality(
+ Node* node, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR, GPRReg leftTempGPR,
+ GPRReg rightTempGPR, GPRReg leftTemp2GPR, GPRReg rightTemp2GPR,
+ JITCompiler::JumpList fastTrue, JITCompiler::JumpList fastFalse)
{
- SpeculateCellOperand left(this, node->child1());
- SpeculateCellOperand right(this, node->child2());
- GPRTemporary length(this);
- GPRTemporary leftTemp(this);
- GPRTemporary rightTemp(this);
- GPRTemporary leftTemp2(this, Reuse, left);
- GPRTemporary rightTemp2(this, Reuse, right);
-
- GPRReg leftGPR = left.gpr();
- GPRReg rightGPR = right.gpr();
- GPRReg lengthGPR = length.gpr();
- GPRReg leftTempGPR = leftTemp.gpr();
- GPRReg rightTempGPR = rightTemp.gpr();
- GPRReg leftTemp2GPR = leftTemp2.gpr();
- GPRReg rightTemp2GPR = rightTemp2.gpr();
-
JITCompiler::JumpList trueCase;
JITCompiler::JumpList falseCase;
JITCompiler::JumpList slowCase;
- speculateString(node->child1(), leftGPR);
-
- // It's safe to branch around the type check below, since proving that the values are
- // equal does indeed prove that the right value is a string.
- trueCase.append(m_jit.branchPtr(MacroAssembler::Equal, leftGPR, rightGPR));
-
- speculateString(node->child2(), rightGPR);
+ trueCase.append(fastTrue);
+ falseCase.append(fastFalse);
m_jit.load32(MacroAssembler::Address(leftGPR, JSString::offsetOfLength()), lengthGPR);
@@ -3822,31 +3789,90 @@
m_jit.branchTest32(MacroAssembler::NonZero, lengthGPR).linkTo(loop, &m_jit);
trueCase.link(&m_jit);
-#if USE(JSVALUE64)
- m_jit.move(TrustedImm64(ValueTrue), leftTempGPR);
-#else
- m_jit.move(TrustedImm32(true), leftTempGPR);
-#endif
+ moveTrueTo(leftTempGPR);
JITCompiler::Jump done = m_jit.jump();
falseCase.link(&m_jit);
-#if USE(JSVALUE64)
- m_jit.move(TrustedImm64(ValueFalse), leftTempGPR);
-#else
- m_jit.move(TrustedImm32(false), leftTempGPR);
-#endif
+ moveFalseTo(leftTempGPR);
done.link(&m_jit);
addSlowPathGenerator(
slowPathCall(
slowCase, this, operationCompareStringEq, leftTempGPR, leftGPR, rightGPR));
-#if USE(JSVALUE64)
- jsValueResult(leftTempGPR, node, DataFormatJSBoolean);
-#else
- booleanResult(leftTempGPR, node);
-#endif
+ blessedBooleanResult(leftTempGPR, node);
+}
+
+void SpeculativeJIT::compileStringEquality(Node* node)
+{
+ SpeculateCellOperand left(this, node->child1());
+ SpeculateCellOperand right(this, node->child2());
+ GPRTemporary length(this);
+ GPRTemporary leftTemp(this);
+ GPRTemporary rightTemp(this);
+ GPRTemporary leftTemp2(this, Reuse, left);
+ GPRTemporary rightTemp2(this, Reuse, right);
+
+ GPRReg leftGPR = left.gpr();
+ GPRReg rightGPR = right.gpr();
+ GPRReg lengthGPR = length.gpr();
+ GPRReg leftTempGPR = leftTemp.gpr();
+ GPRReg rightTempGPR = rightTemp.gpr();
+ GPRReg leftTemp2GPR = leftTemp2.gpr();
+ GPRReg rightTemp2GPR = rightTemp2.gpr();
+
+ speculateString(node->child1(), leftGPR);
+
+ // It's safe to branch around the type check below, since proving that the values are
+ // equal does indeed prove that the right value is a string.
+ JITCompiler::Jump fastTrue = m_jit.branchPtr(MacroAssembler::Equal, leftGPR, rightGPR);
+
+ speculateString(node->child2(), rightGPR);
+
+ compileStringEquality(
+ node, leftGPR, rightGPR, lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
+ rightTemp2GPR, fastTrue, JITCompiler::Jump());
+}
+
+void SpeculativeJIT::compileStringToUntypedEquality(Node* node, Edge stringEdge, Edge untypedEdge)
+{
+ SpeculateCellOperand left(this, stringEdge);
+ JSValueOperand right(this, untypedEdge, ManualOperandSpeculation);
+ GPRTemporary length(this);
+ GPRTemporary leftTemp(this);
+ GPRTemporary rightTemp(this);
+ GPRTemporary leftTemp2(this, Reuse, left);
+ GPRTemporary rightTemp2(this);
+
+ GPRReg leftGPR = left.gpr();
+ JSValueRegs rightRegs = right.jsValueRegs();
+ GPRReg lengthGPR = length.gpr();
+ GPRReg leftTempGPR = leftTemp.gpr();
+ GPRReg rightTempGPR = rightTemp.gpr();
+ GPRReg leftTemp2GPR = leftTemp2.gpr();
+ GPRReg rightTemp2GPR = rightTemp2.gpr();
+
+ speculateString(stringEdge, leftGPR);
+
+ JITCompiler::JumpList fastTrue;
+ JITCompiler::JumpList fastFalse;
+
+ fastFalse.append(branchNotCell(rightRegs));
+
+ // It's safe to branch around the type check below, since proving that the values are
+ // equal does indeed prove that the right value is a string.
+ fastTrue.append(m_jit.branchPtr(
+ MacroAssembler::Equal, leftGPR, rightRegs.payloadGPR()));
+
+ fastFalse.append(m_jit.branchStructurePtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()),
+ m_jit.vm()->stringStructure.get()));
+
+ compileStringEquality(
+ node, leftGPR, rightRegs.payloadGPR(), lengthGPR, leftTempGPR, rightTempGPR, leftTemp2GPR,
+ rightTemp2GPR, fastTrue, fastFalse);
}
void SpeculativeJIT::compileStringIdentEquality(Node* node)
@@ -3861,9 +3887,6 @@
GPRReg leftTempGPR = leftTemp.gpr();
GPRReg rightTempGPR = rightTemp.gpr();
- JITCompiler::JumpList trueCase;
- JITCompiler::JumpList falseCase;
-
speculateString(node->child1(), leftGPR);
speculateString(node->child2(), rightGPR);
@@ -3872,12 +3895,38 @@
m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, leftTempGPR);
-#if USE(JSVALUE64)
- m_jit.or32(TrustedImm32(ValueFalse), leftTempGPR);
- jsValueResult(leftTempGPR, node, DataFormatJSBoolean);
-#else
- booleanResult(leftTempGPR, node);
-#endif
+ unblessedBooleanResult(leftTempGPR, node);
+}
+
+void SpeculativeJIT::compileStringIdentToNotStringVarEquality(
+ Node* node, Edge stringEdge, Edge notStringVarEdge)
+{
+ SpeculateCellOperand left(this, stringEdge);
+ JSValueOperand right(this, notStringVarEdge, ManualOperandSpeculation);
+ GPRTemporary leftTemp(this);
+ GPRTemporary rightTemp(this);
+ GPRReg leftTempGPR = leftTemp.gpr();
+ GPRReg rightTempGPR = rightTemp.gpr();
+ GPRReg leftGPR = left.gpr();
+ JSValueRegs rightRegs = right.jsValueRegs();
+
+ speculateString(stringEdge, leftGPR);
+ speculateStringIdentAndLoadStorage(stringEdge, leftGPR, leftTempGPR);
+
+ moveFalseTo(rightTempGPR);
+ JITCompiler::JumpList notString;
+ notString.append(branchNotCell(rightRegs));
+ notString.append(m_jit.branchStructurePtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(rightRegs.payloadGPR(), JSCell::structureIDOffset()),
+ m_jit.vm()->stringStructure.get()));
+
+ speculateStringIdentAndLoadStorage(notStringVarEdge, rightRegs.payloadGPR(), rightTempGPR);
+
+ m_jit.comparePtr(MacroAssembler::Equal, leftTempGPR, rightTempGPR, rightTempGPR);
+ notString.link(&m_jit);
+
+ unblessedBooleanResult(rightTempGPR, node);
}
void SpeculativeJIT::compileStringZeroLength(Node* node)
@@ -3894,12 +3943,7 @@
// Fetch the length field from the string object.
m_jit.test32(MacroAssembler::Zero, MacroAssembler::Address(strGPR, JSString::offsetOfLength()), MacroAssembler::TrustedImm32(-1), eqGPR);
-#if USE(JSVALUE64)
- m_jit.or32(TrustedImm32(ValueFalse), eqGPR);
- jsValueResult(eqGPR, node, DataFormatJSBoolean);
-#else
- booleanResult(eqGPR, node);
-#endif
+ unblessedBooleanResult(eqGPR, node);
}
void SpeculativeJIT::compileConstantStoragePointer(Node* node)
@@ -4559,58 +4603,28 @@
JSValueOperand operand(this, edge, ManualOperandSpeculation);
GPRTemporary temp(this);
GPRReg tempGPR = temp.gpr();
-#if USE(JSVALUE64)
- GPRReg gpr = operand.gpr();
- MacroAssembler::Jump notCell = m_jit.branchTest64(
- MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump notCell = branchNotCell(operand.jsValueRegs());
+ GPRReg gpr = operand.jsValueRegs().payloadGPR();
DFG_TYPE_CHECK(
- JSValueRegs(gpr), edge, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
+ operand.jsValueRegs(), edge, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
MacroAssembler::Equal,
MacroAssembler::Address(gpr, JSCell::structureIDOffset()),
m_jit.vm()->stringStructure.get()));
MacroAssembler::Jump done = m_jit.jump();
notCell.link(&m_jit);
if (needsTypeCheck(edge, SpecCell | SpecOther)) {
- m_jit.move(gpr, tempGPR);
- m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR);
-
typeCheck(
- JSValueRegs(gpr), edge, SpecCell | SpecOther,
- m_jit.branch64(
- MacroAssembler::NotEqual, tempGPR,
- MacroAssembler::TrustedImm64(ValueNull)));
+ operand.jsValueRegs(), edge, SpecCell | SpecOther,
+ branchNotOther(operand.jsValueRegs(), tempGPR));
}
done.link(&m_jit);
-#else
- GPRReg tagGPR = operand.tagGPR();
- GPRReg payloadGPR = operand.payloadGPR();
- MacroAssembler::Jump notCell =
- m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag));
- DFG_TYPE_CHECK(
- JSValueRegs(tagGPR, payloadGPR), edge, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
- MacroAssembler::Equal,
- MacroAssembler::Address(payloadGPR, JSCell::structureIDOffset()),
- m_jit.vm()->stringStructure.get()));
- MacroAssembler::Jump done = m_jit.jump();
- notCell.link(&m_jit);
- if (needsTypeCheck(edge, SpecCell | SpecOther)) {
- m_jit.move(tagGPR, tempGPR);
- m_jit.or32(TrustedImm32(1), tempGPR);
-
- typeCheck(
- JSValueRegs(tagGPR, payloadGPR), edge, SpecCell | SpecOther,
- m_jit.branch32(
- MacroAssembler::NotEqual, tempGPR,
- MacroAssembler::TrustedImm32(JSValue::NullTag)));
- }
- done.link(&m_jit);
-#endif
}
void SpeculativeJIT::speculateString(Edge edge, GPRReg cell)
{
DFG_TYPE_CHECK(
- JSValueSource::unboxedCell(cell), edge, SpecString, m_jit.branchStructurePtr(
+ JSValueSource::unboxedCell(cell), edge, SpecString | ~SpecCell,
+ m_jit.branchStructurePtr(
MacroAssembler::NotEqual,
MacroAssembler::Address(cell, JSCell::structureIDOffset()),
m_jit.vm()->stringStructure.get()));
@@ -4620,7 +4634,7 @@
{
m_jit.loadPtr(MacroAssembler::Address(string, JSString::offsetOfValue()), storage);
- if (!needsTypeCheck(edge, SpecStringIdent))
+ if (!needsTypeCheck(edge, SpecStringIdent | ~SpecString))
return;
speculationCheck(
@@ -4632,7 +4646,7 @@
MacroAssembler::Address(storage, StringImpl::flagsOffset()),
MacroAssembler::TrustedImm32(StringImpl::flagIsIdentifier())));
- m_interpreter.filter(edge, SpecStringIdent);
+ m_interpreter.filter(edge, SpecStringIdent | ~SpecString);
}
void SpeculativeJIT::speculateStringIdent(Edge edge, GPRReg string)
@@ -4709,23 +4723,33 @@
m_interpreter.filter(edge, SpecString | SpecStringObject);
}
+void SpeculativeJIT::speculateNotStringVar(Edge edge)
+{
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+ GPRTemporary temp(this);
+ GPRReg tempGPR = temp.gpr();
+
+ JITCompiler::Jump notCell = branchNotCell(operand.jsValueRegs());
+ GPRReg cell = operand.jsValueRegs().payloadGPR();
+
+ JITCompiler::Jump notString = m_jit.branchStructurePtr(
+ MacroAssembler::NotEqual,
+ MacroAssembler::Address(cell, JSCell::structureIDOffset()),
+ m_jit.vm()->stringStructure.get());
+
+ speculateStringIdentAndLoadStorage(edge, cell, tempGPR);
+
+ notString.link(&m_jit);
+ notCell.link(&m_jit);
+}
+
void SpeculativeJIT::speculateNotCell(Edge edge)
{
if (!needsTypeCheck(edge, ~SpecCell))
return;
- JSValueOperand operand(this, edge, ManualOperandSpeculation);
-#if USE(JSVALUE64)
- typeCheck(
- JSValueRegs(operand.gpr()), edge, ~SpecCell,
- m_jit.branchTest64(
- JITCompiler::Zero, operand.gpr(), GPRInfo::tagMaskRegister));
-#else
- typeCheck(
- JSValueRegs(operand.tagGPR(), operand.payloadGPR()), edge, ~SpecCell,
- m_jit.branch32(
- JITCompiler::Equal, operand.tagGPR(), TrustedImm32(JSValue::CellTag)));
-#endif
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+ typeCheck(operand.jsValueRegs(), edge, ~SpecCell, branchIsCell(operand.jsValueRegs()));
}
void SpeculativeJIT::speculateOther(Edge edge)
@@ -4736,21 +4760,9 @@
JSValueOperand operand(this, edge, ManualOperandSpeculation);
GPRTemporary temp(this);
GPRReg tempGPR = temp.gpr();
-#if USE(JSVALUE64)
- m_jit.move(operand.gpr(), tempGPR);
- m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR);
typeCheck(
- JSValueRegs(operand.gpr()), edge, SpecOther,
- m_jit.branch64(
- MacroAssembler::NotEqual, tempGPR,
- MacroAssembler::TrustedImm64(ValueNull)));
-#else
- m_jit.move(operand.tagGPR(), tempGPR);
- m_jit.or32(TrustedImm32(1), tempGPR);
- typeCheck(
- JSValueRegs(operand.tagGPR(), operand.payloadGPR()), edge, SpecOther,
- m_jit.branch32(MacroAssembler::NotEqual, tempGPR, TrustedImm32(JSValue::NullTag)));
-#endif
+ operand.jsValueRegs(), edge, SpecOther,
+ branchNotOther(operand.jsValueRegs(), tempGPR));
}
void SpeculativeJIT::speculateMisc(Edge edge, JSValueRegs regs)
@@ -4834,6 +4846,9 @@
case StringOrStringObjectUse:
speculateStringOrStringObject(edge);
break;
+ case NotStringVarUse:
+ speculateNotStringVar(edge);
+ break;
case NotCellUse:
speculateNotCell(edge);
break;
@@ -4982,17 +4997,7 @@
op1.use();
-#if USE(JSVALUE64)
- addBranch(
- m_jit.branchTest64(
- MacroAssembler::NonZero, op1Regs.gpr(), GPRInfo::tagMaskRegister),
- data->fallThrough.block);
-#else
- addBranch(
- m_jit.branch32(
- MacroAssembler::NotEqual, op1Regs.tagGPR(), TrustedImm32(JSValue::CellTag)),
- data->fallThrough.block);
-#endif
+ addBranch(branchNotCell(op1Regs), data->fallThrough.block);
addBranch(
m_jit.branchStructurePtr(
@@ -5282,17 +5287,7 @@
op1.use();
-#if USE(JSVALUE64)
- addBranch(
- m_jit.branchTest64(
- MacroAssembler::NonZero, op1Regs.gpr(), GPRInfo::tagMaskRegister),
- data->fallThrough.block);
-#else
- addBranch(
- m_jit.branch32(
- MacroAssembler::NotEqual, op1Regs.tagGPR(), TrustedImm32(JSValue::CellTag)),
- data->fallThrough.block);
-#endif
+ addBranch(branchNotCell(op1Regs), data->fallThrough.block);
addBranch(
m_jit.branchStructurePtr(
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 957b3e3..274271c 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -861,8 +861,11 @@
GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
info.initCell(node, node->refCount(), reg);
}
- void booleanResult(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren)
+ void blessedBooleanResult(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren)
{
+#if USE(JSVALUE64)
+ jsValueResult(reg, node, DataFormatJSBoolean, mode);
+#else
if (mode == CallUseChildren)
useChildren(node);
@@ -870,6 +873,14 @@
m_gprs.retain(reg, virtualRegister, SpillOrderBoolean);
GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
info.initBoolean(node, node->refCount(), reg);
+#endif
+ }
+ void unblessedBooleanResult(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren)
+ {
+#if USE(JSVALUE64)
+ blessBoolean(reg);
+#endif
+ blessedBooleanResult(reg, node, mode);
}
#if USE(JSVALUE64)
void jsValueResult(GPRReg reg, Node* node, DataFormat format = DataFormatJS, UseChildrenMode mode = CallUseChildren)
@@ -890,6 +901,16 @@
jsValueResult(reg, node, DataFormatJS, mode);
}
#elif USE(JSVALUE32_64)
+ void booleanResult(GPRReg reg, Node* node, UseChildrenMode mode = CallUseChildren)
+ {
+ if (mode == CallUseChildren)
+ useChildren(node);
+
+ VirtualRegister virtualRegister = node->virtualRegister();
+ m_gprs.retain(reg, virtualRegister, SpillOrderBoolean);
+ GenerationInfo& info = generationInfoFromVirtualRegister(virtualRegister);
+ info.initBoolean(node, node->refCount(), reg);
+ }
void jsValueResult(GPRReg tag, GPRReg payload, Node* node, DataFormat format = DataFormatJS, UseChildrenMode mode = CallUseChildren)
{
if (mode == CallUseChildren)
@@ -1980,8 +2001,15 @@
void compileObjectToObjectOrOtherEquality(Edge leftChild, Edge rightChild);
void compileObjectOrOtherLogicalNot(Edge value);
void compileLogicalNot(Node*);
+ void compileStringEquality(
+ Node*, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR,
+ GPRReg leftTempGPR, GPRReg rightTempGPR, GPRReg leftTemp2GPR,
+ GPRReg rightTemp2GPR, JITCompiler::JumpList fastTrue,
+ JITCompiler::JumpList fastSlow);
void compileStringEquality(Node*);
void compileStringIdentEquality(Node*);
+ void compileStringToUntypedEquality(Node*, Edge stringEdge, Edge untypedEdge);
+ void compileStringIdentToNotStringVarEquality(Node*, Edge stringEdge, Edge notStringVarEdge);
void compileStringZeroLength(Node*);
void compileMiscStrictEq(Node*);
@@ -2078,6 +2106,15 @@
void compileNewFunctionExpression(Node*);
bool compileRegExpExec(Node*);
+ JITCompiler::Jump branchIsCell(JSValueRegs);
+ JITCompiler::Jump branchNotCell(JSValueRegs);
+ JITCompiler::Jump branchIsOther(JSValueRegs, GPRReg tempGPR);
+ JITCompiler::Jump branchNotOther(JSValueRegs, GPRReg tempGPR);
+
+ void moveTrueTo(GPRReg);
+ void moveFalseTo(GPRReg);
+ void blessBoolean(GPRReg);
+
// size can be an immediate or a register, and must be in bytes. If size is a register,
// it must be a different register than resultGPR. Emits code that place a pointer to
// the end of the allocation. The returned jump is the jump to the slow path.
@@ -2193,6 +2230,7 @@
void speculateStringIdent(Edge edge, GPRReg string);
void speculateStringIdent(Edge);
void speculateString(Edge);
+ void speculateNotStringVar(Edge);
template<typename StructureLocationType>
void speculateStringObjectForStructure(Edge, StructureLocationType);
void speculateStringObject(Edge, GPRReg);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 79adedc..9687bbc 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -236,8 +236,8 @@
JITCompiler::Jump notMasqueradesAsUndefined;
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
if (!isKnownCell(operand.node()))
- notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
-
+ notCell = branchNotCell(arg.jsValueRegs());
+
m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultPayloadGPR);
notMasqueradesAsUndefined = m_jit.jump();
} else {
@@ -245,8 +245,8 @@
GPRTemporary remoteGlobalObject(this);
if (!isKnownCell(operand.node()))
- notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
-
+ notCell = branchNotCell(arg.jsValueRegs());
+
JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
JITCompiler::NonZero,
JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
@@ -305,16 +305,16 @@
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
if (!isKnownCell(operand.node()))
- notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
-
+ notCell = branchNotCell(arg.jsValueRegs());
+
jump(invert ? taken : notTaken, ForceJump);
} else {
GPRTemporary localGlobalObject(this);
GPRTemporary remoteGlobalObject(this);
if (!isKnownCell(operand.node()))
- notCell = m_jit.branch32(MacroAssembler::NotEqual, argTagGPR, TrustedImm32(JSValue::CellTag));
-
+ notCell = branchNotCell(arg.jsValueRegs());
+
branchTest8(JITCompiler::Zero,
JITCompiler::Address(argPayloadGPR, JSCell::typeInfoFlagsOffset()),
JITCompiler::TrustedImm32(MasqueradesAsUndefined),
@@ -682,7 +682,7 @@
m_jit.emitStoreCodeOrigin(node->origin.semantic);
- slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, calleeTagGPR, TrustedImm32(JSValue::CellTag)));
+ slowPath.append(branchNotCell(callee.jsValueRegs()));
slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultPayloadGPR);
m_jit.storePtr(resultPayloadGPR, calleeFramePayloadSlot(JSStack::ScopeChain));
@@ -980,8 +980,16 @@
}
ASSERT((info.spillFormat() & DataFormatJS) || info.spillFormat() == DataFormatCell);
- if (type & ~SpecCell)
- speculationCheck(BadType, JSValueSource(JITCompiler::addressFor(virtualRegister)), edge, m_jit.branch32(MacroAssembler::NotEqual, JITCompiler::tagFor(virtualRegister), TrustedImm32(JSValue::CellTag)));
+ if (type & ~SpecCell) {
+ speculationCheck(
+ BadType,
+ JSValueSource(JITCompiler::addressFor(virtualRegister)),
+ edge,
+ m_jit.branch32(
+ MacroAssembler::NotEqual,
+ JITCompiler::tagFor(virtualRegister),
+ TrustedImm32(JSValue::CellTag)));
+ }
GPRReg gpr = allocate();
m_jit.load32(JITCompiler::payloadFor(virtualRegister), gpr);
m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
@@ -1001,8 +1009,11 @@
GPRReg payloadGPR = info.payloadGPR();
m_gprs.lock(tagGPR);
m_gprs.lock(payloadGPR);
- if (type & ~SpecCell)
- speculationCheck(BadType, JSValueRegs(tagGPR, payloadGPR), edge, m_jit.branch32(MacroAssembler::NotEqual, tagGPR, TrustedImm32(JSValue::CellTag)));
+ if (type & ~SpecCell) {
+ speculationCheck(
+ BadType, JSValueRegs(tagGPR, payloadGPR), edge,
+ branchNotCell(info.jsValueRegs()));
+ }
m_gprs.unlock(tagGPR);
m_gprs.release(tagGPR);
m_gprs.release(payloadGPR);
@@ -1240,8 +1251,7 @@
// It seems that most of the time when programs do a == b where b may be either null/undefined
// or an object, b is usually an object. Balance the branches to make that case fast.
- MacroAssembler::Jump rightNotCell =
- m_jit.branch32(MacroAssembler::NotEqual, op2TagGPR, TrustedImm32(JSValue::CellTag));
+ MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs());
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
@@ -1334,8 +1344,7 @@
// It seems that most of the time when programs do a == b where b may be either null/undefined
// or an object, b is usually an object. Balance the branches to make that case fast.
- MacroAssembler::Jump rightNotCell =
- m_jit.branch32(MacroAssembler::NotEqual, op2TagGPR, TrustedImm32(JSValue::CellTag));
+ MacroAssembler::Jump rightNotCell = branchNotCell(op2.jsValueRegs());
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
@@ -1432,7 +1441,7 @@
structureGPR = structure.gpr();
}
- MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
+ MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs());
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
@@ -1562,7 +1571,7 @@
GPRReg valuePayloadGPR = value.payloadGPR();
GPRReg scratchGPR = scratch.gpr();
- MacroAssembler::Jump notCell = m_jit.branch32(MacroAssembler::NotEqual, valueTagGPR, TrustedImm32(JSValue::CellTag));
+ MacroAssembler::Jump notCell = branchNotCell(value.jsValueRegs());
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
DFG_TYPE_CHECK(
JSValueRegs(valueTagGPR, valuePayloadGPR), nodeUse, (~SpecCell) | SpecObject,
@@ -3069,7 +3078,7 @@
m_jit.move(op1TagGPR, resultTagGPR);
m_jit.move(op1PayloadGPR, resultPayloadGPR);
} else {
- MacroAssembler::Jump alreadyPrimitive = m_jit.branch32(MacroAssembler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
+ MacroAssembler::Jump alreadyPrimitive = branchNotCell(op1.jsValueRegs());
MacroAssembler::Jump notPrimitive = m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(op1PayloadGPR, JSCell::structureIDOffset()), MacroAssembler::TrustedImmPtr(m_jit.vm()->stringStructure.get()));
alreadyPrimitive.link(&m_jit);
@@ -3099,8 +3108,7 @@
JITCompiler::Jump done;
if (node->child1()->prediction() & SpecString) {
- JITCompiler::Jump slowPath1 = m_jit.branch32(
- JITCompiler::NotEqual, op1TagGPR, TrustedImm32(JSValue::CellTag));
+ JITCompiler::Jump slowPath1 = branchNotCell(op1.jsValueRegs());
JITCompiler::Jump slowPath2 = m_jit.branchPtr(
JITCompiler::NotEqual,
JITCompiler::Address(op1PayloadGPR, JSCell::structureIDOffset()),
@@ -3467,8 +3475,7 @@
GPRReg tempTagGPR = tempTag.gpr();
MacroAssembler::JumpList slowCases;
- slowCases.append(m_jit.branch32(
- MacroAssembler::NotEqual, thisValueTagGPR, TrustedImm32(JSValue::CellTag)));
+ slowCases.append(branchNotCell(thisValue.jsValueRegs()));
slowCases.append(m_jit.branch8(
MacroAssembler::NotEqual,
MacroAssembler::Address(thisValuePayloadGPR, JSCell::typeInfoTypeOffset()),
@@ -3679,7 +3686,7 @@
base.use();
- JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag));
+ JITCompiler::Jump notCell = branchNotCell(base.jsValueRegs());
cachedGetById(node->origin.semantic, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell);
@@ -3735,7 +3742,7 @@
flushRegisters();
- JITCompiler::Jump notCell = m_jit.branch32(JITCompiler::NotEqual, baseTagGPR, TrustedImm32(JSValue::CellTag));
+ JITCompiler::Jump notCell = branchNotCell(base.jsValueRegs());
cachedGetById(node->origin.semantic, baseTagGPR, basePayloadGPR, resultTagGPR, resultPayloadGPR, node->identifierNumber(), notCell, DontSpill);
@@ -4079,7 +4086,7 @@
GPRTemporary localGlobalObject(this);
GPRTemporary remoteGlobalObject(this);
- JITCompiler::Jump isCell = m_jit.branch32(JITCompiler::Equal, value.tagGPR(), JITCompiler::TrustedImm32(JSValue::CellTag));
+ JITCompiler::Jump isCell = branchIsCell(value.jsValueRegs());
m_jit.compare32(JITCompiler::Equal, value.tagGPR(), TrustedImm32(JSValue::UndefinedTag), result.gpr());
JITCompiler::Jump done = m_jit.jump();
@@ -4135,7 +4142,7 @@
JSValueOperand value(this, node->child1());
GPRTemporary result(this, Reuse, value, TagWord);
- JITCompiler::Jump isNotCell = m_jit.branch32(JITCompiler::NotEqual, value.tagGPR(), JITCompiler::TrustedImm32(JSValue::CellTag));
+ JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs());
m_jit.compare8(JITCompiler::Equal,
JITCompiler::Address(value.payloadGPR(), JSCell::typeInfoTypeOffset()),
@@ -4188,7 +4195,7 @@
ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse);
- JITCompiler::Jump isNotCell = m_jit.branch32(JITCompiler::NotEqual, tagGPR, JITCompiler::TrustedImm32(JSValue::CellTag));
+ JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs());
if (node->child1().useKind() != UntypedUse)
DFG_TYPE_CHECK(JSValueRegs(tagGPR, payloadGPR), node->child1(), SpecCell, isNotCell);
@@ -4747,6 +4754,48 @@
}
#endif // ENABLE(GGC)
+JITCompiler::Jump SpeculativeJIT::branchIsCell(JSValueRegs regs)
+{
+ return m_jit.branch32(MacroAssembler::Equal, regs.tagGPR(), TrustedImm32(JSValue::CellTag));
+}
+
+JITCompiler::Jump SpeculativeJIT::branchNotCell(JSValueRegs regs)
+{
+ return m_jit.branch32(MacroAssembler::NotEqual, regs.tagGPR(), TrustedImm32(JSValue::CellTag));
+}
+
+JITCompiler::Jump SpeculativeJIT::branchIsOther(JSValueRegs regs, GPRReg tempGPR)
+{
+ m_jit.move(regs.tagGPR(), tempGPR);
+ m_jit.or32(TrustedImm32(1), tempGPR);
+ return m_jit.branch32(
+ MacroAssembler::Equal, tempGPR,
+ MacroAssembler::TrustedImm32(JSValue::NullTag));
+}
+
+JITCompiler::Jump SpeculativeJIT::branchNotOther(JSValueRegs regs, GPRReg tempGPR)
+{
+ m_jit.move(regs.tagGPR(), tempGPR);
+ m_jit.or32(TrustedImm32(1), tempGPR);
+ return m_jit.branch32(
+ MacroAssembler::NotEqual, tempGPR,
+ MacroAssembler::TrustedImm32(JSValue::NullTag));
+}
+
+void SpeculativeJIT::moveTrueTo(GPRReg gpr)
+{
+ m_jit.move(TrustedImm32(1), gpr);
+}
+
+void SpeculativeJIT::moveFalseTo(GPRReg gpr)
+{
+ m_jit.move(TrustedImm32(0), gpr);
+}
+
+void SpeculativeJIT::blessBoolean(GPRReg)
+{
+}
+
#endif
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 4187b91..8d437b0 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -242,7 +242,7 @@
JITCompiler::Jump notMasqueradesAsUndefined;
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
if (!isKnownCell(operand.node()))
- notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
+ notCell = branchNotCell(JSValueRegs(argGPR));
m_jit.move(invert ? TrustedImm32(1) : TrustedImm32(0), resultGPR);
notMasqueradesAsUndefined = m_jit.jump();
@@ -252,8 +252,8 @@
GPRTemporary scratch(this);
if (!isKnownCell(operand.node()))
- notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
-
+ notCell = branchNotCell(JSValueRegs(argGPR));
+
JITCompiler::Jump isMasqueradesAsUndefined = m_jit.branchTest8(
JITCompiler::NonZero,
JITCompiler::Address(argGPR, JSCell::typeInfoFlagsOffset()),
@@ -311,8 +311,8 @@
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
if (!isKnownCell(operand.node()))
- notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
-
+ notCell = branchNotCell(JSValueRegs(argGPR));
+
jump(invert ? taken : notTaken, ForceJump);
} else {
GPRTemporary localGlobalObject(this);
@@ -320,8 +320,8 @@
GPRTemporary scratch(this);
if (!isKnownCell(operand.node()))
- notCell = m_jit.branchTest64(MacroAssembler::NonZero, argGPR, GPRInfo::tagMaskRegister);
-
+ notCell = branchNotCell(JSValueRegs(argGPR));
+
branchTest8(JITCompiler::Zero,
JITCompiler::Address(argGPR, JSCell::typeInfoFlagsOffset()),
JITCompiler::TrustedImm32(MasqueradesAsUndefined),
@@ -1367,7 +1367,7 @@
info.fillJSValue(*m_stream, gpr, DataFormatJS);
if (type & ~SpecCell)
- speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister));
+ speculationCheck(BadType, JSValueRegs(gpr), edge, branchNotCell(JSValueRegs(gpr)));
info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
return gpr;
}
@@ -1377,7 +1377,7 @@
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
if (!ASSERT_DISABLED) {
- MacroAssembler::Jump checkCell = m_jit.branchTest64(MacroAssembler::Zero, gpr, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump checkCell = branchIsCell(JSValueRegs(gpr));
m_jit.breakpoint();
checkCell.link(&m_jit);
}
@@ -1388,7 +1388,7 @@
GPRReg gpr = info.gpr();
m_gprs.lock(gpr);
if (type & ~SpecCell)
- speculationCheck(BadType, JSValueRegs(gpr), edge, m_jit.branchTest64(MacroAssembler::NonZero, gpr, GPRInfo::tagMaskRegister));
+ speculationCheck(BadType, JSValueRegs(gpr), edge, branchNotCell(JSValueRegs(gpr)));
info.fillJSValue(*m_stream, gpr, DataFormatJSCell);
return gpr;
}
@@ -1622,8 +1622,7 @@
// It seems that most of the time when programs do a == b where b may be either null/undefined
// or an object, b is usually an object. Balance the branches to make that case fast.
- MacroAssembler::Jump rightNotCell =
- m_jit.branchTest64(MacroAssembler::NonZero, op2GPR, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump rightNotCell = branchNotCell(JSValueRegs(op2GPR));
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
@@ -1713,8 +1712,7 @@
// It seems that most of the time when programs do a == b where b may be either null/undefined
// or an object, b is usually an object. Balance the branches to make that case fast.
- MacroAssembler::Jump rightNotCell =
- m_jit.branchTest64(MacroAssembler::NonZero, op2GPR, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump rightNotCell = branchNotCell(JSValueRegs(op2GPR));
// We know that within this branch, rightChild must be a cell.
if (masqueradesAsUndefinedWatchpointValid) {
@@ -1847,7 +1845,7 @@
scratchGPR = scratch.gpr();
}
- MacroAssembler::Jump notCell = m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump notCell = branchNotCell(JSValueRegs(valueGPR));
if (masqueradesAsUndefinedWatchpointValid) {
DFG_TYPE_CHECK(
JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
@@ -1997,7 +1995,7 @@
structureGPR = structure.gpr();
}
- MacroAssembler::Jump notCell = m_jit.branchTest64(MacroAssembler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump notCell = branchNotCell(JSValueRegs(valueGPR));
if (masqueradesAsUndefinedWatchpointIsStillValid()) {
DFG_TYPE_CHECK(
JSValueRegs(valueGPR), nodeUse, (~SpecCell) | SpecObject, m_jit.branchStructurePtr(
@@ -3422,7 +3420,7 @@
op1.use();
- MacroAssembler::Jump alreadyPrimitive = m_jit.branchTest64(MacroAssembler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
+ MacroAssembler::Jump alreadyPrimitive = branchNotCell(JSValueRegs(op1GPR));
MacroAssembler::Jump notPrimitive = m_jit.branchStructurePtr(
MacroAssembler::NotEqual,
MacroAssembler::Address(op1GPR, JSCell::structureIDOffset()),
@@ -3450,8 +3448,7 @@
JITCompiler::Jump done;
if (node->child1()->prediction() & SpecString) {
- JITCompiler::Jump slowPath1 = m_jit.branchTest64(
- JITCompiler::NonZero, op1GPR, GPRInfo::tagMaskRegister);
+ JITCompiler::Jump slowPath1 = branchNotCell(JSValueRegs(op1GPR));
JITCompiler::Jump slowPath2 = m_jit.branchStructurePtr(
JITCompiler::NotEqual,
JITCompiler::Address(op1GPR, JSCell::structureIDOffset()),
@@ -3810,8 +3807,7 @@
GPRReg tempGPR = temp.gpr();
MacroAssembler::JumpList slowCases;
- slowCases.append(m_jit.branchTest64(
- MacroAssembler::NonZero, thisValueGPR, GPRInfo::tagMaskRegister));
+ slowCases.append(branchNotCell(JSValueRegs(thisValueGPR)));
slowCases.append(m_jit.branch8(
MacroAssembler::NotEqual,
MacroAssembler::Address(thisValueGPR, JSCell::typeInfoTypeOffset()),
@@ -4008,7 +4004,7 @@
base.use();
- JITCompiler::Jump notCell = m_jit.branchTest64(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
+ JITCompiler::Jump notCell = branchNotCell(JSValueRegs(baseGPR));
cachedGetById(node->origin.semantic, baseGPR, resultGPR, node->identifierNumber(), notCell);
@@ -4058,7 +4054,7 @@
base.use();
flushRegisters();
- JITCompiler::Jump notCell = m_jit.branchTest64(JITCompiler::NonZero, baseGPR, GPRInfo::tagMaskRegister);
+ JITCompiler::Jump notCell = branchNotCell(JSValueRegs(baseGPR));
cachedGetById(node->origin.semantic, baseGPR, resultGPR, node->identifierNumber(), notCell, DontSpill);
@@ -4389,7 +4385,7 @@
GPRTemporary remoteGlobalObject(this);
GPRTemporary scratch(this);
- JITCompiler::Jump isCell = m_jit.branchTest64(JITCompiler::Zero, value.gpr(), GPRInfo::tagMaskRegister);
+ JITCompiler::Jump isCell = branchIsCell(value.jsValueRegs());
m_jit.compare64(JITCompiler::Equal, value.gpr(), TrustedImm32(ValueUndefined), result.gpr());
JITCompiler::Jump done = m_jit.jump();
@@ -4449,7 +4445,7 @@
JSValueOperand value(this, node->child1());
GPRTemporary result(this, Reuse, value);
- JITCompiler::Jump isNotCell = m_jit.branchTest64(JITCompiler::NonZero, value.gpr(), GPRInfo::tagMaskRegister);
+ JITCompiler::Jump isNotCell = branchNotCell(value.jsValueRegs());
m_jit.compare8(JITCompiler::Equal,
JITCompiler::Address(value.gpr(), JSCell::typeInfoTypeOffset()),
@@ -4501,7 +4497,7 @@
ASSERT(node->child1().useKind() == UntypedUse || node->child1().useKind() == CellUse || node->child1().useKind() == StringUse);
- JITCompiler::Jump isNotCell = m_jit.branchTest64(JITCompiler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
+ JITCompiler::Jump isNotCell = branchNotCell(JSValueRegs(valueGPR));
if (node->child1().useKind() != UntypedUse)
DFG_TYPE_CHECK(JSValueSource(valueGPR), node->child1(), SpecCell, isNotCell);
@@ -5056,8 +5052,8 @@
{
JITCompiler::Jump isNotCell;
if (!isKnownCell(valueUse.node()))
- isNotCell = m_jit.branchTest64(JITCompiler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
-
+ isNotCell = branchNotCell(JSValueRegs(valueGPR));
+
JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(ownerGPR);
storeToWriteBarrierBuffer(ownerGPR, scratch1, scratch2);
ownerNotMarkedOrAlreadyRemembered.link(&m_jit);
@@ -5070,8 +5066,8 @@
{
JITCompiler::Jump isNotCell;
if (!isKnownCell(valueUse.node()))
- isNotCell = m_jit.branchTest64(JITCompiler::NonZero, valueGPR, GPRInfo::tagMaskRegister);
-
+ isNotCell = branchNotCell(JSValueRegs(valueGPR));
+
JITCompiler::Jump ownerNotMarkedOrAlreadyRemembered = m_jit.checkMarkByte(owner);
storeToWriteBarrierBuffer(owner, scratch1, scratch2);
ownerNotMarkedOrAlreadyRemembered.link(&m_jit);
@@ -5081,6 +5077,49 @@
}
#endif // ENABLE(GGC)
+JITCompiler::Jump SpeculativeJIT::branchIsCell(JSValueRegs regs)
+{
+ return m_jit.branchTest64(MacroAssembler::Zero, regs.gpr(), GPRInfo::tagMaskRegister);
+}
+
+JITCompiler::Jump SpeculativeJIT::branchNotCell(JSValueRegs regs)
+{
+ return m_jit.branchTest64(MacroAssembler::NonZero, regs.gpr(), GPRInfo::tagMaskRegister);
+}
+
+JITCompiler::Jump SpeculativeJIT::branchIsOther(JSValueRegs regs, GPRReg tempGPR)
+{
+ m_jit.move(regs.gpr(), tempGPR);
+ m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR);
+ return m_jit.branch64(
+ MacroAssembler::Equal, tempGPR,
+ MacroAssembler::TrustedImm64(ValueNull));
+}
+
+JITCompiler::Jump SpeculativeJIT::branchNotOther(JSValueRegs regs, GPRReg tempGPR)
+{
+ m_jit.move(regs.gpr(), tempGPR);
+ m_jit.and64(MacroAssembler::TrustedImm32(~TagBitUndefined), tempGPR);
+ return m_jit.branch64(
+ MacroAssembler::NotEqual, tempGPR,
+ MacroAssembler::TrustedImm64(ValueNull));
+}
+
+void SpeculativeJIT::moveTrueTo(GPRReg gpr)
+{
+ m_jit.move(TrustedImm32(ValueTrue), gpr);
+}
+
+void SpeculativeJIT::moveFalseTo(GPRReg gpr)
+{
+ m_jit.move(TrustedImm32(ValueFalse), gpr);
+}
+
+void SpeculativeJIT::blessBoolean(GPRReg gpr)
+{
+ m_jit.or32(TrustedImm32(ValueFalse), gpr);
+}
+
#endif
} } // namespace JSC::DFG
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.cpp b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
index b7a5c6f..25c9fe9 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.cpp
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.cpp
@@ -91,6 +91,9 @@
case StringOrStringObjectUse:
out.print("StringOrStringObject");
break;
+ case NotStringVarUse:
+ out.print("NotStringVar");
+ break;
case NotCellUse:
out.print("NotCell");
break;
diff --git a/Source/JavaScriptCore/dfg/DFGUseKind.h b/Source/JavaScriptCore/dfg/DFGUseKind.h
index f66d143..61bc923 100644
--- a/Source/JavaScriptCore/dfg/DFGUseKind.h
+++ b/Source/JavaScriptCore/dfg/DFGUseKind.h
@@ -52,6 +52,7 @@
KnownStringUse,
StringObjectUse,
StringOrStringObjectUse,
+ NotStringVarUse,
NotCellUse,
OtherUse,
MiscUse,
@@ -93,6 +94,8 @@
return SpecStringObject;
case StringOrStringObjectUse:
return SpecString | SpecStringObject;
+ case NotStringVarUse:
+ return ~SpecStringVar;
case NotCellUse:
return ~SpecCell;
case OtherUse:
diff --git a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
index 9070b84..d503af7 100644
--- a/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
+++ b/Source/JavaScriptCore/ftl/FTLCapabilities.cpp
@@ -238,6 +238,8 @@
break;
if (node->isBinaryUseKind(NumberUse))
break;
+ if (node->isBinaryUseKind(StringIdentUse))
+ break;
if (node->isBinaryUseKind(ObjectUse))
break;
if (node->isBinaryUseKind(UntypedUse))
@@ -256,6 +258,8 @@
break;
if (node->isBinaryUseKind(NumberUse))
break;
+ if (node->isBinaryUseKind(StringIdentUse))
+ break;
if (node->isBinaryUseKind(ObjectUse))
break;
if (node->isBinaryUseKind(BooleanUse))
@@ -264,6 +268,10 @@
break;
if (node->isBinaryUseKind(UntypedUse, MiscUse))
break;
+ if (node->isBinaryUseKind(StringIdentUse, NotStringVarUse))
+ break;
+ if (node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
+ break;
return CannotCompile;
case CompareLess:
case CompareLessEq:
@@ -358,6 +366,8 @@
case NotCellUse:
case OtherUse:
case MiscUse:
+ case StringIdentUse:
+ case NotStringVarUse:
// These are OK.
break;
default:
diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
index 78f62fb..7dcfaf6 100644
--- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
+++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp
@@ -3364,7 +3364,8 @@
|| m_node->isBinaryUseKind(MachineIntUse)
|| m_node->isBinaryUseKind(NumberUse)
|| m_node->isBinaryUseKind(ObjectUse)
- || m_node->isBinaryUseKind(BooleanUse)) {
+ || m_node->isBinaryUseKind(BooleanUse)
+ || m_node->isBinaryUseKind(StringIdentUse)) {
compileCompareStrictEq();
return;
}
@@ -3417,6 +3418,12 @@
return;
}
+ if (m_node->isBinaryUseKind(StringIdentUse)) {
+ setBoolean(
+ m_out.equal(lowStringIdent(m_node->child1()), lowStringIdent(m_node->child2())));
+ return;
+ }
+
if (m_node->isBinaryUseKind(ObjectUse)) {
setBoolean(
m_out.equal(
@@ -3441,6 +3448,36 @@
return;
}
+ if (m_node->isBinaryUseKind(StringIdentUse, NotStringVarUse)
+ || m_node->isBinaryUseKind(NotStringVarUse, StringIdentUse)) {
+ Edge leftEdge = m_node->childFor(StringIdentUse);
+ Edge rightEdge = m_node->childFor(NotStringVarUse);
+
+ LValue left = lowStringIdent(leftEdge);
+ LValue rightValue = lowJSValue(rightEdge, ManualOperandSpeculation);
+
+ LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar is cell case"));
+ LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar is string case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("CompareStrictEq StringIdent to NotStringVar continuation"));
+
+ ValueFromBlock notCellResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(isCell(rightValue), unsure(isCellCase), unsure(continuation));
+
+ LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
+ ValueFromBlock notStringResult = m_out.anchor(m_out.booleanFalse);
+ m_out.branch(isString(rightValue), unsure(isStringCase), unsure(continuation));
+
+ m_out.appendTo(isStringCase, continuation);
+ LValue right = m_out.loadPtr(rightValue, m_heaps.JSString_value);
+ speculateStringIdent(rightEdge, rightValue, right);
+ ValueFromBlock isStringResult = m_out.anchor(m_out.equal(left, right));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ setBoolean(m_out.phi(m_out.boolean, notCellResult, notStringResult, isStringResult));
+ return;
+ }
+
RELEASE_ASSERT_NOT_REACHED();
}
@@ -4821,13 +4858,23 @@
LValue lowString(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
- ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringUse || edge.useKind() == KnownStringUse);
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringUse || edge.useKind() == KnownStringUse || edge.useKind() == StringIdentUse);
LValue result = lowCell(edge, mode);
speculateString(edge, result);
return result;
}
+ LValue lowStringIdent(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
+ {
+ ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == StringIdentUse);
+
+ LValue string = lowString(edge, mode);
+ LValue stringImpl = m_out.loadPtr(string, m_heaps.JSString_value);
+ speculateStringIdent(edge, string, stringImpl);
+ return stringImpl;
+ }
+
LValue lowNonNullObject(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
{
ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || edge.useKind() == ObjectUse);
@@ -5189,6 +5236,9 @@
case StringUse:
speculateString(edge);
break;
+ case StringIdentUse:
+ speculateStringIdent(edge);
+ break;
case StringObjectUse:
speculateStringObject(edge);
break;
@@ -5207,6 +5257,9 @@
case BooleanUse:
speculateBoolean(edge);
break;
+ case NotStringVarUse:
+ speculateNotStringVar(edge);
+ break;
case NotCellUse:
speculateNotCell(edge);
break;
@@ -5366,7 +5419,7 @@
void speculateString(Edge edge, LValue cell)
{
- FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString, isNotString(cell));
+ FTL_TYPE_CHECK(jsValueValue(cell), edge, SpecString | ~SpecCell, isNotString(cell));
}
void speculateString(Edge edge)
@@ -5374,6 +5427,25 @@
speculateString(edge, lowCell(edge));
}
+ void speculateStringIdent(Edge edge, LValue string, LValue stringImpl)
+ {
+ if (!m_interpreter.needsTypeCheck(edge, SpecStringIdent | ~SpecString))
+ return;
+
+ speculate(BadType, jsValueValue(string), edge.node(), m_out.isNull(stringImpl));
+ speculate(
+ BadType, jsValueValue(string), edge.node(),
+ m_out.testIsZero32(
+ m_out.load32(stringImpl, m_heaps.StringImpl_hashAndFlags),
+ m_out.constInt32(StringImpl::flagIsIdentifier())));
+ m_interpreter.filter(edge, SpecStringIdent | ~SpecString);
+ }
+
+ void speculateStringIdent(Edge edge)
+ {
+ lowStringIdent(edge);
+ }
+
void speculateStringObject(Edge edge)
{
if (!m_interpreter.needsTypeCheck(edge, SpecStringObject))
@@ -5475,6 +5547,29 @@
lowBoolean(edge);
}
+ void speculateNotStringVar(Edge edge)
+ {
+ if (!m_interpreter.needsTypeCheck(edge, ~SpecStringVar))
+ return;
+
+ LValue value = lowJSValue(edge, ManualOperandSpeculation);
+
+ LBasicBlock isCellCase = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar is cell case"));
+ LBasicBlock isStringCase = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar is string case"));
+ LBasicBlock continuation = FTL_NEW_BLOCK(m_out, ("Speculate NotStringVar continuation"));
+
+ m_out.branch(isCell(value), unsure(isCellCase), unsure(continuation));
+
+ LBasicBlock lastNext = m_out.appendTo(isCellCase, isStringCase);
+ m_out.branch(isString(value), unsure(isStringCase), unsure(continuation));
+
+ m_out.appendTo(isStringCase, continuation);
+ speculateStringIdent(edge, value, m_out.loadPtr(value, m_heaps.JSString_value));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ }
+
void speculateNotCell(Edge edge)
{
if (!m_interpreter.needsTypeCheck(edge))
diff --git a/Source/JavaScriptCore/runtime/JSCJSValue.h b/Source/JavaScriptCore/runtime/JSCJSValue.h
index 918de14..3009d47 100644
--- a/Source/JavaScriptCore/runtime/JSCJSValue.h
+++ b/Source/JavaScriptCore/runtime/JSCJSValue.h
@@ -100,6 +100,12 @@
#define TagOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag))
#define PayloadOffset (OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload))
+#if USE(JSVALUE64)
+#define CellPayloadOffset 0
+#else
+#define CellPayloadOffset PayloadOffset
+#endif
+
enum WhichValueWord {
TagWord,
PayloadWord
diff --git a/Source/JavaScriptCore/tests/stress/string-ident-to-not-string-var-equality.js b/Source/JavaScriptCore/tests/stress/string-ident-to-not-string-var-equality.js
new file mode 100644
index 0000000..3ceb1b2
--- /dev/null
+++ b/Source/JavaScriptCore/tests/stress/string-ident-to-not-string-var-equality.js
@@ -0,0 +1,32 @@
+function foo(a, b) {
+ return a === b;
+}
+
+function bar(a, b) {
+ return b === a;
+}
+
+function test(a, b, expected) {
+ var fooActual = foo(a, b);
+ var barActual = bar(a, b);
+
+ if (fooActual != expected)
+ throw new Error("Bad result: " + fooActual);
+ if (barActual != expected)
+ throw new Error("Bad result: " + barActual);
+}
+
+for (var i = 0; i < 10000; ++i) {
+ test("foo", "foo", true);
+ test("foo", "bar", false);
+ test("fuz", 42, false);
+ test("buz", {}, false);
+ test("bla", null, false);
+}
+
+var fooString = "";
+fooString += "f";
+for (var i = 0; i < 2; ++i)
+ fooString += "o";
+
+test(fooString, "foo", true);