<!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>[202955] 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/202955">202955</a></dd>
<dt>Author</dt> <dd>msaboff@apple.com</dd>
<dt>Date</dt> <dd>2016-07-07 20:47:59 -0700 (Thu, 07 Jul 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION(184445): Need to insert a StoreBarrier when we don't know child's epoch
https://bugs.webkit.org/show_bug.cgi?id=159537

Reviewed by Benjamin Poulain.

We weren't checking the case of a child node with a null epoch.  The problem surfaces
when the base node of a PutByVal variant has a non-null epoch, because it represents an
allocation in the current function, while the child of the same node has an unknown epoch.
Added a check that the child node is not null before comparing the epochs of the base and
child nodes.

The added test creates the problem circumstance by doing a full GC to place an array in
remembered space, allocating a new object followed by an eden GC.  The new object is
only referenced by the array and therefore won't be visited Without the store barrier.
The test may crash or more likely get the wrong answer with the bug.

* dfg/DFGStoreBarrierInsertionPhase.cpp:
* tests/stress/regress-159537.js: Added test.
(MyNumber):
(MyNumber.prototype.plusOne):
(bar):
(foo):
(test):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGStoreBarrierInsertionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressregress159537js">trunk/Source/JavaScriptCore/tests/stress/regress-159537.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (202954 => 202955)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-07-08 03:13:11 UTC (rev 202954)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-07-08 03:47:59 UTC (rev 202955)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2016-07-07  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        REGRESSION(184445): Need to insert a StoreBarrier when we don't know child's epoch
+        https://bugs.webkit.org/show_bug.cgi?id=159537
+
+        Reviewed by Benjamin Poulain.
+
+        We weren't checking the case of a child node with a null epoch.  The problem surfaces
+        when the base node of a PutByVal variant has a non-null epoch, because it represents an
+        allocation in the current function, while the child of the same node has an unknown epoch.
+        Added a check that the child node is not null before comparing the epochs of the base and
+        child nodes.
+
+        The added test creates the problem circumstance by doing a full GC to place an array in
+        remembered space, allocating a new object followed by an eden GC.  The new object is
+        only referenced by the array and therefore won't be visited Without the store barrier.
+        The test may crash or more likely get the wrong answer with the bug.
+
+        * dfg/DFGStoreBarrierInsertionPhase.cpp:
+        * tests/stress/regress-159537.js: Added test.
+        (MyNumber):
+        (MyNumber.prototype.plusOne):
+        (bar):
+        (foo):
+        (test):
+
</ins><span class="cx"> 2016-07-07  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unexpected &quot;Out of memory&quot; error for &quot;x&quot;.repeat(-1)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGStoreBarrierInsertionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp (202954 => 202955)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp        2016-07-08 03:13:11 UTC (rev 202954)
+++ trunk/Source/JavaScriptCore/dfg/DFGStoreBarrierInsertionPhase.cpp        2016-07-08 03:47:59 UTC (rev 202955)
</span><span class="lines">@@ -459,12 +459,12 @@
</span><span class="cx">         // Something we watch out for here is that the null epoch is a catch-all for objects
</span><span class="cx">         // allocated before we did any epoch tracking. Two objects being in the null epoch
</span><span class="cx">         // means that we don't know their epoch relationship.
</span><del>-        if (!!base-&gt;epoch() &amp;&amp; base-&gt;epoch() &gt;= child-&gt;epoch()) {
</del><ins>+        if (!!base-&gt;epoch() &amp;&amp; !!child-&gt;epoch() &amp;&amp; base-&gt;epoch() &gt;= child-&gt;epoch()) {
</ins><span class="cx">             if (verbose)
</span><span class="cx">                 dataLog(&quot;            Rejecting because of epoch ordering.\n&quot;);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         considerBarrier(base);
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressregress159537js"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/regress-159537.js (0 => 202955)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/regress-159537.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/regress-159537.js        2016-07-08 03:47:59 UTC (rev 202955)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+// This test verifies that we don't crash in FTL generated code due to lack of a store barrier
+// for a put-by-val when we don't know when the value was allocated.
+
+class MyNumber
+{
+    constructor(v)
+    {
+        this._v = v;
+    }
+
+    plusOne()
+    {
+        return this._v + 1;
+    }
+}
+
+noDFG(MyNumber.plusOne);
+
+let count = 0;
+let bogus = null;
+
+function bar()
+{
+    count++;
+
+    if (!(count % 100))
+        fullGC();
+    return new MyNumber(count);
+}
+
+noDFG(bar);
+noInline(bar);
+
+function foo(index, arg)
+{
+    var result = [arg[0]];
+    if (arg.length &gt; 1)
+        result[1] = bar();
+    return result;
+}
+
+noInline(foo);
+
+function test()
+{
+    for (let i = 0; i &lt; 50000; i++)
+    {
+        let a = [1, i];
+        let x = foo(i, a);
+
+        if (!(count % 100))
+            edenGC();
+
+        for (let j = 0; j &lt; 100; j++)
+            bogus = new MyNumber(-1);
+        
+        if ((count + 1) != x[1].plusOne())
+            throw(&quot;Wrong value for count&quot;);
+    }
+}
+
+test();
</ins></span></pre>
</div>
</div>

</body>
</html>