<!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>[213037] releases/WebKitGTK/webkit-2.16</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/213037">213037</a></dd>
<dt>Author</dt> <dd>carlosgc@webkit.org</dd>
<dt>Date</dt> <dd>2017-02-27 00:24:07 -0800 (Mon, 27 Feb 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>The collector thread should only start when the mutator doesn't have heap access
https://bugs.webkit.org/show_bug.cgi?id=167737

Reviewed by Keith Miller.
JSTests:

        
Add versions of splay that flash heap access, to simulate what might happen if a third-party app
was running concurrent GC. In this case, we might actually start the collector thread.

* stress/splay-flash-access-1ms.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):
* stress/splay-flash-access.js: Added.
(performance.now):
(this.Setup.setup.setup):
(this.TearDown.tearDown.tearDown):
(Benchmark):
(BenchmarkResult):
(BenchmarkResult.prototype.valueOf):
(BenchmarkSuite):
(alert):
(Math.random):
(BenchmarkSuite.ResetRNG):
(RunStep):
(BenchmarkSuite.RunSuites):
(BenchmarkSuite.CountBenchmarks):
(BenchmarkSuite.GeometricMean):
(BenchmarkSuite.GeometricMeanTime):
(BenchmarkSuite.AverageAbovePercentile):
(BenchmarkSuite.GeometricMeanLatency):
(BenchmarkSuite.FormatScore):
(BenchmarkSuite.prototype.NotifyStep):
(BenchmarkSuite.prototype.NotifyResult):
(BenchmarkSuite.prototype.NotifyError):
(BenchmarkSuite.prototype.RunSingleBenchmark):
(RunNextSetup):
(RunNextBenchmark):
(RunNextTearDown):
(BenchmarkSuite.prototype.RunStep):
(GeneratePayloadTree):
(GenerateKey):
(SplayUpdateStats):
(InsertNewNode):
(SplaySetup):
(SplayTearDown):
(SplayRun):
(SplayTree):
(SplayTree.prototype.isEmpty):
(SplayTree.prototype.insert):
(SplayTree.prototype.remove):
(SplayTree.prototype.find):
(SplayTree.prototype.findMax):
(SplayTree.prototype.findGreatestLessThan):
(SplayTree.prototype.exportKeys):
(SplayTree.prototype.splay_):
(SplayTree.Node):
(SplayTree.Node.prototype.traverse_):
(jscSetUp):
(jscTearDown):
(jscRun):
(averageAbovePercentile):
(printPercentile):

Source/JavaScriptCore:

        
This turns the collector thread's workflow into a state machine, so that the mutator thread can
run it directly. This reduces the amount of synchronization we do with the collector thread, and
means that most apps will never start the collector thread. The collector thread will still start
when we need to finish collecting and we don't have heap access.
        
In this new world, &quot;stopping the world&quot; means relinquishing control of collection to the mutator.
This means tracking who is conducting collection. I use the GCConductor enum to say who is
conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term &quot;conn&quot; to
refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
collector the conn.
        
This meant bringing back the conservative scan of the calling thread. It turns out that this
scan was too slow to be called on each GC increment because apparently setjmp() now does system
calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
whether or not it was correct, so I also made it so that the GC only rarely asks for the register
state. I think we still want to use my register saving code instead of setjmp because setjmp
seems to save things we don't need, and that could make us overly conservative.
        
It turns out that this new scheduling discipline makes the old space-time scheduler perform
better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
because the mutator having the conn enables us to time the mutator&lt;-&gt;collector context switches
by polling. The OS is never involved. So, we can use super precise timing. This allows the old
space-time schduler to shine like it hadn't before.
        
