<!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>[162017] 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/162017">162017</a></dd>
<dt>Author</dt> <dd>mhahnenberg@apple.com</dd>
<dt>Date</dt> <dd>2014-01-14 15:03:01 -0800 (Tue, 14 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Copying should be generational
https://bugs.webkit.org/show_bug.cgi?id=126555

Reviewed by Geoffrey Garen.

This patch adds support for copying to our generational collector. Eden collections 
always trigger copying. Full collections use our normal fragmentation-based heuristics.

The way this works is that the CopiedSpace now has the notion of an old generation set of CopiedBlocks
and a new generation of CopiedBlocks. During each mutator cycle new CopiedSpace allocations reside
in the new generation. When a collection occurs, those blocks are moved to the old generation.

One key thing to remember is that both new and old generation objects in the MarkedSpace can
refer to old or new generation allocations in CopiedSpace. This is why we must fire write barriers 
when assigning to an old (MarkedSpace) object's Butterfly.

* heap/CopiedAllocator.h:
(JSC::CopiedAllocator::tryAllocateDuringCopying):
* heap/CopiedBlock.h:
(JSC::CopiedBlock::CopiedBlock):
(JSC::CopiedBlock::didEvacuateBytes):
(JSC::CopiedBlock::isOld):
(JSC::CopiedBlock::didPromote):
* heap/CopiedBlockInlines.h:
(JSC::CopiedBlock::reportLiveBytes):
(JSC::CopiedBlock::reportLiveBytesDuringCopying):
* heap/CopiedSpace.cpp:
(JSC::CopiedSpace::CopiedSpace):
(JSC::CopiedSpace::~CopiedSpace):
(JSC::CopiedSpace::init):
(JSC::CopiedSpace::tryAllocateOversize):
(JSC::CopiedSpace::tryReallocateOversize):
(JSC::CopiedSpace::doneFillingBlock):
(JSC::CopiedSpace::didStartFullCollection):
(JSC::CopiedSpace::doneCopying):
(JSC::CopiedSpace::size):
(JSC::CopiedSpace::capacity):
(JSC::CopiedSpace::isPagedOut):
* heap/CopiedSpace.h:
(JSC::CopiedSpace::CopiedGeneration::CopiedGeneration):
* heap/CopiedSpaceInlines.h:
(JSC::CopiedSpace::contains):
(JSC::CopiedSpace::recycleEvacuatedBlock):
(JSC::CopiedSpace::allocateBlock):
(JSC::CopiedSpace::startedCopying):
* heap/CopyVisitor.cpp:
(JSC::CopyVisitor::copyFromShared):
* heap/CopyVisitorInlines.h:
(JSC::CopyVisitor::allocateNewSpace):
(JSC::CopyVisitor::allocateNewSpaceSlow):
* heap/GCThreadSharedData.cpp:
(JSC::GCThreadSharedData::didStartCopying):
* heap/Heap.cpp:
(JSC::Heap::copyBackingStores):
* heap/SlotVisitorInlines.h:
(JSC::SlotVisitor::copyLater):
* heap/TinyBloomFilter.h:
(JSC::TinyBloomFilter::add):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedAllocatorh">trunk/Source/JavaScriptCore/heap/CopiedAllocator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedBlockh">trunk/Source/JavaScriptCore/heap/CopiedBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedBlockInlinesh">trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedSpacecpp">trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedSpaceh">trunk/Source/JavaScriptCore/heap/CopiedSpace.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedSpaceInlinesh">trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopyVisitorcpp">trunk/Source/JavaScriptCore/heap/CopyVisitor.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopyVisitorInlinesh">trunk/Source/JavaScriptCore/heap/CopyVisitorInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapGCThreadSharedDatacpp">trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapSlotVisitorInlinesh">trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapTinyBloomFilterh">trunk/Source/JavaScriptCore/heap/TinyBloomFilter.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -1,3 +1,64 @@
</span><ins>+2014-01-10  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
+
+        Copying should be generational
+        https://bugs.webkit.org/show_bug.cgi?id=126555
+
+        Reviewed by Geoffrey Garen.
+
+        This patch adds support for copying to our generational collector. Eden collections 
+        always trigger copying. Full collections use our normal fragmentation-based heuristics.
+
+        The way this works is that the CopiedSpace now has the notion of an old generation set of CopiedBlocks
+        and a new generation of CopiedBlocks. During each mutator cycle new CopiedSpace allocations reside
+        in the new generation. When a collection occurs, those blocks are moved to the old generation.
+
+        One key thing to remember is that both new and old generation objects in the MarkedSpace can
+        refer to old or new generation allocations in CopiedSpace. This is why we must fire write barriers 
+        when assigning to an old (MarkedSpace) object's Butterfly.
+
+        * heap/CopiedAllocator.h:
+        (JSC::CopiedAllocator::tryAllocateDuringCopying):
+        * heap/CopiedBlock.h:
+        (JSC::CopiedBlock::CopiedBlock):
+        (JSC::CopiedBlock::didEvacuateBytes):
+        (JSC::CopiedBlock::isOld):
+        (JSC::CopiedBlock::didPromote):
+        * heap/CopiedBlockInlines.h:
+        (JSC::CopiedBlock::reportLiveBytes):
+        (JSC::CopiedBlock::reportLiveBytesDuringCopying):
+        * heap/CopiedSpace.cpp:
+        (JSC::CopiedSpace::CopiedSpace):
+        (JSC::CopiedSpace::~CopiedSpace):
+        (JSC::CopiedSpace::init):
+        (JSC::CopiedSpace::tryAllocateOversize):
+        (JSC::CopiedSpace::tryReallocateOversize):
+        (JSC::CopiedSpace::doneFillingBlock):
+        (JSC::CopiedSpace::didStartFullCollection):
+        (JSC::CopiedSpace::doneCopying):
+        (JSC::CopiedSpace::size):
+        (JSC::CopiedSpace::capacity):
+        (JSC::CopiedSpace::isPagedOut):
+        * heap/CopiedSpace.h:
+        (JSC::CopiedSpace::CopiedGeneration::CopiedGeneration):
+        * heap/CopiedSpaceInlines.h:
+        (JSC::CopiedSpace::contains):
+        (JSC::CopiedSpace::recycleEvacuatedBlock):
+        (JSC::CopiedSpace::allocateBlock):
+        (JSC::CopiedSpace::startedCopying):
+        * heap/CopyVisitor.cpp:
+        (JSC::CopyVisitor::copyFromShared):
+        * heap/CopyVisitorInlines.h:
+        (JSC::CopyVisitor::allocateNewSpace):
+        (JSC::CopyVisitor::allocateNewSpaceSlow):
+        * heap/GCThreadSharedData.cpp:
+        (JSC::GCThreadSharedData::didStartCopying):
+        * heap/Heap.cpp:
+        (JSC::Heap::copyBackingStores):
+        * heap/SlotVisitorInlines.h:
+        (JSC::SlotVisitor::copyLater):
+        * heap/TinyBloomFilter.h:
+        (JSC::TinyBloomFilter::add):
+
</ins><span class="cx"> 2014-01-14  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         ASSERTION FAILED: !hasError() in JSC::Parser&lt;LexerType&gt;::createSavePoint().
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedAllocator.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedAllocator.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopiedAllocator.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx">     
</span><span class="cx">     bool fastPathShouldSucceed(size_t bytes) const;
</span><span class="cx">     CheckedBoolean tryAllocate(size_t bytes, void** outPtr);
</span><ins>+    CheckedBoolean tryAllocateDuringCopying(size_t bytes, void** outPtr);
</ins><span class="cx">     CheckedBoolean tryReallocate(void *oldPtr, size_t oldBytes, size_t newBytes);
</span><span class="cx">     void* forceAllocate(size_t bytes);
</span><span class="cx">     CopiedBlock* resetCurrentBlock();
</span><span class="lines">@@ -93,6 +94,14 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline CheckedBoolean CopiedAllocator::tryAllocateDuringCopying(size_t bytes, void** outPtr)
+{
+    if (!tryAllocate(bytes, outPtr))
+        return false;
+    m_currentBlock-&gt;reportLiveBytesDuringCopying(bytes);
+    return true;
+}
+
</ins><span class="cx"> inline CheckedBoolean CopiedAllocator::tryReallocate(
</span><span class="cx">     void* oldPtr, size_t oldBytes, size_t newBytes)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedBlock.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedBlock.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopiedBlock.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -49,10 +49,14 @@
</span><span class="cx">     void pin();
</span><span class="cx">     bool isPinned();
</span><span class="cx"> 
</span><ins>+    bool isOld();
</ins><span class="cx">     bool isOversize();
</span><ins>+    void didPromote();
</ins><span class="cx"> 
</span><span class="cx">     unsigned liveBytes();
</span><del>-    void reportLiveBytes(JSCell*, CopyToken, unsigned);
</del><ins>+    bool shouldReportLiveBytes(SpinLockHolder&amp;, JSCell* owner);
+    void reportLiveBytes(SpinLockHolder&amp;, JSCell*, CopyToken, unsigned);
+    void reportLiveBytesDuringCopying(unsigned);
</ins><span class="cx">     void didSurviveGC();
</span><span class="cx">     void didEvacuateBytes(unsigned);
</span><span class="cx">     bool shouldEvacuate();
</span><span class="lines">@@ -81,6 +85,7 @@
</span><span class="cx"> 
</span><span class="cx">     bool hasWorkList();
</span><span class="cx">     CopyWorkList&amp; workList();
</span><ins>+    SpinLock&amp; workListLock() { return m_workListLock; }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     CopiedBlock(Region*);
</span><span class="lines">@@ -88,13 +93,12 @@
</span><span class="cx"> 
</span><span class="cx">     void checkConsistency();
</span><span class="cx"> 
</span><del>-#if ENABLE(PARALLEL_GC)
</del><span class="cx">     SpinLock m_workListLock;
</span><del>-#endif
</del><span class="cx">     OwnPtr&lt;CopyWorkList&gt; m_workList;
</span><span class="cx"> 
</span><span class="cx">     size_t m_remaining;
</span><del>-    uintptr_t m_isPinned;
</del><ins>+    bool m_isPinned : 1;
+    bool m_isOld : 1;
</ins><span class="cx">     unsigned m_liveBytes;
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     unsigned m_liveObjects;
</span><span class="lines">@@ -130,14 +134,13 @@
</span><span class="cx">     : HeapBlock&lt;CopiedBlock&gt;(region)
</span><span class="cx">     , m_remaining(payloadCapacity())
</span><span class="cx">     , m_isPinned(false)
</span><ins>+    , m_isOld(false)
</ins><span class="cx">     , m_liveBytes(0)
</span><span class="cx"> #ifndef NDEBUG
</span><span class="cx">     , m_liveObjects(0)
</span><span class="cx"> #endif
</span><span class="cx"> {
</span><del>-#if ENABLE(PARALLEL_GC)
</del><span class="cx">     m_workListLock.Init();
</span><del>-#endif
</del><span class="cx">     ASSERT(is8ByteAligned(reinterpret_cast&lt;void*&gt;(m_remaining)));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -156,6 +159,7 @@
</span><span class="cx"> inline void CopiedBlock::didEvacuateBytes(unsigned bytes)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(m_liveBytes &gt;= bytes);
</span><ins>+    ASSERT(m_liveObjects);
</ins><span class="cx">     checkConsistency();
</span><span class="cx">     m_liveBytes -= bytes;
</span><span class="cx"> #ifndef NDEBUG
</span><span class="lines">@@ -188,6 +192,16 @@
</span><span class="cx">     return m_isPinned;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool CopiedBlock::isOld()
+{
+    return m_isOld;
+}
+
+inline void CopiedBlock::didPromote()
+{
+    m_isOld = true;
+}
+
</ins><span class="cx"> inline bool CopiedBlock::isOversize()
</span><span class="cx"> {
</span><span class="cx">     return region()-&gt;isCustomSize();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedBlockInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopiedBlockInlines.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -26,21 +26,33 @@
</span><span class="cx"> #ifndef CopiedBlockInlines_h
</span><span class="cx"> #define CopiedBlockInlines_h
</span><span class="cx"> 
</span><ins>+#include &quot;ClassInfo.h&quot;
</ins><span class="cx"> #include &quot;CopiedBlock.h&quot;
</span><span class="cx"> #include &quot;Heap.h&quot;
</span><ins>+#include &quot;MarkedBlock.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx">     
</span><del>-inline void CopiedBlock::reportLiveBytes(JSCell* owner, CopyToken token, unsigned bytes)
</del><ins>+inline bool CopiedBlock::shouldReportLiveBytes(SpinLockHolder&amp;, JSCell* owner)
</ins><span class="cx"> {
</span><del>-#if ENABLE(PARALLEL_GC)
-    SpinLockHolder locker(&amp;m_workListLock);
-#endif
</del><ins>+    // We want to add to live bytes if the owner isn't part of the remembered set or
+    // if this block was allocated during the last cycle. 
+    // If we always added live bytes we would double count for elements in the remembered
+    // set across collections. 
+    // If we didn't always add live bytes to new blocks, we'd get too few.
+    bool ownerIsRemembered = MarkedBlock::blockFor(owner)-&gt;isRemembered(owner);
+    return !ownerIsRemembered || !m_isOld;
+}
+
+inline void CopiedBlock::reportLiveBytes(SpinLockHolder&amp;, JSCell* owner, CopyToken token, unsigned bytes)
+{
+    checkConsistency();
</ins><span class="cx"> #ifndef NDEBUG
</span><del>-    checkConsistency();
</del><span class="cx">     m_liveObjects++;
</span><span class="cx"> #endif
</span><span class="cx">     m_liveBytes += bytes;
</span><ins>+    checkConsistency();
+    ASSERT(m_liveBytes &lt;= CopiedBlock::blockSize);
</ins><span class="cx"> 
</span><span class="cx">     if (isPinned())
</span><span class="cx">         return;
</span><span class="lines">@@ -56,6 +68,19 @@
</span><span class="cx">     m_workList-&gt;append(CopyWorklistItem(owner, token));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void CopiedBlock::reportLiveBytesDuringCopying(unsigned bytes)
+{
+    checkConsistency();
+    // This doesn't need to be locked because the thread that calls this function owns the current block.
+    m_isOld = true;
+#ifndef NDEBUG
+    m_liveObjects++;
+#endif
+    m_liveBytes += bytes;
+    checkConsistency();
+    ASSERT(m_liveBytes &lt;= CopiedBlock::blockSize);
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // CopiedBlockInlines_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedSpacecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -35,8 +35,6 @@
</span><span class="cx"> 
</span><span class="cx"> CopiedSpace::CopiedSpace(Heap* heap)
</span><span class="cx">     : m_heap(heap)
</span><del>-    , m_toSpace(0)
-    , m_fromSpace(0)
</del><span class="cx">     , m_inCopyingPhase(false)
</span><span class="cx">     , m_shouldDoCopyPhase(false)
</span><span class="cx">     , m_numberOfLoanedBlocks(0)
</span><span class="lines">@@ -46,21 +44,40 @@
</span><span class="cx"> 
</span><span class="cx"> CopiedSpace::~CopiedSpace()
</span><span class="cx"> {
</span><del>-    while (!m_toSpace-&gt;isEmpty())
-        m_heap-&gt;blockAllocator().deallocate(CopiedBlock::destroy(m_toSpace-&gt;removeHead()));
</del><ins>+    while (!m_oldGen.toSpace-&gt;isEmpty())
+        m_heap-&gt;blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.toSpace-&gt;removeHead()));
</ins><span class="cx"> 
</span><del>-    while (!m_fromSpace-&gt;isEmpty())
-        m_heap-&gt;blockAllocator().deallocate(CopiedBlock::destroy(m_fromSpace-&gt;removeHead()));
</del><ins>+    while (!m_oldGen.fromSpace-&gt;isEmpty())
+        m_heap-&gt;blockAllocator().deallocate(CopiedBlock::destroy(m_oldGen.fromSpace-&gt;removeHead()));
</ins><span class="cx"> 
</span><del>-    while (!m_oversizeBlocks.isEmpty())
-        m_heap-&gt;blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_oversizeBlocks.removeHead()));
</del><ins>+    while (!m_oldGen.oversizeBlocks.isEmpty())
+        m_heap-&gt;blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_oldGen.oversizeBlocks.removeHead()));
+
+    while (!m_newGen.toSpace-&gt;isEmpty())
+        m_heap-&gt;blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.toSpace-&gt;removeHead()));
+
+    while (!m_newGen.fromSpace-&gt;isEmpty())
+        m_heap-&gt;blockAllocator().deallocate(CopiedBlock::destroy(m_newGen.fromSpace-&gt;removeHead()));
+
+    while (!m_newGen.oversizeBlocks.isEmpty())
+        m_heap-&gt;blockAllocator().deallocateCustomSize(CopiedBlock::destroy(m_newGen.oversizeBlocks.removeHead()));
+
+    ASSERT(m_oldGen.toSpace-&gt;isEmpty());
+    ASSERT(m_oldGen.fromSpace-&gt;isEmpty());
+    ASSERT(m_oldGen.oversizeBlocks.isEmpty());
+    ASSERT(m_newGen.toSpace-&gt;isEmpty());
+    ASSERT(m_newGen.fromSpace-&gt;isEmpty());
+    ASSERT(m_newGen.oversizeBlocks.isEmpty());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CopiedSpace::init()
</span><span class="cx"> {
</span><del>-    m_toSpace = &amp;m_blocks1;
-    m_fromSpace = &amp;m_blocks2;
</del><ins>+    m_oldGen.toSpace = &amp;m_oldGen.blocks1;
+    m_oldGen.fromSpace = &amp;m_oldGen.blocks2;
</ins><span class="cx">     
</span><ins>+    m_newGen.toSpace = &amp;m_newGen.blocks1;
+    m_newGen.fromSpace = &amp;m_newGen.blocks2;
+
</ins><span class="cx">     allocateBlock();
</span><span class="cx"> }   
</span><span class="cx"> 
</span><span class="lines">@@ -83,9 +100,10 @@
</span><span class="cx">     ASSERT(isOversize(bytes));
</span><span class="cx">     
</span><span class="cx">     CopiedBlock* block = CopiedBlock::create(m_heap-&gt;blockAllocator().allocateCustomSize(sizeof(CopiedBlock) + bytes, CopiedBlock::blockSize));
</span><del>-    m_oversizeBlocks.push(block);
-    m_blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
</del><ins>+    m_newGen.oversizeBlocks.push(block);
+    m_newGen.blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
</ins><span class="cx">     m_blockSet.add(block);
</span><ins>+    ASSERT(!block-&gt;isOld());
</ins><span class="cx">     
</span><span class="cx">     CopiedAllocator allocator;
</span><span class="cx">     allocator.setCurrentBlock(block);
</span><span class="lines">@@ -138,7 +156,10 @@
</span><span class="cx"> 
</span><span class="cx">     CopiedBlock* oldBlock = CopiedSpace::blockFor(oldPtr);
</span><span class="cx">     if (oldBlock-&gt;isOversize()) {
</span><del>-        m_oversizeBlocks.remove(oldBlock);
</del><ins>+        if (oldBlock-&gt;isOld())
+            m_oldGen.oversizeBlocks.remove(oldBlock);
+        else
+            m_newGen.oversizeBlocks.remove(oldBlock);
</ins><span class="cx">         m_blockSet.remove(oldBlock);
</span><span class="cx">         m_heap-&gt;blockAllocator().deallocateCustomSize(CopiedBlock::destroy(oldBlock));
</span><span class="cx">     }
</span><span class="lines">@@ -165,10 +186,11 @@
</span><span class="cx">     block-&gt;zeroFillWilderness();
</span><span class="cx"> 
</span><span class="cx">     {
</span><ins>+        // Always put the block into the old gen because it's being promoted!
</ins><span class="cx">         SpinLockHolder locker(&amp;m_toSpaceLock);
</span><del>-        m_toSpace-&gt;push(block);
</del><ins>+        m_oldGen.toSpace-&gt;push(block);
</ins><span class="cx">         m_blockSet.add(block);
</span><del>-        m_blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
</del><ins>+        m_oldGen.blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     {
</span><span class="lines">@@ -181,52 +203,25 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CopiedSpace::startedCopying()
</del><ins>+void CopiedSpace::didStartFullCollection()
</ins><span class="cx"> {
</span><del>-    std::swap(m_fromSpace, m_toSpace);
</del><ins>+    ASSERT(heap()-&gt;operationInProgress() == FullCollection);
+    ASSERT(m_oldGen.fromSpace-&gt;isEmpty());
+    ASSERT(m_newGen.fromSpace-&gt;isEmpty());
</ins><span class="cx"> 
</span><del>-    m_blockFilter.reset();
-    m_allocator.resetCurrentBlock();
</del><ins>+#ifndef NDEBUG
+    for (CopiedBlock* block = m_newGen.toSpace-&gt;head(); block; block = block-&gt;next())
+        ASSERT(!block-&gt;liveBytes());
</ins><span class="cx"> 
</span><del>-    CopiedBlock* next = 0;
-    size_t totalLiveBytes = 0;
-    size_t totalUsableBytes = 0;
-    for (CopiedBlock* block = m_fromSpace-&gt;head(); block; block = next) {
-        next = block-&gt;next();
-        if (!block-&gt;isPinned() &amp;&amp; block-&gt;canBeRecycled()) {
-            recycleEvacuatedBlock(block);
-            continue;
-        }
-        totalLiveBytes += block-&gt;liveBytes();
-        totalUsableBytes += block-&gt;payloadCapacity();
-    }
</del><ins>+    for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block-&gt;next())
+        ASSERT(!block-&gt;liveBytes());
+#endif
</ins><span class="cx"> 
</span><del>-    CopiedBlock* block = m_oversizeBlocks.head();
-    while (block) {
-        CopiedBlock* next = block-&gt;next();
-        if (block-&gt;isPinned()) {
-            m_blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
-            totalLiveBytes += block-&gt;payloadCapacity();
-            totalUsableBytes += block-&gt;payloadCapacity();
-            block-&gt;didSurviveGC();
-        } else {
-            m_oversizeBlocks.remove(block);
-            m_blockSet.remove(block);
-            m_heap-&gt;blockAllocator().deallocateCustomSize(CopiedBlock::destroy(block));
-        } 
-        block = next;
-    }
</del><ins>+    for (CopiedBlock* block = m_oldGen.toSpace-&gt;head(); block; block = block-&gt;next())
+        block-&gt;didSurviveGC();
</ins><span class="cx"> 
</span><del>-    double markedSpaceBytes = m_heap-&gt;objectSpace().capacity();
-    double totalFragmentation = ((double)totalLiveBytes + markedSpaceBytes) / ((double)totalUsableBytes + markedSpaceBytes);
-    m_shouldDoCopyPhase = totalFragmentation &lt;= Options::minHeapUtilization();
-    if (!m_shouldDoCopyPhase)
-        return;
-
-    ASSERT(m_shouldDoCopyPhase);
-    ASSERT(!m_inCopyingPhase);
-    ASSERT(!m_numberOfLoanedBlocks);
-    m_inCopyingPhase = true;
</del><ins>+    for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block-&gt;next())
+        block-&gt;didSurviveGC();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CopiedSpace::doneCopying()
</span><span class="lines">@@ -240,22 +235,40 @@
</span><span class="cx">     ASSERT(m_inCopyingPhase == m_shouldDoCopyPhase);
</span><span class="cx">     m_inCopyingPhase = false;
</span><span class="cx"> 
</span><del>-    while (!m_fromSpace-&gt;isEmpty()) {
-        CopiedBlock* block = m_fromSpace-&gt;removeHead();
-        // All non-pinned blocks in from-space should have been reclaimed as they were evacuated.
-        ASSERT(block-&gt;isPinned() || !m_shouldDoCopyPhase);
-        block-&gt;didSurviveGC();
</del><ins>+    DoublyLinkedList&lt;CopiedBlock&gt;* toSpace;
+    DoublyLinkedList&lt;CopiedBlock&gt;* fromSpace;
+    TinyBloomFilter* blockFilter;
+    if (heap()-&gt;operationInProgress() == FullCollection) {
+        toSpace = m_oldGen.toSpace;
+        fromSpace = m_oldGen.fromSpace;
+        blockFilter = &amp;m_oldGen.blockFilter;
+    } else {
+        toSpace = m_newGen.toSpace;
+        fromSpace = m_newGen.fromSpace;
+        blockFilter = &amp;m_newGen.blockFilter;
+    }
+
+    while (!fromSpace-&gt;isEmpty()) {
+        CopiedBlock* block = fromSpace-&gt;removeHead();
</ins><span class="cx">         // We don't add the block to the blockSet because it was never removed.
</span><span class="cx">         ASSERT(m_blockSet.contains(block));
</span><del>-        m_blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
-        m_toSpace-&gt;push(block);
</del><ins>+        blockFilter-&gt;add(reinterpret_cast&lt;Bits&gt;(block));
+        toSpace-&gt;push(block);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!m_toSpace-&gt;head())
-        allocateBlock();
-    else
-        m_allocator.setCurrentBlock(m_toSpace-&gt;head());
</del><ins>+    if (heap()-&gt;operationInProgress() == EdenCollection) {
+        m_oldGen.toSpace-&gt;append(*m_newGen.toSpace);
+        m_oldGen.oversizeBlocks.append(m_newGen.oversizeBlocks);
+        m_oldGen.blockFilter.add(m_newGen.blockFilter);
+        m_newGen.blockFilter.reset();
+    }
</ins><span class="cx"> 
</span><ins>+    ASSERT(m_newGen.toSpace-&gt;isEmpty());
+    ASSERT(m_newGen.fromSpace-&gt;isEmpty());
+    ASSERT(m_newGen.oversizeBlocks.isEmpty());
+
+    allocateBlock();
+
</ins><span class="cx">     m_shouldDoCopyPhase = false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -263,15 +276,24 @@
</span><span class="cx"> {
</span><span class="cx">     size_t calculatedSize = 0;
</span><span class="cx"> 
</span><del>-    for (CopiedBlock* block = m_toSpace-&gt;head(); block; block = block-&gt;next())
</del><ins>+    for (CopiedBlock* block = m_oldGen.toSpace-&gt;head(); block; block = block-&gt;next())
</ins><span class="cx">         calculatedSize += block-&gt;size();
</span><span class="cx"> 
</span><del>-    for (CopiedBlock* block = m_fromSpace-&gt;head(); block; block = block-&gt;next())
</del><ins>+    for (CopiedBlock* block = m_oldGen.fromSpace-&gt;head(); block; block = block-&gt;next())
</ins><span class="cx">         calculatedSize += block-&gt;size();
</span><span class="cx"> 
</span><del>-    for (CopiedBlock* block = m_oversizeBlocks.head(); block; block = block-&gt;next())
</del><ins>+    for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block-&gt;next())
</ins><span class="cx">         calculatedSize += block-&gt;size();
</span><span class="cx"> 
</span><ins>+    for (CopiedBlock* block = m_newGen.toSpace-&gt;head(); block; block = block-&gt;next())
+        calculatedSize += block-&gt;size();
+
+    for (CopiedBlock* block = m_newGen.fromSpace-&gt;head(); block; block = block-&gt;next())
+        calculatedSize += block-&gt;size();
+
+    for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block-&gt;next())
+        calculatedSize += block-&gt;size();
+
</ins><span class="cx">     return calculatedSize;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -279,15 +301,24 @@
</span><span class="cx"> {
</span><span class="cx">     size_t calculatedCapacity = 0;
</span><span class="cx"> 
</span><del>-    for (CopiedBlock* block = m_toSpace-&gt;head(); block; block = block-&gt;next())
</del><ins>+    for (CopiedBlock* block = m_oldGen.toSpace-&gt;head(); block; block = block-&gt;next())
</ins><span class="cx">         calculatedCapacity += block-&gt;capacity();
</span><span class="cx"> 
</span><del>-    for (CopiedBlock* block = m_fromSpace-&gt;head(); block; block = block-&gt;next())
</del><ins>+    for (CopiedBlock* block = m_oldGen.fromSpace-&gt;head(); block; block = block-&gt;next())
</ins><span class="cx">         calculatedCapacity += block-&gt;capacity();
</span><span class="cx"> 
</span><del>-    for (CopiedBlock* block = m_oversizeBlocks.head(); block; block = block-&gt;next())
</del><ins>+    for (CopiedBlock* block = m_oldGen.oversizeBlocks.head(); block; block = block-&gt;next())
</ins><span class="cx">         calculatedCapacity += block-&gt;capacity();
</span><span class="cx"> 
</span><ins>+    for (CopiedBlock* block = m_newGen.toSpace-&gt;head(); block; block = block-&gt;next())
+        calculatedCapacity += block-&gt;capacity();
+
+    for (CopiedBlock* block = m_newGen.fromSpace-&gt;head(); block; block = block-&gt;next())
+        calculatedCapacity += block-&gt;capacity();
+
+    for (CopiedBlock* block = m_newGen.oversizeBlocks.head(); block; block = block-&gt;next())
+        calculatedCapacity += block-&gt;capacity();
+
</ins><span class="cx">     return calculatedCapacity;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -311,22 +342,12 @@
</span><span class="cx"> 
</span><span class="cx"> bool CopiedSpace::isPagedOut(double deadline)
</span><span class="cx"> {
</span><del>-    return isBlockListPagedOut(deadline, m_toSpace) 
-        || isBlockListPagedOut(deadline, m_fromSpace) 
-        || isBlockListPagedOut(deadline, &amp;m_oversizeBlocks);
</del><ins>+    return isBlockListPagedOut(deadline, m_oldGen.toSpace) 
+        || isBlockListPagedOut(deadline, m_oldGen.fromSpace) 
+        || isBlockListPagedOut(deadline, &amp;m_oldGen.oversizeBlocks)
+        || isBlockListPagedOut(deadline, m_newGen.toSpace) 
+        || isBlockListPagedOut(deadline, m_newGen.fromSpace) 
+        || isBlockListPagedOut(deadline, &amp;m_newGen.oversizeBlocks);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CopiedSpace::didStartFullCollection()
-{
-    ASSERT(heap()-&gt;operationInProgress() == FullCollection);
-
-    ASSERT(m_fromSpace-&gt;isEmpty());
-
-    for (CopiedBlock* block = m_toSpace-&gt;head(); block; block = block-&gt;next())
-        block-&gt;didSurviveGC();
-
-    for (CopiedBlock* block = m_oversizeBlocks.head(); block; block = block-&gt;next())
-        block-&gt;didSurviveGC();
-}
-
</del><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedSpaceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedSpace.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedSpace.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopiedSpace.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #include &quot;CopiedAllocator.h&quot;
</span><span class="cx"> #include &quot;HeapBlock.h&quot;
</span><ins>+#include &quot;HeapOperation.h&quot;
</ins><span class="cx"> #include &quot;TinyBloomFilter.h&quot;
</span><span class="cx"> #include &lt;wtf/Assertions.h&gt;
</span><span class="cx"> #include &lt;wtf/CheckedBoolean.h&gt;
</span><span class="lines">@@ -62,7 +63,10 @@
</span><span class="cx"> 
</span><span class="cx">     void didStartFullCollection();
</span><span class="cx"> 
</span><ins>+    template &lt;HeapOperation collectionType&gt;
</ins><span class="cx">     void startedCopying();
</span><ins>+    void startedEdenCopy();
+    void startedFullCopy();
</ins><span class="cx">     void doneCopying();
</span><span class="cx">     bool isInCopyPhase() { return m_inCopyingPhase; }
</span><span class="cx"> 
</span><span class="lines">@@ -95,24 +99,36 @@
</span><span class="cx">     CopiedBlock* allocateBlockForCopyingPhase();
</span><span class="cx"> 
</span><span class="cx">     void doneFillingBlock(CopiedBlock*, CopiedBlock**);
</span><del>-    void recycleEvacuatedBlock(CopiedBlock*);
</del><ins>+    void recycleEvacuatedBlock(CopiedBlock*, HeapOperation collectionType);
</ins><span class="cx">     void recycleBorrowedBlock(CopiedBlock*);
</span><span class="cx"> 
</span><span class="cx">     Heap* m_heap;
</span><span class="cx"> 
</span><span class="cx">     CopiedAllocator m_allocator;
</span><span class="cx"> 
</span><del>-    TinyBloomFilter m_blockFilter;
</del><span class="cx">     HashSet&lt;CopiedBlock*&gt; m_blockSet;
</span><span class="cx"> 
</span><span class="cx">     SpinLock m_toSpaceLock;
</span><span class="cx"> 
</span><del>-    DoublyLinkedList&lt;CopiedBlock&gt;* m_toSpace;
-    DoublyLinkedList&lt;CopiedBlock&gt;* m_fromSpace;
-    
-    DoublyLinkedList&lt;CopiedBlock&gt; m_blocks1;
-    DoublyLinkedList&lt;CopiedBlock&gt; m_blocks2;
-    DoublyLinkedList&lt;CopiedBlock&gt; m_oversizeBlocks;
</del><ins>+    struct CopiedGeneration {
+        CopiedGeneration()
+            : toSpace(0)
+            , fromSpace(0)
+        {
+        }
+
+        DoublyLinkedList&lt;CopiedBlock&gt;* toSpace;
+        DoublyLinkedList&lt;CopiedBlock&gt;* fromSpace;
+        
+        DoublyLinkedList&lt;CopiedBlock&gt; blocks1;
+        DoublyLinkedList&lt;CopiedBlock&gt; blocks2;
+        DoublyLinkedList&lt;CopiedBlock&gt; oversizeBlocks;
+
+        TinyBloomFilter blockFilter;
+    };
+
+    CopiedGeneration m_oldGen;
+    CopiedGeneration m_newGen;
</ins><span class="cx">    
</span><span class="cx">     bool m_inCopyingPhase;
</span><span class="cx">     bool m_shouldDoCopyPhase;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedSpaceInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -37,7 +37,8 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool CopiedSpace::contains(CopiedBlock* block)
</span><span class="cx"> {
</span><del>-    return !m_blockFilter.ruleOut(reinterpret_cast&lt;Bits&gt;(block)) &amp;&amp; m_blockSet.contains(block);
</del><ins>+    return (!m_newGen.blockFilter.ruleOut(reinterpret_cast&lt;Bits&gt;(block)) || !m_oldGen.blockFilter.ruleOut(reinterpret_cast&lt;Bits&gt;(block)))
+        &amp;&amp; m_blockSet.contains(block);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool CopiedSpace::contains(void* ptr, CopiedBlock*&amp; result)
</span><span class="lines">@@ -92,7 +93,7 @@
</span><span class="cx">         pin(block);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline void CopiedSpace::recycleEvacuatedBlock(CopiedBlock* block)
</del><ins>+inline void CopiedSpace::recycleEvacuatedBlock(CopiedBlock* block, HeapOperation collectionType)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(block);
</span><span class="cx">     ASSERT(block-&gt;canBeRecycled());
</span><span class="lines">@@ -100,7 +101,10 @@
</span><span class="cx">     {
</span><span class="cx">         SpinLockHolder locker(&amp;m_toSpaceLock);
</span><span class="cx">         m_blockSet.remove(block);
</span><del>-        m_fromSpace-&gt;remove(block);
</del><ins>+        if (collectionType == EdenCollection)
+            m_newGen.fromSpace-&gt;remove(block);
+        else
+            m_oldGen.fromSpace-&gt;remove(block);
</ins><span class="cx">     }
</span><span class="cx">     m_heap-&gt;blockAllocator().deallocate(CopiedBlock::destroy(block));
</span><span class="cx"> }
</span><span class="lines">@@ -141,8 +145,8 @@
</span><span class="cx">     
</span><span class="cx">     CopiedBlock* block = CopiedBlock::create(m_heap-&gt;blockAllocator().allocate&lt;CopiedBlock&gt;());
</span><span class="cx">         
</span><del>-    m_toSpace-&gt;push(block);
-    m_blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
</del><ins>+    m_newGen.toSpace-&gt;push(block);
+    m_newGen.blockFilter.add(reinterpret_cast&lt;Bits&gt;(block));
</ins><span class="cx">     m_blockSet.add(block);
</span><span class="cx">     m_allocator.setCurrentBlock(block);
</span><span class="cx"> }
</span><span class="lines">@@ -174,6 +178,85 @@
</span><span class="cx">     return reinterpret_cast&lt;CopiedBlock*&gt;(reinterpret_cast&lt;size_t&gt;(ptr) &amp; s_blockMask);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template &lt;HeapOperation collectionType&gt;
+inline void CopiedSpace::startedCopying()
+{
+    DoublyLinkedList&lt;CopiedBlock&gt;* fromSpace;
+    DoublyLinkedList&lt;CopiedBlock&gt;* oversizeBlocks;
+    TinyBloomFilter* blockFilter;
+    if (collectionType == FullCollection) {
+        ASSERT(m_oldGen.fromSpace-&gt;isEmpty());
+        ASSERT(m_newGen.fromSpace-&gt;isEmpty());
+
+        m_oldGen.toSpace-&gt;append(*m_newGen.toSpace);
+        m_oldGen.oversizeBlocks.append(m_newGen.oversizeBlocks);
+
+        ASSERT(m_newGen.toSpace-&gt;isEmpty());
+        ASSERT(m_newGen.fromSpace-&gt;isEmpty());
+        ASSERT(m_newGen.oversizeBlocks.isEmpty());
+
+        std::swap(m_oldGen.fromSpace, m_oldGen.toSpace);
+        fromSpace = m_oldGen.fromSpace;
+        oversizeBlocks = &amp;m_oldGen.oversizeBlocks;
+        blockFilter = &amp;m_oldGen.blockFilter;
+    } else {
+        std::swap(m_newGen.fromSpace, m_newGen.toSpace);
+        fromSpace = m_newGen.fromSpace;
+        oversizeBlocks = &amp;m_newGen.oversizeBlocks;
+        blockFilter = &amp;m_newGen.blockFilter;
+    }
+
+    blockFilter-&gt;reset();
+    m_allocator.resetCurrentBlock();
+
+    CopiedBlock* next = 0;
+    size_t totalLiveBytes = 0;
+    size_t totalUsableBytes = 0;
+    for (CopiedBlock* block = fromSpace-&gt;head(); block; block = next) {
+        next = block-&gt;next();
+        if (!block-&gt;isPinned() &amp;&amp; block-&gt;canBeRecycled()) {
+            recycleEvacuatedBlock(block, collectionType);
+            continue;
+        }
+        ASSERT(block-&gt;liveBytes() &lt;= CopiedBlock::blockSize);
+        totalLiveBytes += block-&gt;liveBytes();
+        totalUsableBytes += block-&gt;payloadCapacity();
+        block-&gt;didPromote();
+    }
+
+    CopiedBlock* block = oversizeBlocks-&gt;head();
+    while (block) {
+        CopiedBlock* next = block-&gt;next();
+        if (block-&gt;isPinned()) {
+            blockFilter-&gt;add(reinterpret_cast&lt;Bits&gt;(block));
+            totalLiveBytes += block-&gt;payloadCapacity();
+            totalUsableBytes += block-&gt;payloadCapacity();
+            block-&gt;didPromote();
+        } else {
+            oversizeBlocks-&gt;remove(block);
+            m_blockSet.remove(block);
+            m_heap-&gt;blockAllocator().deallocateCustomSize(CopiedBlock::destroy(block));
+        } 
+        block = next;
+    }
+
+    double markedSpaceBytes = m_heap-&gt;objectSpace().capacity();
+    double totalFragmentation = static_cast&lt;double&gt;(totalLiveBytes + markedSpaceBytes) / static_cast&lt;double&gt;(totalUsableBytes + markedSpaceBytes);
+    m_shouldDoCopyPhase = m_heap-&gt;operationInProgress() == EdenCollection || totalFragmentation &lt;= Options::minHeapUtilization();
+    if (!m_shouldDoCopyPhase) {
+        if (Options::logGC())
+            dataLog(&quot;Skipped copying, &quot;);
+        return;
+    }
+
+    if (Options::logGC())
+        dataLogF(&quot;Did copy, &quot;);
+    ASSERT(m_shouldDoCopyPhase);
+    ASSERT(!m_numberOfLoanedBlocks);
+    ASSERT(!m_inCopyingPhase);
+    m_inCopyingPhase = true;
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // CopiedSpaceInlines_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopyVisitorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopyVisitor.cpp (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopyVisitor.cpp        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopyVisitor.cpp        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -57,7 +57,7 @@
</span><span class="cx">                 visitItem(*it);
</span><span class="cx"> 
</span><span class="cx">             ASSERT(!block-&gt;liveBytes());
</span><del>-            m_shared.m_copiedSpace-&gt;recycleEvacuatedBlock(block);
</del><ins>+            m_shared.m_copiedSpace-&gt;recycleEvacuatedBlock(block, m_shared.m_vm-&gt;heap.operationInProgress());
</ins><span class="cx">         }
</span><span class="cx">         m_shared.getNextBlocksToCopy(next, end);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopyVisitorInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopyVisitorInlines.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopyVisitorInlines.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/CopyVisitorInlines.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -55,7 +55,7 @@
</span><span class="cx"> inline void* CopyVisitor::allocateNewSpace(size_t bytes)
</span><span class="cx"> {
</span><span class="cx">     void* result = 0; // Compilers don't realize that this will be assigned.
</span><del>-    if (LIKELY(m_copiedAllocator.tryAllocate(bytes, &amp;result)))
</del><ins>+    if (LIKELY(m_copiedAllocator.tryAllocateDuringCopying(bytes, &amp;result)))
</ins><span class="cx">         return result;
</span><span class="cx">     
</span><span class="cx">     result = allocateNewSpaceSlow(bytes);
</span><span class="lines">@@ -70,7 +70,7 @@
</span><span class="cx">     m_copiedAllocator.setCurrentBlock(newBlock);
</span><span class="cx"> 
</span><span class="cx">     void* result = 0;
</span><del>-    CheckedBoolean didSucceed = m_copiedAllocator.tryAllocate(bytes, &amp;result);
</del><ins>+    CheckedBoolean didSucceed = m_copiedAllocator.tryAllocateDuringCopying(bytes, &amp;result);
</ins><span class="cx">     ASSERT(didSucceed);
</span><span class="cx">     return result;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapGCThreadSharedDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/GCThreadSharedData.cpp        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -181,7 +181,15 @@
</span><span class="cx"> {
</span><span class="cx">     {
</span><span class="cx">         SpinLockHolder locker(&amp;m_copyLock);
</span><del>-        WTF::copyToVector(m_copiedSpace-&gt;m_blockSet, m_blocksToCopy);
</del><ins>+        if (m_vm-&gt;heap.operationInProgress() == EdenCollection) {
+            // Reset the vector to be empty, but don't throw away the backing store.
+            m_blocksToCopy.shrink(0);
+            for (CopiedBlock* block = m_copiedSpace-&gt;m_newGen.fromSpace-&gt;head(); block; block = block-&gt;next())
+                m_blocksToCopy.append(block);
+        } else {
+            ASSERT(m_vm-&gt;heap.operationInProgress() == FullCollection);
+            WTF::copyToVector(m_copiedSpace-&gt;m_blockSet, m_blocksToCopy);
+        }
</ins><span class="cx">         m_copyIndex = 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -641,10 +641,7 @@
</span><span class="cx"> template &lt;HeapOperation collectionType&gt;
</span><span class="cx"> void Heap::copyBackingStores()
</span><span class="cx"> {
</span><del>-    if (collectionType == EdenCollection)
-        return;
-
-    m_storageSpace.startedCopying();
</del><ins>+    m_storageSpace.startedCopying&lt;collectionType&gt;();
</ins><span class="cx">     if (m_storageSpace.shouldDoCopyPhase()) {
</span><span class="cx">         m_sharedData.didStartCopying();
</span><span class="cx">         m_copyVisitor.startCopying();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapSlotVisitorInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -225,18 +225,17 @@
</span><span class="cx"> inline void SlotVisitor::copyLater(JSCell* owner, CopyToken token, void* ptr, size_t bytes)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(bytes);
</span><del>-    // We don't do any copying during EdenCollections.
-    ASSERT(heap()-&gt;operationInProgress() != EdenCollection);
-
-    m_bytesCopied += bytes;
-
</del><span class="cx">     CopiedBlock* block = CopiedSpace::blockFor(ptr);
</span><span class="cx">     if (block-&gt;isOversize()) {
</span><span class="cx">         m_shared.m_copiedSpace-&gt;pin(block);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    block-&gt;reportLiveBytes(owner, token, bytes);
</del><ins>+    SpinLockHolder locker(&amp;block-&gt;workListLock());
+    if (heap()-&gt;operationInProgress() == FullCollection || block-&gt;shouldReportLiveBytes(locker, owner)) {
+        m_bytesCopied += bytes;
+        block-&gt;reportLiveBytes(locker, owner, token, bytes);
+    }
</ins><span class="cx"> }
</span><span class="cx">     
</span><span class="cx"> inline void SlotVisitor::reportExtraMemoryUsage(JSCell* owner, size_t size)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapTinyBloomFilterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/TinyBloomFilter.h (162016 => 162017)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/TinyBloomFilter.h        2014-01-14 23:01:33 UTC (rev 162016)
+++ trunk/Source/JavaScriptCore/heap/TinyBloomFilter.h        2014-01-14 23:03:01 UTC (rev 162017)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx">     TinyBloomFilter();
</span><span class="cx"> 
</span><span class="cx">     void add(Bits);
</span><ins>+    void add(TinyBloomFilter&amp;);
</ins><span class="cx">     bool ruleOut(Bits) const; // True for 0.
</span><span class="cx">     void reset();
</span><span class="cx"> 
</span><span class="lines">@@ -52,6 +53,11 @@
</span><span class="cx">     m_bits |= bits;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline void TinyBloomFilter::add(TinyBloomFilter&amp; other)
+{
+    m_bits |= other.m_bits;
+}
+
</ins><span class="cx"> inline bool TinyBloomFilter::ruleOut(Bits bits) const
</span><span class="cx"> {
</span><span class="cx">     if (!bits)
</span></span></pre>
</div>
</div>

</body>
</html>