<!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>[206470] 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/206470">206470</a></dd>
<dt>Author</dt> <dd>jfbastien@apple.com</dd>
<dt>Date</dt> <dd>2016-09-27 16:41:34 -0700 (Tue, 27 Sep 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Speed up Heap::isMarkedConcurrently
https://bugs.webkit.org/show_bug.cgi?id=162095

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Speed up isMarkedConcurrently by using WTF::consumeLoad.

* heap/MarkedBlock.h:
(JSC::MarkedBlock::areMarksStale):
(JSC::MarkedBlock::areMarksStaleWithDependency):
(JSC::MarkedBlock::isMarkedConcurrently): do away with the load-load fence

Source/WTF:

Heap::isMarkedConcurrently had a load-load fence which is expensive on weak memory ISAs such as ARM.

This patch is fairly perf-neutral overall, but the GC's instrumentation reports:
  GC:Eden is 93% average runtime after change
  GC:Full is 76% average runtime after change

The fence was there because:
 1. If the read of m_markingVersion in MarkedBlock::areMarksStale isn't what's expected then;
 2. The read of m_marks in MarkedBlock::isMarked needs to observe the value that was stored *before* m_markingVersion was stored.

This ordering isn't guaranteed on ARM, which has a weak memory model.

There are 3 ways to guarantee this ordering:
 A. Use a barrier instruction.
 B. Use a load-acquire (new in ARMv8).
 C. use ARM's address dependency rule, which C++ calls memory_order_consume.

In general:
 A. is slow but orders all of memory in an intuitive manner.
 B. is faster-ish and has the same property-ish.
 C. should be faster still, but *only orders dependent loads*. This last part is critical! Consume isn't an all-out replacement for acquire (acquire is rather a superset of consume).

ARM explains the address dependency rule in their document &quot;barrier litmus tests and cookbook&quot;:

&gt; *Resolving by the use of barriers and address dependency*
&gt;
&gt; There is a rule within the ARM architecture that:
&gt; Where the value returned by a read is used to compute the virtual address of a subsequent read or write (this is known as an address dependency), then these two memory accesses will be observed in program order. An address dependency exists even if the value read by the first read has no effect in changing the virtual address (as might be the case if the value returned is masked off before it is used, or if it had no effect on changing a predicted address value).
&gt; This restriction applies only when the data value returned from one read is used as a data value to calculate the address of a subsequent read or write. This does not apply if the data value returned from one read is used to determine the condition code flags, and the values of the flags are used for condition code evaluation to determine the address of a subsequent reads, either through conditional execution or the evaluation of a branch. This is known as a control dependency.
&gt; Where both a control and address dependency exist, the ordering behaviour is consistent with the address dependency.

C++'s memory_order_consume is unfortunately unimplemented by C++ compilers, and maybe unimplementable as spec'd. I'm working with interested folks in the committee to fix this situation: http://wg21.link/p0190r2

* wtf/Atomics.h:
(WTF::zeroWithConsumeDependency): a 0 which carries a dependency
(WTF::consumeLoad): pixie magic

Tools:

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

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkedBlockh">trunk/Source/JavaScriptCore/heap/MarkedBlock.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="#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>Added 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 (206469 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-09-27 23:33:08 UTC (rev 206469)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2016-09-27  JF Bastien  &lt;jfbastien@apple.com&gt;
+
+        Speed up Heap::isMarkedConcurrently
+        https://bugs.webkit.org/show_bug.cgi?id=162095
+
+        Reviewed by Filip Pizlo.
+
+        Speed up isMarkedConcurrently by using WTF::consumeLoad.
+
+        * heap/MarkedBlock.h:
+        (JSC::MarkedBlock::areMarksStale):
+        (JSC::MarkedBlock::areMarksStaleWithDependency):
+        (JSC::MarkedBlock::isMarkedConcurrently): do away with the load-load fence
+
</ins><span class="cx"> 2016-09-27  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add some needed CatchScopes in code that should not throw.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkedBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/MarkedBlock.h (206469 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkedBlock.h        2016-09-27 23:33:08 UTC (rev 206469)
+++ trunk/Source/JavaScriptCore/heap/MarkedBlock.h        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -269,9 +269,14 @@
</span><span class="cx">     void noteMarked();
</span><span class="cx">         
</span><span class="cx">     WeakSet&amp; weakSet();
</span><del>-    
</del><ins>+
+    bool areMarksStale();
</ins><span class="cx">     bool areMarksStale(HeapVersion markingVersion);
</span><del>-    bool areMarksStale();
</del><ins>+    struct MarksWithDependency {
+        bool areStale;
+        ConsumeDependency dependency;
+    };
+    MarksWithDependency areMarksStaleWithDependency(HeapVersion markingVersion);
</ins><span class="cx">     
</span><span class="cx">     void aboutToMark(HeapVersion markingVersion);
</span><span class="cx">         
</span><span class="lines">@@ -474,6 +479,15 @@
</span><span class="cx">     return markingVersion != m_markingVersion;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE MarkedBlock::MarksWithDependency MarkedBlock::areMarksStaleWithDependency(HeapVersion markingVersion)
+{
+    auto consumed = consumeLoad(&amp;m_markingVersion);
+    MarksWithDependency ret;
+    ret.areStale = consumed.value != markingVersion;
+    ret.dependency = consumed.dependency;
+    return ret;
+}
+
</ins><span class="cx"> inline void MarkedBlock::aboutToMark(HeapVersion markingVersion)
</span><span class="cx"> {
</span><span class="cx">     if (UNLIKELY(areMarksStale(markingVersion)))
</span><span class="lines">@@ -499,10 +513,10 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool MarkedBlock::isMarkedConcurrently(HeapVersion markingVersion, const void* p)
</span><span class="cx"> {
</span><del>-    if (areMarksStale(markingVersion))
</del><ins>+    auto marksWithDependency = areMarksStaleWithDependency(markingVersion);
+    if (marksWithDependency.areStale)
</ins><span class="cx">         return false;
</span><del>-    WTF::loadLoadFence();
-    return m_marks.get(atomNumber(p));
</del><ins>+    return m_marks.get(atomNumber(p) + marksWithDependency.dependency);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool MarkedBlock::testAndSetMarked(const void* p)
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (206469 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2016-09-27 23:33:08 UTC (rev 206469)
+++ trunk/Source/WTF/ChangeLog        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -1,5 +1,49 @@
</span><span class="cx"> 2016-09-27  JF Bastien  &lt;jfbastien@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Speed up Heap::isMarkedConcurrently
+        https://bugs.webkit.org/show_bug.cgi?id=162095
+
+        Reviewed by Filip Pizlo.
+
+        Heap::isMarkedConcurrently had a load-load fence which is expensive on weak memory ISAs such as ARM.
+
+        This patch is fairly perf-neutral overall, but the GC's instrumentation reports:
+          GC:Eden is 93% average runtime after change
+          GC:Full is 76% average runtime after change
+
+        The fence was there because:
+         1. If the read of m_markingVersion in MarkedBlock::areMarksStale isn't what's expected then;
+         2. The read of m_marks in MarkedBlock::isMarked needs to observe the value that was stored *before* m_markingVersion was stored.
+
+        This ordering isn't guaranteed on ARM, which has a weak memory model.
+
+        There are 3 ways to guarantee this ordering:
+         A. Use a barrier instruction.
+         B. Use a load-acquire (new in ARMv8).
+         C. use ARM's address dependency rule, which C++ calls memory_order_consume.
+
+        In general:
+         A. is slow but orders all of memory in an intuitive manner.
+         B. is faster-ish and has the same property-ish.
+         C. should be faster still, but *only orders dependent loads*. This last part is critical! Consume isn't an all-out replacement for acquire (acquire is rather a superset of consume).
+
+        ARM explains the address dependency rule in their document &quot;barrier litmus tests and cookbook&quot;:
+
+        &gt; *Resolving by the use of barriers and address dependency*
+        &gt;
+        &gt; There is a rule within the ARM architecture that:
+        &gt; Where the value returned by a read is used to compute the virtual address of a subsequent read or write (this is known as an address dependency), then these two memory accesses will be observed in program order. An address dependency exists even if the value read by the first read has no effect in changing the virtual address (as might be the case if the value returned is masked off before it is used, or if it had no effect on changing a predicted address value).
+        &gt; This restriction applies only when the data value returned from one read is used as a data value to calculate the address of a subsequent read or write. This does not apply if the data value returned from one read is used to determine the condition code flags, and the values of the flags are used for condition code evaluation to determine the address of a subsequent reads, either through conditional execution or the evaluation of a branch. This is known as a control dependency.
+        &gt; Where both a control and address dependency exist, the ordering behaviour is consistent with the address dependency.
+
+        C++'s memory_order_consume is unfortunately unimplemented by C++ compilers, and maybe unimplementable as spec'd. I'm working with interested folks in the committee to fix this situation: http://wg21.link/p0190r2
+
+        * wtf/Atomics.h:
+        (WTF::zeroWithConsumeDependency): a 0 which carries a dependency
+        (WTF::consumeLoad): pixie magic
+
+2016-09-27  JF Bastien  &lt;jfbastien@apple.com&gt;
+
</ins><span class="cx">         Atomics.h on Windows: remove seq_cst hack
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=162022
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWTFwtfAtomicsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Atomics.h (206469 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Atomics.h        2016-09-27 23:33:08 UTC (rev 206469)
+++ trunk/Source/WTF/wtf/Atomics.h        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -168,8 +168,121 @@
</span><span class="cx"> 
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+typedef size_t ConsumeDependency;
+
+template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 8&gt;::type* = nullptr&gt;
+ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
+{
+    uint64_t dependency;
+    uint64_t copy = bitwise_cast&lt;uint64_t&gt;(value);
+#if CPU(ARM64)
+    // Create a magical zero value through inline assembly, whose computation
+    // isn't visible to the optimizer. This zero is then usable as an offset in
+    // further address computations: adding zero does nothing, but the compiler
+    // doesn't know it. It's magical because it creates an address dependency
+    // from the load of `location` to the uses of the dependency, which triggers
+    // the ARM ISA's address dependency rule, a.k.a. the mythical C++ consume
+    // ordering. This forces weak memory order CPUs to observe `location` and
+    // dependent loads in their store order without the reader using a barrier
+    // or an acquire load.
+    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;);
+#elif CPU(ARM)
+    asm volatile(&quot;eor %[dependency], %[in], %[in]&quot;
+                 : [dependency] &quot;=r&quot;(dependency)
+                 : [in] &quot;r&quot;(copy)
+                 : &quot;memory&quot;);
+#else
+    // No dependency is needed for this architecture.
+    loadLoadFence();
+    dependency = 0;
+    (void)copy;
+#endif
+    return static_cast&lt;ConsumeDependency&gt;(dependency);
+}
+
+template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 4&gt;::type* = nullptr&gt;
+ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
+{
+    uint32_t dependency;
+    uint32_t copy = bitwise_cast&lt;uint32_t&gt;(value);
+#if CPU(ARM64)
+    asm volatile(&quot;eor %w[dependency], %w[in], %w[in]&quot;
+                 : [dependency] &quot;=r&quot;(dependency)
+                 : [in] &quot;r&quot;(copy)
+                 : &quot;memory&quot;);
+#elif CPU(ARM)
+    asm volatile(&quot;eor %[dependency], %[in], %[in]&quot;
+                 : [dependency] &quot;=r&quot;(dependency)
+                 : [in] &quot;r&quot;(copy)
+                 : &quot;memory&quot;);
+#else
+    loadLoadFence();
+    dependency = 0;
+    (void)copy;
+#endif
+    return static_cast&lt;ConsumeDependency&gt;(dependency);
+}
+
+template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 2&gt;::type* = nullptr&gt;
+ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
+{
+    uint16_t copy = bitwise_cast&lt;uint16_t&gt;(value);
+    return zeroWithConsumeDependency(static_cast&lt;size_t&gt;(copy));
+}
+
+template &lt;typename T, typename std::enable_if&lt;sizeof(T) == 1&gt;::type* = nullptr&gt;
+ALWAYS_INLINE ConsumeDependency zeroWithConsumeDependency(T value)
+{
+    uint8_t copy = bitwise_cast&lt;uint8_t&gt;(value);
+    return zeroWithConsumeDependency(static_cast&lt;size_t&gt;(copy));
+}
+
+template &lt;typename T&gt;
+struct Consumed {
+    T value;
+    ConsumeDependency dependency;
+};
+
+// 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)
+{
+    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;
+}
+
</ins><span class="cx"> } // namespace WTF
</span><span class="cx"> 
</span><span class="cx"> using WTF::Atomic;
</span><ins>+using WTF::ConsumeDependency;
+using WTF::consumeLoad;
</ins><span class="cx"> 
</span><span class="cx"> #endif // Atomics_h
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (206469 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2016-09-27 23:33:08 UTC (rev 206469)
+++ trunk/Tools/ChangeLog        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-09-27  JF Bastien  &lt;jfbastien@apple.com&gt;
+
+        Speed up Heap::isMarkedConcurrently
+        https://bugs.webkit.org/show_bug.cgi?id=162095
+
+        Reviewed by Filip Pizlo.
+
+        * TestWebKitAPI/CMakeLists.txt:
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/WTF/Consume.cpp: Added.
+        (testConsume):
+        (TestWebKitAPI::TEST):
+
</ins><span class="cx"> 2016-09-26  Alex Christensen  &lt;achristensen@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Implement URLParser::syntaxViolation
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPICMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/CMakeLists.txt (206469 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/CMakeLists.txt        2016-09-27 23:33:08 UTC (rev 206469)
+++ trunk/Tools/TestWebKitAPI/CMakeLists.txt        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -42,6 +42,7 @@
</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><ins>+    ${TESTWEBKITAPI_DIR}/Tests/WTF/Consume.cpp
</ins><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 (206469 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-09-27 23:33:08 UTC (rev 206469)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -431,6 +431,7 @@
</span><span class="cx">                 A1DF74321C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm in Sources */ = {isa = PBXBuildFile; fileRef = A1DF74301C41B65800A2F4D0 /* AlwaysRevalidatedURLSchemes.mm */; };
</span><span class="cx">                 A57A34F216AF6B2B00C2501F /* PageVisibilityStateWithWindowChanges.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A57A34F116AF69E200C2501F /* PageVisibilityStateWithWindowChanges.html */; };
</span><span class="cx">                 A5E2027515B21F6E00C13E14 /* WindowlessWebViewWithMedia.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = A5E2027015B2180600C13E14 /* WindowlessWebViewWithMedia.html */; };
</span><ins>+                ADCEBBA61D9AE229002E283A /* Consume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ADCEBBA51D99D4CF002E283A /* Consume.cpp */; };
</ins><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">@@ -1056,6 +1057,7 @@
</span><span class="cx">                 A5E2027015B2180600C13E14 /* WindowlessWebViewWithMedia.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = WindowlessWebViewWithMedia.html; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A5E2027215B2181900C13E14 /* WindowlessWebViewWithMedia.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WindowlessWebViewWithMedia.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CheckedArithmeticOperations.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                ADCEBBA51D99D4CF002E283A /* Consume.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Consume.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><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">@@ -1730,6 +1732,7 @@
</span><span class="cx">                                 E40019301ACE9B5C001B0A2A /* BloomFilter.cpp */,
</span><span class="cx">                                 A7A966DA140ECCC8005EF9B4 /* CheckedArithmeticOperations.cpp */,
</span><span class="cx">                                 0FEAE3671B7D19CB00CE17F2 /* Condition.cpp */,
</span><ins>+                                ADCEBBA51D99D4CF002E283A /* Consume.cpp */,
</ins><span class="cx">                                 51714EB91D087416004723C4 /* CrossThreadTask.cpp */,
</span><span class="cx">                                 26A2C72E15E2E73C005B1A14 /* CString.cpp */,
</span><span class="cx">                                 7AA021BA1AB09EA70052953F /* DateMath.cpp */,
</span><span class="lines">@@ -2242,6 +2245,7 @@
</span><span class="cx">                                 7C83DEF61D0A590C00FEBCF3 /* MetaAllocator.cpp in Sources */,
</span><span class="cx">                                 7C83DEFE1D0A590C00FEBCF3 /* NakedPtr.cpp in Sources */,
</span><span class="cx">                                 7C83DF011D0A590C00FEBCF3 /* Optional.cpp in Sources */,
</span><ins>+                                ADCEBBA61D9AE229002E283A /* Consume.cpp in Sources */,
</ins><span class="cx">                                 7C83DF021D0A590C00FEBCF3 /* OSObjectPtr.cpp in Sources */,
</span><span class="cx">                                 7C83DF591D0A590C00FEBCF3 /* ParkingLot.cpp in Sources */,
</span><span class="cx">                                 7C83DF131D0A590C00FEBCF3 /* RedBlackTree.cpp in Sources */,
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsWTFConsumecpp"></a>
<div class="addfile"><h4>Added: trunk/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp (0 => 206470)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp                                (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WTF/Consume.cpp        2016-09-27 23:41:34 UTC (rev 206470)
</span><span class="lines">@@ -0,0 +1,141 @@
</span><ins>+/*
+ * 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;
+}
+}
</ins></span></pre>
</div>
</div>

</body>
</html>