The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
effect.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::visitChildren):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::ThreadBody::ThreadBody):
(JSC::DFG::Worklist::dump):
(JSC::DFG::numberOfWorklists):
(JSC::DFG::ensureWorklistForIndex):
(JSC::DFG::existingWorklistForIndexOrNull):
(JSC::DFG::existingWorklistForIndex):
* dfg/DFGWorklist.h:
(JSC::DFG::numberOfWorklists): Deleted.
(JSC::DFG::ensureWorklistForIndex): Deleted.
(JSC::DFG::existingWorklistForIndexOrNull): Deleted.
(JSC::DFG::existingWorklistForIndex): Deleted.
* heap/CollectingScope.h: Added.
(JSC::CollectingScope::CollectingScope):
(JSC::CollectingScope::~CollectingScope):
* heap/CollectorPhase.cpp: Added.
(JSC::worldShouldBeSuspended):
(WTF::printInternal):
* heap/CollectorPhase.h: Added.
* heap/EdenGCActivityCallback.cpp:
(JSC::EdenGCActivityCallback::lastGCLength):
* heap/FullGCActivityCallback.cpp:
(JSC::FullGCActivityCallback::doCollection):
(JSC::FullGCActivityCallback::lastGCLength):
* heap/GCConductor.cpp: Added.
(JSC::gcConductorShortName):
(WTF::printInternal):
* heap/GCConductor.h: Added.
* heap/GCFinalizationCallback.cpp: Added.
(JSC::GCFinalizationCallback::GCFinalizationCallback):
(JSC::GCFinalizationCallback::~GCFinalizationCallback):
* heap/GCFinalizationCallback.h: Added.
(JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
(JSC::createGCFinalizationCallback):
* heap/Heap.cpp:
(JSC::Heap::Thread::Thread):
(JSC::Heap::Heap):
(JSC::Heap::lastChanceToFinalize):
(JSC::Heap::gatherStackRoots):
(JSC::Heap::updateObjectCounts):
(JSC::Heap::sweepSynchronously):
(JSC::Heap::collectAllGarbage):
(JSC::Heap::collectAsync):
(JSC::Heap::collectSync):
(JSC::Heap::shouldCollectInCollectorThread):
(JSC::Heap::collectInCollectorThread):
(JSC::Heap::checkConn):
(JSC::Heap::runNotRunningPhase):
(JSC::Heap::runBeginPhase):
(JSC::Heap::runFixpointPhase):
(JSC::Heap::runConcurrentPhase):
(JSC::Heap::runReloopPhase):
(JSC::Heap::runEndPhase):
(JSC::Heap::changePhase):
(JSC::Heap::finishChangingPhase):
(JSC::Heap::stopThePeriphery):
(JSC::Heap::resumeThePeriphery):
(JSC::Heap::stopTheMutator):
(JSC::Heap::resumeTheMutator):
(JSC::Heap::stopIfNecessarySlow):
(JSC::Heap::collectInMutatorThread):
(JSC::Heap::waitForCollector):
(JSC::Heap::acquireAccessSlow):
(JSC::Heap::releaseAccessSlow):
(JSC::Heap::relinquishConn):
(JSC::Heap::finishRelinquishingConn):
(JSC::Heap::handleNeedFinalize):
(JSC::Heap::notifyThreadStopping):
(JSC::Heap::finalize):
(JSC::Heap::addFinalizationCallback):
(JSC::Heap::requestCollection):
(JSC::Heap::waitForCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::collectIfNecessaryOrDefer):
(JSC::Heap::notifyIsSafeToCollect):
(JSC::Heap::preventCollection):
(JSC::Heap::performIncrement):
(JSC::Heap::markToFixpoint): Deleted.
(JSC::Heap::shouldCollectInThread): Deleted.
(JSC::Heap::collectInThread): Deleted.
(JSC::Heap::stopTheWorld): Deleted.
(JSC::Heap::resumeTheWorld): Deleted.
* heap/Heap.h:
(JSC::Heap::machineThreads):
(JSC::Heap::lastFullGCLength):
(JSC::Heap::lastEdenGCLength):
(JSC::Heap::increaseLastFullGCLength):
* heap/HeapInlines.h:
(JSC::Heap::mutatorIsStopped): Deleted.
* heap/HeapStatistics.cpp: Removed.
* heap/HeapStatistics.h: Removed.
* heap/HelpingGCScope.h: Removed.
* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::stopSweeping):
(JSC::IncrementalSweeper::willFinishSweeping): Deleted.
* heap/IncrementalSweeper.h:
* heap/MachineStackMarker.cpp:
(JSC::MachineThreads::gatherFromCurrentThread):
(JSC::MachineThreads::gatherConservativeRoots):
(JSC::callWithCurrentThreadState):
* heap/MachineStackMarker.h:
* heap/MarkedAllocator.cpp:
(JSC::MarkedAllocator::allocateSlowCaseImpl):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::Handle::sweep):
* heap/MarkedSpace.cpp:
(JSC::MarkedSpace::sweep):
* heap/MutatorState.cpp:
(WTF::printInternal):
* heap/MutatorState.h:
* heap/RegisterState.h: Added.
* heap/RunningScope.h: Added.
(JSC::RunningScope::RunningScope):
(JSC::RunningScope::~RunningScope):
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::SlotVisitor):
(JSC::SlotVisitor::drain):
(JSC::SlotVisitor::drainFromShared):
(JSC::SlotVisitor::drainInParallelPassively):
(JSC::SlotVisitor::donateAll):
(JSC::SlotVisitor::donate):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::codeName):
* heap/StochasticSpaceTimeMutatorScheduler.cpp:
(JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
(JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
(JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
* heap/SweepingScope.h: Added.
(JSC::SweepingScope::SweepingScope):
(JSC::SweepingScope::~SweepingScope):
* jit/JITWorklist.cpp:
(JSC::JITWorklist::Thread::Thread):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionFlashHeapAccess):
* runtime/InitializeThreading.cpp:
(JSC::initializeThreading):
* runtime/JSCellInlines.h:
(JSC::JSCell::classInfo):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/TestRunnerUtils.cpp:
(JSC::finalizeStatsAtEndOfTesting):

Source/WebCore:


Added new tests in JSTests.
        
The WebCore changes involve:
        
- Refactoring around new header discipline.
        
- Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.

* ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
* ForwardingHeaders/heap/IncrementalSweeper.h: Added.
* ForwardingHeaders/heap/MachineStackMarker.h: Added.
* ForwardingHeaders/heap/RunningScope.h: Added.
* bindings/js/CommonVM.cpp:
* testing/Internals.cpp:
(WebCore::Internals::parserMetaData):
(WebCore::Internals::isReadableStreamDisturbed):
(WebCore::Internals::isGCRunning):
(WebCore::Internals::addGCFinalizationCallback):
(WebCore::Internals::stopSweeping):
(WebCore::Internals::startSweeping):
* testing/Internals.h:
* testing/Internals.idl:

Source/WTF:

        
Extend the use of AbstractLocker so that we can use more locking idioms.

* wtf/AutomaticThread.cpp:
(WTF::AutomaticThreadCondition::notifyOne):
(WTF::AutomaticThreadCondition::notifyAll):
(WTF::AutomaticThreadCondition::add):
(WTF::AutomaticThreadCondition::remove):
(WTF::AutomaticThreadCondition::contains):
(WTF::AutomaticThread::AutomaticThread):
(WTF::AutomaticThread::tryStop):
(WTF::AutomaticThread::isWaiting):
(WTF::AutomaticThread::notify):
(WTF::AutomaticThread::start):
(WTF::AutomaticThread::threadIsStopping):
* wtf/AutomaticThread.h:
* wtf/NumberOfCores.cpp:
(WTF::numberOfProcessorCores):
* wtf/ParallelHelperPool.cpp:
(WTF::ParallelHelperClient::finish):
(WTF::ParallelHelperClient::claimTask):
(WTF::ParallelHelperPool::Thread::Thread):
(WTF::ParallelHelperPool::didMakeWorkAvailable):
(WTF::ParallelHelperPool::hasClientWithTask):
(WTF::ParallelHelperPool::getClientWithTask):
* wtf/ParallelHelperPool.h:

Tools:

        
Make more tests collect continuously.

* Scripts/run-jsc-stress-tests:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit216JSTestsChangeLog">releases/WebKitGTK/webkit-2.16/JSTests/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreCMakeListstxt">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreChangeLog">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCorebytecodeCodeBlockcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoredfgDFGWorklistcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoredfgDFGWorklisth">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapEdenGCActivityCallbackcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapFullGCActivityCallbackcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/FullGCActivityCallback.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeaph">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapInlinesh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapInlines.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapIncrementalSweepercpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapIncrementalSweeperh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMachineStackMarkercpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMachineStackMarkerh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMarkedAllocatorcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedAllocator.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMarkedBlockcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedBlock.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMarkedSpacecpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedSpace.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMutatorStatecpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMutatorStateh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapSlotVisitorcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapSlotVisitorh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapStochasticSpaceTimeMutatorSchedulercpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/StochasticSpaceTimeMutatorScheduler.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCorejitJITWorklistcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jit/JITWorklist.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCorejsccpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jsc.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeInitializeThreadingcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/InitializeThreading.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeJSCellInlinesh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/JSCellInlines.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeOptionscpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeOptionsh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeTestRunnerUtilscpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWTFChangeLog">releases/WebKitGTK/webkit-2.16/Source/WTF/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWTFwtfAutomaticThreadcpp">releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWTFwtfAutomaticThreadh">releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWTFwtfNumberOfCorescpp">releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/NumberOfCores.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWTFwtfParallelHelperPoolcpp">releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWTFwtfParallelHelperPoolh">releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWebCoreChangeLog">releases/WebKitGTK/webkit-2.16/Source/WebCore/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWebCorebindingsjsCommonVMcpp">releases/WebKitGTK/webkit-2.16/Source/WebCore/bindings/js/CommonVM.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216ToolsChangeLog">releases/WebKitGTK/webkit-2.16/Tools/ChangeLog</a></li>
<li><a href="#releasesWebKitGTKwebkit216ToolsScriptsrunjscstresstests">releases/WebKitGTK/webkit-2.16/Tools/Scripts/run-jsc-stress-tests</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit216JSTestsstresssplayflashaccess1msjs">releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access-1ms.js</a></li>
<li><a href="#releasesWebKitGTKwebkit216JSTestsstresssplayflashaccessjs">releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access.js</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapCollectingScopeh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectingScope.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapCollectorPhasecpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapCollectorPhaseh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapGCConductorcpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapGCConductorh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapRegisterStateh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RegisterState.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapRunningScopeh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RunningScope.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapSweepingScopeh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SweepingScope.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapGCFinalizationCallbackh">releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/GCFinalizationCallback.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapIncrementalSweeperh">releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/IncrementalSweeper.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapMachineStackMarkerh">releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/MachineStackMarker.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapRunningScopeh">releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/RunningScope.h</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapStatisticscpp">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.cpp</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapStatisticsh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.h</a></li>
<li><a href="#releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHelpingGCScopeh">releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HelpingGCScope.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="releasesWebKitGTKwebkit216JSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/JSTests/ChangeLog (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/JSTests/ChangeLog        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/JSTests/ChangeLog        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,3 +1,114 @@
</span><ins>+2017-02-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        The collector thread should only start when the mutator doesn't have heap access
+        https://bugs.webkit.org/show_bug.cgi?id=167737
+
+        Reviewed by Keith Miller.
+        
+        Add versions of splay that flash heap access, to simulate what might happen if a third-party app
+        was running concurrent GC. In this case, we might actually start the collector thread.
+
+        * stress/splay-flash-access-1ms.js: Added.
+        (performance.now):
+        (this.Setup.setup.setup):
+        (this.TearDown.tearDown.tearDown):
+        (Benchmark):
+        (BenchmarkResult):
+        (BenchmarkResult.prototype.valueOf):
+        (BenchmarkSuite):
+        (alert):
+        (Math.random):
+        (BenchmarkSuite.ResetRNG):
+        (RunStep):
+        (BenchmarkSuite.RunSuites):
+        (BenchmarkSuite.CountBenchmarks):
+        (BenchmarkSuite.GeometricMean):
+        (BenchmarkSuite.GeometricMeanTime):
+        (BenchmarkSuite.AverageAbovePercentile):
+        (BenchmarkSuite.GeometricMeanLatency):
+        (BenchmarkSuite.FormatScore):
+        (BenchmarkSuite.prototype.NotifyStep):
+        (BenchmarkSuite.prototype.NotifyResult):
+        (BenchmarkSuite.prototype.NotifyError):
+        (BenchmarkSuite.prototype.RunSingleBenchmark):
+        (RunNextSetup):
+        (RunNextBenchmark):
+        (RunNextTearDown):
+        (BenchmarkSuite.prototype.RunStep):
+        (GeneratePayloadTree):
+        (GenerateKey):
+        (SplayUpdateStats):
+        (InsertNewNode):
+        (SplaySetup):
+        (SplayTearDown):
+        (SplayRun):
+        (SplayTree):
+        (SplayTree.prototype.isEmpty):
+        (SplayTree.prototype.insert):
+        (SplayTree.prototype.remove):
+        (SplayTree.prototype.find):
+        (SplayTree.prototype.findMax):
+        (SplayTree.prototype.findGreatestLessThan):
+        (SplayTree.prototype.exportKeys):
+        (SplayTree.prototype.splay_):
+        (SplayTree.Node):
+        (SplayTree.Node.prototype.traverse_):
+        (jscSetUp):
+        (jscTearDown):
+        (jscRun):
+        (averageAbovePercentile):
+        (printPercentile):
+        * stress/splay-flash-access.js: Added.
+        (performance.now):
+        (this.Setup.setup.setup):
+        (this.TearDown.tearDown.tearDown):
+        (Benchmark):
+        (BenchmarkResult):
+        (BenchmarkResult.prototype.valueOf):
+        (BenchmarkSuite):
+        (alert):
+        (Math.random):
+        (BenchmarkSuite.ResetRNG):
+        (RunStep):
+        (BenchmarkSuite.RunSuites):
+        (BenchmarkSuite.CountBenchmarks):
+        (BenchmarkSuite.GeometricMean):
+        (BenchmarkSuite.GeometricMeanTime):
+        (BenchmarkSuite.AverageAbovePercentile):
+        (BenchmarkSuite.GeometricMeanLatency):
+        (BenchmarkSuite.FormatScore):
+        (BenchmarkSuite.prototype.NotifyStep):
+        (BenchmarkSuite.prototype.NotifyResult):
+        (BenchmarkSuite.prototype.NotifyError):
+        (BenchmarkSuite.prototype.RunSingleBenchmark):
+        (RunNextSetup):
+        (RunNextBenchmark):
+        (RunNextTearDown):
+        (BenchmarkSuite.prototype.RunStep):
+        (GeneratePayloadTree):
+        (GenerateKey):
+        (SplayUpdateStats):
+        (InsertNewNode):
+        (SplaySetup):
+        (SplayTearDown):
+        (SplayRun):
+        (SplayTree):
+        (SplayTree.prototype.isEmpty):
+        (SplayTree.prototype.insert):
+        (SplayTree.prototype.remove):
+        (SplayTree.prototype.find):
+        (SplayTree.prototype.findMax):
+        (SplayTree.prototype.findGreatestLessThan):
+        (SplayTree.prototype.exportKeys):
+        (SplayTree.prototype.splay_):
+        (SplayTree.Node):
+        (SplayTree.Node.prototype.traverse_):
+        (jscSetUp):
+        (jscTearDown):
+        (jscRun):
+        (averageAbovePercentile):
+        (printPercentile):
+
</ins><span class="cx"> 2017-02-21  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: &quot;!scope.exception()&quot; with Object.isSealed/isFrozen and uninitialized module bindings
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216JSTestsstresssplayflashaccess1msjs"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access-1ms.js (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access-1ms.js                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access-1ms.js        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,902 @@
</span><ins>+//@ runNoisyTestDefault
+//@ runNoisyTestNoCJIT
+
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright (C) 2015 Apple Inc. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER 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.
+
+
+// Performance.now is used in latency benchmarks, the fallback is Date.now.
+var performance = performance || {};
+performance.now = (function() {
+  return performance.now       ||
+         performance.mozNow    ||
+         performance.msNow     ||
+         performance.oNow      ||
+         performance.webkitNow ||
+         Date.now;
+})();
+
+// Simple framework for running the benchmark suites and
+// computing a score based on the timing measurements.
+
+
+// A benchmark has a name (string) and a function that will be run to
+// do the performance measurement. The optional setup and tearDown
+// arguments are functions that will be invoked before and after
+// running the benchmark, but the running time of these functions will
+// not be accounted for in the benchmark score.
+function Benchmark(name, doWarmup, doDeterministic, run, setup, tearDown, latencyResult, minIterations) {
+  this.name = name;
+  this.doWarmup = doWarmup;
+  this.doDeterministic = doDeterministic;
+  this.run = run;
+  this.Setup = setup ? setup : function() { };
+  this.TearDown = tearDown ? tearDown : function() { };
+  this.latencyResult = latencyResult ? latencyResult : null; 
+  this.minIterations = minIterations ? minIterations : 32;
+}
+
+
+// Benchmark results hold the benchmark and the measured time used to
+// run the benchmark. The benchmark score is computed later once a
+// full benchmark suite has run to completion. If latency is set to 0
+// then there is no latency score for this benchmark.
+function BenchmarkResult(benchmark, time, latency) {
+  this.benchmark = benchmark;
+  this.time = time;
+  this.latency = latency;
+}
+
+
+// Automatically convert results to numbers. Used by the geometric
+// mean computation.
+BenchmarkResult.prototype.valueOf = function() {
+  return this.time;
+}
+
+
+// Suites of benchmarks consist of a name and the set of benchmarks in
+// addition to the reference timing that the final score will be based
+// on. This way, all scores are relative to a reference run and higher
+// scores implies better performance.
+function BenchmarkSuite(name, reference, benchmarks) {
+  this.name = name;
+  this.reference = reference;
+  this.benchmarks = benchmarks;
+  BenchmarkSuite.suites.push(this);
+}
+
+
+// Keep track of all declared benchmark suites.
+BenchmarkSuite.suites = [];
+
+// Scores are not comparable across versions. Bump the version if
+// you're making changes that will affect that scores, e.g. if you add
+// a new benchmark or change an existing one.
+BenchmarkSuite.version = '9';
+
+// Override the alert function to throw an exception instead.
+alert = function(s) {
+  throw &quot;Alert called with argument: &quot; + s;
+};
+
+
+// To make the benchmark results predictable, we replace Math.random
+// with a 100% deterministic alternative.
+BenchmarkSuite.ResetRNG = function() {
+  Math.random = (function() {
+    var seed = 49734321;
+    return function() {
+      // Robert Jenkins' 32 bit integer hash function.
+      seed = ((seed + 0x7ed55d16) + (seed &lt;&lt; 12))  &amp; 0xffffffff;
+      seed = ((seed ^ 0xc761c23c) ^ (seed &gt;&gt;&gt; 19)) &amp; 0xffffffff;
+      seed = ((seed + 0x165667b1) + (seed &lt;&lt; 5))   &amp; 0xffffffff;
+      seed = ((seed + 0xd3a2646c) ^ (seed &lt;&lt; 9))   &amp; 0xffffffff;
+      seed = ((seed + 0xfd7046c5) + (seed &lt;&lt; 3))   &amp; 0xffffffff;
+      seed = ((seed ^ 0xb55a4f09) ^ (seed &gt;&gt;&gt; 16)) &amp; 0xffffffff;
+      return (seed &amp; 0xfffffff) / 0x10000000;
+    };
+  })();
+}
+
+
+// Runs all registered benchmark suites and optionally yields between
+// each individual benchmark to avoid running for too long in the
+// context of browsers. Once done, the final score is reported to the
+// runner.
+BenchmarkSuite.RunSuites = function(runner) {
+  var continuation = null;
+  var suites = BenchmarkSuite.suites;
+  var length = suites.length;
+  BenchmarkSuite.scores = [];
+  var index = 0;
+  function RunStep() {
+    while (continuation || index &lt; length) {
+      if (continuation) {
+        continuation = continuation();
+      } else {
+        var suite = suites[index++];
+        if (runner.NotifyStart) runner.NotifyStart(suite.name);
+        continuation = suite.RunStep(runner);
+      }
+      if (continuation &amp;&amp; typeof window != 'undefined' &amp;&amp; window.setTimeout) {
+        window.setTimeout(RunStep, 25);
+        return;
+      }
+    }
+
+    // show final result
+    if (runner.NotifyScore) {
+      var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);
+      var formatted = BenchmarkSuite.FormatScore(100 * score);
+      runner.NotifyScore(formatted);
+    }
+  }
+  RunStep();
+}
+
+
+// Counts the total number of registered benchmarks. Useful for
+// showing progress as a percentage.
+BenchmarkSuite.CountBenchmarks = function() {
+  var result = 0;
+  var suites = BenchmarkSuite.suites;
+  for (var i = 0; i &lt; suites.length; i++) {
+    result += suites[i].benchmarks.length;
+  }
+  return result;
+}
+
+
+// Computes the geometric mean of a set of numbers.
+BenchmarkSuite.GeometricMean = function(numbers) {
+  var log = 0;
+  for (var i = 0; i &lt; numbers.length; i++) {
+    log += Math.log(numbers[i]);
+  }
+  return Math.pow(Math.E, log / numbers.length);
+}
+
+
+// Computes the geometric mean of a set of throughput time measurements.
+BenchmarkSuite.GeometricMeanTime = function(measurements) {
+  var log = 0;
+  for (var i = 0; i &lt; measurements.length; i++) {
+    log += Math.log(measurements[i].time);
+  }
+  return Math.pow(Math.E, log / measurements.length);
+}
+
+
+// Computes the average of the worst samples. For example, if percentile is 99, this will report the
+// average of the worst 1% of the samples.
+BenchmarkSuite.AverageAbovePercentile = function(numbers, percentile) {
+  // Don't change the original array.
+  numbers = numbers.slice();
+  
+  // Sort in ascending order.
+  numbers.sort(function(a, b) { return a - b; });
+  
+  // Now the elements we want are at the end. Keep removing them until the array size shrinks too much.
+  // Examples assuming percentile = 99:
+  //
+  // - numbers.length starts at 100: we will remove just the worst entry and then not remove anymore,
+  //   since then numbers.length / originalLength = 0.99.
+  //
+  // - numbers.length starts at 1000: we will remove the ten worst.
+  //
+  // - numbers.length starts at 10: we will remove just the worst.
+  var numbersWeWant = [];
+  var originalLength = numbers.length;
+  while (numbers.length / originalLength &gt; percentile / 100)
+    numbersWeWant.push(numbers.pop());
+  
+  var sum = 0;
+  for (var i = 0; i &lt; numbersWeWant.length; ++i)
+    sum += numbersWeWant[i];
+  
+  var result = sum / numbersWeWant.length;
+  
+  // Do a sanity check.
+  if (numbers.length &amp;&amp; result &lt; numbers[numbers.length - 1]) {
+    throw &quot;Sanity check fail: the worst case result is &quot; + result +
+      &quot; but we didn't take into account &quot; + numbers;
+  }
+  
+  return result;
+}
+
+
+// Computes the geometric mean of a set of latency measurements.
+BenchmarkSuite.GeometricMeanLatency = function(measurements) {
+  var log = 0;
+  var hasLatencyResult = false;
+  for (var i = 0; i &lt; measurements.length; i++) {
+    if (measurements[i].latency != 0) {
+      log += Math.log(measurements[i].latency);
+      hasLatencyResult = true;
+    }
+  }
+  if (hasLatencyResult) {
+    return Math.pow(Math.E, log / measurements.length);
+  } else {
+    return 0;
+  }
+}
+
+
+// Converts a score value to a string with at least three significant
+// digits.
+BenchmarkSuite.FormatScore = function(value) {
+  if (value &gt; 100) {
+    return value.toFixed(0);
+  } else {
+    return value.toPrecision(3);
+  }
+}
+
+// Notifies the runner that we're done running a single benchmark in
+// the benchmark suite. This can be useful to report progress.
+BenchmarkSuite.prototype.NotifyStep = function(result) {
+  this.results.push(result);
+  if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);
+}
+
+
+// Notifies the runner that we're done with running a suite and that
+// we have a result which can be reported to the user if needed.
+BenchmarkSuite.prototype.NotifyResult = function() {
+  var mean = BenchmarkSuite.GeometricMeanTime(this.results);
+  var score = this.reference[0] / mean;
+  BenchmarkSuite.scores.push(score);
+  if (this.runner.NotifyResult) {
+    var formatted = BenchmarkSuite.FormatScore(100 * score);
+    this.runner.NotifyResult(this.name, formatted);
+  }
+  if (this.reference.length == 2) {
+    var meanLatency = BenchmarkSuite.GeometricMeanLatency(this.results);
+    if (meanLatency != 0) {
+      var scoreLatency = this.reference[1] / meanLatency;
+      BenchmarkSuite.scores.push(scoreLatency);
+      if (this.runner.NotifyResult) {
+        var formattedLatency = BenchmarkSuite.FormatScore(100 * scoreLatency)
+        this.runner.NotifyResult(this.name + &quot;Latency&quot;, formattedLatency);
+      }
+    }
+  }
+}
+
+
+// Notifies the runner that running a benchmark resulted in an error.
+BenchmarkSuite.prototype.NotifyError = function(error) {
+  if (this.runner.NotifyError) {
+    this.runner.NotifyError(this.name, error);
+  }
+  if (this.runner.NotifyStep) {
+    this.runner.NotifyStep(this.name);
+  }
+}
+
+
+// Runs a single benchmark for at least a second and computes the
+// average time it takes to run a single iteration.
+BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark, data) {
+  function Measure(data) {
+    var elapsed = 0;
+    var start = new Date();
+  
+  // Run either for 1 second or for the number of iterations specified
+  // by minIterations, depending on the config flag doDeterministic.
+    for (var i = 0; (benchmark.doDeterministic ? 
+      i&lt;benchmark.minIterations : elapsed &lt; 1000); i++) {
+      benchmark.run();
+      elapsed = new Date() - start;
+    }
+    if (data != null) {
+      data.runs += i;
+      data.elapsed += elapsed;
+    }
+  }
+
+  // Sets up data in order to skip or not the warmup phase.
+  if (!benchmark.doWarmup &amp;&amp; data == null) {
+    data = { runs: 0, elapsed: 0 };
+  }
+
+  if (data == null) {
+    Measure(null);
+    return { runs: 0, elapsed: 0 };
+  } else {
+    Measure(data);
+    // If we've run too few iterations, we continue for another second.
+    if (data.runs &lt; benchmark.minIterations) return data;
+    var usec = (data.elapsed * 1000) / data.runs;
+    var latencySamples = (benchmark.latencyResult != null) ? benchmark.latencyResult() : [0];
+    var percentile = 99.5;
+    var latency = BenchmarkSuite.AverageAbovePercentile(latencySamples, percentile) * 1000;
+    this.NotifyStep(new BenchmarkResult(benchmark, usec, latency));
+    return null;
+  }
+}
+
+
+// This function starts running a suite, but stops between each
+// individual benchmark in the suite and returns a continuation
+// function which can be invoked to run the next benchmark. Once the
+// last benchmark has been executed, null is returned.
+BenchmarkSuite.prototype.RunStep = function(runner) {
+  BenchmarkSuite.ResetRNG();
+  this.results = [];
+  this.runner = runner;
+  var length = this.benchmarks.length;
+  var index = 0;
+  var suite = this;
+  var data;
+
+  // Run the setup, the actual benchmark, and the tear down in three
+  // separate steps to allow the framework to yield between any of the
+  // steps.
+
+  function RunNextSetup() {
+    if (index &lt; length) {
+      try {
+        suite.benchmarks[index].Setup();
+      } catch (e) {
+        suite.NotifyError(e);
+        return null;
+      }
+      return RunNextBenchmark;
+    }
+    suite.NotifyResult();
+    return null;
+  }
+
+  function RunNextBenchmark() {
+    try {
+      data = suite.RunSingleBenchmark(suite.benchmarks[index], data);
+    } catch (e) {
+      suite.NotifyError(e);
+      return null;
+    }
+    // If data is null, we're done with this benchmark.
+    return (data == null) ? RunNextTearDown : RunNextBenchmark();
+  }
+
+  function RunNextTearDown() {
+    try {
+      suite.benchmarks[index++].TearDown();
+    } catch (e) {
+      suite.NotifyError(e);
+      return null;
+    }
+    return RunNextSetup;
+  }
+
+  // Start out running the setup.
+  return RunNextSetup();
+}
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright (C) 2015 Apple Inc. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER 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.
+
+// This benchmark is based on a JavaScript log processing module used
+// by the V8 profiler to generate execution time profiles for runs of
+// JavaScript applications, and it effectively measures how fast the
+// JavaScript engine is at allocating nodes and reclaiming the memory
+// used for old nodes. Because of the way splay trees work, the engine
+// also has to deal with a lot of changes to the large tree object
+// graph.
+
+var Splay = new BenchmarkSuite('Splay', [81491, 2739514], [
+  new Benchmark(&quot;Splay&quot;, true, false, 
+    SplayRun, SplaySetup, SplayTearDown, SplayLatency)
+]);
+
+
+// Configuration.
+var kSplayTreeSize = 8000;
+var kSplayTreeModifications = 80;
+var kSplayTreePayloadDepth = 5;
+
+var splayTree = null;
+var splaySampleTimeStart = 0.0;
+
+function GeneratePayloadTree(depth, tag) {
+  if (depth == 0) {
+    return {
+      array  : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
+      string : 'String for key ' + tag + ' in leaf node'
+    };
+  } else {
+    return {
+      left:  GeneratePayloadTree(depth - 1, tag),
+      right: GeneratePayloadTree(depth - 1, tag)
+    };
+  }
+}
+
+
+function GenerateKey() {
+  // The benchmark framework guarantees that Math.random is
+  // deterministic; see base.js.
+  return Math.random();
+}
+
+var splaySamples = [];
+
+function SplayLatency() {
+  return splaySamples;
+}
+
+function SplayUpdateStats(time) {
+  var pause = time - splaySampleTimeStart;
+  splaySampleTimeStart = time;
+  splaySamples.push(pause);
+}
+
+function InsertNewNode() {
+  // Insert new node with a unique key.
+  var key;
+  do {
+    key = GenerateKey();
+  } while (splayTree.find(key) != null);
+  var payload = GeneratePayloadTree(kSplayTreePayloadDepth, String(key));
+  splayTree.insert(key, payload);
+  return key;
+}
+
+
+function SplaySetup() {
+  // Check if the platform has the performance.now high resolution timer.
+  // If not, throw exception and quit.
+  if (!performance.now) {
+    throw &quot;PerformanceNowUnsupported&quot;;
+  }
+
+  splayTree = new SplayTree();
+  splaySampleTimeStart = performance.now()
+  for (var i = 0; i &lt; kSplayTreeSize; i++) {
+    InsertNewNode();
+    if ((i+1) % 20 == 19) {
+      SplayUpdateStats(performance.now());
+    }
+  }
+}
+
+
+function SplayTearDown() {
+  // Allow the garbage collector to reclaim the memory
+  // used by the splay tree no matter how we exit the
+  // tear down function.
+  var keys = splayTree.exportKeys();
+  splayTree = null;
+
+  splaySamples = [];
+
+  // Verify that the splay tree has the right size.
+  var length = keys.length;
+  if (length != kSplayTreeSize) {
+    throw new Error(&quot;Splay tree has wrong size&quot;);
+  }
+
+  // Verify that the splay tree has sorted, unique keys.
+  for (var i = 0; i &lt; length - 1; i++) {
+    if (keys[i] &gt;= keys[i + 1]) {
+      throw new Error(&quot;Splay tree not sorted&quot;);
+    }
+  }
+}
+
+
+function SplayRun() {
+  // Replace a few nodes in the splay tree.
+  for (var i = 0; i &lt; kSplayTreeModifications; i++) {
+    var key = InsertNewNode();
+    var greatest = splayTree.findGreatestLessThan(key);
+    if (greatest == null) splayTree.remove(key);
+    else splayTree.remove(greatest.key);
+  }
+  SplayUpdateStats(performance.now());
+}
+
+
+/**
+ * Constructs a Splay tree.  A splay tree is a self-balancing binary
+ * search tree with the additional property that recently accessed
+ * elements are quick to access again. It performs basic operations
+ * such as insertion, look-up and removal in O(log(n)) amortized time.
+ *
+ * @constructor
+ */
+function SplayTree() {
+};
+
+
+/**
+ * Pointer to the root node of the tree.
+ *
+ * @type {SplayTree.Node}
+ * @private
+ */
+SplayTree.prototype.root_ = null;
+
+
+/**
+ * @return {boolean} Whether the tree is empty.
+ */
+SplayTree.prototype.isEmpty = function() {
+  return !this.root_;
+};
+
+
+/**
+ * Inserts a node into the tree with the specified key and value if
+ * the tree does not already contain a node with the specified key. If
+ * the value is inserted, it becomes the root of the tree.
+ *
+ * @param {number} key Key to insert into the tree.
+ * @param {*} value Value to insert into the tree.
+ */
+SplayTree.prototype.insert = function(key, value) {
+  if (this.isEmpty()) {
+    this.root_ = new SplayTree.Node(key, value);
+    return;
+  }
+  // Splay on the key to move the last node on the search path for
+  // the key to the root of the tree.
+  this.splay_(key);
+  if (this.root_.key == key) {
+    return;
+  }
+  var node = new SplayTree.Node(key, value);
+  if (key &gt; this.root_.key) {
+    node.left = this.root_;
+    node.right = this.root_.right;
+    this.root_.right = null;
+  } else {
+    node.right = this.root_;
+    node.left = this.root_.left;
+    this.root_.left = null;
+  }
+  this.root_ = node;
+};
+
+
+/**
+ * Removes a node with the specified key from the tree if the tree
+ * contains a node with this key. The removed node is returned. If the
+ * key is not found, an exception is thrown.
+ *
+ * @param {number} key Key to find and remove from the tree.
+ * @return {SplayTree.Node} The removed node.
+ */
+SplayTree.prototype.remove = function(key) {
+  if (this.isEmpty()) {
+    throw Error('Key not found: ' + key);
+  }
+  this.splay_(key);
+  if (this.root_.key != key) {
+    throw Error('Key not found: ' + key);
+  }
+  var removed = this.root_;
+  if (!this.root_.left) {
+    this.root_ = this.root_.right;
+  } else {
+    var right = this.root_.right;
+    this.root_ = this.root_.left;
+    // Splay to make sure that the new root has an empty right child.
+    this.splay_(key);
+    // Insert the original right child as the right child of the new
+    // root.
+    this.root_.right = right;
+  }
+  return removed;
+};
+
+
+/**
+ * Returns the node having the specified key or null if the tree doesn't contain
+ * a node with the specified key.
+ *
+ * @param {number} key Key to find in the tree.
+ * @return {SplayTree.Node} Node having the specified key.
+ */
+SplayTree.prototype.find = function(key) {
+  if (this.isEmpty()) {
+    return null;
+  }
+  this.splay_(key);
+  return this.root_.key == key ? this.root_ : null;
+};
+
+
+/**
+ * @return {SplayTree.Node} Node having the maximum key value.
+ */
+SplayTree.prototype.findMax = function(opt_startNode) {
+  if (this.isEmpty()) {
+    return null;
+  }
+  var current = opt_startNode || this.root_;
+  while (current.right) {
+    current = current.right;
+  }
+  return current;
+};
+
+
+/**
+ * @return {SplayTree.Node} Node having the maximum key value that
+ *     is less than the specified key value.
+ */
+SplayTree.prototype.findGreatestLessThan = function(key) {
+  if (this.isEmpty()) {
+    return null;
+  }
+  // Splay on the key to move the node with the given key or the last
+  // node on the search path to the top of the tree.
+  this.splay_(key);
+  // Now the result is either the root node or the greatest node in
+  // the left subtree.
+  if (this.root_.key &lt; key) {
+    return this.root_;
+  } else if (this.root_.left) {
+    return this.findMax(this.root_.left);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * @return {Array&lt;*&gt;} An array containing all the keys of tree's nodes.
+ */
+SplayTree.prototype.exportKeys = function() {
+  var result = [];
+  if (!this.isEmpty()) {
+    this.root_.traverse_(function(node) { result.push(node.key); });
+  }
+  return result;
+};
+
+
+/**
+ * Perform the splay operation for the given key. Moves the node with
+ * the given key to the top of the tree.  If no node has the given
+ * key, the last node on the search path is moved to the top of the
+ * tree. This is the simplified top-down splaying algorithm from:
+ * &quot;Self-adjusting Binary Search Trees&quot; by Sleator and Tarjan
+ *
+ * @param {number} key Key to splay the tree on.
+ * @private
+ */
+SplayTree.prototype.splay_ = function(key) {
+  if (this.isEmpty()) {
+    return;
+  }
+  // Create a dummy node.  The use of the dummy node is a bit
+  // counter-intuitive: The right child of the dummy node will hold
+  // the L tree of the algorithm.  The left child of the dummy node
+  // will hold the R tree of the algorithm.  Using a dummy node, left
+  // and right will always be nodes and we avoid special cases.
+  var dummy, left, right;
+  dummy = left = right = new SplayTree.Node(null, null);
+  var current = this.root_;
+  while (true) {
+    if (key &lt; current.key) {
+      if (!current.left) {
+        break;
+      }
+      if (key &lt; current.left.key) {
+        // Rotate right.
+        var tmp = current.left;
+        current.left = tmp.right;
+        tmp.right = current;
+        current = tmp;
+        if (!current.left) {
+          break;
+        }
+      }
+      // Link right.
+      right.left = current;
+      right = current;
+      current = current.left;
+    } else if (key &gt; current.key) {
+      if (!current.right) {
+        break;
+      }
+      if (key &gt; current.right.key) {
+        // Rotate left.
+        var tmp = current.right;
+        current.right = tmp.left;
+        tmp.left = current;
+        current = tmp;
+        if (!current.right) {
+          break;
+        }
+      }
+      // Link left.
+      left.right = current;
+      left = current;
+      current = current.right;
+    } else {
+      break;
+    }
+  }
+  // Assemble.
+  left.right = current.left;
+  right.left = current.right;
+  current.left = dummy.right;
+  current.right = dummy.left;
+  this.root_ = current;
+};
+
+
+/**
+ * Constructs a Splay tree node.
+ *
+ * @param {number} key Key.
+ * @param {*} value Value.
+ */
+SplayTree.Node = function(key, value) {
+  this.key = key;
+  this.value = value;
+};
+
+
+/**
+ * @type {SplayTree.Node}
+ */
+SplayTree.Node.prototype.left = null;
+
+
+/**
+ * @type {SplayTree.Node}
+ */
+SplayTree.Node.prototype.right = null;
+
+
+/**
+ * Performs an ordered traversal of the subtree starting at
+ * this SplayTree.Node.
+ *
+ * @param {function(SplayTree.Node)} f Visitor function.
+ * @private
+ */
+SplayTree.Node.prototype.traverse_ = function(f) {
+  var current = this;
+  while (current) {
+    var left = current.left;
+    if (left) left.traverse_(f);
+    f(current);
+    current = current.right;
+  }
+};
+function jscSetUp() {
+    SplaySetup();
+}
+
+function jscTearDown() {
+    SplayTearDown();
+}
+
+function jscRun() {
+    SplayRun();
+}
+
+jscSetUp();
+var __before = preciseTime();
+var times = [];
+for (var i = 0; i &lt; 2000; ++i) {
+    var _before = preciseTime();
+    jscRun();
+    var _after = preciseTime();
+    times.push(_after - _before);
+    flashHeapAccess(1);
+}
+var __after = preciseTime();
+jscTearDown();
+
+function averageAbovePercentile(numbers, percentile) {
+    // Don't change the original array.
+    numbers = numbers.slice();
+    
+    // Sort in ascending order.
+    numbers.sort(function(a, b) { return a - b; });
+    
+    // Now the elements we want are at the end. Keep removing them until the array size shrinks too much.
+    // Examples assuming percentile = 99:
+    //
+    // - numbers.length starts at 100: we will remove just the worst entry and then not remove anymore,
+    //   since then numbers.length / originalLength = 0.99.
+    //
+    // - numbers.length starts at 1000: we will remove the ten worst.
+    //
+    // - numbers.length starts at 10: we will remove just the worst.
+    var numbersWeWant = [];
+    var originalLength = numbers.length;
+    while (numbers.length / originalLength &gt; percentile / 100)
+        numbersWeWant.push(numbers.pop());
+    
+    var sum = 0;
+    for (var i = 0; i &lt; numbersWeWant.length; ++i)
+        sum += numbersWeWant[i];
+    
+    var result = sum / numbersWeWant.length;
+    
+    // Do a sanity check.
+    if (numbers.length &amp;&amp; result &lt; numbers[numbers.length - 1]) {
+        throw &quot;Sanity check fail: the worst case result is &quot; + result +
+            &quot; but we didn't take into account &quot; + numbers;
+    }
+    
+    return result;
+}
+
+print(&quot;That took &quot; + (__after - __before) * 1000 + &quot; ms.&quot;);
+
+function printPercentile(percentile)
+{
+    print(&quot;Above &quot; + percentile + &quot;%: &quot; + averageAbovePercentile(times, percentile) * 1000 + &quot; ms.&quot;);
+}
+
+printPercentile(99.9);
+printPercentile(99.5);
+printPercentile(99);
+printPercentile(97.5);
+printPercentile(95);
+printPercentile(90);
+printPercentile(75);
+printPercentile(50);
+printPercentile(0);
+
+gc();
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216JSTestsstresssplayflashaccessjs"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access.js (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access.js                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/JSTests/stress/splay-flash-access.js        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,903 @@
</span><ins>+//@ runNoisyTestDefault
+//@ runNoisyTestNoCJIT
+
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Copyright (C) 2015 Apple Inc. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER 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.
+
+
+// Performance.now is used in latency benchmarks, the fallback is Date.now.
+var performance = performance || {};
+performance.now = (function() {
+  return performance.now       ||
+         performance.mozNow    ||
+         performance.msNow     ||
+         performance.oNow      ||
+         performance.webkitNow ||
+         Date.now;
+})();
+
+// Simple framework for running the benchmark suites and
+// computing a score based on the timing measurements.
+
+
+// A benchmark has a name (string) and a function that will be run to
+// do the performance measurement. The optional setup and tearDown
+// arguments are functions that will be invoked before and after
+// running the benchmark, but the running time of these functions will
+// not be accounted for in the benchmark score.
+function Benchmark(name, doWarmup, doDeterministic, run, setup, tearDown, latencyResult, minIterations) {
+  this.name = name;
+  this.doWarmup = doWarmup;
+  this.doDeterministic = doDeterministic;
+  this.run = run;
+  this.Setup = setup ? setup : function() { };
+  this.TearDown = tearDown ? tearDown : function() { };
+  this.latencyResult = latencyResult ? latencyResult : null; 
+  this.minIterations = minIterations ? minIterations : 32;
+}
+
+
+// Benchmark results hold the benchmark and the measured time used to
+// run the benchmark. The benchmark score is computed later once a
+// full benchmark suite has run to completion. If latency is set to 0
+// then there is no latency score for this benchmark.
+function BenchmarkResult(benchmark, time, latency) {
+  this.benchmark = benchmark;
+  this.time = time;
+  this.latency = latency;
+}
+
+
+// Automatically convert results to numbers. Used by the geometric
+// mean computation.
+BenchmarkResult.prototype.valueOf = function() {
+  return this.time;
+}
+
+
+// Suites of benchmarks consist of a name and the set of benchmarks in
+// addition to the reference timing that the final score will be based
+// on. This way, all scores are relative to a reference run and higher
+// scores implies better performance.
+function BenchmarkSuite(name, reference, benchmarks) {
+  this.name = name;
+  this.reference = reference;
+  this.benchmarks = benchmarks;
+  BenchmarkSuite.suites.push(this);
+}
+
+
+// Keep track of all declared benchmark suites.
+BenchmarkSuite.suites = [];
+
+// Scores are not comparable across versions. Bump the version if
+// you're making changes that will affect that scores, e.g. if you add
+// a new benchmark or change an existing one.
+BenchmarkSuite.version = '9';
+
+// Override the alert function to throw an exception instead.
+alert = function(s) {
+  throw &quot;Alert called with argument: &quot; + s;
+};
+
+
+// To make the benchmark results predictable, we replace Math.random
+// with a 100% deterministic alternative.
+BenchmarkSuite.ResetRNG = function() {
+  Math.random = (function() {
+    var seed = 49734321;
+    return function() {
+      // Robert Jenkins' 32 bit integer hash function.
+      seed = ((seed + 0x7ed55d16) + (seed &lt;&lt; 12))  &amp; 0xffffffff;
+      seed = ((seed ^ 0xc761c23c) ^ (seed &gt;&gt;&gt; 19)) &amp; 0xffffffff;
+      seed = ((seed + 0x165667b1) + (seed &lt;&lt; 5))   &amp; 0xffffffff;
+      seed = ((seed + 0xd3a2646c) ^ (seed &lt;&lt; 9))   &amp; 0xffffffff;
+      seed = ((seed + 0xfd7046c5) + (seed &lt;&lt; 3))   &amp; 0xffffffff;
+      seed = ((seed ^ 0xb55a4f09) ^ (seed &gt;&gt;&gt; 16)) &amp; 0xffffffff;
+      return (seed &amp; 0xfffffff) / 0x10000000;
+    };
+  })();
+}
+
+
+// Runs all registered benchmark suites and optionally yields between
+// each individual benchmark to avoid running for too long in the
+// context of browsers. Once done, the final score is reported to the
+// runner.
+BenchmarkSuite.RunSuites = function(runner) {
+  var continuation = null;
+  var suites = BenchmarkSuite.suites;
+  var length = suites.length;
+  BenchmarkSuite.scores = [];
+  var index = 0;
+  function RunStep() {
+    while (continuation || index &lt; length) {
+      if (continuation) {
+        continuation = continuation();
+      } else {
+        var suite = suites[index++];
+        if (runner.NotifyStart) runner.NotifyStart(suite.name);
+        continuation = suite.RunStep(runner);
+      }
+      if (continuation &amp;&amp; typeof window != 'undefined' &amp;&amp; window.setTimeout) {
+        window.setTimeout(RunStep, 25);
+        return;
+      }
+    }
+
+    // show final result
+    if (runner.NotifyScore) {
+      var score = BenchmarkSuite.GeometricMean(BenchmarkSuite.scores);
+      var formatted = BenchmarkSuite.FormatScore(100 * score);
+      runner.NotifyScore(formatted);
+    }
+  }
+  RunStep();
+}
+
+
+// Counts the total number of registered benchmarks. Useful for
+// showing progress as a percentage.
+BenchmarkSuite.CountBenchmarks = function() {
+  var result = 0;
+  var suites = BenchmarkSuite.suites;
+  for (var i = 0; i &lt; suites.length; i++) {
+    result += suites[i].benchmarks.length;
+  }
+  return result;
+}
+
+
+// Computes the geometric mean of a set of numbers.
+BenchmarkSuite.GeometricMean = function(numbers) {
+  var log = 0;
+  for (var i = 0; i &lt; numbers.length; i++) {
+    log += Math.log(numbers[i]);
+  }
+  return Math.pow(Math.E, log / numbers.length);
+}
+
+
+// Computes the geometric mean of a set of throughput time measurements.
+BenchmarkSuite.GeometricMeanTime = function(measurements) {
+  var log = 0;
+  for (var i = 0; i &lt; measurements.length; i++) {
+    log += Math.log(measurements[i].time);
+  }
+  return Math.pow(Math.E, log / measurements.length);
+}
+
+
+// Computes the average of the worst samples. For example, if percentile is 99, this will report the
+// average of the worst 1% of the samples.
+BenchmarkSuite.AverageAbovePercentile = function(numbers, percentile) {
+  // Don't change the original array.
+  numbers = numbers.slice();
+  
+  // Sort in ascending order.
+  numbers.sort(function(a, b) { return a - b; });
+  
+  // Now the elements we want are at the end. Keep removing them until the array size shrinks too much.
+  // Examples assuming percentile = 99:
+  //
+  // - numbers.length starts at 100: we will remove just the worst entry and then not remove anymore,
+  //   since then numbers.length / originalLength = 0.99.
+  //
+  // - numbers.length starts at 1000: we will remove the ten worst.
+  //
+  // - numbers.length starts at 10: we will remove just the worst.
+  var numbersWeWant = [];
+  var originalLength = numbers.length;
+  while (numbers.length / originalLength &gt; percentile / 100)
+    numbersWeWant.push(numbers.pop());
+  
+  var sum = 0;
+  for (var i = 0; i &lt; numbersWeWant.length; ++i)
+    sum += numbersWeWant[i];
+  
+  var result = sum / numbersWeWant.length;
+  
+  // Do a sanity check.
+  if (numbers.length &amp;&amp; result &lt; numbers[numbers.length - 1]) {
+    throw &quot;Sanity check fail: the worst case result is &quot; + result +
+      &quot; but we didn't take into account &quot; + numbers;
+  }
+  
+  return result;
+}
+
+
+// Computes the geometric mean of a set of latency measurements.
+BenchmarkSuite.GeometricMeanLatency = function(measurements) {
+  var log = 0;
+  var hasLatencyResult = false;
+  for (var i = 0; i &lt; measurements.length; i++) {
+    if (measurements[i].latency != 0) {
+      log += Math.log(measurements[i].latency);
+      hasLatencyResult = true;
+    }
+  }
+  if (hasLatencyResult) {
+    return Math.pow(Math.E, log / measurements.length);
+  } else {
+    return 0;
+  }
+}
+
+
+// Converts a score value to a string with at least three significant
+// digits.
+BenchmarkSuite.FormatScore = function(value) {
+  if (value &gt; 100) {
+    return value.toFixed(0);
+  } else {
+    return value.toPrecision(3);
+  }
+}
+
+// Notifies the runner that we're done running a single benchmark in
+// the benchmark suite. This can be useful to report progress.
+BenchmarkSuite.prototype.NotifyStep = function(result) {
+  this.results.push(result);
+  if (this.runner.NotifyStep) this.runner.NotifyStep(result.benchmark.name);
+}
+
+
+// Notifies the runner that we're done with running a suite and that
+// we have a result which can be reported to the user if needed.
+BenchmarkSuite.prototype.NotifyResult = function() {
+  var mean = BenchmarkSuite.GeometricMeanTime(this.results);
+  var score = this.reference[0] / mean;
+  BenchmarkSuite.scores.push(score);
+  if (this.runner.NotifyResult) {
+    var formatted = BenchmarkSuite.FormatScore(100 * score);
+    this.runner.NotifyResult(this.name, formatted);
+  }
+  if (this.reference.length == 2) {
+    var meanLatency = BenchmarkSuite.GeometricMeanLatency(this.results);
+    if (meanLatency != 0) {
+      var scoreLatency = this.reference[1] / meanLatency;
+      BenchmarkSuite.scores.push(scoreLatency);
+      if (this.runner.NotifyResult) {
+        var formattedLatency = BenchmarkSuite.FormatScore(100 * scoreLatency)
+        this.runner.NotifyResult(this.name + &quot;Latency&quot;, formattedLatency);
+      }
+    }
+  }
+}
+
+
+// Notifies the runner that running a benchmark resulted in an error.
+BenchmarkSuite.prototype.NotifyError = function(error) {
+  if (this.runner.NotifyError) {
+    this.runner.NotifyError(this.name, error);
+  }
+  if (this.runner.NotifyStep) {
+    this.runner.NotifyStep(this.name);
+  }
+}
+
+
+// Runs a single benchmark for at least a second and computes the
+// average time it takes to run a single iteration.
+BenchmarkSuite.prototype.RunSingleBenchmark = function(benchmark, data) {
+  function Measure(data) {
+    var elapsed = 0;
+    var start = new Date();
+  
+  // Run either for 1 second or for the number of iterations specified
+  // by minIterations, depending on the config flag doDeterministic.
+    for (var i = 0; (benchmark.doDeterministic ? 
+      i&lt;benchmark.minIterations : elapsed &lt; 1000); i++) {
+      benchmark.run();
+      elapsed = new Date() - start;
+    }
+    if (data != null) {
+      data.runs += i;
+      data.elapsed += elapsed;
+    }
+  }
+
+  // Sets up data in order to skip or not the warmup phase.
+  if (!benchmark.doWarmup &amp;&amp; data == null) {
+    data = { runs: 0, elapsed: 0 };
+  }
+
+  if (data == null) {
+    Measure(null);
+    return { runs: 0, elapsed: 0 };
+  } else {
+    Measure(data);
+    // If we've run too few iterations, we continue for another second.
+    if (data.runs &lt; benchmark.minIterations) return data;
+    var usec = (data.elapsed * 1000) / data.runs;
+    var latencySamples = (benchmark.latencyResult != null) ? benchmark.latencyResult() : [0];
+    var percentile = 99.5;
+    var latency = BenchmarkSuite.AverageAbovePercentile(latencySamples, percentile) * 1000;
+    this.NotifyStep(new BenchmarkResult(benchmark, usec, latency));
+    return null;
+  }
+}
+
+
+// This function starts running a suite, but stops between each
+// individual benchmark in the suite and returns a continuation
+// function which can be invoked to run the next benchmark. Once the
+// last benchmark has been executed, null is returned.
+BenchmarkSuite.prototype.RunStep = function(runner) {
+  BenchmarkSuite.ResetRNG();
+  this.results = [];
+  this.runner = runner;
+  var length = this.benchmarks.length;
+  var index = 0;
+  var suite = this;
+  var data;
+
+  // Run the setup, the actual benchmark, and the tear down in three
+  // separate steps to allow the framework to yield between any of the
+  // steps.
+
+  function RunNextSetup() {
+    if (index &lt; length) {
+      try {
+        suite.benchmarks[index].Setup();
+      } catch (e) {
+        suite.NotifyError(e);
+        return null;
+      }
+      return RunNextBenchmark;
+    }
+    suite.NotifyResult();
+    return null;
+  }
+
+  function RunNextBenchmark() {
+    try {
+      data = suite.RunSingleBenchmark(suite.benchmarks[index], data);
+    } catch (e) {
+      suite.NotifyError(e);
+      return null;
+    }
+    // If data is null, we're done with this benchmark.
+    return (data == null) ? RunNextTearDown : RunNextBenchmark();
+  }
+
+  function RunNextTearDown() {
+    try {
+      suite.benchmarks[index++].TearDown();
+    } catch (e) {
+      suite.NotifyError(e);
+      return null;
+    }
+    return RunNextSetup;
+  }
+
+  // Start out running the setup.
+  return RunNextSetup();
+}
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright (C) 2015 Apple Inc. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER 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.
+
+// This benchmark is based on a JavaScript log processing module used
+// by the V8 profiler to generate execution time profiles for runs of
+// JavaScript applications, and it effectively measures how fast the
+// JavaScript engine is at allocating nodes and reclaiming the memory
+// used for old nodes. Because of the way splay trees work, the engine
+// also has to deal with a lot of changes to the large tree object
+// graph.
+
+var Splay = new BenchmarkSuite('Splay', [81491, 2739514], [
+  new Benchmark(&quot;Splay&quot;, true, false, 
+    SplayRun, SplaySetup, SplayTearDown, SplayLatency)
+]);
+
+
+// Configuration.
+var kSplayTreeSize = 8000;
+var kSplayTreeModifications = 80;
+var kSplayTreePayloadDepth = 5;
+
+var splayTree = null;
+var splaySampleTimeStart = 0.0;
+
+function GeneratePayloadTree(depth, tag) {
+  if (depth == 0) {
+    return {
+      array  : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
+      string : 'String for key ' + tag + ' in leaf node'
+    };
+  } else {
+    return {
+      left:  GeneratePayloadTree(depth - 1, tag),
+      right: GeneratePayloadTree(depth - 1, tag)
+    };
+  }
+}
+
+
+function GenerateKey() {
+  // The benchmark framework guarantees that Math.random is
+  // deterministic; see base.js.
+  return Math.random();
+}
+
+var splaySamples = [];
+
+function SplayLatency() {
+  return splaySamples;
+}
+
+function SplayUpdateStats(time) {
+  var pause = time - splaySampleTimeStart;
+  splaySampleTimeStart = time;
+  splaySamples.push(pause);
+}
+
+function InsertNewNode() {
+  // Insert new node with a unique key.
+  var key;
+  do {
+    key = GenerateKey();
+  } while (splayTree.find(key) != null);
+  var payload = GeneratePayloadTree(kSplayTreePayloadDepth, String(key));
+  splayTree.insert(key, payload);
+  return key;
+}
+
+
+function SplaySetup() {
+  // Check if the platform has the performance.now high resolution timer.
+  // If not, throw exception and quit.
+  if (!performance.now) {
+    throw &quot;PerformanceNowUnsupported&quot;;
+  }
+
+  splayTree = new SplayTree();
+  splaySampleTimeStart = performance.now()
+  for (var i = 0; i &lt; kSplayTreeSize; i++) {
+    InsertNewNode();
+    if ((i+1) % 20 == 19) {
+      SplayUpdateStats(performance.now());
+    }
+  }
+}
+
+
+function SplayTearDown() {
+  // Allow the garbage collector to reclaim the memory
+  // used by the splay tree no matter how we exit the
+  // tear down function.
+  var keys = splayTree.exportKeys();
+  splayTree = null;
+
+  splaySamples = [];
+
+  // Verify that the splay tree has the right size.
+  var length = keys.length;
+  if (length != kSplayTreeSize) {
+    throw new Error(&quot;Splay tree has wrong size&quot;);
+  }
+
+  // Verify that the splay tree has sorted, unique keys.
+  for (var i = 0; i &lt; length - 1; i++) {
+    if (keys[i] &gt;= keys[i + 1]) {
+      throw new Error(&quot;Splay tree not sorted&quot;);
+    }
+  }
+}
+
+
+function SplayRun() {
+  // Replace a few nodes in the splay tree.
+  for (var i = 0; i &lt; kSplayTreeModifications; i++) {
+    var key = InsertNewNode();
+    var greatest = splayTree.findGreatestLessThan(key);
+    if (greatest == null) splayTree.remove(key);
+    else splayTree.remove(greatest.key);
+  }
+  SplayUpdateStats(performance.now());
+}
+
+
+/**
+ * Constructs a Splay tree.  A splay tree is a self-balancing binary
+ * search tree with the additional property that recently accessed
+ * elements are quick to access again. It performs basic operations
+ * such as insertion, look-up and removal in O(log(n)) amortized time.
+ *
+ * @constructor
+ */
+function SplayTree() {
+};
+
+
+/**
+ * Pointer to the root node of the tree.
+ *
+ * @type {SplayTree.Node}
+ * @private
+ */
+SplayTree.prototype.root_ = null;
+
+
+/**
+ * @return {boolean} Whether the tree is empty.
+ */
+SplayTree.prototype.isEmpty = function() {
+  return !this.root_;
+};
+
+
+/**
+ * Inserts a node into the tree with the specified key and value if
+ * the tree does not already contain a node with the specified key. If
+ * the value is inserted, it becomes the root of the tree.
+ *
+ * @param {number} key Key to insert into the tree.
+ * @param {*} value Value to insert into the tree.
+ */
+SplayTree.prototype.insert = function(key, value) {
+  if (this.isEmpty()) {
+    this.root_ = new SplayTree.Node(key, value);
+    return;
+  }
+  // Splay on the key to move the last node on the search path for
+  // the key to the root of the tree.
+  this.splay_(key);
+  if (this.root_.key == key) {
+    return;
+  }
+  var node = new SplayTree.Node(key, value);
+  if (key &gt; this.root_.key) {
+    node.left = this.root_;
+    node.right = this.root_.right;
+    this.root_.right = null;
+  } else {
+    node.right = this.root_;
+    node.left = this.root_.left;
+    this.root_.left = null;
+  }
+  this.root_ = node;
+};
+
+
+/**
+ * Removes a node with the specified key from the tree if the tree
+ * contains a node with this key. The removed node is returned. If the
+ * key is not found, an exception is thrown.
+ *
+ * @param {number} key Key to find and remove from the tree.
+ * @return {SplayTree.Node} The removed node.
+ */
+SplayTree.prototype.remove = function(key) {
+  if (this.isEmpty()) {
+    throw Error('Key not found: ' + key);
+  }
+  this.splay_(key);
+  if (this.root_.key != key) {
+    throw Error('Key not found: ' + key);
+  }
+  var removed = this.root_;
+  if (!this.root_.left) {
+    this.root_ = this.root_.right;
+  } else {
+    var right = this.root_.right;
+    this.root_ = this.root_.left;
+    // Splay to make sure that the new root has an empty right child.
+    this.splay_(key);
+    // Insert the original right child as the right child of the new
+    // root.
+    this.root_.right = right;
+  }
+  return removed;
+};
+
+
+/**
+ * Returns the node having the specified key or null if the tree doesn't contain
+ * a node with the specified key.
+ *
+ * @param {number} key Key to find in the tree.
+ * @return {SplayTree.Node} Node having the specified key.
+ */
+SplayTree.prototype.find = function(key) {
+  if (this.isEmpty()) {
+    return null;
+  }
+  this.splay_(key);
+  return this.root_.key == key ? this.root_ : null;
+};
+
+
+/**
+ * @return {SplayTree.Node} Node having the maximum key value.
+ */
+SplayTree.prototype.findMax = function(opt_startNode) {
+  if (this.isEmpty()) {
+    return null;
+  }
+  var current = opt_startNode || this.root_;
+  while (current.right) {
+    current = current.right;
+  }
+  return current;
+};
+
+
+/**
+ * @return {SplayTree.Node} Node having the maximum key value that
+ *     is less than the specified key value.
+ */
+SplayTree.prototype.findGreatestLessThan = function(key) {
+  if (this.isEmpty()) {
+    return null;
+  }
+  // Splay on the key to move the node with the given key or the last
+  // node on the search path to the top of the tree.
+  this.splay_(key);
+  // Now the result is either the root node or the greatest node in
+  // the left subtree.
+  if (this.root_.key &lt; key) {
+    return this.root_;
+  } else if (this.root_.left) {
+    return this.findMax(this.root_.left);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * @return {Array&lt;*&gt;} An array containing all the keys of tree's nodes.
+ */
+SplayTree.prototype.exportKeys = function() {
+  var result = [];
+  if (!this.isEmpty()) {
+    this.root_.traverse_(function(node) { result.push(node.key); });
+  }
+  return result;
+};
+
+
+/**
+ * Perform the splay operation for the given key. Moves the node with
+ * the given key to the top of the tree.  If no node has the given
+ * key, the last node on the search path is moved to the top of the
+ * tree. This is the simplified top-down splaying algorithm from:
+ * &quot;Self-adjusting Binary Search Trees&quot; by Sleator and Tarjan
+ *
+ * @param {number} key Key to splay the tree on.
+ * @private
+ */
+SplayTree.prototype.splay_ = function(key) {
+  if (this.isEmpty()) {
+    return;
+  }
+  // Create a dummy node.  The use of the dummy node is a bit
+  // counter-intuitive: The right child of the dummy node will hold
+  // the L tree of the algorithm.  The left child of the dummy node
+  // will hold the R tree of the algorithm.  Using a dummy node, left
+  // and right will always be nodes and we avoid special cases.
+  var dummy, left, right;
+  dummy = left = right = new SplayTree.Node(null, null);
+  var current = this.root_;
+  while (true) {
+    if (key &lt; current.key) {
+      if (!current.left) {
+        break;
+      }
+      if (key &lt; current.left.key) {
+        // Rotate right.
+        var tmp = current.left;
+        current.left = tmp.right;
+        tmp.right = current;
+        current = tmp;
+        if (!current.left) {
+          break;
+        }
+      }
+      // Link right.
+      right.left = current;
+      right = current;
+      current = current.left;
+    } else if (key &gt; current.key) {
+      if (!current.right) {
+        break;
+      }
+      if (key &gt; current.right.key) {
+        // Rotate left.
+        var tmp = current.right;
+        current.right = tmp.left;
+        tmp.left = current;
+        current = tmp;
+        if (!current.right) {
+          break;
+        }
+      }
+      // Link left.
+      left.right = current;
+      left = current;
+      current = current.right;
+    } else {
+      break;
+    }
+  }
+  // Assemble.
+  left.right = current.left;
+  right.left = current.right;
+  current.left = dummy.right;
+  current.right = dummy.left;
+  this.root_ = current;
+};
+
+
+/**
+ * Constructs a Splay tree node.
+ *
+ * @param {number} key Key.
+ * @param {*} value Value.
+ */
+SplayTree.Node = function(key, value) {
+  this.key = key;
+  this.value = value;
+};
+
+
+/**
+ * @type {SplayTree.Node}
+ */
+SplayTree.Node.prototype.left = null;
+
+
+/**
+ * @type {SplayTree.Node}
+ */
+SplayTree.Node.prototype.right = null;
+
+
+/**
+ * Performs an ordered traversal of the subtree starting at
+ * this SplayTree.Node.
+ *
+ * @param {function(SplayTree.Node)} f Visitor function.
+ * @private
+ */
+SplayTree.Node.prototype.traverse_ = function(f) {
+  var current = this;
+  while (current) {
+    var left = current.left;
+    if (left) left.traverse_(f);
+    f(current);
+    current = current.right;
+  }
+};
+function jscSetUp() {
+    SplaySetup();
+}
+
+function jscTearDown() {
+    SplayTearDown();
+}
+
+function jscRun() {
+    SplayRun();
+}
+
+jscSetUp();
+var __before = preciseTime();
+var times = [];
+for (var i = 0; i &lt; 10000; ++i) {
+//for (var i = 0; i &lt; 1000000; ++i) {
+    var _before = preciseTime();
+    jscRun();
+    var _after = preciseTime();
+    times.push(_after - _before);
+    flashHeapAccess();
+}
+var __after = preciseTime();
+jscTearDown();
+
+function averageAbovePercentile(numbers, percentile) {
+    // Don't change the original array.
+    numbers = numbers.slice();
+    
+    // Sort in ascending order.
+    numbers.sort(function(a, b) { return a - b; });
+    
+    // Now the elements we want are at the end. Keep removing them until the array size shrinks too much.
+    // Examples assuming percentile = 99:
+    //
+    // - numbers.length starts at 100: we will remove just the worst entry and then not remove anymore,
+    //   since then numbers.length / originalLength = 0.99.
+    //
+    // - numbers.length starts at 1000: we will remove the ten worst.
+    //
+    // - numbers.length starts at 10: we will remove just the worst.
+    var numbersWeWant = [];
+    var originalLength = numbers.length;
+    while (numbers.length / originalLength &gt; percentile / 100)
+        numbersWeWant.push(numbers.pop());
+    
+    var sum = 0;
+    for (var i = 0; i &lt; numbersWeWant.length; ++i)
+        sum += numbersWeWant[i];
+    
+    var result = sum / numbersWeWant.length;
+    
+    // Do a sanity check.
+    if (numbers.length &amp;&amp; result &lt; numbers[numbers.length - 1]) {
+        throw &quot;Sanity check fail: the worst case result is &quot; + result +
+            &quot; but we didn't take into account &quot; + numbers;
+    }
+    
+    return result;
+}
+
+print(&quot;That took &quot; + (__after - __before) * 1000 + &quot; ms.&quot;);
+
+function printPercentile(percentile)
+{
+    print(&quot;Above &quot; + percentile + &quot;%: &quot; + averageAbovePercentile(times, percentile) * 1000 + &quot; ms.&quot;);
+}
+
+printPercentile(99.9);
+printPercentile(99.5);
+printPercentile(99);
+printPercentile(97.5);
+printPercentile(95);
+printPercentile(90);
+printPercentile(75);
+printPercentile(50);
+printPercentile(0);
+
+gc();
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/CMakeLists.txt (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/CMakeLists.txt        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/CMakeLists.txt        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -474,6 +474,7 @@
</span><span class="cx">     heap/CellContainer.cpp
</span><span class="cx">     heap/CodeBlockSet.cpp
</span><span class="cx">     heap/CollectionScope.cpp
</span><ins>+    heap/CollectorPhase.cpp
</ins><span class="cx">     heap/ConservativeRoots.cpp
</span><span class="cx">     heap/DeferGC.cpp
</span><span class="cx">     heap/DestructionMode.cpp
</span><span class="lines">@@ -481,6 +482,7 @@
</span><span class="cx">     heap/FullGCActivityCallback.cpp
</span><span class="cx">     heap/FreeList.cpp
</span><span class="cx">     heap/GCActivityCallback.cpp
</span><ins>+    heap/GCConductor.cpp
</ins><span class="cx">     heap/GCLogging.cpp
</span><span class="cx">     heap/HandleSet.cpp
</span><span class="cx">     heap/HandleStack.cpp
</span><span class="lines">@@ -490,7 +492,6 @@
</span><span class="cx">     heap/HeapProfiler.cpp
</span><span class="cx">     heap/HeapSnapshot.cpp
</span><span class="cx">     heap/HeapSnapshotBuilder.cpp
</span><del>-    heap/HeapStatistics.cpp
</del><span class="cx">     heap/HeapTimer.cpp
</span><span class="cx">     heap/HeapVerifier.cpp
</span><span class="cx">     heap/IncrementalSweeper.cpp
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/ChangeLog (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/ChangeLog        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/ChangeLog        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,3 +1,190 @@
</span><ins>+2017-02-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        The collector thread should only start when the mutator doesn't have heap access
+        https://bugs.webkit.org/show_bug.cgi?id=167737
+
+        Reviewed by Keith Miller.
+        
+        This turns the collector thread's workflow into a state machine, so that the mutator thread can
+        run it directly. This reduces the amount of synchronization we do with the collector thread, and
+        means that most apps will never start the collector thread. The collector thread will still start
+        when we need to finish collecting and we don't have heap access.
+        
+        In this new world, &quot;stopping the world&quot; means relinquishing control of collection to the mutator.
+        This means tracking who is conducting collection. I use the GCConductor enum to say who is
+        conducting. It's either GCConductor::Mutator or GCConductor::Collector. I use the term &quot;conn&quot; to
+        refer to the concept of conducting (having the conn, relinquishing the conn, taking the conn).
+        So, stopping the world means giving the mutator the conn. Releasing heap access means giving the
+        collector the conn.
+        
+        This meant bringing back the conservative scan of the calling thread. It turns out that this
+        scan was too slow to be called on each GC increment because apparently setjmp() now does system
+        calls. So, I wrote our own callee save register saving for the GC. Then I had doubts about
+        whether or not it was correct, so I also made it so that the GC only rarely asks for the register
+        state. I think we still want to use my register saving code instead of setjmp because setjmp
+        seems to save things we don't need, and that could make us overly conservative.
+        
+        It turns out that this new scheduling discipline makes the old space-time scheduler perform
+        better than the new stochastic space-time scheduler on systems with fewer than 4 cores. This is
+        because the mutator having the conn enables us to time the mutator&lt;-&gt;collector context switches
+        by polling. The OS is never involved. So, we can use super precise timing. This allows the old
+        space-time schduler to shine like it hadn't before.
+        
+        The splay results imply that this is all a good thing. On 2-core systems, this reduces pause
+        times by 40% and it increases throughput about 5%. On 1-core systems, this reduces pause times by
+        half and reduces throughput by 8%. On 4-or-more-core systems, this doesn't seem to have much
+        effect.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::visitChildren):
+        * dfg/DFGWorklist.cpp:
+        (JSC::DFG::Worklist::ThreadBody::ThreadBody):
+        (JSC::DFG::Worklist::dump):
+        (JSC::DFG::numberOfWorklists):
+        (JSC::DFG::ensureWorklistForIndex):
+        (JSC::DFG::existingWorklistForIndexOrNull):
+        (JSC::DFG::existingWorklistForIndex):
+        * dfg/DFGWorklist.h:
+        (JSC::DFG::numberOfWorklists): Deleted.
+        (JSC::DFG::ensureWorklistForIndex): Deleted.
+        (JSC::DFG::existingWorklistForIndexOrNull): Deleted.
+        (JSC::DFG::existingWorklistForIndex): Deleted.
+        * heap/CollectingScope.h: Added.
+        (JSC::CollectingScope::CollectingScope):
+        (JSC::CollectingScope::~CollectingScope):
+        * heap/CollectorPhase.cpp: Added.
+        (JSC::worldShouldBeSuspended):
+        (WTF::printInternal):
+        * heap/CollectorPhase.h: Added.
+        * heap/EdenGCActivityCallback.cpp:
+        (JSC::EdenGCActivityCallback::lastGCLength):
+        * heap/FullGCActivityCallback.cpp:
+        (JSC::FullGCActivityCallback::doCollection):
+        (JSC::FullGCActivityCallback::lastGCLength):
+        * heap/GCConductor.cpp: Added.
+        (JSC::gcConductorShortName):
+        (WTF::printInternal):
+        * heap/GCConductor.h: Added.
+        * heap/GCFinalizationCallback.cpp: Added.
+        (JSC::GCFinalizationCallback::GCFinalizationCallback):
+        (JSC::GCFinalizationCallback::~GCFinalizationCallback):
+        * heap/GCFinalizationCallback.h: Added.
+        (JSC::GCFinalizationCallbackFuncAdaptor::GCFinalizationCallbackFuncAdaptor):
+        (JSC::createGCFinalizationCallback):
+        * heap/Heap.cpp:
+        (JSC::Heap::Thread::Thread):
+        (JSC::Heap::Heap):
+        (JSC::Heap::lastChanceToFinalize):
+        (JSC::Heap::gatherStackRoots):
+        (JSC::Heap::updateObjectCounts):
+        (JSC::Heap::sweepSynchronously):
+        (JSC::Heap::collectAllGarbage):
+        (JSC::Heap::collectAsync):
+        (JSC::Heap::collectSync):
+        (JSC::Heap::shouldCollectInCollectorThread):
+        (JSC::Heap::collectInCollectorThread):
+        (JSC::Heap::checkConn):
+        (JSC::Heap::runNotRunningPhase):
+        (JSC::Heap::runBeginPhase):
+        (JSC::Heap::runFixpointPhase):
+        (JSC::Heap::runConcurrentPhase):
+        (JSC::Heap::runReloopPhase):
+        (JSC::Heap::runEndPhase):
+        (JSC::Heap::changePhase):
+        (JSC::Heap::finishChangingPhase):
+        (JSC::Heap::stopThePeriphery):
+        (JSC::Heap::resumeThePeriphery):
+        (JSC::Heap::stopTheMutator):
+        (JSC::Heap::resumeTheMutator):
+        (JSC::Heap::stopIfNecessarySlow):
+        (JSC::Heap::collectInMutatorThread):
+        (JSC::Heap::waitForCollector):
+        (JSC::Heap::acquireAccessSlow):
+        (JSC::Heap::releaseAccessSlow):
+        (JSC::Heap::relinquishConn):
+        (JSC::Heap::finishRelinquishingConn):
+        (JSC::Heap::handleNeedFinalize):
+        (JSC::Heap::notifyThreadStopping):
+        (JSC::Heap::finalize):
+        (JSC::Heap::addFinalizationCallback):
+        (JSC::Heap::requestCollection):
+        (JSC::Heap::waitForCollection):
+        (JSC::Heap::updateAllocationLimits):
+        (JSC::Heap::didFinishCollection):
+        (JSC::Heap::collectIfNecessaryOrDefer):
+        (JSC::Heap::notifyIsSafeToCollect):
+        (JSC::Heap::preventCollection):
+        (JSC::Heap::performIncrement):
+        (JSC::Heap::markToFixpoint): Deleted.
+        (JSC::Heap::shouldCollectInThread): Deleted.
+        (JSC::Heap::collectInThread): Deleted.
+        (JSC::Heap::stopTheWorld): Deleted.
+        (JSC::Heap::resumeTheWorld): Deleted.
+        * heap/Heap.h:
+        (JSC::Heap::machineThreads):
+        (JSC::Heap::lastFullGCLength):
+        (JSC::Heap::lastEdenGCLength):
+        (JSC::Heap::increaseLastFullGCLength):
+        * heap/HeapInlines.h:
+        (JSC::Heap::mutatorIsStopped): Deleted.
+        * heap/HeapStatistics.cpp: Removed.
+        * heap/HeapStatistics.h: Removed.
+        * heap/HelpingGCScope.h: Removed.
+        * heap/IncrementalSweeper.cpp:
+        (JSC::IncrementalSweeper::stopSweeping):
+        (JSC::IncrementalSweeper::willFinishSweeping): Deleted.
+        * heap/IncrementalSweeper.h:
+        * heap/MachineStackMarker.cpp:
+        (JSC::MachineThreads::gatherFromCurrentThread):
+        (JSC::MachineThreads::gatherConservativeRoots):
+        (JSC::callWithCurrentThreadState):
+        * heap/MachineStackMarker.h:
+        * heap/MarkedAllocator.cpp:
+        (JSC::MarkedAllocator::allocateSlowCaseImpl):
+        * heap/MarkedBlock.cpp:
+        (JSC::MarkedBlock::Handle::sweep):
+        * heap/MarkedSpace.cpp:
+        (JSC::MarkedSpace::sweep):
+        * heap/MutatorState.cpp:
+        (WTF::printInternal):
+        * heap/MutatorState.h:
+        * heap/RegisterState.h: Added.
+        * heap/RunningScope.h: Added.
+        (JSC::RunningScope::RunningScope):
+        (JSC::RunningScope::~RunningScope):
+        * heap/SlotVisitor.cpp:
+        (JSC::SlotVisitor::SlotVisitor):
+        (JSC::SlotVisitor::drain):
+        (JSC::SlotVisitor::drainFromShared):
+        (JSC::SlotVisitor::drainInParallelPassively):
+        (JSC::SlotVisitor::donateAll):
+        (JSC::SlotVisitor::donate):
+        * heap/SlotVisitor.h:
+        (JSC::SlotVisitor::codeName):
+        * heap/StochasticSpaceTimeMutatorScheduler.cpp:
+        (JSC::StochasticSpaceTimeMutatorScheduler::beginCollection):
+        (JSC::StochasticSpaceTimeMutatorScheduler::synchronousDrainingDidStall):
+        (JSC::StochasticSpaceTimeMutatorScheduler::timeToStop):
+        * heap/SweepingScope.h: Added.
+        (JSC::SweepingScope::SweepingScope):
+        (JSC::SweepingScope::~SweepingScope):
+        * jit/JITWorklist.cpp:
+        (JSC::JITWorklist::Thread::Thread):
+        * jsc.cpp:
+        (GlobalObject::finishCreation):
+        (functionFlashHeapAccess):
+        * runtime/InitializeThreading.cpp:
+        (JSC::initializeThreading):
+        * runtime/JSCellInlines.h:
+        (JSC::JSCell::classInfo):
+        * runtime/Options.cpp:
+        (JSC::overrideDefaults):
+        * runtime/Options.h:
+        * runtime/TestRunnerUtils.cpp:
+        (JSC::finalizeStatsAtEndOfTesting):
+
</ins><span class="cx"> 2017-02-21  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: &quot;!scope.exception()&quot; with Object.isSealed/isFrozen and uninitialized module bindings
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -269,6 +269,7 @@
</span><span class="cx">                 0F2BDC4D1522818600CD8910 /* DFGMinifiedNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */; };
</span><span class="cx">                 0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */; };
</span><span class="cx">                 0F2BDC5115228FFD00CD8910 /* DFGVariableEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */; };
</span><ins>+                0F2C63AA1E4FA42E00C13839 /* RunningScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2C63A91E4FA42C00C13839 /* RunningScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F2D4DDD19832D34007D4B19 /* DebuggerScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */; };
</span><span class="cx">                 0F2D4DDE19832D34007D4B19 /* DebuggerScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F2D4DE819832DAC007D4B19 /* ToThisStatus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2D4DE519832DAC007D4B19 /* ToThisStatus.cpp */; };
</span><span class="lines">@@ -634,7 +635,6 @@
</span><span class="cx">                 0FA762051DB9242900B7A2FD /* CollectionScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA762011DB9242300B7A2FD /* CollectionScope.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FA762061DB9243100B7A2FD /* MutatorState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA762021DB9242300B7A2FD /* MutatorState.cpp */; };
</span><span class="cx">                 0FA762071DB9243300B7A2FD /* MutatorState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA762031DB9242300B7A2FD /* MutatorState.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                0FA762091DB9283E00B7A2FD /* HelpingGCScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA762081DB9283C00B7A2FD /* HelpingGCScope.h */; };
</del><span class="cx">                 0FA7620B1DB959F900B7A2FD /* AllocatingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA7620A1DB959F600B7A2FD /* AllocatingScope.h */; };
</span><span class="cx">                 0FA7A8EB18B413C80052371D /* Reg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FA7A8E918B413C80052371D /* Reg.cpp */; };
</span><span class="cx">                 0FA7A8EC18B413C80052371D /* Reg.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FA7A8EA18B413C80052371D /* Reg.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -735,6 +735,13 @@
</span><span class="cx">                 0FCEFAAC1804C13E00472CE4 /* FTLSaveRestore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFAAA1804C13E00472CE4 /* FTLSaveRestore.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FCEFADF180738C000472CE4 /* FTLLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FCEFADD180738C000472CE4 /* FTLLocation.cpp */; };
</span><span class="cx">                 0FCEFAE0180738C000472CE4 /* FTLLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FCEFADE180738C000472CE4 /* FTLLocation.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0FD0E5E91E43D3490006AB08 /* CollectorPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD0E5E61E43D3470006AB08 /* CollectorPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+                0FD0E5EA1E43D34D0006AB08 /* GCConductor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD0E5E81E43D3470006AB08 /* GCConductor.h */; settings = {ATTRIBUTES = (Private, ); }; };
+                0FD0E5EB1E43D3500006AB08 /* CollectorPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD0E5E51E43D3470006AB08 /* CollectorPhase.cpp */; };
+                0FD0E5EC1E43D3530006AB08 /* GCConductor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD0E5E71E43D3470006AB08 /* GCConductor.cpp */; };
+                0FD0E5EE1E468A570006AB08 /* SweepingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD0E5ED1E468A540006AB08 /* SweepingScope.h */; };
+                0FD0E5F01E46BF250006AB08 /* RegisterState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD0E5EF1E46BF230006AB08 /* RegisterState.h */; settings = {ATTRIBUTES = (Private, ); }; };
+                0FD0E5F21E46C8AF0006AB08 /* CollectingScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD0E5F11E46C8AD0006AB08 /* CollectingScope.h */; };
</ins><span class="cx">                 0FD2C92416D01EE900C7803F /* StructureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD2C92316D01EE900C7803F /* StructureInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FD3C82614115D4000FD81CB /* DFGDriver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FD3C82014115CF800FD81CB /* DFGDriver.cpp */; };
</span><span class="cx">                 0FD3C82814115D4F00FD81CB /* DFGDriver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FD3C82214115D0E00FD81CB /* DFGDriver.h */; };
</span><span class="lines">@@ -1205,7 +1212,7 @@
</span><span class="cx">                 14B723B812D7DA6F003BD5ED /* MachineStackMarker.h in Headers */ = {isa = PBXBuildFile; fileRef = 14B7234012D7D0DA003BD5ED /* MachineStackMarker.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 14B8EC720A5652090062BE54 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6560A4CF04B3B3E7008AE952 /* CoreFoundation.framework */; };
</span><span class="cx">                 14BA78F113AAB88F005B7C2C /* SlotVisitor.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BA78F013AAB88F005B7C2C /* SlotVisitor.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                14BA7A9713AADFF8005B7C2C /* Heap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BA7A9513AADFF8005B7C2C /* Heap.cpp */; };
</del><ins>+                14BA7A9713AADFF8005B7C2C /* Heap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BA7A9513AADFF8005B7C2C /* Heap.cpp */; settings = {COMPILER_FLAGS = &quot;-fno-optimize-sibling-calls&quot;; }; };
</ins><span class="cx">                 14BA7A9813AADFF8005B7C2C /* Heap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14BA7A9613AADFF8005B7C2C /* Heap.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 14BD59C50A3E8F9F00BAF59C /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; };
</span><span class="cx">                 14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A290A3E91F600BAF59C /* JSContextRef.cpp */; };
</span><span class="lines">@@ -2177,8 +2184,6 @@
</span><span class="cx">                 C2181FC218A948FB0025A235 /* JSExportTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = C2181FC118A948FB0025A235 /* JSExportTests.mm */; };
</span><span class="cx">                 C225494315F7DBAA0065E898 /* SlotVisitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C225494215F7DBAA0065E898 /* SlotVisitor.cpp */; };
</span><span class="cx">                 C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */; };
-                C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */ = {isa = PBXBuildFile; fileRef = C24D31E1161CD695002AA4DB /* HeapStatistics.h */; settings = {ATTRIBUTES = (Private, ); }; };
</del><span class="cx">                 C25D709B16DE99F400FCA6BC /* JSManagedValue.mm in Sources */ = {isa = PBXBuildFile; fileRef = C25D709916DE99F400FCA6BC /* JSManagedValue.mm */; };
</span><span class="cx">                 C25D709C16DE99F400FCA6BC /* JSManagedValue.h in Headers */ = {isa = PBXBuildFile; fileRef = C25D709A16DE99F400FCA6BC /* JSManagedValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
</span><span class="cx">                 C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */; };
</span><span class="lines">@@ -2745,6 +2750,7 @@
</span><span class="cx">                 0F2BDC4C1522818300CD8910 /* DFGMinifiedNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMinifiedNode.cpp; path = dfg/DFGMinifiedNode.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGValueSource.cpp; path = dfg/DFGValueSource.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEvent.cpp; path = dfg/DFGVariableEvent.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F2C63A91E4FA42C00C13839 /* RunningScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RunningScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F2D4DDB19832D34007D4B19 /* DebuggerScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerScope.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F2D4DDC19832D34007D4B19 /* DebuggerScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DebuggerScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F2D4DDF19832D91007D4B19 /* TypeProfilerLog.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeProfilerLog.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3104,7 +3110,6 @@
</span><span class="cx">                 0FA762011DB9242300B7A2FD /* CollectionScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectionScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FA762021DB9242300B7A2FD /* MutatorState.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MutatorState.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FA762031DB9242300B7A2FD /* MutatorState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MutatorState.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                0FA762081DB9283C00B7A2FD /* HelpingGCScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HelpingGCScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><span class="cx">                 0FA7620A1DB959F600B7A2FD /* AllocatingScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AllocatingScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FA7A8E918B413C80052371D /* Reg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Reg.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FA7A8EA18B413C80052371D /* Reg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reg.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3217,6 +3222,13 @@
</span><span class="cx">                 0FCEFAAA1804C13E00472CE4 /* FTLSaveRestore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLSaveRestore.h; path = ftl/FTLSaveRestore.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FCEFADD180738C000472CE4 /* FTLLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLLocation.cpp; path = ftl/FTLLocation.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FCEFADE180738C000472CE4 /* FTLLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLLocation.h; path = ftl/FTLLocation.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FD0E5E51E43D3470006AB08 /* CollectorPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CollectorPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FD0E5E61E43D3470006AB08 /* CollectorPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectorPhase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FD0E5E71E43D3470006AB08 /* GCConductor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCConductor.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FD0E5E81E43D3470006AB08 /* GCConductor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCConductor.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FD0E5ED1E468A540006AB08 /* SweepingScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SweepingScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FD0E5EF1E46BF230006AB08 /* RegisterState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterState.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FD0E5F11E46C8AD0006AB08 /* CollectingScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CollectingScope.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FD2C92316D01EE900C7803F /* StructureInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FD3C82014115CF800FD81CB /* DFGDriver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDriver.cpp; path = dfg/DFGDriver.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FD3C82214115D0E00FD81CB /* DFGDriver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDriver.h; path = dfg/DFGDriver.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4690,8 +4702,6 @@
</span><span class="cx">                 C2181FC018A948FB0025A235 /* JSExportTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSExportTests.h; path = API/tests/JSExportTests.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C2181FC118A948FB0025A235 /* JSExportTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = JSExportTests.mm; path = API/tests/JSExportTests.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C225494215F7DBAA0065E898 /* SlotVisitor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SlotVisitor.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapStatistics.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
-                C24D31E1161CD695002AA4DB /* HeapStatistics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapStatistics.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><span class="cx">                 C25D709916DE99F400FCA6BC /* JSManagedValue.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = JSManagedValue.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C25D709A16DE99F400FCA6BC /* JSManagedValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSManagedValue.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IncrementalSweeper.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5754,8 +5764,11 @@
</span><span class="cx">                                 0FD8A31117D4326C00CA2C40 /* CodeBlockSet.cpp */,
</span><span class="cx">                                 0FD8A31217D4326C00CA2C40 /* CodeBlockSet.h */,
</span><span class="cx">                                 0F664CE71DA304ED00B00A11 /* CodeBlockSetInlines.h */,
</span><ins>+                                0FD0E5F11E46C8AD0006AB08 /* CollectingScope.h */,
</ins><span class="cx">                                 0FA762001DB9242300B7A2FD /* CollectionScope.cpp */,
</span><span class="cx">                                 0FA762011DB9242300B7A2FD /* CollectionScope.h */,
</span><ins>+                                0FD0E5E51E43D3470006AB08 /* CollectorPhase.cpp */,
+                                0FD0E5E61E43D3470006AB08 /* CollectorPhase.h */,
</ins><span class="cx">                                 146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */,
</span><span class="cx">                                 149DAAF212EB559D0083B12B /* ConservativeRoots.h */,
</span><span class="cx">                                 0F7DF12F1E2970D50095951B /* ConstraintVolatility.h */,
</span><span class="lines">@@ -5773,6 +5786,8 @@
</span><span class="cx">                                 2AACE63A18CA5A0300ED0191 /* GCActivityCallback.cpp */,
</span><span class="cx">                                 2AACE63B18CA5A0300ED0191 /* GCActivityCallback.h */,
</span><span class="cx">                                 BCBE2CAD14E985AA000593AD /* GCAssertions.h */,
</span><ins>+                                0FD0E5E71E43D3470006AB08 /* GCConductor.cpp */,
+                                0FD0E5E81E43D3470006AB08 /* GCConductor.h */,
</ins><span class="cx">                                 0FB4767C1D99AEA7008EA6CB /* GCDeferralContext.h */,
</span><span class="cx">                                 0FB4767D1D99AEA7008EA6CB /* GCDeferralContextInlines.h */,
</span><span class="cx">                                 0F2B66A817B6B53D00A7AE3F /* GCIncomingRefCounted.h */,
</span><span class="lines">@@ -5808,14 +5823,11 @@
</span><span class="cx">                                 A54C2AAF1C6544D100A18D78 /* HeapSnapshot.h */,
</span><span class="cx">                                 A5311C341C77CEAC00E6B1B6 /* HeapSnapshotBuilder.cpp */,
</span><span class="cx">                                 A5311C351C77CEAC00E6B1B6 /* HeapSnapshotBuilder.h */,
</span><del>-                                C24D31E0161CD695002AA4DB /* HeapStatistics.cpp */,
-                                C24D31E1161CD695002AA4DB /* HeapStatistics.h */,
</del><span class="cx">                                 C2E526BB1590EF000054E48D /* HeapTimer.cpp */,
</span><span class="cx">                                 C2E526BC1590EF000054E48D /* HeapTimer.h */,
</span><span class="cx">                                 0FADE6721D4D23BC00768457 /* HeapUtil.h */,
</span><span class="cx">                                 FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */,
</span><span class="cx">                                 FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */,
</span><del>-                                0FA762081DB9283C00B7A2FD /* HelpingGCScope.h */,
</del><span class="cx">                                 C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */,
</span><span class="cx">                                 C25F8BCC157544A900245B71 /* IncrementalSweeper.h */,
</span><span class="cx">                                 0F766D2915A8CC34008F363E /* JITStubRoutineSet.cpp */,
</span><span class="lines">@@ -5853,7 +5865,9 @@
</span><span class="cx">                                 0FA762031DB9242300B7A2FD /* MutatorState.h */,
</span><span class="cx">                                 ADDB1F6218D77DB7009B58A8 /* OpaqueRootSet.h */,
</span><span class="cx">                                 0FBB73B61DEF3AAC002C009E /* PreventCollectionScope.h */,
</span><ins>+                                0FD0E5EF1E46BF230006AB08 /* RegisterState.h */,
</ins><span class="cx">                                 0F7CF94E1DBEEE860098CC12 /* ReleaseHeapAccessScope.h */,
</span><ins>+                                0F2C63A91E4FA42C00C13839 /* RunningScope.h */,
</ins><span class="cx">                                 C225494215F7DBAA0065E898 /* SlotVisitor.cpp */,
</span><span class="cx">                                 14BA78F013AAB88F005B7C2C /* SlotVisitor.h */,
</span><span class="cx">                                 0FCB408515C0A3C30048932B /* SlotVisitorInlines.h */,
</span><span class="lines">@@ -5868,6 +5882,7 @@
</span><span class="cx">                                 0F7DF1311E2970D50095951B /* Subspace.cpp */,
</span><span class="cx">                                 0F7DF1321E2970D50095951B /* Subspace.h */,
</span><span class="cx">                                 0F7DF1331E2970D50095951B /* SubspaceInlines.h */,
</span><ins>+                                0FD0E5ED1E468A540006AB08 /* SweepingScope.h */,
</ins><span class="cx">                                 0F1FB38A1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.cpp */,
</span><span class="cx">                                 0F1FB38B1E173A6200A9BE50 /* SynchronousStopTheWorldMutatorScheduler.h */,
</span><span class="cx">                                 141448CC13A1783700F5BA1A /* TinyBloomFilter.h */,
</span><span class="lines">@@ -7988,6 +8003,7 @@
</span><span class="cx">                                 0F6B8AE31C4EFE1700969052 /* B3BreakCriticalEdges.h in Headers */,
</span><span class="cx">                                 DC9A0C201D2D9CB30085124E /* B3CaseCollection.h in Headers */,
</span><span class="cx">                                 DC9A0C1F1D2D9CB10085124E /* B3CaseCollectionInlines.h in Headers */,
</span><ins>+                                0FD0E5EE1E468A570006AB08 /* SweepingScope.h in Headers */,
</ins><span class="cx">                                 0F338DFA1BE96AA80013C88F /* B3CCallValue.h in Headers */,
</span><span class="cx">                                 0F33FCFB1C1625BE00323F67 /* B3CFG.h in Headers */,
</span><span class="cx">                                 0FEC85061BDACDAC0080FF74 /* B3CheckSpecial.h in Headers */,
</span><span class="lines">@@ -8263,6 +8279,7 @@
</span><span class="cx">                                 0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */,
</span><span class="cx">                                 0F2017801DCADC3500EA5950 /* DFGFlowIndexing.h in Headers */,
</span><span class="cx">                                 0F2017821DCADD4200EA5950 /* DFGFlowMap.h in Headers */,
</span><ins>+                                0F2C63AA1E4FA42E00C13839 /* RunningScope.h in Headers */,
</ins><span class="cx">                                 0F9D339717FFC4E60073C2BC /* DFGFlushedAt.h in Headers */,
</span><span class="cx">                                 A7D89CF817A0B8CC00773AD8 /* DFGFlushFormat.h in Headers */,
</span><span class="cx">                                 0F2DD8151AB3D8BE00BBB8E8 /* DFGForAllKills.h in Headers */,
</span><span class="lines">@@ -8555,11 +8572,10 @@
</span><span class="cx">                                 A5398FAB1C750DA40060A963 /* HeapProfiler.h in Headers */,
</span><span class="cx">                                 A54C2AB11C6544F200A18D78 /* HeapSnapshot.h in Headers */,
</span><span class="cx">                                 A5311C361C77CEC500E6B1B6 /* HeapSnapshotBuilder.h in Headers */,
</span><del>-                                C24D31E3161CD695002AA4DB /* HeapStatistics.h in Headers */,
</del><span class="cx">                                 C2E526BE1590EF000054E48D /* HeapTimer.h in Headers */,
</span><ins>+                                0FD0E5EA1E43D34D0006AB08 /* GCConductor.h in Headers */,
</ins><span class="cx">                                 0FADE6731D4D23BE00768457 /* HeapUtil.h in Headers */,
</span><span class="cx">                                 FE7BA6101A1A7CEC00F1F7B4 /* HeapVerifier.h in Headers */,
</span><del>-                                0FA762091DB9283E00B7A2FD /* HelpingGCScope.h in Headers */,
</del><span class="cx">                                 0F4680D514BBD24B00BFE272 /* HostCallReturnValue.h in Headers */,
</span><span class="cx">                                 DC2143071CA32E55000A8869 /* ICStats.h in Headers */,
</span><span class="cx">                                 BC18C40F0E16F5CD00B34460 /* Identifier.h in Headers */,
</span><span class="lines">@@ -8620,6 +8636,7 @@
</span><span class="cx">                                 A1B9E23E1B4E0D6700BC7FED /* IntlCollatorPrototype.h in Headers */,
</span><span class="cx">                                 A18193E41B4E0CDB00FC1029 /* IntlCollatorPrototype.lut.h in Headers */,
</span><span class="cx">                                 A1587D6E1B4DC14100D69849 /* IntlDateTimeFormat.h in Headers */,
</span><ins>+                                0FD0E5E91E43D3490006AB08 /* CollectorPhase.h in Headers */,
</ins><span class="cx">                                 A1587D701B4DC14100D69849 /* IntlDateTimeFormatConstructor.h in Headers */,
</span><span class="cx">                                 A1587D751B4DC1C600D69849 /* IntlDateTimeFormatConstructor.lut.h in Headers */,
</span><span class="cx">                                 A1587D721B4DC14100D69849 /* IntlDateTimeFormatPrototype.h in Headers */,
</span><span class="lines">@@ -8629,6 +8646,7 @@
</span><span class="cx">                                 A125846E1B45A36000CC7F6C /* IntlNumberFormatConstructor.lut.h in Headers */,
</span><span class="cx">                                 A1D793011B43864B004516F5 /* IntlNumberFormatPrototype.h in Headers */,
</span><span class="cx">                                 A125846F1B45A36000CC7F6C /* IntlNumberFormatPrototype.lut.h in Headers */,
</span><ins>+                                0FD0E5F01E46BF250006AB08 /* RegisterState.h in Headers */,
</ins><span class="cx">                                 A12BBFF21B044A8B00664B69 /* IntlObject.h in Headers */,
</span><span class="cx">                                 708EBE241CE8F35800453146 /* IntlObjectInlines.h in Headers */,
</span><span class="cx">                                 860BD801148EA6F200112B2F /* Intrinsic.h in Headers */,
</span><span class="lines">@@ -9209,6 +9227,7 @@
</span><span class="cx">                                 AD2FCBED1DB58DAD00B3E736 /* WebAssemblyCompileErrorConstructor.h in Headers */,
</span><span class="cx">                                 AD2FCC161DB59CB200B3E736 /* WebAssemblyCompileErrorConstructor.lut.h in Headers */,
</span><span class="cx">                                 AD2FCBEF1DB58DAD00B3E736 /* WebAssemblyCompileErrorPrototype.h in Headers */,
</span><ins>+                                0FD0E5F21E46C8AF0006AB08 /* CollectingScope.h in Headers */,
</ins><span class="cx">                                 AD2FCC171DB59CB200B3E736 /* WebAssemblyCompileErrorPrototype.lut.h in Headers */,
</span><span class="cx">                                 AD4937D41DDD27DE0077C807 /* WebAssemblyFunction.h in Headers */,
</span><span class="cx">                                 AD2FCBF11DB58DAD00B3E736 /* WebAssemblyInstanceConstructor.h in Headers */,
</span><span class="lines">@@ -10183,7 +10202,6 @@
</span><span class="cx">                                 A5398FAC1C750DA60060A963 /* HeapProfiler.cpp in Sources */,
</span><span class="cx">                                 A54C2AB01C6544EE00A18D78 /* HeapSnapshot.cpp in Sources */,
</span><span class="cx">                                 A5311C371C77CECA00E6B1B6 /* HeapSnapshotBuilder.cpp in Sources */,
</span><del>-                                C24D31E2161CD695002AA4DB /* HeapStatistics.cpp in Sources */,
</del><span class="cx">                                 C2E526BD1590EF000054E48D /* HeapTimer.cpp in Sources */,
</span><span class="cx">                                 FE7BA60F1A1A7CEC00F1F7B4 /* HeapVerifier.cpp in Sources */,
</span><span class="cx">                                 0F4680D414BBD24900BFE272 /* HostCallReturnValue.cpp in Sources */,
</span><span class="lines">@@ -10248,6 +10266,7 @@
</span><span class="cx">                                 0FAF7EFD165BA91B000C8455 /* JITDisassembler.cpp in Sources */,
</span><span class="cx">                                 FE187A0E1C030D640038BBCA /* JITDivGenerator.cpp in Sources */,
</span><span class="cx">                                 0F46808314BA573100BFE272 /* JITExceptions.cpp in Sources */,
</span><ins>+                                0FD0E5EB1E43D3500006AB08 /* CollectorPhase.cpp in Sources */,
</ins><span class="cx">                                 0FB14E1E18124ACE009B6B4D /* JITInlineCacheGenerator.cpp in Sources */,
</span><span class="cx">                                 FE3A06BD1C11040D00390FDD /* JITLeftShiftGenerator.cpp in Sources */,
</span><span class="cx">                                 FE187A011BFBE55E0038BBCA /* JITMulGenerator.cpp in Sources */,
</span><span class="lines">@@ -10495,6 +10514,7 @@
</span><span class="cx">                                 6540C7A01B82E1C3000F6B79 /* RegisterAtOffset.cpp in Sources */,
</span><span class="cx">                                 6540C7A11B82E1C3000F6B79 /* RegisterAtOffsetList.cpp in Sources */,
</span><span class="cx">                                 0FC3141518146D7000033232 /* RegisterSet.cpp in Sources */,
</span><ins>+                                0FD0E5EC1E43D3530006AB08 /* GCConductor.cpp in Sources */,
</ins><span class="cx">                                 A57D23ED1891B5540031C7FA /* RegularExpression.cpp in Sources */,
</span><span class="cx">                                 992ABCF91BEA9BD2006403A0 /* RemoteAutomationTarget.cpp in Sources */,
</span><span class="cx">                                 992F56B41E4E84A40035953B /* RemoteConnectionToTargetCocoa.mm in Sources */,
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/bytecode/CodeBlock.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -2532,7 +2532,12 @@
</span><span class="cx">         visitor.reportExtraMemoryVisited(m_jitCode-&gt;size());
</span><span class="cx">     if (m_instructions.size()) {
</span><span class="cx">         unsigned refCount = m_instructions.refCount();
</span><del>-        RELEASE_ASSERT(refCount);
</del><ins>+        if (!refCount) {
+            dataLog(&quot;CodeBlock: &quot;, RawPointer(this), &quot;\n&quot;);
+            dataLog(&quot;m_instructions.data(): &quot;, RawPointer(m_instructions.data()), &quot;\n&quot;);
+            dataLog(&quot;refCount: &quot;, refCount, &quot;\n&quot;);
+            RELEASE_ASSERT_NOT_REACHED();
+        }
</ins><span class="cx">         visitor.reportExtraMemoryVisited(m_instructions.size() * sizeof(Instruction) / refCount);
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoredfgDFGWorklistcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx"> 
</span><span class="cx"> class Worklist::ThreadBody : public AutomaticThread {
</span><span class="cx"> public:
</span><del>-    ThreadBody(const LockHolder&amp; locker, Worklist&amp; worklist, ThreadData&amp; data, Box&lt;Lock&gt; lock, RefPtr&lt;AutomaticThreadCondition&gt; condition, int relativePriority)
</del><ins>+    ThreadBody(const AbstractLocker&amp; locker, Worklist&amp; worklist, ThreadData&amp; data, Box&lt;Lock&gt; lock, RefPtr&lt;AutomaticThreadCondition&gt; condition, int relativePriority)
</ins><span class="cx">         : AutomaticThread(locker, lock, condition)
</span><span class="cx">         , m_worklist(worklist)
</span><span class="cx">         , m_data(data)
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx"> protected:
</span><del>-    PollResult poll(const LockHolder&amp; locker) override
</del><ins>+    PollResult poll(const AbstractLocker&amp; locker) override
</ins><span class="cx">     {
</span><span class="cx">         if (m_worklist.m_queue.isEmpty())
</span><span class="cx">             return PollResult::Wait;
</span><span class="lines">@@ -150,7 +150,7 @@
</span><span class="cx">         m_longLivedState = std::make_unique&lt;LongLivedState&gt;();
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void threadIsStopping(const LockHolder&amp;) override
</del><ins>+    void threadIsStopping(const AbstractLocker&amp;) override
</ins><span class="cx">     {
</span><span class="cx">         // We're holding the Worklist::m_lock, so we should be careful not to deadlock.
</span><span class="cx">         
</span><span class="lines">@@ -479,7 +479,7 @@
</span><span class="cx">     dump(locker, out);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Worklist::dump(const LockHolder&amp;, PrintStream&amp; out) const
</del><ins>+void Worklist::dump(const AbstractLocker&amp;, PrintStream&amp; out) const
</ins><span class="cx"> {
</span><span class="cx">     out.print(
</span><span class="cx">         &quot;Worklist(&quot;, RawPointer(this), &quot;)[Queue Length = &quot;, m_queue.size(),
</span><span class="lines">@@ -535,6 +535,41 @@
</span><span class="cx">     return ensureGlobalDFGWorklist();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+unsigned numberOfWorklists() { return 2; }
+
+Worklist&amp; ensureWorklistForIndex(unsigned index)
+{
+    switch (index) {
+    case 0:
+        return ensureGlobalDFGWorklist();
+    case 1:
+        return ensureGlobalFTLWorklist();
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return ensureGlobalDFGWorklist();
+    }
+}
+
+Worklist* existingWorklistForIndexOrNull(unsigned index)
+{
+    switch (index) {
+    case 0:
+        return existingGlobalDFGWorklistOrNull();
+    case 1:
+        return existingGlobalFTLWorklistOrNull();
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
+Worklist&amp; existingWorklistForIndex(unsigned index)
+{
+    Worklist* result = existingWorklistForIndexOrNull(index);
+    RELEASE_ASSERT(result);
+    return *result;
+}
+
</ins><span class="cx"> void completeAllPlansForVM(VM&amp; vm)
</span><span class="cx"> {
</span><span class="cx">     for (unsigned i = DFG::numberOfWorklists(); i--;) {
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoredfgDFGWorklisth"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/dfg/DFGWorklist.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -93,7 +93,7 @@
</span><span class="cx">     
</span><span class="cx">     void removeAllReadyPlansForVM(VM&amp;, Vector&lt;RefPtr&lt;Plan&gt;, 8&gt;&amp;);
</span><span class="cx"> 
</span><del>-    void dump(const LockHolder&amp;, PrintStream&amp;) const;
</del><ins>+    void dump(const AbstractLocker&amp;, PrintStream&amp;) const;
</ins><span class="cx">     
</span><span class="cx">     CString m_threadName;
</span><span class="cx">     
</span><span class="lines">@@ -132,37 +132,10 @@
</span><span class="cx"> Worklist&amp; ensureGlobalWorklistFor(CompilationMode);
</span><span class="cx"> 
</span><span class="cx"> // Simplify doing things for all worklists.
</span><del>-inline unsigned numberOfWorklists() { return 2; }
-inline Worklist&amp; ensureWorklistForIndex(unsigned index)
-{
-    switch (index) {
-    case 0:
-        return ensureGlobalDFGWorklist();
-    case 1:
-        return ensureGlobalFTLWorklist();
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        return ensureGlobalDFGWorklist();
-    }
-}
-inline Worklist* existingWorklistForIndexOrNull(unsigned index)
-{
-    switch (index) {
-    case 0:
-        return existingGlobalDFGWorklistOrNull();
-    case 1:
-        return existingGlobalFTLWorklistOrNull();
-    default:
-        RELEASE_ASSERT_NOT_REACHED();
-        return 0;
-    }
-}
-inline Worklist&amp; existingWorklistForIndex(unsigned index)
-{
-    Worklist* result = existingWorklistForIndexOrNull(index);
-    RELEASE_ASSERT(result);
-    return *result;
-}
</del><ins>+unsigned numberOfWorklists();
+Worklist&amp; ensureWorklistForIndex(unsigned index);
+Worklist* existingWorklistForIndexOrNull(unsigned index);
+Worklist&amp; existingWorklistForIndex(unsigned index);
</ins><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapCollectingScopehfromrev213034releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapStatisticsh"></a>
<div class="copfile"><h4>Copied: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectingScope.h (from rev 213034, releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.h) (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectingScope.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectingScope.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,52 @@
</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;Heap.h&quot;
+
+namespace JSC {
+
+class CollectingScope {
+public:
+    CollectingScope(Heap&amp; heap)
+        : m_heap(heap)
+        , m_oldState(m_heap.m_mutatorState)
+    {
+        m_heap.m_mutatorState = MutatorState::Collecting;
+    }
+    
+    ~CollectingScope()
+    {
+        m_heap.m_mutatorState = m_oldState;
+    }
+
+private:
+    Heap&amp; m_heap;
+    MutatorState m_oldState;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapCollectorPhasecppfromrev213034releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMutatorStatecpp"></a>
<div class="copfile"><h4>Copied: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.cpp (from rev 213034, releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.cpp) (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.cpp                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,84 @@
</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;CollectorPhase.h&quot;
+
+#include &lt;wtf/PrintStream.h&gt;
+
+namespace JSC {
+
+bool worldShouldBeSuspended(CollectorPhase phase)
+{
+    switch (phase) {
+    case CollectorPhase::NotRunning:
+    case CollectorPhase::Concurrent:
+        return false;
+        
+    case CollectorPhase::Begin:
+    case CollectorPhase::Fixpoint:
+    case CollectorPhase::Reloop:
+    case CollectorPhase::End:
+        return true;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream&amp; out, JSC::CollectorPhase phase)
+{
+    switch (phase) {
+    case CollectorPhase::NotRunning:
+        out.print(&quot;NotRunning&quot;);
+        return;
+    case CollectorPhase::Begin:
+        out.print(&quot;Begin&quot;);
+        return;
+    case CollectorPhase::Fixpoint:
+        out.print(&quot;Fixpoint&quot;);
+        return;
+    case CollectorPhase::Concurrent:
+        out.print(&quot;Concurrent&quot;);
+        return;
+    case CollectorPhase::Reloop:
+        out.print(&quot;Reloop&quot;);
+        return;
+    case CollectorPhase::End:
+        out.print(&quot;End&quot;);
+        return;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapCollectorPhaseh"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.h (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/CollectorPhase.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,75 @@
</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
+
+namespace JSC {
+
+// We track collector phase in order to allow either the collector thread or the mutator thread to
+// jump in and do work. The collector and mutator trade the conn
+// (https://en.wikipedia.org/wiki/Conn_(nautical)) with each other based on who is available to do work,
+// and they use the phase to help each other know what to do once they take the conn.
+//
+// The collector relinquishes the conn whenever it stopTheMutator's and the mutator is running. Then the
+// collector thread goes to sleep.
+//
+// The mutator relinquishes the conn whenever it releaseAccess's. That wakes up the collector thread.
+enum class CollectorPhase : uint8_t {
+    // We use this phase when the collector is not running at all. After this state is Begin.
+    NotRunning,
+    
+    // This is everything from when the collector begins to when it first yields to the mutator for
+    // marking. After this is Fixpoint.
+    Begin,
+    
+    // This means that we should try to do some progress with the world stopped. This usually means
+    // doing an iteration of MarkingConstraintSet::executeConvergence, but it could also mean marking
+    // with the world stopped. After this is either Concurrent or End.
+    Fixpoint,
+    
+    // In this state the collector is relying on the parallel helpers and incremental mutator work to
+    // make progress. After this is Reloop, once marking stalls.
+    Concurrent,
+        
+    // We did some concurrent marking and now we ran out of work. This phase prepares the GC for another
+    // Fixpoint. After this is Fixpoint.
+    Reloop,
+    
+    // The collector is trying to finish up. After this state is NotRunning.
+    End
+};
+
+bool worldShouldBeSuspended(CollectorPhase phase);
+
+} // namespace JSC
+
+namespace WTF {
+
+class PrintStream;
+
+void printInternal(PrintStream&amp;, JSC::CollectorPhase);
+
+} // namespace WTF
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapEdenGCActivityCallbackcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/EdenGCActivityCallback.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014, 2016 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">@@ -45,7 +45,7 @@
</span><span class="cx"> 
</span><span class="cx"> double EdenGCActivityCallback::lastGCLength()
</span><span class="cx"> {
</span><del>-    return m_vm-&gt;heap.lastEdenGCLength();
</del><ins>+    return m_vm-&gt;heap.lastEdenGCLength().seconds();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> double EdenGCActivityCallback::deathRate()
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapFullGCActivityCallbackcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/FullGCActivityCallback.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/FullGCActivityCallback.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/FullGCActivityCallback.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014, 2016 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">@@ -50,7 +50,7 @@
</span><span class="cx">     double startTime = WTF::monotonicallyIncreasingTime();
</span><span class="cx">     if (heap.isPagedOut(startTime + pagingTimeOut)) {
</span><span class="cx">         cancel();
</span><del>-        heap.increaseLastFullGCLength(pagingTimeOut);
</del><ins>+        heap.increaseLastFullGCLength(Seconds(pagingTimeOut));
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> #endif
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx"> 
</span><span class="cx"> double FullGCActivityCallback::lastGCLength()
</span><span class="cx"> {
</span><del>-    return m_vm-&gt;heap.lastFullGCLength();
</del><ins>+    return m_vm-&gt;heap.lastFullGCLength().seconds();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> double FullGCActivityCallback::deathRate()
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapGCConductorcppfromrev213034releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMutatorStatecpp"></a>
<div class="copfile"><h4>Copied: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.cpp (from rev 213034, releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.cpp) (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.cpp                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</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. 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;GCConductor.h&quot;
+
+#include &lt;wtf/PrintStream.h&gt;
+
+namespace JSC {
+
+const char* gcConductorShortName(GCConductor conn)
+{
+    switch (conn) {
+    case GCConductor::Mutator:
+        return &quot;M&quot;;
+    case GCConductor::Collector:
+        return &quot;C&quot;;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+using namespace JSC;
+
+void printInternal(PrintStream&amp; out, GCConductor conn)
+{
+    switch (conn) {
+    case GCConductor::Mutator:
+        out.print(&quot;Mutator&quot;);
+        return;
+    case GCConductor::Collector:
+        out.print(&quot;Collector&quot;);
+        return;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapGCConductorhfromrev213034releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMutatorStateh"></a>
<div class="copfile"><h4>Copied: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.h (from rev 213034, releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.h) (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/GCConductor.h        2017-02-27 08:24:07 UTC (rev 213037)
</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. 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
+
+namespace JSC {
+
+// Either the mutator has the conn (https://en.wikipedia.org/wiki/Conn_(nautical)), meaning that the
+// mutator will incrementally drive the collector when it calls into slow paths; or the collector has the
+// conn, meaning that the collector thread will drive the collector.
+enum class GCConductor : uint8_t {
+    Mutator,
+    Collector
+};
+
+const char* gcConductorShortName(GCConductor officer);
+
+} // namespace JSC
+
+namespace WTF {
+
+class PrintStream;
+
+void printInternal(PrintStream&amp;, JSC::GCConductor);
+
+} // namespace WTF
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> #include &quot;CodeBlockSetInlines.h&quot;
</span><ins>+#include &quot;CollectingScope.h&quot;
</ins><span class="cx"> #include &quot;ConservativeRoots.h&quot;
</span><span class="cx"> #include &quot;DFGWorklistInlines.h&quot;
</span><span class="cx"> #include &quot;EdenGCActivityCallback.h&quot;
</span><span class="lines">@@ -37,9 +38,7 @@
</span><span class="cx"> #include &quot;HeapIterationScope.h&quot;
</span><span class="cx"> #include &quot;HeapProfiler.h&quot;
</span><span class="cx"> #include &quot;HeapSnapshot.h&quot;
</span><del>-#include &quot;HeapStatistics.h&quot;
</del><span class="cx"> #include &quot;HeapVerifier.h&quot;
</span><del>-#include &quot;HelpingGCScope.h&quot;
</del><span class="cx"> #include &quot;IncrementalSweeper.h&quot;
</span><span class="cx"> #include &quot;Interpreter.h&quot;
</span><span class="cx"> #include &quot;JITStubRoutineSet.h&quot;
</span><span class="lines">@@ -48,6 +47,7 @@
</span><span class="cx"> #include &quot;JSGlobalObject.h&quot;
</span><span class="cx"> #include &quot;JSLock.h&quot;
</span><span class="cx"> #include &quot;JSVirtualMachineInternal.h&quot;
</span><ins>+#include &quot;MachineStackMarker.h&quot;
</ins><span class="cx"> #include &quot;MarkedSpaceInlines.h&quot;
</span><span class="cx"> #include &quot;MarkingConstraintSet.h&quot;
</span><span class="cx"> #include &quot;PreventCollectionScope.h&quot;
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx"> #include &quot;SuperSampler.h&quot;
</span><span class="cx"> #include &quot;StochasticSpaceTimeMutatorScheduler.h&quot;
</span><span class="cx"> #include &quot;StopIfNecessaryTimer.h&quot;
</span><ins>+#include &quot;SweepingScope.h&quot;
</ins><span class="cx"> #include &quot;SynchronousStopTheWorldMutatorScheduler.h&quot;
</span><span class="cx"> #include &quot;TypeProfilerLog.h&quot;
</span><span class="cx"> #include &quot;UnlinkedCodeBlock.h&quot;
</span><span class="lines">@@ -206,7 +207,7 @@
</span><span class="cx"> 
</span><span class="cx"> class Heap::Thread : public AutomaticThread {
</span><span class="cx"> public:
</span><del>-    Thread(const LockHolder&amp; locker, Heap&amp; heap)
</del><ins>+    Thread(const AbstractLocker&amp; locker, Heap&amp; heap)
</ins><span class="cx">         : AutomaticThread(locker, heap.m_threadLock, heap.m_threadCondition)
</span><span class="cx">         , m_heap(heap)
</span><span class="cx">     {
</span><span class="lines">@@ -213,13 +214,13 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx"> protected:
</span><del>-    PollResult poll(const LockHolder&amp; locker) override
</del><ins>+    PollResult poll(const AbstractLocker&amp; locker) override
</ins><span class="cx">     {
</span><span class="cx">         if (m_heap.m_threadShouldStop) {
</span><span class="cx">             m_heap.notifyThreadStopping(locker);
</span><span class="cx">             return PollResult::Stop;
</span><span class="cx">         }
</span><del>-        if (m_heap.shouldCollectInThread(locker))
</del><ins>+        if (m_heap.shouldCollectInCollectorThread(locker))
</ins><span class="cx">             return PollResult::Work;
</span><span class="cx">         return PollResult::Wait;
</span><span class="cx">     }
</span><span class="lines">@@ -226,7 +227,7 @@
</span><span class="cx">     
</span><span class="cx">     WorkResult work() override
</span><span class="cx">     {
</span><del>-        m_heap.collectInThread();
</del><ins>+        m_heap.collectInCollectorThread();
</ins><span class="cx">         return WorkResult::Continue;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -257,9 +258,9 @@
</span><span class="cx">     , m_objectSpace(this)
</span><span class="cx">     , m_extraMemorySize(0)
</span><span class="cx">     , m_deprecatedExtraMemorySize(0)
</span><del>-    , m_machineThreads(this)
-    , m_collectorSlotVisitor(std::make_unique&lt;SlotVisitor&gt;(*this))
-    , m_mutatorSlotVisitor(std::make_unique&lt;SlotVisitor&gt;(*this))
</del><ins>+    , m_machineThreads(std::make_unique&lt;MachineThreads&gt;(this))
+    , m_collectorSlotVisitor(std::make_unique&lt;SlotVisitor&gt;(*this, &quot;C&quot;))
+    , m_mutatorSlotVisitor(std::make_unique&lt;SlotVisitor&gt;(*this, &quot;M&quot;))
</ins><span class="cx">     , m_mutatorMarkStack(std::make_unique&lt;MarkStackArray&gt;())
</span><span class="cx">     , m_raceMarkStack(std::make_unique&lt;MarkStackArray&gt;())
</span><span class="cx">     , m_constraintSet(std::make_unique&lt;MarkingConstraintSet&gt;())
</span><span class="lines">@@ -333,6 +334,12 @@
</span><span class="cx"> // Run all pending finalizers now because we won't get another chance.
</span><span class="cx"> void Heap::lastChanceToFinalize()
</span><span class="cx"> {
</span><ins>+    MonotonicTime before;
+    if (Options::logGC()) {
+        before = MonotonicTime::now();
+        dataLog(&quot;[GC&lt;&quot;, RawPointer(this), &quot;&gt;: shutdown &quot;);
+    }
+    
</ins><span class="cx">     RELEASE_ASSERT(!m_vm-&gt;entryScope);
</span><span class="cx">     RELEASE_ASSERT(m_mutatorState == MutatorState::Running);
</span><span class="cx">     
</span><span class="lines">@@ -345,26 +352,62 @@
</span><span class="cx">         waitForThreadCompletion(m_collectContinuouslyThread);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    // Carefully bring the thread down. We need to use waitForCollector() until we know that there
-    // won't be any other collections.
</del><ins>+    if (Options::logGC())
+        dataLog(&quot;1&quot;);
+    
+    // Prevent new collections from being started. This is probably not even necessary, since we're not
+    // going to call into anything that starts collections. Still, this makes the algorithm more
+    // obviously sound.
+    m_isSafeToCollect = false;
+    
+    if (Options::logGC())
+        dataLog(&quot;2&quot;);
+
+    bool isCollecting;
+    {
+        auto locker = holdLock(*m_threadLock);
+        RELEASE_ASSERT(m_lastServedTicket &lt;= m_lastGrantedTicket);
+        isCollecting = m_lastServedTicket &lt; m_lastGrantedTicket;
+    }
+    if (isCollecting) {
+        if (Options::logGC())
+            dataLog(&quot;...]\n&quot;);
+        
+        // Wait for the current collection to finish.
+        waitForCollector(
+            [&amp;] (const AbstractLocker&amp;) -&gt; bool {
+                RELEASE_ASSERT(m_lastServedTicket &lt;= m_lastGrantedTicket);
+                return m_lastServedTicket == m_lastGrantedTicket;
+            });
+        
+        if (Options::logGC())
+            dataLog(&quot;[GC&lt;&quot;, RawPointer(this), &quot;&gt;: shutdown &quot;);
+    }
+    if (Options::logGC())
+        dataLog(&quot;3&quot;);
+
+    RELEASE_ASSERT(m_requests.isEmpty());
+    RELEASE_ASSERT(m_lastServedTicket == m_lastGrantedTicket);
+    
+    // Carefully bring the thread down.
</ins><span class="cx">     bool stopped = false;
</span><span class="cx">     {
</span><span class="cx">         LockHolder locker(*m_threadLock);
</span><span class="cx">         stopped = m_thread-&gt;tryStop(locker);
</span><del>-        if (!stopped) {
-            m_threadShouldStop = true;
</del><ins>+        m_threadShouldStop = true;
+        if (!stopped)
</ins><span class="cx">             m_threadCondition-&gt;notifyOne(locker);
</span><del>-        }
</del><span class="cx">     }
</span><del>-    if (!stopped) {
-        waitForCollector(
-            [&amp;] (const LockHolder&amp;) -&gt; bool {
-                return m_threadIsStopping;
-            });
-        // It's now safe to join the thread, since we know that there will not be any more collections.
</del><ins>+
+    if (Options::logGC())
+        dataLog(&quot;4&quot;);
+    
+    if (!stopped)
</ins><span class="cx">         m_thread-&gt;join();
</span><del>-    }
</del><span class="cx">     
</span><ins>+    if (Options::logGC())
+        dataLog(&quot;5 &quot;);
+    
</ins><span class="cx">     m_arrayBuffers.lastChanceToFinalize();
</span><span class="cx">     m_codeBlocks-&gt;lastChanceToFinalize(*m_vm);
</span><span class="cx">     m_objectSpace.stopAllocating();
</span><span class="lines">@@ -372,6 +415,9 @@
</span><span class="cx">     releaseDelayedReleasedObjects();
</span><span class="cx"> 
</span><span class="cx">     sweepAllLogicallyEmptyWeakBlocks();
</span><ins>+    
+    if (Options::logGC())
+        dataLog((MonotonicTime::now() - before).milliseconds(), &quot;ms]\n&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::releaseDelayedReleasedObjects()
</span><span class="lines">@@ -525,186 +571,9 @@
</span><span class="cx">     RELEASE_ASSERT(ok);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::markToFixpoint(double gcStartTime)
-{
-    TimingScope markToFixpointTimingScope(*this, &quot;Heap::markToFixpoint&quot;);
-    
-    if (m_collectionScope == CollectionScope::Full) {
-        m_opaqueRoots.clear();
-        m_collectorSlotVisitor-&gt;clearMarkStacks();
-        m_mutatorMarkStack-&gt;clear();
-    }
-
-    RELEASE_ASSERT(m_raceMarkStack-&gt;isEmpty());
-
-    beginMarking();
-
-    forEachSlotVisitor(
-        [&amp;] (SlotVisitor&amp; visitor) {
-            visitor.didStartMarking();
-        });
-
-    m_parallelMarkersShouldExit = false;
-
-    m_helperClient.setFunction(
-        [this] () {
-            SlotVisitor* slotVisitor;
-            {
-                LockHolder locker(m_parallelSlotVisitorLock);
-                if (m_availableParallelSlotVisitors.isEmpty()) {
-                    std::unique_ptr&lt;SlotVisitor&gt; newVisitor =
-                        std::make_unique&lt;SlotVisitor&gt;(*this);
-                    
-                    if (Options::optimizeParallelSlotVisitorsForStoppedMutator())
-                        newVisitor-&gt;optimizeForStoppedMutator();
-                    
-                    newVisitor-&gt;didStartMarking();
-                    
-                    slotVisitor = newVisitor.get();
-                    m_parallelSlotVisitors.append(WTFMove(newVisitor));
-                } else
-                    slotVisitor = m_availableParallelSlotVisitors.takeLast();
-            }
-
-            WTF::registerGCThread(GCThreadType::Helper);
-
-            {
-                ParallelModeEnabler parallelModeEnabler(*slotVisitor);
-                slotVisitor-&gt;drainFromShared(SlotVisitor::SlaveDrain);
-            }
-
-            {
-                LockHolder locker(m_parallelSlotVisitorLock);
-                m_availableParallelSlotVisitors.append(slotVisitor);
-            }
-        });
-
-    SlotVisitor&amp; slotVisitor = *m_collectorSlotVisitor;
-
-    m_constraintSet-&gt;didStartMarking();
-    
-    m_scheduler-&gt;beginCollection();
-    if (Options::logGC())
-        m_scheduler-&gt;log();
-    
-    // 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.
-    
-    if (!slotVisitor.didReachTermination()) {
-        dataLog(&quot;Fatal: SlotVisitor should think that GC should terminate before constraint solving, but it does not think this.\n&quot;);
-        dataLog(&quot;slotVisitor.isEmpty(): &quot;, slotVisitor.isEmpty(), &quot;\n&quot;);
-        dataLog(&quot;slotVisitor.collectorMarkStack().isEmpty(): &quot;, slotVisitor.collectorMarkStack().isEmpty(), &quot;\n&quot;);
-        dataLog(&quot;slotVisitor.mutatorMarkStack().isEmpty(): &quot;, slotVisitor.mutatorMarkStack().isEmpty(), &quot;\n&quot;);
-        dataLog(&quot;m_numberOfActiveParallelMarkers: &quot;, m_numberOfActiveParallelMarkers, &quot;\n&quot;);
-        dataLog(&quot;m_sharedCollectorMarkStack-&gt;isEmpty(): &quot;, m_sharedCollectorMarkStack-&gt;isEmpty(), &quot;\n&quot;);
-        dataLog(&quot;m_sharedMutatorMarkStack-&gt;isEmpty(): &quot;, m_sharedMutatorMarkStack-&gt;isEmpty(), &quot;\n&quot;);
-        dataLog(&quot;slotVisitor.didReachTermination(): &quot;, slotVisitor.didReachTermination(), &quot;\n&quot;);
-        RELEASE_ASSERT_NOT_REACHED();
-    }
-    
-    for (;;) {
-        if (Options::logGC())
-            dataLog(&quot;v=&quot;, bytesVisited() / 1024, &quot;kb o=&quot;, m_opaqueRoots.size(), &quot; b=&quot;, m_barriersExecuted, &quot; &quot;);
-        
-        if (slotVisitor.didReachTermination()) {
-            m_scheduler-&gt;didReachTermination();
-            
-            assertSharedMarkStacksEmpty();
-            
-            slotVisitor.mergeIfNecessary();
-            for (auto&amp; parallelVisitor : m_parallelSlotVisitors)
-                parallelVisitor-&gt;mergeIfNecessary();
-            
-            // 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
-            
-            // 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
-            
-            // Wondering what this does? Look at Heap::addCoreConstraints(). The DOM and others can also
-            // add their own using Heap::addMarkingConstraint().
-            bool converged =
-                m_constraintSet-&gt;executeConvergence(slotVisitor, MonotonicTime::infinity());
-            if (converged &amp;&amp; slotVisitor.isEmpty()) {
-                assertSharedMarkStacksEmpty();
-                break;
-            }
-            
-            m_scheduler-&gt;didExecuteConstraints();
-        }
-        
-        if (Options::logGC())
-            dataLog(slotVisitor.collectorMarkStack().size(), &quot;+&quot;, m_mutatorMarkStack-&gt;size() + slotVisitor.mutatorMarkStack().size(), &quot; &quot;);
-        
-        {
-            ParallelModeEnabler enabler(slotVisitor);
-            slotVisitor.drainInParallel(m_scheduler-&gt;timeToResume());
-        }
-        
-        m_scheduler-&gt;synchronousDrainingDidStall();
-
-        if (slotVisitor.didReachTermination())
-            continue;
-        
-        if (!m_scheduler-&gt;shouldResume())
-            continue;
-        
-        m_scheduler-&gt;willResume();
-        
-        if (Options::logGC()) {
-            double thisPauseMS = (MonotonicTime::now() - m_stopTime).milliseconds();
-            dataLog(&quot;p=&quot;, thisPauseMS, &quot;ms (max &quot;, maxPauseMS(thisPauseMS), &quot;)...]\n&quot;);
-        }
-
-        // Forgive the mutator for its past failures to keep up.
-        // FIXME: Figure out if moving this to different places results in perf changes.
-        m_incrementBalance = 0;
-        
-        resumeTheWorld();
-        
-        {
-            ParallelModeEnabler enabler(slotVisitor);
-            slotVisitor.drainInParallelPassively(m_scheduler-&gt;timeToStop());
-        }
-
-        stopTheWorld();
-        
-        if (Options::logGC())
-            dataLog(&quot;[GC: &quot;);
-        
-        m_scheduler-&gt;didStop();
-        
-        if (Options::logGC())
-            m_scheduler-&gt;log();
-    }
-    
-    m_scheduler-&gt;endCollection();
-
-    {
-        std::lock_guard&lt;Lock&gt; lock(m_markingMutex);
-        m_parallelMarkersShouldExit = true;
-        m_markingConditionVariable.notifyAll();
-    }
-    m_helperClient.finish();
-
-    iterateExecutingAndCompilingCodeBlocks(
-        [&amp;] (CodeBlock* codeBlock) {
-            writeBarrier(codeBlock);
-        });
-        
-    updateObjectCounts(gcStartTime);
-    endMarking();
-}
-
</del><span class="cx"> void Heap::gatherStackRoots(ConservativeRoots&amp; roots)
</span><span class="cx"> {
</span><del>-    m_machineThreads.gatherConservativeRoots(roots, *m_jitStubRoutines, *m_codeBlocks);
</del><ins>+    m_machineThreads-&gt;gatherConservativeRoots(roots, *m_jitStubRoutines, *m_codeBlocks, m_currentThreadState);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::gatherJSStackRoots(ConservativeRoots&amp; roots)
</span><span class="lines">@@ -804,12 +673,8 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::updateObjectCounts(double gcStartTime)
</del><ins>+void Heap::updateObjectCounts()
</ins><span class="cx"> {
</span><del>-    if (Options::logGC() == GCLogging::Verbose) {
-        dataLogF(&quot;\nNumber of live Objects after GC %lu, took %.6f secs\n&quot;, static_cast&lt;unsigned long&gt;(visitCount()), WTF::monotonicallyIncreasingTime() - gcStartTime);
-    }
-    
</del><span class="cx">     if (m_collectionScope == CollectionScope::Full)
</span><span class="cx">         m_totalBytesVisited = 0;
</span><span class="cx"> 
</span><span class="lines">@@ -1033,7 +898,7 @@
</span><span class="cx"> {
</span><span class="cx">     double before = 0;
</span><span class="cx">     if (Options::logGC()) {
</span><del>-        dataLog(&quot;[Full sweep: &quot;, capacity() / 1024, &quot;kb &quot;);
</del><ins>+        dataLog(&quot;Full sweep: &quot;, capacity() / 1024, &quot;kb &quot;);
</ins><span class="cx">         before = currentTimeMS();
</span><span class="cx">     }
</span><span class="cx">     m_objectSpace.sweep();
</span><span class="lines">@@ -1040,7 +905,7 @@
</span><span class="cx">     m_objectSpace.shrink();
</span><span class="cx">     if (Options::logGC()) {
</span><span class="cx">         double after = currentTimeMS();
</span><del>-        dataLog(&quot;=&gt; &quot;, capacity() / 1024, &quot;kb, &quot;, after - before, &quot;ms] &quot;);
</del><ins>+        dataLog(&quot;=&gt; &quot;, capacity() / 1024, &quot;kb, &quot;, after - before, &quot;ms&quot;);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1053,13 +918,15 @@
</span><span class="cx"> 
</span><span class="cx">     DeferGCForAWhile deferGC(*this);
</span><span class="cx">     if (UNLIKELY(Options::useImmortalObjects()))
</span><del>-        sweeper()-&gt;willFinishSweeping();
</del><ins>+        sweeper()-&gt;stopSweeping();
</ins><span class="cx"> 
</span><span class="cx">     bool alreadySweptInCollectSync = Options::sweepSynchronously();
</span><span class="cx">     if (!alreadySweptInCollectSync) {
</span><ins>+        if (Options::logGC())
+            dataLog(&quot;[GC&lt;&quot;, RawPointer(this), &quot;&gt;: &quot;);
</ins><span class="cx">         sweepSynchronously();
</span><span class="cx">         if (Options::logGC())
</span><del>-            dataLog(&quot;\n&quot;);
</del><ins>+            dataLog(&quot;]\n&quot;);
</ins><span class="cx">     }
</span><span class="cx">     m_objectSpace.assertNoUnswept();
</span><span class="cx"> 
</span><span class="lines">@@ -1108,18 +975,109 @@
</span><span class="cx">     waitForCollection(requestCollection(scope));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool Heap::shouldCollectInThread(const LockHolder&amp;)
</del><ins>+bool Heap::shouldCollectInCollectorThread(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(m_requests.isEmpty() == (m_lastServedTicket == m_lastGrantedTicket));
</span><span class="cx">     RELEASE_ASSERT(m_lastServedTicket &lt;= m_lastGrantedTicket);
</span><span class="cx">     
</span><del>-    return !m_requests.isEmpty();
</del><ins>+    if (false)
+        dataLog(&quot;Mutator has the conn = &quot;, !!(m_worldState.load() &amp; mutatorHasConnBit), &quot;\n&quot;);
+    
+    return !m_requests.isEmpty() &amp;&amp; !(m_worldState.load() &amp; mutatorHasConnBit);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::collectInThread()
</del><ins>+void Heap::collectInCollectorThread()
</ins><span class="cx"> {
</span><ins>+    for (;;) {
+        RunCurrentPhaseResult result = runCurrentPhase(GCConductor::Collector, nullptr);
+        switch (result) {
+        case RunCurrentPhaseResult::Finished:
+            return;
+        case RunCurrentPhaseResult::Continue:
+            break;
+        case RunCurrentPhaseResult::NeedCurrentThreadState:
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+}
+
+void Heap::checkConn(GCConductor conn)
+{
+    switch (conn) {
+    case GCConductor::Mutator:
+        RELEASE_ASSERT(m_worldState.load() &amp; mutatorHasConnBit);
+        return;
+    case GCConductor::Collector:
+        RELEASE_ASSERT(!(m_worldState.load() &amp; mutatorHasConnBit));
+        return;
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+auto Heap::runCurrentPhase(GCConductor conn, CurrentThreadState* currentThreadState) -&gt; RunCurrentPhaseResult
+{
+    checkConn(conn);
+    m_currentThreadState = currentThreadState;
+    
+    // If the collector transfers the conn to the mutator, it leaves us in between phases.
+    if (!finishChangingPhase(conn)) {
+        // A mischevious mutator could repeatedly relinquish the conn back to us. We try to avoid doing
+        // this, but it's probably not the end of the world if it did happen.
+        if (false)
+            dataLog(&quot;Conn bounce-back.\n&quot;);
+        return RunCurrentPhaseResult::Finished;
+    }
+    
+    bool result = false;
+    switch (m_currentPhase) {
+    case CollectorPhase::NotRunning:
+        result = runNotRunningPhase(conn);
+        break;
+        
+    case CollectorPhase::Begin:
+        result = runBeginPhase(conn);
+        break;
+        
+    case CollectorPhase::Fixpoint:
+        if (!currentThreadState &amp;&amp; conn == GCConductor::Mutator)
+            return RunCurrentPhaseResult::NeedCurrentThreadState;
+        
+        result = runFixpointPhase(conn);
+        break;
+        
+    case CollectorPhase::Concurrent:
+        result = runConcurrentPhase(conn);
+        break;
+        
+    case CollectorPhase::Reloop:
+        result = runReloopPhase(conn);
+        break;
+        
+    case CollectorPhase::End:
+        result = runEndPhase(conn);
+        break;
+    }
+
+    return result ? RunCurrentPhaseResult::Continue : RunCurrentPhaseResult::Finished;
+}
+
+NEVER_INLINE bool Heap::runNotRunningPhase(GCConductor conn)
+{
+    // Check m_requests since the mutator calls this to poll what's going on.
+    {
+        auto locker = holdLock(*m_threadLock);
+        if (m_requests.isEmpty())
+            return false;
+    }
+    
+    return changePhase(conn, CollectorPhase::Begin);
+}
+
+NEVER_INLINE bool Heap::runBeginPhase(GCConductor conn)
+{
</ins><span class="cx">     m_currentGCStartTime = MonotonicTime::now();
</span><del>-    
</del><ins>+        
</ins><span class="cx">     std::optional&lt;CollectionScope&gt; scope;
</span><span class="cx">     {
</span><span class="cx">         LockHolder locker(*m_threadLock);
</span><span class="lines">@@ -1126,37 +1084,19 @@
</span><span class="cx">         RELEASE_ASSERT(!m_requests.isEmpty());
</span><span class="cx">         scope = m_requests.first();
</span><span class="cx">     }
</span><del>-    
-    SuperSamplerScope superSamplerScope(false);
-    TimingScope collectImplTimingScope(scope, &quot;Heap::collectInThread&quot;);
-    
-#if ENABLE(ALLOCATION_LOGGING)
-    dataLogF(&quot;JSC GC starting collection.\n&quot;);
-#endif
-    
-    stopTheWorld();
-    
-    if (false)
-        dataLog(&quot;GC START!\n&quot;);
</del><ins>+        
+    if (Options::logGC())
+        dataLog(&quot;[GC&lt;&quot;, RawPointer(this), &quot;&gt;: START &quot;, gcConductorShortName(conn), &quot; &quot;, capacity() / 1024, &quot;kb &quot;);
</ins><span class="cx"> 
</span><del>-    MonotonicTime before;
-    if (Options::logGC()) {
-        dataLog(&quot;[GC: START &quot;, capacity() / 1024, &quot;kb &quot;);
-        before = MonotonicTime::now();
-    }
-    
-    double gcStartTime;
-    
-    ASSERT(m_isSafeToCollect);
</del><ins>+    m_beforeGC = MonotonicTime::now();
+
</ins><span class="cx">     if (m_collectionScope) {
</span><span class="cx">         dataLog(&quot;Collection scope already set during GC: &quot;, *m_collectionScope, &quot;\n&quot;);
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><del>-    
</del><ins>+        
</ins><span class="cx">     willStartCollection(scope);
</span><del>-    collectImplTimingScope.setScope(*this);
-    
-    gcStartTime = WTF::monotonicallyIncreasingTime();
</del><ins>+        
</ins><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="cx">         // mutators before we begin this new GC cycle.
</span><span class="lines">@@ -1165,11 +1105,233 @@
</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><ins>+        
+    if (m_collectionScope == CollectionScope::Full) {
+        m_opaqueRoots.clear();
+        m_collectorSlotVisitor-&gt;clearMarkStacks();
+        m_mutatorMarkStack-&gt;clear();
+    }
+
+    RELEASE_ASSERT(m_raceMarkStack-&gt;isEmpty());
+
+    beginMarking();
+
+    forEachSlotVisitor(
+        [&amp;] (SlotVisitor&amp; visitor) {
+            visitor.didStartMarking();
+        });
+
+    m_parallelMarkersShouldExit = false;
+
+    m_helperClient.setFunction(
+        [this] () {
+            SlotVisitor* slotVisitor;
+            {
+                LockHolder locker(m_parallelSlotVisitorLock);
+                if (m_availableParallelSlotVisitors.isEmpty()) {
+                    std::unique_ptr&lt;SlotVisitor&gt; newVisitor = std::make_unique&lt;SlotVisitor&gt;(
+                        *this, toCString(&quot;P&quot;, m_parallelSlotVisitors.size() + 1));
+                    
+                    if (Options::optimizeParallelSlotVisitorsForStoppedMutator())
+                        newVisitor-&gt;optimizeForStoppedMutator();
+                    
+                    newVisitor-&gt;didStartMarking();
+                    
+                    slotVisitor = newVisitor.get();
+                    m_parallelSlotVisitors.append(WTFMove(newVisitor));
+                } else
+                    slotVisitor = m_availableParallelSlotVisitors.takeLast();
+            }
+
+            WTF::registerGCThread(GCThreadType::Helper);
+
+            {
+                ParallelModeEnabler parallelModeEnabler(*slotVisitor);
+                slotVisitor-&gt;drainFromShared(SlotVisitor::SlaveDrain);
+            }
+
+            {
+                LockHolder locker(m_parallelSlotVisitorLock);
+                m_availableParallelSlotVisitors.append(slotVisitor);
+            }
+        });
+
+    SlotVisitor&amp; slotVisitor = *m_collectorSlotVisitor;
+
+    m_constraintSet-&gt;didStartMarking();
</ins><span class="cx">     
</span><del>-    markToFixpoint(gcStartTime);
</del><ins>+    m_scheduler-&gt;beginCollection();
+    if (Options::logGC())
+        m_scheduler-&gt;log();
</ins><span class="cx">     
</span><ins>+    // 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.
+    
+    if (!slotVisitor.didReachTermination()) {
+        dataLog(&quot;Fatal: SlotVisitor should think that GC should terminate before constraint solving, but it does not think this.\n&quot;);
+        dataLog(&quot;slotVisitor.isEmpty(): &quot;, slotVisitor.isEmpty(), &quot;\n&quot;);
+        dataLog(&quot;slotVisitor.collectorMarkStack().isEmpty(): &quot;, slotVisitor.collectorMarkStack().isEmpty(), &quot;\n&quot;);
+        dataLog(&quot;slotVisitor.mutatorMarkStack().isEmpty(): &quot;, slotVisitor.mutatorMarkStack().isEmpty(), &quot;\n&quot;);
+        dataLog(&quot;m_numberOfActiveParallelMarkers: &quot;, m_numberOfActiveParallelMarkers, &quot;\n&quot;);
+        dataLog(&quot;m_sharedCollectorMarkStack-&gt;isEmpty(): &quot;, m_sharedCollectorMarkStack-&gt;isEmpty(), &quot;\n&quot;);
+        dataLog(&quot;m_sharedMutatorMarkStack-&gt;isEmpty(): &quot;, m_sharedMutatorMarkStack-&gt;isEmpty(), &quot;\n&quot;);
+        dataLog(&quot;slotVisitor.didReachTermination(): &quot;, slotVisitor.didReachTermination(), &quot;\n&quot;);
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+        
+    return changePhase(conn, CollectorPhase::Fixpoint);
+}
+
+NEVER_INLINE bool Heap::runFixpointPhase(GCConductor conn)
+{
+    RELEASE_ASSERT(conn == GCConductor::Collector || m_currentThreadState);
+    
+    SlotVisitor&amp; slotVisitor = *m_collectorSlotVisitor;
+    
+    if (Options::logGC()) {
+        HashMap&lt;const char*, size_t&gt; visitMap;
+        forEachSlotVisitor(
+            [&amp;] (SlotVisitor&amp; slotVisitor) {
+                visitMap.add(slotVisitor.codeName(), slotVisitor.bytesVisited() / 1024);
+            });
+        
+        auto perVisitorDump = sortedMapDump(
+            visitMap,
+            [] (const char* a, const char* b) -&gt; bool {
+                return strcmp(a, b) &lt; 0;
+            },
+            &quot;:&quot;, &quot; &quot;);
+        
+        dataLog(&quot;v=&quot;, bytesVisited() / 1024, &quot;kb (&quot;, perVisitorDump, &quot;) o=&quot;, m_opaqueRoots.size(), &quot; b=&quot;, m_barriersExecuted, &quot; &quot;);
+    }
+        
+    if (slotVisitor.didReachTermination()) {
+        m_scheduler-&gt;didReachTermination();
+            
+        assertSharedMarkStacksEmpty();
+            
+        slotVisitor.mergeIfNecessary();
+        for (auto&amp; parallelVisitor : m_parallelSlotVisitors)
+            parallelVisitor-&gt;mergeIfNecessary();
+            
+        // 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
+            
+        // 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
+            
+        // Wondering what this does? Look at Heap::addCoreConstraints(). The DOM and others can also
+        // add their own using Heap::addMarkingConstraint().
+        bool converged =
+            m_constraintSet-&gt;executeConvergence(slotVisitor, MonotonicTime::infinity());
+        if (converged &amp;&amp; slotVisitor.isEmpty()) {
+            assertSharedMarkStacksEmpty();
+            return changePhase(conn, CollectorPhase::End);
+        }
+            
+        m_scheduler-&gt;didExecuteConstraints();
+    }
+        
+    if (Options::logGC())
+        dataLog(slotVisitor.collectorMarkStack().size(), &quot;+&quot;, m_mutatorMarkStack-&gt;size() + slotVisitor.mutatorMarkStack().size(), &quot; &quot;);
+        
+    {
+        ParallelModeEnabler enabler(slotVisitor);
+        slotVisitor.drainInParallel(m_scheduler-&gt;timeToResume());
+    }
+        
+    m_scheduler-&gt;synchronousDrainingDidStall();
+
+    if (slotVisitor.didReachTermination())
+        return true; // This is like relooping to the top if runFixpointPhase().
+        
+    if (!m_scheduler-&gt;shouldResume())
+        return true;
+
+    m_scheduler-&gt;willResume();
+        
+    if (Options::logGC()) {
+        double thisPauseMS = (MonotonicTime::now() - m_stopTime).milliseconds();
+        dataLog(&quot;p=&quot;, thisPauseMS, &quot;ms (max &quot;, maxPauseMS(thisPauseMS), &quot;)...]\n&quot;);
+    }
+
+    // Forgive the mutator for its past failures to keep up.
+    // FIXME: Figure out if moving this to different places results in perf changes.
+    m_incrementBalance = 0;
+        
+    return changePhase(conn, CollectorPhase::Concurrent);
+}
+
+NEVER_INLINE bool Heap::runConcurrentPhase(GCConductor conn)
+{
+    SlotVisitor&amp; slotVisitor = *m_collectorSlotVisitor;
+
+    switch (conn) {
+    case GCConductor::Mutator: {
+        // When the mutator has the conn, we poll runConcurrentPhase() on every time someone says
+        // stopIfNecessary(), so on every allocation slow path. When that happens we poll if it's time
+        // to stop and do some work.
+        if (slotVisitor.didReachTermination()
+            || m_scheduler-&gt;shouldStop())
+            return changePhase(conn, CollectorPhase::Reloop);
+        
+        // We could be coming from a collector phase that stuffed our SlotVisitor, so make sure we donate
+        // everything. This is super cheap if the SlotVisitor is already empty.
+        slotVisitor.donateAll();
+        return false;
+    }
+    case GCConductor::Collector: {
+        {
+            ParallelModeEnabler enabler(slotVisitor);
+            slotVisitor.drainInParallelPassively(m_scheduler-&gt;timeToStop());
+        }
+        return changePhase(conn, CollectorPhase::Reloop);
+    } }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+    return false;
+}
+
+NEVER_INLINE bool Heap::runReloopPhase(GCConductor conn)
+{
+    if (Options::logGC())
+        dataLog(&quot;[GC&lt;&quot;, RawPointer(this), &quot;&gt;: &quot;, gcConductorShortName(conn), &quot; &quot;);
+    
+    m_scheduler-&gt;didStop();
+    
+    if (Options::logGC())
+        m_scheduler-&gt;log();
+    
+    return changePhase(conn, CollectorPhase::Fixpoint);
+}
+
+NEVER_INLINE bool Heap::runEndPhase(GCConductor conn)
+{
+    m_scheduler-&gt;endCollection();
+        
+    {
+        auto locker = holdLock(m_markingMutex);
+        m_parallelMarkersShouldExit = true;
+        m_markingConditionVariable.notifyAll();
+    }
+    m_helperClient.finish();
+    
+    iterateExecutingAndCompilingCodeBlocks(
+        [&amp;] (CodeBlock* codeBlock) {
+            writeBarrier(codeBlock);
+        });
+        
+    updateObjectCounts();
+    endMarking();
+        
</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">@@ -1195,7 +1357,7 @@
</span><span class="cx">     m_objectSpace.prepareForAllocation();
</span><span class="cx">     updateAllocationLimits();
</span><span class="cx"> 
</span><del>-    didFinishCollection(gcStartTime);
</del><ins>+    didFinishCollection();
</ins><span class="cx">     
</span><span class="cx">     if (m_verifier) {
</span><span class="cx">         m_verifier-&gt;trimDeadObjects();
</span><span class="lines">@@ -1208,13 +1370,12 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (Options::logGC()) {
</span><del>-        MonotonicTime after = MonotonicTime::now();
-        double thisPauseMS = (after - m_stopTime).milliseconds();
-        dataLog(&quot;p=&quot;, thisPauseMS, &quot;ms (max &quot;, maxPauseMS(thisPauseMS), &quot;), cycle &quot;, (after - before).milliseconds(), &quot;ms END]\n&quot;);
</del><ins>+        double thisPauseMS = (m_afterGC - m_stopTime).milliseconds();
+        dataLog(&quot;p=&quot;, thisPauseMS, &quot;ms (max &quot;, maxPauseMS(thisPauseMS), &quot;), cycle &quot;, (m_afterGC - m_beforeGC).milliseconds(), &quot;ms END]\n&quot;);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     {
</span><del>-        LockHolder locker(*m_threadLock);
</del><ins>+        auto locker = holdLock(*m_threadLock);
</ins><span class="cx">         m_requests.removeFirst();
</span><span class="cx">         m_lastServedTicket++;
</span><span class="cx">         clearMutatorWaiting();
</span><span class="lines">@@ -1225,23 +1386,79 @@
</span><span class="cx">         dataLog(&quot;GC END!\n&quot;);
</span><span class="cx"> 
</span><span class="cx">     setNeedFinalize();
</span><del>-    resumeTheWorld();
-    
</del><ins>+
</ins><span class="cx">     m_lastGCStartTime = m_currentGCStartTime;
</span><span class="cx">     m_lastGCEndTime = MonotonicTime::now();
</span><ins>+        
+    return changePhase(conn, CollectorPhase::NotRunning);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::stopTheWorld()
</del><ins>+bool Heap::changePhase(GCConductor conn, CollectorPhase nextPhase)
</ins><span class="cx"> {
</span><del>-    RELEASE_ASSERT(!m_collectorBelievesThatTheWorldIsStopped);
-    waitWhileNeedFinalize();
-    stopTheMutator();
</del><ins>+    checkConn(conn);
+
+    m_nextPhase = nextPhase;
+
+    return finishChangingPhase(conn);
+}
+
+NEVER_INLINE bool Heap::finishChangingPhase(GCConductor conn)
+{
+    checkConn(conn);
</ins><span class="cx">     
</span><ins>+    if (m_nextPhase == m_currentPhase)
+        return true;
+
+    if (false)
+        dataLog(conn, &quot;: Going to phase: &quot;, m_nextPhase, &quot; (from &quot;, m_currentPhase, &quot;)\n&quot;);
+    
+    bool suspendedBefore = worldShouldBeSuspended(m_currentPhase);
+    bool suspendedAfter = worldShouldBeSuspended(m_nextPhase);
+    
+    if (suspendedBefore != suspendedAfter) {
+        if (suspendedBefore) {
+            RELEASE_ASSERT(!suspendedAfter);
+            
+            resumeThePeriphery();
+            if (conn == GCConductor::Collector)
+                resumeTheMutator();
+            else
+                handleNeedFinalize();
+        } else {
+            RELEASE_ASSERT(!suspendedBefore);
+            RELEASE_ASSERT(suspendedAfter);
+            
+            if (conn == GCConductor::Collector) {
+                waitWhileNeedFinalize();
+                if (!stopTheMutator()) {
+                    if (false)
+                        dataLog(&quot;Returning false.\n&quot;);
+                    return false;
+                }
+            } else {
+                sanitizeStackForVM(m_vm);
+                handleNeedFinalize();
+            }
+            stopThePeriphery(conn);
+        }
+    }
+    
+    m_currentPhase = m_nextPhase;
+    return true;
+}
+
+void Heap::stopThePeriphery(GCConductor conn)
+{
+    if (m_collectorBelievesThatTheWorldIsStopped) {
+        dataLog(&quot;FATAL: world already stopped.\n&quot;);
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    
</ins><span class="cx">     if (m_mutatorDidRun)
</span><span class="cx">         m_mutatorExecutionVersion++;
</span><span class="cx">     
</span><span class="cx">     m_mutatorDidRun = false;
</span><del>-    
</del><ins>+
</ins><span class="cx">     suspendCompilerThreads();
</span><span class="cx">     m_collectorBelievesThatTheWorldIsStopped = true;
</span><span class="cx"> 
</span><span class="lines">@@ -1253,7 +1470,8 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx">     {
</span><span class="cx">         DeferGCForAWhile awhile(*this);
</span><del>-        if (JITWorklist::instance()-&gt;completeAllForVM(*m_vm))
</del><ins>+        if (JITWorklist::instance()-&gt;completeAllForVM(*m_vm)
+            &amp;&amp; conn == GCConductor::Collector)
</ins><span class="cx">             setGCDidJIT();
</span><span class="cx">     }
</span><span class="cx"> #endif // ENABLE(JIT)
</span><span class="lines">@@ -1266,7 +1484,7 @@
</span><span class="cx">     m_stopTime = MonotonicTime::now();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::resumeTheWorld()
</del><ins>+NEVER_INLINE void Heap::resumeThePeriphery()
</ins><span class="cx"> {
</span><span class="cx">     // Calling resumeAllocating does the Right Thing depending on whether this is the end of a
</span><span class="cx">     // collection cycle or this is just a concurrent phase within a collection cycle:
</span><span class="lines">@@ -1277,7 +1495,10 @@
</span><span class="cx">     
</span><span class="cx">     m_barriersExecuted = 0;
</span><span class="cx">     
</span><del>-    RELEASE_ASSERT(m_collectorBelievesThatTheWorldIsStopped);
</del><ins>+    if (!m_collectorBelievesThatTheWorldIsStopped) {
+        dataLog(&quot;Fatal: collector does not believe that the world is stopped.\n&quot;);
+        RELEASE_ASSERT_NOT_REACHED();
+    }
</ins><span class="cx">     m_collectorBelievesThatTheWorldIsStopped = false;
</span><span class="cx">     
</span><span class="cx">     // FIXME: This could be vastly improved: we want to grab the locks in the order in which they
</span><span class="lines">@@ -1315,59 +1536,72 @@
</span><span class="cx">         slotVisitor-&gt;updateMutatorIsStopped();
</span><span class="cx">     
</span><span class="cx">     resumeCompilerThreads();
</span><del>-    resumeTheMutator();
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::stopTheMutator()
</del><ins>+bool Heap::stopTheMutator()
</ins><span class="cx"> {
</span><span class="cx">     for (;;) {
</span><span class="cx">         unsigned oldState = m_worldState.load();
</span><del>-        if ((oldState &amp; stoppedBit)
-            &amp;&amp; (oldState &amp; shouldStopBit))
-            return;
</del><ins>+        if (oldState &amp; stoppedBit) {
+            RELEASE_ASSERT(!(oldState &amp; hasAccessBit));
+            RELEASE_ASSERT(!(oldState &amp; mutatorWaitingBit));
+            RELEASE_ASSERT(!(oldState &amp; mutatorHasConnBit));
+            return true;
+        }
</ins><span class="cx">         
</span><del>-        // Note: We could just have the mutator stop in-place like we do when !hasAccessBit. We could
-        // switch to that if it turned out to be less confusing, but then it would not give the
-        // mutator the opportunity to react to the world being stopped.
-        if (oldState &amp; mutatorWaitingBit) {
-            if (m_worldState.compareExchangeWeak(oldState, oldState &amp; ~mutatorWaitingBit))
-                ParkingLot::unparkAll(&amp;m_worldState);
-            continue;
</del><ins>+        if (oldState &amp; mutatorHasConnBit) {
+            RELEASE_ASSERT(!(oldState &amp; hasAccessBit));
+            RELEASE_ASSERT(!(oldState &amp; stoppedBit));
+            return false;
</ins><span class="cx">         }
</span><del>-        
-        if (!(oldState &amp; hasAccessBit)
-            || (oldState &amp; stoppedBit)) {
</del><ins>+
+        if (!(oldState &amp; hasAccessBit)) {
+            RELEASE_ASSERT(!(oldState &amp; mutatorHasConnBit));
+            RELEASE_ASSERT(!(oldState &amp; mutatorWaitingBit));
</ins><span class="cx">             // We can stop the world instantly.
</span><del>-            if (m_worldState.compareExchangeWeak(oldState, oldState | stoppedBit | shouldStopBit))
-                return;
</del><ins>+            if (m_worldState.compareExchangeWeak(oldState, oldState | stoppedBit))
+                return true;
</ins><span class="cx">             continue;
</span><span class="cx">         }
</span><span class="cx">         
</span><ins>+        // Transfer the conn to the mutator and bail.
</ins><span class="cx">         RELEASE_ASSERT(oldState &amp; hasAccessBit);
</span><span class="cx">         RELEASE_ASSERT(!(oldState &amp; stoppedBit));
</span><del>-        m_worldState.compareExchangeStrong(oldState, oldState | shouldStopBit);
-        m_stopIfNecessaryTimer-&gt;scheduleSoon();
-        ParkingLot::compareAndPark(&amp;m_worldState, oldState | shouldStopBit);
</del><ins>+        unsigned newState = (oldState | mutatorHasConnBit) &amp; ~mutatorWaitingBit;
+        if (m_worldState.compareExchangeWeak(oldState, newState)) {
+            if (false)
+                dataLog(&quot;Handed off the conn.\n&quot;);
+            m_stopIfNecessaryTimer-&gt;scheduleSoon();
+            ParkingLot::unparkAll(&amp;m_worldState);
+            return false;
+        }
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::resumeTheMutator()
</del><ins>+NEVER_INLINE void Heap::resumeTheMutator()
</ins><span class="cx"> {
</span><ins>+    if (false)
+        dataLog(&quot;Resuming the mutator.\n&quot;);
</ins><span class="cx">     for (;;) {
</span><span class="cx">         unsigned oldState = m_worldState.load();
</span><del>-        RELEASE_ASSERT(oldState &amp; shouldStopBit);
</del><ins>+        if (!!(oldState &amp; hasAccessBit) != !(oldState &amp; stoppedBit)) {
+            dataLog(&quot;Fatal: hasAccess = &quot;, !!(oldState &amp; hasAccessBit), &quot;, stopped = &quot;, !!(oldState &amp; stoppedBit), &quot;\n&quot;);
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        if (oldState &amp; mutatorHasConnBit) {
+            dataLog(&quot;Fatal: mutator has the conn.\n&quot;);
+            RELEASE_ASSERT_NOT_REACHED();
+        }
</ins><span class="cx">         
</span><del>-        if (!(oldState &amp; hasAccessBit)) {
-            // We can resume the world instantly.
-            if (m_worldState.compareExchangeWeak(oldState, oldState &amp; ~(stoppedBit | shouldStopBit))) {
-                ParkingLot::unparkAll(&amp;m_worldState);
-                return;
-            }
-            continue;
</del><ins>+        if (!(oldState &amp; stoppedBit)) {
+            if (false)
+                dataLog(&quot;Returning because not stopped.\n&quot;);
+            return;
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        // We can tell the world to resume.
-        if (m_worldState.compareExchangeWeak(oldState, oldState &amp; ~shouldStopBit)) {
</del><ins>+        if (m_worldState.compareExchangeWeak(oldState, oldState &amp; ~stoppedBit)) {
+            if (false)
+                dataLog(&quot;CASing and returning.\n&quot;);
</ins><span class="cx">             ParkingLot::unparkAll(&amp;m_worldState);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="lines">@@ -1389,30 +1623,54 @@
</span><span class="cx"> bool Heap::stopIfNecessarySlow(unsigned oldState)
</span><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(oldState &amp; hasAccessBit);
</span><ins>+    RELEASE_ASSERT(!(oldState &amp; stoppedBit));
</ins><span class="cx">     
</span><span class="cx">     // It's possible for us to wake up with finalization already requested but the world not yet
</span><span class="cx">     // resumed. If that happens, we can't run finalization yet.
</span><del>-    if (!(oldState &amp; stoppedBit)
-        &amp;&amp; handleNeedFinalize(oldState))
</del><ins>+    if (handleNeedFinalize(oldState))
</ins><span class="cx">         return true;
</span><ins>+
+    // FIXME: When entering the concurrent phase, we could arrange for this branch not to fire, and then
+    // have the SlotVisitor do things to the m_worldState to make this branch fire again. That would
+    // prevent us from polling this so much. Ideally, stopIfNecessary would ignore the mutatorHasConnBit
+    // and there would be some other bit indicating whether we were in some GC phase other than the
+    // NotRunning or Concurrent ones.
+    if (oldState &amp; mutatorHasConnBit)
+        collectInMutatorThread();
</ins><span class="cx">     
</span><del>-    if (!(oldState &amp; shouldStopBit) &amp;&amp; !m_scheduler-&gt;shouldStop()) {
-        if (!(oldState &amp; stoppedBit))
-            return false;
-        m_worldState.compareExchangeStrong(oldState, oldState &amp; ~stoppedBit);
-        return true;
-    }
-    
-    sanitizeStackForVM(m_vm);
</del><ins>+    return false;
+}
</ins><span class="cx"> 
</span><del>-    if (verboseStop) {
-        dataLog(&quot;Stopping!\n&quot;);
-        WTFReportBacktrace();
</del><ins>+NEVER_INLINE void Heap::collectInMutatorThread()
+{
+    CollectingScope collectingScope(*this);
+    for (;;) {
+        RunCurrentPhaseResult result = runCurrentPhase(GCConductor::Mutator, nullptr);
+        switch (result) {
+        case RunCurrentPhaseResult::Finished:
+            return;
+        case RunCurrentPhaseResult::Continue:
+            break;
+        case RunCurrentPhaseResult::NeedCurrentThreadState:
+            sanitizeStackForVM(m_vm);
+            auto lambda = [&amp;] (CurrentThreadState&amp; state) {
+                for (;;) {
+                    RunCurrentPhaseResult result = runCurrentPhase(GCConductor::Mutator, &amp;state);
+                    switch (result) {
+                    case RunCurrentPhaseResult::Finished:
+                        return;
+                    case RunCurrentPhaseResult::Continue:
+                        break;
+                    case RunCurrentPhaseResult::NeedCurrentThreadState:
+                        RELEASE_ASSERT_NOT_REACHED();
+                        break;
+                    }
+                }
+            };
+            callWithCurrentThreadState(scopedLambda&lt;void(CurrentThreadState&amp;)&gt;(WTFMove(lambda)));
+            return;
+        }
</ins><span class="cx">     }
</span><del>-    m_worldState.compareExchangeStrong(oldState, oldState | stoppedBit);
-    ParkingLot::unparkAll(&amp;m_worldState);
-    ParkingLot::compareAndPark(&amp;m_worldState, oldState | stoppedBit);
-    return true;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Func&gt;
</span><span class="lines">@@ -1425,6 +1683,7 @@
</span><span class="cx">             done = func(locker);
</span><span class="cx">             if (!done) {
</span><span class="cx">                 setMutatorWaiting();
</span><ins>+                
</ins><span class="cx">                 // At this point, the collector knows that we intend to wait, and he will clear the
</span><span class="cx">                 // waiting bit and then unparkAll when the GC cycle finishes. Clearing the bit
</span><span class="cx">                 // prevents us from parking except if there is also stop-the-world. Unparking after
</span><span class="lines">@@ -1431,12 +1690,16 @@
</span><span class="cx">                 // clearing means that if the clearing happens after we park, then we will unpark.
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-
</del><ins>+        
</ins><span class="cx">         // If we're in a stop-the-world scenario, we need to wait for that even if done is true.
</span><span class="cx">         unsigned oldState = m_worldState.load();
</span><span class="cx">         if (stopIfNecessarySlow(oldState))
</span><span class="cx">             continue;
</span><span class="cx">         
</span><ins>+        // FIXME: We wouldn't need this if stopIfNecessarySlow() had a mode where it knew to just
+        // do the collection.
+        relinquishConn();
+        
</ins><span class="cx">         if (done) {
</span><span class="cx">             clearMutatorWaiting(); // Clean up just in case.
</span><span class="cx">             return;
</span><span class="lines">@@ -1453,8 +1716,7 @@
</span><span class="cx">         unsigned oldState = m_worldState.load();
</span><span class="cx">         RELEASE_ASSERT(!(oldState &amp; hasAccessBit));
</span><span class="cx">         
</span><del>-        if (oldState &amp; shouldStopBit) {
-            RELEASE_ASSERT(oldState &amp; stoppedBit);
</del><ins>+        if (oldState &amp; stoppedBit) {
</ins><span class="cx">             if (verboseStop) {
</span><span class="cx">                 dataLog(&quot;Stopping in acquireAccess!\n&quot;);
</span><span class="cx">                 WTFReportBacktrace();
</span><span class="lines">@@ -1470,6 +1732,7 @@
</span><span class="cx">             handleGCDidJIT();
</span><span class="cx">             handleNeedFinalize();
</span><span class="cx">             m_mutatorDidRun = true;
</span><ins>+            stopIfNecessary();
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1479,28 +1742,73 @@
</span><span class="cx"> {
</span><span class="cx">     for (;;) {
</span><span class="cx">         unsigned oldState = m_worldState.load();
</span><del>-        RELEASE_ASSERT(oldState &amp; hasAccessBit);
-        RELEASE_ASSERT(!(oldState &amp; stoppedBit));
</del><ins>+        if (!(oldState &amp; hasAccessBit)) {
+            dataLog(&quot;FATAL: Attempting to release access but the mutator does not have access.\n&quot;);
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+        if (oldState &amp; stoppedBit) {
+            dataLog(&quot;FATAL: Attempting to release access but the mutator is stopped.\n&quot;);
+            RELEASE_ASSERT_NOT_REACHED();
+        }
</ins><span class="cx">         
</span><span class="cx">         if (handleNeedFinalize(oldState))
</span><span class="cx">             continue;
</span><span class="cx">         
</span><del>-        if (oldState &amp; shouldStopBit) {
-            unsigned newState = (oldState &amp; ~hasAccessBit) | stoppedBit;
-            if (m_worldState.compareExchangeWeak(oldState, newState)) {
-                ParkingLot::unparkAll(&amp;m_worldState);
-                return;
-            }
-            continue;
</del><ins>+        unsigned newState = oldState &amp; ~(hasAccessBit | mutatorHasConnBit);
+        
+        if ((oldState &amp; mutatorHasConnBit)
+            &amp;&amp; m_nextPhase != m_currentPhase) {
+            // This means that the collector thread had given us the conn so that we would do something
+            // for it. Stop ourselves as we release access. This ensures that acquireAccess blocks. In
+            // the meantime, since we're handing the conn over, the collector will be awoken and it is
+            // sure to have work to do.
+            newState |= stoppedBit;
</ins><span class="cx">         }
</span><del>-        
-        RELEASE_ASSERT(!(oldState &amp; shouldStopBit));
-        
-        if (m_worldState.compareExchangeWeak(oldState, oldState &amp; ~hasAccessBit))
</del><ins>+
+        if (m_worldState.compareExchangeWeak(oldState, newState)) {
+            if (oldState &amp; mutatorHasConnBit)
+                finishRelinquishingConn();
</ins><span class="cx">             return;
</span><ins>+        }
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Heap::relinquishConn(unsigned oldState)
+{
+    RELEASE_ASSERT(oldState &amp; hasAccessBit);
+    RELEASE_ASSERT(!(oldState &amp; stoppedBit));
+    
+    if (!(oldState &amp; mutatorHasConnBit))
+        return false; // Done.
+    
+    if (m_threadShouldStop)
+        return false;
+    
+    if (!m_worldState.compareExchangeWeak(oldState, oldState &amp; ~mutatorHasConnBit))
+        return true; // Loop around.
+    
+    finishRelinquishingConn();
+    return true;
+}
+
+void Heap::finishRelinquishingConn()
+{
+    if (false)
+        dataLog(&quot;Relinquished the conn.\n&quot;);
+    
+    sanitizeStackForVM(m_vm);
+    
+    auto locker = holdLock(*m_threadLock);
+    if (!m_requests.isEmpty())
+        m_threadCondition-&gt;notifyOne(locker);
+    ParkingLot::unparkAll(&amp;m_worldState);
+}
+
+void Heap::relinquishConn()
+{
+    while (relinquishConn(m_worldState.load())) { }
+}
+
</ins><span class="cx"> bool Heap::handleGCDidJIT(unsigned oldState)
</span><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(oldState &amp; hasAccessBit);
</span><span class="lines">@@ -1513,7 +1821,7 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool Heap::handleNeedFinalize(unsigned oldState)
</del><ins>+NEVER_INLINE bool Heap::handleNeedFinalize(unsigned oldState)
</ins><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(oldState &amp; hasAccessBit);
</span><span class="cx">     RELEASE_ASSERT(!(oldState &amp; stoppedBit));
</span><span class="lines">@@ -1580,7 +1888,7 @@
</span><span class="cx">     m_worldState.exchangeAnd(~mutatorWaitingBit);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::notifyThreadStopping(const LockHolder&amp;)
</del><ins>+void Heap::notifyThreadStopping(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     m_threadIsStopping = true;
</span><span class="cx">     clearMutatorWaiting();
</span><span class="lines">@@ -1592,11 +1900,11 @@
</span><span class="cx">     MonotonicTime before;
</span><span class="cx">     if (Options::logGC()) {
</span><span class="cx">         before = MonotonicTime::now();
</span><del>-        dataLog(&quot;[GC: finalize &quot;);
</del><ins>+        dataLog(&quot;[GC&lt;&quot;, RawPointer(this), &quot;&gt;: finalize &quot;);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     {
</span><del>-        HelpingGCScope helpingGCScope(*this);
</del><ins>+        SweepingScope helpingGCScope(*this);
</ins><span class="cx">         deleteUnmarkedCompiledCode();
</span><span class="cx">         deleteSourceProviderCaches();
</span><span class="cx">         sweepLargeAllocations();
</span><span class="lines">@@ -1604,7 +1912,7 @@
</span><span class="cx">     
</span><span class="cx">     if (HasOwnPropertyCache* cache = vm()-&gt;hasOwnPropertyCache())
</span><span class="cx">         cache-&gt;clear();
</span><del>-
</del><ins>+    
</ins><span class="cx">     if (Options::sweepSynchronously())
</span><span class="cx">         sweepSynchronously();
</span><span class="cx"> 
</span><span class="lines">@@ -1622,9 +1930,20 @@
</span><span class="cx">     RELEASE_ASSERT(vm()-&gt;atomicStringTable() == wtfThreadData().atomicStringTable());
</span><span class="cx">     
</span><span class="cx">     LockHolder locker(*m_threadLock);
</span><ins>+    // We may be able to steal the conn. That only works if the collector is definitely not running
+    // right now. This is an optimization that prevents the collector thread from ever starting in most
+    // cases.
+    ASSERT(m_lastServedTicket &lt;= m_lastGrantedTicket);
+    if (m_lastServedTicket == m_lastGrantedTicket) {
+        if (false)
+            dataLog(&quot;Taking the conn.\n&quot;);
+        m_worldState.exchangeOr(mutatorHasConnBit);
+    }
+    
</ins><span class="cx">     m_requests.append(scope);
</span><span class="cx">     m_lastGrantedTicket++;
</span><del>-    m_threadCondition-&gt;notifyOne(locker);
</del><ins>+    if (!(m_worldState.load() &amp; mutatorHasConnBit))
+        m_threadCondition-&gt;notifyOne(locker);
</ins><span class="cx">     return m_lastGrantedTicket;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1631,7 +1950,7 @@
</span><span class="cx"> void Heap::waitForCollection(Ticket ticket)
</span><span class="cx"> {
</span><span class="cx">     waitForCollector(
</span><del>-        [&amp;] (const LockHolder&amp;) -&gt; bool {
</del><ins>+        [&amp;] (const AbstractLocker&amp;) -&gt; bool {
</ins><span class="cx">             return m_lastServedTicket &gt;= ticket;
</span><span class="cx">         });
</span><span class="cx"> }
</span><span class="lines">@@ -1770,9 +2089,6 @@
</span><span class="cx">     if (verbose)
</span><span class="cx">         dataLog(&quot;extraMemorySize() = &quot;, extraMemorySize(), &quot;, currentHeapSize = &quot;, currentHeapSize, &quot;\n&quot;);
</span><span class="cx">     
</span><del>-    if (Options::gcMaxHeapSize() &amp;&amp; currentHeapSize &gt; Options::gcMaxHeapSize())
-        HeapStatistics::exitWithFailure();
-
</del><span class="cx">     if (m_collectionScope == CollectionScope::Full) {
</span><span class="cx">         // To avoid pathological GC churn in very small and very large heaps, we set
</span><span class="cx">         // the new allocation limit based on the current size of the heap, with a
</span><span class="lines">@@ -1825,25 +2141,19 @@
</span><span class="cx">         dataLog(&quot;=&gt; &quot;, currentHeapSize / 1024, &quot;kb, &quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::didFinishCollection(double gcStartTime)
</del><ins>+void Heap::didFinishCollection()
</ins><span class="cx"> {
</span><del>-    double gcEndTime = WTF::monotonicallyIncreasingTime();
</del><ins>+    m_afterGC = MonotonicTime::now();
</ins><span class="cx">     CollectionScope scope = *m_collectionScope;
</span><span class="cx">     if (scope == CollectionScope::Full)
</span><del>-        m_lastFullGCLength = gcEndTime - gcStartTime;
</del><ins>+        m_lastFullGCLength = m_afterGC - m_beforeGC;
</ins><span class="cx">     else
</span><del>-        m_lastEdenGCLength = gcEndTime - gcStartTime;
</del><ins>+        m_lastEdenGCLength = m_afterGC - m_beforeGC;
</ins><span class="cx"> 
</span><span class="cx"> #if ENABLE(RESOURCE_USAGE)
</span><span class="cx">     ASSERT(externalMemorySize() &lt;= extraMemorySize());
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    if (Options::recordGCPauseTimes())
-        HeapStatistics::recordGCPauseTime(gcStartTime, gcEndTime);
-
-    if (Options::dumpObjectStatistics())
-        HeapStatistics::dumpObjectStatistics(this);
-
</del><span class="cx">     if (HeapProfiler* heapProfiler = m_vm-&gt;heapProfiler()) {
</span><span class="cx">         gatherExtraHeapSnapshotData(*heapProfiler);
</span><span class="cx">         removeDeadHeapSnapshotNodes(*heapProfiler);
</span><span class="lines">@@ -2070,8 +2380,14 @@
</span><span class="cx"> 
</span><span class="cx">     if (!m_isSafeToCollect)
</span><span class="cx">         return;
</span><del>-    if (mutatorState() == MutatorState::HelpingGC)
</del><ins>+    switch (mutatorState()) {
+    case MutatorState::Running:
+    case MutatorState::Allocating:
+        break;
+    case MutatorState::Sweeping:
+    case MutatorState::Collecting:
</ins><span class="cx">         return;
</span><ins>+    }
</ins><span class="cx">     if (!Options::useGC())
</span><span class="cx">         return;
</span><span class="cx">     
</span><span class="lines">@@ -2080,11 +2396,8 @@
</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><del>-            // FIXME: Check if the scheduler wants us to stop.
-            // https://bugs.webkit.org/show_bug.cgi?id=166827
-        }
</del><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if (UNLIKELY(Options::gcMaxHeapSize())) {
</span><span class="lines">@@ -2099,8 +2412,10 @@
</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">         collectAsync();
</span><ins>+        stopIfNecessary(); // This will immediately start the collection if we have the conn.
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::decrementDeferralDepthAndGCIfNeededSlow()
</span><span class="lines">@@ -2303,6 +2618,12 @@
</span><span class="cx"> 
</span><span class="cx"> void Heap::notifyIsSafeToCollect()
</span><span class="cx"> {
</span><ins>+    MonotonicTime before;
+    if (Options::logGC()) {
+        before = MonotonicTime::now();
+        dataLog(&quot;[GC&lt;&quot;, RawPointer(this), &quot;&gt;: starting &quot;);
+    }
+    
</ins><span class="cx">     addCoreConstraints();
</span><span class="cx">     
</span><span class="cx">     m_isSafeToCollect = true;
</span><span class="lines">@@ -2337,6 +2658,9 @@
</span><span class="cx">                 }
</span><span class="cx">             });
</span><span class="cx">     }
</span><ins>+    
+    if (Options::logGC())
+        dataLog((MonotonicTime::now() - before).milliseconds(), &quot;ms]\n&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::preventCollection()
</span><span class="lines">@@ -2349,7 +2673,7 @@
</span><span class="cx">     
</span><span class="cx">     // Wait for all collections to finish.
</span><span class="cx">     waitForCollector(
</span><del>-        [&amp;] (const LockHolder&amp;) -&gt; bool {
</del><ins>+        [&amp;] (const AbstractLocker&amp;) -&gt; bool {
</ins><span class="cx">             ASSERT(m_lastServedTicket &lt;= m_lastGrantedTicket);
</span><span class="cx">             return m_lastServedTicket == m_lastGrantedTicket;
</span><span class="cx">         });
</span><span class="lines">@@ -2402,22 +2726,11 @@
</span><span class="cx">         return;
</span><span class="cx">     targetBytes = std::min(targetBytes, Options::gcIncrementMaxBytes());
</span><span class="cx"> 
</span><del>-    MonotonicTime before;
-    if (Options::logGC()) {
-        dataLog(&quot;[GC: increment t=&quot;, targetBytes / 1024, &quot;kb &quot;);
-        before = MonotonicTime::now();
-    }
-
</del><span class="cx">     SlotVisitor&amp; slotVisitor = *m_mutatorSlotVisitor;
</span><span class="cx">     ParallelModeEnabler parallelModeEnabler(slotVisitor);
</span><span class="cx">     size_t bytesVisited = slotVisitor.performIncrementOfDraining(static_cast&lt;size_t&gt;(targetBytes));
</span><span class="cx">     // incrementBalance may go negative here because it'll remember how many bytes we overshot.
</span><span class="cx">     m_incrementBalance -= bytesVisited;
</span><del>-
-    if (Options::logGC()) {
-        MonotonicTime after = MonotonicTime::now();
-        dataLog(&quot;p=&quot;, (after - before).milliseconds(), &quot;ms b=&quot;, m_incrementBalance / 1024, &quot;kb]\n&quot;);
-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/Heap.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -24,13 +24,14 @@
</span><span class="cx"> #include &quot;ArrayBuffer.h&quot;
</span><span class="cx"> #include &quot;CellState.h&quot;
</span><span class="cx"> #include &quot;CollectionScope.h&quot;
</span><ins>+#include &quot;CollectorPhase.h&quot;
</ins><span class="cx"> #include &quot;DeleteAllCodeEffort.h&quot;
</span><ins>+#include &quot;GCConductor.h&quot;
</ins><span class="cx"> #include &quot;GCIncomingRefCountedSet.h&quot;
</span><span class="cx"> #include &quot;HandleSet.h&quot;
</span><span class="cx"> #include &quot;HandleStack.h&quot;
</span><span class="cx"> #include &quot;HeapObserver.h&quot;
</span><span class="cx"> #include &quot;ListableHandler.h&quot;
</span><del>-#include &quot;MachineStackMarker.h&quot;
</del><span class="cx"> #include &quot;MarkedBlock.h&quot;
</span><span class="cx"> #include &quot;MarkedBlockSet.h&quot;
</span><span class="cx"> #include &quot;MarkedSpace.h&quot;
</span><span class="lines">@@ -53,6 +54,8 @@
</span><span class="cx"> 
</span><span class="cx"> class CodeBlock;
</span><span class="cx"> class CodeBlockSet;
</span><ins>+class CollectingScope;
+class ConservativeRoots;
</ins><span class="cx"> class GCDeferralContext;
</span><span class="cx"> class EdenGCActivityCallback;
</span><span class="cx"> class ExecutableBase;
</span><span class="lines">@@ -62,7 +65,6 @@
</span><span class="cx"> class Heap;
</span><span class="cx"> class HeapProfiler;
</span><span class="cx"> class HeapVerifier;
</span><del>-class HelpingGCScope;
</del><span class="cx"> class IncrementalSweeper;
</span><span class="cx"> class JITStubRoutine;
</span><span class="cx"> class JITStubRoutineSet;
</span><span class="lines">@@ -69,6 +71,7 @@
</span><span class="cx"> class JSCell;
</span><span class="cx"> class JSValue;
</span><span class="cx"> class LLIntOffsetsExtractor;
</span><ins>+class MachineThreads;
</ins><span class="cx"> class MarkStackArray;
</span><span class="cx"> class MarkedAllocator;
</span><span class="cx"> class MarkedArgumentBuffer;
</span><span class="lines">@@ -75,10 +78,13 @@
</span><span class="cx"> class MarkingConstraint;
</span><span class="cx"> class MarkingConstraintSet;
</span><span class="cx"> class MutatorScheduler;
</span><ins>+class RunningScope;
</ins><span class="cx"> class SlotVisitor;
</span><span class="cx"> class SpaceTimeMutatorScheduler;
</span><span class="cx"> class StopIfNecessaryTimer;
</span><ins>+class SweepingScope;
</ins><span class="cx"> class VM;
</span><ins>+struct CurrentThreadState;
</ins><span class="cx"> 
</span><span class="cx"> namespace DFG {
</span><span class="cx"> class SpeculativeJIT;
</span><span class="lines">@@ -131,7 +137,7 @@
</span><span class="cx">     VM* vm() const;
</span><span class="cx"> 
</span><span class="cx">     MarkedSpace&amp; objectSpace() { return m_objectSpace; }
</span><del>-    MachineThreads&amp; machineThreads() { return m_machineThreads; }
</del><ins>+    MachineThreads&amp; machineThreads() { return *m_machineThreads; }
</ins><span class="cx"> 
</span><span class="cx">     SlotVisitor&amp; collectorSlotVisitor() { return *m_collectorSlotVisitor; }
</span><span class="cx"> 
</span><span class="lines">@@ -147,7 +153,6 @@
</span><span class="cx">     MutatorState mutatorState() const { return m_mutatorState; }
</span><span class="cx">     std::optional&lt;CollectionScope&gt; collectionScope() const { return m_collectionScope; }
</span><span class="cx">     bool hasHeapAccess() const;
</span><del>-    bool mutatorIsStopped() const;
</del><span class="cx">     bool collectorBelievesThatTheWorldIsStopped() const;
</span><span class="cx"> 
</span><span class="cx">     // We're always busy on the collection threads. On the main thread, this returns true if we're
</span><span class="lines">@@ -229,9 +234,9 @@
</span><span class="cx">     void willStartIterating();
</span><span class="cx">     void didFinishIterating();
</span><span class="cx"> 
</span><del>-    double lastFullGCLength() const { return m_lastFullGCLength; }
-    double lastEdenGCLength() const { return m_lastEdenGCLength; }
-    void increaseLastFullGCLength(double amount) { m_lastFullGCLength += amount; }
</del><ins>+    Seconds lastFullGCLength() const { return m_lastFullGCLength; }
+    Seconds lastEdenGCLength() const { return m_lastEdenGCLength; }
+    void increaseLastFullGCLength(Seconds amount) { m_lastFullGCLength += amount; }
</ins><span class="cx"> 
</span><span class="cx">     size_t sizeBeforeLastEdenCollection() const { return m_sizeBeforeLastEdenCollect; }
</span><span class="cx">     size_t sizeAfterLastEdenCollection() const { return m_sizeAfterLastEdenCollect; }
</span><span class="lines">@@ -319,6 +324,9 @@
</span><span class="cx">     // already be called for you at the right times.
</span><span class="cx">     void stopIfNecessary();
</span><span class="cx">     
</span><ins>+    // This gives the conn to the collector.
+    void relinquishConn();
+    
</ins><span class="cx">     bool mayNeedToStop();
</span><span class="cx"> 
</span><span class="cx">     void performIncrement(size_t bytes);
</span><span class="lines">@@ -343,10 +351,11 @@
</span><span class="cx">     CFRunLoopRef runLoop() const { return m_runLoop.get(); }
</span><span class="cx">     JS_EXPORT_PRIVATE void setRunLoop(CFRunLoopRef);
</span><span class="cx"> #endif // USE(CF)
</span><del>-
</del><ins>+    
</ins><span class="cx"> private:
</span><span class="cx">     friend class AllocatingScope;
</span><span class="cx">     friend class CodeBlock;
</span><ins>+    friend class CollectingScope;
</ins><span class="cx">     friend class DeferGC;
</span><span class="cx">     friend class DeferGCForAWhile;
</span><span class="cx">     friend class GCAwareJITStubRoutine;
</span><span class="lines">@@ -355,15 +364,16 @@
</span><span class="cx">     friend class HandleSet;
</span><span class="cx">     friend class HeapUtil;
</span><span class="cx">     friend class HeapVerifier;
</span><del>-    friend class HelpingGCScope;
</del><span class="cx">     friend class JITStubRoutine;
</span><span class="cx">     friend class LLIntOffsetsExtractor;
</span><span class="cx">     friend class MarkedSpace;
</span><span class="cx">     friend class MarkedAllocator;
</span><span class="cx">     friend class MarkedBlock;
</span><ins>+    friend class RunningScope;
</ins><span class="cx">     friend class SlotVisitor;
</span><span class="cx">     friend class SpaceTimeMutatorScheduler;
</span><span class="cx">     friend class StochasticSpaceTimeMutatorScheduler;
</span><ins>+    friend class SweepingScope;
</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">@@ -382,13 +392,35 @@
</span><span class="cx">     JS_EXPORT_PRIVATE void reportExtraMemoryAllocatedSlowCase(size_t);
</span><span class="cx">     JS_EXPORT_PRIVATE void deprecatedReportExtraMemorySlowCase(size_t);
</span><span class="cx">     
</span><del>-    bool shouldCollectInThread(const LockHolder&amp;);
-    void collectInThread();
</del><ins>+    bool shouldCollectInCollectorThread(const AbstractLocker&amp;);
+    void collectInCollectorThread();
</ins><span class="cx">     
</span><del>-    void stopTheWorld();
-    void resumeTheWorld();
</del><ins>+    void checkConn(GCConductor);
+
+    enum class RunCurrentPhaseResult {
+        Finished,
+        Continue,
+        NeedCurrentThreadState
+    };
+    RunCurrentPhaseResult runCurrentPhase(GCConductor, CurrentThreadState*);
</ins><span class="cx">     
</span><del>-    void stopTheMutator();
</del><ins>+    // Returns true if we should keep doing things.
+    bool runNotRunningPhase(GCConductor);
+    bool runBeginPhase(GCConductor);
+    bool runFixpointPhase(GCConductor);
+    bool runConcurrentPhase(GCConductor);
+    bool runReloopPhase(GCConductor);
+    bool runEndPhase(GCConductor);
+    bool changePhase(GCConductor, CollectorPhase);
+    bool finishChangingPhase(GCConductor);
+    
+    void collectInMutatorThread();
+    
+    void stopThePeriphery(GCConductor);
+    void resumeThePeriphery();
+    
+    // Returns true if the mutator is stopped, false if the mutator has the conn now.
+    bool stopTheMutator();
</ins><span class="cx">     void resumeTheMutator();
</span><span class="cx">     
</span><span class="cx">     void stopIfNecessarySlow();
</span><span class="lines">@@ -401,10 +433,14 @@
</span><span class="cx">     JS_EXPORT_PRIVATE void releaseAccessSlow();
</span><span class="cx">     
</span><span class="cx">     bool handleGCDidJIT(unsigned);
</span><ins>+    void handleGCDidJIT();
+    
</ins><span class="cx">     bool handleNeedFinalize(unsigned);
</span><del>-    void handleGCDidJIT();
</del><span class="cx">     void handleNeedFinalize();
</span><span class="cx">     
</span><ins>+    bool relinquishConn(unsigned);
+    void finishRelinquishingConn();
+    
</ins><span class="cx">     void setGCDidJIT();
</span><span class="cx">     void setNeedFinalize();
</span><span class="cx">     void waitWhileNeedFinalize();
</span><span class="lines">@@ -411,7 +447,7 @@
</span><span class="cx">     
</span><span class="cx">     void setMutatorWaiting();
</span><span class="cx">     void clearMutatorWaiting();
</span><del>-    void notifyThreadStopping(const LockHolder&amp;);
</del><ins>+    void notifyThreadStopping(const AbstractLocker&amp;);
</ins><span class="cx">     
</span><span class="cx">     typedef uint64_t Ticket;
</span><span class="cx">     Ticket requestCollection(std::optional&lt;CollectionScope&gt;);
</span><span class="lines">@@ -421,7 +457,6 @@
</span><span class="cx">     void willStartCollection(std::optional&lt;CollectionScope&gt;);
</span><span class="cx">     void prepareForMarking();
</span><span class="cx">     
</span><del>-    void markToFixpoint(double gcStartTime);
</del><span class="cx">     void gatherStackRoots(ConservativeRoots&amp;);
</span><span class="cx">     void gatherJSStackRoots(ConservativeRoots&amp;);
</span><span class="cx">     void gatherScratchBufferRoots(ConservativeRoots&amp;);
</span><span class="lines">@@ -428,7 +463,7 @@
</span><span class="cx">     void beginMarking();
</span><span class="cx">     void visitCompilerWorklistWeakReferences();
</span><span class="cx">     void removeDeadCompilerWorklistEntries();
</span><del>-    void updateObjectCounts(double gcStartTime);
</del><ins>+    void updateObjectCounts();
</ins><span class="cx">     void endMarking();
</span><span class="cx"> 
</span><span class="cx">     void reapWeakHandles();
</span><span class="lines">@@ -443,7 +478,7 @@
</span><span class="cx">     void deleteUnmarkedCompiledCode();
</span><span class="cx">     JS_EXPORT_PRIVATE void addToRememberedSet(const JSCell*);
</span><span class="cx">     void updateAllocationLimits();
</span><del>-    void didFinishCollection(double gcStartTime);
</del><ins>+    void didFinishCollection();
</ins><span class="cx">     void resumeCompilerThreads();
</span><span class="cx">     void gatherExtraHeapSnapshotData(HeapProfiler&amp;);
</span><span class="cx">     void removeDeadHeapSnapshotNodes(HeapProfiler&amp;);
</span><span class="lines">@@ -510,7 +545,7 @@
</span><span class="cx">     ProtectCountSet m_protectedValues;
</span><span class="cx">     std::unique_ptr&lt;HashSet&lt;MarkedArgumentBuffer*&gt;&gt; m_markListSet;
</span><span class="cx"> 
</span><del>-    MachineThreads m_machineThreads;
</del><ins>+    std::unique_ptr&lt;MachineThreads&gt; m_machineThreads;
</ins><span class="cx">     
</span><span class="cx">     std::unique_ptr&lt;SlotVisitor&gt; m_collectorSlotVisitor;
</span><span class="cx">     std::unique_ptr&lt;SlotVisitor&gt; m_mutatorSlotVisitor;
</span><span class="lines">@@ -544,8 +579,8 @@
</span><span class="cx">     unsigned m_barrierThreshold { Options::forceFencedBarrier() ? tautologicalThreshold : blackThreshold };
</span><span class="cx"> 
</span><span class="cx">     VM* m_vm;
</span><del>-    double m_lastFullGCLength;
-    double m_lastEdenGCLength;
</del><ins>+    Seconds m_lastFullGCLength;
+    Seconds m_lastEdenGCLength;
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;ExecutableBase*&gt; m_executables;
</span><span class="cx"> 
</span><span class="lines">@@ -601,8 +636,8 @@
</span><span class="cx">     
</span><span class="cx">     std::unique_ptr&lt;MutatorScheduler&gt; m_scheduler;
</span><span class="cx">     
</span><del>-    static const unsigned shouldStopBit = 1u &lt;&lt; 0u;
-    static const unsigned stoppedBit = 1u &lt;&lt; 1u;
</del><ins>+    static const unsigned mutatorHasConnBit = 1u &lt;&lt; 0u; // Must also be protected by threadLock.
+    static const unsigned stoppedBit = 1u &lt;&lt; 1u; // Only set when !hasAccessBit
</ins><span class="cx">     static const unsigned hasAccessBit = 1u &lt;&lt; 2u;
</span><span class="cx">     static const unsigned gcDidJITBit = 1u &lt;&lt; 3u; // Set when the GC did some JITing, so on resume we need to cpuid.
</span><span class="cx">     static const unsigned needFinalizeBit = 1u &lt;&lt; 4u;
</span><span class="lines">@@ -609,11 +644,15 @@
</span><span class="cx">     static const unsigned mutatorWaitingBit = 1u &lt;&lt; 5u; // Allows the mutator to use this as a condition variable.
</span><span class="cx">     Atomic&lt;unsigned&gt; m_worldState;
</span><span class="cx">     bool m_collectorBelievesThatTheWorldIsStopped { false };
</span><ins>+    MonotonicTime m_beforeGC;
+    MonotonicTime m_afterGC;
</ins><span class="cx">     MonotonicTime m_stopTime;
</span><span class="cx">     
</span><span class="cx">     Deque&lt;std::optional&lt;CollectionScope&gt;&gt; m_requests;
</span><span class="cx">     Ticket m_lastServedTicket { 0 };
</span><span class="cx">     Ticket m_lastGrantedTicket { 0 };
</span><ins>+    CollectorPhase m_currentPhase { CollectorPhase::NotRunning };
+    CollectorPhase m_nextPhase { CollectorPhase::NotRunning };
</ins><span class="cx">     bool m_threadShouldStop { false };
</span><span class="cx">     bool m_threadIsStopping { false };
</span><span class="cx">     bool m_mutatorDidRun { true };
</span><span class="lines">@@ -632,6 +671,8 @@
</span><span class="cx">     MonotonicTime m_currentGCStartTime;
</span><span class="cx">     
</span><span class="cx">     uintptr_t m_barriersExecuted { 0 };
</span><ins>+    
+    CurrentThreadState* m_currentThreadState { nullptr };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapInlinesh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapInlines.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapInlines.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapInlines.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -61,24 +61,6 @@
</span><span class="cx">     return m_worldState.load() &amp; hasAccessBit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline bool Heap::mutatorIsStopped() const
-{
-    unsigned state = m_worldState.load();
-    bool shouldStop = state &amp; shouldStopBit;
-    bool stopped = state &amp; stoppedBit;
-    // I only got it right when I considered all four configurations of shouldStop/stopped:
-    // !shouldStop, !stopped: The GC has not requested that we stop and we aren't stopped, so we
-    //     should return false.
-    // !shouldStop, stopped: The mutator is still stopped but the GC is done and the GC has requested
-    //     that we resume, so we should return false.
-    // shouldStop, !stopped: The GC called stopTheWorld() but the mutator hasn't hit a safepoint yet.
-    //     The mutator should be able to do whatever it wants in this state, as if we were not
-    //     stopped. So return false.
-    // shouldStop, stopped: The GC requested stop the world and the mutator obliged. The world is
-    //     stopped, so return true.
-    return shouldStop &amp; stopped;
-}
-
</del><span class="cx"> inline bool Heap::collectorBelievesThatTheWorldIsStopped() const
</span><span class="cx"> {
</span><span class="cx">     return m_collectorBelievesThatTheWorldIsStopped;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapStatisticscpp"></a>
<div class="delfile"><h4>Deleted: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,251 +0,0 @@
</span><del>-/*
- * Copyright (C) 2012, 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. 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;HeapStatistics.h&quot;
-
-#include &quot;Heap.h&quot;
-#include &quot;HeapIterationScope.h&quot;
-#include &quot;JSCInlines.h&quot;
-#include &quot;JSObject.h&quot;
-#include &quot;MarkedSpaceInlines.h&quot;
-#include &quot;Options.h&quot;
-#include &lt;stdlib.h&gt;
-#include &lt;wtf/CurrentTime.h&gt;
-#include &lt;wtf/DataLog.h&gt;
-#include &lt;wtf/StdLibExtras.h&gt;
-
-#if OS(UNIX)
-#include &lt;sys/resource.h&gt;
-#endif
-
-namespace JSC {
-
-double HeapStatistics::s_startTime = 0.0;
-double HeapStatistics::s_endTime = 0.0;
-Vector&lt;double&gt;* HeapStatistics::s_pauseTimeStarts = 0;
-Vector&lt;double&gt;* HeapStatistics::s_pauseTimeEnds = 0;
-
-#if OS(UNIX) 
-
-void HeapStatistics::initialize()
-{
-    ASSERT(Options::recordGCPauseTimes());
-    s_startTime = WTF::monotonicallyIncreasingTime();
-    s_pauseTimeStarts = new Vector&lt;double&gt;();
-    s_pauseTimeEnds = new Vector&lt;double&gt;();
-}
-
-void HeapStatistics::recordGCPauseTime(double start, double end)
-{
-    ASSERT(Options::recordGCPauseTimes());
-    ASSERT(s_pauseTimeStarts);
-    ASSERT(s_pauseTimeEnds);
-    s_pauseTimeStarts-&gt;append(start);
-    s_pauseTimeEnds-&gt;append(end);
-}
-
-void HeapStatistics::logStatistics()
-{
-    struct rusage usage;
-    getrusage(RUSAGE_SELF, &amp;usage);
-#if USE(CF) || OS(UNIX)
-    char* vmName = getenv(&quot;JSVMName&quot;);
-    char* suiteName = getenv(&quot;JSSuiteName&quot;);
-    char* benchmarkName = getenv(&quot;JSBenchmarkName&quot;);
-#else
-#error &quot;The HeapStatistics module is not supported on this platform.&quot;
-#endif
-    if (!vmName || !suiteName || !benchmarkName)
-        dataLogF(&quot;HeapStatistics: {\&quot;max_rss\&quot;: %ld&quot;, usage.ru_maxrss);
-    else
-        dataLogF(&quot;HeapStatistics: {\&quot;max_rss\&quot;: %ld, \&quot;vm_name\&quot;: \&quot;%s\&quot;, \&quot;suite_name\&quot;: \&quot;%s\&quot;, \&quot;benchmark_name\&quot;: \&quot;%s\&quot;&quot;, 
-            usage.ru_maxrss, vmName, suiteName, benchmarkName); 
-
-    if (Options::recordGCPauseTimes()) {
-        dataLogF(&quot;, \&quot;pause_times\&quot;: [&quot;);
-        Vector&lt;double&gt;::iterator startIt = s_pauseTimeStarts-&gt;begin();
-        Vector&lt;double&gt;::iterator endIt = s_pauseTimeEnds-&gt;begin();
-        if (startIt != s_pauseTimeStarts-&gt;end() &amp;&amp; endIt != s_pauseTimeEnds-&gt;end()) {
-            dataLogF(&quot;[%f, %f]&quot;, *startIt, *endIt);
-            ++startIt;
-            ++endIt;
-        }
-        while (startIt != s_pauseTimeStarts-&gt;end() &amp;&amp; endIt != s_pauseTimeEnds-&gt;end()) {
-            dataLogF(&quot;, [%f, %f]&quot;, *startIt, *endIt);
-            ++startIt;
-            ++endIt;
-        }
-        dataLogF(&quot;], \&quot;start_time\&quot;: %f, \&quot;end_time\&quot;: %f&quot;, s_startTime, s_endTime);
-    }
-    dataLogF(&quot;}\n&quot;);
-}
-
-void HeapStatistics::exitWithFailure()
-{
-    ASSERT(Options::logHeapStatisticsAtExit());
-    s_endTime = WTF::monotonicallyIncreasingTime();
-    logStatistics();
-    exit(-1);
-}
-
-void HeapStatistics::reportSuccess()
-{
-    ASSERT(Options::logHeapStatisticsAtExit());
-    s_endTime = WTF::monotonicallyIncreasingTime();
-    logStatistics();
-}
-
-#else
-
-void HeapStatistics::initialize()
-{
-}
-
-void HeapStatistics::recordGCPauseTime(double, double)
-{
-}
-
-void HeapStatistics::logStatistics()
-{
-}
-
-void HeapStatistics::exitWithFailure()
-{
-    exit(-1);
-}
-
-void HeapStatistics::reportSuccess()
-{
-}
-
-#endif // OS(UNIX)
-
-class StorageStatistics : public MarkedBlock::VoidFunctor {
-public:
-    StorageStatistics();
-
-    IterationStatus operator()(HeapCell*, HeapCell::Kind) const;
-
-    size_t objectWithOutOfLineStorageCount();
-    size_t objectCount();
-
-    size_t storageSize();
-    size_t storageCapacity();
-
-private:
-    void visit(JSCell*);
-
-    size_t m_objectWithOutOfLineStorageCount;
-    size_t m_objectCount;
-    size_t m_storageSize;
-    size_t m_storageCapacity;
-};
-
-inline StorageStatistics::StorageStatistics()
-    : m_objectWithOutOfLineStorageCount(0)
-    , m_objectCount(0)
-    , m_storageSize(0)
-    , m_storageCapacity(0)
-{
-}
-
-inline void StorageStatistics::visit(JSCell* cell)
-{
-    if (!cell-&gt;isObject())
-        return;
-
-    JSObject* object = jsCast&lt;JSObject*&gt;(cell);
-    if (hasIndexedProperties(object-&gt;indexingType()))
-        return;
-
-    if (object-&gt;structure()-&gt;isUncacheableDictionary())
-        return;
-
-    ++m_objectCount;
-    if (!object-&gt;hasInlineStorage())
-        ++m_objectWithOutOfLineStorageCount;
-    m_storageSize += object-&gt;structure()-&gt;totalStorageSize() * sizeof(WriteBarrierBase&lt;Unknown&gt;);
-    m_storageCapacity += object-&gt;structure()-&gt;totalStorageCapacity() * sizeof(WriteBarrierBase&lt;Unknown&gt;); 
-}
-
-inline IterationStatus StorageStatistics::operator()(HeapCell* cell, HeapCell::Kind kind) const
-{
-    if (kind == HeapCell::JSCell) {
-        // FIXME: This const_cast exists because this isn't a C++ lambda.
-        // https://bugs.webkit.org/show_bug.cgi?id=159644
-        const_cast&lt;StorageStatistics*&gt;(this)-&gt;visit(static_cast&lt;JSCell*&gt;(cell));
-    }
-    return IterationStatus::Continue;
-}
-
-inline size_t StorageStatistics::objectWithOutOfLineStorageCount()
-{
-    return m_objectWithOutOfLineStorageCount;
-}
-
-inline size_t StorageStatistics::objectCount()
-{
-    return m_objectCount;
-}
-
-inline size_t StorageStatistics::storageSize()
-{
-    return m_storageSize;
-}
-
-inline size_t StorageStatistics::storageCapacity()
-{
-    return m_storageCapacity;
-}
-
-void HeapStatistics::dumpObjectStatistics(Heap* heap)
-{
-    dataLogF(&quot;\n=== Heap Statistics: ===\n&quot;);
-    dataLogF(&quot;size: %ldkB\n&quot;, static_cast&lt;long&gt;(heap-&gt;m_sizeAfterLastCollect / KB));
-    dataLogF(&quot;capacity: %ldkB\n&quot;, static_cast&lt;long&gt;(heap-&gt;capacity() / KB));
-    dataLogF(&quot;pause time: %lfs\n\n&quot;, heap-&gt;m_lastFullGCLength);
-
-    StorageStatistics storageStatistics;
-    {
-        HeapIterationScope iterationScope(*heap);
-        heap-&gt;m_objectSpace.forEachLiveCell(iterationScope, storageStatistics);
-    }
-    long wastedPropertyStorageBytes = 0;
-    long wastedPropertyStoragePercent = 0;
-    long objectWithOutOfLineStorageCount = 0;
-    long objectsWithOutOfLineStoragePercent = 0;
-    if ((storageStatistics.storageCapacity() &gt; 0) &amp;&amp; (storageStatistics.objectCount() &gt; 0)) {
-        wastedPropertyStorageBytes = static_cast&lt;long&gt;((storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB);
-        wastedPropertyStoragePercent = static_cast&lt;long&gt;(
-            (storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100 / storageStatistics.storageCapacity());
-        objectWithOutOfLineStorageCount = static_cast&lt;long&gt;(storageStatistics.objectWithOutOfLineStorageCount());
-        objectsWithOutOfLineStoragePercent = objectWithOutOfLineStorageCount * 100 / storageStatistics.objectCount();
-    }
-    dataLogF(&quot;wasted .property storage: %ldkB (%ld%%)\n&quot;, wastedPropertyStorageBytes, wastedPropertyStoragePercent);
-    dataLogF(&quot;objects with out-of-line .property storage: %ld (%ld%%)\n&quot;, objectWithOutOfLineStorageCount, objectsWithOutOfLineStoragePercent);
-}
-
-} // namespace JSC
</del></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHeapStatisticsh"></a>
<div class="delfile"><h4>Deleted: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HeapStatistics.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,53 +0,0 @@
</span><del>-/*
- * Copyright (C) 2012 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;JSExportMacros.h&quot;
-#include &lt;wtf/Vector.h&gt;
-
-namespace JSC {
-
-class Heap;
-
-class HeapStatistics {
-public:
-    NO_RETURN static void exitWithFailure();
-    JS_EXPORT_PRIVATE static void reportSuccess();
-
-    static void initialize();
-    static void recordGCPauseTime(double start, double end);
-
-    static void dumpObjectStatistics(Heap*);
-
-private:
-    static void logStatistics();
-    static Vector&lt;double&gt;* s_pauseTimeStarts;
-    static Vector&lt;double&gt;* s_pauseTimeEnds;
-    static double s_startTime;
-    static double s_endTime;
-};
-
-} // namespace JSC
</del></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHelpingGCScopeh"></a>
<div class="delfile"><h4>Deleted: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HelpingGCScope.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HelpingGCScope.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HelpingGCScope.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,52 +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. 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;Heap.h&quot;
-
-namespace JSC {
-
-class HelpingGCScope {
-public:
-    HelpingGCScope(Heap&amp; heap)
-        : m_heap(heap)
-        , m_oldState(m_heap.m_mutatorState)
-    {
-        m_heap.m_mutatorState = MutatorState::HelpingGC;
-    }
-    
-    ~HelpingGCScope()
-    {
-        m_heap.m_mutatorState = m_oldState;
-    }
-
-private:
-    Heap&amp; m_heap;
-    MutatorState m_oldState;
-};
-
-} // namespace JSC
-
</del></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapIncrementalSweepercpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -97,7 +97,7 @@
</span><span class="cx">     m_currentAllocator = m_vm-&gt;heap.objectSpace().firstAllocator();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IncrementalSweeper::willFinishSweeping()
</del><ins>+void IncrementalSweeper::stopSweeping()
</ins><span class="cx"> {
</span><span class="cx">     m_currentAllocator = nullptr;
</span><span class="cx">     if (m_vm)
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapIncrementalSweeperh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/IncrementalSweeper.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -37,11 +37,11 @@
</span><span class="cx"> public:
</span><span class="cx">     JS_EXPORT_PRIVATE explicit IncrementalSweeper(Heap*);
</span><span class="cx"> 
</span><del>-    void startSweeping();
</del><ins>+    JS_EXPORT_PRIVATE void startSweeping();
</ins><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE void doWork() override;
</span><span class="cx">     bool sweepNextBlock();
</span><del>-    void willFinishSweeping();
</del><ins>+    JS_EXPORT_PRIVATE void stopSweeping();
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     void doSweep(double startTime);
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMachineStackMarkercpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- *  Copyright (C) 2003-2009, 2015-2016 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2003-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *  Copyright (C) 2007 Eric Seidel &lt;eric@webkit.org&gt;
</span><span class="cx">  *  Copyright (C) 2009 Acision BV. All rights reserved.
</span><span class="cx">  *
</span><span class="lines">@@ -313,6 +313,18 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+SUPPRESS_ASAN
+void MachineThreads::gatherFromCurrentThread(ConservativeRoots&amp; conservativeRoots, JITStubRoutineSet&amp; jitStubRoutines, CodeBlockSet&amp; codeBlocks, CurrentThreadState&amp; currentThreadState)
+{
+    if (currentThreadState.registerState) {
+        void* registersBegin = currentThreadState.registerState;
+        void* registersEnd = reinterpret_cast&lt;void*&gt;(roundUpToMultipleOf&lt;sizeof(void*)&gt;(reinterpret_cast&lt;uintptr_t&gt;(currentThreadState.registerState + 1)));
+        conservativeRoots.add(registersBegin, registersEnd, jitStubRoutines, codeBlocks);
+    }
+
+    conservativeRoots.add(currentThreadState.stackTop, currentThreadState.stackOrigin, jitStubRoutines, codeBlocks);
+}
+
</ins><span class="cx"> MachineThreads::Thread::Thread(const PlatformThread&amp; platThread, void* base, void* end)
</span><span class="cx">     : platformThread(platThread)
</span><span class="cx">     , stackBase(base)
</span><span class="lines">@@ -1020,8 +1032,11 @@
</span><span class="cx">     *buffer = fastMalloc(*capacity);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void MachineThreads::gatherConservativeRoots(ConservativeRoots&amp; conservativeRoots, JITStubRoutineSet&amp; jitStubRoutines, CodeBlockSet&amp; codeBlocks)
</del><ins>+void MachineThreads::gatherConservativeRoots(ConservativeRoots&amp; conservativeRoots, JITStubRoutineSet&amp; jitStubRoutines, CodeBlockSet&amp; codeBlocks, CurrentThreadState* currentThreadState)
</ins><span class="cx"> {
</span><ins>+    if (currentThreadState)
+        gatherFromCurrentThread(conservativeRoots, jitStubRoutines, codeBlocks, *currentThreadState);
+
</ins><span class="cx">     size_t size;
</span><span class="cx">     size_t capacity = 0;
</span><span class="cx">     void* buffer = nullptr;
</span><span class="lines">@@ -1036,4 +1051,11 @@
</span><span class="cx">     fastFree(buffer);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+NEVER_INLINE int callWithCurrentThreadState(const ScopedLambda&lt;void(CurrentThreadState&amp;)&gt;&amp; lambda)
+{
+    DECLARE_AND_COMPUTE_CURRENT_THREAD_STATE(state);
+    lambda(state);
+    return 42; // Suppress tail call optimization.
+}
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMachineStackMarkerh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MachineStackMarker.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,7 +1,7 @@
</span><span class="cx"> /*
</span><span class="cx">  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
</span><span class="cx">  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
</span><del>- *  Copyright (C) 2003-2009, 2015-2016 Apple Inc. All rights reserved.
</del><ins>+ *  Copyright (C) 2003-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  *  This library is free software; you can redistribute it and/or
</span><span class="cx">  *  modify it under the terms of the GNU Lesser General Public
</span><span class="lines">@@ -21,9 +21,10 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><del>-#include &lt;setjmp.h&gt;
</del><ins>+#include &quot;RegisterState.h&quot;
</ins><span class="cx"> #include &lt;wtf/Lock.h&gt;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><ins>+#include &lt;wtf/ScopedLambda.h&gt;
</ins><span class="cx"> #include &lt;wtf/ThreadSpecific.h&gt;
</span><span class="cx"> 
</span><span class="cx"> #if OS(DARWIN)
</span><span class="lines">@@ -57,15 +58,19 @@
</span><span class="cx"> class Heap;
</span><span class="cx"> class JITStubRoutineSet;
</span><span class="cx"> 
</span><ins>+struct CurrentThreadState {
+    void* stackOrigin { nullptr };
+    void* stackTop { nullptr };
+    RegisterState* registerState { nullptr };
+};
+    
</ins><span class="cx"> class MachineThreads {
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(MachineThreads);
</span><span class="cx"> public:
</span><del>-    typedef jmp_buf RegisterState;
-
</del><span class="cx">     MachineThreads(Heap*);
</span><span class="cx">     ~MachineThreads();
</span><span class="cx"> 
</span><del>-    void gatherConservativeRoots(ConservativeRoots&amp;, JITStubRoutineSet&amp;, CodeBlockSet&amp;);
</del><ins>+    void gatherConservativeRoots(ConservativeRoots&amp;, JITStubRoutineSet&amp;, CodeBlockSet&amp;, CurrentThreadState*);
</ins><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE void addCurrentThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
</span><span class="cx"> 
</span><span class="lines">@@ -145,6 +150,8 @@
</span><span class="cx">     Thread* machineThreadForCurrentThread();
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    void gatherFromCurrentThread(ConservativeRoots&amp;, JITStubRoutineSet&amp;, CodeBlockSet&amp;, CurrentThreadState&amp;);
+
</ins><span class="cx">     void tryCopyOtherThreadStack(Thread*, void*, size_t capacity, size_t*);
</span><span class="cx">     bool tryCopyOtherThreadStacks(LockHolder&amp;, void*, size_t capacity, size_t*);
</span><span class="cx"> 
</span><span class="lines">@@ -161,24 +168,15 @@
</span><span class="cx"> #endif
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+#define DECLARE_AND_COMPUTE_CURRENT_THREAD_STATE(stateName) \
+    CurrentThreadState stateName; \
+    stateName.stackTop = &amp;stateName; \
+    stateName.stackOrigin = wtfThreadData().stack().origin(); \
+    ALLOCATE_AND_GET_REGISTER_STATE(stateName ## _registerState); \
+    stateName.registerState = &amp;stateName ## _registerState
+
+// The return value is meaningless. We just use it to suppress tail call optimization.
+int callWithCurrentThreadState(const ScopedLambda&lt;void(CurrentThreadState&amp;)&gt;&amp;);
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><del>-#if COMPILER(GCC_OR_CLANG)
-#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
-#else
-#define REGISTER_BUFFER_ALIGNMENT
-#endif
-
-// ALLOCATE_AND_GET_REGISTER_STATE() is a macro so that it is always &quot;inlined&quot; even in debug builds.
-#if COMPILER(MSVC)
-#pragma warning(push)
-#pragma warning(disable: 4611)
-#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
-    MachineThreads::RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
-    setjmp(registers)
-#pragma warning(pop)
-#else
-#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
-    MachineThreads::RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
-    setjmp(registers)
-#endif
</del></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMarkedAllocatorcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedAllocator.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedAllocator.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedAllocator.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -216,6 +216,14 @@
</span><span class="cx"> 
</span><span class="cx">     m_heap-&gt;collectIfNecessaryOrDefer(deferralContext);
</span><span class="cx">     
</span><ins>+    // Goofy corner case: the GC called a callback and now this allocator has a currentBlock. This only
+    // happens when running WebKit tests, which inject a callback into the GC's finalization.
+    if (UNLIKELY(m_currentBlock)) {
+        if (crashOnFailure)
+            return allocate(deferralContext);
+        return tryAllocate(deferralContext);
+    }
+    
</ins><span class="cx">     void* result = tryAllocateWithoutCollecting();
</span><span class="cx">     
</span><span class="cx">     if (LIKELY(result != 0))
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMarkedBlockcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedBlock.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedBlock.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedBlock.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -26,12 +26,12 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;MarkedBlock.h&quot;
</span><span class="cx"> 
</span><del>-#include &quot;HelpingGCScope.h&quot;
</del><span class="cx"> #include &quot;JSCell.h&quot;
</span><span class="cx"> #include &quot;JSDestructibleObject.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;MarkedBlockInlines.h&quot;
</span><span class="cx"> #include &quot;SuperSampler.h&quot;
</span><ins>+#include &quot;SweepingScope.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><span class="lines">@@ -409,8 +409,7 @@
</span><span class="cx"> 
</span><span class="cx"> FreeList MarkedBlock::Handle::sweep(SweepMode sweepMode)
</span><span class="cx"> {
</span><del>-    // FIXME: Maybe HelpingGCScope should just be called SweepScope?
-    HelpingGCScope helpingGCScope(*heap());
</del><ins>+    SweepingScope sweepingScope(*heap());
</ins><span class="cx">     
</span><span class="cx">     m_allocator-&gt;setIsUnswept(NoLockingNecessary, this, false);
</span><span class="cx">     
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMarkedSpacecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedSpace.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedSpace.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MarkedSpace.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -225,7 +225,7 @@
</span><span class="cx"> 
</span><span class="cx"> void MarkedSpace::sweep()
</span><span class="cx"> {
</span><del>-    m_heap-&gt;sweeper()-&gt;willFinishSweeping();
</del><ins>+    m_heap-&gt;sweeper()-&gt;stopSweeping();
</ins><span class="cx">     forEachAllocator(
</span><span class="cx">         [&amp;] (MarkedAllocator&amp; allocator) -&gt; IterationStatus {
</span><span class="cx">             allocator.sweep();
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMutatorStatecpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -41,9 +41,12 @@
</span><span class="cx">     case MutatorState::Allocating:
</span><span class="cx">         out.print(&quot;Allocating&quot;);
</span><span class="cx">         return;
</span><del>-    case MutatorState::HelpingGC:
-        out.print(&quot;HelpingGC&quot;);
</del><ins>+    case MutatorState::Sweeping:
+        out.print(&quot;Sweeping&quot;);
</ins><span class="cx">         return;
</span><ins>+    case MutatorState::Collecting:
+        out.print(&quot;Collecting&quot;);
+        return;
</ins><span class="cx">     }
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapMutatorStateh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/MutatorState.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -34,8 +34,11 @@
</span><span class="cx">     // The mutator is in an allocation slow path.
</span><span class="cx">     Allocating,
</span><span class="cx">     
</span><del>-    // The mutator was asked by the GC to do some work.
-    HelpingGC
</del><ins>+    // The mutator is sweeping.
+    Sweeping,
+    
+    // The mutator is collecting.
+    Collecting
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapRegisterStateh"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RegisterState.h (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RegisterState.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RegisterState.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,158 @@
</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;setjmp.h&gt;
+
+namespace JSC {
+
+#if !OS(WINDOWS)
+
+// ALLOCATE_AND_GET_REGISTER_STATE has to ensure that the GC sees callee-saves. It achieves this by
+// ensuring that the callee-saves are either spilled to the stack or saved in the RegisterState. The code
+// looks like it's achieving only the latter. However, it's possible that the compiler chooses to use
+// a callee-save for one of the caller's variables, which means that the value that we were interested in
+// got spilled. In that case, we will store something bogus into the RegisterState, and that's OK.
+
+#if CPU(X86)
+struct RegisterState {
+    uint32_t ebx;
+    uint32_t edi;
+    uint32_t esi;
+};
+
+#define SAVE_REG(regname, where) \
+    asm volatile (&quot;movl %%&quot; #regname &quot;, %0&quot; : &quot;=m&quot;(where) : : &quot;memory&quot;)
+
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    RegisterState registers; \
+    SAVE_REG(ebx, registers.ebx); \
+    SAVE_REG(edi, registers.edi); \
+    SAVE_REG(esi, registers.esi)
+
+#elif CPU(X86_64)
+struct RegisterState {
+    uint64_t rbx;
+    uint64_t r12;
+    uint64_t r13;
+    uint64_t r14;
+    uint64_t r15;
+};
+
+#define SAVE_REG(regname, where) \
+    asm volatile (&quot;movq %%&quot; #regname &quot;, %0&quot; : &quot;=m&quot;(where) : : &quot;memory&quot;)
+
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    RegisterState registers; \
+    SAVE_REG(rbx, registers.rbx); \
+    SAVE_REG(r12, registers.r12); \
+    SAVE_REG(r13, registers.r13); \
+    SAVE_REG(r14, registers.r14); \
+    SAVE_REG(r15, registers.r15)
+
+#elif CPU(ARM_THUMB2)
+struct RegisterState {
+    uint32_t r4;
+    uint32_t r5;
+    uint32_t r6;
+    uint32_t r8;
+    uint32_t r9;
+    uint32_t r10;
+    uint32_t r11;
+};
+
+#define SAVE_REG(regname, where) \
+    asm volatile (&quot;str &quot; #regname &quot;, %0&quot; : &quot;=m&quot;(where) : : &quot;memory&quot;)
+
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    RegisterState registers; \
+    SAVE_REG(r4, registers.r4); \
+    SAVE_REG(r5, registers.r5); \
+    SAVE_REG(r6, registers.r6); \
+    SAVE_REG(r8, registers.r8); \
+    SAVE_REG(r9, registers.r9); \
+    SAVE_REG(r10, registers.r10); \
+    SAVE_REG(r11, registers.r11)
+
+#elif CPU(ARM64)
+struct RegisterState {
+    uint64_t x19;
+    uint64_t x20;
+    uint64_t x21;
+    uint64_t x22;
+    uint64_t x23;
+    uint64_t x24;
+    uint64_t x25;
+    uint64_t x26;
+    uint64_t x27;
+    uint64_t x28;
+};
+
+#define SAVE_REG(regname, where) \
+    asm volatile (&quot;str &quot; #regname &quot;, %0&quot; : &quot;=m&quot;(where) : : &quot;memory&quot;)
+
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    RegisterState registers; \
+    SAVE_REG(x19, registers.x19); \
+    SAVE_REG(x20, registers.x20); \
+    SAVE_REG(x21, registers.x21); \
+    SAVE_REG(x22, registers.x22); \
+    SAVE_REG(x23, registers.x23); \
+    SAVE_REG(x24, registers.x24); \
+    SAVE_REG(x25, registers.x25); \
+    SAVE_REG(x26, registers.x26); \
+    SAVE_REG(x27, registers.x27); \
+    SAVE_REG(x28, registers.x28)
+
+#endif
+#endif // !OS(WINDOWS)
+
+#ifndef ALLOCATE_AND_GET_REGISTER_STATE
+#if COMPILER(GCC_OR_CLANG)
+#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*))))
+#else
+#define REGISTER_BUFFER_ALIGNMENT
+#endif
+
+typedef jmp_buf RegisterState;
+
+// ALLOCATE_AND_GET_REGISTER_STATE() is a macro so that it is always &quot;inlined&quot; even in debug builds.
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4611)
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
+    setjmp(registers)
+#pragma warning(pop)
+#else
+#define ALLOCATE_AND_GET_REGISTER_STATE(registers) \
+    RegisterState registers REGISTER_BUFFER_ALIGNMENT; \
+    setjmp(registers)
+#endif
+#endif // ALLOCATE_AND_GET_REGISTER_STATE
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapRunningScopehfromrev213034releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHelpingGCScopeh"></a>
<div class="copfile"><h4>Copied: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RunningScope.h (from rev 213034, releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HelpingGCScope.h) (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RunningScope.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/RunningScope.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,52 @@
</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;Heap.h&quot;
+
+namespace JSC {
+
+class RunningScope {
+public:
+    RunningScope(Heap&amp; heap)
+        : m_heap(heap)
+        , m_oldState(m_heap.m_mutatorState)
+    {
+        m_heap.m_mutatorState = MutatorState::Running;
+    }
+    
+    ~RunningScope()
+    {
+        m_heap.m_mutatorState = m_oldState;
+    }
+
+private:
+    Heap&amp; m_heap;
+    MutatorState m_oldState;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapSlotVisitorcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include &quot;JSString.h&quot;
</span><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;SlotVisitorInlines.h&quot;
</span><ins>+#include &quot;StopIfNecessaryTimer.h&quot;
</ins><span class="cx"> #include &quot;SuperSampler.h&quot;
</span><span class="cx"> #include &quot;VM.h&quot;
</span><span class="cx"> #include &lt;wtf/Lock.h&gt;
</span><span class="lines">@@ -75,12 +76,13 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-SlotVisitor::SlotVisitor(Heap&amp; heap)
</del><ins>+SlotVisitor::SlotVisitor(Heap&amp; heap, CString codeName)
</ins><span class="cx">     : m_bytesVisited(0)
</span><span class="cx">     , m_visitCount(0)
</span><span class="cx">     , m_isInParallelMode(false)
</span><span class="cx">     , m_markingVersion(MarkedSpace::initialVersion)
</span><span class="cx">     , m_heap(heap)
</span><ins>+    , m_codeName(codeName)
</ins><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     , m_isCheckingForDefaultMarkViolation(false)
</span><span class="cx">     , m_isDraining(false)
</span><span class="lines">@@ -469,9 +471,12 @@
</span><span class="cx">     m_canOptimizeForStoppedMutator = true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void SlotVisitor::drain(MonotonicTime timeout)
</del><ins>+NEVER_INLINE void SlotVisitor::drain(MonotonicTime timeout)
</ins><span class="cx"> {
</span><del>-    RELEASE_ASSERT(m_isInParallelMode);
</del><ins>+    if (!m_isInParallelMode) {
+        dataLog(&quot;FATAL: attempting to drain when not in parallel mode.\n&quot;);
+        RELEASE_ASSERT_NOT_REACHED();
+    }
</ins><span class="cx">     
</span><span class="cx">     auto locker = holdLock(m_rightToRun);
</span><span class="cx">     
</span><span class="lines">@@ -581,7 +586,7 @@
</span><span class="cx">         || !m_heap.m_sharedMutatorMarkStack-&gt;isEmpty();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-SlotVisitor::SharedDrainResult SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode, MonotonicTime timeout)
</del><ins>+NEVER_INLINE SlotVisitor::SharedDrainResult SlotVisitor::drainFromShared(SharedDrainMode sharedDrainMode, MonotonicTime timeout)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_isInParallelMode);
</span><span class="cx">     
</span><span class="lines">@@ -616,8 +621,22 @@
</span><span class="cx">                 if (hasElapsed(timeout))
</span><span class="cx">                     return SharedDrainResult::TimedOut;
</span><span class="cx">                 
</span><del>-                if (didReachTermination(locker))
</del><ins>+                if (didReachTermination(locker)) {
</ins><span class="cx">                     m_heap.m_markingConditionVariable.notifyAll();
</span><ins>+                    
+                    // If we're in concurrent mode, then we know that the mutator will eventually do
+                    // the right thing because:
+                    // - It's possible that the collector has the conn. In that case, the collector will
+                    //   wake up from the notification above. This will happen if the app released heap
+                    //   access. Native apps can spend a lot of time with heap access released.
+                    // - It's possible that the mutator will allocate soon. Then it will check if we
+                    //   reached termination. This is the most likely outcome in programs that allocate
+                    //   a lot.
+                    // - WebCore never releases access. But WebCore has a runloop. The runloop will check
+                    //   if we reached termination.
+                    // So, this tells the runloop that it's got things to do.
+                    m_heap.m_stopIfNecessaryTimer-&gt;scheduleSoon();
+                }
</ins><span class="cx"> 
</span><span class="cx">                 auto isReady = [&amp;] () -&gt; bool {
</span><span class="cx">                     return hasWork(locker)
</span><span class="lines">@@ -659,7 +678,9 @@
</span><span class="cx">     
</span><span class="cx">     ASSERT(Options::numberOfGCMarkers());
</span><span class="cx">     
</span><del>-    if (!m_heap.hasHeapAccess()
</del><ins>+    if (Options::numberOfGCMarkers() == 1
+        || (m_heap.m_worldState.load() &amp; Heap::mutatorWaitingBit)
+        || !m_heap.hasHeapAccess()
</ins><span class="cx">         || m_heap.collectorBelievesThatTheWorldIsStopped()) {
</span><span class="cx">         // This is an optimization over drainInParallel() when we have a concurrent mutator but
</span><span class="cx">         // otherwise it is not profitable.
</span><span class="lines">@@ -684,6 +705,9 @@
</span><span class="cx"> 
</span><span class="cx"> void SlotVisitor::donateAll()
</span><span class="cx"> {
</span><ins>+    if (isEmpty())
+        return;
+    
</ins><span class="cx">     donateAll(holdLock(m_heap.m_markingMutex));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -755,7 +779,11 @@
</span><span class="cx">     
</span><span class="cx"> void SlotVisitor::donate()
</span><span class="cx"> {
</span><del>-    ASSERT(m_isInParallelMode);
</del><ins>+    if (!m_isInParallelMode) {
+        dataLog(&quot;FATAL: Attempting to donate when not in parallel mode.\n&quot;);
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+    
</ins><span class="cx">     if (Options::numberOfGCMarkers() == 1)
</span><span class="cx">         return;
</span><span class="cx">     
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapSlotVisitorh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SlotVisitor.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -56,7 +56,7 @@
</span><span class="cx">     friend class Heap;
</span><span class="cx"> 
</span><span class="cx"> public:
</span><del>-    SlotVisitor(Heap&amp;);
</del><ins>+    SlotVisitor(Heap&amp;, CString codeName);
</ins><span class="cx">     ~SlotVisitor();
</span><span class="cx"> 
</span><span class="cx">     MarkStackArray&amp; collectorMarkStack() { return m_collectorStack; }
</span><span class="lines">@@ -167,6 +167,8 @@
</span><span class="cx">     void setIgnoreNewOpaqueRoots(bool value) { m_ignoreNewOpaqueRoots = value; }
</span><span class="cx"> 
</span><span class="cx">     void donateAll();
</span><ins>+    
+    const char* codeName() const { return m_codeName.data(); }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     friend class ParallelModeEnabler;
</span><span class="lines">@@ -228,6 +230,8 @@
</span><span class="cx">     bool m_canOptimizeForStoppedMutator { false };
</span><span class="cx">     Lock m_rightToRun;
</span><span class="cx">     
</span><ins>+    CString m_codeName;
+    
</ins><span class="cx"> public:
</span><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     bool m_isCheckingForDefaultMarkViolation;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapStochasticSpaceTimeMutatorSchedulercpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/StochasticSpaceTimeMutatorScheduler.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/StochasticSpaceTimeMutatorScheduler.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/StochasticSpaceTimeMutatorScheduler.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -76,6 +76,10 @@
</span><span class="cx">     m_bytesAllocatedThisCycleAtTheEnd = 
</span><span class="cx">         Options::concurrentGCMaxHeadroom() *
</span><span class="cx">         std::max&lt;double&gt;(m_bytesAllocatedThisCycleAtTheBeginning, m_heap.m_maxEdenSize);
</span><ins>+    
+    if (Options::logGC())
+        dataLog(&quot;ca=&quot;, m_bytesAllocatedThisCycleAtTheBeginning / 1024, &quot;kb h=&quot;, (m_bytesAllocatedThisCycleAtTheEnd - m_bytesAllocatedThisCycleAtTheBeginning) / 1024, &quot;kb &quot;);
+    
</ins><span class="cx">     m_beforeConstraints = MonotonicTime::now();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -117,6 +121,11 @@
</span><span class="cx">     Snapshot snapshot(*this);
</span><span class="cx">     
</span><span class="cx">     double resumeProbability = mutatorUtilization(snapshot);
</span><ins>+    if (resumeProbability &lt; Options::epsilonMutatorUtilization()) {
+        m_plannedResumeTime = MonotonicTime::infinity();
+        return;
+    }
+    
</ins><span class="cx">     bool shouldResume = m_random.get() &lt; resumeProbability;
</span><span class="cx">     
</span><span class="cx">     if (shouldResume) {
</span><span class="lines">@@ -135,8 +144,10 @@
</span><span class="cx">     case Stopped:
</span><span class="cx">         return MonotonicTime::now();
</span><span class="cx">     case Resumed: {
</span><del>-        // Once we're running, we keep going.
-        // FIXME: Maybe force stop when we run out of headroom?
</del><ins>+        // Once we're running, we keep going unless we run out of headroom.
+        Snapshot snapshot(*this);
+        if (mutatorUtilization(snapshot) &lt; Options::epsilonMutatorUtilization())
+            return MonotonicTime::now();
</ins><span class="cx">         return MonotonicTime::infinity();
</span><span class="cx">     } }
</span><span class="cx">     
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreheapSweepingScopehfromrev213034releasesWebKitGTKwebkit216SourceJavaScriptCoreheapHelpingGCScopeh"></a>
<div class="copfile"><h4>Copied: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SweepingScope.h (from rev 213034, releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/HelpingGCScope.h) (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SweepingScope.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/heap/SweepingScope.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,52 @@
</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;Heap.h&quot;
+
+namespace JSC {
+
+class SweepingScope {
+public:
+    SweepingScope(Heap&amp; heap)
+        : m_heap(heap)
+        , m_oldState(m_heap.m_mutatorState)
+    {
+        m_heap.m_mutatorState = MutatorState::Sweeping;
+    }
+    
+    ~SweepingScope()
+    {
+        m_heap.m_mutatorState = m_oldState;
+    }
+
+private:
+    Heap&amp; m_heap;
+    MutatorState m_oldState;
+};
+
+} // namespace JSC
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCorejitJITWorklistcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jit/JITWorklist.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jit/JITWorklist.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jit/JITWorklist.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -99,7 +99,7 @@
</span><span class="cx"> 
</span><span class="cx"> class JITWorklist::Thread : public AutomaticThread {
</span><span class="cx"> public:
</span><del>-    Thread(const LockHolder&amp; locker, JITWorklist&amp; worklist)
</del><ins>+    Thread(const AbstractLocker&amp; locker, JITWorklist&amp; worklist)
</ins><span class="cx">         : AutomaticThread(locker, worklist.m_lock, worklist.m_condition)
</span><span class="cx">         , m_worklist(worklist)
</span><span class="cx">     {
</span><span class="lines">@@ -107,7 +107,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx"> protected:
</span><del>-    PollResult poll(const LockHolder&amp;) override
</del><ins>+    PollResult poll(const AbstractLocker&amp;) override
</ins><span class="cx">     {
</span><span class="cx">         RELEASE_ASSERT(m_worklist.m_numAvailableThreads);
</span><span class="cx">         
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCorejsccpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jsc.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jsc.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/jsc.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -38,7 +38,6 @@
</span><span class="cx"> #include &quot;GetterSetter.h&quot;
</span><span class="cx"> #include &quot;HeapProfiler.h&quot;
</span><span class="cx"> #include &quot;HeapSnapshotBuilder.h&quot;
</span><del>-#include &quot;HeapStatistics.h&quot;
</del><span class="cx"> #include &quot;InitializeThreading.h&quot;
</span><span class="cx"> #include &quot;Interpreter.h&quot;
</span><span class="cx"> #include &quot;JIT.h&quot;
</span><span class="lines">@@ -1084,6 +1083,7 @@
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionDollarAgentLeaving(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionWaitForReport(ExecState*);
</span><span class="cx"> static EncodedJSValue JSC_HOST_CALL functionHeapCapacity(ExecState*);
</span><ins>+static EncodedJSValue JSC_HOST_CALL functionFlashHeapAccess(ExecState*);
</ins><span class="cx"> 
</span><span class="cx"> struct Script {
</span><span class="cx">     enum class StrictMode {
</span><span class="lines">@@ -1366,6 +1366,7 @@
</span><span class="cx">         addFunction(vm, &quot;waitForReport&quot;, functionWaitForReport, 0);
</span><span class="cx"> 
</span><span class="cx">         addFunction(vm, &quot;heapCapacity&quot;, functionHeapCapacity, 0);
</span><ins>+        addFunction(vm, &quot;flashHeapAccess&quot;, functionFlashHeapAccess, 0);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void addFunction(VM&amp; vm, JSObject* object, const char* name, NativeFunction function, unsigned arguments)
</span><span class="lines">@@ -2648,6 +2649,21 @@
</span><span class="cx">     return JSValue::encode(jsNumber(vm.heap.capacity()));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+EncodedJSValue JSC_HOST_CALL functionFlashHeapAccess(ExecState* exec)
+{
+    VM&amp; vm = exec-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    
+    vm.heap.releaseAccess();
+    if (exec-&gt;argumentCount() &gt;= 1) {
+        double ms = exec-&gt;argument(0).toNumber(exec);
+        RETURN_IF_EXCEPTION(scope, encodedJSValue());
+        sleep(Seconds::fromMilliseconds(ms));
+    }
+    vm.heap.acquireAccess();
+    return JSValue::encode(jsUndefined());
+}
+
</ins><span class="cx"> template&lt;typename ValueType&gt;
</span><span class="cx"> typename std::enable_if&lt;!std::is_fundamental&lt;ValueType&gt;::value&gt;::type addOption(VM&amp;, JSObject*, Identifier, ValueType) { }
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeInitializeThreadingcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/InitializeThreading.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/InitializeThreading.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/InitializeThreading.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -31,7 +31,6 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;ExecutableAllocator.h&quot;
</span><span class="cx"> #include &quot;Heap.h&quot;
</span><del>-#include &quot;HeapStatistics.h&quot;
</del><span class="cx"> #include &quot;Identifier.h&quot;
</span><span class="cx"> #include &quot;JSDateMath.h&quot;
</span><span class="cx"> #include &quot;JSGlobalObject.h&quot;
</span><span class="lines">@@ -60,8 +59,6 @@
</span><span class="cx">         WTF::initializeThreading();
</span><span class="cx">         WTF::initializeGCThreads();
</span><span class="cx">         Options::initialize();
</span><del>-        if (Options::recordGCPauseTimes())
-            HeapStatistics::initialize();
</del><span class="cx"> #if ENABLE(WRITE_BARRIER_PROFILING)
</span><span class="cx">         WriteBarrierCounters::initialize();
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeJSCellInlinesh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/JSCellInlines.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/JSCellInlines.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/JSCellInlines.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -280,7 +280,7 @@
</span><span class="cx">     // destructing the object. The GC thread or JIT threads, unlike the mutator thread, are able to access classInfo
</span><span class="cx">     // independent of whether the mutator thread is sweeping or not. Hence, we also check for ownerThread() !=
</span><span class="cx">     // std::this_thread::get_id() to allow the GC thread or JIT threads to pass this assertion.
</span><del>-    ASSERT(vm.heap.mutatorState() == MutatorState::Running || vm.apiLock().ownerThread() != std::this_thread::get_id());
</del><ins>+    ASSERT(vm.heap.mutatorState() != MutatorState::Sweeping || vm.apiLock().ownerThread() != std::this_thread::get_id());
</ins><span class="cx">     return structure(vm)-&gt;classInfo();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeOptionscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -317,7 +317,11 @@
</span><span class="cx">         Options::maximumMutatorUtilization() = 0.6;
</span><span class="cx">         Options::concurrentGCMaxHeadroom() = 1.4;
</span><span class="cx">         Options::minimumGCPauseMS() = 1;
</span><del>-        Options::gcIncrementScale() = 1;
</del><ins>+        Options::useStochasticMutatorScheduler() = false;
+        if (WTF::numberOfProcessorCores() &lt;= 1)
+            Options::gcIncrementScale() = 1;
+        else
+            Options::gcIncrementScale() = 0;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/Options.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -200,6 +200,7 @@
</span><span class="cx">     v(double, largeHeapGrowthFactor, 1.24, Normal, nullptr) \
</span><span class="cx">     v(double, minimumMutatorUtilization, 0, Normal, nullptr) \
</span><span class="cx">     v(double, maximumMutatorUtilization, 0.7, Normal, nullptr) \
</span><ins>+    v(double, epsilonMutatorUtilization, 0.01, Normal, nullptr) \
</ins><span class="cx">     v(double, concurrentGCMaxHeadroom, 1.5, Normal, nullptr) \
</span><span class="cx">     v(double, concurrentGCPeriodMS, 2, Normal, nullptr) \
</span><span class="cx">     v(bool, useStochasticMutatorScheduler, true, Normal, nullptr) \
</span><span class="lines">@@ -344,7 +345,6 @@
</span><span class="cx">     v(bool, useZombieMode, false, Normal, &quot;debugging option to scribble over dead objects with 0xbadbeef0&quot;) \
</span><span class="cx">     v(bool, useImmortalObjects, false, Normal, &quot;debugging option to keep all objects alive forever&quot;) \
</span><span class="cx">     v(bool, sweepSynchronously, false, Normal, &quot;debugging option to sweep all dead objects synchronously at GC end before resuming mutator&quot;) \
</span><del>-    v(bool, dumpObjectStatistics, false, Normal, nullptr) \
</del><span class="cx">     v(unsigned, maxSingleAllocationSize, 0, Configurable, &quot;debugging option to limit individual allocations to a max size (0 = limit not set, N = limit size in bytes)&quot;) \
</span><span class="cx">     \
</span><span class="cx">     v(gcLogLevel, logGC, GCLogging::None, Normal, &quot;debugging option to log GC activity (0 = None, 1 = Basic, 2 = Verbose)&quot;) \
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceJavaScriptCoreruntimeTestRunnerUtilscpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/JavaScriptCore/runtime/TestRunnerUtils.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</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">@@ -28,7 +28,6 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> #include &quot;FunctionCodeBlock.h&quot;
</span><del>-#include &quot;HeapStatistics.h&quot;
</del><span class="cx"> #include &quot;JSCInlines.h&quot;
</span><span class="cx"> #include &quot;LLIntData.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -160,8 +159,6 @@
</span><span class="cx"> // This is a hook called at the bitter end of some of our tests.
</span><span class="cx"> void finalizeStatsAtEndOfTesting()
</span><span class="cx"> {
</span><del>-    if (Options::logHeapStatisticsAtExit())
-        HeapStatistics::reportSuccess();
</del><span class="cx">     if (Options::reportLLIntStats())
</span><span class="cx">         LLInt::Data::finalizeStats();
</span><span class="cx"> }
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WTF/ChangeLog (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WTF/ChangeLog        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WTF/ChangeLog        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,3 +1,36 @@
</span><ins>+2017-02-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        The collector thread should only start when the mutator doesn't have heap access
+        https://bugs.webkit.org/show_bug.cgi?id=167737
+
+        Reviewed by Keith Miller.
+        
+        Extend the use of AbstractLocker so that we can use more locking idioms.
+
+        * wtf/AutomaticThread.cpp:
+        (WTF::AutomaticThreadCondition::notifyOne):
+        (WTF::AutomaticThreadCondition::notifyAll):
+        (WTF::AutomaticThreadCondition::add):
+        (WTF::AutomaticThreadCondition::remove):
+        (WTF::AutomaticThreadCondition::contains):
+        (WTF::AutomaticThread::AutomaticThread):
+        (WTF::AutomaticThread::tryStop):
+        (WTF::AutomaticThread::isWaiting):
+        (WTF::AutomaticThread::notify):
+        (WTF::AutomaticThread::start):
+        (WTF::AutomaticThread::threadIsStopping):
+        * wtf/AutomaticThread.h:
+        * wtf/NumberOfCores.cpp:
+        (WTF::numberOfProcessorCores):
+        * wtf/ParallelHelperPool.cpp:
+        (WTF::ParallelHelperClient::finish):
+        (WTF::ParallelHelperClient::claimTask):
+        (WTF::ParallelHelperPool::Thread::Thread):
+        (WTF::ParallelHelperPool::didMakeWorkAvailable):
+        (WTF::ParallelHelperPool::hasClientWithTask):
+        (WTF::ParallelHelperPool::getClientWithTask):
+        * wtf/ParallelHelperPool.h:
+
</ins><span class="cx"> 2017-02-20  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Re-landing] CachedCall should let GC know to keep its arguments alive.
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWTFwtfAutomaticThreadcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AutomaticThreadCondition::notifyOne(const LockHolder&amp; locker)
</del><ins>+void AutomaticThreadCondition::notifyOne(const AbstractLocker&amp; locker)
</ins><span class="cx"> {
</span><span class="cx">     for (AutomaticThread* thread : m_threads) {
</span><span class="cx">         if (thread-&gt;isWaiting(locker)) {
</span><span class="lines">@@ -64,7 +64,7 @@
</span><span class="cx">     m_condition.notifyOne();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AutomaticThreadCondition::notifyAll(const LockHolder&amp; locker)
</del><ins>+void AutomaticThreadCondition::notifyAll(const AbstractLocker&amp; locker)
</ins><span class="cx"> {
</span><span class="cx">     m_condition.notifyAll();
</span><span class="cx"> 
</span><span class="lines">@@ -81,24 +81,24 @@
</span><span class="cx">     m_condition.wait(lock);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AutomaticThreadCondition::add(const LockHolder&amp;, AutomaticThread* thread)
</del><ins>+void AutomaticThreadCondition::add(const AbstractLocker&amp;, AutomaticThread* thread)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(!m_threads.contains(thread));
</span><span class="cx">     m_threads.append(thread);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AutomaticThreadCondition::remove(const LockHolder&amp;, AutomaticThread* thread)
</del><ins>+void AutomaticThreadCondition::remove(const AbstractLocker&amp;, AutomaticThread* thread)
</ins><span class="cx"> {
</span><span class="cx">     m_threads.removeFirst(thread);
</span><span class="cx">     ASSERT(!m_threads.contains(thread));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool AutomaticThreadCondition::contains(const LockHolder&amp;, AutomaticThread* thread)
</del><ins>+bool AutomaticThreadCondition::contains(const AbstractLocker&amp;, AutomaticThread* thread)
</ins><span class="cx"> {
</span><span class="cx">     return m_threads.contains(thread);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-AutomaticThread::AutomaticThread(const LockHolder&amp; locker, Box&lt;Lock&gt; lock, RefPtr&lt;AutomaticThreadCondition&gt; condition)
</del><ins>+AutomaticThread::AutomaticThread(const AbstractLocker&amp; locker, Box&lt;Lock&gt; lock, RefPtr&lt;AutomaticThreadCondition&gt; condition)
</ins><span class="cx">     : m_lock(lock)
</span><span class="cx">     , m_condition(condition)
</span><span class="cx"> {
</span><span class="lines">@@ -118,7 +118,7 @@
</span><span class="cx">     m_condition-&gt;remove(locker, this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool AutomaticThread::tryStop(const LockHolder&amp;)
</del><ins>+bool AutomaticThread::tryStop(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     if (!m_isRunning)
</span><span class="cx">         return true;
</span><span class="lines">@@ -128,12 +128,12 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool AutomaticThread::isWaiting(const LockHolder&amp; locker)
</del><ins>+bool AutomaticThread::isWaiting(const AbstractLocker&amp; locker)
</ins><span class="cx"> {
</span><span class="cx">     return hasUnderlyingThread(locker) &amp;&amp; m_isWaiting;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool AutomaticThread::notify(const LockHolder&amp; locker)
</del><ins>+bool AutomaticThread::notify(const AbstractLocker&amp; locker)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT_UNUSED(locker, hasUnderlyingThread(locker));
</span><span class="cx">     m_isWaiting = false;
</span><span class="lines">@@ -147,7 +147,7 @@
</span><span class="cx">         m_isRunningCondition.wait(*m_lock);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AutomaticThread::start(const LockHolder&amp;)
</del><ins>+void AutomaticThread::start(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(m_isRunning);
</span><span class="cx">     
</span><span class="lines">@@ -169,18 +169,18 @@
</span><span class="cx">                 ASSERT(m_condition-&gt;contains(locker, this));
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            auto stopImpl = [&amp;] (const LockHolder&amp; locker) {
</del><ins>+            auto stopImpl = [&amp;] (const AbstractLocker&amp; locker) {
</ins><span class="cx">                 thread-&gt;threadIsStopping(locker);
</span><span class="cx">                 thread-&gt;m_hasUnderlyingThread = false;
</span><span class="cx">             };
</span><span class="cx">             
</span><del>-            auto stopPermanently = [&amp;] (const LockHolder&amp; locker) {
</del><ins>+            auto stopPermanently = [&amp;] (const AbstractLocker&amp; locker) {
</ins><span class="cx">                 m_isRunning = false;
</span><span class="cx">                 m_isRunningCondition.notifyAll();
</span><span class="cx">                 stopImpl(locker);
</span><span class="cx">             };
</span><span class="cx">             
</span><del>-            auto stopForTimeout = [&amp;] (const LockHolder&amp; locker) {
</del><ins>+            auto stopForTimeout = [&amp;] (const AbstractLocker&amp; locker) {
</ins><span class="cx">                 stopImpl(locker);
</span><span class="cx">             };
</span><span class="cx">             
</span><span class="lines">@@ -227,7 +227,7 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void AutomaticThread::threadIsStopping(const LockHolder&amp;)
</del><ins>+void AutomaticThread::threadIsStopping(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWTFwtfAutomaticThreadh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/AutomaticThread.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -75,8 +75,8 @@
</span><span class="cx">     
</span><span class="cx">     WTF_EXPORT_PRIVATE ~AutomaticThreadCondition();
</span><span class="cx">     
</span><del>-    WTF_EXPORT_PRIVATE void notifyOne(const LockHolder&amp;);
-    WTF_EXPORT_PRIVATE void notifyAll(const LockHolder&amp;);
</del><ins>+    WTF_EXPORT_PRIVATE void notifyOne(const AbstractLocker&amp;);
+    WTF_EXPORT_PRIVATE void notifyAll(const AbstractLocker&amp;);
</ins><span class="cx">     
</span><span class="cx">     // You can reuse this condition for other things, just as you would any other condition.
</span><span class="cx">     // However, since conflating conditions could lead to thundering herd, it's best to avoid it.
</span><span class="lines">@@ -90,9 +90,9 @@
</span><span class="cx">     
</span><span class="cx">     WTF_EXPORT_PRIVATE AutomaticThreadCondition();
</span><span class="cx"> 
</span><del>-    void add(const LockHolder&amp;, AutomaticThread*);
-    void remove(const LockHolder&amp;, AutomaticThread*);
-    bool contains(const LockHolder&amp;, AutomaticThread*);
</del><ins>+    void add(const AbstractLocker&amp;, AutomaticThread*);
+    void remove(const AbstractLocker&amp;, AutomaticThread*);
+    bool contains(const AbstractLocker&amp;, AutomaticThread*);
</ins><span class="cx">     
</span><span class="cx">     Condition m_condition;
</span><span class="cx">     Vector&lt;AutomaticThread*&gt; m_threads;
</span><span class="lines">@@ -113,17 +113,17 @@
</span><span class="cx">     virtual ~AutomaticThread();
</span><span class="cx">     
</span><span class="cx">     // Sometimes it's possible to optimize for the case that there is no underlying thread.
</span><del>-    bool hasUnderlyingThread(const LockHolder&amp;) const { return m_hasUnderlyingThread; }
</del><ins>+    bool hasUnderlyingThread(const AbstractLocker&amp;) const { return m_hasUnderlyingThread; }
</ins><span class="cx">     
</span><span class="cx">     // This attempts to quickly stop the thread. This will succeed if the thread happens to not be
</span><span class="cx">     // running. Returns true if the thread has been stopped. A good idiom for stopping your automatic
</span><span class="cx">     // thread is to first try this, and if that doesn't work, to tell the thread using your own
</span><span class="cx">     // mechanism (set some flag and then notify the condition).
</span><del>-    bool tryStop(const LockHolder&amp;);
</del><ins>+    bool tryStop(const AbstractLocker&amp;);
</ins><span class="cx"> 
</span><del>-    bool isWaiting(const LockHolder&amp;);
</del><ins>+    bool isWaiting(const AbstractLocker&amp;);
</ins><span class="cx"> 
</span><del>-    bool notify(const LockHolder&amp;);
</del><ins>+    bool notify(const AbstractLocker&amp;);
</ins><span class="cx"> 
</span><span class="cx">     void join();
</span><span class="cx">     
</span><span class="lines">@@ -130,7 +130,7 @@
</span><span class="cx"> protected:
</span><span class="cx">     // This logically creates the thread, but in reality the thread won't be created until someone
</span><span class="cx">     // calls AutomaticThreadCondition::notifyOne() or notifyAll().
</span><del>-    AutomaticThread(const LockHolder&amp;, Box&lt;Lock&gt;, RefPtr&lt;AutomaticThreadCondition&gt;);
</del><ins>+    AutomaticThread(const AbstractLocker&amp;, Box&lt;Lock&gt;, RefPtr&lt;AutomaticThreadCondition&gt;);
</ins><span class="cx">     
</span><span class="cx">     // To understand PollResult and WorkResult, imagine that poll() and work() are being called like
</span><span class="cx">     // so:
</span><span class="lines">@@ -159,7 +159,7 @@
</span><span class="cx">     // }
</span><span class="cx">     
</span><span class="cx">     enum class PollResult { Work, Stop, Wait };
</span><del>-    virtual PollResult poll(const LockHolder&amp;) = 0;
</del><ins>+    virtual PollResult poll(const AbstractLocker&amp;) = 0;
</ins><span class="cx">     
</span><span class="cx">     enum class WorkResult { Continue, Stop };
</span><span class="cx">     virtual WorkResult work() = 0;
</span><span class="lines">@@ -168,12 +168,12 @@
</span><span class="cx">     // when the thread dies. These methods let you do this. You can override these methods, and you
</span><span class="cx">     // can be sure that the default ones don't do anything (so you don't need a super call).
</span><span class="cx">     virtual void threadDidStart();
</span><del>-    virtual void threadIsStopping(const LockHolder&amp;);
</del><ins>+    virtual void threadIsStopping(const AbstractLocker&amp;);
</ins><span class="cx">     
</span><span class="cx"> private:
</span><span class="cx">     friend class AutomaticThreadCondition;
</span><span class="cx">     
</span><del>-    void start(const LockHolder&amp;);
</del><ins>+    void start(const AbstractLocker&amp;);
</ins><span class="cx">     
</span><span class="cx">     Box&lt;Lock&gt; m_lock;
</span><span class="cx">     RefPtr&lt;AutomaticThreadCondition&gt; m_condition;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWTFwtfNumberOfCorescpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/NumberOfCores.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/NumberOfCores.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/NumberOfCores.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -47,6 +47,15 @@
</span><span class="cx"> 
</span><span class="cx">     if (s_numberOfCores &gt; 0)
</span><span class="cx">         return s_numberOfCores;
</span><ins>+    
+    if (const char* coresEnv = getenv(&quot;WTF_numberOfProcessorCores&quot;)) {
+        unsigned numberOfCores;
+        if (sscanf(coresEnv, &quot;%u&quot;, &amp;numberOfCores) == 1) {
+            s_numberOfCores = numberOfCores;
+            return s_numberOfCores;
+        } else
+            fprintf(stderr, &quot;WARNING: failed to parse WTF_numberOfProcessorCores=%s\n&quot;, coresEnv);
+    }
</ins><span class="cx"> 
</span><span class="cx"> #if OS(DARWIN)
</span><span class="cx">     unsigned result;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWTFwtfParallelHelperPoolcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-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">@@ -88,7 +88,7 @@
</span><span class="cx">     finish();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ParallelHelperClient::finish(const LockHolder&amp;)
</del><ins>+void ParallelHelperClient::finish(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     m_task = nullptr;
</span><span class="cx">     while (m_numActive)
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx">         m_pool-&gt;m_workCompleteCondition.wait(*m_pool-&gt;m_lock);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-RefPtr&lt;SharedTask&lt;void ()&gt;&gt; ParallelHelperClient::claimTask(const LockHolder&amp;)
</del><ins>+RefPtr&lt;SharedTask&lt;void ()&gt;&gt; ParallelHelperClient::claimTask(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     if (!m_task)
</span><span class="cx">         return nullptr;
</span><span class="lines">@@ -170,7 +170,7 @@
</span><span class="cx"> 
</span><span class="cx"> class ParallelHelperPool::Thread : public AutomaticThread {
</span><span class="cx"> public:
</span><del>-    Thread(const LockHolder&amp; locker, ParallelHelperPool&amp; pool)
</del><ins>+    Thread(const AbstractLocker&amp; locker, ParallelHelperPool&amp; pool)
</ins><span class="cx">         : AutomaticThread(locker, pool.m_lock, pool.m_workAvailableCondition)
</span><span class="cx">         , m_pool(pool)
</span><span class="cx">     {
</span><span class="lines">@@ -177,7 +177,7 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx"> protected:
</span><del>-    PollResult poll(const LockHolder&amp; locker) override
</del><ins>+    PollResult poll(const AbstractLocker&amp; locker) override
</ins><span class="cx">     {
</span><span class="cx">         if (m_pool.m_isDying)
</span><span class="cx">             return PollResult::Stop;
</span><span class="lines">@@ -203,7 +203,7 @@
</span><span class="cx">     RefPtr&lt;SharedTask&lt;void ()&gt;&gt; m_task;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-void ParallelHelperPool::didMakeWorkAvailable(const LockHolder&amp; locker)
</del><ins>+void ParallelHelperPool::didMakeWorkAvailable(const AbstractLocker&amp; locker)
</ins><span class="cx"> {
</span><span class="cx">     while (m_numThreads &gt; m_threads.size())
</span><span class="cx">         m_threads.append(adoptRef(new Thread(locker, *this)));
</span><span class="lines">@@ -210,12 +210,12 @@
</span><span class="cx">     m_workAvailableCondition-&gt;notifyAll(locker);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ParallelHelperPool::hasClientWithTask(const LockHolder&amp; locker)
</del><ins>+bool ParallelHelperPool::hasClientWithTask(const AbstractLocker&amp; locker)
</ins><span class="cx"> {
</span><span class="cx">     return !!getClientWithTask(locker);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ParallelHelperClient* ParallelHelperPool::getClientWithTask(const LockHolder&amp;)
</del><ins>+ParallelHelperClient* ParallelHelperPool::getClientWithTask(const AbstractLocker&amp;)
</ins><span class="cx"> {
</span><span class="cx">     // We load-balance by being random.
</span><span class="cx">     unsigned startIndex = m_random.getUint32(m_clients.size());
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWTFwtfParallelHelperPoolh"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.h (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.h        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WTF/wtf/ParallelHelperPool.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-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">@@ -168,8 +168,8 @@
</span><span class="cx"> private:
</span><span class="cx">     friend class ParallelHelperPool;
</span><span class="cx"> 
</span><del>-    void finish(const LockHolder&amp;);
-    RefPtr&lt;SharedTask&lt;void ()&gt;&gt; claimTask(const LockHolder&amp;);
</del><ins>+    void finish(const AbstractLocker&amp;);
+    RefPtr&lt;SharedTask&lt;void ()&gt;&gt; claimTask(const AbstractLocker&amp;);
</ins><span class="cx">     void runTask(RefPtr&lt;SharedTask&lt;void ()&gt;&gt;);
</span><span class="cx">     
</span><span class="cx">     RefPtr&lt;ParallelHelperPool&gt; m_pool;
</span><span class="lines">@@ -193,11 +193,11 @@
</span><span class="cx">     class Thread;
</span><span class="cx">     friend class Thread;
</span><span class="cx"> 
</span><del>-    void didMakeWorkAvailable(const LockHolder&amp;);
</del><ins>+    void didMakeWorkAvailable(const AbstractLocker&amp;);
</ins><span class="cx"> 
</span><del>-    bool hasClientWithTask(const LockHolder&amp;);
-    ParallelHelperClient* getClientWithTask(const LockHolder&amp;);
-    ParallelHelperClient* waitForClientWithTask(const LockHolder&amp;);
</del><ins>+    bool hasClientWithTask(const AbstractLocker&amp;);
+    ParallelHelperClient* getClientWithTask(const AbstractLocker&amp;);
+    ParallelHelperClient* waitForClientWithTask(const AbstractLocker&amp;);
</ins><span class="cx">     
</span><span class="cx">     Box&lt;Lock&gt; m_lock; // AutomaticThread wants this in a box for safety.
</span><span class="cx">     RefPtr&lt;AutomaticThreadCondition&gt; m_workAvailableCondition;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WebCore/ChangeLog (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WebCore/ChangeLog        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WebCore/ChangeLog        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2017-02-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        The collector thread should only start when the mutator doesn't have heap access
+        https://bugs.webkit.org/show_bug.cgi?id=167737
+
+        Reviewed by Keith Miller.
+
+        Added new tests in JSTests.
+        
+        The WebCore changes involve:
+        
+        - Refactoring around new header discipline.
+        
+        - Adding crazy GC APIs to window.internals to enable us to test the GC's runloop discipline.
+
+        * ForwardingHeaders/heap/GCFinalizationCallback.h: Added.
+        * ForwardingHeaders/heap/IncrementalSweeper.h: Added.
+        * ForwardingHeaders/heap/MachineStackMarker.h: Added.
+        * ForwardingHeaders/heap/RunningScope.h: Added.
+        * bindings/js/CommonVM.cpp:
+        * testing/Internals.cpp:
+        (WebCore::Internals::parserMetaData):
+        (WebCore::Internals::isReadableStreamDisturbed):
+        (WebCore::Internals::isGCRunning):
+        (WebCore::Internals::addGCFinalizationCallback):
+        (WebCore::Internals::stopSweeping):
+        (WebCore::Internals::startSweeping):
+        * testing/Internals.h:
+        * testing/Internals.idl:
+
</ins><span class="cx"> 2017-02-20  Joseph Pecoraro  &lt;pecoraro@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: m_normalWorld-&gt;hasOneRef() under WorkerThread::stop
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapGCFinalizationCallbackh"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/GCFinalizationCallback.h (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/GCFinalizationCallback.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/GCFinalizationCallback.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,3 @@
</span><ins>+#pragma once
+#include &lt;JavaScriptCore/GCFinalizationCallback.h&gt;
+
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapIncrementalSweeperh"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/IncrementalSweeper.h (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/IncrementalSweeper.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/IncrementalSweeper.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+#pragma once
+#include &lt;JavaScriptCore/IncrementalSweeper.h&gt;
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapMachineStackMarkerh"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/MachineStackMarker.h (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/MachineStackMarker.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/MachineStackMarker.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+#pragma once
+#include &lt;JavaScriptCore/MachineStackMarker.h&gt;
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWebCoreForwardingHeadersheapRunningScopeh"></a>
<div class="addfile"><h4>Added: releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/RunningScope.h (0 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/RunningScope.h                                (rev 0)
+++ releases/WebKitGTK/webkit-2.16/Source/WebCore/ForwardingHeaders/heap/RunningScope.h        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+#pragma once
+#include &lt;JavaScriptCore/RunningScope.h&gt;
</ins></span></pre></div>
<a id="releasesWebKitGTKwebkit216SourceWebCorebindingsjsCommonVMcpp"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Source/WebCore/bindings/js/CommonVM.cpp (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Source/WebCore/bindings/js/CommonVM.cpp        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Source/WebCore/bindings/js/CommonVM.cpp        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #include &quot;Settings.h&quot;
</span><span class="cx"> #include &quot;WebCoreJSClientData.h&quot;
</span><span class="cx"> #include &lt;heap/HeapInlines.h&gt;
</span><ins>+#include &quot;heap/MachineStackMarker.h&quot;
</ins><span class="cx"> #include &lt;runtime/VM.h&gt;
</span><span class="cx"> #include &lt;wtf/MainThread.h&gt;
</span><span class="cx"> #include &lt;wtf/text/AtomicString.h&gt;
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216ToolsChangeLog"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Tools/ChangeLog (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Tools/ChangeLog        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Tools/ChangeLog        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2017-02-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        The collector thread should only start when the mutator doesn't have heap access
+        https://bugs.webkit.org/show_bug.cgi?id=167737
+
+        Reviewed by Keith Miller.
+        
+        Make more tests collect continuously.
+
+        * Scripts/run-jsc-stress-tests:
+
</ins><span class="cx"> 2017-02-20  Florian Bruhin  &lt;git@the-compiler.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Handle EINTR during webkitpy server process select()
</span></span></pre></div>
<a id="releasesWebKitGTKwebkit216ToolsScriptsrunjscstresstests"></a>
<div class="modfile"><h4>Modified: releases/WebKitGTK/webkit-2.16/Tools/Scripts/run-jsc-stress-tests (213036 => 213037)</h4>
<pre class="diff"><span>
<span class="info">--- releases/WebKitGTK/webkit-2.16/Tools/Scripts/run-jsc-stress-tests        2017-02-27 08:07:57 UTC (rev 213036)
+++ releases/WebKitGTK/webkit-2.16/Tools/Scripts/run-jsc-stress-tests        2017-02-27 08:24:07 UTC (rev 213037)
</span><span class="lines">@@ -1468,11 +1468,11 @@
</span><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def runNoisyTestNoCJIT
</span><del>-    runNoisyTest(&quot;ftl-no-cjit&quot;, &quot;--validateBytecode=true&quot;, &quot;--validateGraphAtEachPhase=true&quot;, *(FTL_OPTIONS + NO_CJIT_OPTIONS))
</del><ins>+    runNoisyTest(&quot;ftl-no-cjit&quot;, &quot;--validateBytecode=true&quot;, &quot;--validateGraphAtEachPhase=true&quot;, *(FTL_OPTIONS + NO_CJIT_OPTIONS + COLLECT_CONTINUOUSLY_OPTIONS))
</ins><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def runNoisyTestEagerNoCJIT
</span><del>-    runNoisyTest(&quot;ftl-eager-no-cjit&quot;, &quot;--validateBytecode=true&quot;, &quot;--validateGraphAtEachPhase=true&quot;, *(FTL_OPTIONS + NO_CJIT_OPTIONS + EAGER_OPTIONS))
</del><ins>+    runNoisyTest(&quot;ftl-eager-no-cjit&quot;, &quot;--validateBytecode=true&quot;, &quot;--validateGraphAtEachPhase=true&quot;, *(FTL_OPTIONS + NO_CJIT_OPTIONS + EAGER_OPTIONS + COLLECT_CONTINUOUSLY_OPTIONS))
</ins><span class="cx"> end
</span><span class="cx"> 
</span><span class="cx"> def defaultRunNoisyTest
</span></span></pre>
</div>
</div>

</body>
</html>