Title: [282200] trunk
Revision
282200
Author
[email protected]
Date
2021-09-09 01:10:20 -0700 (Thu, 09 Sep 2021)

Log Message

Optimize compareStrictEq when neither side is a double and at least one is not a BigInt
https://bugs.webkit.org/show_bug.cgi?id=226755
<rdar://problem/79321542>

Reviewed by Yusuke Suzuki.

JSTests:

Made the error messages in stress/reflect-set a bit more informative in the process of debugging an issue with the patch.

* stress/reflect-set.js:
(shouldBe):
(shouldThrow):

Source/_javascript_Core:

This is a very similar patch to https://bugs.webkit.org/show_bug.cgi?id=226676.
The difference is that here we allow Strings on both side of the comparison, so we must add code to handle equality among strings.

Like for that other patch, the optimization is disabled for BigInt32.
Enabling it in that case would either need modifying the speculation (from banning HeapBigInt to banning all BigInts), or ensuring that we can never have a HeapBigInt so small it compares equal to a BigInt32.

I only implemented this optimization on 64-bits: it is just painful to write code that handles registers at such a low-level without a 32-bit machine to test things locally.
If anyone wants to make this optimization work on 32-bit, I don't foretell any major difficulty.

Finally, like quite a few other useKinds already, this case does not make the CompareStrictEq merge with an adjacent Branch.
The reason is simply that this patch relies on compileStringEquality, which currently does not support that feature.
I intend to fix this (for all useKinds at once) in a separate patch.

Effect on microbenchmarks:
poly-stricteq-not-double                  46.8000+-0.4110     ^     23.5872+-0.3061        ^ definitely 1.9841x faster
poly-stricteq-not-double-nor-string       16.6880+-0.2317           16.3627+-0.3729          might be 1.0199x faster
poly-stricteq                             49.2175+-0.6047           48.9532+-0.6758

I looked at how many cases of Untyped/Untyped compareStrictEq have been fixed by this patch and two other recent patches.
On JetStream2:
- https://bugs.webkit.org/show_bug.cgi?id=226621: 731 instances
- https://bugs.webkit.org/show_bug.cgi?id=226676: 944 instances
- This patch: only 26 instances
This leaves 20 instances of Untyped/Untyped.

On Speedometer2.0:
- https://bugs.webkit.org/show_bug.cgi?id=226621: 1587 instances
- https://bugs.webkit.org/show_bug.cgi?id=226676: 2784 instances
- This patch: 891 instances
This leaves 75 instances of Untyped/Untyped.

* bytecode/SpeculatedType.h:
(JSC::isNeitherDoubleNorHeapBigIntSpeculation):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldSpeculateNeitherDoubleNorHeapBigInt):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::SafeToExecuteEdge::operator()):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileStrictEq):
(JSC::DFG::SpeculativeJIT::emitBitwiseJSValueEquality):
(JSC::DFG::SpeculativeJIT::emitBranchOnBitwiseJSValueEquality):
(JSC::DFG::SpeculativeJIT::compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality):
(JSC::DFG::SpeculativeJIT::compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality):
(JSC::DFG::SpeculativeJIT::speculateNeitherDoubleNorHeapBigInt):
(JSC::DFG::SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString):
(JSC::DFG::SpeculativeJIT::speculate):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality):
* 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):

Modified Paths

Diff

Modified: trunk/JSTests/ChangeLog (282199 => 282200)


--- trunk/JSTests/ChangeLog	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/JSTests/ChangeLog	2021-09-09 08:10:20 UTC (rev 282200)
@@ -1,3 +1,17 @@
+2021-09-09  Robin Morisset  <[email protected]>
+
+        Optimize compareStrictEq when neither side is a double and at least one is not a BigInt
+        https://bugs.webkit.org/show_bug.cgi?id=226755
+        <rdar://problem/79321542>
+
+        Reviewed by Yusuke Suzuki.
+
+        Made the error messages in stress/reflect-set a bit more informative in the process of debugging an issue with the patch.
+
+        * stress/reflect-set.js:
+        (shouldBe):
+        (shouldThrow):
+
 2021-09-07  Yusuke Suzuki  <[email protected]>
 
         [JSC] Implement Temporal.PlainTime

Modified: trunk/JSTests/stress/reflect-set.js (282199 => 282200)


