<!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
<rdar://problem/16332337>
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 <fpizlo@apple.com>
+
+ Crash beneath operationTearOffActivation running this JS compression demo
+ https://bugs.webkit.org/show_bug.cgi?id=130295
+ <rdar://problem/16332337>
+
+ 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 <oliver@apple.com>
</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() && operand == argumentsRegister())
</span><span class="cx"> return true;
</span><del>-
- // Ditto for the arguments object.
</del><span class="cx"> if (usesArguments() && 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->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->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& data)
+ {
+ if (data.fallThrough.bytecodeIndex() > m_currentIndex)
+ return;
+
+ for (unsigned i = data.cases.size(); i--;) {
+ if (data.cases[i].target.bytecodeIndex() > 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 > m_currentIndex) || (notTaken > 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 <= 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<int32_t>(table.min + i)), target));
</span><span class="cx"> }
</span><ins>+ flushIfTerminal(data);
</ins><span class="cx"> addToGraph(Switch, OpInfo(&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(&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->key.get()), target));
</span><span class="cx"> }
</span><ins>+ flushIfTerminal(data);
</ins><span class="cx"> addToGraph(Switch, OpInfo(&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->m_returnValue.isValid());
</span><span class="cx"> setDirect(m_inlineStackTop->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->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->variablesAtHead.operand(operand);
</span><span class="cx"> if (!livenessNode)
</span><span class="cx"> return;
</span><del>- if (livenessNode->variableAccessData()->isCaptured())
- return;
</del><ins>+ NodeType nodeType;
+ if (livenessNode->flags() & NodeIsFlushed)
+ nodeType = Flush;
+ else
+ nodeType = PhantomLocal;
</ins><span class="cx"> block->appendNode(
</span><del>- m_graph, SpecNone, PhantomLocal, nodeOrigin,
</del><ins>+ m_graph, SpecNone, nodeType, nodeOrigin,
</ins><span class="cx"> OpInfo(livenessNode->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<LocalOperand>();
</span><span class="cx"> propagatePhis<ArgumentOperand>();
</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->size(); nodeIndex--;) {
+ Node* node = block->at(nodeIndex);
+ if (node->op() != Flush)
+ continue;
+ addFlushedLocalOp(node);
+ }
+ }
+ while (!m_flushedLocalOpWorklist.isEmpty()) {
+ Node* node = m_flushedLocalOpWorklist.takeLast();
+ ASSERT(node->flags() & NodeIsFlushed);
+ DFG_NODE_DO_TO_CHILDREN(m_graph, node, addFlushedLocalEdge);
+ }
+ }
+
+ void addFlushedLocalOp(Node* node)
+ {
+ if (node->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<PhiStackEntry, 128> m_argumentPhiStack;
</span><span class="cx"> Vector<PhiStackEntry, 128> m_localPhiStack;
</span><ins>+ Vector<Node*, 128> m_flushedLocalOpWorklist;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> bool performCPSRethreading(Graph& 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->variableAccessData();
+ VirtualRegister local = variableAccessData->local();
+ if (!node->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->variableAccessData();
- VirtualRegister local = variableAccessData->local();
</del><span class="cx"> Node* replacement = node->child1().node();
</span><span class="cx"> if (replacement->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->phis.size(); phiIndex--;)
+ block->phis[phiIndex]->clearFlags(flags);
+ for (unsigned nodeIndex = block->size(); nodeIndex--;)
+ block->at(nodeIndex)->clearFlags(flags);
+ }
+}
+
</ins><span class="cx"> FullBytecodeLiveness& Graph::livenessFor(CodeBlock* codeBlock)
</span><span class="cx"> {
</span><span class="cx"> HashMap<CodeBlock*, std::unique_ptr<FullBytecodeLiveness>>::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 & NodeDoesNotExit))
</span><span class="cx"> out.print(comma, "CanExit");
</span><span class="cx">
</span><ins>+ if (flags & NodeIsFlushed)
+ out.print(comma, "IsFlushed");
+
</ins><span class="cx"> CString string = out.toCString();
</span><span class="cx"> if (!string.length())
</span><span class="cx"> actualOut.print("<empty>");
</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->size(); nodeIndex--;) {
- Node* node = block->at(nodeIndex);
- if (node->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->op() == Phi || node->op() == SetArgument);
</span><span class="cx">
</span><del>- bool isFlushed = m_flushedLocalOps.contains(node);
</del><ins>+ bool isFlushed = !!(node->flags() & NodeIsFlushed);
</ins><span class="cx">
</span><span class="cx"> if (node->op() == Phi) {
</span><span class="cx"> if (!nonTrivialPhis.operand(node->local())) {
</span><span class="lines">@@ -334,7 +315,7 @@
</span><span class="cx"> switch (node->op()) {
</span><span class="cx"> case SetLocal: {
</span><span class="cx"> VariableAccessData* variable = node->variableAccessData();
</span><del>- if (variable->isCaptured() || m_flushedLocalOps.contains(node))
</del><ins>+ if (variable->isCaptured() || !!(node->flags() & NodeIsFlushed))
</ins><span class="cx"> node->mergeFlags(NodeMustGenerate);
</span><span class="cx"> else
</span><span class="cx"> node->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<Node*> m_flushedLocalOps;
- Vector<Node*> 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 > 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 < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (f) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result for i = " + i + ": " + 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 < 10) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result insie closure for i = " + i + ": " + 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 < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (f) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result for i = " + i + ": " + 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 < 10) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result insie closure for i = " + i + ": " + result;
+ return;
+ }
+ count = 0;
+ throw "done";
+}
+
+noInline(bar);
+
+function foo(a) {
+ var x = a + 1;
+ for (;;) {
+ bar(function() { return x; });
+ }
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (done) {
+ if (done != "done")
+ throw "Error: bad exception: " + 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 >= 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 "Error: bad result: " + 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 < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (f) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result for i = " + i + ": " + 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 < 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 < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (f) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result for i = " + i + ": " + 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 < 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 < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (f) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result for i = " + i + ": " + 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 < 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 < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (f) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result for i = " + i + ": " + 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 < 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 < 10000; ++i) {
+ try {
+ foo(i);
+ } catch (f) {
+ var result = f();
+ if (result != i + 1)
+ throw "Error: bad result for i = " + i + ": " + result;
+ }
+}
+
</ins></span></pre>
</div>
</div>
</body>
</html>