<!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>[210521] trunk/Source/JavaScriptCore</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/210521">210521</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2017-01-09 13:45:56 -0800 (Mon, 09 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make the collector's fixpoint smart about scheduling work
https://bugs.webkit.org/show_bug.cgi?id=165910

Reviewed by Keith Miller.
        
Prior to this change, every time the GC would run any constraints in markToFixpoint, it
would run all of the constraints. It would always run them in the same order. That means
that so long as any one constraint was generating new work, we'd pay the price of all
constraints. This is usually OK because most constraints are cheap but it artificially
inflates the cost of slow constraints - especially ones that are expensive but usually
generate no new work.
        
This patch redoes how the GC runs constraints by applying ideas from data flow analysis.
The GC now builds a MarkingConstraintSet when it boots up, and this contains all of the
constraints as well as some meta-data about them. Now, markToFixpoint just calls into
MarkingConstraintSet to execute constraints. Because constraint execution and scheduling
need to be aware of each other, I rewrote markToFixpoint in such a way that it's more
obvious how the GC goes between constraint solving, marking with stopped mutator, and
marking with resumed mutator. This also changes the scheduler API in such a way that a
synchronous stop-the-world collection no longer needs to do fake stop/resume - instead we
just swap the space-time scheduler for the stop-the-world scheduler.
        
This is a big streamlining of the GC. This is a speed-up in GC-heavy tests because we
now execute most constraints exactly twice regardless of how many total fixpoint
iterations we do. Now, when we run out of marking work, the constraint solver will just
run the constraint that is most likely to generate new visiting work, and if it does
generate work, then the GC now goes back to marking. Before, it would run *all*
constraints and then go back to marking. The constraint solver is armed with three
information signals that it uses to sort the constraints in order of descending likelihood
to generate new marking work. Then it runs them in that order until it there is new
marking work. The signals are:
        
1) Whether the constraint is greyed by marking or execution. We call this the volatility
   of the constraint. For example, weak reference constraints have GreyedByMarking as
   their volatility because they are most likely to have something to say after we've done
   some marking. On the other hand, conservative roots have GreyedByExecution as their
   volatility because they will give new information anytime we let the mutator run. The
   constraint solver will only run GreyedByExecution constraints as roots and after the
   GreyedByMarking constraints go silent. This ensures that we don't try to scan
   conservative roots every time we need to re-run weak references and vice-versa.
           
   Another way to look at it is that the constraint solver tries to predict if the
   wavefront is advancing or retreating. The wavefront is almost certainly advancing so
   long as the mark stacks are non-empty or so long as at least one of the GreyedByMarking
   constraints is still producing work. Otherwise the wavefront is almost certainly
   retreating. It's most profitable to run GreyedByMarking constraints when the wavefront
   is advancing, and most profitable to run GreyedByExecution constraints when the
   wavefront is retreating.
           
   We use the predicted wavefront direction and the volatility of constraints as a
   first-order signal of constraint profitability.
        
2) How much visiting work was created the last time the constraint ran. The solver
   remembers the lastVisitCount, and uses it to predict how much work the constraint will
   generate next time. In practice this means we will keep re-running the one interesting
   constraint until it shuts up.
        
3) Optional work predictors for some constraints. The constraint that shuffles the mutator
   mark stack into the main SlotVisitor's mutator mark stack always knows exactly how much
   work it will create.
           
   The sum of (2) and (3) are used as a second-order signal of constraint profitability.
        
The constraint solver will always run all of the GreyedByExecution constraints at GC
start, since these double as the GC's roots. The constraint solver will always run all of
the GreyedByMarking constraints the first time that marking stalls. Other than that, the
solver will keep running constraints, sorted according to their likelihood to create work,
until either work is created or we run out of constraints to run. GC termination happens
when we run out of constraints to run.
        
This new infrastructure means that we have a much better chance of dealing with worst-case
DOM pathologies. If we can intelligently factor different evil DOM things into different
constraints with the right work predictions then this could reduce the cost of those DOM
things by a factor of N where N is the number of fixpoint iterations the GC typically
does. N is usually around 5-6 even for simple heaps.
        
My perf measurements say:
        
PLT3: 0.02% faster with 5.3% confidence.
JetStream: 0.15% faster with 17% confidence.
Speedometer: 0.58% faster with 82% confidence.
        
Here are the details from JetStream:
        
splay: 1.02173x faster with 0.996841 confidence
splay-latency: 1.0617x faster with 0.987462 confidence
towers.c: 1.01852x faster with 0.92128 confidence
crypto-md5: 1.06058x faster with 0.482363 confidence
score: 1.00152x faster with 0.16892 confidence
        
