<!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>[208897] 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/208897">208897</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-11-18 14:11:51 -0800 (Fri, 18 Nov 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Concurrent GC should be able to run splay in debug mode and earley/raytrace in release mode with no perf regression
https://bugs.webkit.org/show_bug.cgi?id=164282

Reviewed by Geoffrey Garen and Oliver Hunt.
        
PerformanceTests:

CDjs is a fun benchmark for stressing concurrent GCs, but to really give the GC a good
workout you need to increase the amount of work that the test does. This adds a second
configuration of the benchmark that has more aircraft. It uses much more memory and causes us
to do more GCs and those GCs take longer.

* JetStream/cdjs/benchmark.js:
(benchmarkImpl):
(benchmark):
* JetStream/cdjs/large.js: Added.

Source/JavaScriptCore:

The two three remaining bugs were:

- Improper ordering inside putDirectWithoutTransition() and friends. We need to make sure
  that the GC doesn't see the store to Structure::m_offset until we've resized the butterfly.
  That proved a bit tricky. On the other hand, this means that we could probably remove the
  requirement that the GC holds the Structure lock in some cases. I haven't removed that lock
  yet because I still think it might protect some weird cases, and it doesn't seem to cost us
  anything.
        
- CodeBlock's GC strategy needed to be made thread-safe (visitWeakly, visitChildren, and
  their friends now hold locks) and incremental-safe (we need to update predictions in the
  finalizer to make sure we clear anything that was put into a value profile towards the end
  of GC).
        
- The GC timeslicing scheduler needed to be made a bit more aggressive to deal with
  generational workloads like earley, raytrace, and CDjs. Once I got those benchmarks to run,
  I found that they would do many useless iterations of GC because they wouldn't pause long
  enough after rescanning weak references and roots. I added a bunch of knobs for forcing a
  pause. In the end, I realized that I could get the desired effect by putting a ceiling on
  mutator utilization. We want the GC to finish quickly if it is possible to do so, even if
  the amount of allocation that the mutator had done is low. Having a utilization ceiling
  seems to accomplish this for benchmarks with trivial heaps (earley and raytrace) as well as
  huge heaps (like CDjs in its &quot;large&quot; configuration).
        
