<!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>[188169] 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/188169">188169</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-08-07 15:38:59 -0700 (Fri, 07 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Lightweight locks should be adaptive
https://bugs.webkit.org/show_bug.cgi?id=147545

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

* dfg/DFGCommon.cpp:
(JSC::DFG::startCrashing):
* heap/CopiedBlock.h:
(JSC::CopiedBlock::workListLock):
* heap/CopiedBlockInlines.h:
(JSC::CopiedBlock::shouldReportLiveBytes):
(JSC::CopiedBlock::reportLiveBytes):
* heap/CopiedSpace.cpp:
(JSC::CopiedSpace::doneFillingBlock):
* heap/CopiedSpace.h:
(JSC::CopiedSpace::CopiedGeneration::CopiedGeneration):
* heap/CopiedSpaceInlines.h:
(JSC::CopiedSpace::recycleEvacuatedBlock):
* heap/GCThreadSharedData.cpp:
(JSC::GCThreadSharedData::didStartCopying):
* heap/GCThreadSharedData.h:
(JSC::GCThreadSharedData::getNextBlocksToCopy):
* heap/ListableHandler.h:
(JSC::ListableHandler::List::addThreadSafe):
(JSC::ListableHandler::List::addNotThreadSafe):
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::tryCopyOtherThreadStacks):
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::copyLater):
* parser/SourceProvider.cpp:
(JSC::SourceProvider::~SourceProvider):
(JSC::SourceProvider::getID):
* profiler/ProfilerDatabase.cpp:
(JSC::Profiler::Database::addDatabaseToAtExit):
(JSC::Profiler::Database::removeDatabaseFromAtExit):
(JSC::Profiler::Database::removeFirstAtExitDatabase):
* runtime/TypeProfilerLog.h:

Source/WebCore:

* bindings/objc/WebScriptObject.mm:
(WebCore::getJSWrapper):
(WebCore::addJSWrapper):
(WebCore::removeJSWrapper):
(WebCore::removeJSWrapperIfRetainCountOne):
* platform/audio/mac/CARingBuffer.cpp:
(WebCore::CARingBuffer::setCurrentFrameBounds):
(WebCore::CARingBuffer::getCurrentFrameBounds):
* platform/audio/mac/CARingBuffer.h:
* platform/ios/wak/WAKWindow.mm:
(-[WAKWindow setExposedScrollViewRect:]):
(-[WAKWindow exposedScrollViewRect]):

Source/WebKit2:

* WebProcess/WebPage/EventDispatcher.cpp:
(WebKit::EventDispatcher::clearQueuedTouchEventsForPage):
(WebKit::EventDispatcher::getQueuedTouchEventsForPage):
(WebKit::EventDispatcher::touchEvent):
(WebKit::EventDispatcher::dispatchTouchEvents):
* WebProcess/WebPage/EventDispatcher.h:
* WebProcess/WebPage/ViewUpdateDispatcher.cpp:
(WebKit::ViewUpdateDispatcher::visibleContentRectUpdate):
(WebKit::ViewUpdateDispatcher::dispatchVisibleContentRectUpdate):
* WebProcess/WebPage/ViewUpdateDispatcher.h:

Source/WTF:

A common idiom in WebKit is to use spinlocks. We use them because the lock acquisition
overhead is lower than system locks and because they take dramatically less space than system
locks. The speed and space advantages of spinlocks can be astonishing: an uncontended spinlock
acquire is up to 10x faster and under microcontention - short critical section with two or
more threads taking turns - spinlocks are up to 100x faster. Spinlocks take only 1 byte or 4
bytes depending on the flavor, while system locks take 64 bytes or more. Clearly, WebKit
should continue to avoid system locks - they are just far too slow and far too big.

But there is a problem with this idiom. System lock implementations will sleep a thread when
it attempts to acquire a lock that is held, while spinlocks will cause the thread to burn CPU.
In WebKit spinlocks, the thread will repeatedly call sched_yield(). This is awesome for
microcontention, but awful when the lock will not be released for a while. In fact, when
critical sections take tens of microseconds or more, the CPU time cost of our spinlocks is
almost 100x more than the CPU time cost of a system lock. This case doesn't arise too
frequently in our current uses of spinlocks, but that's probably because right now there are
places where we make a conscious decision to use system locks - even though they use more
memory and are slower - because we don't want to waste CPU cycles when a thread has to wait a
while to acquire the lock.

The solution is to just implement a modern adaptive mutex in WTF. Luckily, this isn't a new
concept. This patch implements a mutex that is reminiscent of the kinds of low-overhead locks
that JVMs use. The actual implementation here is inspired by some of the ideas from [1]. The
idea is simple: the fast path is an inlined CAS to immediately acquire a lock that isn't held,
the slow path tries some number of spins to acquire the lock, and if that fails, the thread is
put on a queue and put to sleep. The queue is made up of statically allocated thread nodes and
the lock itself is a tagged pointer: either it is just bits telling us the complete lock state
(not held or held) or it is a pointer to the head of a queue of threads waiting to acquire the
lock. This approach gives WTF::Lock three different levels of adaptation: an inlined fast path
if the lock is not contended, a short burst of spinning for microcontention, and a full-blown
queue for critical sections that are held for a long time.

On a locking microbenchmark, this new Lock exhibits the following performance
characteristics:

- Lock+unlock on an uncontended no-op critical section: 2x slower than SpinLock and 3x faster
  than a system mutex.

- Lock+unlock on a contended no-op critical section: 2x slower than SpinLock and 100x faster
  than a system mutex.

- CPU time spent in lock() on a lock held for a while: same as system mutex, 90x less than a
  SpinLock.

- Memory usage: sizeof(void*), so on 64-bit it's 8x less than a system mutex but 2x worse than
  a SpinLock.

This patch replaces all uses of SpinLock with Lock, since our critical sections are not
no-ops so if you do basically anything in your critical section, the Lock overhead will be
invisible. Also, in all places where we used SpinLock, we could tolerate 8 bytes of overhead
instead of 4. Performance benchmarking using JSC macrobenchmarks shows no difference, which is
as it should be: the purpose of this change is to reduce CPU time wasted, not wallclock time.
This patch doesn't replace any uses of ByteSpinLock, since we expect that the space benefits
of having a lock that just uses a byte are still better than the CPU wastage benefits of
Lock. But, this work will enable some future work to create locks that will fit in just 1.6
bits: https://bugs.webkit.org/show_bug.cgi?id=147665.
        
Rolling this back in after fixing Lock::unlockSlow() for architectures that have a truly weak
CAS. Since the Lock::unlock() fast path can go to slow path spuriously, it may go there even if
there aren't any threads on the Lock's queue. So, unlockSlow() must be able to deal with the
possibility of a null queue head.

[1] http://www.filpizlo.com/papers/pizlo-pppj2011-fable.pdf

* WTF.vcxproj/WTF.vcxproj:
* WTF.xcodeproj/project.pbxproj:
* benchmarks: Added.
* benchmarks/LockSpeedTest.cpp: Added.
(main):
* wtf/Atomics.h:
(WTF::Atomic::compareExchangeWeak):
(WTF::Atomic::compareExchangeStrong):
* wtf/CMakeLists.txt:
* wtf/Lock.cpp: Added.
(WTF::LockBase::lockSlow):
(WTF::LockBase::unlockSlow):
* wtf/Lock.h: Added.
(WTF::LockBase::lock):
(WTF::LockBase::unlock):
(WTF::LockBase::isHeld):
(WTF::LockBase::isLocked):
(WTF::Lock::Lock):
* wtf/MetaAllocator.cpp:
(WTF::MetaAllocator::release):
(WTF::MetaAllocatorHandle::shrink):
(WTF::MetaAllocator::allocate):
(WTF::MetaAllocator::currentStatistics):
(WTF::MetaAllocator::addFreshFreeSpace):
(WTF::MetaAllocator::debugFreeSpaceSize):
* wtf/MetaAllocator.h:
* wtf/SpinLock.h:
* wtf/ThreadingPthreads.cpp:
* wtf/ThreadingWin.cpp:
* wtf/text/AtomicString.cpp:
* wtf/text/AtomicStringImpl.cpp:
(WTF::AtomicStringTableLocker::AtomicStringTableLocker):

Tools:

* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WTF/Lock.cpp: Added.
(TestWebKitAPI::runLockTest):
(TestWebKitAPI::TEST):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommoncpp">trunk/Source/JavaScriptCore/dfg/DFGCommon.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedBlockh">trunk/Source/JavaScriptCore/heap/CopiedBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedBlockInlinesh">trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedSpacecpp">trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedSpaceh">trunk/Source/JavaScriptCore/heap/CopiedSpace.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedSpaceInlinesh">trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapGCThreadSharedDatacpp">trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapGCThreadSharedDatah">trunk/Source/JavaScriptCore/heap/GCThreadSharedData.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapListableHandlerh">trunk/Source/JavaScriptCore/heap/ListableHandler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMachineStackMarkercpp">trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorInlinesh">trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserSourceProvidercpp">trunk/Source/JavaScriptCore/parser/SourceProvider.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreprofilerProfilerDatabasecpp">trunk/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeTypeProfilerLogh">trunk/Source/JavaScriptCore/runtime/TypeProfilerLog.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFWTFvcxprojWTFvcxproj">trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj</a></li>
<li><a href="#trunkSourceWTFWTFxcodeprojprojectpbxproj">trunk/Source/WTF/WTF.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceWTFwtfAtomicsh">trunk/Source/WTF/wtf/Atomics.h</a></li>
<li><a href="#trunkSourceWTFwtfCMakeListstxt">trunk/Source/WTF/wtf/CMakeLists.txt</a></li>
<li><a href="#trunkSourceWTFwtfMetaAllocatorcpp">trunk/Source/WTF/wtf/MetaAllocator.cpp</a></li>
<li><a href="#trunkSourceWTFwtfMetaAllocatorh">trunk/Source/WTF/wtf/MetaAllocator.h</a></li>
<li><a href="#trunkSourceWTFwtfSpinLockh">trunk/Source/WTF/wtf/SpinLock.h</a></li>
<li><a href="#trunkSourceWTFwtfThreadingPthreadscpp">trunk/Source/WTF/wtf/ThreadingPthreads.cpp</a></li>
<li><a href="#trunkSourceWTFwtfThreadingWincpp">trunk/Source/WTF/wtf/ThreadingWin.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextAtomicStringcpp">trunk/Source/WTF/wtf/text/AtomicString.cpp</a></li>
<li><a href="#trunkSourceWTFwtftextAtomicStringImplcpp">trunk/Source/WTF/wtf/text/AtomicStringImpl.cpp</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsobjcWebScriptObjectmm">trunk/Source/WebCore/bindings/objc/WebScriptObject.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacCARingBuffercpp">trunk/Source/WebCore/platform/audio/mac/CARingBuffer.cpp</a></li>
<li><a href="#trunkSourceWebCoreplatformaudiomacCARingBufferh">trunk/Source/WebCore/platform/audio/mac/CARingBuffer.h</a></li>
<li><a href="#trunkSourceWebCoreplatformioswakWAKWindowmm">trunk/Source/WebCore/platform/ios/wak/WAKWindow.mm</a></li>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageEventDispatchercpp">trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.cpp</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageEventDispatcherh">trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.h</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageViewUpdateDispatchercpp">trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.cpp</a></li>
<li><a href="#trunkSourceWebKit2WebProcessWebPageViewUpdateDispatcherh">trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPICMakeListstxt">trunk/Tools/TestWebKitAPI/CMakeLists.txt</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIvcxprojTestWebKitAPIvcxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj</a></li>
<li><a href="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/Source/WTF/benchmarks/</li>
<li><a href="#trunkSourceWTFbenchmarksLockSpeedTestcpp">trunk/Source/WTF/benchmarks/LockSpeedTest.cpp</a></li>
<li><a href="#trunkSourceWTFwtfLockcpp">trunk/Source/WTF/wtf/Lock.cpp</a></li>
<li><a href="#trunkSourceWTFwtfLockh">trunk/Source/WTF/wtf/Lock.h</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsWTFLockcpp">trunk/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,3 +1,43 @@
</span><ins>+2015-08-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Lightweight locks should be adaptive
+        https://bugs.webkit.org/show_bug.cgi?id=147545
+
+        Reviewed by Geoffrey Garen.
+
+        * dfg/DFGCommon.cpp:
+        (JSC::DFG::startCrashing):
+        * heap/CopiedBlock.h:
+        (JSC::CopiedBlock::workListLock):
+        * heap/CopiedBlockInlines.h:
+        (JSC::CopiedBlock::shouldReportLiveBytes):
+        (JSC::CopiedBlock::reportLiveBytes):
+        * heap/CopiedSpace.cpp:
+        (JSC::CopiedSpace::doneFillingBlock):
+        * heap/CopiedSpace.h:
+        (JSC::CopiedSpace::CopiedGeneration::CopiedGeneration):
+        * heap/CopiedSpaceInlines.h:
+        (JSC::CopiedSpace::recycleEvacuatedBlock):
+        * heap/GCThreadSharedData.cpp:
+        (JSC::GCThreadSharedData::didStartCopying):
+        * heap/GCThreadSharedData.h:
+        (JSC::GCThreadSharedData::getNextBlocksToCopy):
+        * heap/ListableHandler.h:
+        (JSC::ListableHandler::List::addThreadSafe):
+        (JSC::ListableHandler::List::addNotThreadSafe):
+        * heap/MachineStackMarker.cpp:
+        (JSC::MachineThreads::tryCopyOtherThreadStacks):
+        * heap/SlotVisitorInlines.h:
+        (JSC::SlotVisitor::copyLater):
+        * parser/SourceProvider.cpp:
+        (JSC::SourceProvider::~SourceProvider):
+        (JSC::SourceProvider::getID):
+        * profiler/ProfilerDatabase.cpp:
+        (JSC::Profiler::Database::addDatabaseToAtExit):
+        (JSC::Profiler::Database::removeDatabaseFromAtExit):
+        (JSC::Profiler::Database::removeFirstAtExitDatabase):
+        * runtime/TypeProfilerLog.h:
+
</ins><span class="cx"> 2015-08-07  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rename some variables in the JSC watchdog implementation.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommoncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommon.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommon.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommon.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><del>-static StaticSpinLock crashLock;
</del><ins>+static StaticLock crashLock;
</ins><span class="cx"> 
</span><span class="cx"> void startCrashing()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedBlock.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedBlock.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/CopiedBlock.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -31,7 +31,7 @@
</span><span class="cx"> #include &quot;Options.h&quot;
</span><span class="cx"> #include &lt;wtf/Atomics.h&gt;
</span><span class="cx"> #include &lt;wtf/DoublyLinkedList.h&gt;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -54,8 +54,8 @@
</span><span class="cx">     void didPromote();
</span><span class="cx"> 
</span><span class="cx">     unsigned liveBytes();
</span><del>-    bool shouldReportLiveBytes(SpinLockHolder&amp;, JSCell* owner);
-    void reportLiveBytes(SpinLockHolder&amp;, JSCell*, CopyToken, unsigned);
</del><ins>+    bool shouldReportLiveBytes(LockHolder&amp;, JSCell* owner);
+    void reportLiveBytes(LockHolder&amp;, JSCell*, CopyToken, unsigned);
</ins><span class="cx">     void reportLiveBytesDuringCopying(unsigned);
</span><span class="cx">     void didSurviveGC();
</span><span class="cx">     void didEvacuateBytes(unsigned);
</span><span class="lines">@@ -85,7 +85,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool hasWorkList();
</span><span class="cx">     CopyWorkList&amp; workList();
</span><del>-    SpinLock&amp; workListLock() { return m_workListLock; }
</del><ins>+    Lock&amp; workListLock() { return m_workListLock; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     CopiedBlock(size_t);
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx"> 
</span><span class="cx">     size_t m_capacity;
</span><span class="cx"> 
</span><del>-    SpinLock m_workListLock;
</del><ins>+    Lock m_workListLock;
</ins><span class="cx">     std::unique_ptr&lt;CopyWorkList&gt; m_workList;
</span><span class="cx"> 
</span><span class="cx">     size_t m_remaining;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedBlockInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx">     
</span><del>-inline bool CopiedBlock::shouldReportLiveBytes(SpinLockHolder&amp;, JSCell* owner)
</del><ins>+inline bool CopiedBlock::shouldReportLiveBytes(LockHolder&amp;, JSCell* owner)
</ins><span class="cx"> {
</span><span class="cx">     // We want to add to live bytes if the owner isn't part of the remembered set or
</span><span class="cx">     // if this block was allocated during the last cycle. 
</span><span class="lines">@@ -43,7 +43,7 @@
</span><span class="cx">     return !Heap::isRemembered(owner) || !m_isOld;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void CopiedBlock::reportLiveBytes(SpinLockHolder&amp;, JSCell* owner, CopyToken token, unsigned bytes)
</del><ins>+inline void CopiedBlock::reportLiveBytes(LockHolder&amp;, JSCell* owner, CopyToken token, unsigned bytes)
</ins><span class="cx"> {
</span><span class="cx">     checkConsistency();
</span><span class="cx"> #ifndef NDEBUG
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedSpacecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -191,7 +191,7 @@
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="cx">         // Always put the block into the old gen because it's being promoted!
</span><del>-        SpinLockHolder locker(&amp;m_toSpaceLock);
</del><ins>+        LockHolder locker(&amp;m_toSpaceLock);
</ins><span class="cx">         m_oldGen.toSpace-&gt;push(block);
</span><span class="cx">         m_blockSet.add(block);
</span><span class="cx">         m_oldGen.blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedSpaceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedSpace.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedSpace.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/CopiedSpace.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -33,9 +33,9 @@
</span><span class="cx"> #include &lt;wtf/CheckedBoolean.h&gt;
</span><span class="cx"> #include &lt;wtf/DoublyLinkedList.h&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/OSAllocator.h&gt;
</span><span class="cx"> #include &lt;wtf/PageBlock.h&gt;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><span class="cx"> #include &lt;wtf/StdLibExtras.h&gt;
</span><span class="cx"> #include &lt;wtf/ThreadingPrimitives.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -113,7 +113,7 @@
</span><span class="cx"> 
</span><span class="cx">     HashSet&lt;CopiedBlock*&gt; m_blockSet;
</span><span class="cx"> 
</span><del>-    SpinLock m_toSpaceLock;
</del><ins>+    Lock m_toSpaceLock;
</ins><span class="cx"> 
</span><span class="cx">     struct CopiedGeneration {
</span><span class="cx">         CopiedGeneration()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedSpaceInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx">     ASSERT(block-&gt;canBeRecycled());
</span><span class="cx">     ASSERT(!block-&gt;m_isPinned);
</span><span class="cx">     {
</span><del>-        SpinLockHolder locker(&amp;m_toSpaceLock);
</del><ins>+        LockHolder locker(&amp;m_toSpaceLock);
</ins><span class="cx">         m_blockSet.remove(block);
</span><span class="cx">         if (collectionType == EdenCollection)
</span><span class="cx">             m_newGen.fromSpace-&gt;remove(block);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapGCThreadSharedDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -178,7 +178,7 @@
</span><span class="cx"> void GCThreadSharedData::didStartCopying()
</span><span class="cx"> {
</span><span class="cx">     {
</span><del>-        SpinLockHolder locker(&amp;m_copyLock);
</del><ins>+        LockHolder locker(&amp;m_copyLock);
</ins><span class="cx">         if (m_vm-&gt;heap.operationInProgress() == EdenCollection) {
</span><span class="cx">             // Reset the vector to be empty, but don't throw away the backing store.
</span><span class="cx">             m_blocksToCopy.shrink(0);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapGCThreadSharedDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/GCThreadSharedData.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/GCThreadSharedData.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/GCThreadSharedData.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> #include &quot;WeakReferenceHarvester.h&quot;
</span><span class="cx"> #include &lt;condition_variable&gt;
</span><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx">     std::mutex m_opaqueRootsMutex;
</span><span class="cx">     HashSet&lt;void*&gt; m_opaqueRoots;
</span><span class="cx"> 
</span><del>-    SpinLock m_copyLock;
</del><ins>+    Lock m_copyLock;
</ins><span class="cx">     Vector&lt;CopiedBlock*&gt; m_blocksToCopy;
</span><span class="cx">     size_t m_copyIndex;
</span><span class="cx">     static const size_t s_blockFragmentLength = 32;
</span><span class="lines">@@ -115,7 +115,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline void GCThreadSharedData::getNextBlocksToCopy(size_t&amp; start, size_t&amp; end)
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;m_copyLock);
</del><ins>+    LockHolder locker(&amp;m_copyLock);
</ins><span class="cx">     start = m_copyIndex;
</span><span class="cx">     end = std::min(m_blocksToCopy.size(), m_copyIndex + s_blockFragmentLength);
</span><span class="cx">     m_copyIndex = end;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapListableHandlerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/ListableHandler.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/ListableHandler.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/ListableHandler.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -21,9 +21,9 @@
</span><span class="cx"> #define ListableHandler_h
</span><span class="cx"> 
</span><span class="cx"> #include &lt;stdint.h&gt;
</span><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/Locker.h&gt;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><span class="cx"> #include &lt;wtf/ThreadingPrimitives.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx">         
</span><span class="cx">         void addThreadSafe(T* handler)
</span><span class="cx">         {
</span><del>-            SpinLockHolder locker(&amp;m_lock);
</del><ins>+            LockHolder locker(&amp;m_lock);
</ins><span class="cx">             addNotThreadSafe(handler);
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="lines">@@ -103,7 +103,7 @@
</span><span class="cx">             m_first = handler;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        SpinLock m_lock;
</del><ins>+        Lock m_lock;
</ins><span class="cx">         T* m_first;
</span><span class="cx">     };
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMachineStackMarkercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/MachineStackMarker.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -568,8 +568,8 @@
</span><span class="cx"> {
</span><span class="cx">     // Prevent two VMs from suspending each other's threads at the same time,
</span><span class="cx">     // which can cause deadlock: &lt;rdar://problem/20300842&gt;.
</span><del>-    static StaticSpinLock mutex;
-    std::lock_guard&lt;StaticSpinLock&gt; lock(mutex);
</del><ins>+    static StaticLock mutex;
+    std::lock_guard&lt;StaticLock&gt; lock(mutex);
</ins><span class="cx"> 
</span><span class="cx">     *size = 0;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -250,7 +250,7 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(heap()-&gt;m_storageSpace.contains(block));
</span><span class="cx"> 
</span><del>-    SpinLockHolder locker(&amp;block-&gt;workListLock());
</del><ins>+    LockHolder locker(&amp;block-&gt;workListLock());
</ins><span class="cx">     if (heap()-&gt;operationInProgress() == FullCollection || block-&gt;shouldReportLiveBytes(locker, owner)) {
</span><span class="cx">         m_bytesCopied += bytes;
</span><span class="cx">         block-&gt;reportLiveBytes(locker, owner, token, bytes);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserSourceProvidercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/SourceProvider.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/SourceProvider.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/parser/SourceProvider.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> #include &quot;SourceProvider.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/StdLibExtras.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="lines">@@ -44,11 +44,11 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static StaticSpinLock providerIdLock;
</del><ins>+static StaticLock providerIdLock;
</ins><span class="cx"> 
</span><span class="cx"> void SourceProvider::getID()
</span><span class="cx"> {
</span><del>-    SpinLockHolder lock(&amp;providerIdLock);
</del><ins>+    LockHolder lock(&amp;providerIdLock);
</ins><span class="cx">     if (!m_id) {
</span><span class="cx">         static intptr_t nextProviderID = 0;
</span><span class="cx">         m_id = ++nextProviderID;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreprofilerProfilerDatabasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/profiler/ProfilerDatabase.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> static std::atomic&lt;int&gt; databaseCounter;
</span><span class="cx"> 
</span><del>-static StaticSpinLock registrationLock;
</del><ins>+static StaticLock registrationLock;
</ins><span class="cx"> static std::atomic&lt;int&gt; didRegisterAtExit;
</span><span class="cx"> static Database* firstDatabase;
</span><span class="cx"> 
</span><span class="lines">@@ -138,14 +138,14 @@
</span><span class="cx">     if (++didRegisterAtExit == 1)
</span><span class="cx">         atexit(atExitCallback);
</span><span class="cx">     
</span><del>-    SpinLockHolder holder(registrationLock);
</del><ins>+    LockHolder holder(registrationLock);
</ins><span class="cx">     m_nextRegisteredDatabase = firstDatabase;
</span><span class="cx">     firstDatabase = this;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Database::removeDatabaseFromAtExit()
</span><span class="cx"> {
</span><del>-    SpinLockHolder holder(registrationLock);
</del><ins>+    LockHolder holder(registrationLock);
</ins><span class="cx">     for (Database** current = &amp;firstDatabase; *current; current = &amp;(*current)-&gt;m_nextRegisteredDatabase) {
</span><span class="cx">         if (*current != this)
</span><span class="cx">             continue;
</span><span class="lines">@@ -163,7 +163,7 @@
</span><span class="cx"> 
</span><span class="cx"> Database* Database::removeFirstAtExitDatabase()
</span><span class="cx"> {
</span><del>-    SpinLockHolder holder(registrationLock);
</del><ins>+    LockHolder holder(registrationLock);
</ins><span class="cx">     Database* result = firstDatabase;
</span><span class="cx">     if (result) {
</span><span class="cx">         firstDatabase = result-&gt;m_nextRegisteredDatabase;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeTypeProfilerLogh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/TypeProfilerLog.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/TypeProfilerLog.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/JavaScriptCore/runtime/TypeProfilerLog.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -32,7 +32,6 @@
</span><span class="cx"> #include &quot;JSCJSValue.h&quot;
</span><span class="cx"> #include &quot;Structure.h&quot;
</span><span class="cx"> #include &quot;TypeProfiler.h&quot;
</span><del>-#include &lt;wtf/ByteSpinLock.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/ChangeLog        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,3 +1,106 @@
</span><ins>+2015-08-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Lightweight locks should be adaptive
+        https://bugs.webkit.org/show_bug.cgi?id=147545
+
+        Reviewed by Geoffrey Garen.
+
+        A common idiom in WebKit is to use spinlocks. We use them because the lock acquisition
+        overhead is lower than system locks and because they take dramatically less space than system
+        locks. The speed and space advantages of spinlocks can be astonishing: an uncontended spinlock
+        acquire is up to 10x faster and under microcontention - short critical section with two or
+        more threads taking turns - spinlocks are up to 100x faster. Spinlocks take only 1 byte or 4
+        bytes depending on the flavor, while system locks take 64 bytes or more. Clearly, WebKit
+        should continue to avoid system locks - they are just far too slow and far too big.
+
+        But there is a problem with this idiom. System lock implementations will sleep a thread when
+        it attempts to acquire a lock that is held, while spinlocks will cause the thread to burn CPU.
+        In WebKit spinlocks, the thread will repeatedly call sched_yield(). This is awesome for
+        microcontention, but awful when the lock will not be released for a while. In fact, when
+        critical sections take tens of microseconds or more, the CPU time cost of our spinlocks is
+        almost 100x more than the CPU time cost of a system lock. This case doesn't arise too
+        frequently in our current uses of spinlocks, but that's probably because right now there are
+        places where we make a conscious decision to use system locks - even though they use more
+        memory and are slower - because we don't want to waste CPU cycles when a thread has to wait a
+        while to acquire the lock.
+
+        The solution is to just implement a modern adaptive mutex in WTF. Luckily, this isn't a new
+        concept. This patch implements a mutex that is reminiscent of the kinds of low-overhead locks
+        that JVMs use. The actual implementation here is inspired by some of the ideas from [1]. The
+        idea is simple: the fast path is an inlined CAS to immediately acquire a lock that isn't held,
+        the slow path tries some number of spins to acquire the lock, and if that fails, the thread is
+        put on a queue and put to sleep. The queue is made up of statically allocated thread nodes and
+        the lock itself is a tagged pointer: either it is just bits telling us the complete lock state
+        (not held or held) or it is a pointer to the head of a queue of threads waiting to acquire the
+        lock. This approach gives WTF::Lock three different levels of adaptation: an inlined fast path
+        if the lock is not contended, a short burst of spinning for microcontention, and a full-blown
+        queue for critical sections that are held for a long time.
+
+        On a locking microbenchmark, this new Lock exhibits the following performance
+        characteristics:
+
+        - Lock+unlock on an uncontended no-op critical section: 2x slower than SpinLock and 3x faster
+          than a system mutex.
+
+        - Lock+unlock on a contended no-op critical section: 2x slower than SpinLock and 100x faster
+          than a system mutex.
+
+        - CPU time spent in lock() on a lock held for a while: same as system mutex, 90x less than a
+          SpinLock.
+
+        - Memory usage: sizeof(void*), so on 64-bit it's 8x less than a system mutex but 2x worse than
+          a SpinLock.
+
+        This patch replaces all uses of SpinLock with Lock, since our critical sections are not
+        no-ops so if you do basically anything in your critical section, the Lock overhead will be
+        invisible. Also, in all places where we used SpinLock, we could tolerate 8 bytes of overhead
+        instead of 4. Performance benchmarking using JSC macrobenchmarks shows no difference, which is
+        as it should be: the purpose of this change is to reduce CPU time wasted, not wallclock time.
+        This patch doesn't replace any uses of ByteSpinLock, since we expect that the space benefits
+        of having a lock that just uses a byte are still better than the CPU wastage benefits of
+        Lock. But, this work will enable some future work to create locks that will fit in just 1.6
+        bits: https://bugs.webkit.org/show_bug.cgi?id=147665.
+        
+        Rolling this back in after fixing Lock::unlockSlow() for architectures that have a truly weak
+        CAS. Since the Lock::unlock() fast path can go to slow path spuriously, it may go there even if
+        there aren't any threads on the Lock's queue. So, unlockSlow() must be able to deal with the
+        possibility of a null queue head.
+
+        [1] http://www.filpizlo.com/papers/pizlo-pppj2011-fable.pdf
+
+        * WTF.vcxproj/WTF.vcxproj:
+        * WTF.xcodeproj/project.pbxproj:
+        * benchmarks: Added.
+        * benchmarks/LockSpeedTest.cpp: Added.
+        (main):
+        * wtf/Atomics.h:
+        (WTF::Atomic::compareExchangeWeak):
+        (WTF::Atomic::compareExchangeStrong):
+        * wtf/CMakeLists.txt:
+        * wtf/Lock.cpp: Added.
+        (WTF::LockBase::lockSlow):
+        (WTF::LockBase::unlockSlow):
+        * wtf/Lock.h: Added.
+        (WTF::LockBase::lock):
+        (WTF::LockBase::unlock):
+        (WTF::LockBase::isHeld):
+        (WTF::LockBase::isLocked):
+        (WTF::Lock::Lock):
+        * wtf/MetaAllocator.cpp:
+        (WTF::MetaAllocator::release):
+        (WTF::MetaAllocatorHandle::shrink):
+        (WTF::MetaAllocator::allocate):
+        (WTF::MetaAllocator::currentStatistics):
+        (WTF::MetaAllocator::addFreshFreeSpace):
+        (WTF::MetaAllocator::debugFreeSpaceSize):
+        * wtf/MetaAllocator.h:
+        * wtf/SpinLock.h:
+        * wtf/ThreadingPthreads.cpp:
+        * wtf/ThreadingWin.cpp:
+        * wtf/text/AtomicString.cpp:
+        * wtf/text/AtomicStringImpl.cpp:
+        (WTF::AtomicStringTableLocker::AtomicStringTableLocker):
+
</ins><span class="cx"> 2015-08-05  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, roll out http://trac.webkit.org/changeset/187972.
</span></span></pre></div>
<a id="trunkSourceWTFWTFvcxprojWTFvcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/WTF.vcxproj/WTF.vcxproj        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</del><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</ins><span class="cx"> &lt;Project DefaultTargets=&quot;Build&quot; ToolsVersion=&quot;12.0&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;
</span><span class="cx">   &lt;ItemGroup Label=&quot;ProjectConfigurations&quot;&gt;
</span><span class="cx">     &lt;ProjectConfiguration Include=&quot;DebugSuffix|Win32&quot;&gt;
</span><span class="lines">@@ -106,6 +106,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\wtf\glib\GThreadSafeMainLoopSource.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\wtf\GregorianDateTime.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\wtf\HashTable.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\wtf\Lock.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\wtf\MainThread.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\wtf\MD5.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\wtf\MediaTime.cpp&quot; /&gt;
</span><span class="lines">@@ -223,6 +224,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\IteratorAdaptors.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\IteratorRange.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\ListHashSet.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\wtf\Lock.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\Locker.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\MainThread.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\wtf\MallocPtr.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceWTFWTFxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -40,6 +40,8 @@
</span><span class="cx">                 0FD81AC5154FB22E00983E72 /* FastBitVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD81AC4154FB22E00983E72 /* FastBitVector.h */; settings = {ATTRIBUTES = (); }; };
</span><span class="cx">                 0FDDBFA71666DFA300C55FEF /* StringPrintStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFA51666DFA300C55FEF /* StringPrintStream.cpp */; };
</span><span class="cx">                 0FDDBFA81666DFA300C55FEF /* StringPrintStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFA61666DFA300C55FEF /* StringPrintStream.h */; };
</span><ins>+                0FE1646A1B6FFC9600400E7C /* Lock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FE164681B6FFC9600400E7C /* Lock.cpp */; };
+                0FE1646B1B6FFC9600400E7C /* Lock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FE164691B6FFC9600400E7C /* Lock.h */; };
</ins><span class="cx">                 0FED67B61B22D4D80066CE15 /* TinyPtrSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FED67B51B22D4D80066CE15 /* TinyPtrSet.h */; };
</span><span class="cx">                 14022F4118F5C3FC007FF0EB /* libbmalloc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14022F4018F5C3FC007FF0EB /* libbmalloc.a */; };
</span><span class="cx">                 143F611F1565F0F900DB514A /* RAMSize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 143F611D1565F0F900DB514A /* RAMSize.cpp */; };
</span><span class="lines">@@ -321,6 +323,8 @@
</span><span class="cx">                 0FD81AC4154FB22E00983E72 /* FastBitVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FastBitVector.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDDBFA51666DFA300C55FEF /* StringPrintStream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StringPrintStream.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDDBFA61666DFA300C55FEF /* StringPrintStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringPrintStream.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FE164681B6FFC9600400E7C /* Lock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lock.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FE164691B6FFC9600400E7C /* Lock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lock.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FEC3EE4171B834700FDAC8D /* ByteSpinLock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ByteSpinLock.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FED67B51B22D4D80066CE15 /* TinyPtrSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TinyPtrSet.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 14022F4018F5C3FC007FF0EB /* libbmalloc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libbmalloc.a; sourceTree = BUILT_PRODUCTS_DIR; };
</span><span class="lines">@@ -770,6 +774,8 @@
</span><span class="cx">                                 7CDD7FF9186D2A54007433CD /* IteratorRange.h */,
</span><span class="cx">                                 A70DA0831799F04D00529A9B /* ListDump.h */,
</span><span class="cx">                                 A8A472C1151A825A004123FF /* ListHashSet.h */,
</span><ins>+                                0FE164681B6FFC9600400E7C /* Lock.cpp */,
+                                0FE164691B6FFC9600400E7C /* Lock.h */,
</ins><span class="cx">                                 A8A472C3151A825A004123FF /* Locker.h */,
</span><span class="cx">                                 1447AEC818FCE59400B3D7FF /* mbmalloc.cpp */,
</span><span class="cx">                                 A8A472CA151A825B004123FF /* MD5.cpp */,
</span><span class="lines">@@ -1206,6 +1212,7 @@
</span><span class="cx">                                 A8A4746A151A825B004123FF /* UTF8.h in Headers */,
</span><span class="cx">                                 A8A473B9151A825B004123FF /* utils.h in Headers */,
</span><span class="cx">                                 A8A4747D151A825B004123FF /* ValueCheck.h in Headers */,
</span><ins>+                                0FE1646B1B6FFC9600400E7C /* Lock.h in Headers */,
</ins><span class="cx">                                 A8A4747E151A825B004123FF /* Vector.h in Headers */,
</span><span class="cx">                                 A8A4747F151A825B004123FF /* VectorTraits.h in Headers */,
</span><span class="cx">                                 0FED67B61B22D4D80066CE15 /* TinyPtrSet.h in Headers */,
</span><span class="lines">@@ -1337,6 +1344,7 @@
</span><span class="cx">                                 A8A4739E151A825B004123FF /* DataLog.cpp in Sources */,
</span><span class="cx">                                 A8A473A0151A825B004123FF /* DateMath.cpp in Sources */,
</span><span class="cx">                                 A8A473A2151A825B004123FF /* DecimalNumber.cpp in Sources */,
</span><ins>+                                0FE1646A1B6FFC9600400E7C /* Lock.cpp in Sources */,
</ins><span class="cx">                                 A8A473AE151A825B004123FF /* diy-fp.cc in Sources */,
</span><span class="cx">                                 A8A473B0151A825B004123FF /* double-conversion.cc in Sources */,
</span><span class="cx">                                 A8A473BA151A825B004123FF /* dtoa.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceWTFbenchmarksLockSpeedTestcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WTF/benchmarks/LockSpeedTest.cpp (0 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/benchmarks/LockSpeedTest.cpp                                (rev 0)
+++ trunk/Source/WTF/benchmarks/LockSpeedTest.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -0,0 +1,137 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+
+#include &lt;unistd.h&gt;
+#include &lt;wtf/CurrentTime.h&gt;
+#include &lt;wtf/Lock.h&gt;
+#include &lt;wtf/SpinLock.h&gt;
+#include &lt;wtf/StdLibExtras.h&gt;
+#include &lt;wtf/Threading.h&gt;
+#include &lt;wtf/ThreadingPrimitives.h&gt;
+
+namespace {
+
+unsigned numThreadGroups;
+unsigned numThreadsPerGroup;
+unsigned workPerCriticalSection;
+unsigned numNoiseThreads;
+unsigned numIterations;
+    
+NO_RETURN void usage()
+{
+    printf(&quot;Usage: LockSpeedTest spinlock|lock|mutex|all &lt;num thread groups&gt; &lt;num threads per group&gt; &lt;work per critical section&gt; &lt;num noise threads&gt; &lt;num iterations&gt;\n&quot;);
+    exit(1);
+}
+
+template&lt;typename LockType&gt;
+void runBenchmark(const char* name)
+{
+    std::unique_ptr&lt;LockType[]&gt; locks = std::make_unique&lt;LockType[]&gt;(numThreadGroups);
+    std::unique_ptr&lt;double[]&gt; words = std::make_unique&lt;double[]&gt;(numThreadGroups);
+    std::unique_ptr&lt;ThreadIdentifier[]&gt; threads = std::make_unique&lt;ThreadIdentifier[]&gt;(numThreadGroups * numThreadsPerGroup);
+    std::unique_ptr&lt;ThreadIdentifier[]&gt; noiseThreads = std::make_unique&lt;ThreadIdentifier[]&gt;(numNoiseThreads);
+    std::unique_ptr&lt;double[]&gt; noiseCounts = std::make_unique&lt;double[]&gt;(numNoiseThreads);
+
+    volatile bool shouldStop = false;
+    for (unsigned threadIndex = numNoiseThreads; threadIndex--;) {
+        noiseCounts[threadIndex] = 0;
+        noiseThreads[threadIndex] = createThread(
+            &quot;Noise Thread&quot;,
+            [&amp;shouldStop, &amp;noiseCounts, threadIndex] () {
+                while (!shouldStop)
+                    noiseCounts[threadIndex]++;
+            });
+    }
+
+    double before = monotonicallyIncreasingTimeMS();
+    
+    for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
+        words[threadGroupIndex] = 0;
+
+        for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
+            threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = createThread(
+                &quot;Benchmark thread&quot;,
+                [threadGroupIndex, &amp;locks, &amp;words] () {
+                    for (unsigned i = numIterations; i--;) {
+                        locks[threadGroupIndex].lock();
+                        for (unsigned j = workPerCriticalSection; j--;) {
+                            words[threadGroupIndex]++;
+                            words[threadGroupIndex] *= 1.01;
+                        }
+                        locks[threadGroupIndex].unlock();
+                    }
+                });
+        }
+    }
+
+    for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
+        waitForThreadCompletion(threads[threadIndex]);
+    shouldStop = true;
+    double noiseCount = 0;
+    for (unsigned threadIndex = numNoiseThreads; threadIndex--;) {
+        waitForThreadCompletion(noiseThreads[threadIndex]);
+        noiseCount += noiseCounts[threadIndex];
+    }
+
+    double after = monotonicallyIncreasingTimeMS();
+
+    printf(&quot;%s: %.3lf ms, %.0lf noise.\n&quot;, name, after - before, noiseCount);
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv)
+{
+    WTF::initializeThreading();
+    
+    if (argc != 7
+        || sscanf(argv[2], &quot;%u&quot;, &amp;numThreadGroups) != 1
+        || sscanf(argv[3], &quot;%u&quot;, &amp;numThreadsPerGroup) != 1
+        || sscanf(argv[4], &quot;%u&quot;, &amp;workPerCriticalSection) != 1
+        || sscanf(argv[5], &quot;%u&quot;, &amp;numNoiseThreads) != 1
+        || sscanf(argv[6], &quot;%u&quot;, &amp;numIterations) != 1)
+        usage();
+
+    bool didRun = false;
+    if (!strcmp(argv[1], &quot;spinlock&quot;) || !strcmp(argv[1], &quot;all&quot;)) {
+        runBenchmark&lt;SpinLock&gt;(&quot;SpinLock&quot;);
+        didRun = true;
+    }
+    if (!strcmp(argv[1], &quot;lock&quot;) || !strcmp(argv[1], &quot;all&quot;)) {
+        runBenchmark&lt;Lock&gt;(&quot;WTF Lock&quot;);
+        didRun = true;
+    }
+    if (!strcmp(argv[1], &quot;mutex&quot;) || !strcmp(argv[1], &quot;all&quot;)) {
+        runBenchmark&lt;Mutex&gt;(&quot;Platform Mutex&quot;);
+        didRun = true;
+    }
+
+    if (!didRun)
+        usage();
+
+    return 0;
+}
</ins></span></pre></div>
<a id="trunkSourceWTFwtfAtomicsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Atomics.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Atomics.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/Atomics.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -91,12 +91,21 @@
</span><span class="cx"> 
</span><span class="cx">     bool compareExchangeWeak(T expected, T desired, std::memory_order order = std::memory_order_seq_cst)
</span><span class="cx">     {
</span><ins>+#if OS(WINDOWS)
+        // Windows makes strange assertions about the argument to compare_exchange_weak, and anyway,
+        // Windows is X86 so seq_cst is cheap.
+        order = std::memory_order_seq_cst;
+#endif
</ins><span class="cx">         T expectedOrActual = expected;
</span><span class="cx">         return value.compare_exchange_weak(expectedOrActual, desired, order);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     bool compareExchangeStrong(T expected, T desired, std::memory_order order = std::memory_order_seq_cst)
</span><span class="cx">     {
</span><ins>+#if OS(WINDOWS)
+        // See above.
+        order = std::memory_order_seq_cst;
+#endif
</ins><span class="cx">         T expectedOrActual = expected;
</span><span class="cx">         return value.compare_exchange_strong(expectedOrActual, desired, order);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWTFwtfCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/CMakeLists.txt (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/CMakeLists.txt        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/CMakeLists.txt        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx">     IteratorAdaptors.h
</span><span class="cx">     IteratorRange.h
</span><span class="cx">     ListHashSet.h
</span><ins>+    Lock.h
</ins><span class="cx">     Locker.h
</span><span class="cx">     MD5.h
</span><span class="cx">     MainThread.h
</span><span class="lines">@@ -156,6 +157,7 @@
</span><span class="cx">     FunctionDispatcher.cpp
</span><span class="cx">     GregorianDateTime.cpp
</span><span class="cx">     HashTable.cpp
</span><ins>+    Lock.cpp
</ins><span class="cx">     MD5.cpp
</span><span class="cx">     MainThread.cpp
</span><span class="cx">     MediaTime.cpp
</span></span></pre></div>
<a id="trunkSourceWTFwtfLockcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/WTF/wtf/Lock.cpp (0 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Lock.cpp                                (rev 0)
+++ trunk/Source/WTF/wtf/Lock.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -0,0 +1,269 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;Lock.h&quot;
+
+#include &quot;DataLog.h&quot;
+#include &quot;StringPrintStream.h&quot;
+#include &quot;ThreadSpecific.h&quot;
+#include &quot;ThreadingPrimitives.h&quot;
+#include &lt;condition_variable&gt;
+#include &lt;mutex&gt;
+#include &lt;thread&gt;
+
+namespace WTF {
+
+namespace {
+
+// This data structure serves three purposes:
+//
+// 1) A parking mechanism for threads that go to sleep. That involves just a system mutex and
+//    condition variable.
+//
+// 2) A queue node for when a thread is on some Lock's queue.
+//
+// 3) The queue head. This is kind of funky. When a thread is the head of a queue, it also serves as
+//    the basic queue bookkeeping data structure. When a thread is dequeued, the next thread in the
+//    queue takes on the queue head duties.
+struct ThreadData {
+    // The parking mechanism.
+    bool shouldPark { false };
+    std::mutex parkingLock;
+    std::condition_variable parkingCondition;
+
+    // The queue node.
+    ThreadData* nextInQueue { nullptr };
+
+    // The queue itself.
+    ThreadData* queueTail { nullptr };
+};
+
+ThreadSpecific&lt;ThreadData&gt;* threadData;
+
+ThreadData* myThreadData()
+{
+    static std::once_flag initializeOnce;
+    std::call_once(
+        initializeOnce,
+        [] {
+            threadData = new ThreadSpecific&lt;ThreadData&gt;();
+        });
+
+    return *threadData;
+}
+
+} // anonymous namespace
+
+void LockBase::lockSlow()
+{
+    unsigned spinCount = 0;
+
+    // This magic number turns out to be optimal based on past JikesRVM experiments.
+    const unsigned spinLimit = 40;
+    
+    for (;;) {
+        uintptr_t currentWordValue = m_word.load();
+        
+        if (!(currentWordValue &amp; isLockedBit)) {
+            // It's not possible for someone to hold the queue lock while the lock itself is no longer
+            // held, since we will only attempt to acquire the queue lock when the lock is held and
+            // the queue lock prevents unlock.
+            ASSERT(!(currentWordValue &amp; isQueueLockedBit));
+            if (m_word.compareExchangeWeak(currentWordValue, currentWordValue | isLockedBit)) {
+                // Success! We acquired the lock.
+                return;
+            }
+        }
+
+        // If there is no queue and we haven't spun too much, we can just try to spin around again.
+        if (!(currentWordValue &amp; ~queueHeadMask) &amp;&amp; spinCount &lt; spinLimit) {
+            spinCount++;
+            std::this_thread::yield();
+            continue;
+        }
+
+        // Need to put ourselves on the queue. Create the queue if one does not exist. This requries
+        // owning the queue for a little bit. The lock that controls the queue is itself a spinlock.
+        // But before we acquire the queue spinlock, we make sure that we have a ThreadData for this
+        // thread.
+        ThreadData* me = myThreadData();
+        ASSERT(!me-&gt;shouldPark);
+        ASSERT(!me-&gt;nextInQueue);
+        ASSERT(!me-&gt;queueTail);
+
+        // Reload the current word value, since some time may have passed.
+        currentWordValue = m_word.load();
+
+        // We proceed only if the queue lock is not held, the Lock is held, and we succeed in
+        // acquiring the queue lock.
+        if ((currentWordValue &amp; isQueueLockedBit)
+            || !(currentWordValue &amp; isLockedBit)
+            || !m_word.compareExchangeWeak(currentWordValue, currentWordValue | isQueueLockedBit)) {
+            std::this_thread::yield();
+            continue;
+        }
+        
+        me-&gt;shouldPark = true;
+
+        // We own the queue. Nobody can enqueue or dequeue until we're done. Also, it's not possible
+        // to release the Lock while we hold the queue lock.
+        ThreadData* queueHead = bitwise_cast&lt;ThreadData*&gt;(currentWordValue &amp; ~queueHeadMask);
+        if (queueHead) {
+            // Put this thread at the end of the queue.
+            queueHead-&gt;queueTail-&gt;nextInQueue = me;
+            queueHead-&gt;queueTail = me;
+
+            // Release the queue lock.
+            currentWordValue = m_word.load();
+            ASSERT(currentWordValue &amp; ~queueHeadMask);
+            ASSERT(currentWordValue &amp; isQueueLockedBit);
+            ASSERT(currentWordValue &amp; isLockedBit);
+            m_word.store(currentWordValue &amp; ~isQueueLockedBit);
+        } else {
+            // Make this thread be the queue-head.
+            queueHead = me;
+            me-&gt;queueTail = me;
+
+            // Release the queue lock and install ourselves as the head. No need for a CAS loop, since
+            // we own the queue lock.
+            currentWordValue = m_word.load();
+            ASSERT(~(currentWordValue &amp; ~queueHeadMask));
+            ASSERT(currentWordValue &amp; isQueueLockedBit);
+            ASSERT(currentWordValue &amp; isLockedBit);
+            uintptr_t newWordValue = currentWordValue;
+            newWordValue |= bitwise_cast&lt;uintptr_t&gt;(queueHead);
+            newWordValue &amp;= ~isQueueLockedBit;
+            m_word.store(newWordValue);
+        }
+
+        // At this point everyone who acquires the queue lock will see me on the queue, and anyone who
+        // acquires me's lock will see that me wants to park. Note that shouldPark may have been
+        // cleared as soon as the queue lock was released above, but it will happen while the
+        // releasing thread holds me's parkingLock.
+
+        {
+            std::unique_lock&lt;std::mutex&gt; locker(me-&gt;parkingLock);
+            while (me-&gt;shouldPark)
+                me-&gt;parkingCondition.wait(locker);
+        }
+
+        ASSERT(!me-&gt;shouldPark);
+        ASSERT(!me-&gt;nextInQueue);
+        ASSERT(!me-&gt;queueTail);
+        
+        // Now we can loop around and try to acquire the lock again.
+    }
+}
+
+void LockBase::unlockSlow()
+{
+    // The fast path can fail either because of spurious weak CAS failure, or because someone put a
+    // thread on the queue, or the queue lock is held. If the queue lock is held, it can only be
+    // because someone *will* enqueue a thread onto the queue.
+
+    // Acquire the queue lock, or release the lock. This loop handles both lock release in case the
+    // fast path's weak CAS spuriously failed and it handles queue lock acquisition if there is
+    // actually something interesting on the queue.
+    for (;;) {
+        uintptr_t currentWordValue = m_word.load();
+
+        ASSERT(currentWordValue &amp; isLockedBit);
+        
+        if (currentWordValue == isLockedBit) {
+            if (m_word.compareExchangeWeak(isLockedBit, 0)) {
+                // The fast path's weak CAS had spuriously failed, and now we succeeded. The lock is
+                // unlocked and we're done!
+                return;
+            }
+            // Loop around and try again.
+            std::this_thread::yield();
+            continue;
+        }
+        
+        if (currentWordValue &amp; isQueueLockedBit) {
+            std::this_thread::yield();
+            continue;
+        }
+
+        // If it wasn't just a spurious weak CAS failure and if the queue lock is not held, then there
+        // must be an entry on the queue.
+        ASSERT(currentWordValue &amp; ~queueHeadMask);
+
+        if (m_word.compareExchangeWeak(currentWordValue, currentWordValue | isQueueLockedBit))
+            break;
+    }
+
+    uintptr_t currentWordValue = m_word.load();
+        
+    // After we acquire the queue lock, the Lock must still be held and the queue must be
+    // non-empty. The queue must be non-empty since only the lockSlow() method could have held the
+    // queue lock and if it did then it only releases it after putting something on the queue.
+    ASSERT(currentWordValue &amp; isLockedBit);
+    ASSERT(currentWordValue &amp; isQueueLockedBit);
+    ThreadData* queueHead = bitwise_cast&lt;ThreadData*&gt;(currentWordValue &amp; ~queueHeadMask);
+    ASSERT(queueHead);
+
+    ThreadData* newQueueHead = queueHead-&gt;nextInQueue;
+    // Either this was the only thread on the queue, in which case we delete the queue, or there
+    // are still more threads on the queue, in which case we create a new queue head.
+    if (newQueueHead)
+        newQueueHead-&gt;queueTail = queueHead-&gt;queueTail;
+
+    // Change the queue head, possibly removing it if newQueueHead is null. No need for a CAS loop,
+    // since we hold the queue lock and the lock itself so nothing about the lock can change right
+    // now.
+    currentWordValue = m_word.load();
+    ASSERT(currentWordValue &amp; isLockedBit);
+    ASSERT(currentWordValue &amp; isQueueLockedBit);
+    ASSERT((currentWordValue &amp; ~queueHeadMask) == bitwise_cast&lt;uintptr_t&gt;(queueHead));
+    uintptr_t newWordValue = currentWordValue;
+    newWordValue &amp;= ~isLockedBit; // Release the Lock.
+    newWordValue &amp;= ~isQueueLockedBit; // Release the queue lock.
+    newWordValue &amp;= queueHeadMask; // Clear out the old queue head.
+    newWordValue |= bitwise_cast&lt;uintptr_t&gt;(newQueueHead); // Install new queue head.
+    m_word.store(newWordValue);
+
+    // Now the lock is available for acquisition. But we just have to wake up the old queue head.
+    // After that, we're done!
+
+    queueHead-&gt;nextInQueue = nullptr;
+    queueHead-&gt;queueTail = nullptr;
+
+    // We do this carefully because this may run either before or during the parkingLock critical
+    // section in lockSlow().
+    {
+        std::unique_lock&lt;std::mutex&gt; locker(queueHead-&gt;parkingLock);
+        queueHead-&gt;shouldPark = false;
+    }
+    // Doesn't matter if we notify_all() or notify_one() here since the only thread that could be
+    // waiting is queueHead.
+    queueHead-&gt;parkingCondition.notify_one();
+
+    // The old queue head can now contend for the lock again. We're done!
+}
+
+} // namespace WTF
+
</ins></span></pre></div>
<a id="trunkSourceWTFwtfLockh"></a>
<div class="addfile"><h4>Added: trunk/Source/WTF/wtf/Lock.h (0 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Lock.h                                (rev 0)
+++ trunk/Source/WTF/wtf/Lock.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -0,0 +1,168 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef WTF_Lock_h
+#define WTF_Lock_h
+
+#include &lt;wtf/Atomics.h&gt;
+#include &lt;wtf/Compiler.h&gt;
+#include &lt;wtf/Locker.h&gt;
+#include &lt;wtf/Noncopyable.h&gt;
+
+namespace WTF {
+
+// A Lock is a fully adaptive mutex that gives you the best of SpinLock and Mutex. For small critical
+// sections (that take nanoseconds), it will usually perform within 2x of a SpinLock in both the
+// contended and uncontended case. When using a Mutex, such critical sections take up to 100x longer
+// than Lock in the contended case, or 3x longer than Lock in the uncontended case. For longer
+// critical sections (that take tens of microseconds), it will perform as well as a Mutex and slightly
+// better than a SpinLock. But, crucially, a SpinLock will burn up to 90x more time in the kernel for
+// such critical sections than either Lock or Mutex. Hence, using Lock will make the common case of
+// locking perform close to SpinLock for any critical section that does more than a few nanoseconds of
+// work while being as kind to the scheduler for longer critical sections as a Mutex.
+//
+// Like SpinLock, Lock takes very little memory - just sizeof(void*), though see a detailed caveat
+// below.
+//
+// Generally, you should use Lock instead of SpinLock because while it penalizes you slightly, you
+// make up for it by not wasting CPU cycles in case of contention.
+//
+// The Lock has the following nice properties:
+//
+// - Uncontended fast paths for lock acquisition and lock release that are almost as fast as the
+//   uncontended fast paths of a spinlock. The only overhead is that the spinlock will not CAS on
+//   release, while Lock will CAS. This overhead *can* slow things down for extremely small critical
+//   sections that do little or nothing - it makes them 2x slower since in that case, CAS is the most
+//   expensive instruction and having two of them is twice as bad as just having one. However, this
+//   lock implementation is still almost 3x faster than a platform mutex in those cases. It's unlikely
+//   that you'll encounter no-op critical sections, so usually, this lock is better than a spinlock.
+//
+// - Contended fast path that attempts to spin and yield for some number of times. For critical
+//   sections that are held only briefly, this allows Lock to perform almost as well as a SpinLock.
+//   SpinLock can still be almost 2x faster than Lock if the critical section is a no-op, but this
+//   advantage diminishes as the critical section grows.
+//
+// - Contended slow path that enqueues the contending thread and causes it to wait on a condition
+//   variable until the lock is released. This is the only case in which system mutexes and condition
+//   variables are used. This case is rare and self-limiting: it will only happen when a lock is held
+//   for long enough that spinning some number of times doesn't acquire it. The fact that Lock does
+//   this as a fallback when spinning for some number of times fails means that it will burn
+//   dramatically fewer CPU cycles - for example with 10 threads on an 8 logical CPU machine acquiring
+//   a critical section that takes 50 microseconds, the WTF SpinLock will cause 90x more time to be
+//   spent in the kernel than Lock.
+//
+// - Very low memory usage. Each Lock requires only sizeof(void*) memory. When the contended slow
+//   path is activated, Lock only relies on each thread having a preallocated thread-specific data
+//   structure called ThreadData that, together with the Lock itself, is used to build up a thread
+//   queue. So, the total memory usage of all Locks is still bounded by:
+//
+//       numberOfLocks * sizeof(void*) + numberOfThreads * sizeof(ThreadData)
+//
+//   Where ThreadData is a decently large data structure, but we will only ever have one per thread,
+//   regardless of the number of Locks in memory. Another way to view this is that the worst case
+//   memory usage per Lock is:
+//
+//       sizeof(void*) + numberOfThreads / numberOfLocks * sizeof(ThreadData)
+//
+//   So, unless you have a small number of Locks (or, a large number of threads, which is far less
+//   likely), the memory usage per-Lock is still going to be somewhere around sizeof(void*).
+//
+// - Barging fast paths. The Lock is tuned for maximum throughput rather than maximum fairness. If
+//   a thread releases a Lock that was contended and had a queue of waiting threads, then it will
+//   wake up the head of the queue, but it will also mark the lock as being available. This means that
+//   some other thread that is just now attempting to acquire the lock may get it before the thread
+//   that got woken up. When a thread barges into the lock, the thread that got woken up will simply
+//   go back to the end of the queue. The barging behavior ends up being probabilistic on most
+//   platforms and even though it may be unfair to some thread at some moment in time, it will rarely
+//   have a long streak of unfairness towards any particular thread: eventually each thread waiting on
+//   the lock will get to have a turn so long as no thread just holds the lock forever. That said,
+//   there *is* a chance of pathologies - users of Lock should not depend on first-in, first-out lock
+//   acquisition order under contention. The same caveat is generally true of SpinLock and platform
+//   mutexes on some platforms.
+
+// This is a struct without a constructor or destructor so that it can be statically initialized.
+// Use Lock in instance variables.
+struct LockBase {
+    void lock()
+    {
+        if (LIKELY(m_word.compareExchangeWeak(0, isLockedBit, std::memory_order_acquire))) {
+            // Lock acquired!
+            return;
+        }
+
+        lockSlow();
+    }
+
+    void unlock()
+    {
+        if (LIKELY(m_word.compareExchangeWeak(isLockedBit, 0, std::memory_order_release))) {
+            // Lock released, and nobody was waiting!
+            return;
+        }
+
+        unlockSlow();
+    }
+
+    bool isHeld() const
+    {
+        return m_word.load(std::memory_order_acquire) &amp; isLockedBit;
+    }
+
+    bool isLocked() const
+    {
+        return isHeld();
+    }
+
+protected:
+    static const uintptr_t isLockedBit = 1;
+    static const uintptr_t isQueueLockedBit = 2;
+    static const uintptr_t queueHeadMask = 3;
+
+    WTF_EXPORT_PRIVATE void lockSlow();
+    WTF_EXPORT_PRIVATE void unlockSlow();
+
+    Atomic&lt;uintptr_t&gt; m_word;
+};
+
+class Lock : public LockBase {
+    WTF_MAKE_NONCOPYABLE(Lock);
+public:
+    Lock()
+    {
+        m_word.store(0, std::memory_order_relaxed);
+    }
+};
+
+typedef LockBase StaticLock;
+typedef Locker&lt;LockBase&gt; LockHolder;
+
+} // namespace WTF
+
+using WTF::StaticLock;
+using WTF::Lock;
+using WTF::LockHolder;
+
+#endif // WTF_Lock_h
+
</ins></span></pre></div>
<a id="trunkSourceWTFwtfMetaAllocatorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/MetaAllocator.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/MetaAllocator.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/MetaAllocator.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE void MetaAllocator::release(MetaAllocatorHandle* handle)
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;m_lock);
</del><ins>+    LockHolder locker(&amp;m_lock);
</ins><span class="cx">     if (handle-&gt;sizeInBytes()) {
</span><span class="cx">         decrementPageOccupancy(handle-&gt;start(), handle-&gt;sizeInBytes());
</span><span class="cx">         addFreeSpaceFromReleasedHandle(handle-&gt;start(), handle-&gt;sizeInBytes());
</span><span class="lines">@@ -91,7 +91,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(newSizeInBytes &lt;= m_sizeInBytes);
</span><span class="cx">     
</span><del>-    SpinLockHolder locker(&amp;m_allocator-&gt;m_lock);
</del><ins>+    LockHolder locker(&amp;m_allocator-&gt;m_lock);
</ins><span class="cx"> 
</span><span class="cx">     newSizeInBytes = m_allocator-&gt;roundUp(newSizeInBytes);
</span><span class="cx">     
</span><span class="lines">@@ -150,7 +150,7 @@
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;MetaAllocatorHandle&gt; MetaAllocator::allocate(size_t sizeInBytes, void* ownerUID)
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;m_lock);
</del><ins>+    LockHolder locker(&amp;m_lock);
</ins><span class="cx"> 
</span><span class="cx">     if (!sizeInBytes)
</span><span class="cx">         return 0;
</span><span class="lines">@@ -196,7 +196,7 @@
</span><span class="cx"> 
</span><span class="cx"> MetaAllocator::Statistics MetaAllocator::currentStatistics()
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;m_lock);
</del><ins>+    LockHolder locker(&amp;m_lock);
</ins><span class="cx">     Statistics result;
</span><span class="cx">     result.bytesAllocated = m_bytesAllocated;
</span><span class="cx">     result.bytesReserved = m_bytesReserved;
</span><span class="lines">@@ -281,7 +281,7 @@
</span><span class="cx"> 
</span><span class="cx"> void MetaAllocator::addFreshFreeSpace(void* start, size_t sizeInBytes)
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;m_lock);
</del><ins>+    LockHolder locker(&amp;m_lock);
</ins><span class="cx">     m_bytesReserved += sizeInBytes;
</span><span class="cx">     addFreeSpace(start, sizeInBytes);
</span><span class="cx"> }
</span><span class="lines">@@ -289,7 +289,7 @@
</span><span class="cx"> size_t MetaAllocator::debugFreeSpaceSize()
</span><span class="cx"> {
</span><span class="cx"> #ifndef NDEBUG
</span><del>-    SpinLockHolder locker(&amp;m_lock);
</del><ins>+    LockHolder locker(&amp;m_lock);
</ins><span class="cx">     size_t result = 0;
</span><span class="cx">     for (FreeSpaceNode* node = m_freeSpaceSizeMap.first(); node; node = node-&gt;successor())
</span><span class="cx">         result += node-&gt;m_sizeInBytes;
</span></span></pre></div>
<a id="trunkSourceWTFwtfMetaAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/MetaAllocator.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/MetaAllocator.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/MetaAllocator.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -31,13 +31,13 @@
</span><span class="cx"> 
</span><span class="cx"> #include &lt;wtf/Assertions.h&gt;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/MetaAllocatorHandle.h&gt;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="cx"> #include &lt;wtf/PageBlock.h&gt;
</span><span class="cx"> #include &lt;wtf/RedBlackTree.h&gt;
</span><span class="cx"> #include &lt;wtf/RefCounted.h&gt;
</span><span class="cx"> #include &lt;wtf/RefPtr.h&gt;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><span class="lines">@@ -183,7 +183,7 @@
</span><span class="cx">     size_t m_bytesReserved;
</span><span class="cx">     size_t m_bytesCommitted;
</span><span class="cx">     
</span><del>-    SpinLock m_lock;
</del><ins>+    Lock m_lock;
</ins><span class="cx"> 
</span><span class="cx">     MetaAllocatorTracker* m_tracker;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtfSpinLockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/SpinLock.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/SpinLock.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/SpinLock.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -32,6 +32,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><ins>+// SpinLock is a very simple lock implementation that has extremely fast lock/unlock for very small
+// uncontended critical sections. However, it will exhibit bad performance degradation when the lock
+// becomes contended: the thread trying to acquire the lock will simply waste CPU cycles.
+//
+// For most (all?) locking use cases, it's better to use Lock (see wtf/Lock.h). That uses only a bit
+// more memory (8 bytes instead of 4 on 64-bit), and is only a bit slower in the uncontended case
+// (Lock needs CAS to unlock, while SpinLock doesn't), but will burn a lot less CPU time - for 10
+// threads acquiring a 50 microsecond critical section, Lock will use up to 100x less kernel CPU time
+// than SpinLock.
+
</ins><span class="cx"> // SpinLockBase is a struct without an explicitly defined constructors so that
</span><span class="cx"> // it can be initialized at compile time. See StaticSpinLock below.
</span><span class="cx"> struct SpinLockBase {
</span></span></pre></div>
<a id="trunkSourceWTFwtfThreadingPthreadscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/ThreadingPthreads.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/ThreadingPthreads.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/ThreadingPthreads.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2007, 2009, 2015 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
</span><span class="cx">  * Copyright (C) 2011 Research In Motion Limited. All rights reserved.
</span><span class="cx">  *
</span></span></pre></div>
<a id="trunkSourceWTFwtfThreadingWincpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/ThreadingWin.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/ThreadingWin.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/ThreadingWin.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2007, 2008, 2015 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2009 Google Inc. All rights reserved.
</span><span class="cx">  * Copyright (C) 2009 Torch Mobile, Inc. All rights reserved.
</span><span class="cx">  *
</span></span></pre></div>
<a id="trunkSourceWTFwtftextAtomicStringcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/AtomicString.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/AtomicString.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/text/AtomicString.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> #include &quot;dtoa.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #if USE(WEB_THREAD)
</span><del>-#include &quot;SpinLock.h&quot;
</del><ins>+#include &quot;Lock.h&quot;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceWTFwtftextAtomicStringImplcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/text/AtomicStringImpl.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/text/AtomicStringImpl.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WTF/wtf/text/AtomicStringImpl.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> #include &lt;wtf/unicode/UTF8.h&gt;
</span><span class="cx"> 
</span><span class="cx"> #if USE(WEB_THREAD)
</span><del>-#include &quot;SpinLock.h&quot;
</del><ins>+#include &quot;Lock.h&quot;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="lines">@@ -42,18 +42,18 @@
</span><span class="cx"> 
</span><span class="cx"> #if USE(WEB_THREAD)
</span><span class="cx"> 
</span><del>-class AtomicStringTableLocker : public SpinLockHolder {
</del><ins>+class AtomicStringTableLocker : public LockHolder {
</ins><span class="cx">     WTF_MAKE_NONCOPYABLE(AtomicStringTableLocker);
</span><span class="cx"> 
</span><del>-    static StaticSpinLock s_stringTableLock;
</del><ins>+    static StaticLock s_stringTableLock;
</ins><span class="cx"> public:
</span><span class="cx">     AtomicStringTableLocker()
</span><del>-        : SpinLockHolder(&amp;s_stringTableLock)
</del><ins>+        : LockHolder(&amp;s_stringTableLock)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-StaticSpinLock AtomicStringTableLocker::s_stringTableLock;
</del><ins>+StaticLock AtomicStringTableLocker::s_stringTableLock;
</ins><span class="cx"> 
</span><span class="cx"> #else
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebCore/ChangeLog        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2015-08-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Lightweight locks should be adaptive
+        https://bugs.webkit.org/show_bug.cgi?id=147545
+
+        Reviewed by Geoffrey Garen.
+
+        * bindings/objc/WebScriptObject.mm:
+        (WebCore::getJSWrapper):
+        (WebCore::addJSWrapper):
+        (WebCore::removeJSWrapper):
+        (WebCore::removeJSWrapperIfRetainCountOne):
+        * platform/audio/mac/CARingBuffer.cpp:
+        (WebCore::CARingBuffer::setCurrentFrameBounds):
+        (WebCore::CARingBuffer::getCurrentFrameBounds):
+        * platform/audio/mac/CARingBuffer.h:
+        * platform/ios/wak/WAKWindow.mm:
+        (-[WAKWindow setExposedScrollViewRect:]):
+        (-[WAKWindow exposedScrollViewRect]):
+
</ins><span class="cx"> 2015-08-07  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Post-review comments on r188146
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsobjcWebScriptObjectmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/objc/WebScriptObject.mm (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/objc/WebScriptObject.mm        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebCore/bindings/objc/WebScriptObject.mm        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx"> #import &lt;runtime/JSLock.h&gt;
</span><span class="cx"> #import &lt;runtime/Completion.h&gt;
</span><span class="cx"> #import &lt;runtime/Completion.h&gt;
</span><del>-#import &lt;wtf/SpinLock.h&gt;
</del><ins>+#import &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #import &lt;wtf/Threading.h&gt;
</span><span class="cx"> #import &lt;wtf/spi/cocoa/NSMapTableSPI.h&gt;
</span><span class="cx"> #import &lt;wtf/text/WTFString.h&gt;
</span><span class="lines">@@ -72,12 +72,12 @@
</span><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> static NSMapTable* JSWrapperCache;
</span><del>-static StaticSpinLock spinLock;
</del><ins>+static StaticLock spinLock;
</ins><span class="cx"> 
</span><span class="cx"> NSObject* getJSWrapper(JSObject* impl)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><del>-    SpinLockHolder holder(&amp;spinLock);
</del><ins>+    LockHolder holder(&amp;spinLock);
</ins><span class="cx"> 
</span><span class="cx">     if (!JSWrapperCache)
</span><span class="cx">         return nil;
</span><span class="lines">@@ -88,7 +88,7 @@
</span><span class="cx"> void addJSWrapper(NSObject* wrapper, JSObject* impl)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isMainThread());
</span><del>-    SpinLockHolder holder(&amp;spinLock);
</del><ins>+    LockHolder holder(&amp;spinLock);
</ins><span class="cx"> 
</span><span class="cx">     if (!JSWrapperCache)
</span><span class="cx">         JSWrapperCache = createWrapperCache();
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx"> 
</span><span class="cx"> void removeJSWrapper(JSObject* impl)
</span><span class="cx"> {
</span><del>-    SpinLockHolder holder(&amp;spinLock);
</del><ins>+    LockHolder holder(&amp;spinLock);
</ins><span class="cx"> 
</span><span class="cx">     if (!JSWrapperCache)
</span><span class="cx">         return;
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx"> 
</span><span class="cx"> static void removeJSWrapperIfRetainCountOne(NSObject* wrapper, JSObject* impl)
</span><span class="cx"> {
</span><del>-    SpinLockHolder holder(&amp;spinLock);
</del><ins>+    LockHolder holder(&amp;spinLock);
</ins><span class="cx"> 
</span><span class="cx">     if (!JSWrapperCache)
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacCARingBuffercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/CARingBuffer.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/CARingBuffer.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebCore/platform/audio/mac/CARingBuffer.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -200,7 +200,7 @@
</span><span class="cx"> 
</span><span class="cx"> void CARingBuffer::setCurrentFrameBounds(uint64_t startTime, uint64_t endTime)
</span><span class="cx"> {
</span><del>-    ByteSpinLocker locker(m_currentFrameBoundsLock);
</del><ins>+    LockHolder locker(m_currentFrameBoundsLock);
</ins><span class="cx">     uint32_t nextPtr = m_timeBoundsQueuePtr + 1;
</span><span class="cx">     uint32_t index = nextPtr &amp; kGeneralRingTimeBoundsQueueMask;
</span><span class="cx"> 
</span><span class="lines">@@ -212,7 +212,7 @@
</span><span class="cx"> 
</span><span class="cx"> void CARingBuffer::getCurrentFrameBounds(uint64_t &amp;startTime, uint64_t &amp;endTime)
</span><span class="cx"> {
</span><del>-    ByteSpinLocker locker(m_currentFrameBoundsLock);
</del><ins>+    LockHolder locker(m_currentFrameBoundsLock);
</ins><span class="cx">     uint32_t curPtr = m_timeBoundsQueuePtr;
</span><span class="cx">     uint32_t index = curPtr &amp; kGeneralRingTimeBoundsQueueMask;
</span><span class="cx">     CARingBuffer::TimeBounds&amp; bounds = m_timeBoundsQueue[index];
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformaudiomacCARingBufferh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/audio/mac/CARingBuffer.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/audio/mac/CARingBuffer.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebCore/platform/audio/mac/CARingBuffer.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -29,7 +29,7 @@
</span><span class="cx"> #if ENABLE(WEB_AUDIO) &amp;&amp; USE(MEDIATOOLBOX)
</span><span class="cx"> 
</span><span class="cx"> #include &lt;runtime/ArrayBuffer.h&gt;
</span><del>-#include &lt;wtf/ByteSpinLock.h&gt;
</del><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><span class="cx"> typedef struct AudioBufferList AudioBufferList;
</span><span class="lines">@@ -84,7 +84,7 @@
</span><span class="cx">     };
</span><span class="cx">     
</span><span class="cx">     Vector&lt;TimeBounds&gt; m_timeBoundsQueue;
</span><del>-    ByteSpinLock m_currentFrameBoundsLock;
</del><ins>+    Lock m_currentFrameBoundsLock;
</ins><span class="cx">     int32_t m_timeBoundsQueuePtr;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformioswakWAKWindowmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ios/wak/WAKWindow.mm (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ios/wak/WAKWindow.mm        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebCore/platform/ios/wak/WAKWindow.mm        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> #import &quot;WKContentObservation.h&quot;
</span><span class="cx"> #import &quot;WKViewPrivate.h&quot;
</span><span class="cx"> #import &lt;QuartzCore/QuartzCore.h&gt;
</span><del>-#import &lt;wtf/SpinLock.h&gt;
</del><ins>+#import &lt;wtf/Lock.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> WEBCORE_EXPORT NSString * const WAKWindowScreenScaleDidChangeNotification = @&quot;WAKWindowScreenScaleDidChangeNotification&quot;;
</span><span class="cx"> WEBCORE_EXPORT NSString * const WAKWindowVisibilityDidChangeNotification = @&quot;WAKWindowVisibilityDidChangeNotification&quot;;
</span><span class="lines">@@ -56,7 +56,7 @@
</span><span class="cx"> static id&lt;OrientationProvider&gt; gOrientationProvider;
</span><span class="cx"> 
</span><span class="cx"> @implementation WAKWindow {
</span><del>-    SpinLock _exposedScrollViewRectLock;
</del><ins>+    Lock _exposedScrollViewRectLock;
</ins><span class="cx">     CGRect _exposedScrollViewRect;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -358,14 +358,14 @@
</span><span class="cx"> 
</span><span class="cx"> - (void)setExposedScrollViewRect:(CGRect)exposedScrollViewRect
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;_exposedScrollViewRectLock);
</del><ins>+    LockHolder locker(&amp;_exposedScrollViewRectLock);
</ins><span class="cx">     _exposedScrollViewRect = exposedScrollViewRect;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (CGRect)exposedScrollViewRect
</span><span class="cx"> {
</span><span class="cx">     {
</span><del>-        SpinLockHolder locker(&amp;_exposedScrollViewRectLock);
</del><ins>+        LockHolder locker(&amp;_exposedScrollViewRectLock);
</ins><span class="cx">         if (!CGRectIsNull(_exposedScrollViewRect))
</span><span class="cx">             return _exposedScrollViewRect;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebKit2/ChangeLog        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2015-08-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Lightweight locks should be adaptive
+        https://bugs.webkit.org/show_bug.cgi?id=147545
+
+        Reviewed by Geoffrey Garen.
+
+        * WebProcess/WebPage/EventDispatcher.cpp:
+        (WebKit::EventDispatcher::clearQueuedTouchEventsForPage):
+        (WebKit::EventDispatcher::getQueuedTouchEventsForPage):
+        (WebKit::EventDispatcher::touchEvent):
+        (WebKit::EventDispatcher::dispatchTouchEvents):
+        * WebProcess/WebPage/EventDispatcher.h:
+        * WebProcess/WebPage/ViewUpdateDispatcher.cpp:
+        (WebKit::ViewUpdateDispatcher::visibleContentRectUpdate):
+        (WebKit::ViewUpdateDispatcher::dispatchVisibleContentRectUpdate):
+        * WebProcess/WebPage/ViewUpdateDispatcher.h:
+
</ins><span class="cx"> 2015-08-07  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Temporarily allow programmatic input assistance for adding Gmail account
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageEventDispatchercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -172,13 +172,13 @@
</span><span class="cx"> #if ENABLE(IOS_TOUCH_EVENTS)
</span><span class="cx"> void EventDispatcher::clearQueuedTouchEventsForPage(const WebPage&amp; webPage)
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;m_touchEventsLock);
</del><ins>+    LockHolder locker(&amp;m_touchEventsLock);
</ins><span class="cx">     m_touchEvents.remove(webPage.pageID());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void EventDispatcher::getQueuedTouchEventsForPage(const WebPage&amp; webPage, TouchEventQueue&amp; destinationQueue)
</span><span class="cx"> {
</span><del>-    SpinLockHolder locker(&amp;m_touchEventsLock);
</del><ins>+    LockHolder locker(&amp;m_touchEventsLock);
</ins><span class="cx">     destinationQueue = m_touchEvents.take(webPage.pageID());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -186,7 +186,7 @@
</span><span class="cx"> {
</span><span class="cx">     bool updateListWasEmpty;
</span><span class="cx">     {
</span><del>-        SpinLockHolder locker(&amp;m_touchEventsLock);
</del><ins>+        LockHolder locker(&amp;m_touchEventsLock);
</ins><span class="cx">         updateListWasEmpty = m_touchEvents.isEmpty();
</span><span class="cx">         auto addResult = m_touchEvents.add(pageID, TouchEventQueue());
</span><span class="cx">         if (addResult.isNewEntry)
</span><span class="lines">@@ -217,7 +217,7 @@
</span><span class="cx"> {
</span><span class="cx">     HashMap&lt;uint64_t, TouchEventQueue&gt; localCopy;
</span><span class="cx">     {
</span><del>-        SpinLockHolder locker(&amp;m_touchEventsLock);
</del><ins>+        LockHolder locker(&amp;m_touchEventsLock);
</ins><span class="cx">         localCopy.swap(m_touchEvents);
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageEventDispatcherh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -32,9 +32,9 @@
</span><span class="cx"> #include &lt;WebEvent.h&gt;
</span><span class="cx"> #include &lt;memory&gt;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="cx"> #include &lt;wtf/RefPtr.h&gt;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><span class="cx"> #include &lt;wtf/ThreadingPrimitives.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace WebCore {
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     std::unique_ptr&lt;WebCore::WheelEventDeltaTracker&gt; m_recentWheelEventDeltaTracker;
</span><span class="cx"> #if ENABLE(IOS_TOUCH_EVENTS)
</span><del>-    SpinLock m_touchEventsLock;
</del><ins>+    Lock m_touchEventsLock;
</ins><span class="cx">     HashMap&lt;uint64_t, TouchEventQueue&gt; m_touchEvents;
</span><span class="cx"> #endif
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageViewUpdateDispatchercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.cpp (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.cpp        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -58,7 +58,7 @@
</span><span class="cx"> {
</span><span class="cx">     bool updateListWasEmpty;
</span><span class="cx">     {
</span><del>-        SpinLockHolder locker(&amp;m_dataMutex);
</del><ins>+        LockHolder locker(&amp;m_dataMutex);
</ins><span class="cx">         updateListWasEmpty = m_latestUpdate.isEmpty();
</span><span class="cx">         auto iterator = m_latestUpdate.find(pageID);
</span><span class="cx">         if (iterator == m_latestUpdate.end())
</span><span class="lines">@@ -78,7 +78,7 @@
</span><span class="cx"> {
</span><span class="cx">     HashMap&lt;uint64_t, UpdateData&gt; update;
</span><span class="cx">     {
</span><del>-        SpinLockHolder locker(&amp;m_dataMutex);
</del><ins>+        LockHolder locker(&amp;m_dataMutex);
</ins><span class="cx">         update = WTF::move(m_latestUpdate);
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebKit2WebProcessWebPageViewUpdateDispatcherh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.h (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.h        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Source/WebKit2/WebProcess/WebPage/ViewUpdateDispatcher.h        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -30,8 +30,8 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;VisibleContentRectUpdateInfo.h&quot;
</span><span class="cx"> #include &lt;wtf/HashMap.h&gt;
</span><ins>+#include &lt;wtf/Lock.h&gt;
</ins><span class="cx"> #include &lt;wtf/Ref.h&gt;
</span><del>-#include &lt;wtf/SpinLock.h&gt;
</del><span class="cx"> 
</span><span class="cx"> namespace WebKit {
</span><span class="cx"> 
</span><span class="lines">@@ -57,7 +57,7 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     Ref&lt;WorkQueue&gt; m_queue;
</span><del>-    SpinLock m_dataMutex;
</del><ins>+    Lock m_dataMutex;
</ins><span class="cx">     HashMap&lt;uint64_t, UpdateData&gt; m_latestUpdate;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Tools/ChangeLog        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2015-08-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Lightweight locks should be adaptive
+        https://bugs.webkit.org/show_bug.cgi?id=147545
+
+        Reviewed by Geoffrey Garen.
+
+        * TestWebKitAPI/CMakeLists.txt:
+        * TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WTF/Lock.cpp: Added.
+        (TestWebKitAPI::runLockTest):
+        (TestWebKitAPI::TEST):
+
</ins><span class="cx"> 2015-08-07  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix a tyop.
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPICMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/CMakeLists.txt        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -75,6 +75,7 @@
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/HashSet.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/IntegerToStringConversion.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/ListHashSet.cpp
</span><ins>+    ${TESTWEBKITAPI_DIR}/Tests/WTF/Lock.cpp
</ins><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/MD5.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/MathExtras.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/MediaTime.cpp
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIvcxprojTestWebKitAPIvcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.vcxproj/TestWebKitAPI.vcxproj        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</del><ins>+&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
</ins><span class="cx"> &lt;Project DefaultTargets=&quot;Build&quot; ToolsVersion=&quot;4.0&quot; xmlns=&quot;http://schemas.microsoft.com/developer/msbuild/2003&quot;&gt;
</span><span class="cx">   &lt;ItemGroup Label=&quot;ProjectConfigurations&quot;&gt;
</span><span class="cx">     &lt;ProjectConfiguration Include=&quot;DebugSuffix|Win32&quot;&gt;
</span><span class="lines">@@ -319,6 +319,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\Tests\WTF\HashSet.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\Tests\WTF\IntegerToStringConversion.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\Tests\WTF\ListHashSet.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\Tests\WTF\Lock.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\Tests\WTF\MD5.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\Tests\WTF\MathExtras.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\Tests\WTF\MediaTime.cpp&quot; /&gt;
</span><span class="lines">@@ -365,4 +366,4 @@
</span><span class="cx">   &lt;Import Project=&quot;$(VCTargetsPath)\Microsoft.Cpp.targets&quot; /&gt;
</span><span class="cx">   &lt;ImportGroup Label=&quot;ExtensionTargets&quot;&gt;
</span><span class="cx">   &lt;/ImportGroup&gt;
</span><del>-&lt;/Project&gt;
</del><span class="cx">\ No newline at end of file
</span><ins>+&lt;/Project&gt;
</ins></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (188168 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2015-08-07 21:55:17 UTC (rev 188168)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -11,6 +11,7 @@
</span><span class="cx">                 0F139E781A423A6B00F590F5 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
</span><span class="cx">                 0F139E791A42457000F590F5 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
</span><span class="cx">                 0F3B94A71A77267400DE3272 /* WKWebViewEvaluateJavaScript.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B94A51A77266C00DE3272 /* WKWebViewEvaluateJavaScript.mm */; };
</span><ins>+                0FFC45A61B73EBEB0085BD62 /* Lock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFC45A41B73EBE20085BD62 /* Lock.cpp */; };
</ins><span class="cx">                 1A02C870125D4CFD00E3F4BD /* find.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 1A02C84B125D4A5E00E3F4BD /* find.html */; };
</span><span class="cx">                 1A50AA201A2A51FC00F4C345 /* close-from-within-create-page.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 1A50AA1F1A2A4EA500F4C345 /* close-from-within-create-page.html */; };
</span><span class="cx">                 1A63479F183D72A4005B1707 /* all-content-in-one-iframe.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 93D3D19B17B1A7B000C7C415 /* all-content-in-one-iframe.html */; };
</span><span class="lines">@@ -428,6 +429,7 @@
</span><span class="cx">                 0F3B94A51A77266C00DE3272 /* WKWebViewEvaluateJavaScript.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WKWebViewEvaluateJavaScript.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FC6C4CB141027E0005B7F0C /* RedBlackTree.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RedBlackTree.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FC6C4CE141034AD005B7F0C /* MetaAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MetaAllocator.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FFC45A41B73EBE20085BD62 /* Lock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Lock.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 14464012167A8305000BD218 /* LayoutUnit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutUnit.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 14F3B11215E45EAB00210069 /* SaturatedArithmeticOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SaturatedArithmeticOperations.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 1A02C84B125D4A5E00E3F4BD /* find.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = find.html; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -1096,6 +1098,7 @@
</span><span class="cx">                                 26B2DFF815BDE599004F691D /* HashSet.cpp */,
</span><span class="cx">                                 266FAFD215E5775200F61D5B /* IntegerToStringConversion.cpp */,
</span><span class="cx">                                 26300B1716755CD90066886D /* ListHashSet.cpp */,
</span><ins>+                                0FFC45A41B73EBE20085BD62 /* Lock.cpp */,
</ins><span class="cx">                                 B4039F9C15E6D8B3007255D6 /* MathExtras.cpp */,
</span><span class="cx">                                 CD5393C71757BA9700C07123 /* MD5.cpp */,
</span><span class="cx">                                 CD5497B315857F0C00B5BC30 /* MediaTime.cpp */,
</span><span class="lines">@@ -1567,6 +1570,7 @@
</span><span class="cx">                                 7CCE7EC91A411A7E00447C4C /* RenderedImageFromDOMNode.mm in Sources */,
</span><span class="cx">                                 7CCE7ECA1A411A7E00447C4C /* RenderedImageFromDOMRange.mm in Sources */,
</span><span class="cx">                                 51CD1C6C1B38CE4300142CA5 /* ModalAlerts.mm in Sources */,
</span><ins>+                                0FFC45A61B73EBEB0085BD62 /* Lock.cpp in Sources */,
</ins><span class="cx">                                 7CCE7F0E1A411AE600447C4C /* ResizeReversePaginatedWebView.cpp in Sources */,
</span><span class="cx">                                 7CCE7F0F1A411AE600447C4C /* ResizeWindowAfterCrash.cpp in Sources */,
</span><span class="cx">                                 7CCE7F101A411AE600447C4C /* ResponsivenessTimerDoesntFireEarly.cpp in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWTFLockcpp"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp (0 => 188169)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Lock.cpp        2015-08-07 22:38:59 UTC (rev 188169)
</span><span class="lines">@@ -0,0 +1,100 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &lt;wtf/Lock.h&gt;
+#include &lt;wtf/Threading.h&gt;
+#include &lt;wtf/ThreadingPrimitives.h&gt;
+
+using namespace WTF;
+
+namespace TestWebKitAPI {
+
+template&lt;typename LockType&gt;
+void runLockTest(unsigned numThreadGroups, unsigned numThreadsPerGroup, unsigned workPerCriticalSection, unsigned numIterations)
+{
+    std::unique_ptr&lt;LockType[]&gt; locks = std::make_unique&lt;LockType[]&gt;(numThreadGroups);
+    std::unique_ptr&lt;double[]&gt; words = std::make_unique&lt;double[]&gt;(numThreadGroups);
+    std::unique_ptr&lt;ThreadIdentifier[]&gt; threads = std::make_unique&lt;ThreadIdentifier[]&gt;(numThreadGroups * numThreadsPerGroup);
+
+    for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;) {
+        words[threadGroupIndex] = 0;
+
+        for (unsigned threadIndex = numThreadsPerGroup; threadIndex--;) {
+            threads[threadGroupIndex * numThreadsPerGroup + threadIndex] = createThread(
+                &quot;Benchmark thread&quot;,
+                [threadGroupIndex, &amp;locks, &amp;words, numIterations, workPerCriticalSection] () {
+                    for (unsigned i = numIterations; i--;) {
+                        locks[threadGroupIndex].lock();
+                        for (unsigned j = workPerCriticalSection; j--;)
+                            words[threadGroupIndex]++;
+                        locks[threadGroupIndex].unlock();
+                    }
+                });
+        }
+    }
+
+    for (unsigned threadIndex = numThreadGroups * numThreadsPerGroup; threadIndex--;)
+        waitForThreadCompletion(threads[threadIndex]);
+
+    double expected = 0;
+    for (uint64_t i = static_cast&lt;uint64_t&gt;(numIterations) * workPerCriticalSection * numThreadsPerGroup; i--;)
+        expected++;
+
+    for (unsigned threadGroupIndex = numThreadGroups; threadGroupIndex--;)
+        EXPECT_EQ(expected, words[threadGroupIndex]);
+}
+
+TEST(WTF_Lock, UncontentedShortSection)
+{
+    runLockTest&lt;Lock&gt;(1, 1, 1, 10000000);
+}
+
+TEST(WTF_Lock, UncontentedLongSection)
+{
+    runLockTest&lt;Lock&gt;(1, 1, 10000, 1000);
+}
+
+TEST(WTF_Lock, ContentedShortSection)
+{
+    runLockTest&lt;Lock&gt;(1, 10, 1, 10000000);
+}
+
+TEST(WTF_Lock, ContentedLongSection)
+{
+    runLockTest&lt;Lock&gt;(1, 10, 10000, 10000);
+}
+
+TEST(WTF_Lock, ManyContentedShortSections)
+{
+    runLockTest&lt;Lock&gt;(10, 10, 1, 500000);
+}
+
+TEST(WTF_Lock, ManyContentedLongSections)
+{
+    runLockTest&lt;Lock&gt;(10, 10, 10000, 1000);
+}
+
+} // namespace TestWebKitAPI
</ins></span></pre>
</div>
</div>

</body>
</html>