<!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>[213645] 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/213645">213645</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2017-03-09 09:40:10 -0800 (Thu, 09 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>WTF should make it super easy to do ARM concurrency tricks
https://bugs.webkit.org/show_bug.cgi?id=169300

Reviewed by Mark Lam.
        
Source/JavaScriptCore:

This changes a bunch of GC hot paths to use new concurrency APIs that lead to optimal
code on both x86 (fully leverage TSO, transactions become CAS loops) and ARM (use
dependency chains for fencing, transactions become LL/SC loops). While inspecting the
machine code, I found other opportunities for improvement, like inlining the &quot;am I
marked&quot; part of the marking functions.

* heap/Heap.cpp:
(JSC::Heap::setGCDidJIT):
* heap/HeapInlines.h:
(JSC::Heap::testAndSetMarked):
* heap/LargeAllocation.h:
(JSC::LargeAllocation::isMarked):
(JSC::LargeAllocation::isMarkedConcurrently):
(JSC::LargeAllocation::aboutToMark):
(JSC::LargeAllocation::testAndSetMarked):
* heap/MarkedBlock.h:
(JSC::MarkedBlock::areMarksStaleWithDependency):
(JSC::MarkedBlock::aboutToMark):
(JSC::MarkedBlock::isMarkedConcurrently):
(JSC::MarkedBlock::isMarked):
(JSC::MarkedBlock::testAndSetMarked):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::appendSlow):
(JSC::SlotVisitor::appendHiddenSlow):
(JSC::SlotVisitor::appendHiddenSlowImpl):
(JSC::SlotVisitor::setMarkedAndAppendToMarkStack):
(JSC::SlotVisitor::appendUnbarriered): Deleted.
(JSC::SlotVisitor::appendHidden): Deleted.
* heap/SlotVisitor.h:
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::appendUnbarriered):
(JSC::SlotVisitor::appendHidden):
(JSC::SlotVisitor::append):
(JSC::SlotVisitor::appendValues):
(JSC::SlotVisitor::appendValuesHidden):
* runtime/CustomGetterSetter.cpp:
* runtime/JSObject.cpp:
(JSC::JSObject::visitButterflyImpl):
* runtime/JSObject.h:

Source/WTF:

This adds Atomic&lt;&gt;::loadLink and Atomic&lt;&gt;::storeCond, available only when HAVE(LL_SC).
        
It abstracts loadLink/storeCond behind prepare/attempt. You can write prepare/attempt
loops whenever your loop fits into the least common denominator of LL/SC and CAS.
        
This modifies Atomic&lt;&gt;::transaction to use prepare/attempt. So, if you write your loop
using Atomic&lt;&gt;::transaction, then you get LL/SC for free.

Depending on the kind of transaction you are doing, you may not want to perform an LL
until you have a chance to just load the current value. Atomic&lt;&gt;::transaction() assumes
that you do not care to have any ordering guarantees in that case. If you think that
the transaction has a good chance of aborting this way, you want
Atomic&lt;&gt;::transaction() to first do a plain load. But if you don't think that such an
abort is likely, then you want to go straight to the LL. The API supports this concept
via TransactionAbortLikelihood.
        
Additionally, this redoes the depend/consume API to be dead simple. Dependency is
unsigned. You get a dependency on a loaded value by just saying
dependency(loadedValue). You consume the dependency by using it as a bonus index to
some pointer dereference. This is made easy with the consume&lt;T*&gt;(ptr, dependency)
helper. In those cases where you want to pass around both a computed value and a
dependency, there's DependencyWith&lt;T&gt;. But you won't need it in most cases. The loaded
value or any value computed from the loaded value is a fine input to dependency()!
        
This change updates a bunch of hot paths to use the new APIs. Using transaction() gives
us optimal LL/SC loops for object marking and lock acquisition.
        
This change also updates a bunch of hot paths to use dependency()/consume().
        
This is a significant Octane/splay speed-up on ARM.

* wtf/Atomics.h:
(WTF::hasFence):
(WTF::Atomic::prepare):
(WTF::Atomic::attempt):
(WTF::Atomic::transaction):
(WTF::Atomic::transactionRelaxed):
(WTF::nullDependency):
(WTF::dependency):
(WTF::DependencyWith::DependencyWith):
(WTF::dependencyWith):
(WTF::consume):
(WTF::Atomic::tryTransactionRelaxed): Deleted.
(WTF::Atomic::tryTransaction): Deleted.
(WTF::zeroWithConsumeDependency): Deleted.
(WTF::consumeLoad): Deleted.
* wtf/Bitmap.h:
(WTF::WordType&gt;::get):
(WTF::WordType&gt;::concurrentTestAndSet):
(WTF::WordType&gt;::concurrentTestAndClear):
* wtf/LockAlgorithm.h:
(WTF::LockAlgorithm::lockFast):
(WTF::LockAlgorithm::unlockFast):
(WTF::LockAlgorithm::unlockSlow):
* wtf/Platform.h:

Tools:

This vastly simplifies the consume API. The new API is thoroughly tested by being used
in the GC's guts. I think that unit tests are a pain to maintain, so we shouldn't have
them unless we are legitimately worried about coverage. We're not in this case.

* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WTF/Consume.cpp: Removed.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapInlinesh">trunk/Source/JavaScriptCore/heap/HeapInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapLargeAllocationh">trunk/Source/JavaScriptCore/heap/LargeAllocation.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkedBlockh">trunk/Source/JavaScriptCore/heap/MarkedBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorcpp">trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorh">trunk/Source/JavaScriptCore/heap/SlotVisitor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorInlinesh">trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeCustomGetterSettercpp">trunk/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectcpp">trunk/Source/JavaScriptCore/runtime/JSObject.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjecth">trunk/Source/JavaScriptCore/runtime/JSObject.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfAtomicsh">trunk/Source/WTF/wtf/Atomics.h</a></li>
<li><a href="#trunkSourceWTFwtfBitmaph">trunk/Source/WTF/wtf/Bitmap.h</a></li>
<li><a href="#trunkSourceWTFwtfLockAlgorithmh">trunk/Source/WTF/wtf/LockAlgorithm.h</a></li>
<li><a href="#trunkSourceWTFwtfPlatformh">trunk/Source/WTF/wtf/Platform.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="#trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj">trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkToolsTestWebKitAPITestsWTFConsumecpp">trunk/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -1,3 +1,50 @@
</span><ins>+2017-03-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        WTF should make it super easy to do ARM concurrency tricks
+        https://bugs.webkit.org/show_bug.cgi?id=169300
+
+        Reviewed by Mark Lam.
+        
+        This changes a bunch of GC hot paths to use new concurrency APIs that lead to optimal
+        code on both x86 (fully leverage TSO, transactions become CAS loops) and ARM (use
+        dependency chains for fencing, transactions become LL/SC loops). While inspecting the
+        machine code, I found other opportunities for improvement, like inlining the &quot;am I
+        marked&quot; part of the marking functions.
+
+        * heap/Heap.cpp:
+        (JSC::Heap::setGCDidJIT):
+        * heap/HeapInlines.h:
+        (JSC::Heap::testAndSetMarked):
+        * heap/LargeAllocation.h:
+        (JSC::LargeAllocation::isMarked):
+        (JSC::LargeAllocation::isMarkedConcurrently):
+        (JSC::LargeAllocation::aboutToMark):
+        (JSC::LargeAllocation::testAndSetMarked):
+        * heap/MarkedBlock.h:
+        (JSC::MarkedBlock::areMarksStaleWithDependency):
+        (JSC::MarkedBlock::aboutToMark):
+        (JSC::MarkedBlock::isMarkedConcurrently):
+        (JSC::MarkedBlock::isMarked):
+        (JSC::MarkedBlock::testAndSetMarked):
+        * heap/SlotVisitor.cpp:
+        (JSC::SlotVisitor::appendSlow):
+        (JSC::SlotVisitor::appendHiddenSlow):
+        (JSC::SlotVisitor::appendHiddenSlowImpl):
+        (JSC::SlotVisitor::setMarkedAndAppendToMarkStack):
+        (JSC::SlotVisitor::appendUnbarriered): Deleted.
+        (JSC::SlotVisitor::appendHidden): Deleted.
+        * heap/SlotVisitor.h:
+        * heap/SlotVisitorInlines.h:
+        (JSC::SlotVisitor::appendUnbarriered):
+        (JSC::SlotVisitor::appendHidden):
+        (JSC::SlotVisitor::append):
+        (JSC::SlotVisitor::appendValues):
+        (JSC::SlotVisitor::appendValuesHidden):
+        * runtime/CustomGetterSetter.cpp:
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::visitButterflyImpl):
+        * runtime/JSObject.h:
+
</ins><span class="cx"> 2017-03-08  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [GTK] JSC test stress/arity-check-ftl-throw.js.ftl-no-cjit-validate-sampling-profiler crashing on GTK bot
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -1853,9 +1853,10 @@
</span><span class="cx"> void Heap::setGCDidJIT()
</span><span class="cx"> {
</span><span class="cx">     m_worldState.transaction(
</span><del>-        [&amp;] (unsigned&amp; state) {
</del><ins>+        [&amp;] (unsigned&amp; state) -&gt; bool {
</ins><span class="cx">             RELEASE_ASSERT(state &amp; stoppedBit);
</span><span class="cx">             state |= gcDidJITBit;
</span><ins>+            return true;
</ins><span class="cx">         });
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapInlines.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapInlines.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/heap/HeapInlines.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -93,8 +93,8 @@
</span><span class="cx">     if (cell-&gt;isLargeAllocation())
</span><span class="cx">         return cell-&gt;largeAllocation().testAndSetMarked();
</span><span class="cx">     MarkedBlock&amp; block = cell-&gt;markedBlock();
</span><del>-    block.aboutToMark(markingVersion);
-    return block.testAndSetMarked(cell);
</del><ins>+    Dependency dependency = block.aboutToMark(markingVersion);
+    return block.testAndSetMarked(cell, dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE size_t Heap::cellSize(const void* rawCell)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapLargeAllocationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/LargeAllocation.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/LargeAllocation.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/heap/LargeAllocation.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -74,8 +74,9 @@
</span><span class="cx">     
</span><span class="cx">     bool isNewlyAllocated() const { return m_isNewlyAllocated; }
</span><span class="cx">     ALWAYS_INLINE bool isMarked() { return m_isMarked.load(std::memory_order_relaxed); }
</span><del>-    ALWAYS_INLINE bool isMarked(HeapCell*) { return m_isMarked.load(std::memory_order_relaxed); }
-    ALWAYS_INLINE bool isMarkedConcurrently(HeapVersion, HeapCell*) { return m_isMarked.load(std::memory_order_relaxed); }
</del><ins>+    ALWAYS_INLINE bool isMarked(HeapCell*) { return isMarked(); }
+    ALWAYS_INLINE bool isMarked(HeapCell*, Dependency) { return isMarked(); }
+    ALWAYS_INLINE bool isMarkedConcurrently(HeapVersion, HeapCell*) { return isMarked(); }
</ins><span class="cx">     bool isLive() { return isMarked() || isNewlyAllocated(); }
</span><span class="cx">     
</span><span class="cx">     bool hasValidCell() const { return m_hasValidCell; }
</span><span class="lines">@@ -109,7 +110,7 @@
</span><span class="cx">     
</span><span class="cx">     const AllocatorAttributes&amp; attributes() const { return m_attributes; }
</span><span class="cx">     
</span><del>-    void aboutToMark(HeapVersion) { }
</del><ins>+    Dependency aboutToMark(HeapVersion) { return nullDependency(); }
</ins><span class="cx">     
</span><span class="cx">     ALWAYS_INLINE bool testAndSetMarked()
</span><span class="cx">     {
</span><span class="lines">@@ -120,7 +121,7 @@
</span><span class="cx">             return true;
</span><span class="cx">         return m_isMarked.compareExchangeStrong(false, true);
</span><span class="cx">     }
</span><del>-    ALWAYS_INLINE bool testAndSetMarked(HeapCell*) { return testAndSetMarked(); }
</del><ins>+    ALWAYS_INLINE bool testAndSetMarked(HeapCell*, Dependency, TransactionAbortLikelihood = TransactionAbortLikelihood::Likely) { return testAndSetMarked(); }
</ins><span class="cx">     void clearMarked() { m_isMarked.store(false); }
</span><span class="cx">     
</span><span class="cx">     void noteMarked() { }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkedBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/MarkedBlock.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkedBlock.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/heap/MarkedBlock.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -258,7 +258,8 @@
</span><span class="cx">     bool isMarked(const void*);
</span><span class="cx">     bool isMarked(HeapVersion markingVersion, const void*);
</span><span class="cx">     bool isMarkedConcurrently(HeapVersion markingVersion, const void*);
</span><del>-    bool testAndSetMarked(const void*);
</del><ins>+    bool isMarked(const void*, Dependency);
+    bool testAndSetMarked(const void*, Dependency, TransactionAbortLikelihood = TransactionAbortLikelihood::Likely);
</ins><span class="cx">         
</span><span class="cx">     bool isAtom(const void*);
</span><span class="cx">     void clearMarked(const void*);
</span><span class="lines">@@ -278,15 +279,15 @@
</span><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE bool areMarksStale();
</span><span class="cx">     bool areMarksStale(HeapVersion markingVersion);
</span><del>-    struct MarksWithDependency {
-        bool areStale;
-        ConsumeDependency dependency;
-    };
-    MarksWithDependency areMarksStaleWithDependency(HeapVersion markingVersion);
</del><ins>+    DependencyWith&lt;bool&gt; areMarksStaleWithDependency(HeapVersion markingVersion);
</ins><span class="cx">     
</span><del>-    void aboutToMark(HeapVersion markingVersion);
</del><ins>+    Dependency aboutToMark(HeapVersion markingVersion);
</ins><span class="cx">         
</span><del>-    void assertMarksNotStale();
</del><ins>+#if ASSERT_DISABLED
+    void assertMarksNotStale() { }
+#else
+    JS_EXPORT_PRIVATE void assertMarksNotStale();
+#endif
</ins><span class="cx">         
</span><span class="cx">     bool needsDestruction() const { return m_needsDestruction; }
</span><span class="cx">     
</span><span class="lines">@@ -306,7 +307,7 @@
</span><span class="cx">     MarkedBlock(VM&amp;, Handle&amp;);
</span><span class="cx">     Atom* atoms();
</span><span class="cx">         
</span><del>-    void aboutToMarkSlow(HeapVersion markingVersion);
</del><ins>+    JS_EXPORT_PRIVATE void aboutToMarkSlow(HeapVersion markingVersion);
</ins><span class="cx">     void clearHasAnyMarked();
</span><span class="cx">     
</span><span class="cx">     void noteMarkedSlow();
</span><span class="lines">@@ -491,28 +492,20 @@
</span><span class="cx">     return markingVersion != m_markingVersion;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ALWAYS_INLINE MarkedBlock::MarksWithDependency MarkedBlock::areMarksStaleWithDependency(HeapVersion markingVersion)
</del><ins>+ALWAYS_INLINE DependencyWith&lt;bool&gt; MarkedBlock::areMarksStaleWithDependency(HeapVersion markingVersion)
</ins><span class="cx"> {
</span><del>-    auto consumed = consumeLoad(&amp;m_markingVersion);
-    MarksWithDependency ret;
-    ret.areStale = consumed.value != markingVersion;
-    ret.dependency = consumed.dependency;
-    return ret;
</del><ins>+    HeapVersion version = m_markingVersion;
+    return dependencyWith(dependency(version), version != markingVersion);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void MarkedBlock::aboutToMark(HeapVersion markingVersion)
</del><ins>+inline Dependency MarkedBlock::aboutToMark(HeapVersion markingVersion)
</ins><span class="cx"> {
</span><del>-    if (UNLIKELY(areMarksStale(markingVersion)))
</del><ins>+    auto result = areMarksStaleWithDependency(markingVersion);
+    if (UNLIKELY(result.value))
</ins><span class="cx">         aboutToMarkSlow(markingVersion);
</span><del>-    WTF::loadLoadFence();
</del><ins>+    return result.dependency;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-#if ASSERT_DISABLED
-inline void MarkedBlock::assertMarksNotStale()
-{
-}
-#endif // ASSERT_DISABLED
-
</del><span class="cx"> inline void MarkedBlock::Handle::assertMarksNotStale()
</span><span class="cx"> {
</span><span class="cx">     block().assertMarksNotStale();
</span><span class="lines">@@ -530,18 +523,24 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool MarkedBlock::isMarkedConcurrently(HeapVersion markingVersion, const void* p)
</span><span class="cx"> {
</span><del>-    auto marksWithDependency = areMarksStaleWithDependency(markingVersion);
-    if (marksWithDependency.areStale)
</del><ins>+    auto result = areMarksStaleWithDependency(markingVersion);
+    if (result.value)
</ins><span class="cx">         return false;
</span><del>-    return m_marks.get(atomNumber(p) + marksWithDependency.dependency);
</del><ins>+    return m_marks.get(atomNumber(p), result.dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline bool MarkedBlock::testAndSetMarked(const void* p)
</del><ins>+inline bool MarkedBlock::isMarked(const void* p, Dependency dependency)
</ins><span class="cx"> {
</span><span class="cx">     assertMarksNotStale();
</span><del>-    return m_marks.concurrentTestAndSet(atomNumber(p));
</del><ins>+    return m_marks.get(atomNumber(p), dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool MarkedBlock::testAndSetMarked(const void* p, Dependency dependency, TransactionAbortLikelihood abortLikelihood)
+{
+    assertMarksNotStale();
+    return m_marks.concurrentTestAndSet(atomNumber(p), dependency, abortLikelihood);
+}
+
</ins><span class="cx"> inline bool MarkedBlock::Handle::isNewlyAllocated(const void* p)
</span><span class="cx"> {
</span><span class="cx">     return m_newlyAllocated.get(m_block-&gt;atomNumber(p));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -222,32 +222,22 @@
</span><span class="cx">     } }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SlotVisitor::appendUnbarriered(JSValue value)
</del><ins>+void SlotVisitor::appendSlow(JSCell* cell, Dependency dependency)
</ins><span class="cx"> {
</span><del>-    if (!value || !value.isCell())
-        return;
-
</del><span class="cx">     if (UNLIKELY(m_heapSnapshotBuilder))
</span><del>-        m_heapSnapshotBuilder-&gt;appendEdge(m_currentCell, value.asCell());
-
-    setMarkedAndAppendToMarkStack(value.asCell());
</del><ins>+        m_heapSnapshotBuilder-&gt;appendEdge(m_currentCell, cell);
+    
+    appendHiddenSlowImpl(cell, dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SlotVisitor::appendHidden(JSValue value)
</del><ins>+void SlotVisitor::appendHiddenSlow(JSCell* cell, Dependency dependency)
</ins><span class="cx"> {
</span><del>-    if (!value || !value.isCell())
-        return;
-
-    setMarkedAndAppendToMarkStack(value.asCell());
</del><ins>+    appendHiddenSlowImpl(cell, dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SlotVisitor::setMarkedAndAppendToMarkStack(JSCell* cell)
</del><ins>+ALWAYS_INLINE void SlotVisitor::appendHiddenSlowImpl(JSCell* cell, Dependency dependency)
</ins><span class="cx"> {
</span><del>-    SuperSamplerScope superSamplerScope(false);
-    
</del><span class="cx">     ASSERT(!m_isCheckingForDefaultMarkViolation);
</span><del>-    if (!cell)
-        return;
</del><span class="cx"> 
</span><span class="cx"> #if ENABLE(GC_VALIDATION)
</span><span class="cx">     validate(cell);
</span><span class="lines">@@ -254,17 +244,15 @@
</span><span class="cx"> #endif
</span><span class="cx">     
</span><span class="cx">     if (cell-&gt;isLargeAllocation())
</span><del>-        setMarkedAndAppendToMarkStack(cell-&gt;largeAllocation(), cell);
</del><ins>+        setMarkedAndAppendToMarkStack(cell-&gt;largeAllocation(), cell, dependency);
</ins><span class="cx">     else
</span><del>-        setMarkedAndAppendToMarkStack(cell-&gt;markedBlock(), cell);
</del><ins>+        setMarkedAndAppendToMarkStack(cell-&gt;markedBlock(), cell, dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename ContainerType&gt;
</span><del>-ALWAYS_INLINE void SlotVisitor::setMarkedAndAppendToMarkStack(ContainerType&amp; container, JSCell* cell)
</del><ins>+ALWAYS_INLINE void SlotVisitor::setMarkedAndAppendToMarkStack(ContainerType&amp; container, JSCell* cell, Dependency dependency)
</ins><span class="cx"> {
</span><del>-    container.aboutToMark(m_markingVersion);
-    
-    if (container.testAndSetMarked(cell))
</del><ins>+    if (container.testAndSetMarked(cell, dependency, TransactionAbortLikelihood::Unlikely))
</ins><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     ASSERT(cell-&gt;structure());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -175,11 +175,14 @@
</span><span class="cx">     
</span><span class="cx">     void appendJSCellOrAuxiliary(HeapCell*);
</span><span class="cx">     void appendHidden(JSValue);
</span><ins>+    void appendHidden(JSCell*);
</ins><span class="cx"> 
</span><del>-    JS_EXPORT_PRIVATE void setMarkedAndAppendToMarkStack(JSCell*);
</del><ins>+    JS_EXPORT_PRIVATE void appendSlow(JSCell*, Dependency);
+    JS_EXPORT_PRIVATE void appendHiddenSlow(JSCell*, Dependency);
+    void appendHiddenSlowImpl(JSCell*, Dependency);
</ins><span class="cx">     
</span><span class="cx">     template&lt;typename ContainerType&gt;
</span><del>-    void setMarkedAndAppendToMarkStack(ContainerType&amp;, JSCell*);
</del><ins>+    void setMarkedAndAppendToMarkStack(ContainerType&amp;, JSCell*, Dependency);
</ins><span class="cx">     
</span><span class="cx">     void appendToMarkStack(JSCell*);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -31,49 +31,106 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-inline void SlotVisitor::appendUnbarriered(JSValue* slot, size_t count)
</del><ins>+ALWAYS_INLINE void SlotVisitor::appendUnbarriered(JSValue* slot, size_t count)
</ins><span class="cx"> {
</span><span class="cx">     for (size_t i = count; i--;)
</span><span class="cx">         appendUnbarriered(slot[i]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void SlotVisitor::appendUnbarriered(JSCell* cell)
</del><ins>+ALWAYS_INLINE void SlotVisitor::appendUnbarriered(JSCell* cell)
</ins><span class="cx"> {
</span><del>-    appendUnbarriered(JSValue(cell));
</del><ins>+    // This needs to be written in a very specific way to ensure that it gets inlined
+    // properly. In particular, it appears that using templates here breaks ALWAYS_INLINE.
+    
+    if (!cell)
+        return;
+    
+    Dependency dependency;
+    if (UNLIKELY(cell-&gt;isLargeAllocation())) {
+        dependency = nullDependency();
+        if (LIKELY(cell-&gt;largeAllocation().isMarked())) {
+            if (LIKELY(!m_heapSnapshotBuilder))
+                return;
+        }
+    } else {
+        MarkedBlock&amp; block = cell-&gt;markedBlock();
+        dependency = block.aboutToMark(m_markingVersion);
+        if (LIKELY(block.isMarked(cell, dependency))) {
+            if (LIKELY(!m_heapSnapshotBuilder))
+                return;
+        }
+    }
+    
+    appendSlow(cell, dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE void SlotVisitor::appendUnbarriered(JSValue value)
+{
+    if (value.isCell())
+        appendUnbarriered(value.asCell());
+}
+
+ALWAYS_INLINE void SlotVisitor::appendHidden(JSValue value)
+{
+    if (value.isCell())
+        appendHidden(value.asCell());
+}
+
+ALWAYS_INLINE void SlotVisitor::appendHidden(JSCell* cell)
+{
+    // This needs to be written in a very specific way to ensure that it gets inlined
+    // properly. In particular, it appears that using templates here breaks ALWAYS_INLINE.
+    
+    if (!cell)
+        return;
+    
+    Dependency dependency;
+    if (UNLIKELY(cell-&gt;isLargeAllocation())) {
+        dependency = nullDependency();
+        if (LIKELY(cell-&gt;largeAllocation().isMarked()))
+            return;
+    } else {
+        MarkedBlock&amp; block = cell-&gt;markedBlock();
+        dependency = block.aboutToMark(m_markingVersion);
+        if (LIKELY(block.isMarked(cell, dependency)))
+            return;
+    }
+    
+    appendHiddenSlow(cell, dependency);
+}
+
</ins><span class="cx"> template&lt;typename T&gt;
</span><del>-inline void SlotVisitor::append(const Weak&lt;T&gt;&amp; weak)
</del><ins>+ALWAYS_INLINE void SlotVisitor::append(const Weak&lt;T&gt;&amp; weak)
</ins><span class="cx"> {
</span><span class="cx">     appendUnbarriered(weak.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename T&gt;
</span><del>-inline void SlotVisitor::append(const WriteBarrierBase&lt;T&gt;&amp; slot)
</del><ins>+ALWAYS_INLINE void SlotVisitor::append(const WriteBarrierBase&lt;T&gt;&amp; slot)
</ins><span class="cx"> {
</span><span class="cx">     appendUnbarriered(slot.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename T&gt;
</span><del>-inline void SlotVisitor::appendHidden(const WriteBarrierBase&lt;T&gt;&amp; slot)
</del><ins>+ALWAYS_INLINE void SlotVisitor::appendHidden(const WriteBarrierBase&lt;T&gt;&amp; slot)
</ins><span class="cx"> {
</span><span class="cx">     appendHidden(slot.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Iterator&gt;
</span><del>-inline void SlotVisitor::append(Iterator begin, Iterator end)
</del><ins>+ALWAYS_INLINE void SlotVisitor::append(Iterator begin, Iterator end)
</ins><span class="cx"> {
</span><span class="cx">     for (auto it = begin; it != end; ++it)
</span><span class="cx">         append(*it);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void SlotVisitor::appendValues(const WriteBarrierBase&lt;Unknown&gt;* barriers, size_t count)
</del><ins>+ALWAYS_INLINE void SlotVisitor::appendValues(const WriteBarrierBase&lt;Unknown&gt;* barriers, size_t count)
</ins><span class="cx"> {
</span><span class="cx">     for (size_t i = 0; i &lt; count; ++i)
</span><span class="cx">         append(barriers[i]);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void SlotVisitor::appendValuesHidden(const WriteBarrierBase&lt;Unknown&gt;* barriers, size_t count)
</del><ins>+ALWAYS_INLINE void SlotVisitor::appendValuesHidden(const WriteBarrierBase&lt;Unknown&gt;* barriers, size_t count)
</ins><span class="cx"> {
</span><span class="cx">     for (size_t i = 0; i &lt; count; ++i)
</span><span class="cx">         appendHidden(barriers[i]);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeCustomGetterSettercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -26,9 +26,7 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;CustomGetterSetter.h&quot;
</span><span class="cx"> 
</span><del>-#include &quot;JSCJSValueInlines.h&quot;
-#include &quot;JSObject.h&quot;
-#include &quot;SlotVisitorInlines.h&quot;
</del><ins>+#include &quot;JSCInlines.h&quot;
</ins><span class="cx"> #include &lt;wtf/Assertions.h&gt;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.cpp (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.cpp        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -382,6 +382,7 @@
</span><span class="cx">     structure = vm.getStructure(structureID);
</span><span class="cx">     lastOffset = structure-&gt;lastOffset();
</span><span class="cx">     IndexingType indexingType = structure-&gt;indexingType();
</span><ins>+    Dependency indexingTypeDependency = dependency(indexingType);
</ins><span class="cx">     Locker&lt;JSCell&gt; locker(NoLockingNecessary);
</span><span class="cx">     switch (indexingType) {
</span><span class="cx">     case ALL_CONTIGUOUS_INDEXING_TYPES:
</span><span class="lines">@@ -395,14 +396,13 @@
</span><span class="cx">     default:
</span><span class="cx">         break;
</span><span class="cx">     }
</span><del>-    WTF::loadLoadFence();
-    butterfly = this-&gt;butterfly();
</del><ins>+    butterfly = consume(this, indexingTypeDependency)-&gt;butterfly();
+    Dependency butterflyDependency = dependency(butterfly);
</ins><span class="cx">     if (!butterfly)
</span><span class="cx">         return structure;
</span><del>-    WTF::loadLoadFence();
-    if (this-&gt;structureID() != structureID)
</del><ins>+    if (consume(this, butterflyDependency)-&gt;structureID() != structureID)
</ins><span class="cx">         return nullptr;
</span><del>-    if (structure-&gt;lastOffset() != lastOffset)
</del><ins>+    if (consume(structure, butterflyDependency)-&gt;lastOffset() != lastOffset)
</ins><span class="cx">         return nullptr;
</span><span class="cx">     
</span><span class="cx">     markAuxiliaryAndVisitOutOfLineProperties(visitor, butterfly, structure, lastOffset);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjecth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObject.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObject.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/JavaScriptCore/runtime/JSObject.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -664,7 +664,7 @@
</span><span class="cx">         
</span><span class="cx">     const Butterfly* butterfly() const { return m_butterfly.get(); }
</span><span class="cx">     Butterfly* butterfly() { return m_butterfly.get(); }
</span><del>-        
</del><ins>+    
</ins><span class="cx">     ConstPropertyStorage outOfLineStorage() const { return m_butterfly.get()-&gt;propertyStorage(); }
</span><span class="cx">     PropertyStorage outOfLineStorage() { return m_butterfly.get()-&gt;propertyStorage(); }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/WTF/ChangeLog        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -1,3 +1,66 @@
</span><ins>+2017-03-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        WTF should make it super easy to do ARM concurrency tricks
+        https://bugs.webkit.org/show_bug.cgi?id=169300
+
+        Reviewed by Mark Lam.
+        
+        This adds Atomic&lt;&gt;::loadLink and Atomic&lt;&gt;::storeCond, available only when HAVE(LL_SC).
+        
+        It abstracts loadLink/storeCond behind prepare/attempt. You can write prepare/attempt
+        loops whenever your loop fits into the least common denominator of LL/SC and CAS.
+        
+        This modifies Atomic&lt;&gt;::transaction to use prepare/attempt. So, if you write your loop
+        using Atomic&lt;&gt;::transaction, then you get LL/SC for free.
+
+        Depending on the kind of transaction you are doing, you may not want to perform an LL
+        until you have a chance to just load the current value. Atomic&lt;&gt;::transaction() assumes
+        that you do not care to have any ordering guarantees in that case. If you think that
+        the transaction has a good chance of aborting this way, you want
+        Atomic&lt;&gt;::transaction() to first do a plain load. But if you don't think that such an
+        abort is likely, then you want to go straight to the LL. The API supports this concept
+        via TransactionAbortLikelihood.
+        
+        Additionally, this redoes the depend/consume API to be dead simple. Dependency is
+        unsigned. You get a dependency on a loaded value by just saying
+        dependency(loadedValue). You consume the dependency by using it as a bonus index to
+        some pointer dereference. This is made easy with the consume&lt;T*&gt;(ptr, dependency)
+        helper. In those cases where you want to pass around both a computed value and a
+        dependency, there's DependencyWith&lt;T&gt;. But you won't need it in most cases. The loaded
+        value or any value computed from the loaded value is a fine input to dependency()!
+        
+        This change updates a bunch of hot paths to use the new APIs. Using transaction() gives
+        us optimal LL/SC loops for object marking and lock acquisition.
+        
+        This change also updates a bunch of hot paths to use dependency()/consume().
+        
+        This is a significant Octane/splay speed-up on ARM.
+
+        * wtf/Atomics.h:
+        (WTF::hasFence):
+        (WTF::Atomic::prepare):
+        (WTF::Atomic::attempt):
+        (WTF::Atomic::transaction):
+        (WTF::Atomic::transactionRelaxed):
+        (WTF::nullDependency):
+        (WTF::dependency):
+        (WTF::DependencyWith::DependencyWith):
+        (WTF::dependencyWith):
+        (WTF::consume):
+        (WTF::Atomic::tryTransactionRelaxed): Deleted.
+        (WTF::Atomic::tryTransaction): Deleted.
+        (WTF::zeroWithConsumeDependency): Deleted.
+        (WTF::consumeLoad): Deleted.
+        * wtf/Bitmap.h:
+        (WTF::WordType&gt;::get):
+        (WTF::WordType&gt;::concurrentTestAndSet):
+        (WTF::WordType&gt;::concurrentTestAndClear):
+        * wtf/LockAlgorithm.h:
+        (WTF::LockAlgorithm::lockFast):
+        (WTF::LockAlgorithm::unlockFast):
+        (WTF::LockAlgorithm::unlockSlow):
+        * wtf/Platform.h:
+
</ins><span class="cx"> 2017-03-08  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Simplify the PaymentCoordinator interface
</span></span></pre></div>
<a id="trunkSourceWTFwtfAtomicsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Atomics.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Atomics.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/WTF/wtf/Atomics.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2007-2008, 2010, 2012-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2007-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -40,6 +40,16 @@
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE bool hasFence(std::memory_order order)
+{
+    return order != std::memory_order_relaxed;
+}
+
+enum class TransactionAbortLikelihood {
+    Unlikely,
+    Likely
+};
+    
</ins><span class="cx"> // Atomic wraps around std::atomic with the sole purpose of making the compare_exchange
</span><span class="cx"> // operations not alter the expected value. This is more in line with how we typically
</span><span class="cx"> // use CAS in our code.
</span><span class="lines">@@ -107,39 +117,129 @@
</span><span class="cx">     
</span><span class="cx">     ALWAYS_INLINE T exchange(T newValue, std::memory_order order = std::memory_order_seq_cst) { return value.exchange(newValue, order); }
</span><span class="cx">     
</span><del>-    template&lt;typename Func&gt;
-    ALWAYS_INLINE bool tryTransactionRelaxed(const Func&amp; func)
</del><ins>+#if HAVE(LL_SC)
+    ALWAYS_INLINE T loadLink(std::memory_order order = std::memory_order_seq_cst);
+    ALWAYS_INLINE bool storeCond(T value,  std::memory_order order = std::memory_order_seq_cst);
+#endif // HAVE(LL_SC)
+
+    ALWAYS_INLINE T prepare(std::memory_order order = std::memory_order_seq_cst)
</ins><span class="cx">     {
</span><del>-        T oldValue = load(std::memory_order_relaxed);
-        T newValue = oldValue;
-        func(newValue);
-        return compareExchangeWeakRelaxed(oldValue, newValue);
</del><ins>+#if HAVE(LL_SC)
+        return loadLink(order);
+#else
+        UNUSED_PARAM(order);
+        return load(std::memory_order_relaxed);
+#endif
</ins><span class="cx">     }
</span><ins>+    
+#if HAVE(LL_SC)
+    static const bool prepareIsFast = false;
+#else
+    static const bool prepareIsFast = true;
+#endif
</ins><span class="cx"> 
</span><del>-    template&lt;typename Func&gt;
-    ALWAYS_INLINE void transactionRelaxed(const Func&amp; func)
</del><ins>+    ALWAYS_INLINE bool attempt(T oldValue, T newValue, std::memory_order order = std::memory_order_seq_cst)
</ins><span class="cx">     {
</span><del>-        while (!tryTransationRelaxed(func)) { }
</del><ins>+#if HAVE(LL_SC)
+        UNUSED_PARAM(oldValue);
+        return storeCond(newValue, order);
+#else
+        return compareExchangeWeak(oldValue, newValue, order);
+#endif
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     template&lt;typename Func&gt;
</span><del>-    ALWAYS_INLINE bool tryTransaction(const Func&amp; func)
</del><ins>+    ALWAYS_INLINE bool transaction(const Func&amp; func, std::memory_order order = std::memory_order_seq_cst, TransactionAbortLikelihood abortLikelihood = TransactionAbortLikelihood::Likely)
</ins><span class="cx">     {
</span><del>-        T oldValue = load(std::memory_order_relaxed);
-        T newValue = oldValue;
-        func(newValue);
-        return compareExchangeWeak(oldValue, newValue);
</del><ins>+        // If preparing is not fast then we want to skip the loop when func would fail.
+        if (!prepareIsFast &amp;&amp; abortLikelihood == TransactionAbortLikelihood::Likely) {
+            T oldValue = load(std::memory_order_relaxed);
+            // Note: many funcs will constant-fold to true, which will kill all of this code.
+            if (!func(oldValue))
+                return false;
+        }
+        for (;;) {
+            T oldValue = prepare(order);
+            T newValue = oldValue;
+            if (!func(newValue))
+                return false;
+            if (attempt(oldValue, newValue, order))
+                return true;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     template&lt;typename Func&gt;
</span><del>-    ALWAYS_INLINE void transaction(const Func&amp; func)
</del><ins>+    ALWAYS_INLINE bool transactionRelaxed(const Func&amp; func, TransactionAbortLikelihood abortLikelihood = TransactionAbortLikelihood::Likely)
</ins><span class="cx">     {
</span><del>-        while (!tryTransaction(func)) { }
</del><ins>+        return transaction(func, std::memory_order_relaxed, abortLikelihood);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     std::atomic&lt;T&gt; value;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+#if CPU(ARM64)
+#define DEFINE_LL_SC(width, modifier, suffix)   \
+    template&lt;&gt; \
+    ALWAYS_INLINE uint ## width ## _t Atomic&lt;uint ## width ##_t&gt;::loadLink(std::memory_order order) \
+    { \
+        int ## width ## _t result; \
+        if (hasFence(order)) { \
+            asm volatile ( \
+                &quot;ldaxr&quot; suffix &quot; %&quot; modifier &quot;0, [%1]&quot; \
+                : &quot;=r&quot;(result) \
+                : &quot;r&quot;(this) \
+                : &quot;memory&quot;); \
+        } else { \
+            asm ( \
+                &quot;ldxr&quot; suffix &quot; %&quot; modifier &quot;0, [%1]&quot; \
+                : &quot;=r&quot;(result) \
+                : &quot;r&quot;(this) \
+                : &quot;memory&quot;); \
+        } \
+        return result; \
+    } \
+    \
+    template&lt;&gt; \
+    ALWAYS_INLINE bool Atomic&lt;uint ## width ## _t&gt;::storeCond(uint ## width ## _t value, std::memory_order order) \
+    { \
+        bool result; \
+        if (hasFence(order)) { \
+            asm volatile ( \
+                &quot;stlxr&quot; suffix &quot; %w0, %&quot; modifier &quot;1, [%2]&quot; \
+                : &quot;=&amp;r&quot;(result) \
+                : &quot;r&quot;(value), &quot;r&quot;(this) \
+                : &quot;memory&quot;); \
+        } else { \
+            asm ( \
+                &quot;stxr&quot; suffix &quot; %w0, %&quot; modifier &quot;1, [%2]&quot; \
+                : &quot;=&amp;r&quot;(result) \
+                : &quot;r&quot;(value), &quot;r&quot;(this) \
+                : &quot;memory&quot;); \
+        } \
+        return !result; \
+    } \
+    \
+    template&lt;&gt; \
+    ALWAYS_INLINE int ## width ## _t Atomic&lt;int ## width ## _t&gt;::loadLink(std::memory_order order) \
+    { \
+        return bitwise_cast&lt;Atomic&lt;uint ## width ## _t&gt;*&gt;(this)-&gt;loadLink(order); \
+    } \
+    \
+    template&lt;&gt; \
+    ALWAYS_INLINE bool Atomic&lt;int ## width ## _t&gt;::storeCond(int ## width ## _t value, std::memory_order order) \
+    { \
+        return bitwise_cast&lt;Atomic&lt;uint ## width ## _t&gt;*&gt;(this)-&gt;storeCond(value, order); \
+    }
+
+DEFINE_LL_SC(8, &quot;w&quot;, &quot;b&quot;)
+DEFINE_LL_SC(16, &quot;w&quot;, &quot;h&quot;)
+DEFINE_LL_SC(32, &quot;w&quot;, &quot;&quot;)
+DEFINE_LL_SC(64, &quot;&quot;, &quot;&quot;)
+DEFINE_LL_SC(ptr, &quot;&quot;, &quot;&quot;)
+
+#undef DEFINE_LL_SC
+#endif // CPU(ARM64)
+
</ins><span class="cx"> template&lt;typename T&gt;
</span><span class="cx"> inline T atomicLoad(T* location, std::memory_order order = std::memory_order_seq_cst)
</span><span class="cx"> {
</span><span class="lines">@@ -308,12 +408,17 @@
</span><span class="cx"> 
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-typedef size_t ConsumeDependency;
</del><ins>+typedef unsigned Dependency;
</ins><span class="cx"> 
</span><ins>+ALWAYS_INLINE Dependency nullDependency()
+{
+    return 0;
+}
+
</ins><span class="cx"> template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 8&gt;::type* = nullptr&gt;
</span><del>-ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
</del><ins>+ALWAYS_INLINE Dependency dependency(T value)
</ins><span class="cx"> {
</span><del>-    uint64_t dependency;
</del><ins>+    unsigned dependency;
</ins><span class="cx">     uint64_t copy = bitwise_cast&lt;uint64_t&gt;(value);
</span><span class="cx"> #if CPU(ARM64)
</span><span class="cx">     // Create a magical zero value through inline assembly, whose computation
</span><span class="lines">@@ -325,104 +430,102 @@
</span><span class="cx">     // ordering. This forces weak memory order CPUs to observe `location` and
</span><span class="cx">     // dependent loads in their store order without the reader using a barrier
</span><span class="cx">     // or an acquire load.
</span><del>-    asm volatile(&quot;eor %x[dependency], %x[in], %x[in]&quot;
-                 : [dependency] &quot;=r&quot;(dependency)
-                 : [in] &quot;r&quot;(copy)
-                 // Lie about touching memory. Not strictly needed, but is
-                 // likely to avoid unwanted load/store motion.
-                 : &quot;memory&quot;);
</del><ins>+    asm(&quot;eor %w[dependency], %w[in], %w[in]&quot;
+        : [dependency] &quot;=r&quot;(dependency)
+        : [in] &quot;r&quot;(copy));
</ins><span class="cx"> #elif CPU(ARM)
</span><del>-    asm volatile(&quot;eor %[dependency], %[in], %[in]&quot;
-                 : [dependency] &quot;=r&quot;(dependency)
-                 : [in] &quot;r&quot;(copy)
-                 : &quot;memory&quot;);
</del><ins>+    asm(&quot;eor %[dependency], %[in], %[in]&quot;
+        : [dependency] &quot;=r&quot;(dependency)
+        : [in] &quot;r&quot;(copy));
</ins><span class="cx"> #else
</span><span class="cx">     // No dependency is needed for this architecture.
</span><span class="cx">     loadLoadFence();
</span><span class="cx">     dependency = 0;
</span><del>-    (void)copy;
</del><ins>+    UNUSED_PARAM(copy);
</ins><span class="cx"> #endif
</span><del>-    return static_cast&lt;ConsumeDependency&gt;(dependency);
</del><ins>+    return dependency;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// FIXME: This code is almost identical to the other dependency() overload.
+// https://bugs.webkit.org/show_bug.cgi?id=169405
</ins><span class="cx"> template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 4&gt;::type* = nullptr&gt;
</span><del>-ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
</del><ins>+ALWAYS_INLINE Dependency dependency(T value)
</ins><span class="cx"> {
</span><del>-    uint32_t dependency;
</del><ins>+    unsigned dependency;
</ins><span class="cx">     uint32_t copy = bitwise_cast&lt;uint32_t&gt;(value);
</span><span class="cx"> #if CPU(ARM64)
</span><del>-    asm volatile(&quot;eor %w[dependency], %w[in], %w[in]&quot;
-                 : [dependency] &quot;=r&quot;(dependency)
-                 : [in] &quot;r&quot;(copy)
-                 : &quot;memory&quot;);
</del><ins>+    asm(&quot;eor %w[dependency], %w[in], %w[in]&quot;
+        : [dependency] &quot;=r&quot;(dependency)
+        : [in] &quot;r&quot;(copy));
</ins><span class="cx"> #elif CPU(ARM)
</span><del>-    asm volatile(&quot;eor %[dependency], %[in], %[in]&quot;
-                 : [dependency] &quot;=r&quot;(dependency)
-                 : [in] &quot;r&quot;(copy)
-                 : &quot;memory&quot;);
</del><ins>+    asm(&quot;eor %[dependency], %[in], %[in]&quot;
+        : [dependency] &quot;=r&quot;(dependency)
+        : [in] &quot;r&quot;(copy));
</ins><span class="cx"> #else
</span><span class="cx">     loadLoadFence();
</span><span class="cx">     dependency = 0;
</span><del>-    (void)copy;
</del><ins>+    UNUSED_PARAM(copy);
</ins><span class="cx"> #endif
</span><del>-    return static_cast&lt;ConsumeDependency&gt;(dependency);
</del><ins>+    return dependency;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 2&gt;::type* = nullptr&gt;
</span><del>-ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
</del><ins>+ALWAYS_INLINE Dependency dependency(T value)
</ins><span class="cx"> {
</span><del>-    uint16_t copy = bitwise_cast&lt;uint16_t&gt;(value);
-    return zeroWithConsumeDependency(static_cast&lt;size_t&gt;(copy));
</del><ins>+    return dependency(static_cast&lt;uint32_t&gt;(value));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 1&gt;::type* = nullptr&gt;
</span><del>-ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
</del><ins>+ALWAYS_INLINE Dependency dependency(T value)
</ins><span class="cx"> {
</span><del>-    uint8_t copy = bitwise_cast&lt;uint8_t&gt;(value);
-    return zeroWithConsumeDependency(static_cast&lt;size_t&gt;(copy));
</del><ins>+    return dependency(static_cast&lt;uint32_t&gt;(value));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-template &lt;typename T&gt;
-struct Consumed {
</del><ins>+template&lt;typename T&gt;
+struct DependencyWith {
+public:
+    DependencyWith()
+        : dependency(nullDependency())
+        , value()
+    {
+    }
+    
+    DependencyWith(Dependency dependency, const T&amp; value)
+        : dependency(dependency)
+        , value(value)
+    {
+    }
+    
+    Dependency dependency;
</ins><span class="cx">     T value;
</span><del>-    ConsumeDependency dependency;
</del><span class="cx"> };
</span><ins>+    
+template&lt;typename T&gt;
+inline DependencyWith&lt;T&gt; dependencyWith(Dependency dependency, const T&amp; value)
+{
+    return DependencyWith&lt;T&gt;(dependency, value);
+}
</ins><span class="cx"> 
</span><del>-// Consume load, returning the loaded `value` at `location` and a dependent-zero
-// which creates an address dependency from the `location`.
-//
-// Usage notes:
-//
-//  * Regarding control dependencies: merely branching based on `value` or
-//    `dependency` isn't sufficient to impose a dependency ordering: you must
-//    use `dependency` in the address computation of subsequent loads which
-//    should observe the store order w.r.t. `location`.
-// * Regarding memory ordering: consume load orders the `location` load with
-//   susequent dependent loads *only*. It says nothing about ordering of other
-//   loads!
-//
-// Caveat emptor.
-template &lt;typename T&gt;
-ALWAYS_INLINE auto consumeLoad(const T* location)
</del><ins>+template&lt;typename T&gt;
+inline T* consume(T* pointer, Dependency dependency)
</ins><span class="cx"> {
</span><del>-    typedef typename std::remove_cv&lt;T&gt;::type Returned;
-    Consumed&lt;Returned&gt; ret { };
-    // Force the read of `location` to occur exactly once and without fusing or
-    // forwarding using volatile. This is important because the compiler could
-    // otherwise rematerialize or find equivalent loads, or simply forward from
-    // a previous one, and lose the dependency we're trying so hard to
-    // create. Prevent tearing by using an atomic, but let it move around by
-    // using relaxed. We have at least a memory fence after this which prevents
-    // the load from moving too much.
-    ret.value = reinterpret_cast&lt;const volatile std::atomic&lt;Returned&gt;*&gt;(location)-&gt;load(std::memory_order_relaxed);
-    ret.dependency = zeroWithConsumeDependency(ret.value);
-    return ret;
</del><ins>+#if CPU(ARM64) || CPU(ARM)
+    return bitwise_cast&lt;T*&gt;(bitwise_cast&lt;char*&gt;(pointer) + dependency);
+#else
+    UNUSED_PARAM(dependency);
+    return pointer;
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WTF
</span><span class="cx"> 
</span><span class="cx"> using WTF::Atomic;
</span><del>-using WTF::ConsumeDependency;
-using WTF::consumeLoad;
</del><ins>+using WTF::Dependency;
+using WTF::DependencyWith;
+using WTF::TransactionAbortLikelihood;
+using WTF::consume;
+using WTF::dependency;
+using WTF::dependencyWith;
+using WTF::nullDependency;
</ins><span class="cx"> 
</span><span class="cx"> #endif // Atomics_h
</span></span></pre></div>
<a id="trunkSourceWTFwtfBitmaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Bitmap.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Bitmap.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/WTF/wtf/Bitmap.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -40,13 +40,13 @@
</span><span class="cx">         return bitmapSize;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    bool get(size_t) const;
</del><ins>+    bool get(size_t, Dependency = nullDependency()) const;
</ins><span class="cx">     void set(size_t);
</span><span class="cx">     void set(size_t, bool);
</span><span class="cx">     bool testAndSet(size_t);
</span><span class="cx">     bool testAndClear(size_t);
</span><del>-    bool concurrentTestAndSet(size_t);
-    bool concurrentTestAndClear(size_t);
</del><ins>+    bool concurrentTestAndSet(size_t, Dependency = nullDependency(), TransactionAbortLikelihood = TransactionAbortLikelihood::Likely);
+    bool concurrentTestAndClear(size_t, Dependency = nullDependency(), TransactionAbortLikelihood = TransactionAbortLikelihood::Likely);
</ins><span class="cx">     size_t nextPossiblyUnset(size_t) const;
</span><span class="cx">     void clear(size_t);
</span><span class="cx">     void clearAll();
</span><span class="lines">@@ -91,9 +91,9 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;size_t bitmapSize, typename WordType&gt;
</span><del>-inline bool Bitmap&lt;bitmapSize, WordType&gt;::get(size_t n) const
</del><ins>+inline bool Bitmap&lt;bitmapSize, WordType&gt;::get(size_t n, Dependency dependency) const
</ins><span class="cx"> {
</span><del>-    return !!(bits[n / wordSize] &amp; (one &lt;&lt; (n % wordSize)));
</del><ins>+    return !!(bits[n / wordSize + dependency] &amp; (one &lt;&lt; (n % wordSize)));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;size_t bitmapSize, typename WordType&gt;
</span><span class="lines">@@ -132,33 +132,37 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;size_t bitmapSize, typename WordType&gt;
</span><del>-inline bool Bitmap&lt;bitmapSize, WordType&gt;::concurrentTestAndSet(size_t n)
</del><ins>+ALWAYS_INLINE bool Bitmap&lt;bitmapSize, WordType&gt;::concurrentTestAndSet(size_t n, Dependency dependency, TransactionAbortLikelihood abortLikelihood)
</ins><span class="cx"> {
</span><span class="cx">     WordType mask = one &lt;&lt; (n % wordSize);
</span><span class="cx">     size_t index = n / wordSize;
</span><del>-    WordType* wordPtr = bits.data() + index;
-    WordType oldValue;
-    do {
-        oldValue = *wordPtr;
-        if (oldValue &amp; mask)
</del><ins>+    WordType* data = bits.data() + index + dependency;
+    return !bitwise_cast&lt;Atomic&lt;WordType&gt;*&gt;(data)-&gt;transactionRelaxed(
+        [&amp;] (WordType&amp; value) -&gt; bool {
+            if (value &amp; mask)
+                return false;
+            
+            value |= mask;
</ins><span class="cx">             return true;
</span><del>-    } while (!atomicCompareExchangeWeakRelaxed(wordPtr, oldValue, static_cast&lt;WordType&gt;(oldValue | mask)));
-    return false;
</del><ins>+        },
+        abortLikelihood);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;size_t bitmapSize, typename WordType&gt;
</span><del>-inline bool Bitmap&lt;bitmapSize, WordType&gt;::concurrentTestAndClear(size_t n)
</del><ins>+ALWAYS_INLINE bool Bitmap&lt;bitmapSize, WordType&gt;::concurrentTestAndClear(size_t n, Dependency dependency, TransactionAbortLikelihood abortLikelihood)
</ins><span class="cx"> {
</span><span class="cx">     WordType mask = one &lt;&lt; (n % wordSize);
</span><span class="cx">     size_t index = n / wordSize;
</span><del>-    WordType* wordPtr = bits.data() + index;
-    WordType oldValue;
-    do {
-        oldValue = *wordPtr;
-        if (!(oldValue &amp; mask))
-            return false;
-    } while (!atomicCompareExchangeWeakRelaxed(wordPtr, oldValue, static_cast&lt;WordType&gt;(oldValue &amp; ~mask)));
-    return true;
</del><ins>+    WordType* data = bits.data() + index + dependency;
+    return !bitwise_cast&lt;Atomic&lt;WordType&gt;*&gt;(data)-&gt;transactionRelaxed(
+        [&amp;] (WordType&amp; value) -&gt; bool {
+            if (!(value &amp; mask))
+                return false;
+            
+            value &amp;= ~mask;
+            return true;
+        },
+        abortLikelihood);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;size_t bitmapSize, typename WordType&gt;
</span></span></pre></div>
<a id="trunkSourceWTFwtfLockAlgorithmh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/LockAlgorithm.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/LockAlgorithm.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/WTF/wtf/LockAlgorithm.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -50,10 +50,15 @@
</span><span class="cx">     
</span><span class="cx">     static bool lockFast(Atomic&lt;LockType&gt;&amp; lock)
</span><span class="cx">     {
</span><del>-        LockType oldValue = lock.load(std::memory_order_relaxed);
-        if (oldValue &amp; isHeldBit)
-            return false;
-        return lock.compareExchangeWeak(oldValue, oldValue | isHeldBit, std::memory_order_acquire);
</del><ins>+        return lock.transaction(
+            [&amp;] (LockType&amp; value) -&gt; bool {
+                if (value &amp; isHeldBit)
+                    return false;
+                value |= isHeldBit;
+                return true;
+            },
+            std::memory_order_acquire,
+            TransactionAbortLikelihood::Unlikely);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     static void lock(Atomic&lt;LockType&gt;&amp; lock)
</span><span class="lines">@@ -80,10 +85,15 @@
</span><span class="cx">     
</span><span class="cx">     static bool unlockFast(Atomic&lt;LockType&gt;&amp; lock)
</span><span class="cx">     {
</span><del>-        LockType oldValue = lock.load(std::memory_order_relaxed);
-        if ((oldValue &amp; mask) != isHeldBit)
-            return false;
-        return lock.compareExchangeWeak(oldValue, oldValue &amp; ~isHeldBit, std::memory_order_release);
</del><ins>+        return lock.transaction(
+            [&amp;] (LockType&amp; value) -&gt; bool {
+                if ((value &amp; mask) != isHeldBit)
+                    return false;
+                value &amp;= ~isHeldBit;
+                return true;
+            },
+            std::memory_order_relaxed,
+            TransactionAbortLikelihood::Unlikely);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     static void unlock(Atomic&lt;LockType&gt;&amp; lock)
</span><span class="lines">@@ -206,10 +216,11 @@
</span><span class="cx">                     }
</span><span class="cx">                     
</span><span class="cx">                     lock.transaction(
</span><del>-                        [&amp;] (LockType&amp; value) {
</del><ins>+                        [&amp;] (LockType&amp; value) -&gt; bool {
</ins><span class="cx">                             value &amp;= ~mask;
</span><span class="cx">                             if (result.mayHaveMoreThreads)
</span><span class="cx">                                 value |= hasParkedBit;
</span><ins>+                            return true;
</ins><span class="cx">                         });
</span><span class="cx">                     return BargingOpportunity;
</span><span class="cx">                 });
</span></span></pre></div>
<a id="trunkSourceWTFwtfPlatformh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Platform.h (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Platform.h        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Source/WTF/wtf/Platform.h        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -757,6 +757,10 @@
</span><span class="cx"> #define ENABLE_CONCURRENT_JS 1
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if CPU(ARM64)
+#define HAVE_LL_SC 1
+#endif // CPU(ARM64)
+
</ins><span class="cx"> /* This controls whether B3 is built. B3 is needed for FTL JIT and WebAssembly */
</span><span class="cx"> #if ENABLE(FTL_JIT) || ENABLE(WEBASSEMBLY)
</span><span class="cx"> #define ENABLE_B3_JIT 1
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Tools/ChangeLog        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2017-03-08  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        WTF should make it super easy to do ARM concurrency tricks
+        https://bugs.webkit.org/show_bug.cgi?id=169300
+
+        Reviewed by Mark Lam.
+        
+        This vastly simplifies the consume API. The new API is thoroughly tested by being used
+        in the GC's guts. I think that unit tests are a pain to maintain, so we shouldn't have
+        them unless we are legitimately worried about coverage. We're not in this case.
+
+        * TestWebKitAPI/CMakeLists.txt:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WTF/Consume.cpp: Removed.
+
</ins><span class="cx"> 2017-03-08  Srinivasan Vijayaraghavan  &lt;svijayaraghavan@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix error/warning duplication in JSON bindings results
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPICMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/CMakeLists.txt        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -42,7 +42,6 @@
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/TestsController.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/AtomicString.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/BloomFilter.cpp
</span><del>-    ${TESTWEBKITAPI_DIR}/Tests/WTF/Consume.cpp
</del><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/CrossThreadTask.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/CString.cpp
</span><span class="cx">     ${TESTWEBKITAPI_DIR}/Tests/WTF/CheckedArithmeticOperations.cpp
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestWebKitAPIxcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -492,7 +492,6 @@
</span><span class="cx">                 AD57AC211DA7465B00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD57AC1F1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp */; };
</span><span class="cx">                 AD57AC221DA7466E00FF1BDE /* many-iframes.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = AD57AC1D1DA7463800FF1BDE /* many-iframes.html */; };
</span><span class="cx">                 AD7C434D1DD2A54E0026888B /* Expected.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AD7C434C1DD2A5470026888B /* Expected.cpp */; };
</span><del>-                ADCEBBA61D9AE229002E283A /* Consume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADCEBBA51D99D4CF002E283A /* Consume.cpp */; };
</del><span class="cx">                 B55AD1D5179F3B3000AC1494 /* PreventImageLoadWithAutoResizing_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55AD1D3179F3ABF00AC1494 /* PreventImageLoadWithAutoResizing_Bundle.cpp */; };
</span><span class="cx">                 B55F11B71517D03300915916 /* attributedStringCustomFont.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = B55F11B01517A2C400915916 /* attributedStringCustomFont.html */; };
</span><span class="cx">                 B55F11BE15191A0600915916 /* Ahem.ttf in Copy Resources */ = {isa = PBXBuildFile; fileRef = B55F11B9151916E600915916 /* Ahem.ttf */; };
</span><span class="lines">@@ -1247,7 +1246,6 @@
</span><span class="cx">                 AD57AC1E1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidRemoveFrameFromHiearchyInPageCache_Bundle.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 AD57AC1F1DA7464D00FF1BDE /* DidRemoveFrameFromHiearchyInPageCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DidRemoveFrameFromHiearchyInPageCache.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 AD7C434C1DD2A5470026888B /* Expected.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Expected.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                ADCEBBA51D99D4CF002E283A /* Consume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Consume.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><span class="cx">                 B4039F9C15E6D8B3007255D6 /* MathExtras.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MathExtras.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 B55AD1D1179F336600AC1494 /* PreventImageLoadWithAutoResizing.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = PreventImageLoadWithAutoResizing.mm; path = WebKit2ObjC/PreventImageLoadWithAutoResizing.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 B55AD1D3179F3ABF00AC1494 /* PreventImageLoadWithAutoResizing_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PreventImageLoadWithAutoResizing_Bundle.cpp; path = WebKit2ObjC/PreventImageLoadWithAutoResizing_Bundle.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -2025,7 +2023,6 @@
</span><span class="cx">                                 E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */,
</span><span class="cx">                                 A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */,
</span><span class="cx">                                 0FEAE3671B7D19CB00CE17F2 /* Condition.cpp */,
</span><del>-                                ADCEBBA51D99D4CF002E283A /* Consume.cpp */,
</del><span class="cx">                                 51714EB91D087416004723C4 /* CrossThreadTask.cpp */,
</span><span class="cx">                                 26A2C72E15E2E73C005B1A14 /* CString.cpp */,
</span><span class="cx">                                 7AA021BA1AB09EA70052953F /* DateMath.cpp */,
</span><span class="lines">@@ -2594,7 +2591,6 @@
</span><span class="cx">                                 7C83DEFE1D0A590C00FEBCF3 /* NakedPtr.cpp in Sources */,
</span><span class="cx">                                 531C1D8E1DF8EF72006E979F /* LEBDecoder.cpp in Sources */,
</span><span class="cx">                                 7C83DF011D0A590C00FEBCF3 /* Optional.cpp in Sources */,
</span><del>-                                ADCEBBA61D9AE229002E283A /* Consume.cpp in Sources */,
</del><span class="cx">                                 AD7C434D1DD2A54E0026888B /* Expected.cpp in Sources */,
</span><span class="cx">                                 7C83DF021D0A590C00FEBCF3 /* OSObjectPtr.cpp in Sources */,
</span><span class="cx">                                 7C83DF591D0A590C00FEBCF3 /* ParkingLot.cpp in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWTFConsumecpp"></a>
<div class="delfile"><h4>Deleted: trunk/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp (213644 => 213645)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp        2017-03-09 17:40:06 UTC (rev 213644)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp        2017-03-09 17:40:10 UTC (rev 213645)
</span><span class="lines">@@ -1,141 +0,0 @@
</span><del>-/*
- * Copyright (C) 2016 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;thread&gt;
-#include &lt;wtf/Atomics.h&gt;
-
-template &lt;typename T&gt;
-NEVER_INLINE auto testConsume(const T* location)
-{
-    WTF::compilerFence(); // Paranoid testing.
-    auto ret = WTF::consumeLoad(location);
-    WTF::compilerFence(); // Paranoid testing.
-    return ret;
-}
-
-namespace TestWebKitAPI {
-
-TEST(WTF, Consumei8)
-{
-    uint8_t i8 = 42;
-    auto i8_consumed = testConsume(&amp;i8);
-    ASSERT_EQ(i8_consumed.value, 42u);
-    ASSERT_EQ(i8_consumed.dependency, 0u);
-}
-
-TEST(WTF, Consumei16)
-{
-    uint16_t i16 = 42;
-    auto i16_consumed = testConsume(&amp;i16);
-    ASSERT_EQ(i16_consumed.value, 42u);
-    ASSERT_EQ(i16_consumed.dependency, 0u);
-}
-
-TEST(WTF, Consumei32)
-{
-    uint32_t i32 = 42;
-    auto i32_consumed = testConsume(&amp;i32);
-    ASSERT_EQ(i32_consumed.value, 42u);
-    ASSERT_EQ(i32_consumed.dependency, 0u);
-}
-
-TEST(WTF, Consumei64)
-{
-    uint64_t i64 = 42;
-    auto i64_consumed = testConsume(&amp;i64);
-    ASSERT_EQ(i64_consumed.value, 42u);
-    ASSERT_EQ(i64_consumed.dependency, 0u);
-}
-
-TEST(WTF, Consumef32)
-{
-    float f32 = 42.f;
-    auto f32_consumed = testConsume(&amp;f32);
-    ASSERT_EQ(f32_consumed.value, 42.f);
-    ASSERT_EQ(f32_consumed.dependency, 0u);
-}
-
-TEST(WTF, Consumef64)
-{
-    double f64 = 42.;
-    auto f64_consumed = testConsume(&amp;f64);
-    ASSERT_EQ(f64_consumed.value, 42.);
-    ASSERT_EQ(f64_consumed.dependency, 0u);
-}
-
-static int* global;
-
-TEST(WTF, ConsumeGlobalPtr)
-{
-    auto* ptr = &amp;global;
-    auto ptr_consumed = testConsume(&amp;ptr);
-    ASSERT_EQ(ptr_consumed.value, &amp;global);
-    ASSERT_EQ(ptr_consumed.dependency, 0u);
-}
-
-static int* globalArray[128];
-
-TEST(WTF, ConsumeGlobalArrayPtr)
-{
-    auto* ptr = &amp;globalArray[64];
-    auto ptr_consumed = testConsume(&amp;ptr);
-    ASSERT_EQ(ptr_consumed.value, &amp;globalArray[64]);
-    ASSERT_EQ(ptr_consumed.dependency, 0u);
-}
-
-TEST(WTF, ConsumeStackPtr)
-{
-    char* hello = nullptr;
-    auto* stack = &amp;hello;
-    auto stack_consumed = testConsume(&amp;stack);
-    ASSERT_EQ(stack_consumed.value, &amp;hello);
-    ASSERT_EQ(stack_consumed.dependency, 0u);
-}
-
-TEST(WTF, ConsumeWithThread)
-{
-    bool ready = false;
-    constexpr size_t num = 1024;
-    uint32_t* vec = new uint32_t[num];
-    std::thread t([&amp;]() {
-        for (size_t i = 0; i != num; ++i)
-            vec[i] = i * 2;
-        WTF::storeStoreFence();
-        ready = true;
-    });
-    do {
-        auto stack_consumed = testConsume(&amp;ready);
-        if (stack_consumed.value) {
-            for (size_t i = 0; i != num; ++i)
-                ASSERT_EQ(vec[i + stack_consumed.dependency], i * 2);
-            break;
-        }
-    } while (true);
-    t.join();
-    delete[] vec;
-}
-}
</del></span></pre>
</div>
</div>

</body>
</html>