--- trunk/JSTests/stress/reflect-set.js	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/JSTests/stress/reflect-set.js	2021-09-09 08:10:20 UTC (rev 282200)
@@ -1,6 +1,6 @@
 function shouldBe(actual, expected) {
     if (actual !== expected)
-        throw new Error('bad value: ' + actual);
+        throw new Error('bad value: ' + describe(actual) + ', expected: ' + describe(expected));
 }
 
 function shouldThrow(func, message) {
@@ -11,9 +11,9 @@
         error = e;
     }
     if (!error)
-        throw new Error('not thrown.');
+        throw new Error('not thrown. Expected: ' + message);
     if (String(error) !== message)
-        throw new Error('bad error: ' + String(error));
+        throw new Error('bad error: ' + String(error) + ', expected: ' + message);
 }
 
 function unreachable()

Modified: trunk/Source/_javascript_Core/ChangeLog (282199 => 282200)


--- trunk/Source/_javascript_Core/ChangeLog	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-09-09 08:10:20 UTC (rev 282200)
@@ -1,3 +1,74 @@
+2021-09-09  Robin Morisset  <[email protected]>
+
+        Optimize compareStrictEq when neither side is a double and at least one is not a BigInt
+        https://bugs.webkit.org/show_bug.cgi?id=226755
+        <rdar://problem/79321542>
+
+        Reviewed by Yusuke Suzuki.
+
+        This is a very similar patch to https://bugs.webkit.org/show_bug.cgi?id=226676.
+        The difference is that here we allow Strings on both side of the comparison, so we must add code to handle equality among strings.
+
+        Like for that other patch, the optimization is disabled for BigInt32.
+        Enabling it in that case would either need modifying the speculation (from banning HeapBigInt to banning all BigInts), or ensuring that we can never have a HeapBigInt so small it compares equal to a BigInt32.
+
+        I only implemented this optimization on 64-bits: it is just painful to write code that handles registers at such a low-level without a 32-bit machine to test things locally.
+        If anyone wants to make this optimization work on 32-bit, I don't foretell any major difficulty.
+
+        Finally, like quite a few other useKinds already, this case does not make the CompareStrictEq merge with an adjacent Branch.
+        The reason is simply that this patch relies on compileStringEquality, which currently does not support that feature.
+        I intend to fix this (for all useKinds at once) in a separate patch.
+
+        Effect on microbenchmarks:
+        poly-stricteq-not-double                  46.8000+-0.4110     ^     23.5872+-0.3061        ^ definitely 1.9841x faster
+        poly-stricteq-not-double-nor-string       16.6880+-0.2317           16.3627+-0.3729          might be 1.0199x faster
+        poly-stricteq                             49.2175+-0.6047           48.9532+-0.6758
+
+        I looked at how many cases of Untyped/Untyped compareStrictEq have been fixed by this patch and two other recent patches.
+        On JetStream2:
+        - https://bugs.webkit.org/show_bug.cgi?id=226621: 731 instances
+        - https://bugs.webkit.org/show_bug.cgi?id=226676: 944 instances
+        - This patch: only 26 instances
+        This leaves 20 instances of Untyped/Untyped.
+
+        On Speedometer2.0:
+        - https://bugs.webkit.org/show_bug.cgi?id=226621: 1587 instances
+        - https://bugs.webkit.org/show_bug.cgi?id=226676: 2784 instances
+        - This patch: 891 instances
+        This leaves 75 instances of Untyped/Untyped.
+
+        * bytecode/SpeculatedType.h:
+        (JSC::isNeitherDoubleNorHeapBigIntSpeculation):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupCompareStrictEqAndSameValue):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::shouldSpeculateNeitherDoubleNorHeapBigInt):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::SafeToExecuteEdge::operator()):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileStrictEq):
+        (JSC::DFG::SpeculativeJIT::emitBitwiseJSValueEquality):
+        (JSC::DFG::SpeculativeJIT::emitBranchOnBitwiseJSValueEquality):
+        (JSC::DFG::SpeculativeJIT::compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality):
+        (JSC::DFG::SpeculativeJIT::compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality):
+        (JSC::DFG::SpeculativeJIT::speculateNeitherDoubleNorHeapBigInt):
+        (JSC::DFG::SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString):
+        (JSC::DFG::SpeculativeJIT::speculate):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality):
+        * 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):
+
 2021-09-07  Yusuke Suzuki  <[email protected]>
 
         Unreviewed, add files to xcodeproj

Modified: trunk/Source/_javascript_Core/bytecode/SpeculatedType.h (282199 => 282200)


