Diff
Modified: trunk/JSTests/ChangeLog (278567 => 278568)
--- trunk/JSTests/ChangeLog 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/JSTests/ChangeLog 2021-06-07 19:55:30 UTC (rev 278568)
@@ -1,3 +1,27 @@
+2021-06-07 Robin Morisset <rmoris...@apple.com>
+
+ Optimize compareStrictEq when neither side is a double and at least one is neither a string nor a BigInt
+ https://bugs.webkit.org/show_bug.cgi?id=226676
+
+ Reviewed by Filip Pizlo.
+
+ I made two variants of the already existing poly-stricteq microbenchmarks with different types in the array.
+ I also tweaked all three so that we more reliably reach the FTL.
+ Finally I added a stress-test to verify that I did not introduce an OSR exit bug.
+
+ * microbenchmarks/poly-stricteq-not-double-nor-string.js: Added.
+ (foo):
+ (test):
+ * microbenchmarks/poly-stricteq-not-double.js: Added.
+ (foo):
+ (test):
+ * microbenchmarks/poly-stricteq.js:
+ (foo):
+ (test):
+ * stress/poly-stricteq-not-double-nor-string-fail.js: Added.
+ (foo):
+ (test):
+
2021-06-04 Yusuke Suzuki <ysuz...@apple.com>
[JSC] Private static method should define privateClassBrandIdentifier in class-scope
Added: trunk/JSTests/microbenchmarks/poly-stricteq-not-double-nor-string.js (0 => 278568)
--- trunk/JSTests/microbenchmarks/poly-stricteq-not-double-nor-string.js (rev 0)
+++ trunk/JSTests/microbenchmarks/poly-stricteq-not-double-nor-string.js 2021-06-07 19:55:30 UTC (rev 278568)
@@ -0,0 +1,40 @@
+//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
+//@ runNoFTL
+
+// Tests the performance of polymorphic strict equality.
+// It has most kinds of types, but not Doubles. This is relevant because NaN is the only value that returns false when compared to itself.
+// This test does not have strings or big ints either. This is relevant because strings/big ints at different places in memory can compare equal.
+
+var array = [];
+
+for (var i = 0; i < 1000; ++i) {
+ array.push((i%2) == 0);
+ array.push(i);
+ array.push([i]);
+ var o = {};
+ o["a" + i] = i + 1;
+ array.push(o);
+}
+
+var numStrictEqual = 0;
+
+function foo(x, y)
+{
+ if(x === y)
+ numStrictEqual++;
+}
+
+function test()
+{
+ for (var i = 0; i < array.length; ++i) {
+ for (var j = i + 1; j < array.length; ++j) {
+ foo(array[i], array[j]);
+ }
+ }
+
+ if (numStrictEqual != 249500)
+ throw "Incorrect result: " + numStrictEqual;
+}
+noInline(test)
+test();
+
Added: trunk/JSTests/microbenchmarks/poly-stricteq-not-double.js (0 => 278568)
--- trunk/JSTests/microbenchmarks/poly-stricteq-not-double.js (rev 0)
+++ trunk/JSTests/microbenchmarks/poly-stricteq-not-double.js 2021-06-07 19:55:30 UTC (rev 278568)
@@ -0,0 +1,40 @@
+//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
+//@ runNoFTL
+
+// Tests the performance of polymorphic strict equality.
+// It has most kinds of types, but not Doubles. This is relevant because NaN is the only value that returns false when compared to itself.
+
+var array = [];
+
+for (var i = 0; i < 1000; ++i) {
+ array.push((i%2) == 0);
+ array.push(i);
+ array.push("" + i);
+ var o = {};
+ o["a" + i] = i + 1;
+ array.push(o);
+}
+
+var numStrictEqual = 0;
+
+function foo(x, y)
+{
+ if(x === y)
+ numStrictEqual++;
+}
+
+function test()
+{
+ for (var i = 0; i < array.length; ++i) {
+ for (var j = i + 1; j < array.length; ++j) {
+ foo(array[i], array[j]);
+ }
+ }
+
+ if (numStrictEqual != 249500)
+ throw "Incorrect result: " + numStrictEqual;
+}
+noInline(test);
+test();
+
+
Modified: trunk/JSTests/microbenchmarks/poly-stricteq.js (278567 => 278568)
--- trunk/JSTests/microbenchmarks/poly-stricteq.js 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/JSTests/microbenchmarks/poly-stricteq.js 2021-06-07 19:55:30 UTC (rev 278568)
@@ -6,8 +6,8 @@
var array = [];
for (var i = 0; i < 1000; ++i) {
- array.push(i);
- array.push((i%2) == 0);
+ array.push((i % 2) == 0);
+ array.push(3.14 * i);
array.push("" + i);
var o = {};
o["a" + i] = i + 1;
@@ -15,15 +15,25 @@
}
var numStrictEqual = 0;
-for (var i = 0; i < array.length; ++i) {
- for (var j = i + 1; j < array.length; ++j) {
- if (array[i] === array[j])
- numStrictEqual++;
- }
+
+function foo(x, y)
+{
+ if(x === y)
+ numStrictEqual++;
}
-if (numStrictEqual != 249500)
- throw "Incorrect result: " + numStrictEqual;
+function test()
+{
+ for (var i = 0; i < array.length; ++i) {
+ for (var j = i + 1; j < array.length; ++j) {
+ foo(array[i], array[j]);
+ }
+ }
+ if (numStrictEqual != 249500)
+ throw "Incorrect result: " + numStrictEqual;
+}
+noInline(test);
+test();
Added: trunk/JSTests/stress/poly-stricteq-not-double-nor-string-fail.js (0 => 278568)
--- trunk/JSTests/stress/poly-stricteq-not-double-nor-string-fail.js (rev 0)
+++ trunk/JSTests/stress/poly-stricteq-not-double-nor-string-fail.js 2021-06-07 19:55:30 UTC (rev 278568)
@@ -0,0 +1,43 @@
+//@ skip if $model == "Apple Watch Series 3" # added by mark-jsc-stress-test.py
+
+var array = [];
+
+for (var i = 0; i < 1000; ++i) {
+ array.push((i%2) == 0);
+ array.push(i);
+ array.push([i]);
+ var o = {};
+ o["a" + i] = i + 1;
+ array.push(o);
+}
+
+var numStrictEqual = 0;
+
+function foo(x, y)
+{
+ if(x === y)
+ numStrictEqual++;
+}
+noInline(foo);
+
+function test()
+{
+ for (var i = 0; i < array.length; ++i) {
+ for (var j = i + 1; j < array.length; ++j) {
+ foo(array[i], array[j]);
+ }
+ }
+
+ if (numStrictEqual != 249500)
+ throw "Incorrect result: " + numStrictEqual;
+
+ foo(42, 42.0);
+ foo(NaN, NaN);
+ foo("foobar", "foo" + "bar")
+
+ if (numStrictEqual != 249502)
+ throw "Incorrect result at the end " + numStrictEqual;
+}
+noInline(test)
+test();
+
Modified: trunk/Source/_javascript_Core/ChangeLog (278567 => 278568)
--- trunk/Source/_javascript_Core/ChangeLog 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-06-07 19:55:30 UTC (rev 278568)
@@ -1,3 +1,86 @@
+2021-06-07 Robin Morisset <rmoris...@apple.com>
+
+ Optimize compareStrictEq when neither side is a double and at least one is neither a string nor a BigInt
+ https://bugs.webkit.org/show_bug.cgi?id=226676
+
+ Reviewed by Filip Pizlo.
+
+ There is exactly one case where x === y must return false despite x and y being JSValues with the same bits:
+ NaN === NaN
+ There are a few cases where x === y must return true despite x and y being JSValues with potentially different bits:
+ Double === Int32
+ String === String
+ HeapBigInt === HeapBigInt
+ HeapBigInt === BigInt32 (if they are enabled)
+ If we don't have a double on either side, at least one side has neither a String nor a HeapBigInt, and BigInt32 are disabled, we can clearly ignore all of these pathological cases.
+
+ This optimization was decided based on looking at DFG graphs of Speedometer2; here is a sample of the compareStrictEq(Untyped, Untyped), courtesy of Phil:
+ Final|Array|String|Bool, Final|Array|String|Bool
+ Array|String|Bool, String|Bool (twice)
+ Array|String|Bool, String|Int32 (once in DFG, once in FTL)
+ ! Array|String|Bool, Array|Bool
+ ! Final|Other, Final|Other
+ ! Int32|Other, Int32
+ Final|StringIdent, Final|StringIdent (3 times)
+ Final|StringIdent|BoolInt32, StringIdent|BoolInt32 (twice)
+ String|Bool, String|Bool (4 times)
+ DoublePureNaN, String|Bool
+ ! Other, Function|Other
+ ! Final|Other, Final|Function|Other (twice)
+ Final|String|Bool|Other, Final|String|Bool|Other (3 times, two in the FTL)
+ Final|String|Int32, String|Int32 (four times)
+ String|Int32|Bool, Function|String|Int32|Bool (twice)
+ String|DoublePureNaN, String|Bool (twice)
+ ! Final|Bool|Other, Final|Function|Other (four times, twice in FTL)
+ I marked with a ! those for which this optimization should apply.
+
+ The only slightly interesting part of this patch is DFG::SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString where I took care to skip every test whose result we can predict from the abstract interpreter.
+
+ Results on microbenchmarks:
+ poly-stricteq-not-double 45.5793+-0.5304 ? 46.0306+-0.5621 ?
+ poly-stricteq-not-double-nor-string 45.5829+-0.5750 ^ 16.9089+-0.3070 ^ definitely 2.6958x faster
+ poly-stricteq 49.9719+-0.6450 48.9855+-0.5227 might be 1.0201x faster
+
+ I also measured the amount of code that we generate in the DFG on JetStream2.
+ The results here are disappointing but still measurable. Before:
+ DFG_fast_CompareStrictEq totalBytes: 468425 count: 10951 avg: 42.774632
+ DFG_fast_CompareStrictEq totalBytes: 468020 count: 10917 avg: 42.870752
+ DFG_fast_CompareStrictEq totalBytes: 467424 count: 10888 avg: 42.930198
+ After:
+ DFG_fast_CompareStrictEq totalBytes: 463946 count: 10917 avg: 42.497573
+ DFG_fast_CompareStrictEq totalBytes: 474492 count: 11138 avg: 42.601185
+ DFG_fast_CompareStrictEq totalBytes: 467138 count: 10970 avg: 42.583227
+
+ * bytecode/SpeculatedType.h:
+ (JSC::isNeitherDoubleNorHeapBigIntNorStringSpeculation):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::shouldSpeculateNeitherDoubleNorHeapBigIntNorString):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::SafeToExecuteEdge::operator()):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compileStrictEq):
+ (JSC::DFG::SpeculativeJIT::compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality):
+ (JSC::DFG::SpeculativeJIT::compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality):
+ (JSC::DFG::SpeculativeJIT::speculateNotDouble):
+ (JSC::DFG::SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString):
+ (JSC::DFG::SpeculativeJIT::speculate):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGUseKind.cpp:
+ (WTF::printInternal):
+ * dfg/DFGUseKind.h:
+ (JSC::DFG::typeFilterFor):
+ (JSC::DFG::checkMayCrashIfInputIsEmpty):
+ * ftl/FTLCapabilities.cpp:
+ (JSC::FTL::canCompile):
+ * ftl/FTLLowerDFGToB3.cpp:
+ (JSC::FTL::DFG::LowerDFGToB3::compileCompareStrictEq):
+ (JSC::FTL::DFG::LowerDFGToB3::speculate):
+ (JSC::FTL::DFG::LowerDFGToB3::speculateNeitherDoubleNorHeapBigIntNorString):
+
2021-06-07 Tuomas Karkkainen <tuomas.web...@apple.com>
$vm should have a function for checking if security assertions are enabled similar to $vm.assertEnabled
Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.h (278567 => 278568)
--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.h 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.h 2021-06-07 19:55:30 UTC (rev 278568)
@@ -444,6 +444,11 @@
return !(type & SpecFullDouble);
}
+inline bool isNeitherDoubleNorHeapBigIntNorStringSpeculation(SpeculatedType type)
+{
+ return !(type & (SpecFullDouble | SpecHeapBigInt | SpecString));
+}
+
inline bool isOtherSpeculation(SpeculatedType value)
{
return value == SpecOther;
Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp 2021-06-07 19:55:30 UTC (rev 278568)
@@ -47,7 +47,7 @@
// 1. Allocates any objects.
// 2. Resolves a rope string, which allocates a string.
// 3. Produces a string (which allocates the string) except when we can prove that
- // the string will always be one of the pre-allcoated SmallStrings.
+ // the string will always be one of the pre-allocated SmallStrings.
// 4. Triggers a structure transition (which can allocate a new structure)
// unless it is a known transition between previously allocated structures
// such as between Array types.
@@ -496,7 +496,8 @@
|| node->isBinaryUseKind(ObjectUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, ObjectUse)
|| node->isBinaryUseKind(ObjectUse)
|| node->isBinaryUseKind(MiscUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, MiscUse)
- || node->isBinaryUseKind(StringIdentUse, NotStringVarUse) || node->isBinaryUseKind(NotStringVarUse, StringIdentUse))
+ || node->isBinaryUseKind(StringIdentUse, NotStringVarUse) || node->isBinaryUseKind(NotStringVarUse, StringIdentUse)
+ || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse) || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse))
return false;
return true;
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2021-06-07 19:55:30 UTC (rev 278568)
@@ -4408,6 +4408,23 @@
node->setOpAndDefaultFlags(CompareStrictEq);
return;
}
+#if !USE(BIGINT32)
+ // As long as a BigInt32 and a HeapBigInt can compare equal, it is not sound to replace compareStrictEq by a simple comparison of the JSValue in the following cases.
+ if (node->child1()->shouldSpeculateNeitherDoubleNorHeapBigIntNorString()
+ && node->child2()->shouldSpeculateNotDouble()) {
+ fixEdge<NeitherDoubleNorHeapBigIntNorStringUse>(node->child1());
+ fixEdge<NotDoubleUse>(node->child2());
+ node->setOpAndDefaultFlags(CompareStrictEq);
+ return;
+ }
+ if (node->child1()->shouldSpeculateNotDouble()
+ && node->child2()->shouldSpeculateNeitherDoubleNorHeapBigIntNorString()) {
+ fixEdge<NotDoubleUse>(node->child1());
+ fixEdge<NeitherDoubleNorHeapBigIntNorStringUse>(node->child2());
+ node->setOpAndDefaultFlags(CompareStrictEq);
+ return;
+ }
+#endif
}
void fixupChecksInBlock(BasicBlock* block)
Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGNode.h 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h 2021-06-07 19:55:30 UTC (rev 278568)
@@ -2802,6 +2802,11 @@
{
return isNotDoubleSpeculation(prediction());
}
+
+ bool shouldSpeculateNeitherDoubleNorHeapBigIntNorString()
+ {
+ return isNeitherDoubleNorHeapBigIntNorStringSpeculation(prediction());
+ }
bool shouldSpeculateUntypedForArithmetic()
{
Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h 2021-06-07 19:55:30 UTC (rev 278568)
@@ -93,6 +93,7 @@
case AnyIntUse:
case DoubleRepAnyIntUse:
case NotDoubleUse:
+ case NeitherDoubleNorHeapBigIntNorStringUse:
return;
case KnownInt32Use:
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2021-06-07 19:55:30 UTC (rev 278568)
@@ -6933,7 +6933,42 @@
compileSymbolEquality(node);
return false;
}
-
+
+#if !USE(BIGINT32)
+ if (node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse)) {
+ Edge notDoubleChild = node->child1();
+ Edge neitherDoubleNorHeapBigIntNorStringChild = node->child2();
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ Node* branchNode = m_block->at(branchIndexInBlock);
+ compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(node, branchNode, notDoubleChild, neitherDoubleNorHeapBigIntNorStringChild);
+ use(notDoubleChild);
+ use(neitherDoubleNorHeapBigIntNorStringChild);
+ m_indexInBlock = branchIndexInBlock;
+ m_currentNode = branchNode;
+ return true;
+ }
+ compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(node, notDoubleChild, neitherDoubleNorHeapBigIntNorStringChild);
+ return false;
+ }
+ if (node->isBinaryUseKind(NeitherDoubleNorHeapBigIntNorStringUse, NotDoubleUse)) {
+ Edge neitherDoubleNorHeapBigIntNorStringChild = node->child1();
+ Edge notDoubleChild = node->child2();
+ unsigned branchIndexInBlock = detectPeepHoleBranch();
+ if (branchIndexInBlock != UINT_MAX) {
+ Node* branchNode = m_block->at(branchIndexInBlock);
+ compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(node, branchNode, notDoubleChild, neitherDoubleNorHeapBigIntNorStringChild);
+ use(notDoubleChild);
+ use(neitherDoubleNorHeapBigIntNorStringChild);
+ m_indexInBlock = branchIndexInBlock;
+ m_currentNode = branchNode;
+ return true;
+ }
+ compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(node, notDoubleChild, neitherDoubleNorHeapBigIntNorStringChild);
+ return false;
+ }
+#endif
+
if (node->isBinaryUseKind(HeapBigIntUse)) {
compileHeapBigIntEquality(node);
return false;
@@ -7163,6 +7198,72 @@
}
}
+void SpeculativeJIT::compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node* node, Edge notDoubleChild, Edge neitherDoubleNorHeapBigIntNorStringChild)
+{
+ JSValueOperand left(this, notDoubleChild, ManualOperandSpeculation);
+ JSValueOperand right(this, neitherDoubleNorHeapBigIntNorStringChild, ManualOperandSpeculation);
+
+ GPRTemporary temp(this);
+#if USE(JSVALUE64)
+ GPRTemporary result(this, Reuse, left, right);
+#else
+ GPRTemporary result(this, Reuse, left, PayloadWord);
+#endif
+ JSValueRegs leftRegs = left.jsValueRegs();
+ JSValueRegs rightRegs = right.jsValueRegs();
+ GPRReg tempGPR = temp.gpr();
+ GPRReg resultGPR = result.gpr();
+
+ speculateNotDouble(notDoubleChild, leftRegs, tempGPR);
+ speculateNeitherDoubleNorHeapBigIntNorString(neitherDoubleNorHeapBigIntNorStringChild, rightRegs, tempGPR);
+
+#if USE(JSVALUE64)
+ m_jit.compare64(JITCompiler::Equal, left.gpr(), right.gpr(), result.gpr());
+#else
+ m_jit.move(TrustedImm32(0), result.gpr());
+ JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, left.tagGPR(), right.tagGPR());
+ m_jit.compare32(JITCompiler::Equal, left.payloadGPR(), right.payloadGPR(), result.gpr());
+ notEqual.link(&m_jit);
+#endif
+ unblessedBooleanResult(resultGPR, node);
+}
+
+void SpeculativeJIT::compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node*, Node* branchNode, Edge notDoubleChild, Edge neitherDoubleNorHeapBigIntNorStringChild)
+{
+ JSValueOperand left(this, notDoubleChild, ManualOperandSpeculation);
+ JSValueOperand right(this, neitherDoubleNorHeapBigIntNorStringChild, ManualOperandSpeculation);
+
+ GPRTemporary temp(this);
+ JSValueRegs leftRegs = left.jsValueRegs();
+ JSValueRegs rightRegs = right.jsValueRegs();
+ GPRReg tempGPR = temp.gpr();
+
+ speculateNotDouble(notDoubleChild, leftRegs, tempGPR);
+ speculateNeitherDoubleNorHeapBigIntNorString(neitherDoubleNorHeapBigIntNorStringChild, rightRegs, tempGPR);
+
+ BasicBlock* taken = branchNode->branchData()->taken.block;
+ BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
+
+#if USE(JSVALUE64)
+ if (taken == nextBlock()) {
+ branch64(JITCompiler::NotEqual, left.gpr(), right.gpr(), notTaken);
+ jump(taken);
+ } else {
+ branch64(JITCompiler::Equal, left.gpr(), right.gpr(), taken);
+ jump(notTaken);
+ }
+#else
+ branch32(JITCompiler::NotEqual, left.tagGPR(), right.tagGPR(), notTaken);
+ if (taken == nextBlock()) {
+ branch32(JITCompiler::NotEqual, left.payloadGPR(), right.payloadGPR(), notTaken);
+ jump(taken);
+ } else {
+ branch32(JITCompiler::Equal, left.payloadGPR(), right.payloadGPR(), taken);
+ jump(notTaken);
+ }
+#endif
+}
+
void SpeculativeJIT::compileStringEquality(
Node* node, GPRReg leftGPR, GPRReg rightGPR, GPRReg lengthGPR, GPRReg leftTempGPR,
GPRReg rightTempGPR, GPRReg leftTemp2GPR, GPRReg rightTemp2GPR,
@@ -11432,6 +11533,23 @@
#endif
}
+void SpeculativeJIT::speculateNotDouble(Edge edge, JSValueRegs regs, GPRReg tempGPR)
+{
+ if (!needsTypeCheck(edge, ~SpecFullDouble))
+ return;
+
+ JITCompiler::Jump done;
+
+ bool mayBeInt32 = needsTypeCheck(edge, ~SpecInt32Only);
+ if (mayBeInt32)
+ done = m_jit.branchIfInt32(regs);
+
+ DFG_TYPE_CHECK(regs, edge, ~SpecFullDouble, m_jit.branchIfNumber(regs, tempGPR));
+
+ if (mayBeInt32)
+ done.link(&m_jit);
+}
+
void SpeculativeJIT::speculateNotDouble(Edge edge)
{
if (!needsTypeCheck(edge, ~SpecFullDouble))
@@ -11442,11 +11560,46 @@
JSValueRegs regs = operand.jsValueRegs();
GPRReg tempGPR = temp.gpr();
- JITCompiler::Jump done = m_jit.branchIfInt32(regs);
+ speculateNotDouble(edge, regs, tempGPR);
+}
+
+void SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString(Edge edge, JSValueRegs regs, GPRReg tempGPR)
+{
+ if (!needsTypeCheck(edge, ~(SpecFullDouble | SpecString)))
+ return;
+
+ MacroAssembler::JumpList done;
+
+ bool mayBeInt32 = needsTypeCheck(edge, ~SpecInt32Only);
+ if (mayBeInt32)
+ done.append(m_jit.branchIfInt32(regs));
+
DFG_TYPE_CHECK(regs, edge, ~SpecFullDouble, m_jit.branchIfNumber(regs, tempGPR));
- done.link(&m_jit);
+
+ bool mayNotBeCell = needsTypeCheck(edge, SpecCell);
+ if (mayNotBeCell)
+ done.append(m_jit.branchIfNotCell(regs));
+
+ DFG_TYPE_CHECK(regs, edge, ~SpecString, m_jit.branchIfString(regs.payloadGPR()));
+ DFG_TYPE_CHECK(regs, edge, ~SpecHeapBigInt, m_jit.branchIfHeapBigInt(regs.payloadGPR()));
+
+ if (mayBeInt32 || mayNotBeCell)
+ done.link(&m_jit);
}
+void SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString(Edge edge)
+{
+ if (!needsTypeCheck(edge, ~(SpecFullDouble | SpecString)))
+ return;
+
+ JSValueOperand operand(this, edge, ManualOperandSpeculation);
+ GPRTemporary temp(this);
+ JSValueRegs regs = operand.jsValueRegs();
+ GPRReg tempGPR = temp.gpr();
+
+ speculateNeitherDoubleNorHeapBigIntNorString(edge, regs, tempGPR);
+}
+
void SpeculativeJIT::speculateOther(Edge edge, JSValueRegs regs, GPRReg tempGPR)
{
DFG_TYPE_CHECK(regs, edge, SpecOther, m_jit.branchIfNotOther(regs, tempGPR));
@@ -11632,6 +11785,9 @@
case NotDoubleUse:
speculateNotDouble(edge);
break;
+ case NeitherDoubleNorHeapBigIntNorStringUse:
+ speculateNeitherDoubleNorHeapBigIntNorString(edge);
+ break;
case OtherUse:
speculateOther(edge);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2021-06-07 19:55:30 UTC (rev 278568)
@@ -1189,6 +1189,8 @@
void compileSymbolEquality(Node*);
void compileHeapBigIntEquality(Node*);
void compilePeepHoleSymbolEquality(Node*, Node* branchNode);
+ void compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node*, Edge notDoubleEdge, Edge neitherDoubleNorHeapBigIntNorStringEdge);
+ void compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node*, Node* branchNode, Edge notDoubleEdge, Edge neitherDoubleNorHeapBigIntNorStringEdge);
void compileSymbolUntypedEquality(Node*, Edge symbolEdge, Edge untypedEdge);
void emitObjectOrOtherBranch(Edge value, BasicBlock* taken, BasicBlock* notTaken);
@@ -1671,7 +1673,10 @@
void speculateNotCell(Edge, JSValueRegs);
void speculateNotCell(Edge);
void speculateNotCellNorBigInt(Edge);
+ void speculateNotDouble(Edge, JSValueRegs, GPRReg temp);
void speculateNotDouble(Edge);
+ void speculateNeitherDoubleNorHeapBigIntNorString(Edge, JSValueRegs, GPRReg temp);
+ void speculateNeitherDoubleNorHeapBigIntNorString(Edge);
void speculateOther(Edge, JSValueRegs, GPRReg temp);
void speculateOther(Edge, JSValueRegs);
void speculateOther(Edge);
Modified: trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp 2021-06-07 19:55:30 UTC (rev 278568)
@@ -173,6 +173,9 @@
case NotDoubleUse:
out.print("NotDouble");
return;
+ case NeitherDoubleNorHeapBigIntNorStringUse:
+ out.print("NeitherDoubleNorHeapBigIntNorString");
+ return;
case KnownOtherUse:
out.print("KnownOther");
return;
Modified: trunk/Source/_javascript_Core/dfg/DFGUseKind.h (278567 => 278568)
--- trunk/Source/_javascript_Core/dfg/DFGUseKind.h 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/dfg/DFGUseKind.h 2021-06-07 19:55:30 UTC (rev 278568)
@@ -82,6 +82,7 @@
NotCellUse,
NotCellNorBigIntUse,
NotDoubleUse,
+ NeitherDoubleNorHeapBigIntNorStringUse,
KnownOtherUse,
OtherUse,
MiscUse,
@@ -190,6 +191,8 @@
return ~SpecCellCheck & ~SpecBigInt;
case NotDoubleUse:
return ~SpecFullDouble;
+ case NeitherDoubleNorHeapBigIntNorStringUse:
+ return ~SpecFullDouble & ~SpecHeapBigInt & ~SpecString;
case KnownOtherUse:
case OtherUse:
return SpecOther;
@@ -309,6 +312,7 @@
case NotCellUse:
case NotCellNorBigIntUse:
case NotDoubleUse:
+ case NeitherDoubleNorHeapBigIntNorStringUse:
return false;
default:
return true;
Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (278567 => 278568)
--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp 2021-06-07 19:55:30 UTC (rev 278568)
@@ -529,6 +529,7 @@
case AnyIntUse:
case DoubleRepAnyIntUse:
case NotDoubleUse:
+ case NeitherDoubleNorHeapBigIntNorStringUse:
// These are OK.
break;
default:
Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (278567 => 278568)
--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-06-07 19:46:05 UTC (rev 278567)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp 2021-06-07 19:55:30 UTC (rev 278568)
@@ -9502,7 +9502,13 @@
}
if (m_node->isBinaryUseKind(MiscUse, UntypedUse)
- || m_node->isBinaryUseKind(UntypedUse, MiscUse)) {
+ || m_node->isBinaryUseKind(UntypedUse, MiscUse)
+#if !USE(BIGINT32)
+ || m_node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse)
+ || m_node->isBinaryUseKind(NeitherDoubleNorHeapBigIntNorStringUse, NotDoubleUse)) {
+#else
+ ) {
+#endif
speculate(m_node->child1());
speculate(m_node->child2());
LValue left = lowJSValue(m_node->child1(), ManualOperandSpeculation);
@@ -18406,6 +18412,9 @@
case NotDoubleUse:
speculateNotDouble(edge);
break;
+ case NeitherDoubleNorHeapBigIntNorStringUse:
+ speculateNeitherDoubleNorHeapBigIntNorString(edge);
+ break;
case OtherUse:
speculateOther(edge);
break;
@@ -18469,6 +18478,31 @@
m_out.appendTo(continuation, lastNext);
}
+
+ void speculateNeitherDoubleNorHeapBigIntNorString(Edge edge)
+ {
+ if (!m_interpreter.needsTypeCheck(edge))
+ return;
+
+ LValue value = lowJSValue(edge, ManualOperandSpeculation);
+
+ LBasicBlock isNotInt32 = m_out.newBlock();
+ LBasicBlock isCellBlock = m_out.newBlock();
+ LBasicBlock continuation = m_out.newBlock();
+
+ m_out.branch(isInt32(value, provenType(edge)), unsure(continuation), unsure(isNotInt32));
+
+ LBasicBlock lastNext = m_out.appendTo(isNotInt32, isCellBlock);
+ FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecFullDouble, isNumber(value));
+ m_out.branch(isCell(value, provenType(edge)), unsure(isCellBlock), unsure(continuation));
+
+ m_out.appendTo(isCellBlock, continuation);
+ FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecString, isString(value));
+ FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecHeapBigInt, isHeapBigInt(value));
+ m_out.jump(continuation);
+
+ m_out.appendTo(continuation, lastNext);
+ }
void speculateCellOrOther(Edge edge)
{