<!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>[189126] trunk</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/189126">189126</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-08-28 15:38:41 -0700 (Fri, 28 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>LICM should be sound even if the CFG has changed
https://bugs.webkit.org/show_bug.cgi?id=148259

Reviewed by Benjamin Poulain.

Source/JavaScriptCore:

Prior to this change, LICM expected a certain CFG shape around a loop: broken critical edges,
a pre-header, and the pre-header's terminal has exitOK. LICM would either crash on an
assertion, or generate code that fails validation, if these conditions weren't met.

The broken critical edge assumption is fine; so far we are assuming that SSA means broken
critical edges. We may revisit this, but we don't have to right now.

The other assumptions are not fine, because it's hard to guarantee that every phase will
preserve the presence of pre-headers. Even if we required that pre-headers are regenerated
before LICM, that regeneration wouldn't be guaranteed to create pre-headers that have exitOK at
the terminal. That's because once in SSA, the loop header probably has exitOK=false at the
head because of Phi's. Pre-header creation has no choice but to use the Node::origin from the
loop header, which means creating a pre-header that has exitOK=false. Regardless of whether
that's a fixable problem, it seems that our best short-term approach is just to be defensive
and turn undesirable pathologies into performance bugs and not crashes.

For the foreseeable future, once pre-headers are created they will probably not be removed. Our
current CFG simplification phase doesn't have a rule for removing pre-headers (since it doesn't
have any jump threading). So, it wouldn't be profitable to put effort towards reneration of
pre-headers for LICM's benefit.