--- trunk/Source/_javascript_Core/bytecode/SpeculatedType.h	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/bytecode/SpeculatedType.h	2021-09-09 08:10:20 UTC (rev 282200)
@@ -449,6 +449,11 @@
     return !(type & (SpecFullDouble | SpecHeapBigInt | SpecString));
 }
 
+inline bool isNeitherDoubleNorHeapBigIntSpeculation(SpeculatedType type)
+{
+    return !(type & (SpecFullDouble | SpecHeapBigInt));
+}
+
 inline bool isOtherSpeculation(SpeculatedType value)
 {
     return value == SpecOther;

Modified: trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGDoesGC.cpp	2021-09-09 08:10:20 UTC (rev 282200)
@@ -492,7 +492,7 @@
             || node->isBinaryUseKind(ObjectUse)
             || node->isBinaryUseKind(MiscUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, MiscUse)
             || node->isBinaryUseKind(StringIdentUse, NotStringVarUse) || node->isBinaryUseKind(NotStringVarUse, StringIdentUse)
-            || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse) || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse))
+            || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse) || node->isBinaryUseKind(NeitherDoubleNorHeapBigIntNorStringUse, NotDoubleUse))
             return false;
         return true;
 

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2021-09-09 08:10:20 UTC (rev 282200)
@@ -4477,7 +4477,23 @@
             node->setOpAndDefaultFlags(CompareStrictEq);
             return;
         }
-#endif
+#if USE(JSVALUE64)
+        if (node->child1()->shouldSpeculateNeitherDoubleNorHeapBigInt()
+            && node->child2()->shouldSpeculateNotDouble()) {
+            fixEdge<NeitherDoubleNorHeapBigIntUse>(node->child1());
+            fixEdge<NotDoubleUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+        if (node->child1()->shouldSpeculateNotDouble()
+            && node->child2()->shouldSpeculateNeitherDoubleNorHeapBigInt()) {
+            fixEdge<NotDoubleUse>(node->child1());
+            fixEdge<NeitherDoubleNorHeapBigIntUse>(node->child2());
+            node->setOpAndDefaultFlags(CompareStrictEq);
+            return;
+        }
+#endif // USE(JSVALUE64)
+#endif // !USE(BIGINT32)
     }
 
     void fixupChecksInBlock(BasicBlock* block)

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2021-09-09 08:10:20 UTC (rev 282200)
@@ -2887,6 +2887,11 @@
     {
         return isNeitherDoubleNorHeapBigIntNorStringSpeculation(prediction());
     }
+
+    bool shouldSpeculateNeitherDoubleNorHeapBigInt()
+    {
+        return isNeitherDoubleNorHeapBigIntSpeculation(prediction());
+    }
     
     bool shouldSpeculateUntypedForArithmetic()
     {

Modified: trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGSafeToExecute.h	2021-09-09 08:10:20 UTC (rev 282200)
@@ -94,6 +94,7 @@
         case DoubleRepAnyIntUse:
         case NotDoubleUse:
         case NeitherDoubleNorHeapBigIntNorStringUse:
+        case NeitherDoubleNorHeapBigIntUse:
             return;
             
         case KnownInt32Use:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2021-09-09 08:10:20 UTC (rev 282200)
@@ -7226,7 +7226,21 @@
         compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(node, notDoubleChild, neitherDoubleNorHeapBigIntNorStringChild);
         return false;
     }
-#endif
+#if USE(JSVALUE64)
+    if (node->isBinaryUseKind(NeitherDoubleNorHeapBigIntUse, NotDoubleUse)) {
+        Edge neitherDoubleNorHeapBigIntChild = node->child1();
+        Edge notDoubleChild = node->child2();
+        compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality(node, neitherDoubleNorHeapBigIntChild, notDoubleChild);
+        return false;
+    }
+    if (node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntUse)) {
+        Edge notDoubleChild = node->child1();
+        Edge neitherDoubleNorHeapBigIntChild = node->child2();
+        compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality(node, neitherDoubleNorHeapBigIntChild, notDoubleChild);
+        return false;
+    }
+#endif // USE(JSVALUE64)
+#endif // !USE(BIGINT32)
 
     if (node->isBinaryUseKind(HeapBigIntUse)) {
         compileHeapBigIntEquality(node);
@@ -7457,6 +7471,40 @@
     }
 }
 
