<!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>[182200] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/182200">182200</a></dd>
<dt>Author</dt> <dd>akling@apple.com</dd>
<dt>Date</dt> <dd>2015-03-31 13:01:29 -0700 (Tue, 31 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Logically empty WeakBlocks should not pin down their MarkedBlocks indefinitely.
&lt;https://webkit.org/b/143210&gt;

Reviewed by Geoffrey Garen.

Since a MarkedBlock cannot be destroyed until all the WeakBlocks pointing into it are gone,
we had a little problem where WeakBlocks with only null pointers would still keep their
MarkedBlock alive.

This patch fixes that by detaching WeakBlocks from their MarkedBlock once a sweep discovers
that the WeakBlock contains no pointers to live objects. Ownership of the WeakBlock is passed
to the Heap, which will sweep the list of these detached WeakBlocks as part of a full GC,
destroying them once they're fully dead.

This allows the garbage collector to reclaim the 64kB MarkedBlocks much sooner, and resolves
a mysterious issue where doing two full garbage collections back-to-back would free additional
memory in the second collection.

Management of detached WeakBlocks is implemented as a Vector&lt;WeakBlock*&gt; in Heap, along with
an index of the next block in that vector that needs to be swept. The IncrementalSweeper then
calls into Heap::sweepNextLogicallyEmptyWeakBlock() to sweep one block at a time.

* heap/Heap.h:
* heap/Heap.cpp:
(JSC::Heap::collectAllGarbage): Add a final pass where we sweep the logically empty WeakBlocks
owned by Heap, after everything else has been swept.

(JSC::Heap::notifyIncrementalSweeper): Set up an incremental sweep of logically empty WeakBlocks
after a full garbage collection ends. Note that we don't do this after Eden collections, since
they are unlikely to cause entire WeakBlocks to go empty.

(JSC::Heap::addLogicallyEmptyWeakBlock): Added. Interface for passing ownership of a WeakBlock
to the Heap when it's detached from a WeakSet.

(JSC::Heap::sweepAllLogicallyEmptyWeakBlocks): Helper for collectAllGarbage() that sweeps all
of the logically empty WeakBlocks owned by Heap.

(JSC::Heap::sweepNextLogicallyEmptyWeakBlock): Sweeps one logically empty WeakBlock if needed
and updates the next-logically-empty-weak-block-to-sweep index.

(JSC::Heap::lastChanceToFinalize): call sweepAllLogicallyEmptyWeakBlocks() here, since there
won't be another chance after this.

* heap/IncrementalSweeper.h:
(JSC::IncrementalSweeper::hasWork): Deleted.

* heap/IncrementalSweeper.cpp:
(JSC::IncrementalSweeper::fullSweep):
(JSC::IncrementalSweeper::doSweep):
(JSC::IncrementalSweeper::sweepNextBlock): Restructured IncrementalSweeper a bit to simplify
adding a new sweeping stage for the Heap's logically empty WeakBlocks. sweepNextBlock() is
changed to return a bool (true if there's more work to be done.)

* heap/WeakBlock.cpp:
(JSC::WeakBlock::sweep): This now figures out if the WeakBlock is logically empty, i.e doesn't
contain any pointers to live objects. The answer is stored in a new SweepResult member.

* heap/WeakBlock.h:
(JSC::WeakBlock::isLogicallyEmptyButNotFree): Added. Can be queried after a sweep to determine
if the WeakBlock could be detached from the MarkedBlock.

(JSC::WeakBlock::SweepResult::SweepResult): Deleted in favor of initializing member variables
when declaring them.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapIncrementalSweepercpp">trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapIncrementalSweeperh">trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapWeakBlockcpp">trunk/Source/JavaScriptCore/heap/WeakBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapWeakBlockh">trunk/Source/JavaScriptCore/heap/WeakBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapWeakSetcpp">trunk/Source/JavaScriptCore/heap/WeakSet.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -1,3 +1,69 @@
</span><ins>+2015-03-31  Andreas Kling  &lt;akling@apple.com&gt;
+
+        Logically empty WeakBlocks should not pin down their MarkedBlocks indefinitely.
+        &lt;https://webkit.org/b/143210&gt;
+
+        Reviewed by Geoffrey Garen.
+
+        Since a MarkedBlock cannot be destroyed until all the WeakBlocks pointing into it are gone,
+        we had a little problem where WeakBlocks with only null pointers would still keep their
+        MarkedBlock alive.
+
+        This patch fixes that by detaching WeakBlocks from their MarkedBlock once a sweep discovers
+        that the WeakBlock contains no pointers to live objects. Ownership of the WeakBlock is passed
+        to the Heap, which will sweep the list of these detached WeakBlocks as part of a full GC,
+        destroying them once they're fully dead.
+
+        This allows the garbage collector to reclaim the 64kB MarkedBlocks much sooner, and resolves
+        a mysterious issue where doing two full garbage collections back-to-back would free additional
+        memory in the second collection.
+
+        Management of detached WeakBlocks is implemented as a Vector&lt;WeakBlock*&gt; in Heap, along with
+        an index of the next block in that vector that needs to be swept. The IncrementalSweeper then
+        calls into Heap::sweepNextLogicallyEmptyWeakBlock() to sweep one block at a time.
+
+        * heap/Heap.h:
+        * heap/Heap.cpp:
+        (JSC::Heap::collectAllGarbage): Add a final pass where we sweep the logically empty WeakBlocks
+        owned by Heap, after everything else has been swept.
+
+        (JSC::Heap::notifyIncrementalSweeper): Set up an incremental sweep of logically empty WeakBlocks
+        after a full garbage collection ends. Note that we don't do this after Eden collections, since
+        they are unlikely to cause entire WeakBlocks to go empty.
+
+        (JSC::Heap::addLogicallyEmptyWeakBlock): Added. Interface for passing ownership of a WeakBlock
+        to the Heap when it's detached from a WeakSet.
+
+        (JSC::Heap::sweepAllLogicallyEmptyWeakBlocks): Helper for collectAllGarbage() that sweeps all
+        of the logically empty WeakBlocks owned by Heap.
+
+        (JSC::Heap::sweepNextLogicallyEmptyWeakBlock): Sweeps one logically empty WeakBlock if needed
+        and updates the next-logically-empty-weak-block-to-sweep index.
+
+        (JSC::Heap::lastChanceToFinalize): call sweepAllLogicallyEmptyWeakBlocks() here, since there
+        won't be another chance after this.
+
+        * heap/IncrementalSweeper.h:
+        (JSC::IncrementalSweeper::hasWork): Deleted.
+
+        * heap/IncrementalSweeper.cpp:
+        (JSC::IncrementalSweeper::fullSweep):
+        (JSC::IncrementalSweeper::doSweep):
+        (JSC::IncrementalSweeper::sweepNextBlock): Restructured IncrementalSweeper a bit to simplify
+        adding a new sweeping stage for the Heap's logically empty WeakBlocks. sweepNextBlock() is
+        changed to return a bool (true if there's more work to be done.)
+
+        * heap/WeakBlock.cpp:
+        (JSC::WeakBlock::sweep): This now figures out if the WeakBlock is logically empty, i.e doesn't
+        contain any pointers to live objects. The answer is stored in a new SweepResult member.
+
+        * heap/WeakBlock.h:
+        (JSC::WeakBlock::isLogicallyEmptyButNotFree): Added. Can be queried after a sweep to determine
+        if the WeakBlock could be detached from the MarkedBlock.
+
+        (JSC::WeakBlock::SweepResult::SweepResult): Deleted in favor of initializing member variables
+        when declaring them.
+
</ins><span class="cx"> 2015-03-31  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         eval(&quot;this.foo&quot;) causes a crash if this had not been initialized in a derived class's constructor
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -373,6 +373,8 @@
</span><span class="cx"> 
</span><span class="cx">     m_objectSpace.lastChanceToFinalize();
</span><span class="cx">     releaseDelayedReleasedObjects();
</span><ins>+
+    sweepAllLogicallyEmptyWeakBlocks();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::releaseDelayedReleasedObjects()
</span><span class="lines">@@ -1002,6 +1004,8 @@
</span><span class="cx">     DeferGCForAWhile deferGC(*this);
</span><span class="cx">     m_objectSpace.sweep();
</span><span class="cx">     m_objectSpace.shrink();
</span><ins>+
+    sweepAllLogicallyEmptyWeakBlocks();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static double minute = 60.0;
</span><span class="lines">@@ -1240,8 +1244,11 @@
</span><span class="cx">     GCPHASE(NotifyIncrementalSweeper);
</span><span class="cx">     if (m_operationInProgress == EdenCollection)
</span><span class="cx">         m_sweeper-&gt;addBlocksAndContinueSweeping(WTF::move(m_blockSnapshot));
</span><del>-    else
</del><ins>+    else {
+        if (!m_logicallyEmptyWeakBlocks.isEmpty())
+            m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
</ins><span class="cx">         m_sweeper-&gt;startSweeping(WTF::move(m_blockSnapshot));
</span><ins>+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::rememberCurrentlyExecutingCodeBlocks()
</span><span class="lines">@@ -1476,4 +1483,41 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Heap::addLogicallyEmptyWeakBlock(WeakBlock* block)
+{
+    m_logicallyEmptyWeakBlocks.append(block);
+}
+
+void Heap::sweepAllLogicallyEmptyWeakBlocks()
+{
+    if (m_logicallyEmptyWeakBlocks.isEmpty())
+        return;
+
+    m_indexOfNextLogicallyEmptyWeakBlockToSweep = 0;
+    while (sweepNextLogicallyEmptyWeakBlock()) { }
+}
+
+bool Heap::sweepNextLogicallyEmptyWeakBlock()
+{
+    if (m_indexOfNextLogicallyEmptyWeakBlockToSweep == WTF::notFound)
+        return false;
+
+    WeakBlock* block = m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep];
+
+    block-&gt;sweep();
+    if (block-&gt;isEmpty()) {
+        std::swap(m_logicallyEmptyWeakBlocks[m_indexOfNextLogicallyEmptyWeakBlockToSweep], m_logicallyEmptyWeakBlocks.last());
+        m_logicallyEmptyWeakBlocks.removeLast();
+        WeakBlock::destroy(block);
+    } else
+        m_indexOfNextLogicallyEmptyWeakBlockToSweep++;
+
+    if (m_indexOfNextLogicallyEmptyWeakBlockToSweep &gt;= m_logicallyEmptyWeakBlocks.size()) {
+        m_indexOfNextLogicallyEmptyWeakBlockToSweep = WTF::notFound;
+        return false;
+    }
+
+    return true;
+}
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -238,6 +238,8 @@
</span><span class="cx">     void registerWeakGCMap(void* weakGCMap, std::function&lt;void()&gt; pruningCallback);
</span><span class="cx">     void unregisterWeakGCMap(void* weakGCMap);
</span><span class="cx"> 
</span><ins>+    void addLogicallyEmptyWeakBlock(WeakBlock*);
+
</ins><span class="cx"> private:
</span><span class="cx">     friend class CodeBlock;
</span><span class="cx">     friend class CopiedBlock;
</span><span class="lines">@@ -330,6 +332,9 @@
</span><span class="cx">     void zombifyDeadObjects();
</span><span class="cx">     void markDeadObjects();
</span><span class="cx"> 
</span><ins>+    void sweepAllLogicallyEmptyWeakBlocks();
+    bool sweepNextLogicallyEmptyWeakBlock();
+
</ins><span class="cx">     bool shouldDoFullCollection(HeapOperation requestedCollectionType) const;
</span><span class="cx">     size_t sizeAfterCollect();
</span><span class="cx"> 
</span><span class="lines">@@ -392,6 +397,9 @@
</span><span class="cx">     double m_lastCodeDiscardTime;
</span><span class="cx"> 
</span><span class="cx">     Vector&lt;ExecutableBase*&gt; m_compiledCode;
</span><ins>+
+    Vector&lt;WeakBlock*&gt; m_logicallyEmptyWeakBlocks;
+    size_t m_indexOfNextLogicallyEmptyWeakBlockToSweep { WTF::notFound };
</ins><span class="cx">     
</span><span class="cx">     RefPtr&lt;GCActivityCallback&gt; m_fullActivityCallback;
</span><span class="cx">     RefPtr&lt;GCActivityCallback&gt; m_edenActivityCallback;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapIncrementalSweepercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/heap/IncrementalSweeper.cpp        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -61,8 +61,7 @@
</span><span class="cx"> 
</span><span class="cx"> void IncrementalSweeper::fullSweep()
</span><span class="cx"> {
</span><del>-    while (hasWork())
-        doWork();
</del><ins>+    while (sweepNextBlock()) { }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IncrementalSweeper::doWork()
</span><span class="lines">@@ -72,9 +71,7 @@
</span><span class="cx"> 
</span><span class="cx"> void IncrementalSweeper::doSweep(double sweepBeginTime)
</span><span class="cx"> {
</span><del>-    while (!m_blocksToSweep.isEmpty()) {
-        sweepNextBlock();
-
</del><ins>+    while (sweepNextBlock()) {
</ins><span class="cx">         double elapsedTime = WTF::monotonicallyIncreasingTime() - sweepBeginTime;
</span><span class="cx">         if (elapsedTime &lt; sweepTimeSlice)
</span><span class="cx">             continue;
</span><span class="lines">@@ -87,7 +84,7 @@
</span><span class="cx">     cancelTimer();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IncrementalSweeper::sweepNextBlock()
</del><ins>+bool IncrementalSweeper::sweepNextBlock()
</ins><span class="cx"> {
</span><span class="cx">     while (!m_blocksToSweep.isEmpty()) {
</span><span class="cx">         MarkedBlock* block = m_blocksToSweep.takeLast();
</span><span class="lines">@@ -98,8 +95,10 @@
</span><span class="cx">         DeferGCForAWhile deferGC(m_vm-&gt;heap);
</span><span class="cx">         block-&gt;sweep();
</span><span class="cx">         m_vm-&gt;heap.objectSpace().freeOrShrinkBlock(block);
</span><del>-        return;
</del><ins>+        return true;
</ins><span class="cx">     }
</span><ins>+
+    return m_vm-&gt;heap.sweepNextLogicallyEmptyWeakBlock();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void IncrementalSweeper::startSweeping(Vector&lt;MarkedBlock*&gt;&amp;&amp; blockSnapshot)
</span><span class="lines">@@ -147,8 +146,9 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void IncrementalSweeper::sweepNextBlock()
</del><ins>+bool IncrementalSweeper::sweepNextBlock()
</ins><span class="cx"> {
</span><ins>+    return false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapIncrementalSweeperh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/heap/IncrementalSweeper.h        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx">     void addBlocksAndContinueSweeping(Vector&lt;MarkedBlock*&gt;&amp;&amp;);
</span><span class="cx"> 
</span><span class="cx">     JS_EXPORT_PRIVATE virtual void doWork() override;
</span><del>-    void sweepNextBlock();
</del><ins>+    bool sweepNextBlock();
</ins><span class="cx">     void willFinishSweeping();
</span><span class="cx"> 
</span><span class="cx"> #if USE(CF)
</span><span class="lines">@@ -56,7 +56,6 @@
</span><span class="cx">     void doSweep(double startTime);
</span><span class="cx">     void scheduleTimer();
</span><span class="cx">     void cancelTimer();
</span><del>-    bool hasWork() const { return !m_blocksToSweep.isEmpty(); }
</del><span class="cx">     
</span><span class="cx">     Vector&lt;MarkedBlock*&gt;&amp; m_blocksToSweep;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapWeakBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/WeakBlock.cpp (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/WeakBlock.cpp        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/heap/WeakBlock.cpp        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -81,8 +81,11 @@
</span><span class="cx">             finalize(weakImpl);
</span><span class="cx">         if (weakImpl-&gt;state() == WeakImpl::Deallocated)
</span><span class="cx">             addToFreeList(&amp;sweepResult.freeList, weakImpl);
</span><del>-        else
</del><ins>+        else {
</ins><span class="cx">             sweepResult.blockIsFree = false;
</span><ins>+            if (weakImpl-&gt;state() == WeakImpl::Live)
+                sweepResult.blockIsLogicallyEmpty = false;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     m_sweepResult = sweepResult;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapWeakBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/WeakBlock.h (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/WeakBlock.h        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/heap/WeakBlock.h        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -48,11 +48,11 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     struct SweepResult {
</span><del>-        SweepResult();
</del><span class="cx">         bool isNull() const;
</span><span class="cx"> 
</span><del>-        bool blockIsFree;
-        FreeCell* freeList;
</del><ins>+        bool blockIsFree { true };
+        bool blockIsLogicallyEmpty { true };
+        FreeCell* freeList { nullptr };
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     static WeakBlock* create();
</span><span class="lines">@@ -61,6 +61,7 @@
</span><span class="cx">     static WeakImpl* asWeakImpl(FreeCell*);
</span><span class="cx"> 
</span><span class="cx">     bool isEmpty();
</span><ins>+    bool isLogicallyEmptyButNotFree() const;
</ins><span class="cx"> 
</span><span class="cx">     void sweep();
</span><span class="cx">     SweepResult takeSweepResult();
</span><span class="lines">@@ -85,13 +86,6 @@
</span><span class="cx">     SweepResult m_sweepResult;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-inline WeakBlock::SweepResult::SweepResult()
-    : blockIsFree(true)
-    , freeList(0)
-{
-    ASSERT(isNull());
-}
-
</del><span class="cx"> inline bool WeakBlock::SweepResult::isNull() const
</span><span class="cx"> {
</span><span class="cx">     return blockIsFree &amp;&amp; !freeList; // This state is impossible, so we can use it to mean null.
</span><span class="lines">@@ -140,6 +134,11 @@
</span><span class="cx">     return !m_sweepResult.isNull() &amp;&amp; m_sweepResult.blockIsFree;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool WeakBlock::isLogicallyEmptyButNotFree() const
+{
+    return !m_sweepResult.isNull() &amp;&amp; !m_sweepResult.blockIsFree &amp;&amp; m_sweepResult.blockIsLogicallyEmpty;
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // WeakBlock_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapWeakSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/WeakSet.cpp (182199 => 182200)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/WeakSet.cpp        2015-03-31 19:43:45 UTC (rev 182199)
+++ trunk/Source/JavaScriptCore/heap/WeakSet.cpp        2015-03-31 20:01:29 UTC (rev 182200)
</span><span class="lines">@@ -44,8 +44,18 @@
</span><span class="cx"> 
</span><span class="cx"> void WeakSet::sweep()
</span><span class="cx"> {
</span><del>-    for (WeakBlock* block = m_blocks.head(); block; block = block-&gt;next())
</del><ins>+    for (WeakBlock* block = m_blocks.head(); block;) {
+        WeakBlock* nextBlock = block-&gt;next();
</ins><span class="cx">         block-&gt;sweep();
</span><ins>+        if (block-&gt;isLogicallyEmptyButNotFree()) {
+            // If this WeakBlock is logically empty, but still has Weaks pointing into it,
+            // we can't destroy it just yet. Detach it from the WeakSet and hand ownership
+            // to the Heap so we don't pin down the entire 64kB MarkedBlock.
+            m_blocks.remove(block);
+            heap()-&gt;addLogicallyEmptyWeakBlock(block);
+        }
+        block = nextBlock;
+    }
</ins><span class="cx"> 
</span><span class="cx">     resetAllocator();
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>