<!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>[166678] 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/166678">166678</a></dd>
<dt>Author</dt> <dd>mhahnenberg@apple.com</dd>
<dt>Date</dt> <dd>2014-04-02 16:50:25 -0700 (Wed, 02 Apr 2014)</dd>
</dl>

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

Reviewed by Geoffrey Garen.

During EdenCollections we now only visit those CodeBlocks that:
a) Are new since the last collection if they were somehow otherwise reachable.
b) Are reachable from an Executable that is part of the remembered set.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock): Initialize uninitialized variables.
(JSC::CodeBlock::visitAggregate): Move the addition of the weak reference harvester after the
shouldImmediatelyAssumeLivenessDuringScan check since it's redundant if we assume liveness.
* bytecode/CodeBlock.h:
(JSC::CodeBlock::forEachRelatedCodeBlock): Executes a functor for each CodeBlock reachable from the current CodeBlock (including this).
We use this to clear marks for the CodeBlocks of remembered Executables (see: CodeBlockSet::clearMarksForEdenCollection).
(JSC::CodeBlockSet::mark): Also check the set of new CodeBlocks for memebership when doing conservative scanning.
(JSC::ScriptExecutable::forEachCodeBlock): Executes a functor for each of this Executable's CodeBlocks.
* heap/CodeBlockSet.cpp:
(JSC::CodeBlockSet::~CodeBlockSet):
(JSC::CodeBlockSet::add):
(JSC::CodeBlockSet::promoteYoungCodeBlocks): Moves all CodeBlocks currently in the set of new CodeBlocks into
the set of old CodeBlocks.
(JSC::CodeBlockSet::clearMarksForFullCollection): Clears the marks for all CodeBlocks.
(JSC::CodeBlockSet::clearMarksForEdenCollection): Clears the marks for CodeBlocks owned by Executables in the
remembered set. When an Executable is added to the remembered set it's typically because we need to do something
with its CodeBlock.
(JSC::CodeBlockSet::clearMarks):
(JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced): Fixpoints over either just the new CodeBlocks or all CodeBlocks
to determine which CodeBlocks are dead and eagerly finalizes/deletes them.
(JSC::CodeBlockSet::remove):
(JSC::CodeBlockSet::traceMarked): Iterate only the currently executing CodeBlocks instead of all CodeBlocks.
(JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): Clear m_mayBeExecuting for all currently executing
CodeBlocks because we no longer always do this at the beginning of EdenCollections.
* heap/CodeBlockSet.h:
(JSC::CodeBlockSet::iterate):
* heap/Heap.cpp:
(JSC::Heap::markRoots):
(JSC::Heap::deleteAllCompiledCode):
(JSC::Heap::deleteUnmarkedCompiledCode):
* runtime/Executable.cpp:
(JSC::ScriptExecutable::installCode): Write barrier code on installation. We do this due to the following situation:
a) A CodeBlock is created and is compiled on a DFG worker thread.
b) No GC happens.
c) The CodeBlock has finished being compiled and is installed in the Executable.
d) The function never executes before the next GC.
e) The next GC needs needs to visit the new CodeBlock but the Executable won't be revisited unless
    it's added to the remembered set.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSetcpp">trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSeth">trunk/Source/JavaScriptCore/heap/CodeBlockSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeExecutablecpp">trunk/Source/JavaScriptCore/runtime/Executable.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeExecutableh">trunk/Source/JavaScriptCore/runtime/Executable.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -1,3 +1,54 @@