+void SpeculativeJIT::emitBitwiseJSValueEquality(JSValueRegs& left, JSValueRegs& right, GPRReg& result)
+{
+#if USE(JSVALUE64)
+    m_jit.compare64(JITCompiler::Equal, left.gpr(), right.gpr(), result);
+#else
+    m_jit.move(TrustedImm32(0), result);
+    JITCompiler::Jump notEqual = m_jit.branch32(JITCompiler::NotEqual, left.tagGPR(), right.tagGPR());
+    m_jit.compare32(JITCompiler::Equal, left.payloadGPR(), right.payloadGPR(), result);
+    notEqual.link(&m_jit);
+#endif
+}
+
+void SpeculativeJIT::emitBranchOnBitwiseJSValueEquality(JSValueRegs& left, JSValueRegs& right, BasicBlock* taken, BasicBlock* notTaken)
+{
+#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::compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node* node, Edge notDoubleChild, Edge neitherDoubleNorHeapBigIntNorStringChild)
 {
     JSValueOperand left(this, notDoubleChild, ManualOperandSpeculation);
@@ -7476,14 +7524,7 @@
     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
+    emitBitwiseJSValueEquality(leftRegs, rightRegs, resultGPR);
     unblessedBooleanResult(resultGPR, node);
 }
 
@@ -7503,24 +7544,7 @@
     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
+    emitBranchOnBitwiseJSValueEquality(leftRegs, rightRegs, taken, notTaken);
 }
 
 void SpeculativeJIT::compileStringEquality(
@@ -11781,6 +11805,42 @@
     speculateNotDouble(edge, regs, tempGPR);
 }
 
+void SpeculativeJIT::speculateNeitherDoubleNorHeapBigInt(Edge edge, JSValueRegs regs, GPRReg tempGPR)
+{
+    if (!needsTypeCheck(edge, ~(SpecFullDouble | SpecHeapBigInt)))
+        return;
+
+    JITCompiler::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));
+
+    bool mayBeNotCell = needsTypeCheck(edge, SpecCell);
+    if (mayBeNotCell)
+        done.append(m_jit.branchIfNotCell(regs));
+
+    DFG_TYPE_CHECK(regs, edge, ~SpecHeapBigInt, m_jit.branchIfHeapBigInt(regs.payloadGPR()));
+
+    if (mayBeInt32 || mayBeNotCell)
+        done.link(&m_jit);
+}
+
+void SpeculativeJIT::speculateNeitherDoubleNorHeapBigInt(Edge edge)
+{
+    if (!needsTypeCheck(edge, ~(SpecFullDouble | SpecHeapBigInt)))
+        return;
+
+    JSValueOperand operand(this, edge, ManualOperandSpeculation);
+    GPRTemporary temp(this);
+    JSValueRegs regs = operand.jsValueRegs();
+    GPRReg tempGPR = temp.gpr();
+
+    speculateNeitherDoubleNorHeapBigInt(edge, regs, tempGPR);
+}
+
 void SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString(Edge edge, JSValueRegs regs, GPRReg tempGPR)
 {
     if (!needsTypeCheck(edge, ~(SpecFullDouble | SpecString | SpecHeapBigInt)))
@@ -11794,14 +11854,14 @@
 
     DFG_TYPE_CHECK(regs, edge, ~SpecFullDouble, m_jit.branchIfNumber(regs, tempGPR));
 
-    bool mayNotBeCell = needsTypeCheck(edge, SpecCell);
-    if (mayNotBeCell)
+    bool mayBeNotCell = needsTypeCheck(edge, SpecCell);
+    if (mayBeNotCell)
         done.append(m_jit.branchIfNotCell(regs));
 
     static_assert(StringType + 1 == HeapBigIntType);
     DFG_TYPE_CHECK(regs, edge, ~(SpecString | SpecHeapBigInt), m_jit.branchIfType(regs.payloadGPR(), JSTypeRange { StringType, HeapBigIntType }));
 
-    if (mayBeInt32 || mayNotBeCell)
+    if (mayBeInt32 || mayBeNotCell)
         done.link(&m_jit);
 }
 
@@ -12003,6 +12063,9 @@
     case NotDoubleUse:
         speculateNotDouble(edge);
         break;
+    case NeitherDoubleNorHeapBigIntUse:
+        speculateNeitherDoubleNorHeapBigInt(edge);
+        break;
     case NeitherDoubleNorHeapBigIntNorStringUse:
         speculateNeitherDoubleNorHeapBigIntNorString(edge);
         break;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2021-09-09 08:10:20 UTC (rev 282200)
@@ -1248,6 +1248,11 @@
     void compileSymbolEquality(Node*);
     void compileHeapBigIntEquality(Node*);
     void compilePeepHoleSymbolEquality(Node*, Node* branchNode);
