<!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>[167897] trunk/Source</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/167897">167897</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-04-28 12:01:07 -0700 (Mon, 28 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>GC should be able to remove things from the DFG worklist and cancel on-going compilations if it knows that the compilation would already be invalidated
https://bugs.webkit.org/show_bug.cgi?id=132166

Reviewed by Oliver Hunt and Mark Hahnenberg.
        
The GC can aid type inference by removing structures that are dead and jettisoning
code that relies on those structures. This can dramatically accelerate type inference
for some tricky programs.
        
Unfortunately, we previously pinned any structures that enqueued compilations depended
on. This means that if you're on a machine that only runs a single compilation thread
and where compilations are relatively slow, you have a high chance of large numbers of
structures being pinned during any GC since the compilation queue is likely to be full
of random stuff.
        
This comprehensively fixes this issue by allowing the GC to remove compilation plans
if the things they depend on are dead, and to even cancel safepointed compilations.
        
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan):
(JSC::CodeBlock::isKnownToBeLiveDuringGC):
(JSC::CodeBlock::finalizeUnconditionally):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan): Deleted.
* dfg/DFGDesiredIdentifiers.cpp:
(JSC::DFG::DesiredIdentifiers::DesiredIdentifiers):
* dfg/DFGDesiredIdentifiers.h:
* dfg/DFGDesiredWatchpoints.h:
* dfg/DFGDesiredWeakReferences.cpp:
(JSC::DFG::DesiredWeakReferences::DesiredWeakReferences):
* dfg/DFGDesiredWeakReferences.h:
* dfg/DFGGraphSafepoint.cpp:
(JSC::DFG::GraphSafepoint::GraphSafepoint):
* dfg/DFGGraphSafepoint.h:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::Plan):
(JSC::DFG::Plan::compileInThread):
(JSC::DFG::Plan::compileInThreadImpl):
(JSC::DFG::Plan::notifyCompiling):
(JSC::DFG::Plan::notifyCompiled):
(JSC::DFG::Plan::notifyReady):
(JSC::DFG::Plan::checkLivenessAndVisitChildren):
(JSC::DFG::Plan::isKnownToBeLiveDuringGC):
(JSC::DFG::Plan::cancel):
(JSC::DFG::Plan::visitChildren): Deleted.
* dfg/DFGPlan.h:
* dfg/DFGSafepoint.cpp:
(JSC::DFG::Safepoint::Result::~Result):
(JSC::DFG::Safepoint::Result::didGetCancelled):
(JSC::DFG::Safepoint::Safepoint):
(JSC::DFG::Safepoint::~Safepoint):
(JSC::DFG::Safepoint::checkLivenessAndVisitChildren):
(JSC::DFG::Safepoint::isKnownToBeLiveDuringGC):
(JSC::DFG::Safepoint::cancel):
(JSC::DFG::Safepoint::visitChildren): Deleted.
* dfg/DFGSafepoint.h:
(JSC::DFG::Safepoint::Result::Result):
* dfg/DFGWorklist.cpp:
(JSC::DFG::Worklist::compilationState):
(JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady):
(JSC::DFG::Worklist::removeAllReadyPlansForVM):
(JSC::DFG::Worklist::completeAllReadyPlansForVM):
(JSC::DFG::Worklist::visitWeakReferences):
(JSC::DFG::Worklist::removeDeadPlans):
(JSC::DFG::Worklist::runThread):
(JSC::DFG::Worklist::visitChildren): Deleted.
* dfg/DFGWorklist.h:
* ftl/FTLCompile.cpp:
(JSC::FTL::compile):
* ftl/FTLCompile.h:
* heap/CodeBlockSet.cpp:
(JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks):
* heap/Heap.cpp:
(JSC::Heap::markRoots):
(JSC::Heap::visitCompilerWorklistWeakReferences):
(JSC::Heap::removeDeadCompilerWorklistEntries):
(JSC::Heap::visitWeakHandles):
(JSC::Heap::collect):
(JSC::Heap::visitCompilerWorklists): Deleted.
* heap/Heap.h:</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="#trunkSourceJavaScriptCoredfgDFGDesiredIdentifierscpp">trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDesiredIdentifiersh">trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDesiredWatchpointsh">trunk/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDesiredWeakReferencescpp">trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDesiredWeakReferencesh">trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphSafepointcpp">trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphSafepointh">trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlancpp">trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlanh">trunk/Source/JavaScriptCore/dfg/DFGPlan.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafepointcpp">trunk/Source/JavaScriptCore/dfg/DFGSafepoint.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafepointh">trunk/Source/JavaScriptCore/dfg/DFGSafepoint.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWorklistcpp">trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGWorklisth">trunk/Source/JavaScriptCore/dfg/DFGWorklist.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompilecpp">trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompileh">trunk/Source/JavaScriptCore/ftl/FTLCompile.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSetcpp">trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp</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="#trunkSourceWTFwtfThreadingPthreadscpp">trunk/Source/WTF/wtf/ThreadingPthreads.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -1,3 +1,86 @@
</span><ins>+2014-04-27  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        GC should be able to remove things from the DFG worklist and cancel on-going compilations if it knows that the compilation would already be invalidated
+        https://bugs.webkit.org/show_bug.cgi?id=132166
+
+        Reviewed by Oliver Hunt and Mark Hahnenberg.
+        
+        The GC can aid type inference by removing structures that are dead and jettisoning
+        code that relies on those structures. This can dramatically accelerate type inference
+        for some tricky programs.
+        
+        Unfortunately, we previously pinned any structures that enqueued compilations depended
+        on. This means that if you're on a machine that only runs a single compilation thread
+        and where compilations are relatively slow, you have a high chance of large numbers of
+        structures being pinned during any GC since the compilation queue is likely to be full
+        of random stuff.
+        
+        This comprehensively fixes this issue by allowing the GC to remove compilation plans
+        if the things they depend on are dead, and to even cancel safepointed compilations.
+        
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan):
+        (JSC::CodeBlock::isKnownToBeLiveDuringGC):
+        (JSC::CodeBlock::finalizeUnconditionally):
+        * bytecode/CodeBlock.h:
+        (JSC::CodeBlock::shouldImmediatelyAssumeLivenessDuringScan): Deleted.
+        * dfg/DFGDesiredIdentifiers.cpp:
+        (JSC::DFG::DesiredIdentifiers::DesiredIdentifiers):
+        * dfg/DFGDesiredIdentifiers.h:
+        * dfg/DFGDesiredWatchpoints.h:
+        * dfg/DFGDesiredWeakReferences.cpp:
+        (JSC::DFG::DesiredWeakReferences::DesiredWeakReferences):
+        * dfg/DFGDesiredWeakReferences.h:
+        * dfg/DFGGraphSafepoint.cpp:
+        (JSC::DFG::GraphSafepoint::GraphSafepoint):
+        * dfg/DFGGraphSafepoint.h:
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::Plan):
+        (JSC::DFG::Plan::compileInThread):
+        (JSC::DFG::Plan::compileInThreadImpl):
+        (JSC::DFG::Plan::notifyCompiling):
+        (JSC::DFG::Plan::notifyCompiled):
+        (JSC::DFG::Plan::notifyReady):
+        (JSC::DFG::Plan::checkLivenessAndVisitChildren):
+        (JSC::DFG::Plan::isKnownToBeLiveDuringGC):
+        (JSC::DFG::Plan::cancel):
+        (JSC::DFG::Plan::visitChildren): Deleted.
+        * dfg/DFGPlan.h:
+        * dfg/DFGSafepoint.cpp:
+        (JSC::DFG::Safepoint::Result::~Result):
+        (JSC::DFG::Safepoint::Result::didGetCancelled):
+        (JSC::DFG::Safepoint::Safepoint):
+        (JSC::DFG::Safepoint::~Safepoint):
+        (JSC::DFG::Safepoint::checkLivenessAndVisitChildren):
+        (JSC::DFG::Safepoint::isKnownToBeLiveDuringGC):
+        (JSC::DFG::Safepoint::cancel):
+        (JSC::DFG::Safepoint::visitChildren): Deleted.
+        * dfg/DFGSafepoint.h:
+        (JSC::DFG::Safepoint::Result::Result):
+        * dfg/DFGWorklist.cpp:
+        (JSC::DFG::Worklist::compilationState):
+        (JSC::DFG::Worklist::waitUntilAllPlansForVMAreReady):
+        (JSC::DFG::Worklist::removeAllReadyPlansForVM):
+        (JSC::DFG::Worklist::completeAllReadyPlansForVM):
+        (JSC::DFG::Worklist::visitWeakReferences):
+        (JSC::DFG::Worklist::removeDeadPlans):
+        (JSC::DFG::Worklist::runThread):
+        (JSC::DFG::Worklist::visitChildren): Deleted.
+        * dfg/DFGWorklist.h:
+        * ftl/FTLCompile.cpp:
+        (JSC::FTL::compile):
+        * ftl/FTLCompile.h:
+        * heap/CodeBlockSet.cpp:
+        (JSC::CodeBlockSet::rememberCurrentlyExecutingCodeBlocks):
+        * heap/Heap.cpp:
+        (JSC::Heap::markRoots):
+        (JSC::Heap::visitCompilerWorklistWeakReferences):
+        (JSC::Heap::removeDeadCompilerWorklistEntries):
+        (JSC::Heap::visitWeakHandles):
+        (JSC::Heap::collect):
+        (JSC::Heap::visitCompilerWorklists): Deleted.
+        * heap/Heap.h:
+
</ins><span class="cx"> 2014-04-28  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Deleting properties poisons objects
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -1972,6 +1972,49 @@
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool CodeBlock::shouldImmediatelyAssumeLivenessDuringScan()
+{
+#if ENABLE(DFG_JIT)
+    // Interpreter and Baseline JIT CodeBlocks don't need to be jettisoned when
+    // their weak references go stale. So if a basline JIT CodeBlock gets
+    // scanned, we can assume that this means that it's live.
+    if (!JITCode::isOptimizingJIT(jitType()))
+        return true;
+
+    // For simplicity, we don't attempt to jettison code blocks during GC if
+    // they are executing. Instead we strongly mark their weak references to
+    // allow them to continue to execute soundly.
+    if (m_mayBeExecuting)
+        return true;
+
+    if (Options::forceDFGCodeBlockLiveness())
+        return true;
+
+    return false;
+#else
+    return true;
+#endif
+}
+
+bool CodeBlock::isKnownToBeLiveDuringGC()
+{
+#if ENABLE(DFG_JIT)
+    // This should return true for:
+    // - Code blocks that behave like normal objects - i.e. if they are referenced then they
+    //   are live.
+    // - Code blocks that were running on the stack.
+    // - Code blocks that survived the last GC if the current GC is an Eden GC. This is
+    //   because either livenessHasBeenProved would have survived as true or m_mayBeExecuting
+    //   would survive as true.
+    // - Code blocks that don't have any dead weak references.
+    
+    return shouldImmediatelyAssumeLivenessDuringScan()
+        || m_jitCode-&gt;dfgCommon()-&gt;livenessHasBeenProved;
+#else
+    return true;
+#endif
+}
+
</ins><span class="cx"> void CodeBlock::propagateTransitions(SlotVisitor&amp; visitor)
</span><span class="cx"> {
</span><span class="cx">     UNUSED_PARAM(visitor);
</span><span class="lines">@@ -2215,7 +2258,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx">     // Check if we're not live. If we are, then jettison.
</span><del>-    if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_jitCode-&gt;dfgCommon()-&gt;livenessHasBeenProved)) {
</del><ins>+    if (!isKnownToBeLiveDuringGC()) {
</ins><span class="cx">         if (Options::verboseOSR())
</span><span class="cx">             dataLog(*this, &quot; has dead weak references, jettisoning during GC.\n&quot;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -947,6 +947,8 @@
</span><span class="cx">     void beginValidationDidFail();
</span><span class="cx">     NO_RETURN_DUE_TO_CRASH void endValidationDidFail();
</span><span class="cx"> 
</span><ins>+    bool isKnownToBeLiveDuringGC(); // Will only return valid results when called during GC. Assumes that you've already established that the owner executable is live.
+
</ins><span class="cx"> protected:
</span><span class="cx">     virtual void visitWeakReferences(SlotVisitor&amp;) override;
</span><span class="cx">     virtual void finalizeUnconditionally() override;
</span><span class="lines">@@ -1001,29 +1003,7 @@
</span><span class="cx">     void dumpArrayProfiling(PrintStream&amp;, const Instruction*&amp;, bool&amp; hasPrintedProfiling);
</span><span class="cx">     void dumpRareCaseProfile(PrintStream&amp;, const char* name, RareCaseProfile*, bool&amp; hasPrintedProfiling);
</span><span class="cx">         
</span><del>-#if ENABLE(DFG_JIT)
-    bool shouldImmediatelyAssumeLivenessDuringScan()
-    {
-        // Interpreter and Baseline JIT CodeBlocks don't need to be jettisoned when
-        // their weak references go stale. So if a basline JIT CodeBlock gets
-        // scanned, we can assume that this means that it's live.
-        if (!JITCode::isOptimizingJIT(jitType()))
-            return true;
-
-        // For simplicity, we don't attempt to jettison code blocks during GC if
-        // they are executing. Instead we strongly mark their weak references to
-        // allow them to continue to execute soundly.
-        if (m_mayBeExecuting)
-            return true;
-
-        if (Options::forceDFGCodeBlockLiveness())
-            return true;
-
-        return false;
-    }
-#else
-    bool shouldImmediatelyAssumeLivenessDuringScan() { return true; }
-#endif
</del><ins>+    bool shouldImmediatelyAssumeLivenessDuringScan();
</ins><span class="cx">     
</span><span class="cx">     void propagateTransitions(SlotVisitor&amp;);
</span><span class="cx">     void determineLiveness(SlotVisitor&amp;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDesiredIdentifierscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -33,6 +33,11 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><ins>+DesiredIdentifiers::DesiredIdentifiers()
+    : m_codeBlock(nullptr)
+{
+}
+
</ins><span class="cx"> DesiredIdentifiers::DesiredIdentifiers(CodeBlock* codeBlock)
</span><span class="cx">     : m_codeBlock(codeBlock)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDesiredIdentifiersh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGDesiredIdentifiers.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -40,6 +40,7 @@
</span><span class="cx"> 
</span><span class="cx"> class DesiredIdentifiers {
</span><span class="cx"> public:
</span><ins>+    DesiredIdentifiers();
</ins><span class="cx">     DesiredIdentifiers(CodeBlock*);
</span><span class="cx">     ~DesiredIdentifiers();
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDesiredWatchpointsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -81,7 +81,6 @@
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename WatchpointSetType, typename Adaptor = GenericSetAdaptor&lt;WatchpointSetType&gt;&gt;
</span><span class="cx"> class GenericDesiredWatchpoints {
</span><del>-    WTF_MAKE_NONCOPYABLE(GenericDesiredWatchpoints);
</del><span class="cx"> #if !ASSERT_DISABLED
</span><span class="cx">     typedef HashMap&lt;WatchpointSetType*, bool&gt; StateMap;
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDesiredWeakReferencescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -34,6 +34,11 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><ins>+DesiredWeakReferences::DesiredWeakReferences()
+    : m_codeBlock(nullptr)
+{
+}
+
</ins><span class="cx"> DesiredWeakReferences::DesiredWeakReferences(CodeBlock* codeBlock)
</span><span class="cx">     : m_codeBlock(codeBlock)
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDesiredWeakReferencesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGDesiredWeakReferences.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -43,6 +43,7 @@
</span><span class="cx"> 
</span><span class="cx"> class DesiredWeakReferences {
</span><span class="cx"> public:
</span><ins>+    DesiredWeakReferences();
</ins><span class="cx">     DesiredWeakReferences(CodeBlock*);
</span><span class="cx">     ~DesiredWeakReferences();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphSafepointcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -33,8 +33,8 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><del>-GraphSafepoint::GraphSafepoint(Graph&amp; graph)
-    : m_safepoint(graph.m_plan)
</del><ins>+GraphSafepoint::GraphSafepoint(Graph&amp; graph, Safepoint::Result&amp; result)
+    : m_safepoint(graph.m_plan, result)
</ins><span class="cx"> {
</span><span class="cx">     m_safepoint.add(&amp;graph);
</span><span class="cx">     m_safepoint.begin();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphSafepointh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraphSafepoint.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> 
</span><span class="cx"> class GraphSafepoint {
</span><span class="cx"> public:
</span><del>-    GraphSafepoint(Graph&amp;);
</del><ins>+    GraphSafepoint(Graph&amp;, Safepoint::Result&amp;);
</ins><span class="cx">     ~GraphSafepoint();
</span><span class="cx">     
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -124,7 +124,7 @@
</span><span class="cx">     , identifiers(codeBlock.get())
</span><span class="cx">     , weakReferences(codeBlock.get())
</span><span class="cx">     , willTryToTierUp(false)
</span><del>-    , isCompiled(false)
</del><ins>+    , stage(Preparing)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -143,8 +143,11 @@
</span><span class="cx">     this-&gt;threadData = threadData;
</span><span class="cx">     
</span><span class="cx">     double before = 0;
</span><del>-    if (reportCompileTimes())
</del><ins>+    CString codeBlockName;
+    if (reportCompileTimes()) {
</ins><span class="cx">         before = currentTimeMS();
</span><ins>+        codeBlockName = toCString(*codeBlock);
+    }
</ins><span class="cx">     
</span><span class="cx">     SamplingRegion samplingRegion(&quot;DFG Compilation (Plan)&quot;);
</span><span class="cx">     CompilationScope compilationScope;
</span><span class="lines">@@ -154,7 +157,8 @@
</span><span class="cx"> 
</span><span class="cx">     CompilationPath path = compileInThreadImpl(longLivedState);
</span><span class="cx"> 
</span><del>-    RELEASE_ASSERT(finalizer);
</del><ins>+    RELEASE_ASSERT(path == CancelPath || finalizer);
+    RELEASE_ASSERT((path == CancelPath) == (stage == Cancelled));
</ins><span class="cx">     
</span><span class="cx">     if (reportCompileTimes()) {
</span><span class="cx">         const char* pathName;
</span><span class="lines">@@ -168,13 +172,16 @@
</span><span class="cx">         case FTLPath:
</span><span class="cx">             pathName = &quot;FTL&quot;;
</span><span class="cx">             break;
</span><ins>+        case CancelPath:
+            pathName = &quot;Cancelled&quot;;
+            break;
</ins><span class="cx">         default:
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">             pathName = &quot;&quot;;
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         double now = currentTimeMS();
</span><del>-        dataLog(&quot;Optimized &quot;, *codeBlock, &quot; using &quot;, mode, &quot; with &quot;, pathName, &quot; into &quot;, finalizer-&gt;codeSize(), &quot; bytes in &quot;, now - before, &quot; ms&quot;);
</del><ins>+        dataLog(&quot;Optimized &quot;, codeBlockName, &quot; using &quot;, mode, &quot; with &quot;, pathName, &quot; into &quot;, finalizer ? finalizer-&gt;codeSize() : 0, &quot; bytes in &quot;, now - before, &quot; ms&quot;);
</ins><span class="cx">         if (path == FTLPath)
</span><span class="cx">             dataLog(&quot; (DFG: &quot;, beforeFTL - before, &quot;, LLVM: &quot;, now - beforeFTL, &quot;)&quot;);
</span><span class="cx">         dataLog(&quot;.\n&quot;);
</span><span class="lines">@@ -322,10 +329,13 @@
</span><span class="cx">         dumpAndVerifyGraph(dfg, &quot;Graph just before FTL lowering:&quot;);
</span><span class="cx">         
</span><span class="cx">         bool haveLLVM;
</span><ins>+        Safepoint::Result safepointResult;
</ins><span class="cx">         {
</span><del>-            GraphSafepoint safepoint(dfg);
</del><ins>+            GraphSafepoint safepoint(dfg, safepointResult);
</ins><span class="cx">             haveLLVM = initializeLLVM();
</span><span class="cx">         }
</span><ins>+        if (safepointResult.didGetCancelled())
+            return CancelPath;
</ins><span class="cx">         
</span><span class="cx">         if (!haveLLVM) {
</span><span class="cx">             finalizer = adoptPtr(new FailedFinalizer(*this));
</span><span class="lines">@@ -343,8 +353,10 @@
</span><span class="cx">             return FTLPath;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        FTL::compile(state);
-            
</del><ins>+        FTL::compile(state, safepointResult);
+        if (safepointResult.didGetCancelled())
+            return CancelPath;
+        
</ins><span class="cx">         if (Options::llvmAlwaysFailsBeforeLink()) {
</span><span class="cx">             FTL::fail(state);
</span><span class="cx">             return FTLPath;
</span><span class="lines">@@ -384,10 +396,20 @@
</span><span class="cx">     writeBarriers.trigger(vm);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Plan::notifyCompiling()
+{
+    stage = Compiling;
+}
+
+void Plan::notifyCompiled()
+{
+    stage = Compiled;
+}
+
</ins><span class="cx"> void Plan::notifyReady()
</span><span class="cx"> {
</span><span class="cx">     callback-&gt;compilationDidBecomeReadyAsynchronously(codeBlock.get());
</span><del>-    isCompiled = true;
</del><ins>+    stage = Ready;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CompilationResult Plan::finalizeWithoutNotifyingCallback()
</span><span class="lines">@@ -419,8 +441,11 @@
</span><span class="cx">     return CompilationKey(codeBlock-&gt;alternative(), mode);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Plan::visitChildren(SlotVisitor&amp; visitor, CodeBlockSet&amp; codeBlocks)
</del><ins>+void Plan::checkLivenessAndVisitChildren(SlotVisitor&amp; visitor, CodeBlockSet&amp; codeBlocks)
</ins><span class="cx"> {
</span><ins>+    if (!isKnownToBeLiveDuringGC())
+        return;
+    
</ins><span class="cx">     for (unsigned i = mustHandleValues.size(); i--;)
</span><span class="cx">         visitor.appendUnbarrieredValue(&amp;mustHandleValues[i]);
</span><span class="cx">     
</span><span class="lines">@@ -434,6 +459,37 @@
</span><span class="cx">     transitions.visitChildren(visitor);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Plan::isKnownToBeLiveDuringGC()
+{
+    if (stage == Cancelled)
+        return false;
+    if (!Heap::isMarked(codeBlock-&gt;ownerExecutable()))
+        return false;
+    if (!codeBlock-&gt;alternative()-&gt;isKnownToBeLiveDuringGC())
+        return false;
+    if (!!profiledDFGCodeBlock &amp;&amp; !profiledDFGCodeBlock-&gt;isKnownToBeLiveDuringGC())
+        return false;
+    return true;
+}
+
+void Plan::cancel()
+{
+    codeBlock = nullptr;
+    profiledDFGCodeBlock = nullptr;
+    mustHandleValues.clear();
+    compilation = nullptr;
+    finalizer.clear();
+    inlineCallFrames = nullptr;
+    watchpoints = DesiredWatchpoints();
+    identifiers = DesiredIdentifiers();
+    chains = DesiredStructureChains();
+    weakReferences = DesiredWeakReferences();
+    writeBarriers = DesiredWriteBarriers();
+    transitions = DesiredTransitions();
+    callback = nullptr;
+    stage = Cancelled;
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlanh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -60,17 +60,21 @@
</span><span class="cx">         CompilationMode, unsigned osrEntryBytecodeIndex,
</span><span class="cx">         const Operands&lt;JSValue&gt;&amp; mustHandleValues);
</span><span class="cx">     ~Plan();
</span><del>-    
</del><ins>+
</ins><span class="cx">     void compileInThread(LongLivedState&amp;, ThreadData*);
</span><span class="cx">     
</span><span class="cx">     CompilationResult finalizeWithoutNotifyingCallback();
</span><span class="cx">     void finalizeAndNotifyCallback();
</span><span class="cx">     
</span><ins>+    void notifyCompiling();
+    void notifyCompiled();
</ins><span class="cx">     void notifyReady();
</span><span class="cx">     
</span><span class="cx">     CompilationKey key();
</span><span class="cx">     
</span><del>-    void visitChildren(SlotVisitor&amp;, CodeBlockSet&amp;);
</del><ins>+    void checkLivenessAndVisitChildren(SlotVisitor&amp;, CodeBlockSet&amp;);
+    bool isKnownToBeLiveDuringGC();
+    void cancel();
</ins><span class="cx">     
</span><span class="cx">     VM&amp; vm;
</span><span class="cx">     RefPtr&lt;CodeBlock&gt; codeBlock;
</span><span class="lines">@@ -96,15 +100,16 @@
</span><span class="cx">     bool willTryToTierUp;
</span><span class="cx"> 
</span><span class="cx">     double beforeFTL;
</span><del>-    
-    bool isCompiled;
</del><span class="cx"> 
</span><ins>+    enum Stage { Preparing, Compiling, Compiled, Ready, Cancelled };
+    Stage stage;
+
</ins><span class="cx">     RefPtr&lt;DeferredCompilationCallback&gt; callback;
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     bool reportCompileTimes() const;
</span><span class="cx">     
</span><del>-    enum CompilationPath { FailPath, DFGPath, FTLPath };
</del><ins>+    enum CompilationPath { FailPath, DFGPath, FTLPath, CancelPath };
</ins><span class="cx">     CompilationPath compileInThreadImpl(LongLivedState&amp;);
</span><span class="cx">     
</span><span class="cx">     bool isStillValid();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafepointcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafepoint.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafepoint.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafepoint.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -35,10 +35,25 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><del>-Safepoint::Safepoint(Plan&amp; plan)
</del><ins>+Safepoint::Result::~Result()
+{
+    RELEASE_ASSERT(m_wasChecked);
+}
+
+bool Safepoint::Result::didGetCancelled()
+{
+    m_wasChecked = true;
+    return m_didGetCancelled;
+}
+
+Safepoint::Safepoint(Plan&amp; plan, Result&amp; result)
</ins><span class="cx">     : m_plan(plan)
</span><span class="cx">     , m_didCallBegin(false)
</span><ins>+    , m_result(result)
</ins><span class="cx"> {
</span><ins>+    RELEASE_ASSERT(result.m_wasChecked);
+    result.m_wasChecked = false;
+    result.m_didGetCancelled = false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Safepoint::~Safepoint()
</span><span class="lines">@@ -46,8 +61,8 @@
</span><span class="cx">     RELEASE_ASSERT(m_didCallBegin);
</span><span class="cx">     if (ThreadData* data = m_plan.threadData) {
</span><span class="cx">         RELEASE_ASSERT(data-&gt;m_safepoint == this);
</span><ins>+        data-&gt;m_rightToRun.lock();
</ins><span class="cx">         data-&gt;m_safepoint = nullptr;
</span><del>-        data-&gt;m_rightToRun.lock();
</del><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -68,13 +83,39 @@
</span><span class="cx">     m_didCallBegin = true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Safepoint::visitChildren(SlotVisitor&amp; visitor)
</del><ins>+void Safepoint::checkLivenessAndVisitChildren(SlotVisitor&amp; visitor)
</ins><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(m_didCallBegin);
</span><ins>+
+    if (m_result.m_didGetCancelled)
+        return; // We were cancelled during a previous GC!
+    
+    if (!isKnownToBeLiveDuringGC())
+        return;
+    
</ins><span class="cx">     for (unsigned i = m_scannables.size(); i--;)
</span><span class="cx">         m_scannables[i]-&gt;visitChildren(visitor);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Safepoint::isKnownToBeLiveDuringGC()
+{
+    RELEASE_ASSERT(m_didCallBegin);
+    
+    if (m_result.m_didGetCancelled)
+        return true; // We were cancelled during a previous GC, so let's not mess with it this time around - pretend it's live and move on.
+    
+    return m_plan.isKnownToBeLiveDuringGC();
+}
+
+void Safepoint::cancel()
+{
+    RELEASE_ASSERT(m_didCallBegin);
+    RELEASE_ASSERT(!m_result.m_didGetCancelled); // We cannot get cancelled twice because subsequent GCs will think that we're alive and they will not do anything to us.
+    
+    m_plan.cancel();
+    m_result.m_didGetCancelled = true;
+}
+
</ins><span class="cx"> VM&amp; Safepoint::vm() const
</span><span class="cx"> {
</span><span class="cx">     return m_plan.vm;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafepointh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafepoint.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafepoint.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafepoint.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -42,14 +42,35 @@
</span><span class="cx"> 
</span><span class="cx"> class Safepoint {
</span><span class="cx"> public:
</span><del>-    Safepoint(Plan&amp;);
</del><ins>+    class Result {
+    public:
+        Result()
+            : m_didGetCancelled(false)
+            , m_wasChecked(true)
+        {
+        }
+        
+        ~Result();
+        
+        bool didGetCancelled();
+        
+    private:
+        friend class Safepoint;
+        
+        bool m_didGetCancelled;
+        bool m_wasChecked;
+    };
+    
+    Safepoint(Plan&amp;, Result&amp;);
</ins><span class="cx">     ~Safepoint();
</span><span class="cx">     
</span><span class="cx">     void add(Scannable*);
</span><span class="cx">     
</span><span class="cx">     void begin();
</span><span class="cx">     
</span><del>-    void visitChildren(SlotVisitor&amp;);
</del><ins>+    void checkLivenessAndVisitChildren(SlotVisitor&amp;);
+    bool isKnownToBeLiveDuringGC();
+    void cancel();
</ins><span class="cx">     
</span><span class="cx">     VM&amp; vm() const;
</span><span class="cx"> 
</span><span class="lines">@@ -57,6 +78,7 @@
</span><span class="cx">     Plan&amp; m_plan;
</span><span class="cx">     Vector&lt;Scannable*&gt; m_scannables;
</span><span class="cx">     bool m_didCallBegin;
</span><ins>+    Result&amp; m_result;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWorklistcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGWorklist.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -105,7 +105,7 @@
</span><span class="cx">     PlanMap::iterator iter = m_plans.find(key);
</span><span class="cx">     if (iter == m_plans.end())
</span><span class="cx">         return NotKnown;
</span><del>-    return iter-&gt;value-&gt;isCompiled ? Compiled : Compiling;
</del><ins>+    return iter-&gt;value-&gt;stage == Plan::Ready ? Compiled : Compiling;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Worklist::waitUntilAllPlansForVMAreReady(VM&amp; vm)
</span><span class="lines">@@ -130,7 +130,7 @@
</span><span class="cx">         for (PlanMap::iterator iter = m_plans.begin(); iter != end; ++iter) {
</span><span class="cx">             if (&amp;iter-&gt;value-&gt;vm != &amp;vm)
</span><span class="cx">                 continue;
</span><del>-            if (!iter-&gt;value-&gt;isCompiled) {
</del><ins>+            if (iter-&gt;value-&gt;stage != Plan::Ready) {
</ins><span class="cx">                 allAreCompiled = false;
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="lines">@@ -151,7 +151,7 @@
</span><span class="cx">         RefPtr&lt;Plan&gt; plan = m_readyPlans[i];
</span><span class="cx">         if (&amp;plan-&gt;vm != &amp;vm)
</span><span class="cx">             continue;
</span><del>-        if (!plan-&gt;isCompiled)
</del><ins>+        if (plan-&gt;stage != Plan::Ready)
</ins><span class="cx">             continue;
</span><span class="cx">         myReadyPlans.append(plan);
</span><span class="cx">         m_readyPlans[i--] = m_readyPlans.last();
</span><span class="lines">@@ -182,7 +182,7 @@
</span><span class="cx">         if (Options::verboseCompilationQueue())
</span><span class="cx">             dataLog(*this, &quot;: Completing &quot;, currentKey, &quot;\n&quot;);
</span><span class="cx">         
</span><del>-        RELEASE_ASSERT(plan-&gt;isCompiled);
</del><ins>+        RELEASE_ASSERT(plan-&gt;stage == Plan::Ready);
</ins><span class="cx">         
</span><span class="cx">         plan-&gt;finalizeAndNotifyCallback();
</span><span class="cx">         
</span><span class="lines">@@ -220,7 +220,7 @@
</span><span class="cx">     m_suspensionLock.unlock();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Worklist::visitChildren(SlotVisitor&amp; visitor, CodeBlockSet&amp; codeBlocks)
</del><ins>+void Worklist::visitWeakReferences(SlotVisitor&amp; visitor, CodeBlockSet&amp; codeBlocks)
</ins><span class="cx"> {
</span><span class="cx">     VM* vm = visitor.heap()-&gt;vm();
</span><span class="cx">     {
</span><span class="lines">@@ -229,11 +229,10 @@
</span><span class="cx">             Plan* plan = iter-&gt;value.get();
</span><span class="cx">             if (&amp;plan-&gt;vm != vm)
</span><span class="cx">                 continue;
</span><del>-            iter-&gt;value-&gt;visitChildren(visitor, codeBlocks);
</del><ins>+            iter-&gt;value-&gt;checkLivenessAndVisitChildren(visitor, codeBlocks);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
-    // This loop doesn't need further locking because:
</del><ins>+    // This loop doesn't need locking because:
</ins><span class="cx">     // (1) no new threads can be added to m_threads. Hence, it is immutable and needs no locks.
</span><span class="cx">     // (2) ThreadData::m_safepoint is protected by that thread's m_rightToRun which we must be
</span><span class="cx">     //     holding here because of a prior call to suspendAllThreads().
</span><span class="lines">@@ -241,10 +240,58 @@
</span><span class="cx">         ThreadData* data = m_threads[i].get();
</span><span class="cx">         Safepoint* safepoint = data-&gt;m_safepoint;
</span><span class="cx">         if (safepoint &amp;&amp; &amp;safepoint-&gt;vm() == vm)
</span><del>-            safepoint-&gt;visitChildren(visitor);
</del><ins>+            safepoint-&gt;checkLivenessAndVisitChildren(visitor);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Worklist::removeDeadPlans(VM&amp; vm)
+{
+    {
+        MutexLocker locker(m_lock);
+        HashSet&lt;CompilationKey&gt; deadPlanKeys;
+        for (PlanMap::iterator iter = m_plans.begin(); iter != m_plans.end(); ++iter) {
+            Plan* plan = iter-&gt;value.get();
+            if (&amp;plan-&gt;vm != &amp;vm)
+                continue;
+            if (plan-&gt;isKnownToBeLiveDuringGC())
+                continue;
+            RELEASE_ASSERT(plan-&gt;stage != Plan::Cancelled); // Should not be cancelled, yet.
+            ASSERT(!deadPlanKeys.contains(plan-&gt;key()));
+            deadPlanKeys.add(plan-&gt;key());
+        }
+        if (!deadPlanKeys.isEmpty()) {
+            for (HashSet&lt;CompilationKey&gt;::iterator iter = deadPlanKeys.begin(); iter != deadPlanKeys.end(); ++iter)
+                m_plans.take(*iter)-&gt;cancel();
+            Deque&lt;RefPtr&lt;Plan&gt;&gt; newQueue;
+            while (!m_queue.isEmpty()) {
+                RefPtr&lt;Plan&gt; plan = m_queue.takeFirst();
+                if (plan-&gt;stage != Plan::Cancelled)
+                    newQueue.append(plan);
+            }
+            m_queue.swap(newQueue);
+            for (unsigned i = 0; i &lt; m_readyPlans.size(); ++i) {
+                if (m_readyPlans[i]-&gt;stage != Plan::Cancelled)
+                    continue;
+                m_readyPlans[i] = m_readyPlans.last();
+                m_readyPlans.removeLast();
+            }
+        }
+    }
+    
+    // No locking needed for this part, see comment in visitWeakReferences().
+    for (unsigned i = m_threads.size(); i--;) {
+        ThreadData* data = m_threads[i].get();
+        Safepoint* safepoint = data-&gt;m_safepoint;
+        if (!safepoint)
+            continue;
+        if (&amp;safepoint-&gt;vm() != &amp;vm)
+            continue;
+        if (safepoint-&gt;isKnownToBeLiveDuringGC())
+            continue;
+        safepoint-&gt;cancel();
+    }
+}
+
</ins><span class="cx"> size_t Worklist::queueLength()
</span><span class="cx"> {
</span><span class="cx">     MutexLocker locker(m_lock);
</span><span class="lines">@@ -294,15 +341,43 @@
</span><span class="cx">         
</span><span class="cx">         {
</span><span class="cx">             MutexLocker locker(data-&gt;m_rightToRun);
</span><ins>+            {
+                MutexLocker locker(m_lock);
+                if (plan-&gt;stage == Plan::Cancelled) {
+                    m_numberOfActiveThreads--;
+                    continue;
+                }
+                plan-&gt;notifyCompiling();
+            }
</ins><span class="cx">         
</span><span class="cx">             if (Options::verboseCompilationQueue())
</span><span class="cx">                 dataLog(*this, &quot;: Compiling &quot;, plan-&gt;key(), &quot; asynchronously\n&quot;);
</span><span class="cx">         
</span><ins>+            RELEASE_ASSERT(!plan-&gt;vm.heap.isCollecting());
</ins><span class="cx">             plan-&gt;compileInThread(longLivedState, data);
</span><ins>+            RELEASE_ASSERT(!plan-&gt;vm.heap.isCollecting());
+            
+            {
+                MutexLocker locker(m_lock);
+                if (plan-&gt;stage == Plan::Cancelled) {
+                    m_numberOfActiveThreads--;
+                    continue;
+                }
+                plan-&gt;notifyCompiled();
+            }
+            RELEASE_ASSERT(!plan-&gt;vm.heap.isCollecting());
</ins><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         {
</span><span class="cx">             MutexLocker locker(m_lock);
</span><ins>+            
+            // We could have been cancelled between releasing rightToRun and acquiring m_lock.
+            // This would mean that we might be in the middle of GC right now.
+            if (plan-&gt;stage == Plan::Cancelled) {
+                m_numberOfActiveThreads--;
+                continue;
+            }
+            
</ins><span class="cx">             plan-&gt;notifyReady();
</span><span class="cx">             
</span><span class="cx">             if (Options::verboseCompilationQueue()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGWorklisth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGWorklist.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGWorklist.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/dfg/DFGWorklist.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -71,7 +71,9 @@
</span><span class="cx">     
</span><span class="cx">     bool isActiveForVM(VM&amp;) const;
</span><span class="cx">     
</span><del>-    void visitChildren(SlotVisitor&amp;, CodeBlockSet&amp;); // Only called on the main thread after suspending all threads.
</del><ins>+    // Only called on the main thread after suspending all threads.
+    void visitWeakReferences(SlotVisitor&amp;, CodeBlockSet&amp;);
+    void removeDeadPlans(VM&amp;);
</ins><span class="cx">     
</span><span class="cx">     void dump(PrintStream&amp;) const;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -490,12 +490,12 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void compile(State&amp; state)
</del><ins>+void compile(State&amp; state, Safepoint::Result&amp; safepointResult)
</ins><span class="cx"> {
</span><span class="cx">     char* error = 0;
</span><span class="cx">     
</span><span class="cx">     {
</span><del>-        GraphSafepoint safepoint(state.graph);
</del><ins>+        GraphSafepoint safepoint(state.graph, safepointResult);
</ins><span class="cx">         
</span><span class="cx">         LLVMMCJITCompilerOptions options;
</span><span class="cx">         llvm-&gt;InitializeMCJITCompilerOptions(&amp;options, sizeof(options));
</span><span class="lines">@@ -566,7 +566,10 @@
</span><span class="cx">         llvm-&gt;DisposePassManager(modulePasses);
</span><span class="cx">         llvm-&gt;DisposeExecutionEngine(engine);
</span><span class="cx">     }
</span><del>-
</del><ins>+    if (safepointResult.didGetCancelled())
+        return;
+    RELEASE_ASSERT(!state.graph.m_vm.heap.isCollecting());
+    
</ins><span class="cx">     if (shouldShowDisassembly()) {
</span><span class="cx">         for (unsigned i = 0; i &lt; state.jitCode-&gt;handles().size(); ++i) {
</span><span class="cx">             ExecutableMemoryHandle* handle = state.jitCode-&gt;handles()[i].get();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompileh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -28,11 +28,12 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(FTL_JIT)
</span><span class="cx"> 
</span><ins>+#include &quot;DFGSafepoint.h&quot;
</ins><span class="cx"> #include &quot;FTLState.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace FTL {
</span><span class="cx"> 
</span><del>-void compile(State&amp;);
</del><ins>+void compile(State&amp;, DFG::Safepoint::Result&amp;);
</ins><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::FTL
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -145,6 +145,8 @@
</span><span class="cx"> void CodeBlockSet::rememberCurrentlyExecutingCodeBlocks(Heap* heap)
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(GGC)
</span><ins>+    if (verbose)
+        dataLog(&quot;Remembering &quot;, m_currentlyExecuting.size(), &quot; code blocks.\n&quot;);
</ins><span class="cx">     for (CodeBlock* codeBlock : m_currentlyExecuting) {
</span><span class="cx">         heap-&gt;addToRememberedSet(codeBlock-&gt;ownerExecutable());
</span><span class="cx">         ASSERT(codeBlock-&gt;m_mayBeExecuting);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -516,7 +516,6 @@
</span><span class="cx">         visitExternalRememberedSet();
</span><span class="cx">         visitSmallStrings();
</span><span class="cx">         visitConservativeRoots(conservativeRoots);
</span><del>-        visitCompilerWorklists();
</del><span class="cx">         visitProtectedObjects(heapRootVisitor);
</span><span class="cx">         visitTempSortVectors(heapRootVisitor);
</span><span class="cx">         visitArgumentBuffers(heapRootVisitor);
</span><span class="lines">@@ -622,17 +621,23 @@
</span><span class="cx">     m_slotVisitor.donateAndDrain();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::visitCompilerWorklists()
</del><ins>+void Heap::visitCompilerWorklistWeakReferences()
</ins><span class="cx"> {
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><del>-    GCPHASE(VisitDFGWorklists);
</del><span class="cx">     for (auto worklist : m_suspendedCompilerWorklists)
</span><del>-        worklist-&gt;visitChildren(m_slotVisitor, m_codeBlocks);
</del><ins>+        worklist-&gt;visitWeakReferences(m_slotVisitor, m_codeBlocks);
</ins><span class="cx"> 
</span><span class="cx">     if (Options::logGC() == GCLogging::Verbose)
</span><span class="cx">         dataLog(&quot;DFG Worklists:\n&quot;, m_slotVisitor);
</span><ins>+#endif
+}
</ins><span class="cx"> 
</span><del>-    m_slotVisitor.donateAndDrain();
</del><ins>+void Heap::removeDeadCompilerWorklistEntries()
+{
+#if ENABLE(DFG_JIT)
+    GCPHASE(FinalizeDFGWorklists);
+    for (auto worklist : m_suspendedCompilerWorklists)
+        worklist-&gt;removeDeadPlans(*m_vm);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -743,6 +748,8 @@
</span><span class="cx">     while (true) {
</span><span class="cx">         m_objectSpace.visitWeakSets(visitor);
</span><span class="cx">         harvestWeakReferences();
</span><ins>+        visitCompilerWorklistWeakReferences();
+        m_codeBlocks.traceMarked(m_slotVisitor); // New &quot;executing&quot; code blocks may be discovered.
</ins><span class="cx">         if (m_slotVisitor.isEmpty())
</span><span class="cx">             break;
</span><span class="cx"> 
</span><span class="lines">@@ -998,6 +1005,7 @@
</span><span class="cx">     copyBackingStores();
</span><span class="cx"> 
</span><span class="cx">     finalizeUnconditionalFinalizers();
</span><ins>+    removeDeadCompilerWorklistEntries();
</ins><span class="cx">     deleteUnmarkedCompiledCode();
</span><span class="cx">     deleteSourceProviderCaches();
</span><span class="cx">     notifyIncrementalSweeper();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -274,7 +274,8 @@
</span><span class="cx">     void visitExternalRememberedSet();
</span><span class="cx">     void visitSmallStrings();
</span><span class="cx">     void visitConservativeRoots(ConservativeRoots&amp;);
</span><del>-    void visitCompilerWorklists();
</del><ins>+    void visitCompilerWorklistWeakReferences();
+    void removeDeadCompilerWorklistEntries();
</ins><span class="cx">     void visitProtectedObjects(HeapRootVisitor&amp;);
</span><span class="cx">     void visitTempSortVectors(HeapRootVisitor&amp;);
</span><span class="cx">     void visitArgumentBuffers(HeapRootVisitor&amp;);
</span></span></pre></div>
<a id="trunkSourceWTFwtfThreadingPthreadscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/ThreadingPthreads.cpp (167896 => 167897)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/ThreadingPthreads.cpp        2014-04-28 18:45:44 UTC (rev 167896)
+++ trunk/Source/WTF/wtf/ThreadingPthreads.cpp        2014-04-28 19:01:07 UTC (rev 167897)
</span><span class="lines">@@ -44,6 +44,8 @@
</span><span class="cx"> #include &quot;ThreadFunctionInvocation.h&quot;
</span><span class="cx"> #include &quot;ThreadIdentifierDataPthreads.h&quot;
</span><span class="cx"> #include &quot;ThreadSpecific.h&quot;
</span><ins>+#include &lt;wtf/DataLog.h&gt;
+#include &lt;wtf/RawPointer.h&gt;
</ins><span class="cx"> #include &lt;wtf/WTFThreadData.h&gt;
</span><span class="cx"> #include &lt;errno.h&gt;
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>