<!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>[183235] 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/183235">183235</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-04-23 19:23:36 -0700 (Thu, 23 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Allow function allocation sinking
https://bugs.webkit.org/show_bug.cgi?id=144016

Patch by Basile Clement &lt;basile_clement@apple.com&gt; on 2015-04-23
Reviewed by Filip Pizlo.

Source/JavaScriptCore:

This adds the ability to sink function allocations in the
DFGObjectAllocationSinkingPhase.

In order to enable this, we add a new PhantomNewFunction node that is
used similarily to the PhantomNewObject node, i.e. as a placeholder to replace
a sunk NewFunction and keep track of the allocations that have to be performed
in case of OSR exit after the sunk allocation but before the real one.
The FunctionExecutable and JSLexicalEnvironment (activation) of the function
are stored onto the PhantomNewFunction through PutHints in order for them
to be recovered on OSR exit.

Contrary to sunk object allocations, sunk function allocations do not
support any kind of operations (e.g. storing into a field) ; any such operation
will mark the function allocation as escaping and trigger materialization. As
such, function allocations can only be sunk to places where it would have been
correct to syntactically move them, and we don't need a special
MaterializeNewFunction node to recover possible operations on the function. A
sunk NewFunction node will simply create new NewFunction nodes, then replace
itself with a PhantomNewFunction node.

In itself, this change is not expected to have a significant impact on
performances other than in degenerate cases (see e.g.
JSRegress/sink-function), but it is a step towards being able to sink recursive
closures onces we support CreateActivation sinking as well as allocation cycles
sinking.

* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPhantomNewFunction):
(JSC::DFG::Node::isPhantomAllocation):
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations):
(JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
(JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize):
(JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGPromotedHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGPromotedHeapLocation.h:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validateCPS):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationMaterializeObjectInOSR):
* tests/stress/function-sinking-no-double-allocate.js: Added.
(call):
(.f):
(sink):
* tests/stress/function-sinking-osrexit.js: Added.
(.g):
(sink):
* tests/stress/function-sinking-put.js: Added.
(.g):
(sink):

LayoutTests:

Add a new test in JSRegress to check function sinking is being
performed.