+#if USE(JSVALUE64)
+    void compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality(Node*, Edge neitherDoubleNorHeapBigInt, Edge notDouble);
+#endif
+    void emitBitwiseJSValueEquality(JSValueRegs&, JSValueRegs&, GPRReg& result);
+    void emitBranchOnBitwiseJSValueEquality(JSValueRegs&, JSValueRegs&, BasicBlock* taken, BasicBlock* notTaken);
     void compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node*, Edge notDoubleEdge, Edge neitherDoubleNorHeapBigIntNorStringEdge);
     void compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node*, Node* branchNode, Edge notDoubleEdge, Edge neitherDoubleNorHeapBigIntNorStringEdge);
     void compileSymbolUntypedEquality(Node*, Edge symbolEdge, Edge untypedEdge);
@@ -1740,6 +1745,8 @@
     void speculateNotCellNorBigInt(Edge);
     void speculateNotDouble(Edge, JSValueRegs, GPRReg temp);
     void speculateNotDouble(Edge);
+    void speculateNeitherDoubleNorHeapBigInt(Edge, JSValueRegs, GPRReg temp);
+    void speculateNeitherDoubleNorHeapBigInt(Edge);
     void speculateNeitherDoubleNorHeapBigIntNorString(Edge, JSValueRegs, GPRReg temp);
     void speculateNeitherDoubleNorHeapBigIntNorString(Edge);
     void speculateOther(Edge, JSValueRegs, GPRReg temp);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2021-09-09 08:10:20 UTC (rev 282200)
@@ -336,6 +336,95 @@
     }
 }
 
