<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[282200] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/282200">282200</a></dd>
<dt>Author</dt> <dd>rmorisset@apple.com</dd>
<dt>Date</dt> <dd>2021-09-09 01:10:20 -0700 (Thu, 09 Sep 2021)</dd>
</dl>

<h3>Log Message</h3>
<pre>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/JavaScriptCore:

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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestsstressreflectsetjs">trunk/JSTests/stress/reflect-set.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeSpeculatedTypeh">trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGUseKindcpp">trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGUseKindh">trunk/Source/JavaScriptCore/dfg/DFGUseKind.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog  2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/JSTests/ChangeLog     2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2021-09-09  Robin Morisset  <rmorisset@apple.com>
+
+        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):
+
</ins><span class="cx"> 2021-09-07  Yusuke Suzuki  <ysuzuki@apple.com>
</span><span class="cx"> 
</span><span class="cx">         [JSC] Implement Temporal.PlainTime
</span></span></pre></div>
<a id="trunkJSTestsstressreflectsetjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/reflect-set.js (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> function shouldBe(actual, expected) {
</span><span class="cx">     if (actual !== expected)
</span><del>-        throw new Error('bad value: ' + actual);
</del><ins>+        throw new Error('bad value: ' + describe(actual) + ', expected: ' + describe(expected));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function shouldThrow(func, message) {
</span><span class="lines">@@ -11,9 +11,9 @@
</span><span class="cx">         error = e;
</span><span class="cx">     }
</span><span class="cx">     if (!error)
</span><del>-        throw new Error('not thrown.');
</del><ins>+        throw new Error('not thrown. Expected: ' + message);
</ins><span class="cx">     if (String(error) !== message)
</span><del>-        throw new Error('bad error: ' + String(error));
</del><ins>+        throw new Error('bad error: ' + String(error) + ', expected: ' + message);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> function unreachable()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog    2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/ChangeLog       2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -1,3 +1,74 @@
</span><ins>+2021-09-09  Robin Morisset  <rmorisset@apple.com>
+
+        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):
+
</ins><span class="cx"> 2021-09-07  Yusuke Suzuki  <ysuzuki@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, add files to xcodeproj
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeSpeculatedTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h    2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/bytecode/SpeculatedType.h       2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -449,6 +449,11 @@
</span><span class="cx">     return !(type & (SpecFullDouble | SpecHeapBigInt | SpecString));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool isNeitherDoubleNorHeapBigIntSpeculation(SpeculatedType type)
+{
+    return !(type & (SpecFullDouble | SpecHeapBigInt));
+}
+
</ins><span class="cx"> inline bool isOtherSpeculation(SpeculatedType value)
</span><span class="cx"> {
</span><span class="cx">     return value == SpecOther;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp    2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp       2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -492,7 +492,7 @@
</span><span class="cx">             || node->isBinaryUseKind(ObjectUse)
</span><span class="cx">             || node->isBinaryUseKind(MiscUse, UntypedUse) || node->isBinaryUseKind(UntypedUse, MiscUse)
</span><span class="cx">             || node->isBinaryUseKind(StringIdentUse, NotStringVarUse) || node->isBinaryUseKind(NotStringVarUse, StringIdentUse)
</span><del>-            || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse) || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse))
</del><ins>+            || node->isBinaryUseKind(NotDoubleUse, NeitherDoubleNorHeapBigIntNorStringUse) || node->isBinaryUseKind(NeitherDoubleNorHeapBigIntNorStringUse, NotDoubleUse))
</ins><span class="cx">             return false;
</span><span class="cx">         return true;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp   2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -4477,7 +4477,23 @@
</span><span class="cx">             node->setOpAndDefaultFlags(CompareStrictEq);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-#endif
</del><ins>+#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)
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void fixupChecksInBlock(BasicBlock* block)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h   2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -2887,6 +2887,11 @@
</span><span class="cx">     {
</span><span class="cx">         return isNeitherDoubleNorHeapBigIntNorStringSpeculation(prediction());
</span><span class="cx">     }
</span><ins>+
+    bool shouldSpeculateNeitherDoubleNorHeapBigInt()
+    {
+        return isNeitherDoubleNorHeapBigIntSpeculation(prediction());
+    }
</ins><span class="cx">     
</span><span class="cx">     bool shouldSpeculateUntypedForArithmetic()
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h       2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h  2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -94,6 +94,7 @@
</span><span class="cx">         case DoubleRepAnyIntUse:
</span><span class="cx">         case NotDoubleUse:
</span><span class="cx">         case NeitherDoubleNorHeapBigIntNorStringUse:
</span><ins>+        case NeitherDoubleNorHeapBigIntUse:
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case KnownInt32Use:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp    2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp       2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -7226,7 +7226,21 @@
</span><span class="cx">         compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(node, notDoubleChild, neitherDoubleNorHeapBigIntNorStringChild);
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><del>-#endif
</del><ins>+#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)
</ins><span class="cx"> 
</span><span class="cx">     if (node->isBinaryUseKind(HeapBigIntUse)) {
</span><span class="cx">         compileHeapBigIntEquality(node);
</span><span class="lines">@@ -7457,6 +7471,40 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+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
+}
+
</ins><span class="cx"> void SpeculativeJIT::compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node* node, Edge notDoubleChild, Edge neitherDoubleNorHeapBigIntNorStringChild)
</span><span class="cx"> {
</span><span class="cx">     JSValueOperand left(this, notDoubleChild, ManualOperandSpeculation);
</span><span class="lines">@@ -7476,14 +7524,7 @@
</span><span class="cx">     speculateNotDouble(notDoubleChild, leftRegs, tempGPR);
</span><span class="cx">     speculateNeitherDoubleNorHeapBigIntNorString(neitherDoubleNorHeapBigIntNorStringChild, rightRegs, tempGPR);
</span><span class="cx"> 
</span><del>-#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
</del><ins>+    emitBitwiseJSValueEquality(leftRegs, rightRegs, resultGPR);
</ins><span class="cx">     unblessedBooleanResult(resultGPR, node);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -7503,24 +7544,7 @@
</span><span class="cx">     BasicBlock* taken = branchNode->branchData()->taken.block;
</span><span class="cx">     BasicBlock* notTaken = branchNode->branchData()->notTaken.block;
</span><span class="cx"> 
</span><del>-#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
</del><ins>+    emitBranchOnBitwiseJSValueEquality(leftRegs, rightRegs, taken, notTaken);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void SpeculativeJIT::compileStringEquality(
</span><span class="lines">@@ -11781,6 +11805,42 @@
</span><span class="cx">     speculateNotDouble(edge, regs, tempGPR);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+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);
+}
+
</ins><span class="cx"> void SpeculativeJIT::speculateNeitherDoubleNorHeapBigIntNorString(Edge edge, JSValueRegs regs, GPRReg tempGPR)
</span><span class="cx"> {
</span><span class="cx">     if (!needsTypeCheck(edge, ~(SpecFullDouble | SpecString | SpecHeapBigInt)))
</span><span class="lines">@@ -11794,14 +11854,14 @@
</span><span class="cx"> 
</span><span class="cx">     DFG_TYPE_CHECK(regs, edge, ~SpecFullDouble, m_jit.branchIfNumber(regs, tempGPR));
</span><span class="cx"> 
</span><del>-    bool mayNotBeCell = needsTypeCheck(edge, SpecCell);
-    if (mayNotBeCell)
</del><ins>+    bool mayBeNotCell = needsTypeCheck(edge, SpecCell);
+    if (mayBeNotCell)
</ins><span class="cx">         done.append(m_jit.branchIfNotCell(regs));
</span><span class="cx"> 
</span><span class="cx">     static_assert(StringType + 1 == HeapBigIntType);
</span><span class="cx">     DFG_TYPE_CHECK(regs, edge, ~(SpecString | SpecHeapBigInt), m_jit.branchIfType(regs.payloadGPR(), JSTypeRange { StringType, HeapBigIntType }));
</span><span class="cx"> 
</span><del>-    if (mayBeInt32 || mayNotBeCell)
</del><ins>+    if (mayBeInt32 || mayBeNotCell)
</ins><span class="cx">         done.link(&m_jit);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -12003,6 +12063,9 @@
</span><span class="cx">     case NotDoubleUse:
</span><span class="cx">         speculateNotDouble(edge);
</span><span class="cx">         break;
</span><ins>+    case NeitherDoubleNorHeapBigIntUse:
+        speculateNeitherDoubleNorHeapBigInt(edge);
+        break;
</ins><span class="cx">     case NeitherDoubleNorHeapBigIntNorStringUse:
</span><span class="cx">         speculateNeitherDoubleNorHeapBigIntNorString(edge);
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h      2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h 2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -1248,6 +1248,11 @@
</span><span class="cx">     void compileSymbolEquality(Node*);
</span><span class="cx">     void compileHeapBigIntEquality(Node*);
</span><span class="cx">     void compilePeepHoleSymbolEquality(Node*, Node* branchNode);
</span><ins>+#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);
</ins><span class="cx">     void compileNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node*, Edge notDoubleEdge, Edge neitherDoubleNorHeapBigIntNorStringEdge);
</span><span class="cx">     void compilePeepHoleNotDoubleNeitherDoubleNorHeapBigIntNorStringStrictEquality(Node*, Node* branchNode, Edge notDoubleEdge, Edge neitherDoubleNorHeapBigIntNorStringEdge);
</span><span class="cx">     void compileSymbolUntypedEquality(Node*, Edge symbolEdge, Edge untypedEdge);
</span><span class="lines">@@ -1740,6 +1745,8 @@
</span><span class="cx">     void speculateNotCellNorBigInt(Edge);
</span><span class="cx">     void speculateNotDouble(Edge, JSValueRegs, GPRReg temp);
</span><span class="cx">     void speculateNotDouble(Edge);
</span><ins>+    void speculateNeitherDoubleNorHeapBigInt(Edge, JSValueRegs, GPRReg temp);
+    void speculateNeitherDoubleNorHeapBigInt(Edge);
</ins><span class="cx">     void speculateNeitherDoubleNorHeapBigIntNorString(Edge, JSValueRegs, GPRReg temp);
</span><span class="cx">     void speculateNeitherDoubleNorHeapBigIntNorString(Edge);
</span><span class="cx">     void speculateOther(Edge, JSValueRegs, GPRReg temp);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp  2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp     2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -336,6 +336,95 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+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);
+}
+
</ins><span class="cx"> void SpeculativeJIT::nonSpeculativePeepholeStrictEq(Node* node, Node* branchNode, bool invert)
</span><span class="cx"> {
</span><span class="cx">     BasicBlock* taken = branchNode->branchData()->taken.block;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGUseKindcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp   2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGUseKind.cpp      2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -173,6 +173,9 @@
</span><span class="cx">     case NotDoubleUse:
</span><span class="cx">         out.print("NotDouble");
</span><span class="cx">         return;
</span><ins>+    case NeitherDoubleNorHeapBigIntUse:
+        out.print("NeitherDoubleNorHeapBigInt");
+        return;
</ins><span class="cx">     case NeitherDoubleNorHeapBigIntNorStringUse:
</span><span class="cx">         out.print("NeitherDoubleNorHeapBigIntNorString");
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGUseKindh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGUseKind.h (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGUseKind.h     2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/dfg/DFGUseKind.h        2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -82,6 +82,7 @@
</span><span class="cx">     NotCellUse,
</span><span class="cx">     NotCellNorBigIntUse,
</span><span class="cx">     NotDoubleUse,
</span><ins>+    NeitherDoubleNorHeapBigIntUse,
</ins><span class="cx">     NeitherDoubleNorHeapBigIntNorStringUse,
</span><span class="cx">     KnownOtherUse,
</span><span class="cx">     OtherUse,
</span><span class="lines">@@ -191,6 +192,8 @@
</span><span class="cx">         return ~SpecCellCheck & ~SpecBigInt;
</span><span class="cx">     case NotDoubleUse:
</span><span class="cx">         return ~SpecFullDouble;
</span><ins>+    case NeitherDoubleNorHeapBigIntUse:
+        return ~SpecFullDouble & ~SpecHeapBigInt;
</ins><span class="cx">     case NeitherDoubleNorHeapBigIntNorStringUse:
</span><span class="cx">         return ~(SpecFullDouble | SpecHeapBigInt | SpecString);
</span><span class="cx">     case KnownOtherUse:
</span><span class="lines">@@ -312,6 +315,7 @@
</span><span class="cx">     case NotCellUse:
</span><span class="cx">     case NotCellNorBigIntUse:
</span><span class="cx">     case NotDoubleUse:
</span><ins>+    case NeitherDoubleNorHeapBigIntUse:
</ins><span class="cx">     case NeitherDoubleNorHeapBigIntNorStringUse:
</span><span class="cx">         return false;
</span><span class="cx">     default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp      2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp 2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -527,6 +527,7 @@
</span><span class="cx">                 case AnyIntUse:
</span><span class="cx">                 case DoubleRepAnyIntUse:
</span><span class="cx">                 case NotDoubleUse:
</span><ins>+                case NeitherDoubleNorHeapBigIntUse:
</ins><span class="cx">                 case NeitherDoubleNorHeapBigIntNorStringUse:
</span><span class="cx">                     // These are OK.
</span><span class="cx">                     break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (282199 => 282200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp      2021-09-09 07:37:01 UTC (rev 282199)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp 2021-09-09 08:10:20 UTC (rev 282200)
</span><span class="lines">@@ -9821,6 +9821,15 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        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;
+        }
+
</ins><span class="cx">         // FIXME: we can do something much smarter here, see the DFGSpeculativeJIT approach in e.g. SpeculativeJIT::nonSpeculativePeepholeStrictEq
</span><span class="cx">         DFG_ASSERT(m_graph, m_node, m_node->isBinaryUseKind(UntypedUse), m_node->child1().useKind(), m_node->child2().useKind());
</span><span class="cx">         genericJSValueCompare(
</span><span class="lines">@@ -9869,6 +9878,91 @@
</span><span class="cx">         setBoolean(m_out.phi(Int32, fastTrue, fastFalse, slowResult));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    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));
+    }
+
</ins><span class="cx">     void compileCompareEqPtr()
</span><span class="cx">     {
</span><span class="cx">         setBoolean(
</span><span class="lines">@@ -18047,25 +18141,25 @@
</span><span class="cx">     {
</span><span class="cx">         m_interpreter.filter(highValue, typesPassedThrough);
</span><span class="cx">     }
</span><del>-    
-    void typeCheck(
</del><ins>+
+    void typeCheckWithoutUpdatingInterpreter(
</ins><span class="cx">         FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
</span><span class="cx">         LValue failCondition, ExitKind exitKind = BadType)
</span><span class="cx">     {
</span><del>-        appendTypeCheck(lowValue, highValue, typesPassedThrough, failCondition, exitKind);
-    }
-    
-    void appendTypeCheck(
-        FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
-        LValue failCondition, ExitKind exitKind)
-    {
</del><span class="cx">         if (!m_interpreter.needsTypeCheck(highValue, typesPassedThrough))
</span><span class="cx">             return;
</span><span class="cx">         ASSERT(mayHaveTypeCheck(highValue.useKind()));
</span><span class="cx">         appendOSRExit(exitKind, lowValue, highValue.node(), failCondition, m_origin);
</span><ins>+    }
+
+    void typeCheck(
+        FormattedValue lowValue, Edge highValue, SpeculatedType typesPassedThrough,
+        LValue failCondition, ExitKind exitKind = BadType)
+    {
+        typeCheckWithoutUpdatingInterpreter(lowValue, highValue, typesPassedThrough, failCondition, exitKind);
</ins><span class="cx">         m_interpreter.filter(highValue, typesPassedThrough);
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     LValue lowInt32(Edge edge, OperandSpeculationMode mode = AutomaticOperandSpeculation)
</span><span class="cx">     {
</span><span class="cx">         ASSERT_UNUSED(mode, mode == ManualOperandSpeculation || (edge.useKind() == Int32Use || edge.useKind() == KnownInt32Use));
</span><span class="lines">@@ -18921,6 +19015,9 @@
</span><span class="cx">         case NotDoubleUse:
</span><span class="cx">             speculateNotDouble(edge);
</span><span class="cx">             break;
</span><ins>+        case NeitherDoubleNorHeapBigIntUse:
+            speculateNeitherDoubleNorHeapBigInt(edge);
+            break;
</ins><span class="cx">         case NeitherDoubleNorHeapBigIntNorStringUse:
</span><span class="cx">             speculateNeitherDoubleNorHeapBigIntNorString(edge);
</span><span class="cx">             break;
</span><span class="lines">@@ -18988,6 +19085,30 @@
</span><span class="cx">         m_out.appendTo(continuation, lastNext);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    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);
+    }
+
</ins><span class="cx">     void speculateNeitherDoubleNorHeapBigIntNorString(Edge edge)
</span><span class="cx">     {
</span><span class="cx">         if (!m_interpreter.needsTypeCheck(edge))
</span></span></pre>
</div>
</div>

</body>
</html>