Also, we cannot guarantee that some sequence of CFG transformations will not create a loop that
doesn't have a pre-header. This would be super rare. But you could imagine that some program
has control flow encoded using relooping (like
https://github.com/kripken/Relooper/blob/master/paper.pdf). If that happens, our compiler will
probably incrementally discover the &quot;original&quot; CFG. That may happen only after SSA conversion,
and so after pre-header generation. This is super unlikely for a bunch of reasons, but it
*could* happen.

So, this patch just makes sure that if pre-headers are missing or cannot be exited from, LICM
will simply avoid hoisting out of that block. At some point later, we can worry about a more
comprehensive solution to the pre-header problem. That's covered by this bug:
https://bugs.webkit.org/show_bug.cgi?id=148586

* dfg/DFGLICMPhase.cpp:
(JSC::DFG::LICMPhase::run):
(JSC::DFG::LICMPhase::attemptHoist):
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* runtime/Options.h:
* tests/stress/licm-no-pre-header.js: Added.
(foo):
* tests/stress/licm-pre-header-cannot-exit.js: Added.
(foo):

Tools:

Add a utility for creating tests that set some uncommon option.

* Scripts/run-jsc-stress-tests:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCFGSimplificationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGLICMPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGLoopPreHeaderCreationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGLoopPreHeaderCreationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlancpp">trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptsrunjscstresstests">trunk/Tools/Scripts/run-jsc-stress-tests</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstresslicmnopreheaderjs">trunk/Source/JavaScriptCore/tests/stress/licm-no-pre-header.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresslicmpreheadercannotexitjs">trunk/Source/JavaScriptCore/tests/stress/licm-pre-header-cannot-exit.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -1,3 +1,55 @@
</span><ins>+2015-08-28  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        LICM should be sound even if the CFG has changed
+        https://bugs.webkit.org/show_bug.cgi?id=148259
+
+        Reviewed by Benjamin Poulain.
+
+        Prior to this change, LICM expected a certain CFG shape around a loop: broken critical edges,
+        a pre-header, and the pre-header's terminal has exitOK. LICM would either crash on an
+        assertion, or generate code that fails validation, if these conditions weren't met.
+
+        The broken critical edge assumption is fine; so far we are assuming that SSA means broken
+        critical edges. We may revisit this, but we don't have to right now.
+
+        The other assumptions are not fine, because it's hard to guarantee that every phase will
+        preserve the presence of pre-headers. Even if we required that pre-headers are regenerated
+        before LICM, that regeneration wouldn't be guaranteed to create pre-headers that have exitOK at
+        the terminal. That's because once in SSA, the loop header probably has exitOK=false at the
+        head because of Phi's. Pre-header creation has no choice but to use the Node::origin from the
+        loop header, which means creating a pre-header that has exitOK=false. Regardless of whether
+        that's a fixable problem, it seems that our best short-term approach is just to be defensive
+        and turn undesirable pathologies into performance bugs and not crashes.
+
+        For the foreseeable future, once pre-headers are created they will probably not be removed. Our
+        current CFG simplification phase doesn't have a rule for removing pre-headers (since it doesn't
+        have any jump threading). So, it wouldn't be profitable to put effort towards reneration of
+        pre-headers for LICM's benefit.
+
+        Also, we cannot guarantee that some sequence of CFG transformations will not create a loop that
+        doesn't have a pre-header. This would be super rare. But you could imagine that some program
+        has control flow encoded using relooping (like
+        https://github.com/kripken/Relooper/blob/master/paper.pdf). If that happens, our compiler will
+        probably incrementally discover the &quot;original&quot; CFG. That may happen only after SSA conversion,
+        and so after pre-header generation. This is super unlikely for a bunch of reasons, but it
+        *could* happen.
+
+        So, this patch just makes sure that if pre-headers are missing or cannot be exited from, LICM
+        will simply avoid hoisting out of that block. At some point later, we can worry about a more
+        comprehensive solution to the pre-header problem. That's covered by this bug:
+        https://bugs.webkit.org/show_bug.cgi?id=148586
+
+        * dfg/DFGLICMPhase.cpp:
+        (JSC::DFG::LICMPhase::run):
+        (JSC::DFG::LICMPhase::attemptHoist):
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        * runtime/Options.h:
+        * tests/stress/licm-no-pre-header.js: Added.
+        (foo):
+        * tests/stress/licm-pre-header-cannot-exit.js: Added.
+        (foo):
+
</ins><span class="cx"> 2015-08-28  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Move std::function from JSFunction into NativeStdFunctionCell to correctly destroy the heap allocated std::function
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCFGSimplificationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -46,6 +46,9 @@
</span><span class="cx">     
</span><span class="cx">     bool run()
</span><span class="cx">     {
</span><ins>+        // FIXME: We should make this work in SSA. https://bugs.webkit.org/show_bug.cgi?id=148260
+        DFG_ASSERT(m_graph, nullptr, m_graph.m_form != SSA);
+        
</ins><span class="cx">         const bool extremeLogging = false;
</span><span class="cx"> 
</span><span class="cx">         bool outerChanged = false;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGLICMPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> 
</span><span class="cx"> struct LoopData {
</span><span class="cx">     LoopData()
</span><del>-        : preHeader(0)
</del><ins>+        : preHeader(nullptr)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -112,6 +112,7 @@
</span><span class="cx">         for (unsigned loopIndex = m_graph.m_naturalLoops.numLoops(); loopIndex--;) {
</span><span class="cx">             const NaturalLoop&amp; loop = m_graph.m_naturalLoops.loop(loopIndex);
</span><span class="cx">             LoopData&amp; data = m_data[loop.index()];
</span><ins>+            
</ins><span class="cx">             for (
</span><span class="cx">                 const NaturalLoop* outerLoop = m_graph.m_naturalLoops.innerMostOuterLoop(loop);
</span><span class="cx">                 outerLoop;
</span><span class="lines">@@ -119,24 +120,46 @@
</span><span class="cx">                 m_data[outerLoop-&gt;index()].writes.addAll(data.writes);
</span><span class="cx">             
</span><span class="cx">             BasicBlock* header = loop.header();
</span><del>-            BasicBlock* preHeader = 0;
</del><ins>+            BasicBlock* preHeader = nullptr;
+            unsigned numberOfPreHeaders = 0; // We're cool if this is 1.
+
+            // This is guaranteed because we expect the CFG not to have unreachable code. Therefore, a
+            // loop header must have a predecessor. (Also, we don't allow the root block to be a loop,
+            // which cuts out the one other way of having a loop header with only one predecessor.)
+            DFG_ASSERT(m_graph, header-&gt;at(0), header-&gt;predecessors.size() &gt; 1);
+            
</ins><span class="cx">             for (unsigned i = header-&gt;predecessors.size(); i--;) {
</span><span class="cx">                 BasicBlock* predecessor = header-&gt;predecessors[i];
</span><span class="cx">                 if (m_graph.m_dominators.dominates(header, predecessor))
</span><span class="cx">                     continue;
</span><del>-                DFG_ASSERT(m_graph, nullptr, !preHeader || preHeader == predecessor);
</del><ins>+
</ins><span class="cx">                 preHeader = predecessor;
</span><ins>+                ++numberOfPreHeaders;
</ins><span class="cx">             }
</span><del>-            
</del><ins>+
+            // We need to validate the pre-header. There are a bunch of things that could be wrong
+            // about it:
+            //
+            // - There might be more than one. This means that pre-header creation either did not run,
+            //   or some CFG transformation destroyed the pre-headers.
+            //
+            // - It may not be legal to exit at the pre-header. That would be a real bummer. Currently,
+            //   LICM assumes that it can always hoist checks. See
+            //   https://bugs.webkit.org/show_bug.cgi?id=148545. Though even with that fixed, we anyway
+            //   would need to check if it's OK to exit at the pre-header since if we can't then we
+            //   would have to restrict hoisting to non-exiting nodes.
+
+            if (numberOfPreHeaders != 1)
+                continue;
+
+            // This is guaranteed because the header has multiple predecessors and critical edges are
+            // broken. Therefore the predecessors must all have one successor, which implies that they
+            // must end in a Jump.
</ins><span class="cx">             DFG_ASSERT(m_graph, preHeader-&gt;terminal(), preHeader-&gt;terminal()-&gt;op() == Jump);
</span><ins>+
+            if (!preHeader-&gt;terminal()-&gt;origin.exitOK)
+                continue;
</ins><span class="cx">             
</span><del>-            // We should validate the pre-header. This currently assumes that it's valid to OSR exit at
-            // the Jump of the pre-header. That may not always be the case, like if we lowered a Node
-            // that was ExitInvalid to a loop. This phase should somehow defend against this - at the
-            // very least with assertions, if not with something better (like only hoisting things that
-            // cannot exit).
-            // FIXME: https://bugs.webkit.org/show_bug.cgi?id=148259
-            
</del><span class="cx">             data.preHeader = preHeader;
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="lines">@@ -146,6 +169,7 @@
</span><span class="cx">         // We try to hoist to the outer-most loop that permits it. Hoisting is valid if:
</span><span class="cx">         // - The node doesn't write anything.
</span><span class="cx">         // - The node doesn't read anything that the loop writes.
</span><ins>+        // - The preHeader is valid (i.e. it passed the validation above).
</ins><span class="cx">         // - The preHeader's state at tail makes the node safe to execute.
</span><span class="cx">         // - The loop's children all belong to nodes that strictly dominate the loop header.
</span><span class="cx">         // - The preHeader's state at tail is still valid. This is mostly to save compile
</span><span class="lines">@@ -205,6 +229,12 @@
</span><span class="cx">     {
</span><span class="cx">         Node* node = nodeRef;
</span><span class="cx">         LoopData&amp; data = m_data[loop-&gt;index()];
</span><ins>+
+        if (!data.preHeader) {
+            if (verbose)
+                dataLog(&quot;    Not hoisting &quot;, node, &quot; because the pre-header is invalid.\n&quot;);
+            return false;
+        }
</ins><span class="cx">         
</span><span class="cx">         if (!data.preHeader-&gt;cfaDidFinish) {
</span><span class="cx">             if (verbose)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGLoopPreHeaderCreationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGLoopPreHeaderCreationPhase.cpp (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGLoopPreHeaderCreationPhase.cpp        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Source/JavaScriptCore/dfg/DFGLoopPreHeaderCreationPhase.cpp        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -39,8 +39,56 @@
</span><span class="cx"> 
</span><span class="cx"> BasicBlock* createPreHeader(Graph&amp; graph, BlockInsertionSet&amp; insertionSet, BasicBlock* block)
</span><span class="cx"> {
</span><ins>+    // FIXME: If we run this utility on SSA IR, then we may end up with a bizarre arrangement of
+    // Upsilons and Phis, like:
+    //
+    // BB#1:
+    //     Upsilon(@a, ^p)
+    //     Jump(#3)
+    //
+    // BB#2:
+    //     Upsilon(@b, ^p)
+    //     Jump(#3)
+    //
+    // BB#3:
+    //     Jump(#4)
+    //
+    // BB#4:
+    //     p: Phi()
+    //
+    // Notice how the Upsilons are not in the predecessor of the Phi anymore. It's not clear if this
+    // would be bad. Probably not, but it's weird anyway. We should add a validation rule, and we
+    // should implement a Upsilon/Phi canonicalization that handles this by calling into the
+    // SSACalculator and treating the Upsilons as Defs and rebuilding the Phis from scratch.
+    //
+    // https://bugs.webkit.org/show_bug.cgi?id=148587
+    
</ins><span class="cx">     // Don't bother to preserve execution frequencies for now.
</span><span class="cx">     BasicBlock* preHeader = insertionSet.insertBefore(block, PNaN);
</span><ins>+
+    // FIXME: It would be great if we put some effort into enabling exitOK at this origin, if it
+    // happens to be unset. It might not be set because the loop header (i.e. &quot;block&quot;) has Phis in it.
+    // Phis have to have exitOK=false. There are a few ways to try to set exitOK:
+    //
+    // - Regenerate an exit origin by proving that we are at an exit origin boundary. If all of the
+    //   predecessors' terminals have different exit origins than the exit origin of head of block,
+    //   then we can leverage the assumption that exit origin boundaries can always exit. We could
+    //   extend this further, and say that we will set exitOK even if a predecessor's terminal has the
+    //   same exit origin, but so long it hadn't done anything that clobbers exit since the start of
+    //   the origin.
+    //
+    // - Analyze the Phi's and MovHint's at the head of block. If prior to the ExitOK there are only
+    //   Phi's and MovHint's, we could &quot;roll them back&quot; by proving that for each of the MovHints, the
+    //   referenced Phi has a child that dominates the pre-header, and that child is the node that is
+    //   OSR-available at the local being MovHinted.
+    //
+    // Note that there are some obviously wrong ways to try to set exitOK. For example, we cannot
+    // simply use the origin of our predecessors, since in bytecode that could be *any* kind of
+    // instruction. It may not even be a control flow construct, if we had lowered some non-control
+    // bytecode operation into DFG IR that has control flow. Hence, we really do need to try to use the
+    // origin of the head of the loop header.
+    //
+    // https://bugs.webkit.org/show_bug.cgi?id=148586
</ins><span class="cx">     preHeader-&gt;appendNode(
</span><span class="cx">         graph, SpecNone, Jump, block-&gt;at(0)-&gt;origin, OpInfo(block));
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -374,7 +374,8 @@
</span><span class="cx">         
</span><span class="cx">         performCleanUp(dfg); // Reduce the graph size a bit.
</span><span class="cx">         performCriticalEdgeBreaking(dfg);
</span><del>-        performLoopPreHeaderCreation(dfg);
</del><ins>+        if (Options::createPreHeaders())
+            performLoopPreHeaderCreation(dfg);
</ins><span class="cx">         performCPSRethreading(dfg);
</span><span class="cx">         performSSAConversion(dfg);
</span><span class="cx">         performSSALowering(dfg);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -195,6 +195,7 @@
</span><span class="cx">     v(unsigned, maxPolymorphicCallVariantsForInlining, 5, nullptr) \
</span><span class="cx">     v(unsigned, frequentCallThreshold, 2, nullptr) \
</span><span class="cx">     v(double, minimumCallToKnownRate, 0.51, nullptr) \
</span><ins>+    v(bool, createPreHeaders, true, nullptr) \
</ins><span class="cx">     v(bool, enableMovHintRemoval, true, nullptr) \
</span><span class="cx">     v(bool, enableObjectAllocationSinking, true, nullptr) \
</span><span class="cx">     \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresslicmnopreheaderjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/licm-no-pre-header.js (0 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/licm-no-pre-header.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/licm-no-pre-header.js        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+//@ runMiscFTLNoCJITTest(&quot;--createPreHeaders=false&quot;)
+
+function foo(array) {
+    var result = 0;
+    var i = 0;
+    if (!array.length)
+        array = [1];
+    do {
+        result += array[i++];
+    } while (i &lt; array.length)
+    return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i)
+    foo([1, 2, 3]);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresslicmpreheadercannotexitjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/licm-pre-header-cannot-exit.js (0 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/licm-pre-header-cannot-exit.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/licm-pre-header-cannot-exit.js        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+//@ runMiscFTLNoCJITTest(&quot;--createPreHeaders=false&quot;)
+
+function foo(object, predicate) {
+    var result = 0;
+    var i = 0;
+    if (DFGTrue())
+        predicate = 42;
+    while (predicate &gt;= 42) {
+        result += object.array[i++];
+        if (i &gt;= object.array.length)
+            break;
+    }
+    return result;
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i)
+    foo({array: [1, 2, 3]}, {valueOf: function() { return 42; }});
</ins></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Tools/ChangeLog        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2015-08-28  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        LICM should be sound even if the CFG has changed
+        https://bugs.webkit.org/show_bug.cgi?id=148259
+
+        Reviewed by Benjamin Poulain.
+
+        Add a utility for creating tests that set some uncommon option.
+
+        * Scripts/run-jsc-stress-tests:
+
</ins><span class="cx"> 2015-08-28  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Win] Unreviewed EWS correction.
</span></span></pre></div>
<a id="trunkToolsScriptsrunjscstresstests"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/run-jsc-stress-tests (189125 => 189126)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/run-jsc-stress-tests        2015-08-28 21:54:34 UTC (rev 189125)
+++ trunk/Tools/Scripts/run-jsc-stress-tests        2015-08-28 22:38:41 UTC (rev 189126)
</span><span class="lines">@@ -762,6 +762,14 @@
</span><span class="cx">     run(&quot;ftl-no-cjit-small-pool&quot;, &quot;--jitMemoryReservationSize=50000&quot;, *(FTL_OPTIONS + NO_CJIT_OPTIONS)) if $enableFTL
</span><span class="cx"> end
</span><span class="cx"> 
</span><ins>+def runMiscNoCJITTest(*options)
+    run(&quot;misc-no-cjit&quot;, *(NO_CJIT_OPTIONS + options))
+end
+
+def runMiscFTLNoCJITTest(*options)
+    run(&quot;misc-ftl-no-cjit&quot;, *(FTL_OPTIONS + NO_CJIT_OPTIONS + options))
+end
+
</ins><span class="cx"> def defaultRun
</span><span class="cx">     runDefault
</span><span class="cx">     runAlwaysTriggerCopyPhase
</span></span></pre>
</div>
</div>

</body>
</html>