<!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>[165995] 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/165995">165995</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-03-20 13:53:37 -0700 (Thu, 20 Mar 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Crash beneath operationTearOffActivation running this JS compression demo
https://bugs.webkit.org/show_bug.cgi?id=130295
&lt;rdar://problem/16332337&gt;

Reviewed by Oliver Hunt.
        
Make sure that we flush things as if we were at a terminal, if we are at a block with
no forward edges. This fixes infinitely loopy code with captured variables.

Make sure that the CFG simplifier adds explicit flushes whenever it jettisons a block.
        
Make it so that NodeIsFlushed is a thing. Previously only SSA used it and it computed
it by itself. Now it's an artifact of CPS rethreading.
        
Add a bunch of tests. All of them previously either crashed or returned bad output due
to memory corruption.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::isCaptured):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::flushForTerminal):
(JSC::DFG::ByteCodeParser::flushForReturn):
(JSC::DFG::ByteCodeParser::flushIfTerminal):
(JSC::DFG::ByteCodeParser::branchData):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
* dfg/DFGCPSRethreadingPhase.cpp:
(JSC::DFG::CPSRethreadingPhase::run):
(JSC::DFG::CPSRethreadingPhase::computeIsFlushed):
(JSC::DFG::CPSRethreadingPhase::addFlushedLocalOp):
(JSC::DFG::CPSRethreadingPhase::addFlushedLocalEdge):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::clearFlagsOnAllNodes):
* dfg/DFGGraph.h:
* dfg/DFGNode.h:
* dfg/DFGNodeFlags.cpp:
(JSC::DFG::dumpNodeFlags):
* dfg/DFGNodeFlags.h:
* dfg/DFGSSAConversionPhase.cpp:
(JSC::DFG::SSAConversionPhase::run):
* tests/stress/activation-test-loop.js: Added.
(Inner.this.doStuff):
(Inner):
(foo.inner.isDone):
(foo):
* tests/stress/inferred-infinite-loop-that-uses-captured-variables.js: Added.
(bar):
(foo):
(noInline):
* tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js: Added.
(bar):
(foo):
(noInline):
* tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js: Added.
(bar):
(foo):
(noInline):
* tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js: Added.
(bar):
(foo):
(noInline):
* tests/stress/infinite-loop-that-uses-captured-variables.js: Added.
(bar):
(foo):
(noInline):
* tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added.
(bar):
(fuzz):
(foo.f):
(foo):
* tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added.
(bar):
(foo.f):
(foo):
* tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added.
(bar):
(foo.f):
(foo):
* tests/stress/tricky-infinite-loop-that-uses-captured-variables.js: Added.
(bar):
(foo):
(noInline):</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="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCFGSimplificationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCPSRethreadingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCSEPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeFlagscpp">trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeFlagsh">trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressactivationtestloopjs">trunk/Source/JavaScriptCore/tests/stress/activation-test-loop.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressinferredinfiniteloopthatusescapturedvariablesjs">trunk/Source/JavaScriptCore/tests/stress/inferred-infinite-loop-that-uses-captured-variables.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariablesbeforethrowingjs">trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariablesbuttheydonotescapejs">trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariableswithosrentryjs">trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariablesjs">trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrickyindirectlyinferredinfiniteloopthatusescapturedvariablesandcreatestheactivationoutsidetheloopjs">trunk/Source/JavaScriptCore/tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrickyinferredinfiniteloopthatusescapturedvariablesandcreatestheactivationoutsidetheloopjs">trunk/Source/JavaScriptCore/tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrickyinfiniteloopthatusescapturedvariablesandcreatestheactivationoutsidetheloopjs">trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstrickyinfiniteloopthatusescapturedvariablesjs">trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -1,3 +1,91 @@
</span><ins>+2014-03-20  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Crash beneath operationTearOffActivation running this JS compression demo
+        https://bugs.webkit.org/show_bug.cgi?id=130295
+        &lt;rdar://problem/16332337&gt;
+
+        Reviewed by Oliver Hunt.
+        
+        Make sure that we flush things as if we were at a terminal, if we are at a block with
+        no forward edges. This fixes infinitely loopy code with captured variables.
+
+        Make sure that the CFG simplifier adds explicit flushes whenever it jettisons a block.
+        
+        Make it so that NodeIsFlushed is a thing. Previously only SSA used it and it computed
+        it by itself. Now it's an artifact of CPS rethreading.
+        
+        Add a bunch of tests. All of them previously either crashed or returned bad output due
+        to memory corruption.
+
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::isCaptured):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::flushForTerminal):
+        (JSC::DFG::ByteCodeParser::flushForReturn):
+        (JSC::DFG::ByteCodeParser::flushIfTerminal):
+        (JSC::DFG::ByteCodeParser::branchData):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCFGSimplificationPhase.cpp:
+        (JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
+        * dfg/DFGCPSRethreadingPhase.cpp:
+        (JSC::DFG::CPSRethreadingPhase::run):
+        (JSC::DFG::CPSRethreadingPhase::computeIsFlushed):
+        (JSC::DFG::CPSRethreadingPhase::addFlushedLocalOp):
+        (JSC::DFG::CPSRethreadingPhase::addFlushedLocalEdge):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::clearFlagsOnAllNodes):
+        * dfg/DFGGraph.h:
+        * dfg/DFGNode.h:
+        * dfg/DFGNodeFlags.cpp:
+        (JSC::DFG::dumpNodeFlags):
+        * dfg/DFGNodeFlags.h:
+        * dfg/DFGSSAConversionPhase.cpp:
+        (JSC::DFG::SSAConversionPhase::run):
+        * tests/stress/activation-test-loop.js: Added.
+        (Inner.this.doStuff):
+        (Inner):
+        (foo.inner.isDone):
+        (foo):
+        * tests/stress/inferred-infinite-loop-that-uses-captured-variables.js: Added.
+        (bar):
+        (foo):
+        (noInline):
+        * tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js: Added.
+        (bar):
+        (foo):
+        (noInline):
+        * tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js: Added.
+        (bar):
+        (foo):
+        (noInline):
+        * tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js: Added.
+        (bar):
+        (foo):
+        (noInline):
+        * tests/stress/infinite-loop-that-uses-captured-variables.js: Added.
+        (bar):
+        (foo):
+        (noInline):
+        * tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added.
+        (bar):
+        (fuzz):
+        (foo.f):
+        (foo):
+        * tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added.
+        (bar):
+        (foo.f):
+        (foo):
+        * tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js: Added.
+        (bar):
+        (foo.f):
+        (foo):
+        * tests/stress/tricky-infinite-loop-that-uses-captured-variables.js: Added.
+        (bar):
+        (foo):
+        (noInline):
+
</ins><span class="cx"> 2014-03-20  Oliver Hunt  &lt;oliver@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Incorrect behavior when mutating a typed array during set.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -2439,8 +2439,6 @@
</span><span class="cx">     // Ditto for the arguments object.
</span><span class="cx">     if (usesArguments() &amp;&amp; operand == argumentsRegister())
</span><span class="cx">         return true;
</span><del>-
-    // Ditto for the arguments object.
</del><span class="cx">     if (usesArguments() &amp;&amp; operand == unmodifiedArgumentsRegister(argumentsRegister()))
</span><span class="cx">         return true;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -481,7 +481,7 @@
</span><span class="cx">         if (argumentPosition)
</span><span class="cx">             argumentPosition-&gt;addVariable(variable);
</span><span class="cx">     }
</span><del>-
</del><ins>+    
</ins><span class="cx">     void flush(InlineStackEntry* inlineStackEntry)
</span><span class="cx">     {
</span><span class="cx">         int numArguments;
</span><span class="lines">@@ -502,16 +502,29 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void flushAllArgumentsAndCapturedVariablesInInlineStack()
</del><ins>+    void flushForTerminal()
</ins><span class="cx">     {
</span><span class="cx">         for (InlineStackEntry* inlineStackEntry = m_inlineStackTop; inlineStackEntry; inlineStackEntry = inlineStackEntry-&gt;m_caller)
</span><span class="cx">             flush(inlineStackEntry);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void flushArgumentsAndCapturedVariables()
</del><ins>+    void flushForReturn()
</ins><span class="cx">     {
</span><span class="cx">         flush(m_inlineStackTop);
</span><span class="cx">     }
</span><ins>+    
+    void flushIfTerminal(SwitchData&amp; data)
+    {
+        if (data.fallThrough.bytecodeIndex() &gt; m_currentIndex)
+            return;
+        
+        for (unsigned i = data.cases.size(); i--;) {
+            if (data.cases[i].target.bytecodeIndex() &gt; m_currentIndex)
+                return;
+        }
+        
+        flushForTerminal();
+    }
</ins><span class="cx"> 
</span><span class="cx">     // NOTE: Only use this to construct constants that arise from non-speculative
</span><span class="cx">     // constant folding. I.e. creating constants using this if we had constant
</span><span class="lines">@@ -720,6 +733,9 @@
</span><span class="cx"> 
</span><span class="cx">     BranchData* branchData(unsigned taken, unsigned notTaken)
</span><span class="cx">     {
</span><ins>+        // We assume that branches originating from bytecode always have a fall-through. We
+        // use this assumption to avoid checking for the creation of terminal blocks.
+        ASSERT((taken &gt; m_currentIndex) || (notTaken &gt; m_currentIndex));
</ins><span class="cx">         BranchData* data = m_graph.m_branchData.add();
</span><span class="cx">         *data = BranchData::withBytecodeIndices(taken, notTaken);
</span><span class="cx">         return data;
</span><span class="lines">@@ -2726,7 +2742,9 @@
</span><span class="cx">         // === Block terminators. ===
</span><span class="cx"> 
</span><span class="cx">         case op_jmp: {
</span><del>-            unsigned relativeOffset = currentInstruction[1].u.operand;
</del><ins>+            int relativeOffset = currentInstruction[1].u.operand;
+            if (relativeOffset &lt;= 0)
+                flushForTerminal();
</ins><span class="cx">             addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
</span><span class="cx">             LAST_OPCODE(op_jmp);
</span><span class="cx">         }
</span><span class="lines">@@ -3007,6 +3025,7 @@
</span><span class="cx">                     continue;
</span><span class="cx">                 data.cases.append(SwitchCase::withBytecodeIndex(jsNumber(static_cast&lt;int32_t&gt;(table.min + i)), target));
</span><span class="cx">             }
</span><ins>+            flushIfTerminal(data);
</ins><span class="cx">             addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</span><span class="cx">             LAST_OPCODE(op_switch_imm);
</span><span class="cx">         }
</span><span class="lines">@@ -3026,6 +3045,7 @@
</span><span class="cx">                 data.cases.append(
</span><span class="cx">                     SwitchCase::withBytecodeIndex(LazyJSValue::singleCharacterString(table.min + i), target));
</span><span class="cx">             }
</span><ins>+            flushIfTerminal(data);
</ins><span class="cx">             addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</span><span class="cx">             LAST_OPCODE(op_switch_char);
</span><span class="cx">         }
</span><span class="lines">@@ -3045,12 +3065,13 @@
</span><span class="cx">                 data.cases.append(
</span><span class="cx">                     SwitchCase::withBytecodeIndex(LazyJSValue::knownStringImpl(iter-&gt;key.get()), target));
</span><span class="cx">             }
</span><ins>+            flushIfTerminal(data);
</ins><span class="cx">             addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</span><span class="cx">             LAST_OPCODE(op_switch_string);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_ret:
</span><del>-            flushArgumentsAndCapturedVariables();
</del><ins>+            flushForReturn();
</ins><span class="cx">             if (inlineCallFrame()) {
</span><span class="cx">                 ASSERT(m_inlineStackTop-&gt;m_returnValue.isValid());
</span><span class="cx">                 setDirect(m_inlineStackTop-&gt;m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSet);
</span><span class="lines">@@ -3078,20 +3099,20 @@
</span><span class="cx">             LAST_OPCODE(op_ret);
</span><span class="cx">             
</span><span class="cx">         case op_end:
</span><del>-            flushArgumentsAndCapturedVariables();
</del><ins>+            flushForReturn();
</ins><span class="cx">             ASSERT(!inlineCallFrame());
</span><span class="cx">             addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
</span><span class="cx">             LAST_OPCODE(op_end);
</span><span class="cx"> 
</span><span class="cx">         case op_throw:
</span><span class="cx">             addToGraph(Throw, get(VirtualRegister(currentInstruction[1].u.operand)));
</span><del>-            flushAllArgumentsAndCapturedVariablesInInlineStack();
</del><ins>+            flushForTerminal();
</ins><span class="cx">             addToGraph(Unreachable);
</span><span class="cx">             LAST_OPCODE(op_throw);
</span><span class="cx">             
</span><span class="cx">         case op_throw_static_error:
</span><span class="cx">             addToGraph(ThrowReferenceError);
</span><del>-            flushAllArgumentsAndCapturedVariablesInInlineStack();
</del><ins>+            flushForTerminal();
</ins><span class="cx">             addToGraph(Unreachable);
</span><span class="cx">             LAST_OPCODE(op_throw_static_error);
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCFGSimplificationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -263,16 +263,19 @@
</span><span class="cx">                 m_graph, SpecNone, Jump, branch-&gt;origin, OpInfo(targetBlock));
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-
</del><ins>+    
</ins><span class="cx">     void keepOperandAlive(BasicBlock* block, BasicBlock* jettisonedBlock, NodeOrigin nodeOrigin, VirtualRegister operand)
</span><span class="cx">     {
</span><span class="cx">         Node* livenessNode = jettisonedBlock-&gt;variablesAtHead.operand(operand);
</span><span class="cx">         if (!livenessNode)
</span><span class="cx">             return;
</span><del>-        if (livenessNode-&gt;variableAccessData()-&gt;isCaptured())
-            return;
</del><ins>+        NodeType nodeType;
+        if (livenessNode-&gt;flags() &amp; NodeIsFlushed)
+            nodeType = Flush;
+        else
+            nodeType = PhantomLocal;
</ins><span class="cx">         block-&gt;appendNode(
</span><del>-            m_graph, SpecNone, PhantomLocal, nodeOrigin, 
</del><ins>+            m_graph, SpecNone, nodeType, nodeOrigin, 
</ins><span class="cx">             OpInfo(livenessNode-&gt;variableAccessData()));
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCPSRethreadingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -55,6 +55,7 @@
</span><span class="cx">         canonicalizeLocalsInBlocks();
</span><span class="cx">         propagatePhis&lt;LocalOperand&gt;();
</span><span class="cx">         propagatePhis&lt;ArgumentOperand&gt;();
</span><ins>+        computeIsFlushed();
</ins><span class="cx">         
</span><span class="cx">         m_graph.m_form = ThreadedCPS;
</span><span class="cx">         return true;
</span><span class="lines">@@ -482,9 +483,43 @@
</span><span class="cx">         return m_localPhiStack;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void computeIsFlushed()
+    {
+        m_graph.clearFlagsOnAllNodes(NodeIsFlushed);
+        
+        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
+                continue;
+            for (unsigned nodeIndex = block-&gt;size(); nodeIndex--;) {
+                Node* node = block-&gt;at(nodeIndex);
+                if (node-&gt;op() != Flush)
+                    continue;
+                addFlushedLocalOp(node);
+            }
+        }
+        while (!m_flushedLocalOpWorklist.isEmpty()) {
+            Node* node = m_flushedLocalOpWorklist.takeLast();
+            ASSERT(node-&gt;flags() &amp; NodeIsFlushed);
+            DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge);
+        }
+    }
+    
+    void addFlushedLocalOp(Node* node)
+    {
+        if (node-&gt;mergeFlags(NodeIsFlushed))
+            m_flushedLocalOpWorklist.append(node);
+    }
+
+    void addFlushedLocalEdge(Node*, Edge edge)
+    {
+        addFlushedLocalOp(edge.node());
+    }
+
</ins><span class="cx">     BasicBlock* m_block;
</span><span class="cx">     Vector&lt;PhiStackEntry, 128&gt; m_argumentPhiStack;
</span><span class="cx">     Vector&lt;PhiStackEntry, 128&gt; m_localPhiStack;
</span><ins>+    Vector&lt;Node*, 128&gt; m_flushedLocalOpWorklist;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> bool performCPSRethreading(Graph&amp; graph)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCSEPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -1225,13 +1225,15 @@
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case Flush: {
</span><del>-            if (m_graph.m_form == SSA) {
-                // FIXME: Enable Flush store elimination in SSA form.
-                // https://bugs.webkit.org/show_bug.cgi?id=125429
</del><ins>+            ASSERT(m_graph.m_form != SSA);
+            VariableAccessData* variableAccessData = node-&gt;variableAccessData();
+            VirtualRegister local = variableAccessData-&gt;local();
+            if (!node-&gt;child1()) {
+                // FIXME: It's silly that we punt on flush-eliminating here. We don't really
+                // need child1 to figure out what's going on.
+                // https://bugs.webkit.org/show_bug.cgi?id=130521
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><del>-            VariableAccessData* variableAccessData = node-&gt;variableAccessData();
-            VirtualRegister local = variableAccessData-&gt;local();
</del><span class="cx">             Node* replacement = node-&gt;child1().node();
</span><span class="cx">             if (replacement-&gt;op() != SetLocal)
</span><span class="cx">                 break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -673,6 +673,19 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Graph::clearFlagsOnAllNodes(NodeFlags flags)
+{
+    for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
+        BasicBlock* block = m_blocks[blockIndex].get();
+        if (!block)
+            continue;
+        for (unsigned phiIndex = block-&gt;phis.size(); phiIndex--;)
+            block-&gt;phis[phiIndex]-&gt;clearFlags(flags);
+        for (unsigned nodeIndex = block-&gt;size(); nodeIndex--;)
+            block-&gt;at(nodeIndex)-&gt;clearFlags(flags);
+    }
+}
+
</ins><span class="cx"> FullBytecodeLiveness&amp; Graph::livenessFor(CodeBlock* codeBlock)
</span><span class="cx"> {
</span><span class="cx">     HashMap&lt;CodeBlock*, std::unique_ptr&lt;FullBytecodeLiveness&gt;&gt;::iterator iter = m_bytecodeLiveness.find(codeBlock);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -780,6 +780,8 @@
</span><span class="cx">     
</span><span class="cx">     void invalidateCFG();
</span><span class="cx">     
</span><ins>+    void clearFlagsOnAllNodes(NodeFlags);
+    
</ins><span class="cx">     void clearReplacements();
</span><span class="cx">     void initializeNodeOwners();
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -1657,7 +1657,6 @@
</span><span class="cx">     union {
</span><span class="cx">         Node* replacement;
</span><span class="cx">         BasicBlock* owner;
</span><del>-        bool needsBarrier;
</del><span class="cx">     } misc;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeFlagscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -100,6 +100,9 @@
</span><span class="cx">     if (!(flags &amp; NodeDoesNotExit))
</span><span class="cx">         out.print(comma, &quot;CanExit&quot;);
</span><span class="cx">     
</span><ins>+    if (flags &amp; NodeIsFlushed)
+        out.print(comma, &quot;IsFlushed&quot;);
+    
</ins><span class="cx">     CString string = out.toCString();
</span><span class="cx">     if (!string.length())
</span><span class="cx">         actualOut.print(&quot;&lt;empty&gt;&quot;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeFlagsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -67,6 +67,7 @@
</span><span class="cx"> #define NodeRelevantToOSR                0x4000
</span><span class="cx"> 
</span><span class="cx"> #define NodeIsStaticConstant             0x8000 // Used only by the parser, to determine if a constant arose statically and hence could be folded at parse-time.
</span><ins>+#define NodeIsFlushed                   0x10000 // Used by Graph::computeIsFlushed(), will tell you which local nodes are backwards-reachable from a Flush.
</ins><span class="cx"> 
</span><span class="cx"> typedef uint32_t NodeFlags;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (165994 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2014-03-20 20:49:01 UTC (rev 165994)
+++ trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -57,25 +57,6 @@
</span><span class="cx">             m_graph.dump();
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        // Figure out which SetLocal's need flushing. Need to do this while the
-        // Phi graph is still intact.
-        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
-            BasicBlock* block = m_graph.block(blockIndex);
-            if (!block)
-                continue;
-            for (unsigned nodeIndex = block-&gt;size(); nodeIndex--;) {
-                Node* node = block-&gt;at(nodeIndex);
-                if (node-&gt;op() != Flush)
-                    continue;
-                addFlushedLocalOp(node);
-            }
-        }
-        while (!m_flushedLocalOpWorklist.isEmpty()) {
-            Node* node = m_flushedLocalOpWorklist.takeLast();
-            ASSERT(m_flushedLocalOps.contains(node));
-            DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge);
-        }
-        
</del><span class="cx">         // Eliminate all duplicate or self-pointing Phi edges. This means that
</span><span class="cx">         // we transform:
</span><span class="cx">         //
</span><span class="lines">@@ -158,7 +139,7 @@
</span><span class="cx">                 }
</span><span class="cx">                 RELEASE_ASSERT(node-&gt;op() == Phi || node-&gt;op() == SetArgument);
</span><span class="cx">                 
</span><del>-                bool isFlushed = m_flushedLocalOps.contains(node);
</del><ins>+                bool isFlushed = !!(node-&gt;flags() &amp; NodeIsFlushed);
</ins><span class="cx">                 
</span><span class="cx">                 if (node-&gt;op() == Phi) {
</span><span class="cx">                     if (!nonTrivialPhis.operand(node-&gt;local())) {
</span><span class="lines">@@ -334,7 +315,7 @@
</span><span class="cx">                 switch (node-&gt;op()) {
</span><span class="cx">                 case SetLocal: {
</span><span class="cx">                     VariableAccessData* variable = node-&gt;variableAccessData();
</span><del>-                    if (variable-&gt;isCaptured() || m_flushedLocalOps.contains(node))
</del><ins>+                    if (variable-&gt;isCaptured() || !!(node-&gt;flags() &amp; NodeIsFlushed))
</ins><span class="cx">                         node-&gt;mergeFlags(NodeMustGenerate);
</span><span class="cx">                     else
</span><span class="cx">                         node-&gt;setOpAndDefaultFlags(Check);
</span><span class="lines">@@ -476,22 +457,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void addFlushedLocalOp(Node* node)
-    {
-        if (m_flushedLocalOps.contains(node))
-            return;
-        m_flushedLocalOps.add(node);
-        m_flushedLocalOpWorklist.append(node);
-    }
-
-    void addFlushedLocalEdge(Node*, Edge edge)
-    {
-        addFlushedLocalOp(edge.node());
-    }
-    
</del><span class="cx">     InsertionSet m_insertionSet;
</span><del>-    HashSet&lt;Node*&gt; m_flushedLocalOps;
-    Vector&lt;Node*&gt; m_flushedLocalOpWorklist;
</del><span class="cx">     bool m_changed;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressactivationtestloopjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/activation-test-loop.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/activation-test-loop.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/activation-test-loop.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+function Inner() {
+    this.i = 0;
+    this.doStuff = function() {
+        this.i++;
+        if (this.i &gt; 10000)
+            this.isDone();
+    }
+}
+
+var foo = function() {
+    var inner = new Inner();
+    var done = false;
+    inner.isDone = function() {
+        done = true;
+    }
+
+    while (true) {
+        var val = inner.doStuff();
+        if (done)
+            break;
+    }
+}
+
+foo();
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressinferredinfiniteloopthatusescapturedvariablesjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/inferred-infinite-loop-that-uses-captured-variables.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/inferred-infinite-loop-that-uses-captured-variables.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/inferred-infinite-loop-that-uses-captured-variables.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+function bar(f) {
+    throw f;
+}
+
+noInline(bar);
+
+var shouldContinue = true;
+
+function foo(a) {
+    var x = a + 1;
+    while (shouldContinue) {
+        bar(function() { return x; });
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (f) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + result;
+    }
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariablesbeforethrowingjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-before-throwing.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+var count = 0;
+
+function bar(f) {
+    if (++count &lt; 10) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result insie closure for i = &quot; + i + &quot;: &quot; + result;
+        return;
+    }
+    count = 0;
+    throw f;
+}
+
+noInline(bar);
+
+function foo(a) {
+    var x = a + 1;
+    for (;;) {
+        bar(function() { return x; });
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (f) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + result;
+    }
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariablesbuttheydonotescapejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-but-they-do-not-escape.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+var count = 0;
+
+function bar(f) {
+    if (++count &lt; 10) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result insie closure for i = &quot; + i + &quot;: &quot; + result;
+        return;
+    }
+    count = 0;
+    throw &quot;done&quot;;
+}
+
+noInline(bar);
+
+function foo(a) {
+    var x = a + 1;
+    for (;;) {
+        bar(function() { return x; });
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (done) {
+        if (done != &quot;done&quot;)
+            throw &quot;Error: bad exception: &quot; + done;
+    }
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariableswithosrentryjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables-with-osr-entry.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,26 @@
</span><ins>+var count = 0;
+
+function bar(f) {
+    if (++count &gt;= 10000)
+        throw f;
+}
+
+noInline(bar);
+
+function foo(a) {
+    var x = a + 1;
+    for (;;) {
+        bar(function() { return x; });
+    }
+}
+
+noInline(foo);
+
+try {
+    foo(42);
+} catch (f) {
+    var result = f();
+    if (result != 43)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressinfiniteloopthatusescapturedvariablesjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/infinite-loop-that-uses-captured-variables.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,25 @@
</span><ins>+function bar(f) {
+    throw f;
+}
+
+noInline(bar);
+
+function foo(a) {
+    var x = a + 1;
+    for (;;) {
+        bar(function() { return x; });
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (f) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + result;
+    }
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrickyindirectlyinferredinfiniteloopthatusescapturedvariablesandcreatestheactivationoutsidetheloopjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tricky-indirectly-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+var count = 0;
+
+function bar(f) {
+    if (++count &lt; 10)
+        return;
+    count = 0;
+    throw f;
+}
+
+noInline(bar);
+
+function fuzz(a) {
+    return a != true;
+}
+
+function foo(a) {
+    var x = a + 1;
+    var y = a + 2;
+    var f = (function() { return x; });
+    while (fuzz(y)) {
+        bar(f);
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (f) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + result;
+    }
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrickyinferredinfiniteloopthatusescapturedvariablesandcreatestheactivationoutsidetheloopjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tricky-inferred-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+var count = 0;
+
+function bar(f) {
+    if (++count &lt; 10)
+        return;
+    count = 0;
+    throw f;
+}
+
+noInline(bar);
+
+var shouldContinue = true;
+
+function foo(a) {
+    var x = a + 1;
+    var f = (function() { return x; });
+    while (shouldContinue) {
+        bar(f);
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (f) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + result;
+    }
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrickyinfiniteloopthatusescapturedvariablesandcreatestheactivationoutsidetheloopjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables-and-creates-the-activation-outside-the-loop.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+var count = 0;
+
+function bar(f) {
+    if (++count &lt; 10)
+        return;
+    count = 0;
+    throw f;
+}
+
+noInline(bar);
+
+function foo(a) {
+    var x = a + 1;
+    var f = (function() { return x; });
+    for (;;) {
+        bar(f);
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (f) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + result;
+    }
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstrickyinfiniteloopthatusescapturedvariablesjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables.js (0 => 165995)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tricky-infinite-loop-that-uses-captured-variables.js        2014-03-20 20:53:37 UTC (rev 165995)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+var count = 0;
+
+function bar(f) {
+    if (++count &lt; 10)
+        return;
+    count = 0;
+    throw f;
+}
+
+noInline(bar);
+
+function foo(a) {
+    var x = a + 1;
+    for (;;) {
+        bar(function() { return x; });
+    }
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    try {
+        foo(i);
+    } catch (f) {
+        var result = f();
+        if (result != i + 1)
+            throw &quot;Error: bad result for i = &quot; + i + &quot;: &quot; + result;
+    }
+}
+
</ins></span></pre>
</div>
</div>

</body>
</html>