<!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>[167733] 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/167733">167733</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2014-04-23 17:43:15 -0700 (Wed, 23 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>The GC should only resume compiler threads that it suspended in the same GC pass.
&lt;https://webkit.org/b/132088&gt;

Reviewed by Mark Hahnenberg.

Previously, this scenario can occur:
1. Thread 1 starts a GC and tries to suspend DFG worklist threads.  However,
   no worklists were created yet at the that time.
2. Thread 2 starts to compile some functions and creates a DFG worklist, and
   acquires the worklist thread's lock.
3. Thread 1's GC completes and tries to resume suspended DFG worklist thread.
   This time, it sees the worklist created by Thread 2 and ends up unlocking
   the worklist thread's lock that is supposedly held by Thread 2.
Thereafter, chaos ensues.

The fix is to cache the worklists that were actually suspended by each GC pass,
and only resume those when the GC is done.

This issue was discovered by enabling COLLECT_ON_EVERY_ALLOCATION and running
the fast/workers layout tests.

* heap/Heap.cpp:
(JSC::Heap::visitCompilerWorklists):
(JSC::Heap::deleteAllCompiledCode):
(JSC::Heap::suspendCompilerThreads):
(JSC::Heap::resumeCompilerThreads):
* heap/Heap.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (167732 => 167733)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-04-24 00:32:14 UTC (rev 167732)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-04-24 00:43:15 UTC (rev 167733)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2014-04-23  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        The GC should only resume compiler threads that it suspended in the same GC pass.
+        &lt;https://webkit.org/b/132088&gt;
+
+        Reviewed by Mark Hahnenberg.
+
+        Previously, this scenario can occur:
+        1. Thread 1 starts a GC and tries to suspend DFG worklist threads.  However,
+           no worklists were created yet at the that time.
+        2. Thread 2 starts to compile some functions and creates a DFG worklist, and
+           acquires the worklist thread's lock.
+        3. Thread 1's GC completes and tries to resume suspended DFG worklist thread.
+           This time, it sees the worklist created by Thread 2 and ends up unlocking
+           the worklist thread's lock that is supposedly held by Thread 2.
+        Thereafter, chaos ensues.
+
+        The fix is to cache the worklists that were actually suspended by each GC pass,
+        and only resume those when the GC is done.
+
+        This issue was discovered by enabling COLLECT_ON_EVERY_ALLOCATION and running
+        the fast/workers layout tests.
+
+        * heap/Heap.cpp:
+        (JSC::Heap::visitCompilerWorklists):
+        (JSC::Heap::deleteAllCompiledCode):
+        (JSC::Heap::suspendCompilerThreads):
+        (JSC::Heap::resumeCompilerThreads):
+        * heap/Heap.h:
+
</ins><span class="cx"> 2014-04-23  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Arguments::copyBackingStore needs to update m_registers in tandem with m_registerArray
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (167732 => 167733)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-04-24 00:32:14 UTC (rev 167732)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-04-24 00:43:15 UTC (rev 167733)
</span><span class="lines">@@ -626,10 +626,8 @@
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     GCPHASE(VisitDFGWorklists);
</span><del>-    for (unsigned i = DFG::numberOfWorklists(); i--;) {
-        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
-            worklist-&gt;visitChildren(m_slotVisitor, m_codeBlocks);
-    }
</del><ins>+    for (auto worklist : m_suspendedCompilerWorklists)
+        worklist-&gt;visitChildren(m_slotVisitor, m_codeBlocks);
</ins><span class="cx"> 
</span><span class="cx">     if (Options::logGC() == GCLogging::Verbose)
</span><span class="cx">         dataLog(&quot;DFG Worklists:\n&quot;, m_slotVisitor);
</span><span class="lines">@@ -881,11 +879,9 @@
</span><span class="cx">     // means that we are running some hot JS code right now. Maybe causing
</span><span class="cx">     // recompilations isn't a good idea.
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><del>-    for (unsigned i = DFG::numberOfWorklists(); i--;) {
-        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
-            if (worklist-&gt;isActiveForVM(*vm()))
-                return;
-        }
</del><ins>+    for (auto worklist : m_suspendedCompilerWorklists) {
+        if (worklist-&gt;isActiveForVM(*vm()))
+            return;
</ins><span class="cx">     }
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><span class="lines">@@ -1022,9 +1018,12 @@
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     GCPHASE(SuspendCompilerThreads);
</span><ins>+    ASSERT(m_suspendedCompilerWorklists.isEmpty());
</ins><span class="cx">     for (unsigned i = DFG::numberOfWorklists(); i--;) {
</span><del>-        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
</del><ins>+        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i)) {
+            m_suspendedCompilerWorklists.append(worklist);
</ins><span class="cx">             worklist-&gt;suspendAllThreads();
</span><ins>+        }
</ins><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="lines">@@ -1227,10 +1226,9 @@
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     GCPHASE(ResumeCompilerThreads);
</span><del>-    for (unsigned i = DFG::numberOfWorklists(); i--;) {
-        if (DFG::Worklist* worklist = DFG::worklistForIndexOrNull(i))
-            worklist-&gt;resumeAllThreads();
-    }
</del><ins>+    for (auto worklist : m_suspendedCompilerWorklists)
+        worklist-&gt;resumeAllThreads();
+    m_suspendedCompilerWorklists.clear();
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (167732 => 167733)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2014-04-24 00:32:14 UTC (rev 167732)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2014-04-24 00:43:15 UTC (rev 167733)
</span><span class="lines">@@ -71,6 +71,10 @@
</span><span class="cx"> class WeakGCHandlePool;
</span><span class="cx"> class SlotVisitor;
</span><span class="cx"> 
</span><ins>+namespace DFG {
+class Worklist;
+}
+
</ins><span class="cx"> typedef std::pair&lt;JSValue, WTF::String&gt; ValueStringPair;
</span><span class="cx"> typedef HashCountedSet&lt;JSCell*&gt; ProtectCountSet;
</span><span class="cx"> typedef HashCountedSet&lt;const char*&gt; TypeCountSet;
</span><span class="lines">@@ -373,6 +377,7 @@
</span><span class="cx">     Vector&lt;MarkedBlock*&gt; m_blockSnapshot;
</span><span class="cx">     
</span><span class="cx">     unsigned m_deferralDepth;
</span><ins>+    Vector&lt;DFG::Worklist*&gt; m_suspendedCompilerWorklists;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre>
</div>
</div>

</body>
</html>