+void SpeculativeJIT::compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality(Node* node, Edge neitherDoubleNorHeapBigIntChild, Edge notDoubleChild)
+{
+    ASSERT(neitherDoubleNorHeapBigIntChild.useKind() == NeitherDoubleNorHeapBigIntUse);
+    ASSERT(notDoubleChild.useKind() == NotDoubleUse);
+
+    JSValueOperand left(this, neitherDoubleNorHeapBigIntChild, ManualOperandSpeculation);
+    JSValueOperand right(this, notDoubleChild, ManualOperandSpeculation);
+
+    GPRTemporary temp(this);
+    GPRTemporary leftTemp(this);
+    GPRTemporary rightTemp(this);
+    GPRTemporary leftTemp2(this, Reuse, left);
+    GPRTemporary rightTemp2(this, Reuse, right);
+    JSValueRegs leftRegs = left.jsValueRegs();
+    JSValueRegs rightRegs = right.jsValueRegs();
+
+    GPRReg leftGPR = leftRegs.payloadGPR();
+    GPRReg rightGPR = rightRegs.payloadGPR();
+    GPRReg tempGPR = temp.gpr();
+    GPRReg leftTempGPR = leftTemp.gpr();
+    GPRReg rightTempGPR = rightTemp.gpr();
+    GPRReg leftTemp2GPR = leftTemp2.gpr();
+    GPRReg rightTemp2GPR = rightTemp2.gpr();
+
+    // We try to avoid repeated and redundant checks here, which leads to the following pseudo-code:
+    /*
+     if (left == true) {
+       speculateNeitherDoubleNorHeapBigInt(left);
+       return true;
+     }
+     speculateNotDouble(right);
+     speculateNotDouble(left);
+     if (left is not Cell)
+       return false;
+     Check that left is not HeapBigInt;
+     if (left is not String)
+       return false;
+     if (right is not Cell)
+       return false;
+     if (right is not String)
+       return false;
+     return stringEquality(left, right)
+     }
+     */
+    // Mercifully we can often eliminate much of this soup of conditionals with the help of the abstract interpreter.
+
+    JITCompiler::JumpList trueCase;
+    JITCompiler::JumpList falseCase;
+
+    JITCompiler::Jump notEqual = m_jit.branch64(JITCompiler::NotEqual, leftGPR, rightGPR);
+    // We cannot use speculateNeitherDoubleNorHeapBigInt here, because it updates the interpreter state, and we can skip over it.
+    // So we would always skip the speculateNotDouble that follows.
+    if (needsTypeCheck(neitherDoubleNorHeapBigIntChild, ~SpecFullDouble)) {
+        if (needsTypeCheck(neitherDoubleNorHeapBigIntChild, ~SpecInt32Only))
+            trueCase.append(m_jit.branchIfInt32(leftRegs));
+        speculationCheck(BadType, leftRegs, neitherDoubleNorHeapBigIntChild.node(), m_jit.branchIfNumber(leftRegs, tempGPR));
+    }
+    if (needsTypeCheck(neitherDoubleNorHeapBigIntChild, ~SpecHeapBigInt)) {
+        if (needsTypeCheck(neitherDoubleNorHeapBigIntChild, SpecCell))
+            trueCase.append(m_jit.branchIfNotCell(leftRegs));
+        speculationCheck(BadType, leftRegs, neitherDoubleNorHeapBigIntChild.node(), m_jit.branchIfHeapBigInt(leftGPR));
+    }
+    trueCase.append(m_jit.jump());
+    notEqual.link(&m_jit);
+
+    speculateNotDouble(notDoubleChild, rightRegs, tempGPR);
+    speculateNotDouble(neitherDoubleNorHeapBigIntChild, leftRegs, tempGPR);
+
+    bool leftMayBeNotCell = needsTypeCheck(neitherDoubleNorHeapBigIntChild, SpecCellCheck);
+    if (leftMayBeNotCell)
+        falseCase.append(m_jit.branchIfNotCell(leftRegs));
+
+    DFG_TYPE_CHECK(leftRegs, neitherDoubleNorHeapBigIntChild, ~SpecHeapBigInt, m_jit.branchIfHeapBigInt(leftGPR));
+
+    bool leftMayBeNotStringKnowingCell = needsTypeCheck(neitherDoubleNorHeapBigIntChild, (~SpecString) & SpecCellCheck);
+    if (leftMayBeNotStringKnowingCell)
+        falseCase.append(m_jit.branchIfNotString(leftGPR));
+
+    bool rightMayBeNotCell = needsTypeCheck(notDoubleChild, SpecCellCheck);
+    if (rightMayBeNotCell)
+        falseCase.append(m_jit.branchIfNotCell(rightRegs));
+
+    bool rightMayBeNotStringKnowingCell = needsTypeCheck(notDoubleChild, (~SpecString) & SpecCellCheck);
+    if (rightMayBeNotStringKnowingCell)
+        falseCase.append(m_jit.branchIfNotString(rightGPR));
+
+    compileStringEquality(node, leftGPR, rightGPR, tempGPR, leftTempGPR, rightTempGPR, leftTemp2GPR, rightTemp2GPR, trueCase, falseCase);
+}
+
 void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node* node, Node* branchNode, bool invert)
 {
     BasicBlock* taken = branchNode->branchData()->taken.block;

Modified: trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGUseKind.cpp	2021-09-09 08:10:20 UTC (rev 282200)
@@ -173,6 +173,9 @@
     case NotDoubleUse:
         out.print("NotDouble");
         return;
+    case NeitherDoubleNorHeapBigIntUse:
+        out.print("NeitherDoubleNorHeapBigInt");
+        return;
     case NeitherDoubleNorHeapBigIntNorStringUse:
         out.print("NeitherDoubleNorHeapBigIntNorString");
         return;

Modified: trunk/Source/_javascript_Core/dfg/DFGUseKind.h (282199 => 282200)


--- trunk/Source/_javascript_Core/dfg/DFGUseKind.h	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/dfg/DFGUseKind.h	2021-09-09 08:10:20 UTC (rev 282200)
@@ -82,6 +82,7 @@
     NotCellUse,
     NotCellNorBigIntUse,
     NotDoubleUse,
+    NeitherDoubleNorHeapBigIntUse,
     NeitherDoubleNorHeapBigIntNorStringUse,
     KnownOtherUse,
     OtherUse,
@@ -191,6 +192,8 @@
         return ~SpecCellCheck & ~SpecBigInt;
     case NotDoubleUse:
         return ~SpecFullDouble;
+    case NeitherDoubleNorHeapBigIntUse:
+        return ~SpecFullDouble & ~SpecHeapBigInt;
     case NeitherDoubleNorHeapBigIntNorStringUse:
         return ~(SpecFullDouble | SpecHeapBigInt | SpecString);
     case KnownOtherUse:
@@ -312,6 +315,7 @@
     case NotCellUse:
     case NotCellNorBigIntUse:
     case NotDoubleUse:
+    case NeitherDoubleNorHeapBigIntUse:
     case NeitherDoubleNorHeapBigIntNorStringUse:
         return false;
     default:

Modified: trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp (282199 => 282200)


--- trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/ftl/FTLCapabilities.cpp	2021-09-09 08:10:20 UTC (rev 282200)
@@ -527,6 +527,7 @@
                 case AnyIntUse:
                 case DoubleRepAnyIntUse:
                 case NotDoubleUse:
+                case NeitherDoubleNorHeapBigIntUse:
                 case NeitherDoubleNorHeapBigIntNorStringUse:
                     // These are OK.
                     break;

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp (282199 => 282200)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToB3.cpp	2021-09-09 08:10:20 UTC (rev 282200)
@@ -9821,6 +9821,15 @@
             return;
         }
 
