<!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>[201678] trunk/Source/JavaScriptCore</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/201678">201678</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2016-06-03 20:28:57 -0700 (Fri, 03 Jun 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Eager FTL failure for strict comparison of NaN with number check
https://bugs.webkit.org/show_bug.cgi?id=158368

Patch by Benjamin Poulain &lt;bpoulain@apple.com&gt; on 2016-06-03
Reviewed by Darin Adler.

DoupleRep with a RealNumberUse starts by handling double
then falls back to Int32 if the unboxed double is NaN.

Before handling integers, the code is checking if the input
is indeed an int32. The problem was that this check failed
to account for NaN as an original input of the DoubleRep.

The call to isNotInt32() filter the doubles checks because
that was handled by the previous block.
The problem is the previous block handles any double except NaN.
If the original input was NaN, the masking by &quot;~SpecFullDouble&quot;
filter that possibility and isNotInt32() fails to test that case.

This patch fixes the issue by changing the filter to SpecDoubleReal.
The type SpecDoubleReal does not include the NaN types.

* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileDoubleRep):
* tests/stress/double-rep-real-number-use-on-nan.js: Added.
To ensure the isNotInt32() does not test anything, we want
proven numbers as input. The (+value) are there to enforce
a ToNumber() which in turn give us a proven Number type.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressdoublereprealnumberuseonnanjs">trunk/Source/JavaScriptCore/tests/stress/double-rep-real-number-use-on-nan.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (201677 => 201678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-06-04 02:04:58 UTC (rev 201677)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-06-04 03:28:57 UTC (rev 201678)
</span><span class="lines">@@ -1,5 +1,35 @@
</span><span class="cx"> 2016-06-03  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Eager FTL failure for strict comparison of NaN with number check
+        https://bugs.webkit.org/show_bug.cgi?id=158368
+
+        Reviewed by Darin Adler.
+
+        DoupleRep with a RealNumberUse starts by handling double
+        then falls back to Int32 if the unboxed double is NaN.
+
+        Before handling integers, the code is checking if the input
+        is indeed an int32. The problem was that this check failed
+        to account for NaN as an original input of the DoubleRep.
+
+        The call to isNotInt32() filter the doubles checks because
+        that was handled by the previous block.
+        The problem is the previous block handles any double except NaN.
+        If the original input was NaN, the masking by &quot;~SpecFullDouble&quot;
+        filter that possibility and isNotInt32() fails to test that case.
+
+        This patch fixes the issue by changing the filter to SpecDoubleReal.
+        The type SpecDoubleReal does not include the NaN types.
+
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileDoubleRep):
+        * tests/stress/double-rep-real-number-use-on-nan.js: Added.
+        To ensure the isNotInt32() does not test anything, we want
+        proven numbers as input. The (+value) are there to enforce
+        a ToNumber() which in turn give us a proven Number type.
+
+2016-06-03  Benjamin Poulain  &lt;bpoulain@apple.com&gt;
+
</ins><span class="cx">         JSON.stringify replacer function calls with numeric array indices
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=158262
</span><span class="cx">         rdar://problem/26613876
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (201677 => 201678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-06-04 02:04:58 UTC (rev 201677)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-06-04 03:28:57 UTC (rev 201678)
</span><span class="lines">@@ -1138,10 +1138,10 @@
</span><span class="cx">                 usually(continuation), rarely(intCase));
</span><span class="cx">             
</span><span class="cx">             LBasicBlock lastNext = m_out.appendTo(intCase, continuation);
</span><del>-            
</del><ins>+
</ins><span class="cx">             FTL_TYPE_CHECK(
</span><span class="cx">                 jsValueValue(value), m_node-&gt;child1(), SpecBytecodeRealNumber,
</span><del>-                isNotInt32(value, provenType(m_node-&gt;child1()) &amp; ~SpecFullDouble));
</del><ins>+                isNotInt32(value, provenType(m_node-&gt;child1()) &amp; ~SpecDoubleReal));
</ins><span class="cx">             ValueFromBlock slowResult = m_out.anchor(m_out.intToDouble(unboxInt32(value)));
</span><span class="cx">             m_out.jump(continuation);
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressdoublereprealnumberuseonnanjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/double-rep-real-number-use-on-nan.js (0 => 201678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/double-rep-real-number-use-on-nan.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/double-rep-real-number-use-on-nan.js        2016-06-04 03:28:57 UTC (rev 201678)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+// Original test case.
+function isNaNOnDouble(value)
+{
+    return (+value) !== value;
+}
+noInline(isNaNOnDouble);
+
+function testIsNaNOnDoubles()
+{
+    var value = isNaNOnDouble(-0);
+    if (value)
+        throw &quot;isNaNOnDouble(-0) = &quot; + value;
+
+    var value = isNaNOnDouble(NaN);
+    if (!value)
+        throw &quot;isNaNOnDouble(NaN) = &quot; + value;
+
+    var value = isNaNOnDouble(Number.POSITIVE_INFINITY);
+    if (value)
+        throw &quot;isNaNOnDouble(Number.POSITIVE_INFINITY) = &quot; + value;
+}
+noInline(testIsNaNOnDoubles);
+
+for (let i = 0; i &lt; 1e6; ++i) {
+    testIsNaNOnDoubles();
+}
+
+// Simplified test case.
+function isNaNOnDouble2(value)
+{
+    let valueToNumber = (+value);
+    return valueToNumber !== valueToNumber;
+}
+noInline(isNaNOnDouble2);
+
+// Warm up without NaN.
+for (let i = 0; i &lt; 1e6; ++i) {
+    if (isNaNOnDouble2(1.5))
+        throw &quot;Failed isNaNOnDouble(1.5)&quot;;
+}
+
+// Then pass some NaNs.
+for (let i = 0; i &lt; 1e6; ++i) {
+    if (!isNaNOnDouble2(NaN))
+        throw &quot;Failed isNaNOnDouble(NaN)&quot;;
+}
</ins></span></pre>
</div>
</div>

</body>
</html>