I think that Speedometer is legitimately benefiting from this change based on looking at
--logGC=true output. We are now spending less time reexecuting expensive constraints. I
think that JetStream/splay is also benefiting, because although the constraints it sees
are cheap, it spends 30% of its time in GC so even small improvements matter.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::markCodeBlocks): Deleted.
(JSC::DFG::Plan::rememberCodeBlocks): Deleted.
* dfg/DFGPlan.h:
* dfg/DFGPlanInlines.h: Added.
(JSC::DFG::Plan::iterateCodeBlocksForGC):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::markCodeBlocks): Deleted.
(JSC::DFG::Worklist::rememberCodeBlocks): Deleted.
(JSC::DFG::rememberCodeBlocks): Deleted.
* dfg/DFGWorklist.h:
* dfg/DFGWorklistInlines.h: Added.
(JSC::DFG::iterateCodeBlocksForGC):
(JSC::DFG::Worklist::iterateCodeBlocksForGC):
* heap/CodeBlockSet.cpp:
(JSC::CodeBlockSet::writeBarrierCurrentlyExecuting): Deleted.
* heap/CodeBlockSet.h:
(JSC::CodeBlockSet::iterate): Deleted.
* heap/CodeBlockSetInlines.h:
(JSC::CodeBlockSet::iterate):
(JSC::CodeBlockSet::iterateCurrentlyExecuting):
* heap/Heap.cpp:
(JSC::Heap::Heap):
(JSC::Heap::iterateExecutingAndCompilingCodeBlocks):
(JSC::Heap::iterateExecutingAndCompilingCodeBlocksWithoutHoldingLocks):
(JSC::Heap::assertSharedMarkStacksEmpty):
(JSC::Heap::markToFixpoint):
(JSC::Heap::endMarking):
(JSC::Heap::collectInThread):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::buildConstraintSet):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::ResumeTheWorldScope::ResumeTheWorldScope): Deleted.
(JSC::Heap::ResumeTheWorldScope::~ResumeTheWorldScope): Deleted.
(JSC::Heap::harvestWeakReferences): Deleted.
(JSC::Heap::visitConservativeRoots): Deleted.
(JSC::Heap::visitCompilerWorklistWeakReferences): Deleted.
* heap/Heap.h:
* heap/MarkingConstraint.cpp: Added.
(JSC::MarkingConstraint::MarkingConstraint):
(JSC::MarkingConstraint::~MarkingConstraint):
(JSC::MarkingConstraint::resetStats):
(JSC::MarkingConstraint::execute):
* heap/MarkingConstraint.h: Added.
(JSC::MarkingConstraint::index):
(JSC::MarkingConstraint::abbreviatedName):
(JSC::MarkingConstraint::name):
(JSC::MarkingConstraint::lastVisitCount):
(JSC::MarkingConstraint::quickWorkEstimate):
(JSC::MarkingConstraint::workEstimate):
(JSC::MarkingConstraint::volatility):
* heap/MarkingConstraintSet.cpp: Added.
(JSC::MarkingConstraintSet::ExecutionContext::ExecutionContext):
(JSC::MarkingConstraintSet::ExecutionContext::didVisitSomething):
(JSC::MarkingConstraintSet::ExecutionContext::shouldTimeOut):
(JSC::MarkingConstraintSet::ExecutionContext::drain):
(JSC::MarkingConstraintSet::ExecutionContext::didExecute):
(JSC::MarkingConstraintSet::ExecutionContext::execute):
(JSC::MarkingConstraintSet::MarkingConstraintSet):
(JSC::MarkingConstraintSet::~MarkingConstraintSet):
(JSC::MarkingConstraintSet::resetStats):
(JSC::MarkingConstraintSet::add):
(JSC::MarkingConstraintSet::executeBootstrap):
(JSC::MarkingConstraintSet::executeConvergence):
(JSC::MarkingConstraintSet::isWavefrontAdvancing):
(JSC::MarkingConstraintSet::executeConvergenceImpl):
(JSC::MarkingConstraintSet::executeAll):
* heap/MarkingConstraintSet.h: Added.
(JSC::MarkingConstraintSet::isWavefrontRetreating):
* heap/MutatorScheduler.cpp: Added.
(JSC::MutatorScheduler::MutatorScheduler):
(JSC::MutatorScheduler::~MutatorScheduler):
(JSC::MutatorScheduler::didStop):
(JSC::MutatorScheduler::willResume):
(JSC::MutatorScheduler::didExecuteConstraints):
(JSC::MutatorScheduler::log):
(JSC::MutatorScheduler::shouldStop):
(JSC::MutatorScheduler::shouldResume):
* heap/MutatorScheduler.h: Added.
* heap/OpaqueRootSet.h:
(JSC::OpaqueRootSet::add):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::visitAsConstraint):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::didReachTermination):
(JSC::SlotVisitor::hasWork):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::addOpaqueRoot):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::addToVisitCount):
* heap/SpaceTimeMutatorScheduler.cpp: Copied from Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp.
(JSC::SpaceTimeMutatorScheduler::Snapshot::Snapshot):
(JSC::SpaceTimeMutatorScheduler::Snapshot::now):
(JSC::SpaceTimeMutatorScheduler::Snapshot::bytesAllocatedThisCycle):
(JSC::SpaceTimeMutatorScheduler::SpaceTimeMutatorScheduler):
(JSC::SpaceTimeMutatorScheduler::~SpaceTimeMutatorScheduler):
(JSC::SpaceTimeMutatorScheduler::state):
(JSC::SpaceTimeMutatorScheduler::beginCollection):
(JSC::SpaceTimeMutatorScheduler::didStop):
(JSC::SpaceTimeMutatorScheduler::willResume):
(JSC::SpaceTimeMutatorScheduler::didExecuteConstraints):
(JSC::SpaceTimeMutatorScheduler::timeToStop):
(JSC::SpaceTimeMutatorScheduler::timeToResume):
(JSC::SpaceTimeMutatorScheduler::log):
(JSC::SpaceTimeMutatorScheduler::endCollection):
(JSC::SpaceTimeMutatorScheduler::bytesAllocatedThisCycleImpl):
(JSC::SpaceTimeMutatorScheduler::bytesSinceBeginningOfCycle):
(JSC::SpaceTimeMutatorScheduler::maxHeadroom):
(JSC::SpaceTimeMutatorScheduler::headroomFullness):
(JSC::SpaceTimeMutatorScheduler::mutatorUtilization):
(JSC::SpaceTimeMutatorScheduler::collectorUtilization):
(JSC::SpaceTimeMutatorScheduler::elapsedInPeriod):
(JSC::SpaceTimeMutatorScheduler::phase):
(JSC::SpaceTimeMutatorScheduler::shouldBeResumed):
(JSC::SpaceTimeScheduler::Decision::targetMutatorUtilization): Deleted.
(JSC::SpaceTimeScheduler::Decision::targetCollectorUtilization): Deleted.
(JSC::SpaceTimeScheduler::Decision::elapsedInPeriod): Deleted.
(JSC::SpaceTimeScheduler::Decision::phase): Deleted.
(JSC::SpaceTimeScheduler::Decision::shouldBeResumed): Deleted.
(JSC::SpaceTimeScheduler::Decision::timeToResume): Deleted.
(JSC::SpaceTimeScheduler::Decision::timeToStop): Deleted.
(JSC::SpaceTimeScheduler::SpaceTimeScheduler): Deleted.
(JSC::SpaceTimeScheduler::snapPhase): Deleted.
(JSC::SpaceTimeScheduler::currentDecision): Deleted.
* heap/SpaceTimeMutatorScheduler.h: Copied from Source/JavaScriptCore/heap/SpaceTimeScheduler.h.
(JSC::SpaceTimeScheduler::Decision::operator bool): Deleted.
* heap/SpaceTimeScheduler.cpp: Removed.
* heap/SpaceTimeScheduler.h: Removed.
* heap/SynchronousStopTheWorldMutatorScheduler.cpp: Added.
(JSC::SynchronousStopTheWorldMutatorScheduler::SynchronousStopTheWorldMutatorScheduler):
(JSC::SynchronousStopTheWorldMutatorScheduler::~SynchronousStopTheWorldMutatorScheduler):
(JSC::SynchronousStopTheWorldMutatorScheduler::state):
(JSC::SynchronousStopTheWorldMutatorScheduler::beginCollection):
(JSC::SynchronousStopTheWorldMutatorScheduler::timeToStop):
(JSC::SynchronousStopTheWorldMutatorScheduler::timeToResume):
(JSC::SynchronousStopTheWorldMutatorScheduler::endCollection):
* heap/SynchronousStopTheWorldMutatorScheduler.h: Added.
* heap/VisitingTimeout.h: Added.
(JSC::VisitingTimeout::VisitingTimeout):
(JSC::VisitingTimeout::visitCount):
(JSC::VisitingTimeout::didVisitSomething):
(JSC::VisitingTimeout::shouldTimeOut):
* runtime/Options.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlancpp">trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlanh">trunk/Source/JavaScriptCore/dfg/DFGPlan.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWorklistcpp">trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWorklisth">trunk/Source/JavaScriptCore/dfg/DFGWorklist.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSetcpp">trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSeth">trunk/Source/JavaScriptCore/heap/CodeBlockSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSetInlinesh">trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h</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="#trunkSourceJavaScriptCoreheapOpaqueRootSeth">trunk/Source/JavaScriptCore/heap/OpaqueRootSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorcpp">trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorh">trunk/Source/JavaScriptCore/heap/SlotVisitor.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlanInlinesh">trunk/Source/JavaScriptCore/dfg/DFGPlanInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWorklistInlinesh">trunk/Source/JavaScriptCore/dfg/DFGWorklistInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkingConstraintcpp">trunk/Source/JavaScriptCore/heap/MarkingConstraint.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkingConstrainth">trunk/Source/JavaScriptCore/heap/MarkingConstraint.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkingConstraintSetcpp">trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkingConstraintSeth">trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMutatorSchedulercpp">trunk/Source/JavaScriptCore/heap/MutatorScheduler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMutatorSchedulerh">trunk/Source/JavaScriptCore/heap/MutatorScheduler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSpaceTimeMutatorSchedulercpp">trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSpaceTimeMutatorSchedulerh">trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSynchronousStopTheWorldMutatorSchedulercpp">trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSynchronousStopTheWorldMutatorSchedulerh">trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapVisitingTimeouth">trunk/Source/JavaScriptCore/heap/VisitingTimeout.h</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreheapSpaceTimeSchedulercpp">trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSpaceTimeSchedulerh">trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -497,10 +497,14 @@
</span><span class="cx">     heap/MarkedAllocator.cpp
</span><span class="cx">     heap/MarkedBlock.cpp
</span><span class="cx">     heap/MarkedSpace.cpp
</span><ins>+    heap/MarkingConstraint.cpp
+    heap/MarkingConstraintSet.cpp
+    heap/MutatorScheduler.cpp
</ins><span class="cx">     heap/MutatorState.cpp
</span><span class="cx">     heap/SlotVisitor.cpp
</span><del>-    heap/SpaceTimeScheduler.cpp
</del><ins>+    heap/SpaceTimeMutatorScheduler.cpp
</ins><span class="cx">     heap/StopIfNecessaryTimer.cpp
</span><ins>+    heap/SynchronousStopTheWorldMutatorScheduler.cpp
</ins><span class="cx">     heap/VisitRaceKey.cpp
</span><span class="cx">     heap/Weak.cpp
</span><span class="cx">     heap/WeakBlock.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,3 +1,249 @@
</span><ins>+2017-01-08  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Make the collector's fixpoint smart about scheduling work
+        https://bugs.webkit.org/show_bug.cgi?id=165910
+
+        Reviewed by Keith Miller.
+        
+        Prior to this change, every time the GC would run any constraints in markToFixpoint, it
+        would run all of the constraints. It would always run them in the same order. That means
+        that so long as any one constraint was generating new work, we'd pay the price of all
+        constraints. This is usually OK because most constraints are cheap but it artificially
+        inflates the cost of slow constraints - especially ones that are expensive but usually
+        generate no new work.
+        
+        This patch redoes how the GC runs constraints by applying ideas from data flow analysis.
+        The GC now builds a MarkingConstraintSet when it boots up, and this contains all of the
+        constraints as well as some meta-data about them. Now, markToFixpoint just calls into
+        MarkingConstraintSet to execute constraints. Because constraint execution and scheduling
+        need to be aware of each other, I rewrote markToFixpoint in such a way that it's more
+        obvious how the GC goes between constraint solving, marking with stopped mutator, and
+        marking with resumed mutator. This also changes the scheduler API in such a way that a
+        synchronous stop-the-world collection no longer needs to do fake stop/resume - instead we
+        just swap the space-time scheduler for the stop-the-world scheduler.
+        
+        This is a big streamlining of the GC. This is a speed-up in GC-heavy tests because we
+        now execute most constraints exactly twice regardless of how many total fixpoint
+        iterations we do. Now, when we run out of marking work, the constraint solver will just
+        run the constraint that is most likely to generate new visiting work, and if it does
+        generate work, then the GC now goes back to marking. Before, it would run *all*
+        constraints and then go back to marking. The constraint solver is armed with three
+        information signals that it uses to sort the constraints in order of descending likelihood
+        to generate new marking work. Then it runs them in that order until it there is new
+        marking work. The signals are:
+        
+        1) Whether the constraint is greyed by marking or execution. We call this the volatility
+           of the constraint. For example, weak reference constraints have GreyedByMarking as
+           their volatility because they are most likely to have something to say after we've done
+           some marking. On the other hand, conservative roots have GreyedByExecution as their
+           volatility because they will give new information anytime we let the mutator run. The
+           constraint solver will only run GreyedByExecution constraints as roots and after the
+           GreyedByMarking constraints go silent. This ensures that we don't try to scan
+           conservative roots every time we need to re-run weak references and vice-versa.
+           
+           Another way to look at it is that the constraint solver tries to predict if the
+           wavefront is advancing or retreating. The wavefront is almost certainly advancing so
+           long as the mark stacks are non-empty or so long as at least one of the GreyedByMarking
+           constraints is still producing work. Otherwise the wavefront is almost certainly
+           retreating. It's most profitable to run GreyedByMarking constraints when the wavefront
+           is advancing, and most profitable to run GreyedByExecution constraints when the
+           wavefront is retreating.
+           
+           We use the predicted wavefront direction and the volatility of constraints as a
+           first-order signal of constraint profitability.
+        
+        2) How much visiting work was created the last time the constraint ran. The solver
+           remembers the lastVisitCount, and uses it to predict how much work the constraint will
+           generate next time. In practice this means we will keep re-running the one interesting
+           constraint until it shuts up.
+        
+        3) Optional work predictors for some constraints. The constraint that shuffles the mutator
+           mark stack into the main SlotVisitor's mutator mark stack always knows exactly how much
+           work it will create.
+           
+           The sum of (2) and (3) are used as a second-order signal of constraint profitability.
+        
+        The constraint solver will always run all of the GreyedByExecution constraints at GC
+        start, since these double as the GC's roots. The constraint solver will always run all of
+        the GreyedByMarking constraints the first time that marking stalls. Other than that, the
+        solver will keep running constraints, sorted according to their likelihood to create work,
+        until either work is created or we run out of constraints to run. GC termination happens
+        when we run out of constraints to run.
+        
+        This new infrastructure means that we have a much better chance of dealing with worst-case
+        DOM pathologies. If we can intelligently factor different evil DOM things into different
+        constraints with the right work predictions then this could reduce the cost of those DOM
+        things by a factor of N where N is the number of fixpoint iterations the GC typically
+        does. N is usually around 5-6 even for simple heaps.
+        
+        My perf measurements say:
+        
+        PLT3: 0.02% faster with 5.3% confidence.
+        JetStream: 0.15% faster with 17% confidence.
+        Speedometer: 0.58% faster with 82% confidence.
+        
+        Here are the details from JetStream:
+        
+        splay: 1.02173x faster with 0.996841 confidence
+        splay-latency: 1.0617x faster with 0.987462 confidence
+        towers.c: 1.01852x faster with 0.92128 confidence
+        crypto-md5: 1.06058x faster with 0.482363 confidence
+        score: 1.00152x faster with 0.16892 confidence
+        
+        I think that Speedometer is legitimately benefiting from this change based on looking at
+        --logGC=true output. We are now spending less time reexecuting expensive constraints. I
+        think that JetStream/splay is also benefiting, because although the constraints it sees
+        are cheap, it spends 30% of its time in GC so even small improvements matter.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::markCodeBlocks): Deleted.
+        (JSC::DFG::Plan::rememberCodeBlocks): Deleted.
+        * dfg/DFGPlan.h:
+        * dfg/DFGPlanInlines.h: Added.
+        (JSC::DFG::Plan::iterateCodeBlocksForGC):
+        * dfg/DFGWorklist.cpp:
+        (JSC::DFG::Worklist::markCodeBlocks): Deleted.
+        (JSC::DFG::Worklist::rememberCodeBlocks): Deleted.
+        (JSC::DFG::rememberCodeBlocks): Deleted.
+        * dfg/DFGWorklist.h:
+        * dfg/DFGWorklistInlines.h: Added.
+        (JSC::DFG::iterateCodeBlocksForGC):
+        (JSC::DFG::Worklist::iterateCodeBlocksForGC):
+        * heap/CodeBlockSet.cpp:
+        (JSC::CodeBlockSet::writeBarrierCurrentlyExecuting): Deleted.
+        * heap/CodeBlockSet.h:
+        (JSC::CodeBlockSet::iterate): Deleted.
+        * heap/CodeBlockSetInlines.h:
+        (JSC::CodeBlockSet::iterate):
+        (JSC::CodeBlockSet::iterateCurrentlyExecuting):
+        * heap/Heap.cpp:
+        (JSC::Heap::Heap):
+        (JSC::Heap::iterateExecutingAndCompilingCodeBlocks):
+        (JSC::Heap::iterateExecutingAndCompilingCodeBlocksWithoutHoldingLocks):
+        (JSC::Heap::assertSharedMarkStacksEmpty):
+        (JSC::Heap::markToFixpoint):
+        (JSC::Heap::endMarking):
+        (JSC::Heap::collectInThread):
+        (JSC::Heap::stopIfNecessarySlow):
+        (JSC::Heap::acquireAccessSlow):
+        (JSC::Heap::collectIfNecessaryOrDefer):
+        (JSC::Heap::buildConstraintSet):
+        (JSC::Heap::notifyIsSafeToCollect):
+        (JSC::Heap::ResumeTheWorldScope::ResumeTheWorldScope): Deleted.
+        (JSC::Heap::ResumeTheWorldScope::~ResumeTheWorldScope): Deleted.
+        (JSC::Heap::harvestWeakReferences): Deleted.
+        (JSC::Heap::visitConservativeRoots): Deleted.
+        (JSC::Heap::visitCompilerWorklistWeakReferences): Deleted.
+        * heap/Heap.h:
+        * heap/MarkingConstraint.cpp: Added.
+        (JSC::MarkingConstraint::MarkingConstraint):
+        (JSC::MarkingConstraint::~MarkingConstraint):
+        (JSC::MarkingConstraint::resetStats):
+        (JSC::MarkingConstraint::execute):
+        * heap/MarkingConstraint.h: Added.
+        (JSC::MarkingConstraint::index):
+        (JSC::MarkingConstraint::abbreviatedName):
+        (JSC::MarkingConstraint::name):
+        (JSC::MarkingConstraint::lastVisitCount):
+        (JSC::MarkingConstraint::quickWorkEstimate):
+        (JSC::MarkingConstraint::workEstimate):
+        (JSC::MarkingConstraint::volatility):
+        * heap/MarkingConstraintSet.cpp: Added.
+        (JSC::MarkingConstraintSet::ExecutionContext::ExecutionContext):
+        (JSC::MarkingConstraintSet::ExecutionContext::didVisitSomething):
+        (JSC::MarkingConstraintSet::ExecutionContext::shouldTimeOut):
+        (JSC::MarkingConstraintSet::ExecutionContext::drain):
+        (JSC::MarkingConstraintSet::ExecutionContext::didExecute):
+        (JSC::MarkingConstraintSet::ExecutionContext::execute):
+        (JSC::MarkingConstraintSet::MarkingConstraintSet):
+        (JSC::MarkingConstraintSet::~MarkingConstraintSet):
+        (JSC::MarkingConstraintSet::resetStats):
+        (JSC::MarkingConstraintSet::add):
+        (JSC::MarkingConstraintSet::executeBootstrap):
+        (JSC::MarkingConstraintSet::executeConvergence):
+        (JSC::MarkingConstraintSet::isWavefrontAdvancing):
+        (JSC::MarkingConstraintSet::executeConvergenceImpl):
+        (JSC::MarkingConstraintSet::executeAll):
+        * heap/MarkingConstraintSet.h: Added.
+        (JSC::MarkingConstraintSet::isWavefrontRetreating):
+        * heap/MutatorScheduler.cpp: Added.
+        (JSC::MutatorScheduler::MutatorScheduler):
+        (JSC::MutatorScheduler::~MutatorScheduler):
+        (JSC::MutatorScheduler::didStop):
+        (JSC::MutatorScheduler::willResume):
+        (JSC::MutatorScheduler::didExecuteConstraints):
+        (JSC::MutatorScheduler::log):
+        (JSC::MutatorScheduler::shouldStop):
+        (JSC::MutatorScheduler::shouldResume):
+        * heap/MutatorScheduler.h: Added.
+        * heap/OpaqueRootSet.h:
+        (JSC::OpaqueRootSet::add):
+        * heap/SlotVisitor.cpp:
+        (JSC::SlotVisitor::visitAsConstraint):
+        (JSC::SlotVisitor::drain):
+        (JSC::SlotVisitor::didReachTermination):
+        (JSC::SlotVisitor::hasWork):
+        (JSC::SlotVisitor::drainFromShared):
+        (JSC::SlotVisitor::drainInParallelPassively):
+        (JSC::SlotVisitor::addOpaqueRoot):
+        * heap/SlotVisitor.h:
+        (JSC::SlotVisitor::addToVisitCount):
+        * heap/SpaceTimeMutatorScheduler.cpp: Copied from Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp.
+        (JSC::SpaceTimeMutatorScheduler::Snapshot::Snapshot):
+        (JSC::SpaceTimeMutatorScheduler::Snapshot::now):
+        (JSC::SpaceTimeMutatorScheduler::Snapshot::bytesAllocatedThisCycle):
+        (JSC::SpaceTimeMutatorScheduler::SpaceTimeMutatorScheduler):
+        (JSC::SpaceTimeMutatorScheduler::~SpaceTimeMutatorScheduler):
+        (JSC::SpaceTimeMutatorScheduler::state):
+        (JSC::SpaceTimeMutatorScheduler::beginCollection):
+        (JSC::SpaceTimeMutatorScheduler::didStop):
+        (JSC::SpaceTimeMutatorScheduler::willResume):
+        (JSC::SpaceTimeMutatorScheduler::didExecuteConstraints):
+        (JSC::SpaceTimeMutatorScheduler::timeToStop):
+        (JSC::SpaceTimeMutatorScheduler::timeToResume):
+        (JSC::SpaceTimeMutatorScheduler::log):
+        (JSC::SpaceTimeMutatorScheduler::endCollection):
+        (JSC::SpaceTimeMutatorScheduler::bytesAllocatedThisCycleImpl):
+        (JSC::SpaceTimeMutatorScheduler::bytesSinceBeginningOfCycle):
+        (JSC::SpaceTimeMutatorScheduler::maxHeadroom):
+        (JSC::SpaceTimeMutatorScheduler::headroomFullness):
+        (JSC::SpaceTimeMutatorScheduler::mutatorUtilization):
+        (JSC::SpaceTimeMutatorScheduler::collectorUtilization):
+        (JSC::SpaceTimeMutatorScheduler::elapsedInPeriod):
+        (JSC::SpaceTimeMutatorScheduler::phase):
+        (JSC::SpaceTimeMutatorScheduler::shouldBeResumed):
+        (JSC::SpaceTimeScheduler::Decision::targetMutatorUtilization): Deleted.
+        (JSC::SpaceTimeScheduler::Decision::targetCollectorUtilization): Deleted.
+        (JSC::SpaceTimeScheduler::Decision::elapsedInPeriod): Deleted.
+        (JSC::SpaceTimeScheduler::Decision::phase): Deleted.
+        (JSC::SpaceTimeScheduler::Decision::shouldBeResumed): Deleted.
+        (JSC::SpaceTimeScheduler::Decision::timeToResume): Deleted.
+        (JSC::SpaceTimeScheduler::Decision::timeToStop): Deleted.
+        (JSC::SpaceTimeScheduler::SpaceTimeScheduler): Deleted.
+        (JSC::SpaceTimeScheduler::snapPhase): Deleted.
+        (JSC::SpaceTimeScheduler::currentDecision): Deleted.
+        * heap/SpaceTimeMutatorScheduler.h: Copied from Source/JavaScriptCore/heap/SpaceTimeScheduler.h.
+        (JSC::SpaceTimeScheduler::Decision::operator bool): Deleted.
+        * heap/SpaceTimeScheduler.cpp: Removed.
+        * heap/SpaceTimeScheduler.h: Removed.
+        * heap/SynchronousStopTheWorldMutatorScheduler.cpp: Added.
+        (JSC::SynchronousStopTheWorldMutatorScheduler::SynchronousStopTheWorldMutatorScheduler):
+        (JSC::SynchronousStopTheWorldMutatorScheduler::~SynchronousStopTheWorldMutatorScheduler):
+        (JSC::SynchronousStopTheWorldMutatorScheduler::state):
+        (JSC::SynchronousStopTheWorldMutatorScheduler::beginCollection):
+        (JSC::SynchronousStopTheWorldMutatorScheduler::timeToStop):
+        (JSC::SynchronousStopTheWorldMutatorScheduler::timeToResume):
+        (JSC::SynchronousStopTheWorldMutatorScheduler::endCollection):
+        * heap/SynchronousStopTheWorldMutatorScheduler.h: Added.
+        * heap/VisitingTimeout.h: Added.
+        (JSC::VisitingTimeout::VisitingTimeout):
+        (JSC::VisitingTimeout::visitCount):
+        (JSC::VisitingTimeout::didVisitSomething):
+        (JSC::VisitingTimeout::shouldTimeOut):
+        * runtime/Options.h:
+
</ins><span class="cx"> 2017-01-09  Commit Queue  &lt;commit-queue@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r210476.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -127,6 +127,13 @@
</span><span class="cx">                 0F1E3A461534CBAF000F9456 /* DFGArgumentPosition.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1E3A431534CBAD000F9456 /* DFGArgumentPosition.h */; };
</span><span class="cx">                 0F1E3A471534CBB9000F9456 /* DFGDoubleFormatState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */; };
</span><span class="cx">                 0F1E3A67153A21E2000F9456 /* DFGSilentRegisterSavePlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1E3A65153A21DF000F9456 /* DFGSilentRegisterSavePlan.h */; };
</span><ins>+                0F1FB38E1E173A6500A9BE50 /* SynchronousStopTheWorldMutatorScheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1FB38A1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.cpp */; };
+                0F1FB38F1E173A6700A9BE50 /* SynchronousStopTheWorldMutatorScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FB38B1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.h */; };
+                0F1FB3901E173A6B00A9BE50 /* MutatorScheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1FB38C1E173A6200A9BE50 /* MutatorScheduler.cpp */; };
+                0F1FB3931E177A7200A9BE50 /* VisitingTimeout.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FB3921E177A6F00A9BE50 /* VisitingTimeout.h */; };
+                0F1FB3961E1AF7E100A9BE50 /* DFGPlanInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FB3941E1AF7DF00A9BE50 /* DFGPlanInlines.h */; };
+                0F1FB3971E1AF7E300A9BE50 /* DFGWorklistInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FB3951E1AF7DF00A9BE50 /* DFGWorklistInlines.h */; };
+                0F1FB3991E1F65FB00A9BE50 /* MutatorScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FB3981E1F65F900A9BE50 /* MutatorScheduler.h */; };
</ins><span class="cx">                 0F1FE51C1922A3BC006987C5 /* AbortReason.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FE51B1922A3BC006987C5 /* AbortReason.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F20177F1DCADC3300EA5950 /* DFGFlowIndexing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F20177D1DCADC3000EA5950 /* DFGFlowIndexing.cpp */; };
</span><span class="cx">                 0F2017801DCADC3500EA5950 /* DFGFlowIndexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F20177E1DCADC3000EA5950 /* DFGFlowIndexing.h */; };
</span><span class="lines">@@ -455,6 +462,10 @@
</span><span class="cx">                 0F64B2791A7957B2006E4E66 /* CallEdge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F64B2771A7957B2006E4E66 /* CallEdge.cpp */; };
</span><span class="cx">                 0F64B27A1A7957B2006E4E66 /* CallEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F64B2781A7957B2006E4E66 /* CallEdge.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F64EAF31C4ECD0600621E9B /* AirArgInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F64EAF21C4ECD0600621E9B /* AirArgInlines.h */; };
</span><ins>+                0F660E371E0517B90031462C /* MarkingConstraint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F660E331E0517B70031462C /* MarkingConstraint.cpp */; };
+                0F660E381E0517BB0031462C /* MarkingConstraint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F660E341E0517B70031462C /* MarkingConstraint.h */; };
+                0F660E391E0517BF0031462C /* MarkingConstraintSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F660E351E0517B70031462C /* MarkingConstraintSet.cpp */; };
+                0F660E3A1E0517C10031462C /* MarkingConstraintSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F660E361E0517B80031462C /* MarkingConstraintSet.h */; };
</ins><span class="cx">                 0F664CE81DA304EF00B00A11 /* CodeBlockSetInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F664CE71DA304ED00B00A11 /* CodeBlockSetInlines.h */; };
</span><span class="cx">                 0F666EC0183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F666EC1183566F900D017F1 /* FullBytecodeLiveness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F666EBF183566F900D017F1 /* FullBytecodeLiveness.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -753,8 +764,8 @@
</span><span class="cx">                 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */; };
</span><span class="cx">                 0FDDBFB61666EEDA00C55FEF /* DFGVariableAccessDataDump.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */; };
</span><span class="cx">                 0FDE87F91DFD0C760064C390 /* CellContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDE87F81DFD0C6D0064C390 /* CellContainer.cpp */; };
</span><del>-                0FDE87FC1DFE6E510064C390 /* SpaceTimeScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */; };
-                0FDE87FD1DFE6E540064C390 /* SpaceTimeScheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */; };
</del><ins>+                0FDE87FC1DFE6E510064C390 /* SpaceTimeMutatorScheduler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDE87FB1DFE6E500064C390 /* SpaceTimeMutatorScheduler.h */; };
+                0FDE87FD1DFE6E540064C390 /* SpaceTimeMutatorScheduler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDE87FA1DFE6E500064C390 /* SpaceTimeMutatorScheduler.cpp */; };
</ins><span class="cx">                 0FDF67D21D9C6D27001B9825 /* B3Kind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FDF67D11D9C6086001B9825 /* B3Kind.h */; };
</span><span class="cx">                 0FDF67D31D9C6D2A001B9825 /* B3Kind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF67D01D9C6086001B9825 /* B3Kind.cpp */; };
</span><span class="cx">                 0FDF67D61D9DC440001B9825 /* AirKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FDF67D41D9DC43E001B9825 /* AirKind.cpp */; };
</span><span class="lines">@@ -2559,6 +2570,13 @@
</span><span class="cx">                 0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDoubleFormatState.h; path = dfg/DFGDoubleFormatState.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F1E3A501537C2CB000F9456 /* DFGSlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSlowPathGenerator.h; path = dfg/DFGSlowPathGenerator.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F1E3A65153A21DF000F9456 /* DFGSilentRegisterSavePlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSilentRegisterSavePlan.h; path = dfg/DFGSilentRegisterSavePlan.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F1FB38A1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SynchronousStopTheWorldMutatorScheduler.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F1FB38B1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SynchronousStopTheWorldMutatorScheduler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F1FB38C1E173A6200A9BE50 /* MutatorScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MutatorScheduler.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F1FB3921E177A6F00A9BE50 /* VisitingTimeout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisitingTimeout.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F1FB3941E1AF7DF00A9BE50 /* DFGPlanInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPlanInlines.h; path = dfg/DFGPlanInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F1FB3951E1AF7DF00A9BE50 /* DFGWorklistInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGWorklistInlines.h; path = dfg/DFGWorklistInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F1FB3981E1F65F900A9BE50 /* MutatorScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MutatorScheduler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F1FE51B1922A3BC006987C5 /* AbortReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbortReason.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F20177D1DCADC3000EA5950 /* DFGFlowIndexing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGFlowIndexing.cpp; path = dfg/DFGFlowIndexing.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F20177E1DCADC3000EA5950 /* DFGFlowIndexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFlowIndexing.h; path = dfg/DFGFlowIndexing.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -2884,6 +2902,10 @@
</span><span class="cx">                 0F64B2771A7957B2006E4E66 /* CallEdge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallEdge.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F64B2781A7957B2006E4E66 /* CallEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallEdge.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F64EAF21C4ECD0600621E9B /* AirArgInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirArgInlines.h; path = b3/air/AirArgInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F660E331E0517B70031462C /* MarkingConstraint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkingConstraint.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F660E341E0517B70031462C /* MarkingConstraint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkingConstraint.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F660E351E0517B70031462C /* MarkingConstraintSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkingConstraintSet.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F660E361E0517B80031462C /* MarkingConstraintSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkingConstraintSet.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F664CE71DA304ED00B00A11 /* CodeBlockSetInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeBlockSetInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F666EBE183566F900D017F1 /* BytecodeLivenessAnalysisInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeLivenessAnalysisInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F666EBF183566F900D017F1 /* FullBytecodeLiveness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FullBytecodeLiveness.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3193,8 +3215,8 @@
</span><span class="cx">                 0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessDataDump.cpp; path = dfg/DFGVariableAccessDataDump.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDDBFB31666EED500C55FEF /* DFGVariableAccessDataDump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessDataDump.h; path = dfg/DFGVariableAccessDataDump.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDE87F81DFD0C6D0064C390 /* CellContainer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CellContainer.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpaceTimeScheduler.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
-                0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpaceTimeScheduler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><ins>+                0FDE87FA1DFE6E500064C390 /* SpaceTimeMutatorScheduler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpaceTimeMutatorScheduler.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FDE87FB1DFE6E500064C390 /* SpaceTimeMutatorScheduler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpaceTimeMutatorScheduler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FDF67D01D9C6086001B9825 /* B3Kind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3Kind.cpp; path = b3/B3Kind.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDF67D11D9C6086001B9825 /* B3Kind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = B3Kind.h; path = b3/B3Kind.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FDF67D41D9DC43E001B9825 /* AirKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = AirKind.cpp; path = b3/air/AirKind.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5751,8 +5773,14 @@
</span><span class="cx">                                 14D2F3D8139F4BE200491031 /* MarkedSpace.cpp */,
</span><span class="cx">                                 14D2F3D9139F4BE200491031 /* MarkedSpace.h */,
</span><span class="cx">                                 0F7C5FB91D8895050044F5E2 /* MarkedSpaceInlines.h */,
</span><ins>+                                0F660E331E0517B70031462C /* MarkingConstraint.cpp */,
+                                0F660E341E0517B70031462C /* MarkingConstraint.h */,
+                                0F660E351E0517B70031462C /* MarkingConstraintSet.cpp */,
+                                0F660E361E0517B80031462C /* MarkingConstraintSet.h */,
</ins><span class="cx">                                 142D6F0E13539A4100B02E86 /* MarkStack.cpp */,
</span><span class="cx">                                 142D6F0F13539A4100B02E86 /* MarkStack.h */,
</span><ins>+                                0F1FB38C1E173A6200A9BE50 /* MutatorScheduler.cpp */,
+                                0F1FB3981E1F65F900A9BE50 /* MutatorScheduler.h */,
</ins><span class="cx">                                 0FA762021DB9242300B7A2FD /* MutatorState.cpp */,
</span><span class="cx">                                 0FA762031DB9242300B7A2FD /* MutatorState.h */,
</span><span class="cx">                                 ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */,
</span><span class="lines">@@ -5761,14 +5789,17 @@
</span><span class="cx">                                 C225494215F7DBAA0065E898 /* SlotVisitor.cpp */,
</span><span class="cx">                                 14BA78F013AAB88F005B7C2C /* SlotVisitor.h */,
</span><span class="cx">                                 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */,
</span><del>-                                0FDE87FA1DFE6E500064C390 /* SpaceTimeScheduler.cpp */,
-                                0FDE87FB1DFE6E500064C390 /* SpaceTimeScheduler.h */,
</del><ins>+                                0FDE87FA1DFE6E500064C390 /* SpaceTimeMutatorScheduler.cpp */,
+                                0FDE87FB1DFE6E500064C390 /* SpaceTimeMutatorScheduler.h */,
</ins><span class="cx">                                 0F7CF9501DC027D70098CC12 /* StopIfNecessaryTimer.cpp */,
</span><span class="cx">                                 0F7CF9511DC027D70098CC12 /* StopIfNecessaryTimer.h */,
</span><span class="cx">                                 142E3132134FF0A600AFADB5 /* Strong.h */,
</span><span class="cx">                                 145722851437E140005FDE26 /* StrongInlines.h */,
</span><ins>+                                0F1FB38A1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.cpp */,
+                                0F1FB38B1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.h */,
</ins><span class="cx">                                 141448CC13A1783700F5BA1A /* TinyBloomFilter.h */,
</span><span class="cx">                                 0F5F08CE146C762F000472A9 /* UnconditionalFinalizer.h */,
</span><ins>+                                0F1FB3921E177A6F00A9BE50 /* VisitingTimeout.h */,
</ins><span class="cx">                                 0F952A9F1DF7860700E06FBD /* VisitRaceKey.cpp */,
</span><span class="cx">                                 0F952AA01DF7860700E06FBD /* VisitRaceKey.h */,
</span><span class="cx">                                 1ACF7376171CA6FB00C9BB1E /* Weak.cpp */,
</span><span class="lines">@@ -6995,6 +7026,7 @@
</span><span class="cx">                                 0F2B9CDF19D0BA7D00B1D1B5 /* DFGPhiChildren.h */,
</span><span class="cx">                                 A78A9772179738B8009DF744 /* DFGPlan.cpp */,
</span><span class="cx">                                 A78A9773179738B8009DF744 /* DFGPlan.h */,
</span><ins>+                                0F1FB3941E1AF7DF00A9BE50 /* DFGPlanInlines.h */,
</ins><span class="cx">                                 DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */,
</span><span class="cx">                                 0FBE0F6D16C1DB010082C5E8 /* DFGPredictionInjectionPhase.cpp */,
</span><span class="cx">                                 0FBE0F6E16C1DB010082C5E8 /* DFGPredictionInjectionPhase.h */,
</span><span class="lines">@@ -7083,6 +7115,7 @@
</span><span class="cx">                                 0FC97F3C18202119002C9B26 /* DFGWatchpointCollectionPhase.h */,
</span><span class="cx">                                 0FDB2CE5174830A2007B3C1B /* DFGWorklist.cpp */,
</span><span class="cx">                                 0FDB2CE6174830A2007B3C1B /* DFGWorklist.h */,
</span><ins>+                                0F1FB3951E1AF7DF00A9BE50 /* DFGWorklistInlines.h */,
</ins><span class="cx">                         );
</span><span class="cx">                         name = dfg;
</span><span class="cx">                         sourceTree = &quot;&lt;group&gt;&quot;;
</span><span class="lines">@@ -7945,6 +7978,7 @@
</span><span class="cx">                                 0FB7F39815ED8E4600F167B2 /* ButterflyInlines.h in Headers */,
</span><span class="cx">                                 C2FCAE1117A9C24E0034C735 /* BytecodeBasicBlock.h in Headers */,
</span><span class="cx">                                 0F21C27F14BEAA8200ADC64B /* BytecodeConventions.h in Headers */,
</span><ins>+                                0F1FB3931E177A7200A9BE50 /* VisitingTimeout.h in Headers */,
</ins><span class="cx">                                 969A07230ED1CE3300F1F681 /* BytecodeGenerator.h in Headers */,
</span><span class="cx">                                 E328DAE81D38D005001A2529 /* BytecodeGeneratorification.h in Headers */,
</span><span class="cx">                                 E328DAE91D38D005001A2529 /* BytecodeGraph.h in Headers */,
</span><span class="lines">@@ -8478,6 +8512,7 @@
</span><span class="cx">                                 A1D793011B43864B004516F5 /* IntlNumberFormatPrototype.h in Headers */,
</span><span class="cx">                                 A125846F1B45A36000CC7F6C /* IntlNumberFormatPrototype.lut.h in Headers */,
</span><span class="cx">                                 A12BBFF21B044A8B00664B69 /* IntlObject.h in Headers */,
</span><ins>+                                0F1FB3971E1AF7E300A9BE50 /* DFGWorklistInlines.h in Headers */,
</ins><span class="cx">                                 708EBE241CE8F35800453146 /* IntlObjectInlines.h in Headers */,
</span><span class="cx">                                 860BD801148EA6F200112B2F /* Intrinsic.h in Headers */,
</span><span class="cx">                                 8B9F6D561D5912FA001C739F /* IterationKind.h in Headers */,
</span><span class="lines">@@ -8562,7 +8597,9 @@
</span><span class="cx">                                 0F2B66EF17B6B5AB00A7AE3F /* JSFloat32Array.h in Headers */,
</span><span class="cx">                                 0F2B66F017B6B5AB00A7AE3F /* JSFloat64Array.h in Headers */,
</span><span class="cx">                                 BC18C41F0E16F5CD00B34460 /* JSFunction.h in Headers */,
</span><ins>+                                0F660E3A1E0517C10031462C /* MarkingConstraintSet.h in Headers */,
</ins><span class="cx">                                 A72028BA1797603D0098028C /* JSFunctionInlines.h in Headers */,
</span><ins>+                                0F660E381E0517BB0031462C /* MarkingConstraint.h in Headers */,
</ins><span class="cx">                                 70B7919C1C024A49002481E2 /* JSGeneratorFunction.h in Headers */,
</span><span class="cx">                                 0F2B66F117B6B5AB00A7AE3F /* JSGenericTypedArrayView.h in Headers */,
</span><span class="cx">                                 0F2B66F217B6B5AB00A7AE3F /* JSGenericTypedArrayViewConstructor.h in Headers */,
</span><span class="lines">@@ -8674,6 +8711,7 @@
</span><span class="cx">                                 AD2FCBEB1DB58DAD00B3E736 /* JSWebAssemblyTable.h in Headers */,
</span><span class="cx">                                 1442566215EDE98D0066A49B /* JSWithScope.h in Headers */,
</span><span class="cx">                                 86E3C619167BABEE006D760A /* JSWrapperMap.h in Headers */,
</span><ins>+                                0F1FB38F1E173A6700A9BE50 /* SynchronousStopTheWorldMutatorScheduler.h in Headers */,
</ins><span class="cx">                                 BC18C42E0E16F5CD00B34460 /* JSWrapperObject.h in Headers */,
</span><span class="cx">                                 BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */,
</span><span class="cx">                                 A72FFD64139985A800E5365A /* KeywordLookup.h in Headers */,
</span><span class="lines">@@ -8719,6 +8757,7 @@
</span><span class="cx">                                 863B23E00FC6118900703AA4 /* MacroAssemblerCodeRef.h in Headers */,
</span><span class="cx">                                 E32AB2441DCD75F400D7533A /* MacroAssemblerHelpers.h in Headers */,
</span><span class="cx">                                 86C568E111A213EE0007F7F0 /* MacroAssemblerMIPS.h in Headers */,
</span><ins>+                                0F1FB3961E1AF7E100A9BE50 /* DFGPlanInlines.h in Headers */,
</ins><span class="cx">                                 FE68C6371B90DE040042BCB3 /* MacroAssemblerPrinter.h in Headers */,
</span><span class="cx">                                 860161E40F3A83C100F84710 /* MacroAssemblerX86.h in Headers */,
</span><span class="cx">                                 860161E50F3A83C100F84710 /* MacroAssemblerX86_64.h in Headers */,
</span><span class="lines">@@ -8901,7 +8940,7 @@
</span><span class="cx">                                 BC18C4630E16F5CD00B34460 /* SourceProvider.h in Headers */,
</span><span class="cx">                                 E49DC16C12EF294E00184A1F /* SourceProviderCache.h in Headers */,
</span><span class="cx">                                 E49DC16D12EF295300184A1F /* SourceProviderCacheItem.h in Headers */,
</span><del>-                                0FDE87FC1DFE6E510064C390 /* SpaceTimeScheduler.h in Headers */,
</del><ins>+                                0FDE87FC1DFE6E510064C390 /* SpaceTimeMutatorScheduler.h in Headers */,
</ins><span class="cx">                                 0FB7F39E15ED8E4600F167B2 /* SparseArrayValueMap.h in Headers */,
</span><span class="cx">                                 A7386554118697B400540279 /* SpecializedThunkJIT.h in Headers */,
</span><span class="cx">                                 0F5541B21613C1FB00CE3E25 /* SpecialPointer.h in Headers */,
</span><span class="lines">@@ -8934,6 +8973,7 @@
</span><span class="cx">                                 BCCF0D080EF0AAB900413C8F /* StructureStubInfo.h in Headers */,
</span><span class="cx">                                 BC9041480EB9250900FE26FA /* StructureTransitionTable.h in Headers */,
</span><span class="cx">                                 0F4A38FA1C8E13DF00190318 /* SuperSampler.h in Headers */,
</span><ins>+                                0F1FB3991E1F65FB00A9BE50 /* MutatorScheduler.h in Headers */,
</ins><span class="cx">                                 705B41AC1A6E501E00716757 /* Symbol.h in Headers */,
</span><span class="cx">                                 705B41AE1A6E501E00716757 /* SymbolConstructor.h in Headers */,
</span><span class="cx">                                 996B73271BDA08EF00331B84 /* SymbolConstructor.lut.h in Headers */,
</span><span class="lines">@@ -9743,6 +9783,7 @@
</span><span class="cx">                                 A7E5A3A71797432D00E893C0 /* CompilationResult.cpp in Sources */,
</span><span class="cx">                                 147F39C2107EC37600427A48 /* Completion.cpp in Sources */,
</span><span class="cx">                                 0F6FC750196110A800E1D02D /* ComplexGetStatus.cpp in Sources */,
</span><ins>+                                0F1FB38E1E173A6500A9BE50 /* SynchronousStopTheWorldMutatorScheduler.cpp in Sources */,
</ins><span class="cx">                                 146B16D812EB5B59001BEC1B /* ConservativeRoots.cpp in Sources */,
</span><span class="cx">                                 A5B6A74D18C6DBA600F11E91 /* ConsoleClient.cpp in Sources */,
</span><span class="cx">                                 A5FD0079189B051000633231 /* ConsoleMessage.cpp in Sources */,
</span><span class="lines">@@ -9758,6 +9799,7 @@
</span><span class="cx">                                 147F39C4107EC37600427A48 /* DateConversion.cpp in Sources */,
</span><span class="cx">                                 147F39C5107EC37600427A48 /* DateInstance.cpp in Sources */,
</span><span class="cx">                                 147F39C6107EC37600427A48 /* DatePrototype.cpp in Sources */,
</span><ins>+                                0F660E391E0517BF0031462C /* MarkingConstraintSet.cpp in Sources */,
</ins><span class="cx">                                 14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */,
</span><span class="cx">                                 149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */,
</span><span class="cx">                                 A5FC84B31D1DDAD9006B5C46 /* DebuggerLocation.cpp in Sources */,
</span><span class="lines">@@ -10346,7 +10388,7 @@
</span><span class="cx">                                 9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */,
</span><span class="cx">                                 0F493AFA16D0CAD30084508B /* SourceProvider.cpp in Sources */,
</span><span class="cx">                                 E49DC16B12EF293E00184A1F /* SourceProviderCache.cpp in Sources */,
</span><del>-                                0FDE87FD1DFE6E540064C390 /* SpaceTimeScheduler.cpp in Sources */,
</del><ins>+                                0FDE87FD1DFE6E540064C390 /* SpaceTimeMutatorScheduler.cpp in Sources */,
</ins><span class="cx">                                 0F0CD4C415F6B6BB0032F1C0 /* SparseArrayValueMap.cpp in Sources */,
</span><span class="cx">                                 0F5541B11613C1FB00CE3E25 /* SpecialPointer.cpp in Sources */,
</span><span class="cx">                                 0FD82E86141F3FF100179C94 /* SpeculatedType.cpp in Sources */,
</span><span class="lines">@@ -10356,6 +10398,7 @@
</span><span class="cx">                                 A730B6131250068F009D25B1 /* StrictEvalActivation.cpp in Sources */,
</span><span class="cx">                                 14469DEB107EC7E700650446 /* StringConstructor.cpp in Sources */,
</span><span class="cx">                                 70EC0EC61AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp in Sources */,
</span><ins>+                                0F1FB3901E173A6B00A9BE50 /* MutatorScheduler.cpp in Sources */,
</ins><span class="cx">                                 14469DEC107EC7E700650446 /* StringObject.cpp in Sources */,
</span><span class="cx">                                 14469DED107EC7E700650446 /* StringPrototype.cpp in Sources */,
</span><span class="cx">                                 9335F24D12E6765B002B5553 /* StringRecursionChecker.cpp in Sources */,
</span><span class="lines">@@ -10407,6 +10450,7 @@
</span><span class="cx">                                 0F24E55817F74EDB00ABB217 /* ValueRecovery.cpp in Sources */,
</span><span class="cx">                                 79EE0BFF1B4AFB85000385C9 /* VariableEnvironment.cpp in Sources */,
</span><span class="cx">                                 0F6C73501AC9F99F00BE1682 /* VariableWriteFireDetail.cpp in Sources */,
</span><ins>+                                0F660E371E0517B90031462C /* MarkingConstraint.cpp in Sources */,
</ins><span class="cx">                                 0FE0502C1AA9095600D33B33 /* VarOffset.cpp in Sources */,
</span><span class="cx">                                 0F20C2591A8013AB00DA3229 /* VirtualRegister.cpp in Sources */,
</span><span class="cx">                                 0F952AA21DF7860D00E06FBD /* VisitRaceKey.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -610,36 +610,6 @@
</span><span class="cx">     return CompilationKey(codeBlock-&gt;alternative(), mode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Plan::markCodeBlocks(SlotVisitor&amp; slotVisitor)
-{
-    if (!isKnownToBeLiveDuringGC())
-        return;
-    
-    // Compilation writes lots of values to a CodeBlock without performing
-    // an explicit barrier. So, we need to be pessimistic and assume that
-    // all our CodeBlocks must be visited during GC.
-
-    slotVisitor.appendUnbarriered(codeBlock);
-    slotVisitor.appendUnbarriered(codeBlock-&gt;alternative());
-    if (profiledDFGCodeBlock)
-        slotVisitor.appendUnbarriered(profiledDFGCodeBlock);
-}
-
-void Plan::rememberCodeBlocks(VM&amp; vm)
-{
-    if (!isKnownToBeLiveDuringGC())
-        return;
-    
-    // Compilation writes lots of values to a CodeBlock without performing
-    // an explicit barrier. So, we need to be pessimistic and assume that
-    // all our CodeBlocks must be visited during GC.
-
-    vm.heap.writeBarrier(codeBlock);
-    vm.heap.writeBarrier(codeBlock-&gt;alternative());
-    if (profiledDFGCodeBlock)
-        vm.heap.writeBarrier(profiledDFGCodeBlock);
-}
-
</del><span class="cx"> void Plan::checkLivenessAndVisitChildren(SlotVisitor&amp; visitor)
</span><span class="cx"> {
</span><span class="cx">     if (!isKnownToBeLiveDuringGC())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlanh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -70,7 +70,8 @@
</span><span class="cx">     CompilationKey key();
</span><span class="cx">     
</span><span class="cx">     void markCodeBlocks(SlotVisitor&amp;);
</span><del>-    void rememberCodeBlocks(VM&amp;);
</del><ins>+    template&lt;typename Func&gt;
+    void iterateCodeBlocksForGC(const Func&amp;);
</ins><span class="cx">     void checkLivenessAndVisitChildren(SlotVisitor&amp;);
</span><span class="cx">     bool isKnownToBeLiveDuringGC();
</span><span class="cx">     void cancel();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlanInlinesh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGPlanInlines.h (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlanInlines.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlanInlines.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,49 @@
</span><ins>+/*
+ * Copyright (C) 2017 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. 
+ */
+
+#pragma once
+
+#include &quot;DFGPlan.h&quot;
+
+namespace JSC { namespace DFG {
+
+template&lt;typename Func&gt;
+void Plan::iterateCodeBlocksForGC(const Func&amp; func)
+{
+    if (!isKnownToBeLiveDuringGC())
+        return;
+    
+    // Compilation writes lots of values to a CodeBlock without performing
+    // an explicit barrier. So, we need to be pessimistic and assume that
+    // all our CodeBlocks must be visited during GC.
+
+    func(codeBlock);
+    func(codeBlock-&gt;alternative());
+    if (profiledDFGCodeBlock)
+        func(profiledDFGCodeBlock);
+}
+
+} } // namespace JSC::DFG
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWorklistcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -351,28 +351,6 @@
</span><span class="cx">     completeAllReadyPlansForVM(vm);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Worklist::markCodeBlocks(VM&amp; vm, SlotVisitor&amp; slotVisitor)
-{
-    LockHolder locker(*m_lock);
-    for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
-        Plan* plan = iter-&gt;value.get();
-        if (plan-&gt;vm != &amp;vm)
-            continue;
-        plan-&gt;markCodeBlocks(slotVisitor);
-    }
-}
-
-void Worklist::rememberCodeBlocks(VM&amp; vm)
-{
-    LockHolder locker(*m_lock);
-    for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
-        Plan* plan = iter-&gt;value.get();
-        if (plan-&gt;vm != &amp;vm)
-            continue;
-        plan-&gt;rememberCodeBlocks(vm);
-    }
-}
-
</del><span class="cx"> void Worklist::suspendAllThreads()
</span><span class="cx"> {
</span><span class="cx">     m_suspensionLock.lock();
</span><span class="lines">@@ -566,22 +544,6 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void markCodeBlocks(VM&amp; vm, SlotVisitor&amp; slotVisitor)
-{
-    for (unsigned i = DFG::numberOfWorklists(); i--;) {
-        if (DFG::Worklist* worklist = DFG::existingWorklistForIndexOrNull(i))
-            worklist-&gt;markCodeBlocks(vm, slotVisitor);
-    }
-}
-
-void rememberCodeBlocks(VM&amp; vm)
-{
-    for (unsigned i = DFG::numberOfWorklists(); i--;) {
-        if (DFG::Worklist* worklist = DFG::existingWorklistForIndexOrNull(i))
-            worklist-&gt;rememberCodeBlocks(vm);
-    }
-}
-
</del><span class="cx"> #else // ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><span class="cx"> void completeAllPlansForVM(VM&amp;)
</span><span class="lines">@@ -592,10 +554,6 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void rememberCodeBlocks(VM&amp;)
-{
-}
-
</del><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWorklisth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGWorklist.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWorklist.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/dfg/DFGWorklist.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2014, 2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -57,8 +57,8 @@
</span><span class="cx">     // worklist-&gt;completeAllReadyPlansForVM(vm);
</span><span class="cx">     void completeAllPlansForVM(VM&amp;);
</span><span class="cx"> 
</span><del>-    void markCodeBlocks(VM&amp;, SlotVisitor&amp;);
-    void rememberCodeBlocks(VM&amp;);
</del><ins>+    template&lt;typename Func&gt;
+    void iterateCodeBlocksForGC(VM&amp;, const Func&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void waitUntilAllPlansForVMAreReady(VM&amp;);
</span><span class="cx">     State completeAllReadyPlansForVM(VM&amp;, CompilationKey = CompilationKey());
</span><span class="lines">@@ -168,7 +168,9 @@
</span><span class="cx"> 
</span><span class="cx"> void completeAllPlansForVM(VM&amp;);
</span><span class="cx"> void markCodeBlocks(VM&amp;, SlotVisitor&amp;);
</span><del>-void rememberCodeBlocks(VM&amp;);
</del><span class="cx"> 
</span><ins>+template&lt;typename Func&gt;
+void iterateCodeBlocksForGC(VM&amp;, const Func&amp;);
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWorklistInlinesh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGWorklistInlines.h (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWorklistInlines.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGWorklistInlines.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,66 @@
</span><ins>+/*
+ * Copyright (C) 2017 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. 
+ */
+
+#pragma once
+
+#include &quot;DFGPlanInlines.h&quot;
+#include &quot;DFGWorklist.h&quot;
+
+namespace JSC { namespace DFG {
+
+#if ENABLE(DFG_JIT)
+
+template&lt;typename Func&gt;
+void iterateCodeBlocksForGC(VM&amp; vm, const Func&amp; func)
+{
+    for (unsigned i = DFG::numberOfWorklists(); i--;) {
+        if (DFG::Worklist* worklist = DFG::existingWorklistForIndexOrNull(i))
+            worklist-&gt;iterateCodeBlocksForGC(vm, func);
+    }
+}
+
+template&lt;typename Func&gt;
+void Worklist::iterateCodeBlocksForGC(VM&amp; vm, const Func&amp; func)
+{
+    LockHolder locker(*m_lock);
+    for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
+        Plan* plan = iter-&gt;value.get();
+        if (plan-&gt;vm != &amp;vm)
+            continue;
+        plan-&gt;iterateCodeBlocksForGC(func);
+    }
+}
+
+#else // ENABLE(DFG_JIT)
+
+template&lt;typename Func&gt;
+void iterateCodeBlocksForGC(VM&amp;, const Func&amp;)
+{
+}
+
+#endif // ENABLE(DFG_JIT)
+
+} } // namespace JSC::DFG
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -32,8 +32,6 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-static const bool verbose = false;
-
</del><span class="cx"> CodeBlockSet::CodeBlockSet()
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="lines">@@ -114,15 +112,6 @@
</span><span class="cx">     return m_oldCodeBlocks.contains(codeBlock) || m_newCodeBlocks.contains(codeBlock) || m_currentlyExecuting.contains(codeBlock);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CodeBlockSet::writeBarrierCurrentlyExecuting(Heap* heap)
-{
-    LockHolder locker(&amp;m_lock);
-    if (verbose)
-        dataLog(&quot;Remembering &quot;, m_currentlyExecuting.size(), &quot; code blocks.\n&quot;);
-    for (CodeBlock* codeBlock : m_currentlyExecuting)
-        heap-&gt;writeBarrier(codeBlock);
-}
-
</del><span class="cx"> void CodeBlockSet::clearCurrentlyExecuting()
</span><span class="cx"> {
</span><span class="cx">     m_currentlyExecuting.clear();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013-2014, 2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -69,10 +69,6 @@
</span><span class="cx">     // by this set), and that have not been marked.
</span><span class="cx">     void deleteUnmarkedAndUnreferenced(CollectionScope);
</span><span class="cx">     
</span><del>-    // Add all currently executing CodeBlocks to the remembered set to be 
-    // re-scanned during the next collection.
-    void writeBarrierCurrentlyExecuting(Heap*);
-
</del><span class="cx">     void clearCurrentlyExecuting();
</span><span class="cx"> 
</span><span class="cx">     bool contains(const LockHolder&amp;, void* candidateCodeBlock);
</span><span class="lines">@@ -81,22 +77,10 @@
</span><span class="cx">     // Visits each CodeBlock in the heap until the visitor function returns true
</span><span class="cx">     // to indicate that it is done iterating, or until every CodeBlock has been
</span><span class="cx">     // visited.
</span><del>-    template&lt;typename Functor&gt; void iterate(const Functor&amp; functor)
-    {
-        LockHolder locker(m_lock);
-        for (auto&amp; codeBlock : m_oldCodeBlocks) {
-            bool done = functor(codeBlock);
-            if (done)
-                return;
-        }
-
-        for (auto&amp; codeBlock : m_newCodeBlocks) {
-            bool done = functor(codeBlock);
-            if (done)
-                return;
-        }
-    }
</del><ins>+    template&lt;typename Functor&gt; void iterate(const Functor&amp;);
</ins><span class="cx">     
</span><ins>+    template&lt;typename Functor&gt; void iterateCurrentlyExecuting(const Functor&amp;);
+    
</ins><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSetInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -60,5 +60,30 @@
</span><span class="cx">     m_currentlyExecuting.add(codeBlock);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename Functor&gt;
+void CodeBlockSet::iterate(const Functor&amp; functor)
+{
+    LockHolder locker(m_lock);
+    for (auto&amp; codeBlock : m_oldCodeBlocks) {
+        bool done = functor(codeBlock);
+        if (done)
+            return;
+    }
+    
+    for (auto&amp; codeBlock : m_newCodeBlocks) {
+        bool done = functor(codeBlock);
+        if (done)
+            return;
+    }
+}
+
+template&lt;typename Functor&gt;
+void CodeBlockSet::iterateCurrentlyExecuting(const Functor&amp; functor)
+{
+    LockHolder locker(&amp;m_lock);
+    for (CodeBlock* codeBlock : m_currentlyExecuting)
+        functor(codeBlock);
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -22,9 +22,9 @@
</span><span class="cx"> #include &quot;Heap.h&quot;
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><del>-#include &quot;CodeBlockSet.h&quot;
</del><ins>+#include &quot;CodeBlockSetInlines.h&quot;
</ins><span class="cx"> #include &quot;ConservativeRoots.h&quot;
</span><del>-#include &quot;DFGWorklist.h&quot;
</del><ins>+#include &quot;DFGWorklistInlines.h&quot;
</ins><span class="cx"> #include &quot;EdenGCActivityCallback.h&quot;
</span><span class="cx"> #include &quot;Exception.h&quot;
</span><span class="cx"> #include &quot;FullGCActivityCallback.h&quot;
</span><span class="lines">@@ -49,12 +49,14 @@
</span><span class="cx"> #include &quot;JSLock.h&quot;
</span><span class="cx"> #include &quot;JSVirtualMachineInternal.h&quot;
</span><span class="cx"> #include &quot;MarkedSpaceInlines.h&quot;
</span><ins>+#include &quot;MarkingConstraintSet.h&quot;
</ins><span class="cx"> #include &quot;PreventCollectionScope.h&quot;
</span><span class="cx"> #include &quot;SamplingProfiler.h&quot;
</span><span class="cx"> #include &quot;ShadowChicken.h&quot;
</span><del>-#include &quot;SpaceTimeScheduler.h&quot;
</del><ins>+#include &quot;SpaceTimeMutatorScheduler.h&quot;
</ins><span class="cx"> #include &quot;SuperSampler.h&quot;
</span><span class="cx"> #include &quot;StopIfNecessaryTimer.h&quot;
</span><ins>+#include &quot;SynchronousStopTheWorldMutatorScheduler.h&quot;
</ins><span class="cx"> #include &quot;TypeProfilerLog.h&quot;
</span><span class="cx"> #include &quot;UnlinkedCodeBlock.h&quot;
</span><span class="cx"> #include &quot;VM.h&quot;
</span><span class="lines">@@ -91,41 +93,6 @@
</span><span class="cx">     return maxPauseMS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-} // anonymous namespace
-
-class Heap::ResumeTheWorldScope {
-public:
-    ResumeTheWorldScope(Heap&amp; heap)
-        : m_heap(heap)
-    {
-        if (!Options::useConcurrentGC())
-            return;
-        
-        if (Options::logGC()) {
-            double thisPauseMS = (MonotonicTime::now() - m_heap.m_stopTime).milliseconds();
-            dataLog(&quot;p=&quot;, thisPauseMS, &quot; ms (max &quot;, maxPauseMS(thisPauseMS), &quot;)...]\n&quot;);
-        }
-        
-        m_heap.resumeTheWorld();
-    }
-    
-    ~ResumeTheWorldScope()
-    {
-        if (!Options::useConcurrentGC())
-            return;
-        
-        m_heap.stopTheWorld();
-        
-        if (Options::logGC())
-            dataLog(&quot;[GC: &quot;);
-    }
-    
-private:
-    Heap&amp; m_heap;
-};
-
-namespace {
-
</del><span class="cx"> size_t minHeapSize(HeapType heapType, size_t ramSize)
</span><span class="cx"> {
</span><span class="cx">     if (heapType == LargeHeap) {
</span><span class="lines">@@ -316,11 +283,20 @@
</span><span class="cx">     , m_sharedCollectorMarkStack(std::make_unique&lt;MarkStackArray&gt;())
</span><span class="cx">     , m_sharedMutatorMarkStack(std::make_unique&lt;MarkStackArray&gt;())
</span><span class="cx">     , m_helperClient(&amp;heapHelperPool())
</span><ins>+    , m_scheduler(std::make_unique&lt;SpaceTimeMutatorScheduler&gt;(*this))
</ins><span class="cx">     , m_threadLock(Box&lt;Lock&gt;::create())
</span><span class="cx">     , m_threadCondition(AutomaticThreadCondition::create())
</span><span class="cx"> {
</span><span class="cx">     m_worldState.store(0);
</span><span class="cx">     
</span><ins>+    if (Options::useConcurrentGC())
+        m_scheduler = std::make_unique&lt;SpaceTimeMutatorScheduler&gt;(*this);
+    else {
+        // We simulate turning off concurrent GC by making the scheduler say that the world
+        // should always be stopped when the collector is running.
+        m_scheduler = std::make_unique&lt;SynchronousStopTheWorldMutatorScheduler&gt;();
+    }
+    
</ins><span class="cx">     if (Options::verifyHeap())
</span><span class="cx">         m_verifier = std::make_unique&lt;HeapVerifier&gt;(this, Options::numberOfGCCyclesToRecordForVerification());
</span><span class="cx">     
</span><span class="lines">@@ -479,12 +455,6 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::harvestWeakReferences()
-{
-    for (WeakReferenceHarvester* current = m_weakReferenceHarvesters.head(); current; current = current-&gt;next())
-        current-&gt;visitWeakReferences(*m_collectorSlotVisitor);
-}
-
</del><span class="cx"> void Heap::finalizeUnconditionalFinalizers()
</span><span class="cx"> {
</span><span class="cx">     while (m_unconditionalFinalizers.hasNext()) {
</span><span class="lines">@@ -511,6 +481,42 @@
</span><span class="cx">     DFG::completeAllPlansForVM(*m_vm);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename Func&gt;
+void Heap::iterateExecutingAndCompilingCodeBlocks(const Func&amp; func)
+{
+    m_codeBlocks-&gt;iterateCurrentlyExecuting(func);
+    DFG::iterateCodeBlocksForGC(*m_vm, func);
+}
+
+template&lt;typename Func&gt;
+void Heap::iterateExecutingAndCompilingCodeBlocksWithoutHoldingLocks(const Func&amp; func)
+{
+    Vector&lt;CodeBlock*, 256&gt; codeBlocks;
+    iterateExecutingAndCompilingCodeBlocks(
+        [&amp;] (CodeBlock* codeBlock) {
+            codeBlocks.append(codeBlock);
+        });
+    for (CodeBlock* codeBlock : codeBlocks)
+        func(codeBlock);
+}
+
+void Heap::assertSharedMarkStacksEmpty()
+{
+    bool ok = true;
+    
+    if (!m_sharedCollectorMarkStack-&gt;isEmpty()) {
+        dataLog(&quot;FATAL: Shared collector mark stack not empty! It has &quot;, m_sharedCollectorMarkStack-&gt;size(), &quot; elements.\n&quot;);
+        ok = false;
+    }
+    
+    if (!m_sharedMutatorMarkStack-&gt;isEmpty()) {
+        dataLog(&quot;FATAL: Shared mutator mark stack not empty! It has &quot;, m_sharedMutatorMarkStack-&gt;size(), &quot; elements.\n&quot;);
+        ok = false;
+    }
+    
+    RELEASE_ASSERT(ok);
+}
+
</ins><span class="cx"> void Heap::markToFixpoint(double gcStartTime)
</span><span class="cx"> {
</span><span class="cx">     TimingScope markToFixpointTimingScope(*this, &quot;Heap::markToFixpoint&quot;);
</span><span class="lines">@@ -560,133 +566,84 @@
</span><span class="cx">     SlotVisitor&amp; slotVisitor = *m_collectorSlotVisitor;
</span><span class="cx">     slotVisitor.didStartMarking();
</span><span class="cx"> 
</span><del>-    SpaceTimeScheduler scheduler(*this);
</del><ins>+    m_constraintSet-&gt;resetStats();
</ins><span class="cx">     
</span><ins>+    m_scheduler-&gt;beginCollection();
+    if (Options::logGC())
+        m_scheduler-&gt;log();
+    
+    // Wondering what m_constraintSet-&gt;executeXYZ does? It's running the constraints created by
+    // Heap::buildConstraintSet().
+    
+    m_constraintSet-&gt;executeBootstrap(slotVisitor, MonotonicTime::infinity());
+    m_scheduler-&gt;didExecuteConstraints();
+
+    // After this, we will almost certainly fall through all of the &quot;slotVisitor.isEmpty()&quot;
+    // checks because bootstrap would have put things into the visitor. So, we should fall
+    // through to draining.
+    
</ins><span class="cx">     for (unsigned iteration = 1; ; ++iteration) {
</span><span class="cx">         if (Options::logGC())
</span><del>-            dataLog(&quot;i#&quot;, iteration, &quot; &quot;);
-        {
-            TimingScope preConvergenceTimingScope(*this, &quot;Heap::markToFixpoint conservative scan&quot;);
-            m_objectSpace.prepareForConservativeScan();
-            ConservativeRoots conservativeRoots(*this);
-            SuperSamplerScope superSamplerScope(false);
-            gatherStackRoots(conservativeRoots);
-            gatherJSStackRoots(conservativeRoots);
-            gatherScratchBufferRoots(conservativeRoots);
-            visitConservativeRoots(conservativeRoots);
-        }
</del><ins>+            dataLog(&quot;i#&quot;, iteration, &quot; &quot;, slotVisitor.collectorMarkStack().size(), &quot;+&quot;, m_mutatorMarkStack-&gt;size() + slotVisitor.mutatorMarkStack().size(), &quot; b=&quot;, m_barriersExecuted, &quot; &quot;);
+        
+        if (slotVisitor.didReachTermination()) {
+            assertSharedMarkStacksEmpty();
</ins><span class="cx">             
</span><del>-        // Now we visit roots that don't get barriered, so each fixpoint iteration just revisits
-        // all of them.
-#if JSC_OBJC_API_ENABLED
-        scanExternalRememberedSet(*m_vm, slotVisitor);
-#endif
</del><ins>+            // FIXME: Take m_mutatorDidRun into account when scheduling constraints. Most likely,
+            // we don't have to execute root constraints again unless the mutator did run. At a
+            // minimum, we could use this for work estimates - but it's probably more than just an
+            // estimate.
+            // https://bugs.webkit.org/show_bug.cgi?id=166828
</ins><span class="cx">             
</span><del>-        if (m_vm-&gt;smallStrings.needsToBeVisited(*m_collectionScope))
-            m_vm-&gt;smallStrings.visitStrongReferences(slotVisitor);
</del><ins>+            // FIXME: We should take advantage of the fact that we could timeout. This only comes
+            // into play if we're executing constraints for the first time. But that will matter
+            // when we have deep stacks or a lot of DOM stuff.
+            // https://bugs.webkit.org/show_bug.cgi?id=166831
</ins><span class="cx">             
</span><del>-        for (auto&amp; pair : m_protectedValues)
-            slotVisitor.appendUnbarriered(pair.key);
</del><ins>+            bool executedEverything =
+                m_constraintSet-&gt;executeConvergence(slotVisitor, MonotonicTime::infinity());
+            if (executedEverything &amp;&amp; slotVisitor.isEmpty()) {
+                assertSharedMarkStacksEmpty();
+                break;
+            }
</ins><span class="cx">             
</span><del>-        if (m_markListSet &amp;&amp; m_markListSet-&gt;size())
-            MarkedArgumentBuffer::markLists(slotVisitor, *m_markListSet);
-            
-        slotVisitor.appendUnbarriered(m_vm-&gt;exception());
-        slotVisitor.appendUnbarriered(m_vm-&gt;lastException());
-            
-        m_handleSet.visitStrongHandles(slotVisitor);
-        m_handleStack.visit(slotVisitor);
-
-#if ENABLE(SAMPLING_PROFILER)
-        if (SamplingProfiler* samplingProfiler = m_vm-&gt;samplingProfiler()) {
-            LockHolder locker(samplingProfiler-&gt;getLock());
-            samplingProfiler-&gt;processUnverifiedStackTraces();
-            samplingProfiler-&gt;visit(slotVisitor);
-            if (Options::logGC() == GCLogging::Verbose)
-                dataLog(&quot;Sampling Profiler data:\n&quot;, slotVisitor);
</del><ins>+            m_scheduler-&gt;didExecuteConstraints();
</ins><span class="cx">         }
</span><del>-#endif // ENABLE(SAMPLING_PROFILER)
</del><span class="cx">         
</span><del>-        if (m_vm-&gt;typeProfiler())
-            m_vm-&gt;typeProfilerLog()-&gt;visit(slotVisitor);
-                
-        m_vm-&gt;shadowChicken().visitChildren(slotVisitor);
-                
-        m_jitStubRoutines-&gt;traceMarkedStubRoutines(slotVisitor);
-
-        slotVisitor.mergeOpaqueRootsIfNecessary();
-        for (auto&amp; parallelVisitor : m_parallelSlotVisitors)
-            parallelVisitor-&gt;mergeOpaqueRootsIfNecessary();
-
-        m_objectSpace.visitWeakSets(slotVisitor);
-        harvestWeakReferences();
-        visitCompilerWorklistWeakReferences();
-        DFG::markCodeBlocks(*m_vm, slotVisitor);
-        bool shouldTerminate = slotVisitor.isEmpty() &amp;&amp; m_mutatorMarkStack-&gt;isEmpty();
-        
-        if (Options::logGC()) {
-            dataLog(slotVisitor.collectorMarkStack().size(), &quot;+&quot;, m_mutatorMarkStack-&gt;size() + slotVisitor.mutatorMarkStack().size(), &quot;, a=&quot;, m_bytesAllocatedThisCycle / 1024, &quot; kb, b=&quot;, m_barriersExecuted, &quot;, mu=&quot;, scheduler.currentDecision().targetMutatorUtilization(), &quot; &quot;);
</del><ins>+        {
+            ParallelModeEnabler enabler(slotVisitor);
+            slotVisitor.drainInParallel(m_scheduler-&gt;timeToResume());
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        // We want to do this to conservatively ensure that we rescan any code blocks that are
-        // running right now. However, we need to be sure to do it *after* we mark the code block
-        // so that we know for sure if it really needs a barrier. Also, this has to happen after the
-        // fixpoint check - otherwise we might loop forever. Incidentally, we also want to do this
-        // at the end of GC so that anything at the end of the last GC gets barriered in the next
-        // GC.
-        m_codeBlocks-&gt;writeBarrierCurrentlyExecuting(this);
-        DFG::rememberCodeBlocks(*m_vm);
</del><ins>+        if (!m_scheduler-&gt;shouldResume())
+            continue;
</ins><span class="cx">         
</span><del>-        if (shouldTerminate)
-            break;
</del><ins>+        m_scheduler-&gt;willResume();
</ins><span class="cx">         
</span><del>-        // The SlotVisitor's mark stacks are accessed by the collector thread (i.e. this thread)
-        // without locks. That's why we double-buffer.
-        m_mutatorMarkStack-&gt;transferTo(slotVisitor.mutatorMarkStack());
</del><ins>+        if (Options::logGC()) {
+            double thisPauseMS = (MonotonicTime::now() - m_stopTime).milliseconds();
+            dataLog(&quot;p=&quot;, thisPauseMS, &quot; ms (max &quot;, maxPauseMS(thisPauseMS), &quot;)...]\n&quot;);
+        }
</ins><span class="cx">         
</span><del>-        if (Options::logGC() == GCLogging::Verbose)
-            dataLog(&quot;Live Weak Handles:\n&quot;, slotVisitor);
</del><ins>+        resumeTheWorld();
</ins><span class="cx">         
</span><span class="cx">         {
</span><del>-            TimingScope traceTimingScope(*this, &quot;Heap::markToFixpoint tracing&quot;);
</del><span class="cx">             ParallelModeEnabler enabler(slotVisitor);
</span><del>-            
-            if (Options::useCollectorTimeslicing()) {
-                scheduler.snapPhase();
-                
-                SlotVisitor::SharedDrainResult drainResult;
-                do {
-                    auto decision = scheduler.currentDecision();
-                    if (decision.shouldBeResumed()) {
-                        {
-                            ResumeTheWorldScope resumeTheWorldScope(*this);
-                            drainResult = slotVisitor.drainInParallelPassively(decision.timeToStop());
-                            if (drainResult == SlotVisitor::SharedDrainResult::Done) {
-                                // At this point we will stop. But maybe the scheduler does not want
-                                // that.
-                                Seconds scheduledIdle = decision.timeToStop() - MonotonicTime::now();
-                                // It's totally unclear what the value of collectPermittedIdleRatio
-                                // should be, other than it should be greater than 0. You could even
-                                // argue for it being greater than 1. We should tune it.
-                                sleep(scheduledIdle * Options::collectorPermittedIdleRatio());
-                            }
-                        }
-                        if (Options::logGC()) {
-                            Seconds wakeUpLatency = MonotonicTime::now() - decision.timeToStop();
-                            if (wakeUpLatency &gt;= 1_ms)
-                                dataLog(&quot;wul!=&quot;, wakeUpLatency.milliseconds(), &quot; ms &quot;);
-                        }
-                    } else
-                        drainResult = slotVisitor.drainInParallel(decision.timeToResume());
-                } while (drainResult != SlotVisitor::SharedDrainResult::Done);
-            } else {
-                // Disabling collector timeslicing is meant to be used together with
-                // --collectContinuously=true to maximize the opportunity for harmful races.
-                ResumeTheWorldScope resumeTheWorldScope(*this);
-                slotVisitor.drainInParallel();
-            }
</del><ins>+            slotVisitor.drainInParallelPassively(m_scheduler-&gt;timeToStop());
</ins><span class="cx">         }
</span><ins>+
+        stopTheWorld();
+        
+        if (Options::logGC())
+            dataLog(&quot;[GC: &quot;);
+        
+        m_scheduler-&gt;didStop();
+        
+        if (Options::logGC())
+            m_scheduler-&gt;log();
</ins><span class="cx">     }
</span><ins>+    
+    m_scheduler-&gt;endCollection();
</ins><span class="cx"> 
</span><span class="cx">     {
</span><span class="cx">         std::lock_guard&lt;Lock&gt; lock(m_markingMutex);
</span><span class="lines">@@ -694,6 +651,12 @@
</span><span class="cx">         m_markingConditionVariable.notifyAll();
</span><span class="cx">     }
</span><span class="cx">     m_helperClient.finish();
</span><ins>+
+    iterateExecutingAndCompilingCodeBlocks(
+        [&amp;] (CodeBlock* codeBlock) {
+            writeBarrier(codeBlock);
+        });
+        
</ins><span class="cx">     updateObjectCounts(gcStartTime);
</span><span class="cx">     endMarking();
</span><span class="cx"> }
</span><span class="lines">@@ -729,28 +692,8 @@
</span><span class="cx">     m_jitStubRoutines-&gt;clearMarks();
</span><span class="cx">     m_objectSpace.beginMarking();
</span><span class="cx">     setMutatorShouldBeFenced(true);
</span><del>-    m_barriersExecuted = 0;
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::visitConservativeRoots(ConservativeRoots&amp; roots)
-{
-    m_collectorSlotVisitor-&gt;append(roots);
-
-    if (Options::logGC() == GCLogging::Verbose)
-        dataLog(&quot;Conservative Roots:\n&quot;, *m_collectorSlotVisitor);
-}
-
-void Heap::visitCompilerWorklistWeakReferences()
-{
-#if ENABLE(DFG_JIT)
-    for (unsigned i = DFG::numberOfWorklists(); i--;)
-        DFG::existingWorklistForIndex(i).visitWeakReferences(*m_collectorSlotVisitor);
-
-    if (Options::logGC() == GCLogging::Verbose)
-        dataLog(&quot;DFG Worklists:\n&quot;, *m_collectorSlotVisitor);
-#endif
-}
-
</del><span class="cx"> void Heap::removeDeadCompilerWorklistEntries()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="lines">@@ -850,8 +793,7 @@
</span><span class="cx">     for (auto&amp; parallelVisitor : m_parallelSlotVisitors)
</span><span class="cx">         parallelVisitor-&gt;reset();
</span><span class="cx"> 
</span><del>-    RELEASE_ASSERT(m_sharedCollectorMarkStack-&gt;isEmpty());
-    RELEASE_ASSERT(m_sharedMutatorMarkStack-&gt;isEmpty());
</del><ins>+    assertSharedMarkStacksEmpty();
</ins><span class="cx">     m_weakReferenceHarvesters.removeAll();
</span><span class="cx">     
</span><span class="cx">     m_objectSpace.endMarking();
</span><span class="lines">@@ -1136,7 +1078,7 @@
</span><span class="cx">     
</span><span class="cx">     willStartCollection(scope);
</span><span class="cx">     collectImplTimingScope.setScope(*this);
</span><del>-        
</del><ins>+    
</ins><span class="cx">     gcStartTime = WTF::monotonicallyIncreasingTime();
</span><span class="cx">     if (m_verifier) {
</span><span class="cx">         // Verify that live objects from the last GC cycle haven't been corrupted by
</span><span class="lines">@@ -1146,11 +1088,11 @@
</span><span class="cx">         m_verifier-&gt;initializeGCCycle();
</span><span class="cx">         m_verifier-&gt;gatherLiveObjects(HeapVerifier::Phase::BeforeMarking);
</span><span class="cx">     }
</span><del>-        
</del><ins>+    
</ins><span class="cx">     prepareForMarking();
</span><del>-        
</del><ins>+    
</ins><span class="cx">     markToFixpoint(gcStartTime);
</span><del>-        
</del><ins>+    
</ins><span class="cx">     if (m_verifier) {
</span><span class="cx">         m_verifier-&gt;gatherLiveObjects(HeapVerifier::Phase::AfterMarking);
</span><span class="cx">         m_verifier-&gt;verify(HeapVerifier::Phase::AfterMarking);
</span><span class="lines">@@ -1166,8 +1108,11 @@
</span><span class="cx">     finalizeUnconditionalFinalizers();
</span><span class="cx">     removeDeadCompilerWorklistEntries();
</span><span class="cx">     notifyIncrementalSweeper();
</span><del>-        
-    m_codeBlocks-&gt;writeBarrierCurrentlyExecuting(this);
</del><ins>+    
+    m_codeBlocks-&gt;iterateCurrentlyExecuting(
+        [&amp;] (CodeBlock* codeBlock) {
+            writeBarrier(codeBlock);
+        });
</ins><span class="cx">     m_codeBlocks-&gt;clearCurrentlyExecuting();
</span><span class="cx">         
</span><span class="cx">     m_objectSpace.prepareForAllocation();
</span><span class="lines">@@ -1248,6 +1193,8 @@
</span><span class="cx">     // - During collection cycle: it reinstates the last active block.
</span><span class="cx">     m_objectSpace.resumeAllocating();
</span><span class="cx">     
</span><ins>+    m_barriersExecuted = 0;
+    
</ins><span class="cx">     RELEASE_ASSERT(m_collectorBelievesThatTheWorldIsStopped);
</span><span class="cx">     m_collectorBelievesThatTheWorldIsStopped = false;
</span><span class="cx">     
</span><span class="lines">@@ -1354,6 +1301,7 @@
</span><span class="cx">     
</span><span class="cx">     handleGCDidJIT();
</span><span class="cx">     handleNeedFinalize();
</span><ins>+    m_mutatorDidRun = true;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool Heap::stopIfNecessarySlow(unsigned oldState)
</span><span class="lines">@@ -1366,7 +1314,7 @@
</span><span class="cx">         &amp;&amp; handleNeedFinalize(oldState))
</span><span class="cx">         return true;
</span><span class="cx">     
</span><del>-    if (!(oldState &amp; shouldStopBit)) {
</del><ins>+    if (!(oldState &amp; shouldStopBit) &amp;&amp; !m_scheduler-&gt;shouldStop()) {
</ins><span class="cx">         if (!(oldState &amp; stoppedBit))
</span><span class="cx">             return false;
</span><span class="cx">         m_worldState.compareExchangeStrong(oldState, oldState &amp; ~stoppedBit);
</span><span class="lines">@@ -1439,6 +1387,7 @@
</span><span class="cx">         if (m_worldState.compareExchangeWeak(oldState, newState)) {
</span><span class="cx">             handleGCDidJIT();
</span><span class="cx">             handleNeedFinalize();
</span><ins>+            m_mutatorDidRun = true;
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -2052,16 +2001,16 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-bool Heap::collectIfNecessaryOrDefer(GCDeferralContext* deferralContext)
</del><ins>+void Heap::collectIfNecessaryOrDefer(GCDeferralContext* deferralContext)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!DisallowGC::isGCDisallowedOnCurrentThread());
</span><span class="cx"> 
</span><span class="cx">     if (!m_isSafeToCollect)
</span><del>-        return false;
</del><ins>+        return;
</ins><span class="cx">     if (mutatorState() == MutatorState::HelpingGC)
</span><del>-        return false;
</del><ins>+        return;
</ins><span class="cx">     if (!Options::useGC())
</span><del>-        return false;
</del><ins>+        return;
</ins><span class="cx">     
</span><span class="cx">     if (mayNeedToStop()) {
</span><span class="cx">         if (deferralContext)
</span><span class="lines">@@ -2068,16 +2017,19 @@
</span><span class="cx">             deferralContext-&gt;m_shouldGC = true;
</span><span class="cx">         else if (isDeferred())
</span><span class="cx">             m_didDeferGCWork = true;
</span><del>-        else
</del><ins>+        else {
</ins><span class="cx">             stopIfNecessary();
</span><ins>+            // FIXME: Check if the scheduler wants us to stop.
+            // https://bugs.webkit.org/show_bug.cgi?id=166827
+        }
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (UNLIKELY(Options::gcMaxHeapSize())) {
</span><span class="cx">         if (m_bytesAllocatedThisCycle &lt;= Options::gcMaxHeapSize())
</span><del>-            return false;
</del><ins>+            return;
</ins><span class="cx">     } else {
</span><span class="cx">         if (m_bytesAllocatedThisCycle &lt;= m_maxEdenSize)
</span><del>-            return false;
</del><ins>+            return;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (deferralContext)
</span><span class="lines">@@ -2086,7 +2038,6 @@
</span><span class="cx">         m_didDeferGCWork = true;
</span><span class="cx">     else
</span><span class="cx">         collectAsync();
</span><del>-    return true;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::decrementDeferralDepthAndGCIfNeededSlow()
</span><span class="lines">@@ -2141,8 +2092,155 @@
</span><span class="cx"> }
</span><span class="cx"> #endif // USE(CF)
</span><span class="cx"> 
</span><ins>+void Heap::buildConstraintSet()
+{
+    m_constraintSet = std::make_unique&lt;MarkingConstraintSet&gt;();
+    
+    m_constraintSet-&gt;add(
+        &quot;Cs&quot;, &quot;Conservative Scan&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            TimingScope preConvergenceTimingScope(*this, &quot;Constraint: conservative scan&quot;);
+            m_objectSpace.prepareForConservativeScan();
+            ConservativeRoots conservativeRoots(*this);
+            SuperSamplerScope superSamplerScope(false);
+            gatherStackRoots(conservativeRoots);
+            gatherJSStackRoots(conservativeRoots);
+            gatherScratchBufferRoots(conservativeRoots);
+            slotVisitor.append(conservativeRoots);
+        },
+        MarkingConstraint::GreyedByExecution);
+    
+    m_constraintSet-&gt;add(
+        &quot;Msr&quot;, &quot;Misc Small Roots&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+#if JSC_OBJC_API_ENABLED
+            scanExternalRememberedSet(*m_vm, slotVisitor);
+#endif
+
+            if (m_vm-&gt;smallStrings.needsToBeVisited(*m_collectionScope))
+                m_vm-&gt;smallStrings.visitStrongReferences(slotVisitor);
+            
+            for (auto&amp; pair : m_protectedValues)
+                slotVisitor.appendUnbarriered(pair.key);
+            
+            if (m_markListSet &amp;&amp; m_markListSet-&gt;size())
+                MarkedArgumentBuffer::markLists(slotVisitor, *m_markListSet);
+            
+            slotVisitor.appendUnbarriered(m_vm-&gt;exception());
+            slotVisitor.appendUnbarriered(m_vm-&gt;lastException());
+        },
+        MarkingConstraint::GreyedByExecution);
+    
+    m_constraintSet-&gt;add(
+        &quot;Sh&quot;, &quot;Strong Handles&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            m_handleSet.visitStrongHandles(slotVisitor);
+            m_handleStack.visit(slotVisitor);
+        },
+        MarkingConstraint::GreyedByExecution);
+    
+    m_constraintSet-&gt;add(
+        &quot;D&quot;, &quot;Debugger&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+#if ENABLE(SAMPLING_PROFILER)
+            if (SamplingProfiler* samplingProfiler = m_vm-&gt;samplingProfiler()) {
+                LockHolder locker(samplingProfiler-&gt;getLock());
+                samplingProfiler-&gt;processUnverifiedStackTraces();
+                samplingProfiler-&gt;visit(slotVisitor);
+                if (Options::logGC() == GCLogging::Verbose)
+                    dataLog(&quot;Sampling Profiler data:\n&quot;, slotVisitor);
+            }
+#endif // ENABLE(SAMPLING_PROFILER)
+            
+            if (m_vm-&gt;typeProfiler())
+                m_vm-&gt;typeProfilerLog()-&gt;visit(slotVisitor);
+            
+            m_vm-&gt;shadowChicken().visitChildren(slotVisitor);
+        },
+        MarkingConstraint::GreyedByExecution);
+    
+    m_constraintSet-&gt;add(
+        &quot;Jsr&quot;, &quot;JIT Stub Routines&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            m_jitStubRoutines-&gt;traceMarkedStubRoutines(slotVisitor);
+        },
+        MarkingConstraint::GreyedByExecution);
+    
+    m_constraintSet-&gt;add(
+        &quot;Ws&quot;, &quot;Weak Sets&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            slotVisitor.mergeOpaqueRootsIfNecessary();
+            for (auto&amp; parallelVisitor : m_parallelSlotVisitors)
+                parallelVisitor-&gt;mergeOpaqueRootsIfNecessary();
+            
+            m_objectSpace.visitWeakSets(slotVisitor);
+        },
+        MarkingConstraint::GreyedByMarking);
+    
+    m_constraintSet-&gt;add(
+        &quot;Wrh&quot;, &quot;Weak Reference Harvesters&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            for (WeakReferenceHarvester* current = m_weakReferenceHarvesters.head(); current; current = current-&gt;next())
+                current-&gt;visitWeakReferences(slotVisitor);
+        },
+        MarkingConstraint::GreyedByMarking);
+    
+#if ENABLE(DFG_JIT)
+    m_constraintSet-&gt;add(
+        &quot;Dw&quot;, &quot;DFG Worklists&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            for (unsigned i = DFG::numberOfWorklists(); i--;)
+                DFG::existingWorklistForIndex(i).visitWeakReferences(slotVisitor);
+            
+            // FIXME: This is almost certainly unnecessary.
+            // https://bugs.webkit.org/show_bug.cgi?id=166829
+            DFG::iterateCodeBlocksForGC(
+                *m_vm,
+                [&amp;] (CodeBlock* codeBlock) {
+                    slotVisitor.appendUnbarriered(codeBlock);
+                });
+            
+            if (Options::logGC() == GCLogging::Verbose)
+                dataLog(&quot;DFG Worklists:\n&quot;, slotVisitor);
+        },
+        MarkingConstraint::GreyedByMarking);
+#endif
+    
+    m_constraintSet-&gt;add(
+        &quot;Cb&quot;, &quot;CodeBlocks&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            iterateExecutingAndCompilingCodeBlocksWithoutHoldingLocks(
+                [&amp;] (CodeBlock* codeBlock) {
+                    // Visit the CodeBlock as a constraint only if it's black.
+                    if (Heap::isMarked(codeBlock)
+                        &amp;&amp; codeBlock-&gt;cellState() == CellState::PossiblyOldOrBlack)
+                        slotVisitor.visitAsConstraint(codeBlock);
+                });
+        },
+        MarkingConstraint::GreyedByExecution);
+    
+    m_constraintSet-&gt;add(
+        &quot;Mms&quot;, &quot;Mutator Mark Stack&quot;,
+        [this] (SlotVisitor&amp; slotVisitor, const VisitingTimeout&amp;) {
+            // Indicate to the fixpoint that we introduced work!
+            size_t size = m_mutatorMarkStack-&gt;size();
+            slotVisitor.addToVisitCount(size);
+            
+            if (Options::logGC())
+                dataLog(&quot;(&quot;, size, &quot;)&quot;);
+            
+            m_mutatorMarkStack-&gt;transferTo(slotVisitor.mutatorMarkStack());
+        },
+        [this] (SlotVisitor&amp;) -&gt; double {
+            return m_mutatorMarkStack-&gt;size();
+        },
+        MarkingConstraint::GreyedByExecution);
+}
+
</ins><span class="cx"> void Heap::notifyIsSafeToCollect()
</span><span class="cx"> {
</span><ins>+    buildConstraintSet();
+    
</ins><span class="cx">     m_isSafeToCollect = true;
</span><span class="cx">     
</span><span class="cx">     if (Options::collectContinuously()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -73,8 +73,10 @@
</span><span class="cx"> class LLIntOffsetsExtractor;
</span><span class="cx"> class MarkStackArray;
</span><span class="cx"> class MarkedArgumentBuffer;
</span><ins>+class MarkingConstraintSet;
+class MutatorScheduler;
</ins><span class="cx"> class SlotVisitor;
</span><del>-class SpaceTimeScheduler;
</del><ins>+class SpaceTimeMutatorScheduler;
</ins><span class="cx"> class StopIfNecessaryTimer;
</span><span class="cx"> class VM;
</span><span class="cx"> 
</span><span class="lines">@@ -201,7 +203,7 @@
</span><span class="cx">     // and this will wait for that backlog before running its GC and returning.
</span><span class="cx">     JS_EXPORT_PRIVATE void collectSync(std::optional&lt;CollectionScope&gt; = std::nullopt);
</span><span class="cx">     
</span><del>-    bool collectIfNecessaryOrDefer(GCDeferralContext* = nullptr); // Returns true if it did collect.
</del><ins>+    void collectIfNecessaryOrDefer(GCDeferralContext* = nullptr);
</ins><span class="cx"> 
</span><span class="cx">     void completeAllJITPlans();
</span><span class="cx">     
</span><span class="lines">@@ -375,7 +377,7 @@
</span><span class="cx">     friend class MarkedAllocator;
</span><span class="cx">     friend class MarkedBlock;
</span><span class="cx">     friend class SlotVisitor;
</span><del>-    friend class SpaceTimeScheduler;
</del><ins>+    friend class SpaceTimeMutatorScheduler;
</ins><span class="cx">     friend class IncrementalSweeper;
</span><span class="cx">     friend class HeapStatistics;
</span><span class="cx">     friend class VM;
</span><span class="lines">@@ -412,9 +414,6 @@
</span><span class="cx">     void stopTheWorld();
</span><span class="cx">     void resumeTheWorld();
</span><span class="cx">     
</span><del>-    class ResumeTheWorldScope;
-    friend class ResumeTheWorldScope;
-    
</del><span class="cx">     void stopTheMutator();
</span><span class="cx">     void resumeTheMutator();
</span><span class="cx">     
</span><span class="lines">@@ -454,7 +453,6 @@
</span><span class="cx">     void gatherJSStackRoots(ConservativeRoots&amp;);
</span><span class="cx">     void gatherScratchBufferRoots(ConservativeRoots&amp;);
</span><span class="cx">     void beginMarking();
</span><del>-    void visitConservativeRoots(ConservativeRoots&amp;);
</del><span class="cx">     void visitCompilerWorklistWeakReferences();
</span><span class="cx">     void removeDeadCompilerWorklistEntries();
</span><span class="cx">     void updateObjectCounts(double gcStartTime);
</span><span class="lines">@@ -498,6 +496,16 @@
</span><span class="cx">     JS_EXPORT_PRIVATE void writeBarrierOpaqueRootSlow(void*);
</span><span class="cx">     
</span><span class="cx">     void setMutatorShouldBeFenced(bool value);
</span><ins>+    
+    void buildConstraintSet();
+    
+    template&lt;typename Func&gt;
+    void iterateExecutingAndCompilingCodeBlocks(const Func&amp;);
+    
+    template&lt;typename Func&gt;
+    void iterateExecutingAndCompilingCodeBlocksWithoutHoldingLocks(const Func&amp;);
+    
+    void assertSharedMarkStacksEmpty();
</ins><span class="cx"> 
</span><span class="cx">     const HeapType m_heapType;
</span><span class="cx">     const size_t m_ramSize;
</span><span class="lines">@@ -534,6 +542,8 @@
</span><span class="cx">     
</span><span class="cx">     std::unique_ptr&lt;SlotVisitor&gt; m_collectorSlotVisitor;
</span><span class="cx">     std::unique_ptr&lt;MarkStackArray&gt; m_mutatorMarkStack;
</span><ins>+    
+    std::unique_ptr&lt;MarkingConstraintSet&gt; m_constraintSet;
</ins><span class="cx"> 
</span><span class="cx">     // We pool the slot visitors used by parallel marking threads. It's useful to be able to
</span><span class="cx">     // enumerate over them, and it's useful to have them cache some small amount of memory from
</span><span class="lines">@@ -616,6 +626,8 @@
</span><span class="cx">     size_t m_externalMemorySize { 0 };
</span><span class="cx"> #endif
</span><span class="cx">     
</span><ins>+    std::unique_ptr&lt;MutatorScheduler&gt; m_scheduler;
+    
</ins><span class="cx">     static const unsigned shouldStopBit = 1u &lt;&lt; 0u;
</span><span class="cx">     static const unsigned stoppedBit = 1u &lt;&lt; 1u;
</span><span class="cx">     static const unsigned hasAccessBit = 1u &lt;&lt; 2u;
</span><span class="lines">@@ -631,6 +643,7 @@
</span><span class="cx">     Ticket m_lastGrantedTicket { 0 };
</span><span class="cx">     bool m_threadShouldStop { false };
</span><span class="cx">     bool m_threadIsStopping { false };
</span><ins>+    bool m_mutatorDidRun { true };
</ins><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></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkingConstraintcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/MarkingConstraint.cpp (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkingConstraint.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/MarkingConstraint.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,77 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;MarkingConstraint.h&quot;
+
+#include &quot;JSCInlines.h&quot;
+
+namespace JSC {
+
+MarkingConstraint::MarkingConstraint(
+    CString abbreviatedName, CString name,
+    ::Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt; executeFunction,
+    Volatility volatility)
+    : m_abbreviatedName(abbreviatedName)
+    , m_name(WTFMove(name))
+    , m_executeFunction(WTFMove(executeFunction))
+    , m_volatility(volatility)
+{
+}
+
+MarkingConstraint::MarkingConstraint(
+    CString abbreviatedName, CString name,
+    ::Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt; executeFunction,
+    ::Function&lt;double(SlotVisitor&amp;)&gt; quickWorkEstimateFunction,
+    Volatility volatility)
+    : m_abbreviatedName(abbreviatedName)
+    , m_name(WTFMove(name))
+    , m_executeFunction(WTFMove(executeFunction))
+    , m_quickWorkEstimateFunction(WTFMove(quickWorkEstimateFunction))
+    , m_volatility(volatility)
+{
+}
+
+MarkingConstraint::~MarkingConstraint()
+{
+}
+
+void MarkingConstraint::resetStats()
+{
+    m_lastVisitCount = 0;
+}
+
+void MarkingConstraint::execute(SlotVisitor&amp; visitor, bool&amp; didVisitSomething, MonotonicTime timeout)
+{
+    if (Options::logGC())
+        dataLog(abbreviatedName());
+    VisitingTimeout visitingTimeout(visitor, didVisitSomething, timeout);
+    m_executeFunction(visitor, visitingTimeout);
+    m_lastVisitCount = visitingTimeout.visitCount(visitor);
+    didVisitSomething = visitingTimeout.didVisitSomething(visitor);
+}
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkingConstrainth"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/MarkingConstraint.h (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkingConstraint.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/MarkingConstraint.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,111 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include &quot;VisitingTimeout.h&quot;
+#include &lt;wtf/FastMalloc.h&gt;
+#include &lt;wtf/Function.h&gt;
+#include &lt;wtf/MonotonicTime.h&gt;
+#include &lt;wtf/Noncopyable.h&gt;
+#include &lt;wtf/text/CString.h&gt;
+
+namespace JSC {
+
+class MarkingConstraintSet;
+class SlotVisitor;
+
+class MarkingConstraint {
+    WTF_MAKE_NONCOPYABLE(MarkingConstraint);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    enum Volatility {
+        // FIXME: We could introduce a new kind of volatility called GreyedByResumption, which
+        // would mean running all of the times that GreyedByExecution runs except as a root in a
+        // full GC.
+        // https://bugs.webkit.org/show_bug.cgi?id=166830
+        
+        // The constraint needs to be reevaluated anytime the mutator runs: so at GC start and
+        // whenever the GC resuspends after a resumption. This is almost always something that
+        // you'd call a &quot;root&quot; in a traditional GC.
+        GreyedByExecution,
+        
+        // The constraint needs to be reevaluated any time any object is marked and anytime the
+        // mutator resumes.
+        GreyedByMarking
+    };
+    
+    MarkingConstraint(
+        CString abbreviatedName, CString name,
+        ::Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt;,
+        Volatility);
+    
+    MarkingConstraint(
+        CString abbreviatedName, CString name,
+        ::Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt;,
+        ::Function&lt;double(SlotVisitor&amp;)&gt;,
+        Volatility);
+    
+    ~MarkingConstraint();
+    
+    unsigned index() const { return m_index; }
+    
+    const char* abbreviatedName() const { return m_abbreviatedName.data(); }
+    const char* name() const { return m_name.data(); }
+    
+    void resetStats();
+    
+    size_t lastVisitCount() const { return m_lastVisitCount; }
+    
+    void execute(SlotVisitor&amp;, bool&amp; didVisitSomething, MonotonicTime timeout);
+    
+    double quickWorkEstimate(SlotVisitor&amp; visitor)
+    {
+        if (!m_quickWorkEstimateFunction)
+            return 0;
+        return m_quickWorkEstimateFunction(visitor);
+    }
+    
+    double workEstimate(SlotVisitor&amp; visitor)
+    {
+        return lastVisitCount() + quickWorkEstimate(visitor);
+    }
+    
+    Volatility volatility() const { return m_volatility; }
+    
+private:
+    friend class MarkingConstraintSet; // So it can set m_index.
+    
+    unsigned m_index { UINT_MAX };
+    CString m_abbreviatedName;
+    CString m_name;
+    ::Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp; timeout)&gt; m_executeFunction;
+    ::Function&lt;double(SlotVisitor&amp;)&gt; m_quickWorkEstimateFunction;
+    Volatility m_volatility;
+    size_t m_lastVisitCount { 0 };
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkingConstraintSetcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.cpp (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,239 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include &quot;config.h&quot;
+#include &quot;MarkingConstraintSet.h&quot;
+
+#include &quot;Options.h&quot;
+#include &lt;wtf/TimeWithDynamicClockType.h&gt;
+
+namespace JSC {
+
+class MarkingConstraintSet::ExecutionContext {
+public:
+    ExecutionContext(MarkingConstraintSet&amp; set, SlotVisitor&amp; visitor, MonotonicTime timeout)
+        : m_set(set)
+        , m_visitor(visitor)
+        , m_timeout(timeout)
+    {
+    }
+    
+    bool didVisitSomething() const
+    {
+        return m_didVisitSomething;
+    }
+    
+    bool shouldTimeOut() const
+    {
+        return didVisitSomething() &amp;&amp; hasElapsed(m_timeout);
+    }
+    
+    // Returns false if it times out.
+    bool drain(BitVector&amp; unexecuted)
+    {
+        for (size_t index : unexecuted) {
+            execute(index);
+            unexecuted.clear(index);
+            if (shouldTimeOut())
+                return false;
+        }
+        return true;
+    }
+    
+    bool didExecute(size_t index) const { return m_executed.get(index); }
+
+    void execute(size_t index)
+    {
+        m_set.m_set[index]-&gt;execute(m_visitor, m_didVisitSomething, m_timeout);
+        m_executed.set(index);
+    }
+    
+private:
+    MarkingConstraintSet&amp; m_set;
+    SlotVisitor&amp; m_visitor;
+    MonotonicTime m_timeout;
+    BitVector m_executed;
+    bool m_didVisitSomething { false };
+};
+
+MarkingConstraintSet::MarkingConstraintSet()
+{
+}
+
+MarkingConstraintSet::~MarkingConstraintSet()
+{
+}
+
+void MarkingConstraintSet::resetStats()
+{
+    m_unexecutedRoots.clearAll();
+    m_unexecutedOutgrowths.clearAll();
+    for (auto&amp; constraint : m_set) {
+        constraint-&gt;resetStats();
+        switch (constraint-&gt;volatility()) {
+        case MarkingConstraint::GreyedByExecution:
+            m_unexecutedRoots.set(constraint-&gt;index());
+            break;
+        case MarkingConstraint::GreyedByMarking:
+            m_unexecutedOutgrowths.set(constraint-&gt;index());
+            break;
+        }
+    }
+}
+
+void MarkingConstraintSet::add(CString abbreviatedName, CString name, Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt; function, MarkingConstraint::Volatility volatility)
+{
+    add(std::make_unique&lt;MarkingConstraint&gt;(WTFMove(abbreviatedName), WTFMove(name), WTFMove(function), volatility));
+}
+
+void MarkingConstraintSet::add(
+    CString abbreviatedName, CString name,
+    Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt; executeFunction,
+    Function&lt;double(SlotVisitor&amp;)&gt; quickWorkEstimateFunction,
+    MarkingConstraint::Volatility volatility)
+{
+    add(std::make_unique&lt;MarkingConstraint&gt;(WTFMove(abbreviatedName), WTFMove(name), WTFMove(executeFunction), WTFMove(quickWorkEstimateFunction), volatility));
+}
+
+void MarkingConstraintSet::add(
+    std::unique_ptr&lt;MarkingConstraint&gt; constraint)
+{
+    constraint-&gt;m_index = m_set.size();
+    m_ordered.append(constraint.get());
+    if (constraint-&gt;volatility() == MarkingConstraint::GreyedByMarking)
+        m_outgrowths.append(constraint.get());
+    m_set.append(WTFMove(constraint));
+}
+
+bool MarkingConstraintSet::executeBootstrap(SlotVisitor&amp; visitor, MonotonicTime timeout)
+{
+    // Bootstrap means that we haven't done any object visiting yet. This means that we want to
+    // only execute root constraints (which also happens to be those that we say are greyed by
+    // resumption), since the other constraints are super unlikely to trigger without some object
+    // visiting. The expectation is that the caller will go straight to object visiting after
+    // this.
+    ExecutionContext executionContext(*this, visitor, timeout);
+    if (Options::logGC())
+        dataLog(&quot;boot:&quot;);
+    bool result = executionContext.drain(m_unexecutedRoots);
+    if (Options::logGC())
+        dataLog(&quot; &quot;);
+    return result;
+}
+
+bool MarkingConstraintSet::executeConvergence(SlotVisitor&amp; visitor, MonotonicTime timeout)
+{
+    bool result = executeConvergenceImpl(visitor, timeout);
+    if (Options::logGC())
+        dataLog(&quot; &quot;);
+    return result;
+}
+
+bool MarkingConstraintSet::isWavefrontAdvancing(SlotVisitor&amp; visitor)
+{
+    for (MarkingConstraint* outgrowth : m_outgrowths) {
+        if (outgrowth-&gt;workEstimate(visitor))
+            return true;
+    }
+    return false;
+}
+
+bool MarkingConstraintSet::executeConvergenceImpl(SlotVisitor&amp; visitor, MonotonicTime timeout)
+{
+    ExecutionContext executionContext(*this, visitor, timeout);
+    
+    if (Options::logGC())
+        dataLog(&quot;converge:&quot;);
+
+    // If there are any constraints that we have not executed at all during this cycle, then
+    // we should execute those now.
+    if (!executionContext.drain(m_unexecutedRoots))
+        return false;
+    if (!executionContext.drain(m_unexecutedOutgrowths))
+        return false;
+    
+    // We want to keep preferring the outgrowth constraints - the ones that need to be fixpointed
+    // even in a stop-the-world GC - until they stop producing. They have a tendency to go totally
+    // silent at some point during GC, at which point it makes sense not to run them again until
+    // the end. Outgrowths producing new information corresponds almost exactly to the wavefront
+    // advancing: it usually means that we are marking objects that should be marked based on
+    // other objects that we would have marked anyway. Once the wavefront is no longer advancing,
+    // we want to run mostly the root constraints (based on their predictions of how much work
+    // they will have) because at this point we are just trying to outpace the retreating
+    // wavefront.
+    //
+    // Note that this function (executeConvergenceImpl) only returns true if it runs all
+    // constraints. So, all we are controlling are the heuristics that say which constraints to
+    // run first. Choosing the constraints that are the most likely to produce means running fewer
+    // constraints before returning.
+    bool isWavefrontAdvancing = this-&gt;isWavefrontAdvancing(visitor);
+    
+    std::sort(
+        m_ordered.begin(), m_ordered.end(),
+        [&amp;] (MarkingConstraint* a, MarkingConstraint* b) -&gt; bool {
+            // Remember: return true if a should come before b.
+            if (a-&gt;volatility() != b-&gt;volatility()) {
+                if (isWavefrontAdvancing)
+                    return a-&gt;volatility() &gt; b-&gt;volatility(); // GreyedByMarking should come before GreyedByExecution.
+                else
+                    return a-&gt;volatility() &lt; b-&gt;volatility(); // GreyedByExecution should come before GreyedByMarking.
+            }
+            
+            return a-&gt;workEstimate(visitor) &gt; b-&gt;workEstimate(visitor);
+        });
+    
+    for (MarkingConstraint* constraint : m_ordered) {
+        size_t i = constraint-&gt;index();
+        
+        if (executionContext.didExecute(i))
+            continue;
+        executionContext.execute(i);
+        
+        // Once we're in convergence, it makes the most sense to let some marking happen anytime
+        // we find work.
+        // FIXME: Maybe this should execute all constraints until timeout? Not clear if that's
+        // better or worse. Maybe even better is this:
+        // - If the visitor is empty, keep running.
+        // - If the visitor is has at least N things, return.
+        // - Else run until timeout.
+        // https://bugs.webkit.org/show_bug.cgi?id=166832
+        if (executionContext.didVisitSomething())
+            return false;
+    }
+    
+    return true;
+}
+
+void MarkingConstraintSet::executeAll(SlotVisitor&amp; visitor)
+{
+    bool didVisitSomething = false;
+    for (auto&amp; constraint : m_set)
+        constraint-&gt;execute(visitor, didVisitSomething, MonotonicTime::infinity());
+    if (Options::logGC())
+        dataLog(&quot; &quot;);
+}
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkingConstraintSeth"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.h (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/MarkingConstraintSet.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,90 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include &quot;MarkingConstraint.h&quot;
+#include &lt;wtf/BitVector.h&gt;
+#include &lt;wtf/Vector.h&gt;
+
+namespace JSC {
+
+class MarkingConstraintSet {
+public:
+    MarkingConstraintSet();
+    ~MarkingConstraintSet();
+    
+    void resetStats();
+    
+    void add(
+        CString abbreviatedName,
+        CString name,
+        ::Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt;,
+        MarkingConstraint::Volatility);
+    
+    void add(
+        CString abbreviatedName,
+        CString name,
+        ::Function&lt;void(SlotVisitor&amp;, const VisitingTimeout&amp;)&gt;,
+        ::Function&lt;double(SlotVisitor&amp;)&gt;,
+        MarkingConstraint::Volatility);
+    
+    void add(std::unique_ptr&lt;MarkingConstraint&gt;);
+    
+    // Assuming that the mark stacks are all empty, this will give you a guess as to whether or
+    // not the wavefront is advancing.
+    bool isWavefrontAdvancing(SlotVisitor&amp;);
+    bool isWavefrontRetreating(SlotVisitor&amp; visitor) { return !isWavefrontAdvancing(visitor); }
+    
+    // Executes only roots. Returns true if all roots have been executed. It's expected
+    // that you'll do some draining after this and then use executeConvergence().
+    bool executeBootstrap(SlotVisitor&amp;, MonotonicTime timeout = MonotonicTime::infinity());
+    
+    // Returns true if all constraints were executed. This assumes that you've alraedy
+    // visited roots and drained from there.
+    bool executeConvergence(
+        SlotVisitor&amp;,
+        MonotonicTime timeout = MonotonicTime::infinity());
+    
+    // Simply runs all constraints without any shenanigans.
+    void executeAll(SlotVisitor&amp;);
+    
+private:
+    class ExecutionContext;
+    friend class ExecutionContext;
+    
+    bool executeConvergenceImpl(SlotVisitor&amp;, MonotonicTime timeout);
+    
+    bool drain(SlotVisitor&amp;, MonotonicTime, BitVector&amp; unexecuted, BitVector&amp; executed, bool&amp; didVisitSomething);
+    
+    BitVector m_unexecutedRoots;
+    BitVector m_unexecutedOutgrowths;
+    Vector&lt;std::unique_ptr&lt;MarkingConstraint&gt;&gt; m_set;
+    Vector&lt;MarkingConstraint*&gt; m_ordered;
+    Vector&lt;MarkingConstraint*&gt; m_outgrowths;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMutatorSchedulercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/MutatorScheduler.cpp (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MutatorScheduler.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/MutatorScheduler.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;MutatorScheduler.h&quot;
+
+#include &lt;wtf/TimeWithDynamicClockType.h&gt;
+
+namespace JSC {
+
+MutatorScheduler::MutatorScheduler()
+{
+}
+
+MutatorScheduler::~MutatorScheduler()
+{
+}
+
+void MutatorScheduler::didStop()
+{
+}
+
+void MutatorScheduler::willResume()
+{
+}
+
+void MutatorScheduler::didExecuteConstraints()
+{
+}
+
+void MutatorScheduler::log()
+{
+}
+
+bool MutatorScheduler::shouldStop()
+{
+    return hasElapsed(timeToStop());
+}
+
+bool MutatorScheduler::shouldResume()
+{
+    return hasElapsed(timeToResume());
+}
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMutatorSchedulerh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/MutatorScheduler.h (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MutatorScheduler.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/MutatorScheduler.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+/*
+ * Copyright (C) 2017 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. 
+ */
+
+#pragma once
+
+#include &lt;wtf/FastMalloc.h&gt;
+#include &lt;wtf/MonotonicTime.h&gt;
+#include &lt;wtf/Noncopyable.h&gt;
+
+namespace JSC {
+
+class MutatorScheduler {
+    WTF_MAKE_NONCOPYABLE(MutatorScheduler);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    enum State {
+        Normal, // Not collecting.
+        Stopped,
+        Resumed
+    };
+    
+    MutatorScheduler();
+    virtual ~MutatorScheduler();
+    
+    virtual State state() const = 0;
+    
+    virtual void beginCollection() = 0;
+    
+    virtual void didStop();
+    virtual void willResume();
+    virtual void didExecuteConstraints();
+    
+    virtual MonotonicTime timeToStop() = 0; // Call while resumed, to ask when to stop.
+    virtual MonotonicTime timeToResume() = 0; // Call while stopped, to ask when to resume.
+    
+    virtual void log();
+    
+    bool shouldStop(); // Call while resumed, to ask if we should stop now.
+    bool shouldResume(); // Call while stopped, to ask if we should resume now.
+    
+    virtual void endCollection() = 0;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapOpaqueRootSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/OpaqueRootSet.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/OpaqueRootSet.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/OpaqueRootSet.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -59,11 +59,11 @@
</span><span class="cx">         m_containsLastQueriedRoot = false;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void add(void* root)
</del><ins>+    bool add(void* root)
</ins><span class="cx">     {
</span><span class="cx">         if (root == m_lastQueriedRoot)
</span><span class="cx">             m_containsLastQueriedRoot = true;
</span><del>-        m_roots.add(root);
</del><ins>+        return m_roots.add(root).isNewEntry;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     int size() const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2015-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -347,6 +347,11 @@
</span><span class="cx">     SlotVisitor&amp; m_visitor;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+void SlotVisitor::visitAsConstraint(const JSCell* cell)
+{
+    m_isVisitingMutatorStack = true;
+    visitChildren(cell);
+}
</ins><span class="cx"> 
</span><span class="cx"> ALWAYS_INLINE void SlotVisitor::visitChildren(const JSCell* cell)
</span><span class="cx"> {
</span><span class="lines">@@ -461,7 +466,7 @@
</span><span class="cx">     
</span><span class="cx">     auto locker = holdLock(m_rightToRun);
</span><span class="cx">     
</span><del>-    while ((!m_collectorStack.isEmpty() || !m_mutatorStack.isEmpty()) &amp;&amp; !hasElapsed(timeout)) {
</del><ins>+    while (!hasElapsed(timeout)) {
</ins><span class="cx">         updateMutatorIsStopped(locker);
</span><span class="cx">         if (!m_collectorStack.isEmpty()) {
</span><span class="cx">             m_collectorStack.refill();
</span><span class="lines">@@ -476,7 +481,8 @@
</span><span class="cx">             m_isVisitingMutatorStack = true;
</span><span class="cx">             for (unsigned countdown = Options::minimumNumberOfScansBetweenRebalance(); m_mutatorStack.canRemoveLast() &amp;&amp; countdown--;)
</span><span class="cx">                 visitChildren(m_mutatorStack.removeLast());
</span><del>-        }
</del><ins>+        } else
+            break;
</ins><span class="cx">         m_rightToRun.safepoint();
</span><span class="cx">         donateKnownParallel();
</span><span class="cx">     }
</span><span class="lines">@@ -486,12 +492,18 @@
</span><span class="cx"> 
</span><span class="cx"> bool SlotVisitor::didReachTermination()
</span><span class="cx"> {
</span><ins>+    LockHolder locker(m_heap.m_markingMutex);
+    return isEmpty() &amp;&amp; didReachTermination(locker);
+}
+
+bool SlotVisitor::didReachTermination(const LockHolder&amp;)
+{
</ins><span class="cx">     return !m_heap.m_numberOfActiveParallelMarkers
</span><span class="cx">         &amp;&amp; m_heap.m_sharedCollectorMarkStack-&gt;isEmpty()
</span><span class="cx">         &amp;&amp; m_heap.m_sharedMutatorMarkStack-&gt;isEmpty();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool SlotVisitor::hasWork()
</del><ins>+bool SlotVisitor::hasWork(const LockHolder&amp;)
</ins><span class="cx"> {
</span><span class="cx">     return !m_heap.m_sharedCollectorMarkStack-&gt;isEmpty()
</span><span class="cx">         || !m_heap.m_sharedMutatorMarkStack-&gt;isEmpty();
</span><span class="lines">@@ -518,12 +530,12 @@
</span><span class="cx">                     if (hasElapsed(timeout))
</span><span class="cx">                         return SharedDrainResult::TimedOut;
</span><span class="cx">                     
</span><del>-                    if (didReachTermination()) {
</del><ins>+                    if (didReachTermination(locker)) {
</ins><span class="cx">                         m_heap.m_markingConditionVariable.notifyAll();
</span><span class="cx">                         return SharedDrainResult::Done;
</span><span class="cx">                     }
</span><span class="cx">                     
</span><del>-                    if (hasWork())
</del><ins>+                    if (hasWork(locker))
</ins><span class="cx">                         break;
</span><span class="cx">                     
</span><span class="cx">                     m_heap.m_markingConditionVariable.waitUntil(m_heap.m_markingMutex, timeout);
</span><span class="lines">@@ -534,13 +546,13 @@
</span><span class="cx">                 if (hasElapsed(timeout))
</span><span class="cx">                     return SharedDrainResult::TimedOut;
</span><span class="cx">                 
</span><del>-                if (didReachTermination())
</del><ins>+                if (didReachTermination(locker))
</ins><span class="cx">                     m_heap.m_markingConditionVariable.notifyAll();
</span><span class="cx"> 
</span><span class="cx">                 m_heap.m_markingConditionVariable.waitUntil(
</span><span class="cx">                     m_heap.m_markingMutex, timeout,
</span><del>-                    [this] {
-                        return hasWork()
</del><ins>+                    [&amp;] {
+                        return hasWork(locker)
</ins><span class="cx">                             || m_heap.m_parallelMarkersShouldExit;
</span><span class="cx">                     });
</span><span class="cx">                 
</span><span class="lines">@@ -589,7 +601,7 @@
</span><span class="cx">         if (hasElapsed(timeout))
</span><span class="cx">             return SharedDrainResult::TimedOut;
</span><span class="cx">         
</span><del>-        if (didReachTermination()) {
</del><ins>+        if (didReachTermination(locker)) {
</ins><span class="cx">             m_heap.m_markingConditionVariable.notifyAll();
</span><span class="cx">             return SharedDrainResult::Done;
</span><span class="cx">         }
</span><span class="lines">@@ -605,13 +617,13 @@
</span><span class="cx">     
</span><span class="cx">     if (Options::numberOfGCMarkers() == 1) {
</span><span class="cx">         // Put directly into the shared HashSet.
</span><del>-        m_heap.m_opaqueRoots.add(root);
</del><ins>+        m_visitCount += m_heap.m_opaqueRoots.add(root).isNewEntry;
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     // Put into the local set, but merge with the shared one every once in
</span><span class="cx">     // a while to make sure that the local sets don't grow too large.
</span><span class="cx">     mergeOpaqueRootsIfProfitable();
</span><del>-    m_opaqueRoots.add(root);
</del><ins>+    m_visitCount += m_opaqueRoots.add(root);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool SlotVisitor::containsOpaqueRoot(void* root) const
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitor.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitor.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011-2013, 2015-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -103,6 +103,8 @@
</span><span class="cx"> 
</span><span class="cx">     size_t bytesVisited() const { return m_bytesVisited; }
</span><span class="cx">     size_t visitCount() const { return m_visitCount; }
</span><ins>+    
+    void addToVisitCount(size_t value) { m_visitCount += value; }
</ins><span class="cx"> 
</span><span class="cx">     void donate();
</span><span class="cx">     void drain(MonotonicTime timeout = MonotonicTime::infinity());
</span><span class="lines">@@ -151,6 +153,10 @@
</span><span class="cx">     void didRace(JSCell* cell, const char* reason) { didRace(VisitRaceKey(cell, reason)); }
</span><span class="cx">     void didNotRace(const VisitRaceKey&amp;);
</span><span class="cx">     void didNotRace(JSCell* cell, const char* reason) { didNotRace(VisitRaceKey(cell, reason)); }
</span><ins>+    
+    void visitAsConstraint(const JSCell*);
+    
+    bool didReachTermination();
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     friend class ParallelModeEnabler;
</span><span class="lines">@@ -180,8 +186,8 @@
</span><span class="cx">     void donateKnownParallel();
</span><span class="cx">     void donateKnownParallel(MarkStackArray&amp; from, MarkStackArray&amp; to);
</span><span class="cx">     
</span><del>-    bool hasWork();
-    bool didReachTermination();
</del><ins>+    bool hasWork(const LockHolder&amp;);
+    bool didReachTermination(const LockHolder&amp;);
</ins><span class="cx"> 
</span><span class="cx">     MarkStackArray m_collectorStack;
</span><span class="cx">     MarkStackArray m_mutatorStack;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSpaceTimeMutatorSchedulercppfromrev210520trunkSourceJavaScriptCoreheapSpaceTimeSchedulercpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.cpp (from rev 210520, trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp) (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,221 @@
</span><ins>+/*
+ * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;SpaceTimeMutatorScheduler.h&quot;
+
+#include &quot;JSCInlines.h&quot;
+
+namespace JSC {
+
+// The scheduler will often make decisions based on state that is in flux. It will be fine so
+// long as multiple uses of the same value all see the same value. We wouldn't get this for free,
+// since our need to modularize the calculation results in a tendency to access the same mutable
+// field in Heap multiple times, and to access the current time multiple times.
+class SpaceTimeMutatorScheduler::Snapshot {
+public:
+    Snapshot(SpaceTimeMutatorScheduler&amp; scheduler)
+    {
+        m_now = MonotonicTime::now();
+        m_bytesAllocatedThisCycle = scheduler.bytesAllocatedThisCycleImpl();
+    }
+    
+    MonotonicTime now() const { return m_now; }
+    
+    double bytesAllocatedThisCycle() const { return m_bytesAllocatedThisCycle; }
+    
+private:
+    MonotonicTime m_now;
+    double m_bytesAllocatedThisCycle;
+};
+
+SpaceTimeMutatorScheduler::SpaceTimeMutatorScheduler(Heap&amp; heap)
+    : m_heap(heap)
+    , m_period(Seconds::fromMilliseconds(Options::concurrentGCPeriodMS()))
+{
+}
+
+SpaceTimeMutatorScheduler::~SpaceTimeMutatorScheduler()
+{
+}
+
+MutatorScheduler::State SpaceTimeMutatorScheduler::state() const
+{
+    return m_state;
+}
+
+void SpaceTimeMutatorScheduler::beginCollection()
+{
+    RELEASE_ASSERT(m_state == Normal);
+    m_state = Stopped;
+    m_startTime = MonotonicTime::now();
+
+    m_bytesAllocatedThisCycleAtTheBeginning = m_heap.m_bytesAllocatedThisCycle;
+    m_bytesAllocatedThisCycleAtTheEnd = 
+        Options::concurrentGCMaxHeadroom() *
+        std::max&lt;double&gt;(m_bytesAllocatedThisCycleAtTheBeginning, m_heap.m_maxEdenSize);
+}
+
+void SpaceTimeMutatorScheduler::didStop()
+{
+    RELEASE_ASSERT(m_state == Stopped || m_state == Resumed);
+    m_state = Stopped;
+}
+
+void SpaceTimeMutatorScheduler::willResume()
+{
+    RELEASE_ASSERT(m_state == Stopped || m_state == Resumed);
+    m_state = Resumed;
+}
+
+void SpaceTimeMutatorScheduler::didExecuteConstraints()
+{
+    // If we execute constraints, we want to forgive the GC for all of the time it had stopped the
+    // world for in this increment. This hack is empirically better than every other heuristic I
+    // tried, because it just means that the GC is happy to pause for longer when it's dealing
+    // with things that don't play well with concurrency.
+    // FIXME: The feels so wrong but benchmarks so good.
+    // https://bugs.webkit.org/show_bug.cgi?id=166833
+    m_startTime = MonotonicTime::now();
+}
+
+MonotonicTime SpaceTimeMutatorScheduler::timeToStop()
+{
+    switch (m_state) {
+    case Normal:
+        return MonotonicTime::infinity();
+    case Stopped:
+        return MonotonicTime::now();
+    case Resumed: {
+        Snapshot snapshot(*this);
+        if (!shouldBeResumed(snapshot))
+            return snapshot.now();
+        return snapshot.now() - elapsedInPeriod(snapshot) + m_period;
+    } }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+    return MonotonicTime();
+}
+
+MonotonicTime SpaceTimeMutatorScheduler::timeToResume()
+{
+    switch (m_state) {
+    case Normal:
+    case Resumed:
+        return MonotonicTime::now();
+    case Stopped: {
+        Snapshot snapshot(*this);
+        if (shouldBeResumed(snapshot))
+            return snapshot.now();
+        return snapshot.now() - elapsedInPeriod(snapshot) + m_period * collectorUtilization(snapshot);
+    } }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+    return MonotonicTime();
+}
+
+void SpaceTimeMutatorScheduler::log()
+{
+    ASSERT(Options::logGC());
+    Snapshot snapshot(*this);
+    dataLog(
+        &quot;a=&quot;, format(&quot;%.0lf&quot;, bytesSinceBeginningOfCycle(snapshot) / 1024), &quot; kb &quot;,
+        &quot;hf=&quot;, format(&quot;%.3lf&quot;, headroomFullness(snapshot)), &quot; &quot;,
+        &quot;mu=&quot;, format(&quot;%.3lf&quot;, mutatorUtilization(snapshot)), &quot; &quot;);
+}
+
+void SpaceTimeMutatorScheduler::endCollection()
+{
+    m_state = Normal;
+    m_startTime = MonotonicTime::now();
+}
+
+double SpaceTimeMutatorScheduler::bytesAllocatedThisCycleImpl()
+{
+    return m_heap.m_bytesAllocatedThisCycle;
+}
+
+double SpaceTimeMutatorScheduler::bytesSinceBeginningOfCycle(const Snapshot&amp; snapshot)
+{
+    return snapshot.bytesAllocatedThisCycle() - m_bytesAllocatedThisCycleAtTheBeginning;
+}
+
+double SpaceTimeMutatorScheduler::maxHeadroom()
+{
+    return m_bytesAllocatedThisCycleAtTheEnd - m_bytesAllocatedThisCycleAtTheBeginning;
+}
+
+double SpaceTimeMutatorScheduler::headroomFullness(const Snapshot&amp; snapshot)
+{
+    double result = bytesSinceBeginningOfCycle(snapshot) / maxHeadroom();
+
+    // 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.
+    
+    if (!(result &gt;= 0))
+        result = 0;
+    if (!(result &lt;= 1))
+        result = 1;
+
+    return result;
+}
+
+double SpaceTimeMutatorScheduler::mutatorUtilization(const Snapshot&amp; snapshot)
+{
+    double mutatorUtilization = 1 - headroomFullness(snapshot);
+    
+    // Scale the mutator utilization into the permitted window.
+    mutatorUtilization =
+        Options::minimumMutatorUtilization() +
+        mutatorUtilization * (
+            Options::maximumMutatorUtilization() -
+            Options::minimumMutatorUtilization());
+    
+    return mutatorUtilization;
+}
+
+double SpaceTimeMutatorScheduler::collectorUtilization(const Snapshot&amp; snapshot)
+{
+    return 1 - mutatorUtilization(snapshot);
+}
+
+Seconds SpaceTimeMutatorScheduler::elapsedInPeriod(const Snapshot&amp; snapshot)
+{
+    return (snapshot.now() - m_startTime) % m_period;
+}
+
+double SpaceTimeMutatorScheduler::phase(const Snapshot&amp; snapshot)
+{
+    return elapsedInPeriod(snapshot) / m_period;
+}
+
+bool SpaceTimeMutatorScheduler::shouldBeResumed(const Snapshot&amp; snapshot)
+{
+    return phase(snapshot) &gt; collectorUtilization(snapshot);
+}
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSpaceTimeMutatorSchedulerhfromrev210520trunkSourceJavaScriptCoreheapSpaceTimeSchedulerh"></a>
<div class="copfile"><h4>Copied: trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.h (from rev 210520, trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h) (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/SpaceTimeMutatorScheduler.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,86 @@
</span><ins>+/*
+ * Copyright (C) 2016-2017 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. 
+ */
+
+#pragma once
+
+#include &quot;MutatorScheduler.h&quot;
+#include &lt;wtf/Seconds.h&gt;
+
+namespace JSC {
+
+class Heap;
+
+// The JSC concurrent GC sometimes stops the world in order to stay ahead of it. These deliberate,
+// synthetic pauses ensure that the GC won't have to do one huge pause in order to catch up to the
+// retreating wavefront. The scheduler is called &quot;space-time&quot; because it links the amount of time
+// that the world is paused for to the amount of space that the world allocated since the GC cycle
+// began.
+
+class SpaceTimeMutatorScheduler : public MutatorScheduler {
+public:
+    SpaceTimeMutatorScheduler(Heap&amp;);
+    ~SpaceTimeMutatorScheduler();
+    
+    State state() const override;
+    
+    void beginCollection() override;
+    
+    void didStop() override;
+    void willResume() override;
+    void didExecuteConstraints() override;
+    
+    MonotonicTime timeToStop() override;
+    MonotonicTime timeToResume() override;
+    
+    void log() override;
+    
+    void endCollection() override;
+    
+private:
+    class Snapshot;
+    friend class Snapshot;
+    
+    double bytesAllocatedThisCycleImpl();
+    
+    double bytesSinceBeginningOfCycle(const Snapshot&amp;);
+    double maxHeadroom();
+    double headroomFullness(const Snapshot&amp;);
+    double mutatorUtilization(const Snapshot&amp;);
+    double collectorUtilization(const Snapshot&amp;);
+    Seconds elapsedInPeriod(const Snapshot&amp;);
+    double phase(const Snapshot&amp;);
+    bool shouldBeResumed(const Snapshot&amp;);
+    
+    Heap&amp; m_heap;
+    Seconds m_period;
+    State m_state { Normal };
+    
+    double m_bytesAllocatedThisCycleAtTheBeginning { 0 };
+    double m_bytesAllocatedThisCycleAtTheEnd { 0 };
+    MonotonicTime m_startTime;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSpaceTimeSchedulercpp"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,129 +0,0 @@
</span><del>-/*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#include &quot;config.h&quot;
-#include &quot;SpaceTimeScheduler.h&quot;
-
-#include &quot;JSCInlines.h&quot;
-
-namespace JSC {
-
-double SpaceTimeScheduler::Decision::targetMutatorUtilization() const
-{
-    double bytesSinceBeginningOfCycle =
-        m_bytesAllocatedThisCycle - m_scheduler-&gt;m_bytesAllocatedThisCycleAtTheBeginning;
-    
-    double maxHeadroom =
-        m_scheduler-&gt;m_bytesAllocatedThisCycleAtTheEnd - m_scheduler-&gt;m_bytesAllocatedThisCycleAtTheBeginning;
-    
-    double headroomFullness =
-        bytesSinceBeginningOfCycle / maxHeadroom;
-    
-    // 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.
-    
-    if (!(headroomFullness &gt;= 0))
-        headroomFullness = 0;
-    if (!(headroomFullness &lt;= 1))
-        headroomFullness = 1;
-    
-    double mutatorUtilization = 1 - headroomFullness;
-    
-    // Scale the mutator utilization into the permitted window.
-    mutatorUtilization =
-        Options::minimumMutatorUtilization() +
-        mutatorUtilization * (
-            Options::maximumMutatorUtilization() -
-            Options::minimumMutatorUtilization());
-    
-    return mutatorUtilization;
-}
-
-double SpaceTimeScheduler::Decision::targetCollectorUtilization() const
-{
-    return 1 - targetMutatorUtilization();
-}
-
-Seconds SpaceTimeScheduler::Decision::elapsedInPeriod() const
-{
-    return (m_now - m_scheduler-&gt;m_initialTime) % m_scheduler-&gt;m_period;
-}
-
-double SpaceTimeScheduler::Decision::phase() const
-{
-    return elapsedInPeriod() / m_scheduler-&gt;m_period;
-}
-
-bool SpaceTimeScheduler::Decision::shouldBeResumed() const
-{
-    if (Options::collectorShouldResumeFirst())
-        return phase() &lt;= targetMutatorUtilization();
-    return phase() &gt; targetCollectorUtilization();
-}
-
-MonotonicTime SpaceTimeScheduler::Decision::timeToResume() const
-{
-    ASSERT(!shouldBeResumed());
-    if (Options::collectorShouldResumeFirst())
-        return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period;
-    return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period * targetCollectorUtilization();
-}
-
-MonotonicTime SpaceTimeScheduler::Decision::timeToStop() const
-{
-    ASSERT(shouldBeResumed());
-    if (Options::collectorShouldResumeFirst())
-        return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period * targetMutatorUtilization();
-    return m_now - elapsedInPeriod() + m_scheduler-&gt;m_period;
-}
-
-SpaceTimeScheduler::SpaceTimeScheduler(Heap&amp; heap)
-    : m_heap(heap)
-    , m_period(Seconds::fromMilliseconds(Options::concurrentGCPeriodMS()))
-    , m_bytesAllocatedThisCycleAtTheBeginning(heap.m_bytesAllocatedThisCycle)
-    , m_bytesAllocatedThisCycleAtTheEnd(
-        Options::concurrentGCMaxHeadroom() *
-        std::max&lt;double&gt;(m_bytesAllocatedThisCycleAtTheBeginning, heap.m_maxEdenSize))
-{
-    snapPhase();
-}
-
-void SpaceTimeScheduler::snapPhase()
-{
-    m_initialTime = MonotonicTime::now();
-}
-
-SpaceTimeScheduler::Decision SpaceTimeScheduler::currentDecision()
-{
-    Decision result;
-    result.m_scheduler = this;
-    result.m_bytesAllocatedThisCycle = m_heap.m_bytesAllocatedThisCycle;
-    result.m_now = MonotonicTime::now();
-    return result;
-}
-
-} // namespace JSC
-
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSpaceTimeSchedulerh"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/heap/SpaceTimeScheduler.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -1,78 +0,0 @@
</span><del>-/*
- * Copyright (C) 2016 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#pragma once
-
-#include &lt;wtf/MonotonicTime.h&gt;
-#include &lt;wtf/Seconds.h&gt;
-
-namespace JSC {
-
-class Heap;
-
-class SpaceTimeScheduler {
-public:
-    class Decision {
-    public:
-        explicit operator bool() const { return !!m_scheduler; }
-        
-        double targetMutatorUtilization() const;
-        double targetCollectorUtilization() const;
-        Seconds elapsedInPeriod() const;
-        double phase() const;
-        bool shouldBeResumed() const;
-        MonotonicTime timeToResume() const;
-        MonotonicTime timeToStop() const;
-        
-    private:
-        friend class SpaceTimeScheduler;
-
-        SpaceTimeScheduler* m_scheduler { nullptr };
-        double m_bytesAllocatedThisCycle { 0 };
-        MonotonicTime m_now;
-    };
-    
-    // Construct the scheduler at the start of a GC cycle.
-    SpaceTimeScheduler(Heap&amp;);
-    
-    // Forces the next phase to start now.
-    void snapPhase();
-    
-    // Returns a snapshot of the current scheduling decision, which will be valid so long as
-    // SpaceTimeScheduler is live and you haven't called snapPhase().
-    Decision currentDecision();
-    
-private:
-    friend class Decision;
-
-    Heap&amp; m_heap;
-    Seconds m_period;
-    double m_bytesAllocatedThisCycleAtTheBeginning;
-    double m_bytesAllocatedThisCycleAtTheEnd;
-    MonotonicTime m_initialTime;
-};
-
-} // namespace JSC
-
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSynchronousStopTheWorldMutatorSchedulercpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.cpp (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.cpp        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;SynchronousStopTheWorldMutatorScheduler.h&quot;
+
+namespace JSC {
+
+SynchronousStopTheWorldMutatorScheduler::SynchronousStopTheWorldMutatorScheduler()
+{
+}
+
+SynchronousStopTheWorldMutatorScheduler::~SynchronousStopTheWorldMutatorScheduler()
+{
+}
+
+MutatorScheduler::State SynchronousStopTheWorldMutatorScheduler::state() const
+{
+    return m_state;
+}
+
+void SynchronousStopTheWorldMutatorScheduler::beginCollection()
+{
+    RELEASE_ASSERT(m_state == Normal);
+    m_state = Stopped;
+}
+
+MonotonicTime SynchronousStopTheWorldMutatorScheduler::timeToStop()
+{
+    return m_state == Normal ? MonotonicTime::infinity() : MonotonicTime::now();
+}
+
+MonotonicTime SynchronousStopTheWorldMutatorScheduler::timeToResume()
+{
+    return m_state == Normal ? MonotonicTime::now() : MonotonicTime::infinity();
+}
+
+void SynchronousStopTheWorldMutatorScheduler::endCollection()
+{
+    RELEASE_ASSERT(m_state == Stopped);
+    m_state = Normal;
+}
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSynchronousStopTheWorldMutatorSchedulerh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.h (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/SynchronousStopTheWorldMutatorScheduler.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+/*
+ * Copyright (C) 2017 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. 
+ */
+
+#pragma once
+
+#include &quot;MutatorScheduler.h&quot;
+
+namespace JSC {
+
+// The JSC concurrent GC relies on stopping the world to stay ahead of the retreating wavefront.
+// It so happens that the same API can be reused to implement a non-concurrent GC mode, which we
+// use on platforms that don't support the GC's atomicity protocols. That means anything other
+// than X86-64 and ARM64. This scheduler is a drop-in replacement for the concurrent GC's
+// SpaceTimeMutatorScheduler. It tells the GC to never resume the world once the GC cycle begins.
+
+class SynchronousStopTheWorldMutatorScheduler : public MutatorScheduler {
+public:
+    SynchronousStopTheWorldMutatorScheduler();
+    ~SynchronousStopTheWorldMutatorScheduler();
+    
+    State state() const override;
+    
+    void beginCollection() override;
+    
+    MonotonicTime timeToStop() override;
+    MonotonicTime timeToResume() override;
+    
+    void endCollection() override;
+
+private:
+    State m_state { Normal };
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapVisitingTimeouth"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/VisitingTimeout.h (0 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/VisitingTimeout.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/VisitingTimeout.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include &quot;SlotVisitor.h&quot;
+#include &lt;wtf/MonotonicTime.h&gt;
+
+namespace JSC {
+
+class VisitingTimeout {
+public:
+    VisitingTimeout()
+    {
+    }
+    
+    VisitingTimeout(SlotVisitor&amp; visitor, bool didVisitSomething, MonotonicTime timeout)
+        : m_didVisitSomething(didVisitSomething)
+        , m_visitCountBefore(visitor.visitCount())
+        , m_timeout(timeout)
+    {
+    }
+    
+    size_t visitCount(SlotVisitor&amp; visitor) const
+    {
+        return visitor.visitCount() - m_visitCountBefore;
+    }
+
+    bool didVisitSomething(SlotVisitor&amp; visitor) const
+    {
+        return m_didVisitSomething || visitCount(visitor);
+    }
+    
+    bool shouldTimeOut(SlotVisitor&amp; visitor) const
+    {
+        return didVisitSomething(visitor) &amp;&amp; hasElapsed(m_timeout);
+    }
+    
+private:
+    bool m_didVisitSomething { false };
+    size_t m_visitCountBefore { 0 };
+    MonotonicTime m_timeout;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (210520 => 210521)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2017-01-09 21:31:50 UTC (rev 210520)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2017-01-09 21:45:56 UTC (rev 210521)
</span><span class="lines">@@ -202,8 +202,6 @@
</span><span class="cx">     v(double, maximumMutatorUtilization, 0.7, Normal, nullptr) \
</span><span class="cx">     v(double, concurrentGCMaxHeadroom, 1.5, Normal, nullptr) \
</span><span class="cx">     v(double, concurrentGCPeriodMS, 2, Normal, nullptr) \
</span><del>-    v(bool, collectorShouldResumeFirst, false, Normal, nullptr) \
-    v(double, collectorPermittedIdleRatio, 0, Normal, nullptr) \
</del><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>
</div>

</body>
</html>