+        if (m_node->isBinaryUseKind(NeitherDoubleNorHeapBigIntUse, NotDoubleUse)) {
+            compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality(m_node->child1(), m_node->child2());
+            return;
+        }
+        if (m_node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntUse)) {
+            compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality(m_node->child2(), m_node->child1());
+            return;
+        }
+
         // FIXME: we can do something much smarter here, see the DFGSpeculativeJIT approach in e.g. SpeculativeJIT::nonSpeculativePeepholeStrictEq
         DFG_ASSERT(m_graph, m_node, m_node->isBinaryUseKind(UntypedUse), m_node->child1().useKind(), m_node->child2().useKind());
         genericJSValueCompare(
@@ -9869,6 +9878,91 @@
         setBoolean(m_out.phi(Int32, fastTrue, fastFalse, slowResult));
     }
 
+    void compileNeitherDoubleNorHeapBigIntToNotDoubleStrictEquality(Edge neitherDoubleNorHeapBigIntEdge, Edge notDoubleEdge)
+    {
+        ASSERT(neitherDoubleNorHeapBigIntEdge.useKind() == NeitherDoubleNorHeapBigIntUse);
+        ASSERT(notDoubleEdge.useKind() == NotDoubleUse);
+
+        LValue leftValue = lowJSValue(neitherDoubleNorHeapBigIntEdge, ManualOperandSpeculation);
+        LValue rightValue = lowJSValue(notDoubleEdge, ManualOperandSpeculation);
+        SpeculatedType leftValueType = provenType(neitherDoubleNorHeapBigIntEdge);
+        SpeculatedType rightValueType = provenType(notDoubleEdge);
+
+        LBasicBlock triviallyEqualCase = m_out.newBlock();
+        LBasicBlock leftIsNotInt32EqualCase = m_out.newBlock();
+        LBasicBlock leftIsCellEqualCase = m_out.newBlock();
+        LBasicBlock returnTrueBlock = m_out.newBlock();
+        LBasicBlock notTriviallyEqualCase = m_out.newBlock();
+        LBasicBlock leftIsCell = m_out.newBlock();
+        LBasicBlock leftIsString = m_out.newBlock();
+        LBasicBlock rightIsCell = m_out.newBlock();
+        LBasicBlock rightIsString = m_out.newBlock();
+        LBasicBlock continuation = m_out.newBlock();
+
+        // We try to avoid repeated and redundant checks here, which leads to the following pseudo-code:
+        /*
+         if (left == right) {
+           speculateNeitherDoubleNorHeapBigInt(left);
+           return true;
+         }
+         speculateNotDouble(right);
+         speculateNotDouble(left);
+         if (left is not Cell)
+           return false;
+         Check that left is not HeapBigInt;
+         if (left is not String)
+           return false;
+         if (right is not Cell)
+           return false;
+         if (right is not String)
+           return false;
+         return stringEquality(left, right)
+         }
+         */
+        m_out.branch(m_out.equal(leftValue, rightValue), unsure(triviallyEqualCase), unsure(notTriviallyEqualCase));
+
+        LBasicBlock lastNext = m_out.appendTo(triviallyEqualCase, leftIsNotInt32EqualCase);
+        // Logically we want speculateNeitherDoubleNorHeapBigInt, but we cannot use it here as it changes the state of the abstract interpreter.
+        // So if we used it here, we would skip the later checks.
+        // Instead we reimplement it in this and the next few blocks, using typeCheckWithoutUpdatingInterpreter.
+        m_out.branch(isInt32(leftValue, leftValueType), unsure(returnTrueBlock), unsure(leftIsNotInt32EqualCase));
+
+        m_out.appendTo(leftIsNotInt32EqualCase, leftIsCellEqualCase);
+        typeCheckWithoutUpdatingInterpreter(jsValueValue(leftValue), neitherDoubleNorHeapBigIntEdge, ~SpecFullDouble, isNumber(leftValue));
+        m_out.branch(isCell(leftValue, leftValueType & ~SpecFullNumber), unsure(leftIsCellEqualCase), unsure(returnTrueBlock));
+
+        m_out.appendTo(leftIsCellEqualCase, returnTrueBlock);
+        typeCheckWithoutUpdatingInterpreter(jsValueValue(leftValue), neitherDoubleNorHeapBigIntEdge, ~SpecHeapBigInt, isHeapBigInt(leftValue));
+        m_out.jump(returnTrueBlock);
+
+        m_out.appendTo(returnTrueBlock, notTriviallyEqualCase);
+        ValueFromBlock fastTrue = m_out.anchor(m_out.booleanTrue);
+        m_out.jump(continuation);
+
+        m_out.appendTo(notTriviallyEqualCase, leftIsCell);
+        speculateNotDouble(neitherDoubleNorHeapBigIntEdge);
+        speculateNotDouble(notDoubleEdge);
+        ValueFromBlock fastFalse = m_out.anchor(m_out.booleanFalse);
+        m_out.branch(isNotCell(leftValue, leftValueType & ~SpecFullDouble), unsure(continuation), unsure(leftIsCell));
+
+        m_out.appendTo(leftIsCell, leftIsString);
+        FTL_TYPE_CHECK(jsValueValue(leftValue), neitherDoubleNorHeapBigIntEdge, ~SpecHeapBigInt, isHeapBigInt(leftValue));
+        m_out.branch(isNotString(leftValue, leftValueType & SpecCell & ~SpecHeapBigInt), unsure(continuation), unsure(leftIsString));
+
+        m_out.appendTo(leftIsString, rightIsCell);
+        m_out.branch(isNotCell(rightValue, rightValueType & ~SpecFullDouble), unsure(continuation), unsure(rightIsCell));
+
+        m_out.appendTo(rightIsCell, rightIsString);
+        m_out.branch(isNotString(rightValue, rightValueType & SpecCell & ~SpecFullDouble), unsure(continuation), unsure(rightIsString));
+
+        m_out.appendTo(rightIsString, continuation);
+        ValueFromBlock slowResult = m_out.anchor(stringsEqual(leftValue, rightValue, neitherDoubleNorHeapBigIntEdge, notDoubleEdge));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+        setBoolean(m_out.phi(Int32, fastTrue, fastFalse, slowResult));
+    }
+
     void compileCompareEqPtr()
     {
         setBoolean(
@@ -18047,25 +18141,25 @@
     {
         m_interpreter.filter(highValue, typesPassedThrough);
     }
-    
-    void typeCheck(
+
+    void typeCheckWithoutUpdatingInterpreter(
         FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
         LValue failCondition, ExitKind exitKind = BadType)
     {
-        appendTypeCheck(lowValue, highValue, typesPassedThrough, failCondition, exitKind);
-    }
-    
-    void appendTypeCheck(
-        FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
-        LValue failCondition, ExitKind exitKind)
-    {
         if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough))
             return;
         ASSERT(mayHaveTypeCheck(highValue.useKind()));
         appendOSRExit(exitKind, lowValue, highValue.node(), failCondition, m_origin);
+    }
+
+    void typeCheck(
+        FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
+        LValue failCondition, ExitKind exitKind = BadType)
+    {
+        typeCheckWithoutUpdatingInterpreter(lowValue, highValue, typesPassedThrough, failCondition, exitKind);
         m_interpreter.filter(highValue, typesPassedThrough);
     }
-    
+
     LValue lowInt32(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
     {
         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
@@ -18921,6 +19015,9 @@
         case NotDoubleUse:
             speculateNotDouble(edge);
             break;
+        case NeitherDoubleNorHeapBigIntUse:
+            speculateNeitherDoubleNorHeapBigInt(edge);
+            break;
         case NeitherDoubleNorHeapBigIntNorStringUse:
             speculateNeitherDoubleNorHeapBigIntNorString(edge);
             break;
@@ -18988,6 +19085,30 @@
         m_out.appendTo(continuation, lastNext);
     }
 
+    void speculateNeitherDoubleNorHeapBigInt(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) & ~SpecFullNumber), unsure(isCellBlock), unsure(continuation));
+
+        m_out.appendTo(isCellBlock, continuation);
+        FTL_TYPE_CHECK(jsValueValue(value), edge, ~SpecHeapBigInt, isHeapBigInt(value));
+        m_out.jump(continuation);
+
+        m_out.appendTo(continuation, lastNext);
+    }
+
     void speculateNeitherDoubleNorHeapBigIntNorString(Edge edge)
     {
         if (!m_interpreter.needsTypeCheck(edge))
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to