</span><ins>+2014-04-02  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
+
+        CodeBlockSet should be generational
+        https://bugs.webkit.org/show_bug.cgi?id=127152
+
+        Reviewed by Geoffrey Garen.
+
+        During EdenCollections we now only visit those CodeBlocks that:
+        a) Are new since the last collection if they were somehow otherwise reachable.
+        b) Are reachable from an Executable that is part of the remembered set.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::CodeBlock): Initialize uninitialized variables.
+        (JSC::CodeBlock::visitAggregate): Move the addition of the weak reference harvester after the
+        shouldImmediatelyAssumeLivenessDuringScan check since it's redundant if we assume liveness.
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::forEachRelatedCodeBlock): Executes a functor for each CodeBlock reachable from the current CodeBlock (including this).
+        We use this to clear marks for the CodeBlocks of remembered Executables (see: CodeBlockSet::clearMarksForEdenCollection).
+        (JSC::CodeBlockSet::mark): Also check the set of new CodeBlocks for memebership when doing conservative scanning.
+        (JSC::ScriptExecutable::forEachCodeBlock): Executes a functor for each of this Executable's CodeBlocks.
+        * heap/CodeBlockSet.cpp:
+        (JSC::CodeBlockSet::~CodeBlockSet):
+        (JSC::CodeBlockSet::add):
+        (JSC::CodeBlockSet::promoteYoungCodeBlocks): Moves all CodeBlocks currently in the set of new CodeBlocks into 
+        the set of old CodeBlocks.
+        (JSC::CodeBlockSet::clearMarksForFullCollection): Clears the marks for all CodeBlocks.
+        (JSC::CodeBlockSet::clearMarksForEdenCollection): Clears the marks for CodeBlocks owned by Executables in the 
+        remembered set. When an Executable is added to the remembered set it's typically because we need to do something 
+        with its CodeBlock.
+        (JSC::CodeBlockSet::clearMarks):
+        (JSC::CodeBlockSet::deleteUnmarkedAndUnreferenced): Fixpoints over either just the new CodeBlocks or all CodeBlocks
+        to determine which CodeBlocks are dead and eagerly finalizes/deletes them.
+        (JSC::CodeBlockSet::remove):
+        (JSC::CodeBlockSet::traceMarked): Iterate only the currently executing CodeBlocks instead of all CodeBlocks.
+        (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks): Clear m_mayBeExecuting for all currently executing 
+        CodeBlocks because we no longer always do this at the beginning of EdenCollections.
+        * heap/CodeBlockSet.h:
+        (JSC::CodeBlockSet::iterate):
+        * heap/Heap.cpp:
+        (JSC::Heap::markRoots):
+        (JSC::Heap::deleteAllCompiledCode):
+        (JSC::Heap::deleteUnmarkedCompiledCode):
+        * runtime/Executable.cpp:
+        (JSC::ScriptExecutable::installCode): Write barrier code on installation. We do this due to the following situation:
+        a) A CodeBlock is created and is compiled on a DFG worker thread.
+        b) No GC happens.
+        c) The CodeBlock has finished being compiled and is installed in the Executable.
+        d) The function never executes before the next GC.
+        e) The next GC needs needs to visit the new CodeBlock but the Executable won't be revisited unless 
+            it's added to the remembered set.
+
</ins><span class="cx"> 2014-04-02  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Added some more dataLog info for OSR exits.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -1446,6 +1446,8 @@
</span><span class="cx">     , m_activationRegister(other.m_activationRegister)
</span><span class="cx">     , m_isStrictMode(other.m_isStrictMode)
</span><span class="cx">     , m_needsActivation(other.m_needsActivation)
</span><ins>+    , m_mayBeExecuting(false)
+    , m_visitAggregateHasBeenCalled(false)
</ins><span class="cx">     , m_source(other.m_source)
</span><span class="cx">     , m_sourceOffset(other.m_sourceOffset)
</span><span class="cx">     , m_firstLineColumnOffset(other.m_firstLineColumnOffset)
</span><span class="lines">@@ -1503,6 +1505,8 @@
</span><span class="cx">     , m_activationRegister(unlinkedCodeBlock-&gt;activationRegister())
</span><span class="cx">     , m_isStrictMode(unlinkedCodeBlock-&gt;isStrictMode())
</span><span class="cx">     , m_needsActivation(unlinkedCodeBlock-&gt;hasActivationRegister() &amp;&amp; unlinkedCodeBlock-&gt;codeType() == FunctionCode)
</span><ins>+    , m_mayBeExecuting(false)
+    , m_visitAggregateHasBeenCalled(false)
</ins><span class="cx">     , m_source(sourceProvider)
</span><span class="cx">     , m_sourceOffset(sourceOffset)
</span><span class="cx">     , m_firstLineColumnOffset(firstLineColumnOffset)
</span><span class="lines">@@ -1937,10 +1941,6 @@
</span><span class="cx">     // and when it runs, it figures out whether it has any work to do.
</span><span class="cx">     visitor.addUnconditionalFinalizer(this);
</span><span class="cx">     
</span><del>-    // There are two things that we use weak reference harvesters for: DFG fixpoint for
-    // jettisoning, and trying to find structures that would be live based on some
-    // inline cache. So it makes sense to register them regardless.
-    visitor.addWeakReferenceHarvester(this);
</del><span class="cx">     m_allTransitionsHaveBeenMarked = false;
</span><span class="cx">     
</span><span class="cx">     if (shouldImmediatelyAssumeLivenessDuringScan()) {
</span><span class="lines">@@ -1951,6 +1951,11 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    // There are two things that we use weak reference harvesters for: DFG fixpoint for
+    // jettisoning, and trying to find structures that would be live based on some
+    // inline cache. So it makes sense to register them regardless.
+    visitor.addWeakReferenceHarvester(this);
+
</ins><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     // We get here if we're live in the sense that our owner executable is live,
</span><span class="cx">     // but we're not yet live for sure in another sense: we may yet decide that this
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -132,6 +132,23 @@
</span><span class="cx">     CodeBlock* alternative() { return m_alternative.get(); }
</span><span class="cx">     PassRefPtr&lt;CodeBlock&gt; releaseAlternative() { return m_alternative.release(); }
</span><span class="cx">     void setAlternative(PassRefPtr&lt;CodeBlock&gt; alternative) { m_alternative = alternative; }
</span><ins>+
+    template &lt;typename Functor&gt; void forEachRelatedCodeBlock(Functor&amp;&amp; functor)
+    {
+        Functor f(std::forward&lt;Functor&gt;(functor));
+        Vector&lt;CodeBlock*, 4&gt; codeBlocks;
+        codeBlocks.append(this);
+
+        while (!codeBlocks.isEmpty()) {
+            CodeBlock* currentCodeBlock = codeBlocks.takeLast();
+            f(currentCodeBlock);
+
+            if (CodeBlock* alternative = currentCodeBlock-&gt;alternative())
+                codeBlocks.append(alternative);
+            if (CodeBlock* osrEntryBlock = currentCodeBlock-&gt;specialOSREntryBlockOrNull())
+                codeBlocks.append(osrEntryBlock);
+        }
+    }
</ins><span class="cx">     
</span><span class="cx">     CodeSpecializationKind specializationKind() const
</span><span class="cx">     {
</span><span class="lines">@@ -1275,12 +1292,12 @@
</span><span class="cx">     // -1 + 1 = 0
</span><span class="cx">     if (value + 1 &lt;= 1)
</span><span class="cx">         return;
</span><del>-    
-    HashSet&lt;CodeBlock*&gt;::iterator iter = m_set.find(static_cast&lt;CodeBlock*&gt;(candidateCodeBlock));
-    if (iter == m_set.end())
</del><ins>+
+    CodeBlock* codeBlock = static_cast&lt;CodeBlock*&gt;(candidateCodeBlock); 
+    if (!m_oldCodeBlocks.contains(codeBlock) &amp;&amp; !m_newCodeBlocks.contains(codeBlock))
</ins><span class="cx">         return;
</span><del>-    
-    mark(*iter);
</del><ins>+
+    mark(codeBlock);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> inline void CodeBlockSet::mark(CodeBlock* codeBlock)
</span><span class="lines">@@ -1292,11 +1309,40 @@
</span><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     codeBlock-&gt;m_mayBeExecuting = true;
</span><ins>+    // We might not have cleared the marks for this CodeBlock, but we need to visit it.
+    codeBlock-&gt;m_visitAggregateHasBeenCalled = false;
</ins><span class="cx"> #if ENABLE(GGC)
</span><span class="cx">     m_currentlyExecuting.append(codeBlock);
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template &lt;typename Functor&gt; inline void ScriptExecutable::forEachCodeBlock(Functor&amp;&amp; functor)
+{
+    switch (type()) {
+    case ProgramExecutableType: {
+        jsCast&lt;ProgramExecutable*&gt;(this)-&gt;m_programCodeBlock-&gt;forEachRelatedCodeBlock(std::forward&lt;Functor&gt;(functor));
+        break;
+    }
+        
+    case EvalExecutableType: {
+        jsCast&lt;EvalExecutable*&gt;(this)-&gt;m_evalCodeBlock-&gt;forEachRelatedCodeBlock(std::forward&lt;Functor&gt;(functor));
+        break;
+    }
+        
+    case FunctionExecutableType: {
+        Functor f(std::forward&lt;Functor&gt;(functor));
+        FunctionExecutable* executable = jsCast&lt;FunctionExecutable*&gt;(this);
+        if (CodeBlock* codeBlock = executable-&gt;m_codeBlockForCall.get())
+            codeBlock-&gt;forEachRelatedCodeBlock(f);
+        if (CodeBlock* codeBlock = executable-&gt;m_codeBlockForConstruct.get())
+            codeBlock-&gt;forEachRelatedCodeBlock(f);
+        break;
+    }
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // CodeBlock_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -41,36 +41,65 @@
</span><span class="cx"> 
</span><span class="cx"> CodeBlockSet::~CodeBlockSet()
</span><span class="cx"> {
</span><del>-    for (CodeBlock* codeBlock : m_set)
</del><ins>+    for (CodeBlock* codeBlock : m_oldCodeBlocks)
</ins><span class="cx">         codeBlock-&gt;deref();
</span><ins>+
+    for (CodeBlock* codeBlock : m_newCodeBlocks)
+        codeBlock-&gt;deref();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CodeBlockSet::add(PassRefPtr&lt;CodeBlock&gt; codeBlock)
</span><span class="cx"> {
</span><span class="cx">     CodeBlock* block = codeBlock.leakRef();
</span><del>-    bool isNewEntry = m_set.add(block).isNewEntry;
</del><ins>+    bool isNewEntry = m_newCodeBlocks.add(block).isNewEntry;
</ins><span class="cx">     ASSERT_UNUSED(isNewEntry, isNewEntry);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CodeBlockSet::clearMarks()
</del><ins>+void CodeBlockSet::promoteYoungCodeBlocks()
</ins><span class="cx"> {
</span><del>-    for (CodeBlock* codeBlock : m_set) {
</del><ins>+    m_oldCodeBlocks.add(m_newCodeBlocks.begin(), m_newCodeBlocks.end());
+    m_newCodeBlocks.clear();
+}
+
+void CodeBlockSet::clearMarksForFullCollection()
+{
+    for (CodeBlock* codeBlock : m_oldCodeBlocks) {
</ins><span class="cx">         codeBlock-&gt;m_mayBeExecuting = false;
</span><span class="cx">         codeBlock-&gt;m_visitAggregateHasBeenCalled = false;
</span><span class="cx">     }
</span><ins>+
+    // We promote after we clear marks on the old generation CodeBlocks because
+    // none of the young generations CodeBlocks need to be cleared.
+    promoteYoungCodeBlocks();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void CodeBlockSet::deleteUnmarkedAndUnreferenced()
</del><ins>+void CodeBlockSet::clearMarksForEdenCollection(const Vector&lt;const JSCell*&gt;&amp; rememberedSet)
</ins><span class="cx"> {
</span><ins>+    // This ensures that we will revisit CodeBlocks in remembered Executables even if they were previously marked.
+    for (const JSCell* cell : rememberedSet) {
+        ScriptExecutable* executable = const_cast&lt;ScriptExecutable*&gt;(jsDynamicCast&lt;const ScriptExecutable*&gt;(cell));
+        if (!executable)
+            continue;
+        executable-&gt;forEachCodeBlock([](CodeBlock* codeBlock) {
+            codeBlock-&gt;m_mayBeExecuting = false;
+            codeBlock-&gt;m_visitAggregateHasBeenCalled = false;
+        });
+    }
+}
+
+void CodeBlockSet::deleteUnmarkedAndUnreferenced(HeapOperation collectionType)
+{
+    HashSet&lt;CodeBlock*&gt;&amp; set = collectionType == EdenCollection ? m_newCodeBlocks : m_oldCodeBlocks;
+
</ins><span class="cx">     // This needs to be a fixpoint because code blocks that are unmarked may
</span><span class="cx">     // refer to each other. For example, a DFG code block that is owned by
</span><span class="cx">     // the GC may refer to an FTL for-entry code block that is also owned by
</span><span class="cx">     // the GC.
</span><span class="cx">     Vector&lt;CodeBlock*, 16&gt; toRemove;
</span><span class="cx">     if (verbose)
</span><del>-        dataLog(&quot;Fixpointing over unmarked, set size = &quot;, m_set.size(), &quot;...\n&quot;);
</del><ins>+        dataLog(&quot;Fixpointing over unmarked, set size = &quot;, set.size(), &quot;...\n&quot;);
</ins><span class="cx">     for (;;) {
</span><del>-        for (CodeBlock* codeBlock : m_set) {
</del><ins>+        for (CodeBlock* codeBlock : set) {
</ins><span class="cx">             if (!codeBlock-&gt;hasOneRef())
</span><span class="cx">                 continue;
</span><span class="cx">             if (codeBlock-&gt;m_mayBeExecuting)
</span><span class="lines">@@ -83,24 +112,32 @@
</span><span class="cx">         if (toRemove.isEmpty())
</span><span class="cx">             break;
</span><span class="cx">         for (CodeBlock* codeBlock : toRemove)
</span><del>-            m_set.remove(codeBlock);
</del><ins>+            set.remove(codeBlock);
</ins><span class="cx">         toRemove.resize(0);
</span><span class="cx">     }
</span><ins>+
+    // Any remaining young CodeBlocks are live and need to be promoted to the set of old CodeBlocks.
+    if (collectionType == EdenCollection)
+        promoteYoungCodeBlocks();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CodeBlockSet::remove(CodeBlock* codeBlock)
</span><span class="cx"> {
</span><span class="cx">     codeBlock-&gt;deref();
</span><del>-    m_set.remove(codeBlock);
</del><ins>+    if (m_oldCodeBlocks.contains(codeBlock)) {
+        m_oldCodeBlocks.remove(codeBlock);
+        return;
+    }
+    ASSERT(m_newCodeBlocks.contains(codeBlock));
+    m_newCodeBlocks.remove(codeBlock);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CodeBlockSet::traceMarked(SlotVisitor&amp; visitor)
</span><span class="cx"> {
</span><span class="cx">     if (verbose)
</span><del>-        dataLog(&quot;Tracing &quot;, m_set.size(), &quot; code blocks.\n&quot;);
-    for (CodeBlock* codeBlock : m_set) {
-        if (!codeBlock-&gt;m_mayBeExecuting)
-            continue;
</del><ins>+        dataLog(&quot;Tracing &quot;, m_currentlyExecuting.size(), &quot; code blocks.\n&quot;);
+    for (CodeBlock* codeBlock : m_currentlyExecuting) {
+        ASSERT(codeBlock-&gt;m_mayBeExecuting);
</ins><span class="cx">         codeBlock-&gt;visitAggregate(visitor);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -108,8 +145,10 @@
</span><span class="cx"> void CodeBlockSet::rememberCurrentlyExecutingCodeBlocks(Heap* heap)
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(GGC)
</span><del>-    for (CodeBlock* codeBlock : m_currentlyExecuting)
</del><ins>+    for (CodeBlock* codeBlock : m_currentlyExecuting) {
</ins><span class="cx">         heap-&gt;addToRememberedSet(codeBlock-&gt;ownerExecutable());
</span><ins>+        ASSERT(codeBlock-&gt;m_mayBeExecuting);
+    }
</ins><span class="cx">     m_currentlyExecuting.clear();
</span><span class="cx"> #else
</span><span class="cx">     UNUSED_PARAM(heap);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.h (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> #define CodeBlockSet_h
</span><span class="cx"> 
</span><span class="cx"> #include &quot;GCSegmentedArray.h&quot;
</span><ins>+#include &quot;HeapOperation.h&quot;
</ins><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="cx"> #include &lt;wtf/PassRefPtr.h&gt;
</span><span class="lines">@@ -37,6 +38,7 @@
</span><span class="cx"> class BlockAllocator;
</span><span class="cx"> class CodeBlock;
</span><span class="cx"> class Heap;
</span><ins>+class JSCell;
</ins><span class="cx"> class SlotVisitor;
</span><span class="cx"> 
</span><span class="cx"> // CodeBlockSet tracks all CodeBlocks. Every CodeBlock starts out with one
</span><span class="lines">@@ -53,9 +55,12 @@
</span><span class="cx">     // Add a CodeBlock. This is only called by CodeBlock constructors.
</span><span class="cx">     void add(PassRefPtr&lt;CodeBlock&gt;);
</span><span class="cx">     
</span><del>-    // Clear all mark bits associated with DFG code blocks.
-    void clearMarks();
-    
</del><ins>+    // Clear mark bits for certain CodeBlocks depending on the type of collection.
+    void clearMarksForEdenCollection(const Vector&lt;const JSCell*&gt;&amp;);
+
+    // Clear all mark bits for all CodeBlocks.
+    void clearMarksForFullCollection();
+
</ins><span class="cx">     // Mark a pointer that may be a CodeBlock that belongs to the set of DFG
</span><span class="cx">     // blocks. This is defined in CodeBlock.h.
</span><span class="cx">     void mark(CodeBlock* candidateCodeBlock);
</span><span class="lines">@@ -63,7 +68,7 @@
</span><span class="cx">     
</span><span class="cx">     // Delete all code blocks that are only referenced by this set (i.e. owned
</span><span class="cx">     // by this set), and that have not been marked.
</span><del>-    void deleteUnmarkedAndUnreferenced();
</del><ins>+    void deleteUnmarkedAndUnreferenced(HeapOperation);
</ins><span class="cx">     
</span><span class="cx">     void remove(CodeBlock*);
</span><span class="cx">     
</span><span class="lines">@@ -80,18 +85,28 @@
</span><span class="cx">     // visited.
</span><span class="cx">     template&lt;typename Functor&gt; void iterate(Functor&amp; functor)
</span><span class="cx">     {
</span><del>-        for (auto&amp; codeBlock : m_set) {
</del><ins>+        for (auto&amp; codeBlock : m_oldCodeBlocks) {
</ins><span class="cx">             bool done = functor(codeBlock);
</span><span class="cx">             if (done)
</span><del>-                break;
</del><ins>+                return;
</ins><span class="cx">         }
</span><ins>+
+        for (auto&amp; codeBlock : m_newCodeBlocks) {
+            bool done = functor(codeBlock);
+            if (done)
+                return;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span><ins>+    void clearMarksForCodeBlocksInRememberedExecutables(const Vector&lt;const JSCell*&gt;&amp;);
+    void promoteYoungCodeBlocks();
+
</ins><span class="cx">     // This is not a set of RefPtr&lt;CodeBlock&gt; because we need to be able to find
</span><span class="cx">     // arbitrary bogus pointers. I could have written a thingy that had peek types
</span><span class="cx">     // and all, but that seemed like overkill.
</span><del>-    HashSet&lt;CodeBlock* &gt; m_set;
</del><ins>+    HashSet&lt;CodeBlock*&gt; m_oldCodeBlocks;
+    HashSet&lt;CodeBlock*&gt; m_newCodeBlocks;
</ins><span class="cx">     GCSegmentedArray&lt;CodeBlock*&gt; m_currentlyExecuting;
</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 (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -485,8 +485,18 @@
</span><span class="cx">     double gcStartTime = WTF::monotonicallyIncreasingTime();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    m_codeBlocks.clearMarks();
</del><ins>+#if ENABLE(GGC)
+    Vector&lt;const JSCell*&gt; rememberedSet(m_slotVisitor.markStack().size());
+    m_slotVisitor.markStack().fillVector(rememberedSet);
+#else
+    Vector&lt;const JSCell*&gt; rememberedSet;
+#endif
</ins><span class="cx"> 
</span><ins>+    if (m_operationInProgress == EdenCollection)
+        m_codeBlocks.clearMarksForEdenCollection(rememberedSet);
+    else
+        m_codeBlocks.clearMarksForFullCollection();
+
</ins><span class="cx">     // We gather conservative roots before clearing mark bits because conservative
</span><span class="cx">     // gathering uses the mark bits to determine whether a reference is valid.
</span><span class="cx">     void* dummy;
</span><span class="lines">@@ -503,13 +513,6 @@
</span><span class="cx">     m_slotVisitor.didStartMarking();
</span><span class="cx">     HeapRootVisitor heapRootVisitor(m_slotVisitor);
</span><span class="cx"> 
</span><del>-#if ENABLE(GGC)
-    Vector&lt;const JSCell*&gt; rememberedSet(m_slotVisitor.markStack().size());
-    m_slotVisitor.markStack().fillVector(rememberedSet);
-#else
-    Vector&lt;const JSCell*&gt; rememberedSet;
-#endif
-
</del><span class="cx">     {
</span><span class="cx">         ParallelModeEnabler enabler(m_slotVisitor);
</span><span class="cx"> 
</span><span class="lines">@@ -852,8 +855,9 @@
</span><span class="cx">         static_cast&lt;FunctionExecutable*&gt;(current)-&gt;clearCodeIfNotCompiling();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_codeBlocks.clearMarks();
-    m_codeBlocks.deleteUnmarkedAndUnreferenced();
</del><ins>+    ASSERT(m_operationInProgress == FullCollection);
+    m_codeBlocks.clearMarksForFullCollection();
+    m_codeBlocks.deleteUnmarkedAndUnreferenced(FullCollection);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::deleteAllUnlinkedFunctionCode()
</span><span class="lines">@@ -865,9 +869,9 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::deleteUnmarkedCompiledCode()
</del><ins>+void Heap::clearUnmarkedExecutables()
</ins><span class="cx"> {
</span><del>-    GCPHASE(DeleteCodeBlocks);
</del><ins>+    GCPHASE(ClearUnmarkedExecutables);
</ins><span class="cx">     ExecutableBase* next;
</span><span class="cx">     for (ExecutableBase* current = m_compiledCode.head(); current; current = next) {
</span><span class="cx">         next = current-&gt;next();
</span><span class="lines">@@ -879,8 +883,13 @@
</span><span class="cx">         ExecutableBase::clearCodeVirtual(current);
</span><span class="cx">         m_compiledCode.remove(current);
</span><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    m_codeBlocks.deleteUnmarkedAndUnreferenced();
</del><ins>+void Heap::deleteUnmarkedCompiledCode()
+{
+    GCPHASE(DeleteCodeBlocks);
+    clearUnmarkedExecutables();
+    m_codeBlocks.deleteUnmarkedAndUnreferenced(m_operationInProgress);
</ins><span class="cx">     m_jitStubRoutines.deleteUnmarkedJettisonedStubRoutines();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1011,6 +1020,9 @@
</span><span class="cx"> 
</span><span class="cx"> void Heap::deleteOldCode(double gcStartTime)
</span><span class="cx"> {
</span><ins>+    if (m_operationInProgress == EdenCollection)
+        return;
+
</ins><span class="cx">     GCPHASE(DeleteOldCode);
</span><span class="cx">     if (gcStartTime - m_lastCodeDiscardTime &gt; minute) {
</span><span class="cx">         deleteAllCompiledCode();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -292,6 +292,7 @@
</span><span class="cx">     void copyBackingStores();
</span><span class="cx">     void harvestWeakReferences();
</span><span class="cx">     void finalizeUnconditionalFinalizers();
</span><ins>+    void clearUnmarkedExecutables();
</ins><span class="cx">     void deleteUnmarkedCompiledCode();
</span><span class="cx">     void updateAllocationLimits();
</span><span class="cx">     void didFinishCollection(double gcStartTime);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeExecutablecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Executable.cpp (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Executable.cpp        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/runtime/Executable.cpp        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -178,6 +178,8 @@
</span><span class="cx">     Debugger* debugger = genericCodeBlock-&gt;globalObject()-&gt;debugger();
</span><span class="cx">     if (debugger)
</span><span class="cx">         debugger-&gt;registerCodeBlock(genericCodeBlock);
</span><ins>+
+    Heap::heap(this)-&gt;writeBarrier(this);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;CodeBlock&gt; ScriptExecutable::newCodeBlockFor(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeExecutableh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Executable.h (166677 => 166678)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Executable.h        2014-04-02 23:41:04 UTC (rev 166677)
+++ trunk/Source/JavaScriptCore/runtime/Executable.h        2014-04-02 23:50:25 UTC (rev 166678)
</span><span class="lines">@@ -429,6 +429,8 @@
</span><span class="cx">         return prepareForExecutionImpl(exec, function, scope, kind);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    template &lt;typename Functor&gt; void forEachCodeBlock(Functor&amp;&amp;);
+
</ins><span class="cx"> private:
</span><span class="cx">     JSObject* prepareForExecutionImpl(ExecState*, JSFunction*, JSScope**, CodeSpecializationKind);
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>