<!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>[207545] trunk/Source</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/207545">207545</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-10-19 10:47:30 -0700 (Wed, 19 Oct 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>DFG worklist should use AutomaticThread
https://bugs.webkit.org/show_bug.cgi?id=163615

Reviewed by Mark Lam.
        
Source/JavaScriptCore:

AutomaticThread is a new feature in WTF that allows you to easily create worker threads that
shut down automatically. This changes DFG::Worklist to use AutomaticThread, so that its
threads shut down automatically, too. This has the potential to save a lot of memory.
        
This required some improvements to AutomaticThread: Worklist likes to be able to keep state
around for the whole lifetime of a thread, and so it likes knowing when threads are born and
when they die. I added virtual methods for that. Also, Worklist uses notifyOne() so I added
that, too.
        
This looks to be perf-neutral.

* dfg/DFGThreadData.cpp:
(JSC::DFG::ThreadData::ThreadData):
* dfg/DFGThreadData.h:
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::Worklist):
(JSC::DFG::Worklist::~Worklist):
(JSC::DFG::Worklist::finishCreation):
(JSC::DFG::Worklist::isActiveForVM):
(JSC::DFG::Worklist::enqueue):
(JSC::DFG::Worklist::compilationState):
(JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady):
(JSC::DFG::Worklist::removeAllReadyPlansForVM):
(JSC::DFG::Worklist::completeAllReadyPlansForVM):
(JSC::DFG::Worklist::rememberCodeBlocks):
(JSC::DFG::Worklist::visitWeakReferences):
(JSC::DFG::Worklist::removeDeadPlans):
(JSC::DFG::Worklist::removeNonCompilingPlansForVM):
(JSC::DFG::Worklist::queueLength):
(JSC::DFG::Worklist::dump):
(JSC::DFG::Worklist::runThread): Deleted.
(JSC::DFG::Worklist::threadFunction): Deleted.
* dfg/DFGWorklist.h:

Source/WTF:

This adds new functionality to AutomaticThread to support DFG::Worklist:
        
- AutomaticThread::threadDidStart/threadWillStop virtual methods called at the start and end
  of a thread's lifetime. This allows Worklist to tie some resources to the life of the
  thread, and also means that now those resources will naturally free up when the Worklist is
  not in use.
        
- AutomaticThreadCondition::notifyOne(). This required changes to Condition::notifyOne(). We
  need to know if the Condition woke up anyone. If it didn't, then we need to launch one of
  our threads.

* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThread::ThreadScope::ThreadScope):
(WTF::AutomaticThread::ThreadScope::~ThreadScope):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadDidStart):
(WTF::AutomaticThread::threadWillStop):
* wtf/AutomaticThread.h:
* wtf/Condition.h:
(WTF::ConditionBase::notifyOne):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGThreadDatacpp">trunk/Source/JavaScriptCore/dfg/DFGThreadData.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGThreadDatah">trunk/Source/JavaScriptCore/dfg/DFGThreadData.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWorklistcpp">trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWorklisth">trunk/Source/JavaScriptCore/dfg/DFGWorklist.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfAutomaticThreadcpp">trunk/Source/WTF/wtf/AutomaticThread.cpp</a></li>
<li><a href="#trunkSourceWTFwtfAutomaticThreadh">trunk/Source/WTF/wtf/AutomaticThread.h</a></li>
<li><a href="#trunkSourceWTFwtfConditionh">trunk/Source/WTF/wtf/Condition.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -1,3 +1,45 @@
</span><ins>+2016-10-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG worklist should use AutomaticThread
+        https://bugs.webkit.org/show_bug.cgi?id=163615
+
+        Reviewed by Mark Lam.
+        
+        AutomaticThread is a new feature in WTF that allows you to easily create worker threads that
+        shut down automatically. This changes DFG::Worklist to use AutomaticThread, so that its
+        threads shut down automatically, too. This has the potential to save a lot of memory.
+        
+        This required some improvements to AutomaticThread: Worklist likes to be able to keep state
+        around for the whole lifetime of a thread, and so it likes knowing when threads are born and
+        when they die. I added virtual methods for that. Also, Worklist uses notifyOne() so I added
+        that, too.
+        
+        This looks to be perf-neutral.
+
+        * dfg/DFGThreadData.cpp:
+        (JSC::DFG::ThreadData::ThreadData):
+        * dfg/DFGThreadData.h:
+        * dfg/DFGWorklist.cpp:
+        (JSC::DFG::Worklist::ThreadBody::ThreadBody):
+        (JSC::DFG::Worklist::Worklist):
+        (JSC::DFG::Worklist::~Worklist):
+        (JSC::DFG::Worklist::finishCreation):
+        (JSC::DFG::Worklist::isActiveForVM):
+        (JSC::DFG::Worklist::enqueue):
+        (JSC::DFG::Worklist::compilationState):
+        (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady):
+        (JSC::DFG::Worklist::removeAllReadyPlansForVM):
+        (JSC::DFG::Worklist::completeAllReadyPlansForVM):
+        (JSC::DFG::Worklist::rememberCodeBlocks):
+        (JSC::DFG::Worklist::visitWeakReferences):
+        (JSC::DFG::Worklist::removeDeadPlans):
+        (JSC::DFG::Worklist::removeNonCompilingPlansForVM):
+        (JSC::DFG::Worklist::queueLength):
+        (JSC::DFG::Worklist::dump):
+        (JSC::DFG::Worklist::runThread): Deleted.
+        (JSC::DFG::Worklist::threadFunction): Deleted.
+        * dfg/DFGWorklist.h:
+
</ins><span class="cx"> 2016-10-19  Dan Bernstein  &lt;mitz@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Xcode] JavaScriptCore fails to build when CLANG_WARN_DOCUMENTATION_COMMENTS is enabled
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGThreadDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGThreadData.cpp (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGThreadData.cpp        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/JavaScriptCore/dfg/DFGThreadData.cpp        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -34,7 +34,6 @@
</span><span class="cx"> 
</span><span class="cx"> ThreadData::ThreadData(Worklist* worklist)
</span><span class="cx">     : m_worklist(worklist)
</span><del>-    , m_identifier(0)
</del><span class="cx">     , m_safepoint(nullptr)
</span><span class="cx"> {
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGThreadDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGThreadData.h (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGThreadData.h        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/JavaScriptCore/dfg/DFGThreadData.h        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -27,8 +27,8 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><ins>+#include &lt;wtf/AutomaticThread.h&gt;
</ins><span class="cx"> #include &lt;wtf/Lock.h&gt;
</span><del>-#include &lt;wtf/Threading.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx">     friend class Worklist;
</span><span class="cx">     
</span><span class="cx">     Worklist* m_worklist;
</span><del>-    ThreadIdentifier m_identifier;
</del><ins>+    RefPtr&lt;AutomaticThread&gt; m_thread;
</ins><span class="cx">     Lock m_rightToRun;
</span><span class="cx">     Safepoint* m_safepoint;
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWorklistcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -37,8 +37,134 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><ins>+class Worklist::ThreadBody : public AutomaticThread {
+public:
+    ThreadBody(const LockHolder&amp; locker, Worklist&amp; worklist, ThreadData&amp; data, Box&lt;Lock&gt; lock, RefPtr&lt;AutomaticThreadCondition&gt; condition, int relativePriority)
+        : AutomaticThread(locker, lock, condition)
+        , m_worklist(worklist)
+        , m_data(data)
+        , m_relativePriority(relativePriority)
+    {
+    }
+    
+protected:
+    PollResult poll(const LockHolder&amp; locker) override
+    {
+        if (m_worklist.m_queue.isEmpty())
+            return PollResult::Wait;
+        
+        m_plan = m_worklist.m_queue.takeFirst();
+        if (!m_plan) {
+            if (Options::verboseCompilationQueue()) {
+                m_worklist.dump(locker, WTF::dataFile());
+                dataLog(&quot;: Thread shutting down\n&quot;);
+            }
+            return PollResult::Stop;
+        }
+        RELEASE_ASSERT(m_plan-&gt;stage == Plan::Preparing);
+        m_worklist.m_numberOfActiveThreads++;
+        return PollResult::Work;
+    }
+    
+    class WorkScope;
+    friend class WorkScope;
+    class WorkScope {
+    public:
+        WorkScope(ThreadBody&amp; thread)
+            : m_thread(thread)
+        {
+            RELEASE_ASSERT(m_thread.m_plan);
+            RELEASE_ASSERT(m_thread.m_worklist.m_numberOfActiveThreads);
+        }
+        
+        ~WorkScope()
+        {
+            LockHolder locker(*m_thread.m_worklist.m_lock);
+            m_thread.m_plan = nullptr;
+            m_thread.m_worklist.m_numberOfActiveThreads--;
+        }
+        
+    private:
+        ThreadBody&amp; m_thread;
+    };
+    
+    WorkResult work() override
+    {
+        WorkScope workScope(*this);
+        
+        LockHolder locker(m_data.m_rightToRun);
+        {
+            LockHolder locker(*m_worklist.m_lock);
+            if (m_plan-&gt;stage == Plan::Cancelled)
+                return WorkResult::Continue;
+            m_plan-&gt;notifyCompiling();
+        }
+        
+        if (Options::verboseCompilationQueue())
+            dataLog(m_worklist, &quot;: Compiling &quot;, m_plan-&gt;key(), &quot; asynchronously\n&quot;);
+        
+        RELEASE_ASSERT(!m_plan-&gt;vm-&gt;heap.isCollecting());
+        m_plan-&gt;compileInThread(*m_longLivedState, &amp;m_data);
+        RELEASE_ASSERT(m_plan-&gt;stage == Plan::Cancelled || !m_plan-&gt;vm-&gt;heap.isCollecting());
+        
+        {
+            LockHolder locker(*m_worklist.m_lock);
+            if (m_plan-&gt;stage == Plan::Cancelled)
+                return WorkResult::Continue;
+            
+            m_plan-&gt;notifyReady();
+            
+            if (Options::verboseCompilationQueue()) {
+                m_worklist.dump(locker, WTF::dataFile());
+                dataLog(&quot;: Compiled &quot;, m_plan-&gt;key(), &quot; asynchronously\n&quot;);
+            }
+            
+            m_worklist.m_readyPlans.append(m_plan);
+            
+            m_worklist.m_planCompiled.notifyAll();
+        }
+        RELEASE_ASSERT(!m_plan-&gt;vm-&gt;heap.isCollecting());
+        
+        return WorkResult::Continue;
+    }
+    
+    void threadDidStart() override
+    {
+        if (Options::verboseCompilationQueue())
+            dataLog(m_worklist, &quot;: Thread started\n&quot;);
+        
+        if (m_relativePriority)
+            changeThreadPriority(currentThread(), m_relativePriority);
+        
+        m_compilationScope = std::make_unique&lt;CompilationScope&gt;();
+        m_longLivedState = std::make_unique&lt;LongLivedState&gt;();
+    }
+    
+    void threadWillStop() override
+    {
+        if (Options::verboseCompilationQueue())
+            dataLog(m_worklist, &quot;: Thread will stop\n&quot;);
+        
+        ASSERT(!m_plan);
+        
+        m_compilationScope = nullptr;
+        m_longLivedState = nullptr;
+        m_plan = nullptr;
+    }
+    
+private:
+    Worklist&amp; m_worklist;
+    ThreadData&amp; m_data;
+    int m_relativePriority;
+    std::unique_ptr&lt;CompilationScope&gt; m_compilationScope;
+    std::unique_ptr&lt;LongLivedState&gt; m_longLivedState;
+    RefPtr&lt;Plan&gt; m_plan;
+};
+
</ins><span class="cx"> Worklist::Worklist(CString worklistName)
</span><span class="cx">     : m_threadName(toCString(worklistName, &quot; Worker Thread&quot;))
</span><ins>+    , m_lock(Box&lt;Lock&gt;::create())
+    , m_planEnqueued(AutomaticThreadCondition::create())
</ins><span class="cx">     , m_numberOfActiveThreads(0)
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="lines">@@ -46,13 +172,13 @@
</span><span class="cx"> Worklist::~Worklist()
</span><span class="cx"> {
</span><span class="cx">     {
</span><del>-        LockHolder locker(m_lock);
</del><ins>+        LockHolder locker(*m_lock);
</ins><span class="cx">         for (unsigned i = m_threads.size(); i--;)
</span><span class="cx">             m_queue.append(nullptr); // Use null plan to indicate that we want the thread to terminate.
</span><del>-        m_planEnqueued.notifyAll();
</del><ins>+        m_planEnqueued-&gt;notifyAll(locker);
</ins><span class="cx">     }
</span><span class="cx">     for (unsigned i = m_threads.size(); i--;)
</span><del>-        waitForThreadCompletion(m_threads[i]-&gt;m_identifier);
</del><ins>+        m_threads[i]-&gt;m_thread-&gt;join();
</ins><span class="cx">     ASSERT(!m_numberOfActiveThreads);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -59,11 +185,10 @@
</span><span class="cx"> void Worklist::finishCreation(unsigned numberOfThreads, int relativePriority)
</span><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(numberOfThreads);
</span><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     for (unsigned i = numberOfThreads; i--;) {
</span><span class="cx">         std::unique_ptr&lt;ThreadData&gt; data = std::make_unique&lt;ThreadData&gt;(this);
</span><del>-        data-&gt;m_identifier = createThread(threadFunction, data.get(), m_threadName.data());
-        if (relativePriority)
-            changeThreadPriority(data-&gt;m_identifier, relativePriority);
</del><ins>+        data-&gt;m_thread = adoptRef(new ThreadBody(locker, *this, *data, m_lock, m_planEnqueued, relativePriority));
</ins><span class="cx">         m_threads.append(WTFMove(data));
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -77,7 +202,7 @@
</span><span class="cx"> 
</span><span class="cx"> bool Worklist::isActiveForVM(VM&amp; vm) const
</span><span class="cx"> {
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     PlanMap::const_iterator end = m_plans.end();
</span><span class="cx">     for (PlanMap::const_iterator iter = m_plans.begin(); iter != end; ++iter) {
</span><span class="cx">         if (iter-&gt;value-&gt;vm == &amp;vm)
</span><span class="lines">@@ -89,7 +214,7 @@
</span><span class="cx"> void Worklist::enqueue(PassRefPtr&lt;Plan&gt; passedPlan)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;Plan&gt; plan = passedPlan;
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     if (Options::verboseCompilationQueue()) {
</span><span class="cx">         dump(locker, WTF::dataFile());
</span><span class="cx">         dataLog(&quot;: Enqueueing plan to optimize &quot;, plan-&gt;key(), &quot;\n&quot;);
</span><span class="lines">@@ -97,12 +222,12 @@
</span><span class="cx">     ASSERT(m_plans.find(plan-&gt;key()) == m_plans.end());
</span><span class="cx">     m_plans.add(plan-&gt;key(), plan);
</span><span class="cx">     m_queue.append(plan);
</span><del>-    m_planEnqueued.notifyOne();
</del><ins>+    m_planEnqueued-&gt;notifyOne(locker);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Worklist::State Worklist::compilationState(CompilationKey key)
</span><span class="cx"> {
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     PlanMap::iterator iter = m_plans.find(key);
</span><span class="cx">     if (iter == m_plans.end())
</span><span class="cx">         return NotKnown;
</span><span class="lines">@@ -118,7 +243,7 @@
</span><span class="cx">     // After we release this lock, we know that although other VMs may still
</span><span class="cx">     // be adding plans, our VM will not be.
</span><span class="cx">     
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     
</span><span class="cx">     if (Options::verboseCompilationQueue()) {
</span><span class="cx">         dump(locker, WTF::dataFile());
</span><span class="lines">@@ -140,7 +265,7 @@
</span><span class="cx">         if (allAreCompiled)
</span><span class="cx">             break;
</span><span class="cx">         
</span><del>-        m_planCompiled.wait(m_lock);
</del><ins>+        m_planCompiled.wait(*m_lock);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -147,7 +272,7 @@
</span><span class="cx"> void Worklist::removeAllReadyPlansForVM(VM&amp; vm, Vector&lt;RefPtr&lt;Plan&gt;, 8&gt;&amp; myReadyPlans)
</span><span class="cx"> {
</span><span class="cx">     DeferGC deferGC(vm.heap);
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     for (size_t i = 0; i &lt; m_readyPlans.size(); ++i) {
</span><span class="cx">         RefPtr&lt;Plan&gt; plan = m_readyPlans[i];
</span><span class="cx">         if (plan-&gt;vm != &amp;vm)
</span><span class="lines">@@ -192,7 +317,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (!!requestedKey &amp;&amp; resultingState == NotKnown) {
</span><del>-        LockHolder locker(m_lock);
</del><ins>+        LockHolder locker(*m_lock);
</ins><span class="cx">         if (m_plans.contains(requestedKey))
</span><span class="cx">             resultingState = Compiling;
</span><span class="cx">     }
</span><span class="lines">@@ -209,7 +334,7 @@
</span><span class="cx"> 
</span><span class="cx"> void Worklist::rememberCodeBlocks(VM&amp; vm)
</span><span class="cx"> {
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
</span><span class="cx">         Plan* plan = iter-&gt;value.get();
</span><span class="cx">         if (plan-&gt;vm != &amp;vm)
</span><span class="lines">@@ -236,7 +361,7 @@
</span><span class="cx"> {
</span><span class="cx">     VM* vm = visitor.heap()-&gt;vm();
</span><span class="cx">     {
</span><del>-        LockHolder locker(m_lock);
</del><ins>+        LockHolder locker(*m_lock);
</ins><span class="cx">         for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
</span><span class="cx">             Plan* plan = iter-&gt;value.get();
</span><span class="cx">             if (plan-&gt;vm != vm)
</span><span class="lines">@@ -259,7 +384,7 @@
</span><span class="cx"> void Worklist::removeDeadPlans(VM&amp; vm)
</span><span class="cx"> {
</span><span class="cx">     {
</span><del>-        LockHolder locker(m_lock);
</del><ins>+        LockHolder locker(*m_lock);
</ins><span class="cx">         HashSet&lt;CompilationKey&gt; deadPlanKeys;
</span><span class="cx">         for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
</span><span class="cx">             Plan* plan = iter-&gt;value.get();
</span><span class="lines">@@ -306,7 +431,7 @@
</span><span class="cx"> 
</span><span class="cx"> void Worklist::removeNonCompilingPlansForVM(VM&amp; vm)
</span><span class="cx"> {
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     HashSet&lt;CompilationKey&gt; deadPlanKeys;
</span><span class="cx">     Vector&lt;RefPtr&lt;Plan&gt;&gt; deadPlans;
</span><span class="cx">     for (auto&amp; entry : m_plans) {
</span><span class="lines">@@ -337,13 +462,13 @@
</span><span class="cx"> 
</span><span class="cx"> size_t Worklist::queueLength()
</span><span class="cx"> {
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     return m_queue.size();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Worklist::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    LockHolder locker(*m_lock);
</ins><span class="cx">     dump(locker, out);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -355,83 +480,6 @@
</span><span class="cx">         &quot;, Num Active Threads = &quot;, m_numberOfActiveThreads, &quot;/&quot;, m_threads.size(), &quot;]&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Worklist::runThread(ThreadData* data)
-{
-    CompilationScope compilationScope;
-    
-    if (Options::verboseCompilationQueue())
-        dataLog(*this, &quot;: Thread started\n&quot;);
-    
-    LongLivedState longLivedState;
-    
-    for (;;) {
-        RefPtr&lt;Plan&gt; plan;
-        {
-            LockHolder locker(m_lock);
-            while (m_queue.isEmpty())
-                m_planEnqueued.wait(m_lock);
-            
-            plan = m_queue.takeFirst();
-            if (plan) {
-                RELEASE_ASSERT(plan-&gt;stage == Plan::Preparing);
-                m_numberOfActiveThreads++;
-            }
-        }
-        
-        if (!plan) {
-            if (Options::verboseCompilationQueue())
-                dataLog(*this, &quot;: Thread shutting down\n&quot;);
-            return;
-        }
-        
-        {
-            LockHolder locker(data-&gt;m_rightToRun);
-            {
-                LockHolder locker(m_lock);
-                if (plan-&gt;stage == Plan::Cancelled) {
-                    m_numberOfActiveThreads--;
-                    continue;
-                }
-                plan-&gt;notifyCompiling();
-            }
-        
-            if (Options::verboseCompilationQueue())
-                dataLog(*this, &quot;: Compiling &quot;, plan-&gt;key(), &quot; asynchronously\n&quot;);
-        
-            RELEASE_ASSERT(!plan-&gt;vm-&gt;heap.isCollecting());
-            plan-&gt;compileInThread(longLivedState, data);
-            RELEASE_ASSERT(plan-&gt;stage == Plan::Cancelled || !plan-&gt;vm-&gt;heap.isCollecting());
-            
-            {
-                LockHolder locker(m_lock);
-                if (plan-&gt;stage == Plan::Cancelled) {
-                    m_numberOfActiveThreads--;
-                    continue;
-                }
-                
-                plan-&gt;notifyReady();
-                
-                if (Options::verboseCompilationQueue()) {
-                    dump(locker, WTF::dataFile());
-                    dataLog(&quot;: Compiled &quot;, plan-&gt;key(), &quot; asynchronously\n&quot;);
-                }
-                
-                m_readyPlans.append(plan);
-                
-                m_planCompiled.notifyAll();
-                m_numberOfActiveThreads--;
-            }
-            RELEASE_ASSERT(!plan-&gt;vm-&gt;heap.isCollecting());
-        }
-    }
-}
-
-void Worklist::threadFunction(void* argument)
-{
-    ThreadData* data = static_cast&lt;ThreadData*&gt;(argument);
-    data-&gt;m_worklist-&gt;runThread(data);
-}
-
</del><span class="cx"> static Worklist* theGlobalDFGWorklist;
</span><span class="cx"> 
</span><span class="cx"> Worklist* ensureGlobalDFGWorklist()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWorklisth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGWorklist.h (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWorklist.h        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/JavaScriptCore/dfg/DFGWorklist.h        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;DFGPlan.h&quot;
</span><span class="cx"> #include &quot;DFGThreadData.h&quot;
</span><ins>+#include &lt;wtf/AutomaticThread.h&gt;
</ins><span class="cx"> #include &lt;wtf/Condition.h&gt;
</span><span class="cx"> #include &lt;wtf/Deque.h&gt;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><span class="lines">@@ -83,6 +84,9 @@
</span><span class="cx">     Worklist(CString worklistName);
</span><span class="cx">     void finishCreation(unsigned numberOfThreads, int);
</span><span class="cx">     
</span><ins>+    class ThreadBody;
+    friend class ThreadBody;
+    
</ins><span class="cx">     void runThread(ThreadData*);
</span><span class="cx">     static void threadFunction(void* argument);
</span><span class="cx">     
</span><span class="lines">@@ -108,8 +112,8 @@
</span><span class="cx"> 
</span><span class="cx">     Lock m_suspensionLock;
</span><span class="cx">     
</span><del>-    mutable Lock m_lock;
-    Condition m_planEnqueued;
</del><ins>+    Box&lt;Lock&gt; m_lock;
+    RefPtr&lt;AutomaticThreadCondition&gt; m_planEnqueued;
</ins><span class="cx">     Condition m_planCompiled;
</span><span class="cx">     
</span><span class="cx">     Vector&lt;std::unique_ptr&lt;ThreadData&gt;&gt; m_threads;
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/WTF/ChangeLog        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -1,3 +1,32 @@
</span><ins>+2016-10-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG worklist should use AutomaticThread
+        https://bugs.webkit.org/show_bug.cgi?id=163615
+
+        Reviewed by Mark Lam.
+        
+        This adds new functionality to AutomaticThread to support DFG::Worklist:
+        
+        - AutomaticThread::threadDidStart/threadWillStop virtual methods called at the start and end
+          of a thread's lifetime. This allows Worklist to tie some resources to the life of the
+          thread, and also means that now those resources will naturally free up when the Worklist is
+          not in use.
+        
+        - AutomaticThreadCondition::notifyOne(). This required changes to Condition::notifyOne(). We
+          need to know if the Condition woke up anyone. If it didn't, then we need to launch one of
+          our threads.
+
+        * wtf/AutomaticThread.cpp:
+        (WTF::AutomaticThreadCondition::notifyOne):
+        (WTF::AutomaticThread::ThreadScope::ThreadScope):
+        (WTF::AutomaticThread::ThreadScope::~ThreadScope):
+        (WTF::AutomaticThread::start):
+        (WTF::AutomaticThread::threadDidStart):
+        (WTF::AutomaticThread::threadWillStop):
+        * wtf/AutomaticThread.h:
+        * wtf/Condition.h:
+        (WTF::ConditionBase::notifyOne):
+
</ins><span class="cx"> 2016-10-18  Sam Weinig  &lt;sam@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Replace std::experimental::variant with WTF::Variant (or similar)
</span></span></pre></div>
<a id="trunkSourceWTFwtfAutomaticThreadcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/AutomaticThread.cpp (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/AutomaticThread.cpp        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/WTF/wtf/AutomaticThread.cpp        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -45,6 +45,17 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AutomaticThreadCondition::notifyOne(const LockHolder&amp; locker)
+{
+    if (m_condition.notifyOne())
+        return;
+    
+    if (m_threads.isEmpty())
+        return;
+    
+    m_threads.takeLast()-&gt;start(locker);
+}
+
</ins><span class="cx"> void AutomaticThreadCondition::notifyAll(const LockHolder&amp; locker)
</span><span class="cx"> {
</span><span class="cx">     m_condition.notifyAll();
</span><span class="lines">@@ -95,6 +106,23 @@
</span><span class="cx">         m_isRunningCondition.wait(*m_lock);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+class AutomaticThread::ThreadScope {
+public:
+    ThreadScope(AutomaticThread&amp; thread)
+        : m_thread(thread)
+    {
+        m_thread.threadDidStart();
+    }
+    
+    ~ThreadScope()
+    {
+        m_thread.threadWillStop();
+    }
+
+private:
+    AutomaticThread&amp; m_thread;
+};
+
</ins><span class="cx"> void AutomaticThread::start(const LockHolder&amp;)
</span><span class="cx"> {
</span><span class="cx">     RefPtr&lt;AutomaticThread&gt; preserveThisForThread = this;
</span><span class="lines">@@ -111,6 +139,8 @@
</span><span class="cx">                 ASSERT(!m_condition-&gt;contains(locker, this));
</span><span class="cx">             }
</span><span class="cx">             
</span><ins>+            ThreadScope threadScope(*this);
+            
</ins><span class="cx">             auto stop = [&amp;] (const LockHolder&amp;) {
</span><span class="cx">                 m_isRunning = false;
</span><span class="cx">                 m_isRunningCondition.notifyAll();
</span><span class="lines">@@ -150,5 +180,13 @@
</span><span class="cx">     detachThread(thread);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void AutomaticThread::threadDidStart()
+{
+}
+
+void AutomaticThread::threadWillStop()
+{
+}
+
</ins><span class="cx"> } // namespace WTF
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtfAutomaticThreadh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/AutomaticThread.h (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/AutomaticThread.h        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/WTF/wtf/AutomaticThread.h        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -75,6 +75,7 @@
</span><span class="cx">     
</span><span class="cx">     WTF_EXPORT_PRIVATE ~AutomaticThreadCondition();
</span><span class="cx">     
</span><ins>+    WTF_EXPORT_PRIVATE void notifyOne(const LockHolder&amp;);
</ins><span class="cx">     WTF_EXPORT_PRIVATE void notifyAll(const LockHolder&amp;);
</span><span class="cx">     
</span><span class="cx"> private:
</span><span class="lines">@@ -108,7 +109,7 @@
</span><span class="cx">     
</span><span class="cx"> protected:
</span><span class="cx">     // This logically creates the thread, but in reality the thread won't be created until someone
</span><del>-    // calls AutomaticThreadCondition::notifyAll().
</del><ins>+    // calls AutomaticThreadCondition::notifyOne() or notifyAll().
</ins><span class="cx">     AutomaticThread(const LockHolder&amp;, Box&lt;Lock&gt;, RefPtr&lt;AutomaticThreadCondition&gt;);
</span><span class="cx">     
</span><span class="cx">     // To understand PollResult and WorkResult, imagine that poll() and work() are being called like
</span><span class="lines">@@ -143,6 +144,15 @@
</span><span class="cx">     enum class WorkResult { Continue, Stop };
</span><span class="cx">     virtual WorkResult work() = 0;
</span><span class="cx">     
</span><ins>+    class ThreadScope;
+    friend class ThreadScope;
+    
+    // It's sometimes useful to allocate resources while the thread is running, and to destroy them
+    // when the thread dies. These methods let you do this. You can override these methods, and you
+    // can be sure that the default ones don't do anything (so you don't need a super call).
+    virtual void threadDidStart();
+    virtual void threadWillStop();
+    
</ins><span class="cx"> private:
</span><span class="cx">     friend class AutomaticThreadCondition;
</span><span class="cx">     
</span><span class="lines">@@ -157,6 +167,7 @@
</span><span class="cx"> } // namespace WTF
</span><span class="cx"> 
</span><span class="cx"> using WTF::AutomaticThread;
</span><ins>+using WTF::AutomaticThreadCondition;
</ins><span class="cx"> 
</span><span class="cx"> #endif // WTF_AutomaticThread_h
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtfConditionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Condition.h (207544 => 207545)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Condition.h        2016-10-19 17:46:42 UTC (rev 207544)
+++ trunk/Source/WTF/wtf/Condition.h        2016-10-19 17:47:30 UTC (rev 207545)
</span><span class="lines">@@ -168,23 +168,26 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Note that this method is extremely fast when nobody is waiting. It is not necessary to try to
</span><del>-    // avoid calling this method.
-    void notifyOne()
</del><ins>+    // avoid calling this method. This returns true if someone was actually woken up.
+    bool notifyOne()
</ins><span class="cx">     {
</span><span class="cx">         if (!m_hasWaiters.load()) {
</span><span class="cx">             // At this exact instant, there is nobody waiting on this condition. The way to visualize
</span><span class="cx">             // this is that if unparkOne() ran to completion without obstructions at this moment, it
</span><span class="cx">             // wouldn't wake anyone up. Hence, we have nothing to do!
</span><del>-            return;
</del><ins>+            return false;
</ins><span class="cx">         }
</span><span class="cx">         
</span><ins>+        bool didNotifyThread = false;
</ins><span class="cx">         ParkingLot::unparkOne(
</span><span class="cx">             &amp;m_hasWaiters,
</span><del>-            [this] (ParkingLot::UnparkResult result) -&gt; intptr_t {
</del><ins>+            [&amp;] (ParkingLot::UnparkResult result) -&gt; intptr_t {
</ins><span class="cx">                 if (!result.mayHaveMoreThreads)
</span><span class="cx">                     m_hasWaiters.store(false);
</span><ins>+                didNotifyThread = result.didUnparkThread;
</ins><span class="cx">                 return 0;
</span><span class="cx">             });
</span><ins>+        return didNotifyThread;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void notifyAll()
</span></span></pre>
</div>
</div>

</body>
</html>