<!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>[191240] 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/191240">191240</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-10-17 10:26:24 -0700 (Sat, 17 Oct 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Fix some generational heap growth pathologies
https://bugs.webkit.org/show_bug.cgi?id=150270

Reviewed by Andreas Kling.

When doing generational copying, we would pretend that the size of old space was increased
just by the amount of bytes we copied. In reality, it would be increased by the number of
bytes used by the copied blocks we created. This is a larger number, and in some simple
pathological programs, the difference can be huge.

Fixing this bug was relatively easy, and the only really meaningful change here is in
Heap::updateAllocationLimits(). But to convince myself that the change was valid, I had to
add some debugging code and I had to refactor some stuff so that it made more sense.

This change does obviate the need for m_totalBytesCopied, because we no longer use it in
release builds to decide how much heap we are using at the end of collection. But I added a
FIXME about how we could restore our use of m_totalBytesCopied. So, I kept the logic, for
now. The FIXME references https://bugs.webkit.org/show_bug.cgi?id=150268.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* heap/CopiedBlock.cpp: Added.
(JSC::CopiedBlock::createNoZeroFill):
(JSC::CopiedBlock::destroy):
(JSC::CopiedBlock::create):
(JSC::CopiedBlock::zeroFillWilderness):
(JSC::CopiedBlock::CopiedBlock):
* heap/CopiedBlock.h:
(JSC::CopiedBlock::didSurviveGC):
(JSC::CopiedBlock::createNoZeroFill): Deleted.
(JSC::CopiedBlock::destroy): Deleted.
(JSC::CopiedBlock::create): Deleted.
(JSC::CopiedBlock::zeroFillWilderness): Deleted.
(JSC::CopiedBlock::CopiedBlock): Deleted.
* heap/CopiedSpaceInlines.h:
(JSC::CopiedSpace::startedCopying):
* heap/Heap.cpp:
(JSC::Heap::updateObjectCounts):
(JSC::Heap::resetVisitors):
(JSC::Heap::capacity):
(JSC::Heap::protectedGlobalObjectCount):
(JSC::Heap::collectImpl):
(JSC::Heap::willStartCollection):
(JSC::Heap::updateAllocationLimits):
(JSC::Heap::didFinishCollection):
(JSC::Heap::sizeAfterCollect): Deleted.
* heap/Heap.h:
* heap/HeapInlines.h:
(JSC::Heap::shouldCollect):
(JSC::Heap::isBusy):
(JSC::Heap::collectIfNecessaryOrDefer):
* heap/MarkedBlock.cpp:
(JSC::MarkedBlock::create):
(JSC::MarkedBlock::destroy):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedBlockh">trunk/Source/JavaScriptCore/heap/CopiedBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedSpaceInlinesh">trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapInlinesh">trunk/Source/JavaScriptCore/heap/HeapInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMarkedBlockcpp">trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreheapCopiedBlockcpp">trunk/Source/JavaScriptCore/heap/CopiedBlock.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -288,6 +288,7 @@
</span><span class="cx"> 
</span><span class="cx">     heap/CodeBlockSet.cpp
</span><span class="cx">     heap/ConservativeRoots.cpp
</span><ins>+    heap/CopiedBlock.cpp
</ins><span class="cx">     heap/CopiedSpace.cpp
</span><span class="cx">     heap/CopyVisitor.cpp
</span><span class="cx">     heap/DeferGC.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -1,3 +1,60 @@
</span><ins>+2015-10-17  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Fix some generational heap growth pathologies
+        https://bugs.webkit.org/show_bug.cgi?id=150270
+
+        Reviewed by Andreas Kling.
+
+        When doing generational copying, we would pretend that the size of old space was increased
+        just by the amount of bytes we copied. In reality, it would be increased by the number of
+        bytes used by the copied blocks we created. This is a larger number, and in some simple
+        pathological programs, the difference can be huge.
+
+        Fixing this bug was relatively easy, and the only really meaningful change here is in
+        Heap::updateAllocationLimits(). But to convince myself that the change was valid, I had to
+        add some debugging code and I had to refactor some stuff so that it made more sense.
+
+        This change does obviate the need for m_totalBytesCopied, because we no longer use it in
+        release builds to decide how much heap we are using at the end of collection. But I added a
+        FIXME about how we could restore our use of m_totalBytesCopied. So, I kept the logic, for
+        now. The FIXME references https://bugs.webkit.org/show_bug.cgi?id=150268.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * heap/CopiedBlock.cpp: Added.
+        (JSC::CopiedBlock::createNoZeroFill):
+        (JSC::CopiedBlock::destroy):
+        (JSC::CopiedBlock::create):
+        (JSC::CopiedBlock::zeroFillWilderness):
+        (JSC::CopiedBlock::CopiedBlock):
+        * heap/CopiedBlock.h:
+        (JSC::CopiedBlock::didSurviveGC):
+        (JSC::CopiedBlock::createNoZeroFill): Deleted.
+        (JSC::CopiedBlock::destroy): Deleted.
+        (JSC::CopiedBlock::create): Deleted.
+        (JSC::CopiedBlock::zeroFillWilderness): Deleted.
+        (JSC::CopiedBlock::CopiedBlock): Deleted.
+        * heap/CopiedSpaceInlines.h:
+        (JSC::CopiedSpace::startedCopying):
+        * heap/Heap.cpp:
+        (JSC::Heap::updateObjectCounts):
+        (JSC::Heap::resetVisitors):
+        (JSC::Heap::capacity):
+        (JSC::Heap::protectedGlobalObjectCount):
+        (JSC::Heap::collectImpl):
+        (JSC::Heap::willStartCollection):
+        (JSC::Heap::updateAllocationLimits):
+        (JSC::Heap::didFinishCollection):
+        (JSC::Heap::sizeAfterCollect): Deleted.
+        * heap/Heap.h:
+        * heap/HeapInlines.h:
+        (JSC::Heap::shouldCollect):
+        (JSC::Heap::isBusy):
+        (JSC::Heap::collectIfNecessaryOrDefer):
+        * heap/MarkedBlock.cpp:
+        (JSC::MarkedBlock::create):
+        (JSC::MarkedBlock::destroy):
+
</ins><span class="cx"> 2015-10-16  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ES6] Implement String.prototype.normalize
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -514,6 +514,7 @@
</span><span class="cx">                 0FB7F39C15ED8E4600F167B2 /* PropertyStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FB7F39D15ED8E4600F167B2 /* Reject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39115ED8E3800F167B2 /* Reject.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FB7F39E15ED8E4600F167B2 /* SparseArrayValueMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB7F39215ED8E3800F167B2 /* SparseArrayValueMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0FBADF541BD1F4B800E073C1 /* CopiedBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBADF531BD1F4B800E073C1 /* CopiedBlock.cpp */; };
</ins><span class="cx">                 0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */; };
</span><span class="cx">                 0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FBD7E691447999600481315 /* CodeOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBD7E671447998F00481315 /* CodeOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -2377,6 +2378,7 @@
</span><span class="cx">                 0FB7F39015ED8E3800F167B2 /* PropertyStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyStorage.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FB7F39115ED8E3800F167B2 /* Reject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Reject.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FB7F39215ED8E3800F167B2 /* SparseArrayValueMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SparseArrayValueMap.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FBADF531BD1F4B800E073C1 /* CopiedBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopiedBlock.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGExitProfile.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGExitProfile.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FBD7E671447998F00481315 /* CodeOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeOrigin.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4244,6 +4246,7 @@
</span><span class="cx">                                 146B14DB12EB5B12001BEC1B /* ConservativeRoots.cpp */,
</span><span class="cx">                                 149DAAF212EB559D0083B12B /* ConservativeRoots.h */,
</span><span class="cx">                                 C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */,
</span><ins>+                                0FBADF531BD1F4B800E073C1 /* CopiedBlock.cpp */,
</ins><span class="cx">                                 C2C8D02E14A3CEFC00578E65 /* CopiedBlock.h */,
</span><span class="cx">                                 C2FC9BD216644DFB00810D33 /* CopiedBlockInlines.h */,
</span><span class="cx">                                 C240305314B404C90079EB64 /* CopiedSpace.cpp */,
</span><span class="lines">@@ -7828,6 +7831,7 @@
</span><span class="cx">                                 0F24E54C17EE274900ABB217 /* JITOperations.cpp in Sources */,
</span><span class="cx">                                 86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */,
</span><span class="cx">                                 A7C1E8E4112E72EF00A37F98 /* JITPropertyAccess32_64.cpp in Sources */,
</span><ins>+                                0FBADF541BD1F4B800E073C1 /* CopiedBlock.cpp in Sources */,
</ins><span class="cx">                                 0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */,
</span><span class="cx">                                 0F766D2B15A8CC38008F363E /* JITStubRoutineSet.cpp in Sources */,
</span><span class="cx">                                 0F5EF91E16878F7A003E5C25 /* JITThunks.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedBlockcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/heap/CopiedBlock.cpp (0 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedBlock.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/heap/CopiedBlock.cpp        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -0,0 +1,90 @@
</span><ins>+/*
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;CopiedBlock.h&quot;
+
+#include &lt;wtf/DataLog.h&gt;
+
+namespace JSC {
+
+static const bool computeBalance = false;
+static size_t balance;
+
+CopiedBlock* CopiedBlock::createNoZeroFill(size_t capacity)
+{
+    if (computeBalance) {
+        balance++;
+        if (!(balance % 10))
+            dataLog(&quot;CopiedBlock Balance: &quot;, balance, &quot;\n&quot;);
+    }
+    return new(NotNull, fastAlignedMalloc(CopiedBlock::blockSize, capacity)) CopiedBlock(capacity);
+}
+
+void CopiedBlock::destroy(CopiedBlock* copiedBlock)
+{
+    if (computeBalance) {
+        balance--;
+        if (!(balance % 10))
+            dataLog(&quot;CopiedBlock Balance: &quot;, balance, &quot;\n&quot;);
+    }
+    copiedBlock-&gt;~CopiedBlock();
+    fastAlignedFree(copiedBlock);
+}
+
+CopiedBlock* CopiedBlock::create(size_t capacity)
+{
+    CopiedBlock* newBlock = createNoZeroFill(capacity);
+    newBlock-&gt;zeroFillWilderness();
+    return newBlock;
+}
+
+void CopiedBlock::zeroFillWilderness()
+{
+#if USE(JSVALUE64)
+    memset(wilderness(), 0, wildernessSize());
+#else
+    JSValue emptyValue;
+    JSValue* limit = reinterpret_cast_ptr&lt;JSValue*&gt;(wildernessEnd());
+    for (JSValue* currentValue = reinterpret_cast_ptr&lt;JSValue*&gt;(wilderness()); currentValue &lt; limit; currentValue++)
+        *currentValue = emptyValue;
+#endif
+}
+
+CopiedBlock::CopiedBlock(size_t capacity)
+    : DoublyLinkedListNode&lt;CopiedBlock&gt;()
+    , m_capacity(capacity)
+    , m_remaining(payloadCapacity())
+    , m_isPinned(false)
+    , m_isOld(false)
+    , m_liveBytes(0)
+#ifndef NDEBUG
+    , m_liveObjects(0)
+#endif
+{
+    ASSERT(is8ByteAligned(reinterpret_cast&lt;void*&gt;(m_remaining)));
+}
+
+} // namespace JSC
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedBlock.h (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedBlock.h        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/heap/CopiedBlock.h        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -108,50 +108,6 @@
</span><span class="cx"> #endif
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-inline CopiedBlock* CopiedBlock::createNoZeroFill(size_t capacity)
-{
-    return new(NotNull, fastAlignedMalloc(CopiedBlock::blockSize, capacity)) CopiedBlock(capacity);
-}
-
-inline void CopiedBlock::destroy(CopiedBlock* copiedBlock)
-{
-    copiedBlock-&gt;~CopiedBlock();
-    fastAlignedFree(copiedBlock);
-}
-
-inline CopiedBlock* CopiedBlock::create(size_t capacity)
-{
-    CopiedBlock* newBlock = createNoZeroFill(capacity);
-    newBlock-&gt;zeroFillWilderness();
-    return newBlock;
-}
-
-inline void CopiedBlock::zeroFillWilderness()
-{
-#if USE(JSVALUE64)
-    memset(wilderness(), 0, wildernessSize());
-#else
-    JSValue emptyValue;
-    JSValue* limit = reinterpret_cast_ptr&lt;JSValue*&gt;(wildernessEnd());
-    for (JSValue* currentValue = reinterpret_cast_ptr&lt;JSValue*&gt;(wilderness()); currentValue &lt; limit; currentValue++)
-        *currentValue = emptyValue;
-#endif
-}
-
-inline CopiedBlock::CopiedBlock(size_t capacity)
-    : DoublyLinkedListNode&lt;CopiedBlock&gt;()
-    , m_capacity(capacity)
-    , m_remaining(payloadCapacity())
-    , m_isPinned(false)
-    , m_isOld(false)
-    , m_liveBytes(0)
-#ifndef NDEBUG
-    , m_liveObjects(0)
-#endif
-{
-    ASSERT(is8ByteAligned(reinterpret_cast&lt;void*&gt;(m_remaining)));
-}
-
</del><span class="cx"> inline void CopiedBlock::didSurviveGC()
</span><span class="cx"> {
</span><span class="cx">     checkConsistency();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCopiedSpaceInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/heap/CopiedSpaceInlines.h        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -237,8 +237,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     double markedSpaceBytes = m_heap-&gt;objectSpace().capacity();
</span><del>-    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();
</del><ins>+    double totalUtilization = static_cast&lt;double&gt;(totalLiveBytes + markedSpaceBytes) / static_cast&lt;double&gt;(totalUsableBytes + markedSpaceBytes);
+    m_shouldDoCopyPhase = m_heap-&gt;operationInProgress() == EdenCollection || totalUtilization &lt;= Options::minHeapUtilization();
</ins><span class="cx">     if (!m_shouldDoCopyPhase) {
</span><span class="cx">         if (Options::logGC())
</span><span class="cx">             dataLog(&quot;Skipped copying, &quot;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -864,11 +864,12 @@
</span><span class="cx">         m_totalBytesCopied = 0;
</span><span class="cx">     } else
</span><span class="cx">         m_totalBytesCopied -= bytesRemovedFromOldSpaceDueToReallocation;
</span><ins>+
+    m_totalBytesVisitedThisCycle = m_slotVisitor.bytesVisited() + threadBytesVisited();
+    m_totalBytesCopiedThisCycle = m_slotVisitor.bytesCopied() + threadBytesCopied();
</ins><span class="cx">     
</span><del>-    m_totalBytesVisited += m_slotVisitor.bytesVisited();
-    m_totalBytesCopied += m_slotVisitor.bytesCopied();
-    m_totalBytesVisited += threadBytesVisited();
-    m_totalBytesCopied += threadBytesCopied();
</del><ins>+    m_totalBytesVisited += m_totalBytesVisitedThisCycle;
+    m_totalBytesCopied += m_totalBytesCopiedThisCycle;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::resetVisitors()
</span><span class="lines">@@ -902,16 +903,6 @@
</span><span class="cx">     return m_objectSpace.capacity() + m_storageSpace.capacity() + extraMemorySize();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-size_t Heap::sizeAfterCollect()
-{
-    // The result here may not agree with the normal Heap::size(). 
-    // This is due to the fact that we only count live copied bytes
-    // rather than all used (including dead) copied bytes, thus it's 
-    // always the case that m_totalBytesCopied &lt;= m_storageSpace.size(). 
-    ASSERT(m_totalBytesCopied &lt;= m_storageSpace.size());
-    return m_totalBytesVisited + m_totalBytesCopied + extraMemorySize();
-}
-
</del><span class="cx"> size_t Heap::protectedGlobalObjectCount()
</span><span class="cx"> {
</span><span class="cx">     return forEachProtectedCell&lt;CountIfGlobalObject&gt;();
</span><span class="lines">@@ -1043,7 +1034,7 @@
</span><span class="cx">     
</span><span class="cx">     double before = 0;
</span><span class="cx">     if (Options::logGC()) {
</span><del>-        dataLog(&quot;[GC: &quot;);
</del><ins>+        dataLog(&quot;[GC: &quot;, capacity() / 1024, &quot; kb &quot;);
</ins><span class="cx">         before = currentTimeMS();
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -1137,6 +1128,10 @@
</span><span class="cx"> void Heap::willStartCollection(HeapOperation collectionType)
</span><span class="cx"> {
</span><span class="cx">     GCPHASE(StartingCollection);
</span><ins>+    
+    if (Options::logGC())
+        dataLog(&quot;=&gt; &quot;);
+    
</ins><span class="cx">     if (shouldDoFullCollection(collectionType)) {
</span><span class="cx">         m_operationInProgress = FullCollection;
</span><span class="cx">         m_shouldDoFullCollection = false;
</span><span class="lines">@@ -1273,7 +1268,42 @@
</span><span class="cx"> void Heap::updateAllocationLimits()
</span><span class="cx"> {
</span><span class="cx">     GCPHASE(UpdateAllocationLimits);
</span><del>-    size_t currentHeapSize = sizeAfterCollect();
</del><ins>+    
+    // Calculate our current heap size threshold for the purpose of figuring out when we should
+    // run another collection. This isn't the same as either size() or capacity(), though it should
+    // be somewhere between the two. The key is to match the size calculations involved calls to
+    // didAllocate(), while never dangerously underestimating capacity(). In extreme cases of
+    // fragmentation, we may have size() much smaller than capacity(). Our collector sometimes
+    // temporarily allows very high fragmentation because it doesn't defragment old blocks in copied
+    // space.
+    size_t currentHeapSize = 0;
+
+    // For marked space, we use the total number of bytes visited. This matches the logic for
+    // MarkedAllocator's calls to didAllocate(), which effectively accounts for the total size of
+    // objects allocated rather than blocks used. This will underestimate capacity(), and in case
+    // of fragmentation, this may be substantial. Fortunately, marked space rarely fragments because
+    // cells usually have a narrow range of sizes. So, the underestimation is probably OK.
+    currentHeapSize += m_totalBytesVisited;
+
+    // For copied space, we use the capacity of storage space. This is because copied space may get
+    // badly fragmented between full collections. This arises when each eden collection evacuates
+    // much less than one CopiedBlock's worth of stuff. It can also happen when CopiedBlocks get
+    // pinned due to very short-lived objects. In such a case, we want to get to a full collection
+    // sooner rather than later. If we used m_totalBytesCopied, then for for each CopiedBlock that an
+    // eden allocation promoted, we would only deduct the one object's size from eden size. This
+    // would mean that we could &quot;leak&quot; many CopiedBlocks before we did a full collection and
+    // defragmented all of them. It would be great to use m_totalBytesCopied, but we'd need to
+    // augment it with something that accounts for those fragmented blocks.
+    // FIXME: Make it possible to compute heap size using m_totalBytesCopied rather than
+    // m_storageSpace.capacity()
+    // https://bugs.webkit.org/show_bug.cgi?id=150268
+    ASSERT(m_totalBytesCopied &lt;= m_storageSpace.size());
+    currentHeapSize += m_storageSpace.capacity();
+
+    // It's up to the user to ensure that extraMemorySize() ends up corresponding to allocation-time
+    // extra memory reporting.
+    currentHeapSize += extraMemorySize();
+    
</ins><span class="cx">     if (Options::gcMaxHeapSize() &amp;&amp; currentHeapSize &gt; Options::gcMaxHeapSize())
</span><span class="cx">         HeapStatistics::exitWithFailure();
</span><span class="cx"> 
</span><span class="lines">@@ -1286,13 +1316,23 @@
</span><span class="cx">         m_sizeAfterLastFullCollect = currentHeapSize;
</span><span class="cx">         m_bytesAbandonedSinceLastFullCollect = 0;
</span><span class="cx">     } else {
</span><ins>+        static const bool verbose = false;
+        
</ins><span class="cx">         ASSERT(currentHeapSize &gt;= m_sizeAfterLastCollect);
</span><span class="cx">         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
</span><span class="cx">         m_sizeAfterLastEdenCollect = currentHeapSize;
</span><ins>+        if (verbose) {
+            dataLog(&quot;Max heap size: &quot;, m_maxHeapSize, &quot;\n&quot;);
+            dataLog(&quot;Current heap size: &quot;, currentHeapSize, &quot;\n&quot;);
+            dataLog(&quot;Size after last eden collection: &quot;, m_sizeAfterLastEdenCollect, &quot;\n&quot;);
+        }
</ins><span class="cx">         double edenToOldGenerationRatio = (double)m_maxEdenSize / (double)m_maxHeapSize;
</span><ins>+        if (verbose)
+            dataLog(&quot;Eden to old generation ratio: &quot;, edenToOldGenerationRatio, &quot;\n&quot;);
</ins><span class="cx">         double minEdenToOldGenerationRatio = 1.0 / 3.0;
</span><span class="cx">         if (edenToOldGenerationRatio &lt; minEdenToOldGenerationRatio)
</span><span class="cx">             m_shouldDoFullCollection = true;
</span><ins>+        // This seems suspect at first, but what it does is ensure that the nursery size is fixed.
</ins><span class="cx">         m_maxHeapSize += currentHeapSize - m_sizeAfterLastCollect;
</span><span class="cx">         m_maxEdenSize = m_maxHeapSize - currentHeapSize;
</span><span class="cx">         if (m_fullActivityCallback) {
</span><span class="lines">@@ -1305,7 +1345,7 @@
</span><span class="cx">     m_bytesAllocatedThisCycle = 0;
</span><span class="cx"> 
</span><span class="cx">     if (Options::logGC())
</span><del>-        dataLog(currentHeapSize / 1024, &quot; kb, &quot;);
</del><ins>+        dataLog(currentHeapSize / 1024, &quot; kb &quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::didFinishCollection(double gcStartTime)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -330,7 +330,6 @@
</span><span class="cx">     bool sweepNextLogicallyEmptyWeakBlock();
</span><span class="cx"> 
</span><span class="cx">     bool shouldDoFullCollection(HeapOperation requestedCollectionType) const;
</span><del>-    size_t sizeAfterCollect();
</del><span class="cx"> 
</span><span class="cx">     JSStack&amp; stack();
</span><span class="cx">     
</span><span class="lines">@@ -357,7 +356,9 @@
</span><span class="cx">     size_t m_maxHeapSize;
</span><span class="cx">     bool m_shouldDoFullCollection;
</span><span class="cx">     size_t m_totalBytesVisited;
</span><ins>+    size_t m_totalBytesVisitedThisCycle;
</ins><span class="cx">     size_t m_totalBytesCopied;
</span><ins>+    size_t m_totalBytesCopiedThisCycle;
</ins><span class="cx">     
</span><span class="cx">     HeapOperation m_operationInProgress;
</span><span class="cx">     StructureIDTable m_structureIDTable;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapInlines.h (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapInlines.h        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/heap/HeapInlines.h        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -39,9 +39,13 @@
</span><span class="cx"> {
</span><span class="cx">     if (isDeferred())
</span><span class="cx">         return false;
</span><ins>+    if (!m_isSafeToCollect)
+        return false;
+    if (m_operationInProgress != NoOperation)
+        return false;
</ins><span class="cx">     if (Options::gcMaxHeapSize())
</span><del>-        return m_bytesAllocatedThisCycle &gt; Options::gcMaxHeapSize() &amp;&amp; m_isSafeToCollect &amp;&amp; m_operationInProgress == NoOperation;
-    return m_bytesAllocatedThisCycle &gt; m_maxEdenSize &amp;&amp; m_isSafeToCollect &amp;&amp; m_operationInProgress == NoOperation;
</del><ins>+        return m_bytesAllocatedThisCycle &gt; Options::gcMaxHeapSize();
+    return m_bytesAllocatedThisCycle &gt; m_maxEdenSize;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline bool Heap::isBusy()
</span><span class="lines">@@ -274,9 +278,6 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool Heap::collectIfNecessaryOrDefer()
</span><span class="cx"> {
</span><del>-    if (isDeferred())
-        return false;
-
</del><span class="cx">     if (!shouldCollect())
</span><span class="cx">         return false;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMarkedBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp (191239 => 191240)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp        2015-10-17 08:23:35 UTC (rev 191239)
+++ trunk/Source/JavaScriptCore/heap/MarkedBlock.cpp        2015-10-17 17:26:24 UTC (rev 191240)
</span><span class="lines">@@ -32,13 +32,26 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+static const bool computeBalance = false;
+static size_t balance;
+
</ins><span class="cx"> MarkedBlock* MarkedBlock::create(MarkedAllocator* allocator, size_t capacity, size_t cellSize, bool needsDestruction)
</span><span class="cx"> {
</span><ins>+    if (computeBalance) {
+        balance++;
+        if (!(balance % 10))
+            dataLog(&quot;MarkedBlock Balance: &quot;, balance, &quot;\n&quot;);
+    }
</ins><span class="cx">     return new (NotNull, fastAlignedMalloc(blockSize, capacity)) MarkedBlock(allocator, capacity, cellSize, needsDestruction);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void MarkedBlock::destroy(MarkedBlock* block)
</span><span class="cx"> {
</span><ins>+    if (computeBalance) {
+        balance--;
+        if (!(balance % 10))
+            dataLog(&quot;MarkedBlock Balance: &quot;, balance, &quot;\n&quot;);
+    }
</ins><span class="cx">     block-&gt;~MarkedBlock();
</span><span class="cx">     fastAlignedFree(block);
</span><span class="cx"> }
</span></span></pre>
</div>
</div>

</body>
</html>