* js/regress/script-tests/sink-function.js: Added.
(foo.f1):
(foo.f2):
(foo.f3):
(foo.f4):
(foo.f5):
(foo.f6):
(foo.f7):
(foo.f8):
(foo.f9):
(foo.f10):
(foo.f11):
(foo.f12):
(foo.f13):
(foo.f14):
(foo.f15):
(foo.f16):
(foo.f17):
(foo.f18):
(foo.f19):
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPromotedHeapLocationcpp">trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPromotedHeapLocationh">trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGValidatecpp">trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOperationscpp">trunk/Source/JavaScriptCore/ftl/FTLOperations.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregressscripttestssinkfunctionjs">trunk/LayoutTests/js/regress/script-tests/sink-function.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressfunctionsinkingnodoubleallocatejs">trunk/Source/JavaScriptCore/tests/stress/function-sinking-no-double-allocate.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressfunctionsinkingosrexitjs">trunk/Source/JavaScriptCore/tests/stress/function-sinking-osrexit.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressfunctionsinkingputjs">trunk/Source/JavaScriptCore/tests/stress/function-sinking-put.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/LayoutTests/ChangeLog        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -1,3 +1,35 @@
</span><ins>+2015-04-23  Basile Clement  &lt;basile_clement@apple.com&gt;
+
+        Allow function allocation sinking
+        https://bugs.webkit.org/show_bug.cgi?id=144016
+
+        Reviewed by Filip Pizlo.
+
+        Add a new test in JSRegress to check function sinking is being
+        performed.
+
+        * js/regress/script-tests/sink-function.js: Added.
+        (foo.f1):
+        (foo.f2):
+        (foo.f3):
+        (foo.f4):
+        (foo.f5):
+        (foo.f6):
+        (foo.f7):
+        (foo.f8):
+        (foo.f9):
+        (foo.f10):
+        (foo.f11):
+        (foo.f12):
+        (foo.f13):
+        (foo.f14):
+        (foo.f15):
+        (foo.f16):
+        (foo.f17):
+        (foo.f18):
+        (foo.f19):
+        (foo):
+
</ins><span class="cx"> 2015-04-23  Alexey Proskuryakov  &lt;ap@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Test compositing/scrolling/touch-scroll-to-clip.html fails in WK1
</span></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestssinkfunctionjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/sink-function.js (0 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/sink-function.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/sink-function.js        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+function foo(p) {
+    var f1 = function (x) { return x; };
+    var f2 = function (x) { return x; };
+    var f3 = function (x) { return x; };
+    var f4 = function (x) { return x; };
+    var f5 = function (x) { return x; };
+    var f6 = function (x) { return x; };
+    var f7 = function (x) { return x; };
+    var f8 = function (x) { return x; };
+    var f9 = function (x) { return x; };
+    var f10 = function (x) { return x; };
+    var f11 = function (x) { return x; };
+    var f12 = function (x) { return x; };
+    var f13 = function (x) { return x; };
+    var f14 = function (x) { return x; };
+    var f15 = function (x) { return x; };
+    var f16 = function (x) { return x; };
+    var f17 = function (x) { return x; };
+    var f18 = function (x) { return x; };
+    var f19 = function (x) { return x; };
+    if (p)
+        return f1(f2(f3(f4(f5(f6(f7(f8(f9(f10(f11(f12(f13(f14(f15(f16(f17(f18(f19(p)))))))))))))))))));
+}
+noInline(foo);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var result = foo(false);
+    if (result)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
+var result = foo(true);
+if (result !== true)
+    throw &quot;Error: bad result: &quot; + result;
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -1,5 +1,85 @@
</span><span class="cx"> 2015-04-23  Basile Clement  &lt;basile_clement@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Allow function allocation sinking
+        https://bugs.webkit.org/show_bug.cgi?id=144016
+
+        Reviewed by Filip Pizlo.
+
+        This adds the ability to sink function allocations in the
+        DFGObjectAllocationSinkingPhase.
+
+        In order to enable this, we add a new PhantomNewFunction node that is
+        used similarily to the PhantomNewObject node, i.e. as a placeholder to replace
+        a sunk NewFunction and keep track of the allocations that have to be performed
+        in case of OSR exit after the sunk allocation but before the real one.
+        The FunctionExecutable and JSLexicalEnvironment (activation) of the function
+        are stored onto the PhantomNewFunction through PutHints in order for them
+        to be recovered on OSR exit.
+
+        Contrary to sunk object allocations, sunk function allocations do not
+        support any kind of operations (e.g. storing into a field) ; any such operation
+        will mark the function allocation as escaping and trigger materialization. As
+        such, function allocations can only be sunk to places where it would have been
+        correct to syntactically move them, and we don't need a special
+        MaterializeNewFunction node to recover possible operations on the function. A
+        sunk NewFunction node will simply create new NewFunction nodes, then replace
+        itself with a PhantomNewFunction node.
+
+        In itself, this change is not expected to have a significant impact on
+        performances other than in degenerate cases (see e.g.
+        JSRegress/sink-function), but it is a step towards being able to sink recursive
+        closures onces we support CreateActivation sinking as well as allocation cycles
+        sinking.
+
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::convertToPhantomNewFunction):
+        (JSC::DFG::Node::isPhantomAllocation):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        (JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations):
+        (JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
+        (JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize):
+        (JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGPromotedHeapLocation.cpp:
+        (WTF::printInternal):
+        * dfg/DFGPromotedHeapLocation.h:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validateCPS):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        * ftl/FTLOperations.cpp:
+        (JSC::FTL::operationMaterializeObjectInOSR):
+        * tests/stress/function-sinking-no-double-allocate.js: Added.
+        (call):
+        (.f):
+        (sink):
+        * tests/stress/function-sinking-osrexit.js: Added.
+        (.g):
+        (sink):
+        * tests/stress/function-sinking-put.js: Added.
+        (.g):
+        (sink):
+
+2015-04-23  Basile Clement  &lt;basile_clement@apple.com&gt;
+
</ins><span class="cx">         Make FunctionRareData allocation thread-safe
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=144001
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -1353,6 +1353,7 @@
</span><span class="cx">         break;
</span><span class="cx">         
</span><span class="cx">     case PhantomNewObject:
</span><ins>+    case PhantomNewFunction:
</ins><span class="cx">     case PhantomDirectArguments:
</span><span class="cx">     case PhantomClonedArguments:
</span><span class="cx">     case BottomValue:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -857,6 +857,7 @@
</span><span class="cx">     case NewStringObject:
</span><span class="cx">     case PhantomNewObject:
</span><span class="cx">     case MaterializeNewObject:
</span><ins>+    case PhantomNewFunction:
</ins><span class="cx">         read(HeapObjectCount);
</span><span class="cx">         write(HeapObjectCount);
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -197,6 +197,7 @@
</span><span class="cx">     case CheckBadCell:
</span><span class="cx">     case BottomValue:
</span><span class="cx">     case PhantomNewObject:
</span><ins>+    case PhantomNewFunction:
</ins><span class="cx">     case PhantomDirectArguments:
</span><span class="cx">     case PhantomClonedArguments:
</span><span class="cx">     case GetMyArgumentByVal:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -1035,6 +1035,7 @@
</span><span class="cx">         case Identity: // This should have been cleaned up.
</span><span class="cx">         case BooleanToNumber:
</span><span class="cx">         case PhantomNewObject:
</span><ins>+        case PhantomNewFunction:
</ins><span class="cx">         case PhantomDirectArguments:
</span><span class="cx">         case PhantomClonedArguments:
</span><span class="cx">         case ForwardVarargs:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -581,7 +581,17 @@
</span><span class="cx">         m_opInfo2 = 0;
</span><span class="cx">         children = AdjacencyList();
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    void convertToPhantomNewFunction()
+    {
+        ASSERT(m_op == NewFunction);
+        m_op = PhantomNewFunction;
+        m_flags |= NodeMustGenerate;
+        m_opInfo = 0;
+        m_opInfo2 = 0;
+        children = AdjacencyList();
+    }
+
</ins><span class="cx">     void convertPhantomToPhantomLocal()
</span><span class="cx">     {
</span><span class="cx">         ASSERT(m_op == Phantom &amp;&amp; (child1()-&gt;op() == Phi || child1()-&gt;op() == SetLocal || child1()-&gt;op() == SetArgument));
</span><span class="lines">@@ -1427,6 +1437,7 @@
</span><span class="cx">         case PhantomNewObject:
</span><span class="cx">         case PhantomDirectArguments:
</span><span class="cx">         case PhantomClonedArguments:
</span><ins>+        case PhantomNewFunction:
</ins><span class="cx">             return true;
</span><span class="cx">         default:
</span><span class="cx">             return false;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -246,6 +246,7 @@
</span><span class="cx">     macro(PutHint, NodeMustGenerate) \
</span><span class="cx">     macro(CheckStructureImmediate, NodeMustGenerate) \
</span><span class="cx">     macro(MaterializeNewObject, NodeResultJS | NodeHasVarArgs) \
</span><ins>+    macro(PhantomNewFunction, NodeResultJS | NodeMustGenerate) \
</ins><span class="cx">     \
</span><span class="cx">     /* Nodes for misc operations. */\
</span><span class="cx">     macro(Breakpoint, NodeMustGenerate) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -510,13 +510,15 @@
</span><span class="cx">                 Node* node = block-&gt;at(nodeIndex);
</span><span class="cx">                 switch (node-&gt;op()) {
</span><span class="cx">                 case PutByOffset: {
</span><del>-                    if (m_sinkCandidates.contains(node-&gt;child2().node()))
</del><ins>+                    Node* target = node-&gt;child2().node();
+                    if (target-&gt;isPhantomObjectAllocation() &amp;&amp; m_sinkCandidates.contains(target))
</ins><span class="cx">                         node-&gt;convertToPutByOffsetHint();
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><span class="cx">                 case PutStructure: {
</span><del>-                    if (m_sinkCandidates.contains(node-&gt;child1().node())) {
</del><ins>+                    Node* target = node-&gt;child1().node();
+                    if (target-&gt;isPhantomObjectAllocation() &amp;&amp; m_sinkCandidates.contains(target)) {
</ins><span class="cx">                         Node* structure = m_insertionSet.insertConstant(
</span><span class="cx">                             nodeIndex, node-&gt;origin, JSValue(node-&gt;transition()-&gt;next));
</span><span class="cx">                         node-&gt;convertToPutStructureHint(structure);
</span><span class="lines">@@ -557,10 +559,28 @@
</span><span class="cx">                     }
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><del>-                    
</del><ins>+
+                case NewFunction: {
+                    if (m_sinkCandidates.contains(node)) {
+                        Node* executable = m_insertionSet.insertConstant(
+                            nodeIndex + 1, node-&gt;origin, node-&gt;cellOperand());
+                        m_insertionSet.insert(
+                            nodeIndex + 1,
+                            PromotedHeapLocation(FunctionExecutablePLoc, node).createHint(
+                                m_graph, node-&gt;origin, executable));
+                        m_insertionSet.insert(
+                            nodeIndex + 1,
+                            PromotedHeapLocation(FunctionActivationPLoc, node).createHint(
+                                m_graph, node-&gt;origin, node-&gt;child1().node()));
+                        node-&gt;convertToPhantomNewFunction();
+                    }
+                    break;
+                }
+
</ins><span class="cx">                 case StoreBarrier:
</span><span class="cx">                 case StoreBarrierWithNullCheck: {
</span><del>-                    if (m_sinkCandidates.contains(node-&gt;child1().node()))
</del><ins>+                    Node* target = node-&gt;child1().node();
+                    if (target-&gt;isPhantomObjectAllocation() &amp;&amp; m_sinkCandidates.contains(target))
</ins><span class="cx">                         node-&gt;convertToPhantom();
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="lines">@@ -759,7 +779,16 @@
</span><span class="cx">                     escape(edge.node());
</span><span class="cx">                 });
</span><span class="cx">             break;
</span><del>-            
</del><ins>+
+        case NewFunction:
+            sinkCandidate();
+            m_graph.doToChildren(
+                node,
+                [&amp;] (Edge edge) {
+                    escape(edge.node());
+                });
+            break;
+
</ins><span class="cx">         case CheckStructure:
</span><span class="cx">         case GetByOffset:
</span><span class="cx">         case MultiGetByOffset:
</span><span class="lines">@@ -815,7 +844,17 @@
</span><span class="cx">                 OpInfo(data), OpInfo(), 0, 0);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-            
</del><ins>+
+        case NewFunction:
+            result = m_graph.addNode(
+                escapee-&gt;prediction(), NewFunction,
+                NodeOrigin(
+                    escapee-&gt;origin.semantic,
+                    where-&gt;origin.forExit),
+                OpInfo(escapee-&gt;cellOperand()),
+                escapee-&gt;child1());
+            break;
+
</ins><span class="cx">         default:
</span><span class="cx">             DFG_CRASH(m_graph, escapee, &quot;Bad escapee op&quot;);
</span><span class="cx">             break;
</span><span class="lines">@@ -874,7 +913,40 @@
</span><span class="cx">                 firstChild, m_graph.m_varArgChildren.size() - firstChild);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-            
</del><ins>+
+        case NewFunction: {
+            if (!ASSERT_DISABLED) {
+                Vector&lt;PromotedHeapLocation&gt; locations = m_locationsForAllocation.get(escapee);
+
+                ASSERT(locations.size() == 2);
+
+                PromotedHeapLocation executable(FunctionExecutablePLoc, escapee);
+                ASSERT(locations.contains(executable));
+
+                PromotedHeapLocation activation(FunctionActivationPLoc, escapee);
+                ASSERT(locations.contains(activation));
+
+                for (unsigned i = 0; i &lt; locations.size(); ++i) {
+                    switch (locations[i].kind()) {
+                    case FunctionExecutablePLoc: {
+                        ASSERT(locations[i] == executable);
+                        break;
+                    }
+
+                    case FunctionActivationPLoc: {
+                        ASSERT(locations[i] == activation);
+                        break;
+                    }
+
+                    default:
+                        DFG_CRASH(m_graph, node, &quot;Bad location kind&quot;);
+                    }
+                }
+            }
+
+            break;
+        }
+
</ins><span class="cx">         default:
</span><span class="cx">             DFG_CRASH(m_graph, node, &quot;Bad materialize op&quot;);
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -542,6 +542,7 @@
</span><span class="cx">         case Identity:
</span><span class="cx">         case BooleanToNumber:
</span><span class="cx">         case PhantomNewObject:
</span><ins>+        case PhantomNewFunction:
</ins><span class="cx">         case PhantomDirectArguments:
</span><span class="cx">         case PhantomClonedArguments:
</span><span class="cx">         case GetMyArgumentByVal:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPromotedHeapLocationcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -82,6 +82,14 @@
</span><span class="cx">     case ArgumentsCalleePLoc:
</span><span class="cx">         out.print(&quot;ArgumentsCalleePLoc&quot;);
</span><span class="cx">         return;
</span><ins>+
+    case FunctionExecutablePLoc:
+        out.print(&quot;FunctionExecutablePLoc&quot;);
+        return;
+
+    case FunctionActivationPLoc:
+        out.print(&quot;FunctionActivationPLoc&quot;);
+        return;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPromotedHeapLocationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGPromotedHeapLocation.h        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -40,7 +40,10 @@
</span><span class="cx">     NamedPropertyPLoc,
</span><span class="cx">     ArgumentPLoc,
</span><span class="cx">     ArgumentCountPLoc,
</span><del>-    ArgumentsCalleePLoc
</del><ins>+    ArgumentsCalleePLoc,
+
+    FunctionExecutablePLoc,
+    FunctionActivationPLoc,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class PromotedLocationDescriptor {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -272,6 +272,7 @@
</span><span class="cx">     case GetEnumeratorGenericPname:
</span><span class="cx">     case ToIndexString:
</span><span class="cx">     case PhantomNewObject:
</span><ins>+    case PhantomNewFunction:
</ins><span class="cx">     case PutHint:
</span><span class="cx">     case CheckStructureImmediate:
</span><span class="cx">     case MaterializeNewObject:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -4656,6 +4656,7 @@
</span><span class="cx">     case CheckBadCell:
</span><span class="cx">     case BottomValue:
</span><span class="cx">     case PhantomNewObject:
</span><ins>+    case PhantomNewFunction:
</ins><span class="cx">     case PutHint:
</span><span class="cx">     case CheckStructureImmediate:
</span><span class="cx">     case MaterializeNewObject:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -4741,6 +4741,7 @@
</span><span class="cx">     case CheckBadCell:
</span><span class="cx">     case BottomValue:
</span><span class="cx">     case PhantomNewObject:
</span><ins>+    case PhantomNewFunction:
</ins><span class="cx">     case GetMyArgumentByVal:
</span><span class="cx">     case PutHint:
</span><span class="cx">     case CheckStructureImmediate:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -452,6 +452,7 @@
</span><span class="cx">                 case Upsilon:
</span><span class="cx">                 case CheckInBounds:
</span><span class="cx">                 case PhantomNewObject:
</span><ins>+                case PhantomNewFunction:
</ins><span class="cx">                 case GetMyArgumentByVal:
</span><span class="cx">                 case PutHint:
</span><span class="cx">                 case CheckStructureImmediate:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -180,6 +180,7 @@
</span><span class="cx">     case ToIndexString:
</span><span class="cx">     case BottomValue:
</span><span class="cx">     case PhantomNewObject:
</span><ins>+    case PhantomNewFunction:
</ins><span class="cx">     case PutHint:
</span><span class="cx">     case CheckStructureImmediate:
</span><span class="cx">     case MaterializeNewObject:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -849,6 +849,7 @@
</span><span class="cx">         case MovHint:
</span><span class="cx">         case ZombieHint:
</span><span class="cx">         case PhantomNewObject:
</span><ins>+        case PhantomNewFunction:
</ins><span class="cx">         case PhantomDirectArguments:
</span><span class="cx">         case PhantomClonedArguments:
</span><span class="cx">         case PutHint:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOperationscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOperations.cpp (183234 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOperations.cpp        2015-04-24 02:13:39 UTC (rev 183234)
+++ trunk/Source/JavaScriptCore/ftl/FTLOperations.cpp        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -92,7 +92,25 @@
</span><span class="cx">     
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><del>-        
</del><ins>+
+    case PhantomNewFunction: {
+        // Figure out what the executable and activation are
+        FunctionExecutable* executable = nullptr;
+        JSScope* activation = nullptr;
+        for (unsigned i = materialization-&gt;properties().size(); i--;) {
+            const ExitPropertyValue&amp; property = materialization-&gt;properties()[i];
+            if (property.location() == PromotedLocationDescriptor(FunctionExecutablePLoc))
+                executable = jsCast&lt;FunctionExecutable*&gt;(JSValue::decode(values[i]));
+            if (property.location() == PromotedLocationDescriptor(FunctionActivationPLoc))
+                activation = jsCast&lt;JSScope*&gt;(JSValue::decode(values[i]));
+        }
+        RELEASE_ASSERT(executable &amp;&amp; activation);
+
+        JSFunction* result = JSFunction::create(vm, executable, activation);
+
+        return result;
+    }
+
</ins><span class="cx">     case PhantomDirectArguments:
</span><span class="cx">     case PhantomClonedArguments: {
</span><span class="cx">         if (!materialization-&gt;origin().inlineCallFrame) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressfunctionsinkingnodoubleallocatejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/function-sinking-no-double-allocate.js (0 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/function-sinking-no-double-allocate.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/function-sinking-no-double-allocate.js        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+function call(o) { o.x = 3; }
+noInline(call);
+
+function sink (p, q) {
+    var f = function () { };
+    if (p) {
+        call(f); // Force allocation of f
+        if (q) {
+            OSRExit();
+        }
+        return f;
+    }
+    return { 'x': 2 };
+}
+noInline(sink);
+
+for (var i = 0; i &lt; 100000; ++i) {
+    var o = sink(true, false);
+    if (o.x != 3)
+        throw &quot;Error: expected o.x to be 2 but is &quot; + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+if (f.x != 3)
+    throw &quot;Error: expected o.x to be 3 but is &quot; + result;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressfunctionsinkingosrexitjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/function-sinking-osrexit.js (0 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/function-sinking-osrexit.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/function-sinking-osrexit.js        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -0,0 +1,21 @@
</span><ins>+function sink (p, q) {
+    var g = function(x) { return x; };
+    if (p) { if (q) OSRExit(); return g; }
+    return function(x) { return x; };
+}
+noInline(sink);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var f = sink(true, false);
+    var result = f(42);
+    if (result != 42)
+    throw &quot;Error: expected 42 but got &quot; + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Check that the function is properly allocated on OSR exit
+var f = sink(true, true);
+var result = f(42);
+if (result != 42)
+    throw &quot;Error: expected 42 but got &quot; + result;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressfunctionsinkingputjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/function-sinking-put.js (0 => 183235)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/function-sinking-put.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/function-sinking-put.js        2015-04-24 02:23:36 UTC (rev 183235)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+function sink (p, q) {
+    var g = function(x) { return x; };
+    if (p) { if (q) g.inner = 42; return g; }
+    return function(x) { return x; };
+}
+noInline(sink);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var f = sink(true, true);
+    var result = f(42);
+    if (result != 42)
+    throw &quot;Error: expected 42 but got &quot; + result;
+}
+
+// At this point, the function should be compiled down to the FTL
+
+// Test the allocation on the implicit inner else branch
+var f = sink(true, false);
+var result = f(12);
+if (result != 12)
+    // This shouldn't matter as it should be either correct or completely crash
+    throw &quot;Error: expected 12 but got &quot; + result;
+
+// Check that the allocation did not sink beyond the property assignment
+var f = sink(true, true);
+var result = f.inner;
+if (result != 42)
+    throw &quot;Error: inner should be 42 but is &quot; + result;
</ins></span></pre>
</div>
</div>

</body>
</html>