This preserves splay performance, makes the concurrent GC more stable, and makes the
concurrent GC not a perf regression on earley or raytrace. It seems to give us great CDjs
performance as well, but this is still hard to tell because we crash a lot in that benchmark.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::visitWeakly):
(JSC::CodeBlock::visitChildren):
(JSC::CodeBlock::shouldVisitStrongly):
(JSC::CodeBlock::shouldJettisonDueToOldAge):
(JSC::CodeBlock::propagateTransitions):
(JSC::CodeBlock::determineLiveness):
(JSC::CodeBlock::WeakReferenceHarvester::visitWeakReferences):
(JSC::CodeBlock::UnconditionalFinalizer::finalizeUnconditionally):
(JSC::CodeBlock::visitOSRExitTargets):
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::stronglyVisitWeakReferences):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::clearVisitWeaklyHasBeenCalled):
* heap/CodeBlockSet.cpp:
(JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced):
* heap/Heap.cpp:
(JSC::Heap::ResumeTheWorldScope::ResumeTheWorldScope):
(JSC::Heap::markToFixpoint):
(JSC::Heap::beginMarking):
(JSC::Heap::addToRememberedSet):
(JSC::Heap::collectInThread):
* heap/Heap.h:
* heap/HeapInlines.h:
(JSC::Heap::mutatorFence):
* heap/MarkedBlock.cpp:
* runtime/JSCellInlines.h:
(JSC::JSCell::finishCreation):
* runtime/JSObjectInlines.h:
(JSC::JSObject::putDirectWithoutTransition):
(JSC::JSObject::putDirectInternal):
* runtime/Options.h:
* runtime/Structure.cpp:
(JSC::Structure::add):
* runtime/Structure.h:
* runtime/StructureInlines.h:
(JSC::Structure::add):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsChangeLog">trunk/PerformanceTests/ChangeLog</a></li>
<li><a href="#trunkPerformanceTestsJetStreamcdjsbenchmarkjs">trunk/PerformanceTests/JetStream/cdjs/benchmark.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSetcpp">trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapInlinesh">trunk/Source/JavaScriptCore/heap/HeapInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkedBlockcpp">trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSCellInlinesh">trunk/Source/JavaScriptCore/runtime/JSCellInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSObjectInlinesh">trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructurecpp">trunk/Source/JavaScriptCore/runtime/Structure.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureh">trunk/Source/JavaScriptCore/runtime/Structure.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStructureInlinesh">trunk/Source/JavaScriptCore/runtime/StructureInlines.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkPerformanceTestsJetStreamcdjslargejs">trunk/PerformanceTests/JetStream/cdjs/large.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkPerformanceTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/ChangeLog (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/ChangeLog        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/PerformanceTests/ChangeLog        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2016-11-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Concurrent GC should be able to run splay in debug mode and earley/raytrace in release mode with no perf regression
+        https://bugs.webkit.org/show_bug.cgi?id=164282
+
+        Reviewed by Geoffrey Garen and Oliver Hunt.
+        
+        CDjs is a fun benchmark for stressing concurrent GCs, but to really give the GC a good
+        workout you need to increase the amount of work that the test does. This adds a second
+        configuration of the benchmark that has more aircraft. It uses much more memory and causes us
+        to do more GCs and those GCs take longer.
+
+        * JetStream/cdjs/benchmark.js:
+        (benchmarkImpl):
+        (benchmark):
+        * JetStream/cdjs/large.js: Added.
+
</ins><span class="cx"> 2016-11-14  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, revert unintended change.
</span></span></pre></div>
<a id="trunkPerformanceTestsJetStreamcdjsbenchmarkjs"></a>
<div class="modfile"><h4>Modified: trunk/PerformanceTests/JetStream/cdjs/benchmark.js (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/JetStream/cdjs/benchmark.js        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/PerformanceTests/JetStream/cdjs/benchmark.js        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> // Copyright (c) 2001-2010, Purdue University. All rights reserved.
</span><del>-// Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+// Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx"> // 
</span><span class="cx"> // Redistribution and use in source and binary forms, with or without
</span><span class="cx"> // modification, are permitted provided that the following conditions are met:
</span><span class="lines">@@ -23,12 +23,12 @@
</span><span class="cx"> // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
</span><span class="cx"> // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx"> 
</span><del>-function benchmark() {
-    var verbosity = 0;
-    var numAircraft = 1000;
-    var numFrames = 200;
-    var expectedCollisions = 14484;
-    var percentile = 95;
</del><ins>+function benchmarkImpl(configuration) {
+    var verbosity = configuration.verbosity;
+    var numAircraft = configuration.numAircraft;
+    var numFrames = configuration.numFrames;
+    var expectedCollisions = configuration.expectedCollisions;
+    var percentile = configuration.percentile;
</ins><span class="cx"> 
</span><span class="cx">     var simulator = new Simulator(numAircraft);
</span><span class="cx">     var detector = new CollisionDetector();
</span><span class="lines">@@ -78,3 +78,24 @@
</span><span class="cx">     
</span><span class="cx">     return averageAbovePercentile(times, percentile);
</span><span class="cx"> }
</span><ins>+
+function benchmark() {
+    return benchmarkImpl({
+        verbosity: 0,
+        numAircraft: 1000,
+        numFrames: 200,
+        expectedCollisions: 14484,
+        percentile: 95
+    });
+}
+
+function largeBenchmark() {
+    return benchmarkImpl({
+        verbosity: 0,
+        numAircraft: 20000,
+        numFrames: 100,
+        expectedCollisions: 5827,
+        percentile: 95
+    });
+}
+
</ins></span></pre></div>
<a id="trunkPerformanceTestsJetStreamcdjslargejs"></a>
<div class="addfile"><h4>Added: trunk/PerformanceTests/JetStream/cdjs/large.js (0 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/PerformanceTests/JetStream/cdjs/large.js                                (rev 0)
+++ trunk/PerformanceTests/JetStream/cdjs/large.js        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+// Copyright (c) 2001-2010, Purdue University. All rights reserved.
+// 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:
+//  * Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+//  * 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.
+//  * Neither the name of the Purdue University nor the
+//    names of its contributors may be used to endorse or promote products
+//    derived from this software without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; 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 THE COPYRIGHT HOLDER 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.
+
+// This is run as a JSC stress test. Let the harness know that this is a slow test.
+//@ slow!
+
+load(&quot;constants.js&quot;);
+load(&quot;util.js&quot;);
+load(&quot;red_black_tree.js&quot;);
+load(&quot;call_sign.js&quot;);
+load(&quot;vector_2d.js&quot;);
+load(&quot;vector_3d.js&quot;);
+load(&quot;motion.js&quot;);
+load(&quot;reduce_collision_set.js&quot;);
+load(&quot;simulator.js&quot;);
+load(&quot;collision.js&quot;);
+load(&quot;collision_detector.js&quot;);
+load(&quot;benchmark.js&quot;);
+
+var result = largeBenchmark();
+
+print(&quot;Average worst case: &quot; + result + &quot; ms.&quot;);
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -1,3 +1,77 @@
</span><ins>+2016-11-18  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Concurrent GC should be able to run splay in debug mode and earley/raytrace in release mode with no perf regression
+        https://bugs.webkit.org/show_bug.cgi?id=164282
+
+        Reviewed by Geoffrey Garen and Oliver Hunt.
+        
+        The two three remaining bugs were:
+
+        - Improper ordering inside putDirectWithoutTransition() and friends. We need to make sure
+          that the GC doesn't see the store to Structure::m_offset until we've resized the butterfly.
+          That proved a bit tricky. On the other hand, this means that we could probably remove the
+          requirement that the GC holds the Structure lock in some cases. I haven't removed that lock
+          yet because I still think it might protect some weird cases, and it doesn't seem to cost us
+          anything.
+        
+        - CodeBlock's GC strategy needed to be made thread-safe (visitWeakly, visitChildren, and
+          their friends now hold locks) and incremental-safe (we need to update predictions in the
+          finalizer to make sure we clear anything that was put into a value profile towards the end
+          of GC).
+        
+        - The GC timeslicing scheduler needed to be made a bit more aggressive to deal with
+          generational workloads like earley, raytrace, and CDjs. Once I got those benchmarks to run,
+          I found that they would do many useless iterations of GC because they wouldn't pause long
+          enough after rescanning weak references and roots. I added a bunch of knobs for forcing a
+          pause. In the end, I realized that I could get the desired effect by putting a ceiling on
+          mutator utilization. We want the GC to finish quickly if it is possible to do so, even if
+          the amount of allocation that the mutator had done is low. Having a utilization ceiling
+          seems to accomplish this for benchmarks with trivial heaps (earley and raytrace) as well as
+          huge heaps (like CDjs in its &quot;large&quot; configuration).
+        
+        This preserves splay performance, makes the concurrent GC more stable, and makes the
+        concurrent GC not a perf regression on earley or raytrace. It seems to give us great CDjs
+        performance as well, but this is still hard to tell because we crash a lot in that benchmark.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::visitWeakly):
+        (JSC::CodeBlock::visitChildren):
+        (JSC::CodeBlock::shouldVisitStrongly):
+        (JSC::CodeBlock::shouldJettisonDueToOldAge):
+        (JSC::CodeBlock::propagateTransitions):
+        (JSC::CodeBlock::determineLiveness):
+        (JSC::CodeBlock::WeakReferenceHarvester::visitWeakReferences):
+        (JSC::CodeBlock::UnconditionalFinalizer::finalizeUnconditionally):
+        (JSC::CodeBlock::visitOSRExitTargets):
+        (JSC::CodeBlock::stronglyVisitStrongReferences):
+        (JSC::CodeBlock::stronglyVisitWeakReferences):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::clearVisitWeaklyHasBeenCalled):
+        * heap/CodeBlockSet.cpp:
+        (JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced):
+        * heap/Heap.cpp:
+        (JSC::Heap::ResumeTheWorldScope::ResumeTheWorldScope):
+        (JSC::Heap::markToFixpoint):
+        (JSC::Heap::beginMarking):
+        (JSC::Heap::addToRememberedSet):
+        (JSC::Heap::collectInThread):
+        * heap/Heap.h:
+        * heap/HeapInlines.h:
+        (JSC::Heap::mutatorFence):
+        * heap/MarkedBlock.cpp:
+        * runtime/JSCellInlines.h:
+        (JSC::JSCell::finishCreation):
+        * runtime/JSObjectInlines.h:
+        (JSC::JSObject::putDirectWithoutTransition):
+        (JSC::JSObject::putDirectInternal):
+        * runtime/Options.h:
+        * runtime/Structure.cpp:
+        (JSC::Structure::add):
+        * runtime/Structure.h:
+        * runtime/StructureInlines.h:
+        (JSC::Structure::add):
+
</ins><span class="cx"> 2016-11-18  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Generator functions should have a displayable name when shown in stack traces
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -1873,7 +1873,7 @@
</span><span class="cx">     , m_reoptimizationRetryCounter(0)
</span><span class="cx">     , m_creationTime(std::chrono::steady_clock::now())
</span><span class="cx"> {
</span><del>-    m_visitWeaklyHasBeenCalled.store(false, std::memory_order_relaxed);
</del><ins>+    m_visitWeaklyHasBeenCalled = false;
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(heap()-&gt;isDeferred());
</span><span class="cx">     ASSERT(m_scopeRegister.isLocal());
</span><span class="lines">@@ -1932,7 +1932,7 @@
</span><span class="cx">     , m_reoptimizationRetryCounter(0)
</span><span class="cx">     , m_creationTime(std::chrono::steady_clock::now())
</span><span class="cx"> {
</span><del>-    m_visitWeaklyHasBeenCalled.store(false, std::memory_order_relaxed);
</del><ins>+    m_visitWeaklyHasBeenCalled = false;
</ins><span class="cx"> 
</span><span class="cx">     ASSERT(heap()-&gt;isDeferred());
</span><span class="cx">     ASSERT(m_scopeRegister.isLocal());
</span><span class="lines">@@ -2508,18 +2508,20 @@
</span><span class="cx"> 
</span><span class="cx"> void CodeBlock::visitWeakly(SlotVisitor&amp; visitor)
</span><span class="cx"> {
</span><del>-    bool setByMe = !m_visitWeaklyHasBeenCalled.compareExchangeStrong(false, true);
-    if (!setByMe)
</del><ins>+    ConcurrentJSLocker locker(m_lock);
+    if (m_visitWeaklyHasBeenCalled)
</ins><span class="cx">         return;
</span><ins>+    
+    m_visitWeaklyHasBeenCalled = true;
</ins><span class="cx"> 
</span><span class="cx">     if (Heap::isMarkedConcurrently(this))
</span><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    if (shouldVisitStrongly()) {
</del><ins>+    if (shouldVisitStrongly(locker)) {
</ins><span class="cx">         visitor.appendUnbarrieredReadOnlyPointer(this);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-
</del><ins>+    
</ins><span class="cx">     // There are two things that may use unconditional finalizers: inline cache clearing
</span><span class="cx">     // and jettisoning. The probability of us wanting to do at least one of those things
</span><span class="cx">     // is probably quite close to 1. So we add one no matter what and when it runs, it
</span><span class="lines">@@ -2549,10 +2551,10 @@
</span><span class="cx">     // decision by calling harvestWeakReferences().
</span><span class="cx"> 
</span><span class="cx">     m_allTransitionsHaveBeenMarked = false;
</span><del>-    propagateTransitions(visitor);
</del><ins>+    propagateTransitions(locker, visitor);
</ins><span class="cx"> 
</span><span class="cx">     m_jitCode-&gt;dfgCommon()-&gt;livenessHasBeenProved = false;
</span><del>-    determineLiveness(visitor);
</del><ins>+    determineLiveness(locker, visitor);
</ins><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2575,6 +2577,7 @@
</span><span class="cx"> 
</span><span class="cx"> void CodeBlock::visitChildren(SlotVisitor&amp; visitor)
</span><span class="cx"> {
</span><ins>+    ConcurrentJSLocker locker(m_lock);
</ins><span class="cx">     // There are two things that may use unconditional finalizers: inline cache clearing
</span><span class="cx">     // and jettisoning. The probability of us wanting to do at least one of those things
</span><span class="cx">     // is probably quite close to 1. So we add one no matter what and when it runs, it
</span><span class="lines">@@ -2592,19 +2595,19 @@
</span><span class="cx">         visitor.reportExtraMemoryVisited(m_instructions.size() * sizeof(Instruction) / refCount);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    stronglyVisitStrongReferences(visitor);
-    stronglyVisitWeakReferences(visitor);
</del><ins>+    stronglyVisitStrongReferences(locker, visitor);
+    stronglyVisitWeakReferences(locker, visitor);
</ins><span class="cx"> 
</span><span class="cx">     m_allTransitionsHaveBeenMarked = false;
</span><del>-    propagateTransitions(visitor);
</del><ins>+    propagateTransitions(locker, visitor);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool CodeBlock::shouldVisitStrongly()
</del><ins>+bool CodeBlock::shouldVisitStrongly(const ConcurrentJSLocker&amp; locker)
</ins><span class="cx"> {
</span><span class="cx">     if (Options::forceCodeBlockLiveness())
</span><span class="cx">         return true;
</span><span class="cx"> 
</span><del>-    if (shouldJettisonDueToOldAge())
</del><ins>+    if (shouldJettisonDueToOldAge(locker))
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     // Interpreter and Baseline JIT CodeBlocks don't need to be jettisoned when
</span><span class="lines">@@ -2656,7 +2659,7 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool CodeBlock::shouldJettisonDueToOldAge()
</del><ins>+bool CodeBlock::shouldJettisonDueToOldAge(const ConcurrentJSLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     if (Heap::isMarkedConcurrently(this))
</span><span class="cx">         return false;
</span><span class="lines">@@ -2683,7 +2686,7 @@
</span><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><del>-void CodeBlock::propagateTransitions(SlotVisitor&amp; visitor)
</del><ins>+void CodeBlock::propagateTransitions(const ConcurrentJSLocker&amp;, SlotVisitor&amp; visitor)
</ins><span class="cx"> {
</span><span class="cx">     UNUSED_PARAM(visitor);
</span><span class="cx"> 
</span><span class="lines">@@ -2764,7 +2767,7 @@
</span><span class="cx">         m_allTransitionsHaveBeenMarked = true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CodeBlock::determineLiveness(SlotVisitor&amp; visitor)
</del><ins>+void CodeBlock::determineLiveness(const ConcurrentJSLocker&amp;, SlotVisitor&amp; visitor)
</ins><span class="cx"> {
</span><span class="cx">     UNUSED_PARAM(visitor);
</span><span class="cx">     
</span><span class="lines">@@ -2810,9 +2813,9 @@
</span><span class="cx">     CodeBlock* codeBlock =
</span><span class="cx">         bitwise_cast&lt;CodeBlock*&gt;(
</span><span class="cx">             bitwise_cast&lt;char*&gt;(this) - OBJECT_OFFSETOF(CodeBlock, m_weakReferenceHarvester));
</span><del>-
-    codeBlock-&gt;propagateTransitions(visitor);
-    codeBlock-&gt;determineLiveness(visitor);
</del><ins>+    
+    codeBlock-&gt;propagateTransitions(NoLockingNecessary, visitor);
+    codeBlock-&gt;determineLiveness(NoLockingNecessary, visitor);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CodeBlock::clearLLIntGetByIdCache(Instruction* instruction)
</span><span class="lines">@@ -2951,7 +2954,9 @@
</span><span class="cx"> {
</span><span class="cx">     CodeBlock* codeBlock = bitwise_cast&lt;CodeBlock*&gt;(
</span><span class="cx">         bitwise_cast&lt;char*&gt;(this) - OBJECT_OFFSETOF(CodeBlock, m_unconditionalFinalizer));
</span><del>-
</del><ins>+    
+    codeBlock-&gt;updateAllPredictions();
+    
</ins><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     if (codeBlock-&gt;shouldJettisonDueToWeakReference()) {
</span><span class="cx">         codeBlock-&gt;jettison(Profiler::JettisonDueToWeakReference);
</span><span class="lines">@@ -2959,7 +2964,7 @@
</span><span class="cx">     }
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><del>-    if (codeBlock-&gt;shouldJettisonDueToOldAge()) {
</del><ins>+    if (codeBlock-&gt;shouldJettisonDueToOldAge(NoLockingNecessary)) {
</ins><span class="cx">         codeBlock-&gt;jettison(Profiler::JettisonDueToOldAge);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="lines">@@ -3099,7 +3104,7 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-void CodeBlock::visitOSRExitTargets(SlotVisitor&amp; visitor)
</del><ins>+void CodeBlock::visitOSRExitTargets(const ConcurrentJSLocker&amp;, SlotVisitor&amp; visitor)
</ins><span class="cx"> {
</span><span class="cx">     // We strongly visit OSR exits targets because we don't want to deal with
</span><span class="cx">     // the complexity of generating an exit target CodeBlock on demand and
</span><span class="lines">@@ -3119,7 +3124,7 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CodeBlock::stronglyVisitStrongReferences(SlotVisitor&amp; visitor)
</del><ins>+void CodeBlock::stronglyVisitStrongReferences(const ConcurrentJSLocker&amp; locker, SlotVisitor&amp; visitor)
</ins><span class="cx"> {
</span><span class="cx">     visitor.append(&amp;m_globalObject);
</span><span class="cx">     visitor.append(&amp;m_ownerExecutable);
</span><span class="lines">@@ -3141,13 +3146,11 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     if (JITCode::isOptimizingJIT(jitType()))
</span><del>-        visitOSRExitTargets(visitor);
</del><ins>+        visitOSRExitTargets(locker, visitor);
</ins><span class="cx"> #endif
</span><del>-
-    updateAllPredictions();
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CodeBlock::stronglyVisitWeakReferences(SlotVisitor&amp; visitor)
</del><ins>+void CodeBlock::stronglyVisitWeakReferences(const ConcurrentJSLocker&amp;, SlotVisitor&amp; visitor)
</ins><span class="cx"> {
</span><span class="cx">     UNUSED_PARAM(visitor);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -836,7 +836,7 @@
</span><span class="cx">     // concurrent compilation threads finish what they're doing.
</span><span class="cx">     mutable ConcurrentJSLock m_lock;
</span><span class="cx"> 
</span><del>-    Atomic&lt;bool&gt; m_visitWeaklyHasBeenCalled;
</del><ins>+    bool m_visitWeaklyHasBeenCalled;
</ins><span class="cx"> 
</span><span class="cx">     bool m_shouldAlwaysBeInlined; // Not a bitfield because the JIT wants to store to it.
</span><span class="cx"> 
</span><span class="lines">@@ -947,16 +947,16 @@
</span><span class="cx">     void dumpRareCaseProfile(PrintStream&amp;, const char* name, RareCaseProfile*, bool&amp; hasPrintedProfiling);
</span><span class="cx">     void dumpArithProfile(PrintStream&amp;, ArithProfile*, bool&amp; hasPrintedProfiling);
</span><span class="cx"> 
</span><del>-    bool shouldVisitStrongly();
</del><ins>+    bool shouldVisitStrongly(const ConcurrentJSLocker&amp;);
</ins><span class="cx">     bool shouldJettisonDueToWeakReference();
</span><del>-    bool shouldJettisonDueToOldAge();
</del><ins>+    bool shouldJettisonDueToOldAge(const ConcurrentJSLocker&amp;);
</ins><span class="cx">     
</span><del>-    void propagateTransitions(SlotVisitor&amp;);
-    void determineLiveness(SlotVisitor&amp;);
</del><ins>+    void propagateTransitions(const ConcurrentJSLocker&amp;, SlotVisitor&amp;);
+    void determineLiveness(const ConcurrentJSLocker&amp;, SlotVisitor&amp;);
</ins><span class="cx">         
</span><del>-    void stronglyVisitStrongReferences(SlotVisitor&amp;);
-    void stronglyVisitWeakReferences(SlotVisitor&amp;);
-    void visitOSRExitTargets(SlotVisitor&amp;);
</del><ins>+    void stronglyVisitStrongReferences(const ConcurrentJSLocker&amp;, SlotVisitor&amp;);
+    void stronglyVisitWeakReferences(const ConcurrentJSLocker&amp;, SlotVisitor&amp;);
+    void visitOSRExitTargets(const ConcurrentJSLocker&amp;, SlotVisitor&amp;);
</ins><span class="cx"> 
</span><span class="cx">     std::chrono::milliseconds timeSinceCreation()
</span><span class="cx">     {
</span><span class="lines">@@ -1079,7 +1079,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline void CodeBlock::clearVisitWeaklyHasBeenCalled()
</span><span class="cx"> {
</span><del>-    m_visitWeaklyHasBeenCalled.store(false, std::memory_order_relaxed);
</del><ins>+    m_visitWeaklyHasBeenCalled = false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename ExecutableType&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -94,8 +94,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Any remaining young CodeBlocks are live and need to be promoted to the set of old CodeBlocks.
</span><del>-    if (scope == CollectionScope::Eden)
-        promoteYoungCodeBlocks(locker);
</del><ins>+    promoteYoungCodeBlocks(locker);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool CodeBlockSet::contains(const LockHolder&amp;, void* candidateCodeBlock)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx">         
</span><span class="cx">         if (Options::logGC()) {
</span><span class="cx">             double thisPauseMS = (MonotonicTime::now() - m_heap.m_stopTime).milliseconds();
</span><del>-            dataLog(thisPauseMS, &quot; ms (max &quot;, maxPauseMS(thisPauseMS), &quot;)...]\n&quot;);
</del><ins>+            dataLog(&quot;p=&quot;, thisPauseMS, &quot; ms (max &quot;, maxPauseMS(thisPauseMS), &quot;)...]\n&quot;);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         m_heap.resumeTheWorld();
</span><span class="lines">@@ -542,21 +542,42 @@
</span><span class="cx">     const Seconds period = Seconds::fromMilliseconds(Options::concurrentGCPeriodMS());
</span><span class="cx">     
</span><span class="cx">     const double bytesAllocatedThisCycleAtTheBeginning = m_bytesAllocatedThisCycle;
</span><del>-    const double bytesAllocatedThisCycleAtTheEnd = bytesAllocatedThisCycleAtTheBeginning * Options::concurrentGCHeadroomRatio();
</del><ins>+    const double bytesAllocatedThisCycleAtTheEnd =
+        Options::concurrentGCMaxHeadroom() *
+        std::max(
+            bytesAllocatedThisCycleAtTheBeginning,
+            static_cast&lt;double&gt;(m_maxEdenSize));
</ins><span class="cx">     
</span><del>-    auto targetCollectorUtilization = [&amp;] () -&gt; double {
</del><ins>+    auto targetMutatorUtilization = [&amp;] () -&gt; double {
</ins><span class="cx">         double headroomFullness =
</span><span class="cx">             (m_bytesAllocatedThisCycle - bytesAllocatedThisCycleAtTheBeginning) /
</span><span class="cx">             (bytesAllocatedThisCycleAtTheEnd - bytesAllocatedThisCycleAtTheBeginning);
</span><span class="cx">         
</span><ins>+        // headroomFullness can be NaN and other interesting things if
+        // bytesAllocatedThisCycleAtTheBeginning is zero. We see that in debug tests. This code
+        // defends against all floating point dragons.
+        
</ins><span class="cx">         if (!(headroomFullness &gt;= 0))
</span><span class="cx">             headroomFullness = 0;
</span><span class="cx">         if (!(headroomFullness &lt;= 1))
</span><span class="cx">             headroomFullness = 1;
</span><span class="cx">         
</span><del>-        return headroomFullness;
</del><ins>+        double mutatorUtilization = 1 - headroomFullness;
+        
+        // Scale the mutator utilization into the permitted window.
+        mutatorUtilization =
+            Options::minimumMutatorUtilization() +
+            mutatorUtilization * (
+                Options::maximumMutatorUtilization() -
+                Options::minimumMutatorUtilization());
+        
+        return mutatorUtilization;
</ins><span class="cx">     };
</span><span class="cx">     
</span><ins>+    auto targetCollectorUtilization = [&amp;] () -&gt; double {
+        return 1 - targetMutatorUtilization();
+    };
+    
</ins><span class="cx">     auto elapsedInPeriod = [&amp;] (MonotonicTime now) -&gt; Seconds {
</span><span class="cx">         return (now - initialTime) % period;
</span><span class="cx">     };
</span><span class="lines">@@ -566,22 +587,41 @@
</span><span class="cx">     };
</span><span class="cx">     
</span><span class="cx">     auto shouldBeResumed = [&amp;] (MonotonicTime now) -&gt; bool {
</span><ins>+        if (Options::collectorShouldResumeFirst())
+            return phase(now) &lt;= targetMutatorUtilization();
</ins><span class="cx">         return phase(now) &gt; targetCollectorUtilization();
</span><span class="cx">     };
</span><span class="cx">     
</span><span class="cx">     auto timeToResume = [&amp;] (MonotonicTime now) -&gt; MonotonicTime {
</span><span class="cx">         ASSERT(!shouldBeResumed(now));
</span><ins>+        if (Options::collectorShouldResumeFirst())
+            return now - elapsedInPeriod(now) + period;
</ins><span class="cx">         return now - elapsedInPeriod(now) + period * targetCollectorUtilization();
</span><span class="cx">     };
</span><span class="cx">     
</span><span class="cx">     auto timeToStop = [&amp;] (MonotonicTime now) -&gt; MonotonicTime {
</span><span class="cx">         ASSERT(shouldBeResumed(now));
</span><del>-        return now - elapsedInPeriod(now) + period;
</del><ins>+        if (Options::collectorShouldResumeFirst())
+            return now - elapsedInPeriod(now) + period * targetMutatorUtilization();
+        return now -  - elapsedInPeriod(now) + period;
</ins><span class="cx">     };
</span><span class="cx">     
</span><ins>+    // Adjust the target extra pause ratio as necessary.
+    double rateOfCollection =
+        (m_lastGCEndTime - m_lastGCStartTime) /
+        (m_currentGCStartTime - m_lastGCStartTime);
+    
+    if (Options::logGC())
+        dataLog(&quot;cr=&quot;, rateOfCollection, &quot; &quot;);
+    
+    // FIXME: Determine if this is useful or get rid of it.
+    // https://bugs.webkit.org/show_bug.cgi?id=164940
+    double extraPauseRatio = Options::initialExtraPauseRatio();
+    
</ins><span class="cx">     for (unsigned iteration = 1; ; ++iteration) {
</span><span class="cx">         if (Options::logGC())
</span><span class="cx">             dataLog(&quot;i#&quot;, iteration, &quot; &quot;);
</span><ins>+        MonotonicTime topOfLoop = MonotonicTime::now();
</ins><span class="cx">         {
</span><span class="cx">             TimingScope preConvergenceTimingScope(*this, &quot;Heap::markToFixpoint conservative scan&quot;);
</span><span class="cx">             ConservativeRoots conservativeRoots(*this);
</span><span class="lines">@@ -642,6 +682,9 @@
</span><span class="cx">         DFG::markCodeBlocks(*m_vm, *m_collectorSlotVisitor);
</span><span class="cx">         bool shouldTerminate = m_collectorSlotVisitor-&gt;isEmpty() &amp;&amp; m_mutatorMarkStack-&gt;isEmpty();
</span><span class="cx">         
</span><ins>+        if (Options::logGC())
+            dataLog(m_collectorSlotVisitor-&gt;collectorMarkStack().size(), &quot;+&quot;, m_mutatorMarkStack-&gt;size() + m_collectorSlotVisitor-&gt;mutatorMarkStack().size(), &quot;, a=&quot;, m_bytesAllocatedThisCycle / 1024, &quot; kb, b=&quot;, m_barriersExecuted, &quot;, mu=&quot;, targetMutatorUtilization(), &quot; &quot;);
+        
</ins><span class="cx">         // We want to do this to conservatively ensure that we rescan any code blocks that are
</span><span class="cx">         // running right now. However, we need to be sure to do it *after* we mark the code block
</span><span class="cx">         // so that we know for sure if it really needs a barrier. Also, this has to happen after the
</span><span class="lines">@@ -661,23 +704,30 @@
</span><span class="cx">         if (Options::logGC() == GCLogging::Verbose)
</span><span class="cx">             dataLog(&quot;Live Weak Handles:\n&quot;, *m_collectorSlotVisitor);
</span><span class="cx">         
</span><del>-        if (Options::logGC())
-            dataLog(m_collectorSlotVisitor-&gt;collectorMarkStack().size(), &quot;+&quot;, m_collectorSlotVisitor-&gt;mutatorMarkStack().size(), &quot; mu=&quot;, 1 - targetCollectorUtilization(), &quot; &quot;);
</del><ins>+        MonotonicTime beforeConvergence = MonotonicTime::now();
</ins><span class="cx">         
</span><span class="cx">         {
</span><span class="cx">             TimingScope traceTimingScope(*this, &quot;Heap::markToFixpoint tracing&quot;);
</span><span class="cx">             ParallelModeEnabler enabler(*m_collectorSlotVisitor);
</span><ins>+            
</ins><span class="cx">             if (Options::useCollectorTimeslicing()) {
</span><del>-                for (;;) {
</del><ins>+                // Before we yield to the mutator, we should do GC work proportional to the time we
+                // spent paused. We initialize the timeslicer to start after this &quot;mandatory&quot; pause
+                // completes.
+                
+                SlotVisitor::SharedDrainResult drainResult;
+                
+                Seconds extraPause = (beforeConvergence - topOfLoop) * extraPauseRatio;
+                initialTime = beforeConvergence + extraPause;
+                drainResult = m_collectorSlotVisitor-&gt;drainInParallel(initialTime);
+                
+                while (drainResult != SlotVisitor::SharedDrainResult::Done) {
</ins><span class="cx">                     MonotonicTime now = MonotonicTime::now();
</span><del>-                    SlotVisitor::SharedDrainResult drainResult;
</del><span class="cx">                     if (shouldBeResumed(now)) {
</span><span class="cx">                         ResumeTheWorldScope resumeTheWorldScope(*this);
</span><span class="cx">                         drainResult = m_collectorSlotVisitor-&gt;drainInParallel(timeToStop(now));
</span><span class="cx">                     } else
</span><span class="cx">                         drainResult = m_collectorSlotVisitor-&gt;drainInParallel(timeToResume(now));
</span><del>-                    if (drainResult == SlotVisitor::SharedDrainResult::Done)
-                        break;
</del><span class="cx">                 }
</span><span class="cx">             } else {
</span><span class="cx">                 // Disabling collector timeslicing is meant to be used together with
</span><span class="lines">@@ -686,6 +736,8 @@
</span><span class="cx">                 m_collectorSlotVisitor-&gt;drainInParallel();
</span><span class="cx">             }
</span><span class="cx">         }
</span><ins>+        
+        extraPauseRatio *= Options::extraPauseRatioIterationGrowthRate();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="lines">@@ -730,6 +782,7 @@
</span><span class="cx">     m_objectSpace.beginMarking();
</span><span class="cx">     m_mutatorShouldBeFenced = true;
</span><span class="cx">     m_barrierThreshold = tautologicalThreshold;
</span><ins>+    m_barriersExecuted = 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::visitConservativeRoots(ConservativeRoots&amp; roots)
</span><span class="lines">@@ -986,6 +1039,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(cell);
</span><span class="cx">     ASSERT(!Options::useConcurrentJIT() || !isCompilationThread());
</span><ins>+    m_barriersExecuted++;
</ins><span class="cx">     if (!Heap::isMarkedConcurrently(cell)) {
</span><span class="cx">         // During a full collection a store into an unmarked object that had surivived past
</span><span class="cx">         // collections will manifest as a store to an unmarked black object. If the object gets
</span><span class="lines">@@ -1082,6 +1136,8 @@
</span><span class="cx"> 
</span><span class="cx"> void Heap::collectInThread()
</span><span class="cx"> {
</span><ins>+    m_currentGCStartTime = MonotonicTime::now();
+    
</ins><span class="cx">     Optional&lt;CollectionScope&gt; scope;
</span><span class="cx">     {
</span><span class="cx">         LockHolder locker(*m_threadLock);
</span><span class="lines">@@ -1166,7 +1222,7 @@
</span><span class="cx">     if (Options::logGC()) {
</span><span class="cx">         MonotonicTime after = MonotonicTime::now();
</span><span class="cx">         double thisPauseMS = (after - m_stopTime).milliseconds();
</span><del>-        dataLog(thisPauseMS, &quot; ms (max &quot;, maxPauseMS(thisPauseMS), &quot;), cycle &quot;, (after - before).milliseconds(), &quot; ms END]\n&quot;);
</del><ins>+        dataLog(&quot;p=&quot;, thisPauseMS, &quot; ms (max &quot;, maxPauseMS(thisPauseMS), &quot;), cycle &quot;, (after - before).milliseconds(), &quot; ms END]\n&quot;);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     {
</span><span class="lines">@@ -1179,6 +1235,9 @@
</span><span class="cx"> 
</span><span class="cx">     setNeedFinalize();
</span><span class="cx">     resumeTheWorld();
</span><ins>+    
+    m_lastGCStartTime = m_currentGCStartTime;
+    m_lastGCEndTime = MonotonicTime::now();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::stopTheWorld()
</span><span class="lines">@@ -1698,7 +1757,7 @@
</span><span class="cx">     m_bytesAllocatedThisCycle = 0;
</span><span class="cx"> 
</span><span class="cx">     if (Options::logGC())
</span><del>-        dataLog(currentHeapSize / 1024, &quot; kb, &quot;);
</del><ins>+        dataLog(&quot;=&gt; &quot;, currentHeapSize / 1024, &quot; kb, &quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::didFinishCollection(double gcStartTime)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -116,6 +116,8 @@
</span><span class="cx">     
</span><span class="cx">     void writeBarrierWithoutFence(const JSCell* from);
</span><span class="cx">     
</span><ins>+    void mutatorFence();
+    
</ins><span class="cx">     // Take this if you know that from-&gt;cellState() &lt; barrierThreshold.
</span><span class="cx">     JS_EXPORT_PRIVATE void writeBarrierSlowPath(const JSCell* from);
</span><span class="cx"> 
</span><span class="lines">@@ -605,6 +607,12 @@
</span><span class="cx">     Box&lt;Lock&gt; m_threadLock;
</span><span class="cx">     RefPtr&lt;AutomaticThreadCondition&gt; m_threadCondition; // The mutator must not wait on this. It would cause a deadlock.
</span><span class="cx">     RefPtr&lt;AutomaticThread&gt; m_thread;
</span><ins>+    
+    MonotonicTime m_lastGCStartTime;
+    MonotonicTime m_lastGCEndTime;
+    MonotonicTime m_currentGCStartTime;
+    
+    uintptr_t m_barriersExecuted { 0 };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapInlines.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapInlines.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/heap/HeapInlines.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -157,6 +157,12 @@
</span><span class="cx">         addToRememberedSet(from);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void Heap::mutatorFence()
+{
+    if (isX86() || UNLIKELY(mutatorShouldBeFenced()))
+        WTF::storeStoreFence();
+}
+
</ins><span class="cx"> template&lt;typename Functor&gt; inline void Heap::forEachCodeBlock(const Functor&amp; func)
</span><span class="cx"> {
</span><span class="cx">     forEachCodeBlockImpl(scopedLambdaRef&lt;bool(CodeBlock*)&gt;(func));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkedBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -34,6 +34,8 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+const size_t MarkedBlock::blockSize;
+
</ins><span class="cx"> static const bool computeBalance = false;
</span><span class="cx"> static size_t balance;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSCellInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSCellInlines.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSCellInlines.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/runtime/JSCellInlines.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -60,8 +60,7 @@
</span><span class="cx"> {
</span><span class="cx">     // This object is ready to be escaped so the concurrent GC may see it at any time. We have
</span><span class="cx">     // to make sure that none of our stores sink below here.
</span><del>-    if (isX86() || UNLIKELY(vm.heap.mutatorShouldBeFenced()))
-        WTF::storeStoreFence();
</del><ins>+    vm.heap.mutatorFence();
</ins><span class="cx"> #if ENABLE(GC_VALIDATION)
</span><span class="cx">     ASSERT(vm.isInitializingObject());
</span><span class="cx">     vm.setInitializingObjectClass(0);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSObjectInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -167,9 +167,9 @@
</span><span class="cx">     unsigned oldOutOfLineCapacity = structure-&gt;outOfLineCapacity();
</span><span class="cx">     structure-&gt;addPropertyWithoutTransition(
</span><span class="cx">         vm, propertyName, attributes,
</span><del>-        [&amp;] (const GCSafeConcurrentJSLocker&amp;, PropertyOffset offset) {
-            if (structure-&gt;outOfLineCapacity() != oldOutOfLineCapacity) {
-                butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, structure-&gt;outOfLineCapacity());
</del><ins>+        [&amp;] (const GCSafeConcurrentJSLocker&amp;, PropertyOffset offset, unsigned newOutOfLineCapacity) {
+            if (newOutOfLineCapacity != oldOutOfLineCapacity) {
+                butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);
</ins><span class="cx">                 WTF::storeStoreFence();
</span><span class="cx">                 setButterfly(vm, butterfly);
</span><span class="cx">             }
</span><span class="lines">@@ -266,15 +266,14 @@
</span><span class="cx">         unsigned oldOutOfLineCapacity = structure-&gt;outOfLineCapacity();
</span><span class="cx">         offset = structure-&gt;addPropertyWithoutTransition(
</span><span class="cx">             vm, propertyName, attributes,
</span><del>-            [&amp;] (const GCSafeConcurrentJSLocker&amp;, PropertyOffset offset) {
</del><ins>+            [&amp;] (const GCSafeConcurrentJSLocker&amp;, PropertyOffset offset, unsigned newOutOfLineCapacity) {
</ins><span class="cx">                 Butterfly* butterfly = this-&gt;butterfly();
</span><del>-                if (structure-&gt;outOfLineCapacity() != oldOutOfLineCapacity) {
-                    butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, structure-&gt;outOfLineCapacity());
</del><ins>+                if (newOutOfLineCapacity != oldOutOfLineCapacity) {
+                    butterfly = allocateMoreOutOfLineStorage(vm, oldOutOfLineCapacity, newOutOfLineCapacity);
</ins><span class="cx">                     WTF::storeStoreFence();
</span><span class="cx">                     setButterfly(vm, butterfly);
</span><span class="cx">                 }
</span><span class="cx">                 validateOffset(offset);
</span><del>-                ASSERT(structure-&gt;isValidOffset(offset));
</del><span class="cx">                 putDirect(vm, offset, value);
</span><span class="cx">             });
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -195,8 +195,13 @@
</span><span class="cx">     v(double, mediumHeapGrowthFactor, 1.5, Normal, nullptr) \
</span><span class="cx">     v(double, largeHeapGrowthFactor, 1.24, Normal, nullptr) \
</span><span class="cx">     v(bool, useCollectorTimeslicing, true, Normal, nullptr) \
</span><del>-    v(double, concurrentGCHeadroomRatio, 1.5, Normal, nullptr) \
</del><ins>+    v(double, minimumMutatorUtilization, 0, Normal, nullptr) \
+    v(double, maximumMutatorUtilization, 0.7, Normal, nullptr) \
+    v(double, concurrentGCMaxHeadroom, 1.5, Normal, nullptr) \
</ins><span class="cx">     v(double, concurrentGCPeriodMS, 2, Normal, nullptr) \
</span><ins>+    v(double, initialExtraPauseRatio, 0, Normal, nullptr) \
+    v(double, extraPauseRatioIterationGrowthRate, 1.1, Normal, nullptr) \
+    v(bool, collectorShouldResumeFirst, false, Normal, nullptr) \
</ins><span class="cx">     v(bool, scribbleFreeCells, false, Normal, nullptr) \
</span><span class="cx">     v(double, sizeClassProgression, 1.4, Normal, nullptr) \
</span><span class="cx">     v(unsigned, largeAllocationCutoff, 100000, Normal, nullptr) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructurecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.cpp (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.cpp        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/runtime/Structure.cpp        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -943,7 +943,7 @@
</span><span class="cx"> 
</span><span class="cx"> PropertyOffset Structure::add(VM&amp; vm, PropertyName propertyName, unsigned attributes)
</span><span class="cx"> {
</span><del>-    return add(vm, propertyName, attributes, [] (const GCSafeConcurrentJSLocker&amp;, PropertyOffset) { });
</del><ins>+    return add(vm, propertyName, attributes, [] (const GCSafeConcurrentJSLocker&amp;, PropertyOffset, unsigned) { });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PropertyOffset Structure::remove(PropertyName propertyName)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Structure.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Structure.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/runtime/Structure.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -294,26 +294,11 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned outOfLineCapacity() const
</span><span class="cx">     {
</span><del>-        ASSERT(checkOffsetConsistency());
-            
-        unsigned outOfLineSize = this-&gt;outOfLineSize();
-
-        if (!outOfLineSize)
-            return 0;
-
-        if (outOfLineSize &lt;= initialOutOfLineCapacity)
-            return initialOutOfLineCapacity;
-
-        ASSERT(outOfLineSize &gt; initialOutOfLineCapacity);
-        COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
-        return WTF::roundUpToPowerOfTwo(outOfLineSize);
</del><ins>+        return outOfLineCapacity(m_offset);
</ins><span class="cx">     }
</span><span class="cx">     unsigned outOfLineSize() const
</span><span class="cx">     {
</span><del>-        ASSERT(checkOffsetConsistency());
-        ASSERT(structure()-&gt;classInfo() == info());
-            
-        return numberOfOutOfLineSlotsForLastOffset(m_offset);
</del><ins>+        return outOfLineSize(m_offset);
</ins><span class="cx">     }
</span><span class="cx">     bool hasInlineStorage() const
</span><span class="cx">     {
</span><span class="lines">@@ -636,7 +621,34 @@
</span><span class="cx">     void findStructuresAndMapForMaterialization(Vector&lt;Structure*, 8&gt;&amp; structures, Structure*&amp;, PropertyTable*&amp;);
</span><span class="cx">     
</span><span class="cx">     static Structure* toDictionaryTransition(VM&amp;, Structure*, DictionaryKind, DeferredStructureTransitionWatchpointFire* = nullptr);
</span><ins>+    
+    unsigned outOfLineCapacity(PropertyOffset lastOffset) const
+    {
+        unsigned outOfLineSize = this-&gt;outOfLineSize(lastOffset);
</ins><span class="cx"> 
</span><ins>+        // This algorithm completely determines the out-of-line property storage growth algorithm.
+        // The JSObject code will only trigger a resize if the value returned by this algorithm
+        // changed between the new and old structure. So, it's important to keep this simple because
+        // it's on a fast path.
+        
+        if (!outOfLineSize)
+            return 0;
+
+        if (outOfLineSize &lt;= initialOutOfLineCapacity)
+            return initialOutOfLineCapacity;
+
+        ASSERT(outOfLineSize &gt; initialOutOfLineCapacity);
+        COMPILE_ASSERT(outOfLineGrowthFactor == 2, outOfLineGrowthFactor_is_two);
+        return WTF::roundUpToPowerOfTwo(outOfLineSize);
+    }
+    
+    unsigned outOfLineSize(PropertyOffset lastOffset) const
+    {
+        ASSERT(structure()-&gt;classInfo() == info());
+            
+        return numberOfOutOfLineSlotsForLastOffset(lastOffset);
+    }
+
</ins><span class="cx">     template&lt;typename Func&gt;
</span><span class="cx">     PropertyOffset add(VM&amp;, PropertyName, unsigned attributes, const Func&amp;);
</span><span class="cx">     PropertyOffset add(VM&amp;, PropertyName, unsigned attributes);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStructureInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StructureInlines.h (208896 => 208897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StructureInlines.h        2016-11-18 22:04:43 UTC (rev 208896)
+++ trunk/Source/JavaScriptCore/runtime/StructureInlines.h        2016-11-18 22:11:51 UTC (rev 208897)
</span><span class="lines">@@ -304,11 +304,14 @@
</span><span class="cx"> 
</span><span class="cx">     PropertyOffset newOffset = table-&gt;nextOffset(m_inlineCapacity);
</span><span class="cx">     
</span><del>-    table-&gt;add(PropertyMapEntry(rep, newOffset, attributes), m_offset, PropertyTable::PropertyOffsetMayChange);
</del><ins>+    PropertyOffset newLastOffset = m_offset;
+    table-&gt;add(PropertyMapEntry(rep, newOffset, attributes), newLastOffset, PropertyTable::PropertyOffsetMayChange);
</ins><span class="cx">     
</span><ins>+    func(locker, newOffset, outOfLineCapacity(newLastOffset));
+    vm.heap.mutatorFence();
+    m_offset = newLastOffset;
+
</ins><span class="cx">     checkConsistency();
</span><del>-
-    func(locker, newOffset);
</del><span class="cx">     return newOffset;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>