<!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>[190370] 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/190370">190370</a></dd>
<dt>Author</dt> <dd>msaboff@apple.com</dd>
<dt>Date</dt> <dd>2015-09-30 15:28:08 -0700 (Wed, 30 Sep 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Source/JavaScriptCore:
Relanding <a href="http://trac.webkit.org/projects/webkit/changeset/190289">r190289</a> with the following two fixes:

 1. REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/190289">r190289</a>): It made Speedometer/Full.html performance test fail
    https://bugs.webkit.org/show_bug.cgi?id=149621

    Reviewed by Saam Barati.

    We need to restore callee saves for both the fast and slow paths before making a
    tail call in the FTL.

    * ftl/FTLJSCallBase.cpp:
    (JSC::FTL::JSCallBase::emit):

 2. [ARM] REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/190289">r190289</a>): It made 374 tests crash on 32 bit ARM Linux
    https://bugs.webkit.org/show_bug.cgi?id=149619

    Reviewed by Filip Pizlo.

    Need to check for ARMv7_TRADITIONAL and ARMv7 in addition to ARM in &quot;if&quot;
    statement to handle platforms with a link register.
            
    * llint/LowLevelInterpreter.asm:
    (prepareForTailCall):

LayoutTests:
Relanding <a href="http://trac.webkit.org/projects/webkit/changeset/190289">r190289</a> after fixes tracked in https://bugs.webkit.org/show_bug.cgi?id=149619
and https://bugs.webkit.org/show_bug.cgi?id=149621

Reviewed by Saam Barati.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsjscallerpropertyexpectedtxt">trunk/LayoutTests/js/caller-property-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsscripttestscallerpropertyjs">trunk/LayoutTests/js/script-tests/caller-property.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxprojfilters">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGTierUpCheckInjectionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCompilecpp">trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLInlineCacheSizecpp">trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLInlineCacheSizeh">trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallcpp">trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallBasecpp">trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallBaseh">trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSCallVarargscpp">trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLocationh">trunk/Source/JavaScriptCore/ftl/FTLLocation.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLStateh">trunk/Source/JavaScriptCore/ftl/FTLState.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitAssemblyHelperscpp">trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShuffleDatah">trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShufflercpp">trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShufflerh">trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShuffler64cpp">trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCallcpp">trunk/Source/JavaScriptCore/jit/JITCall.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRegh">trunk/Source/JavaScriptCore/jit/Reg.h</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreterasm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestses6yaml">trunk/Source/JavaScriptCore/tests/es6.yaml</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSTailCallcpp">trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLJSTailCallh">trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressdfgtailcallsjs">trunk/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressmutualtailcallnostackoverflowjs">trunk/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstailcallnostackoverflowjs">trunk/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstailcallrecognizejs">trunk/Source/JavaScriptCore/tests/stress/tail-call-recognize.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstailcallvarargsnostackoverflowjs">trunk/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresstailcallsdontoverwritelivestackjs">trunk/Source/JavaScriptCore/tests/stress/tail-calls-dont-overwrite-live-stack.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/LayoutTests/ChangeLog        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -1,3 +1,10 @@
</span><ins>+2015-09-30  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        Relanding r190289 after fixes tracked in https://bugs.webkit.org/show_bug.cgi?id=149619
+        and https://bugs.webkit.org/show_bug.cgi?id=149621
+
+        Reviewed by Saam Barati.
+
</ins><span class="cx"> 2015-09-29  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [iOS] Allow tests to generate user gestures for UI testing
</span></span></pre></div>
<a id="trunkLayoutTestsjscallerpropertyexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/caller-property-expected.txt (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/caller-property-expected.txt        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/LayoutTests/js/caller-property-expected.txt        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -10,10 +10,14 @@
</span><span class="cx"> PASS nonStrictCaller(strictCallee) threw exception TypeError: Type error.
</span><span class="cx"> PASS strictCaller(nonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller.
</span><span class="cx"> PASS strictCaller(strictCallee) threw exception TypeError: Type error.
</span><ins>+PASS strictTailCaller(nonStrictCallee) is null
+PASS strictTailCaller(strictCallee) threw exception TypeError: Type error.
</ins><span class="cx"> PASS nonStrictCaller(boundNonStrictCallee) is nonStrictCaller
</span><span class="cx"> PASS nonStrictCaller(boundStrictCallee) threw exception TypeError: Type error.
</span><span class="cx"> PASS strictCaller(boundNonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller.
</span><span class="cx"> PASS strictCaller(boundStrictCallee) threw exception TypeError: Type error.
</span><ins>+PASS strictTailCaller(boundNonStrictCallee) is null
+PASS strictTailCaller(boundStrictCallee) threw exception TypeError: Type error.
</ins><span class="cx"> PASS nonStrictGetter(nonStrictAccessor) is nonStrictGetter
</span><span class="cx"> PASS nonStrictSetter(nonStrictAccessor) is true
</span><span class="cx"> PASS nonStrictGetter(strictAccessor) threw exception TypeError: Type error.
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestscallerpropertyjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/caller-property.js (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/caller-property.js        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/LayoutTests/js/script-tests/caller-property.js        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -23,11 +23,15 @@
</span><span class="cx"> function nonStrictCallee() { return nonStrictCallee.caller; }
</span><span class="cx"> function strictCallee() { &quot;use strict&quot;; return strictCallee.caller; }
</span><span class="cx"> function nonStrictCaller(x) { return x(); }
</span><del>-function strictCaller(x) { &quot;use strict&quot;; return x(); }
</del><ins>+// Tail calls leak and show our caller's caller, which is null here
+function strictCaller(x) { &quot;use strict&quot;; var result = x(); return result; }
+function strictTailCaller(x) { &quot;use strict&quot;; return x(); }
</ins><span class="cx"> shouldBe(&quot;nonStrictCaller(nonStrictCallee)&quot;, &quot;nonStrictCaller&quot;);
</span><span class="cx"> shouldThrow(&quot;nonStrictCaller(strictCallee)&quot;, '&quot;TypeError: Type error&quot;');
</span><span class="cx"> shouldThrow(&quot;strictCaller(nonStrictCallee)&quot;, '&quot;TypeError: Function.caller used to retrieve strict caller&quot;');
</span><span class="cx"> shouldThrow(&quot;strictCaller(strictCallee)&quot;, '&quot;TypeError: Type error&quot;');
</span><ins>+shouldBe(&quot;strictTailCaller(nonStrictCallee)&quot;, &quot;null&quot;);
+shouldThrow(&quot;strictTailCaller(strictCallee)&quot;, '&quot;TypeError: Type error&quot;');
</ins><span class="cx"> 
</span><span class="cx"> // .caller within a bound function reaches the caller, ignoring the binding.
</span><span class="cx"> var boundNonStrictCallee = nonStrictCallee.bind();
</span><span class="lines">@@ -36,6 +40,8 @@
</span><span class="cx"> shouldThrow(&quot;nonStrictCaller(boundStrictCallee)&quot;, '&quot;TypeError: Type error&quot;');
</span><span class="cx"> shouldThrow(&quot;strictCaller(boundNonStrictCallee)&quot;, '&quot;TypeError: Function.caller used to retrieve strict caller&quot;');
</span><span class="cx"> shouldThrow(&quot;strictCaller(boundStrictCallee)&quot;, '&quot;TypeError: Type error&quot;');
</span><ins>+shouldBe(&quot;strictTailCaller(boundNonStrictCallee)&quot;, &quot;null&quot;);
+shouldThrow(&quot;strictTailCaller(boundStrictCallee)&quot;, '&quot;TypeError: Type error&quot;');
</ins><span class="cx"> 
</span><span class="cx"> // Check that .caller works (or throws) as expected, over an accessor call.
</span><span class="cx"> function getFooGetter(x) { return Object.getOwnPropertyDescriptor(x, 'foo').get; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -904,6 +904,7 @@
</span><span class="cx">         ftl/FTLJSCall.cpp
</span><span class="cx">         ftl/FTLJSCallBase.cpp
</span><span class="cx">         ftl/FTLJSCallVarargs.cpp
</span><ins>+        ftl/FTLJSTailCall.cpp
</ins><span class="cx">         ftl/FTLLink.cpp
</span><span class="cx">         ftl/FTLLocation.cpp
</span><span class="cx">         ftl/FTLLowerDFGToLLVM.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2015-09-30  Michael Saboff  &lt;msaboff@apple.com&gt;
+
+        Relanding r190289 with the following two fixes:
+
+         1. REGRESSION(r190289): It made Speedometer/Full.html performance test fail
+            https://bugs.webkit.org/show_bug.cgi?id=149621
+
+            Reviewed by Saam Barati.
+
+            We need to restore callee saves for both the fast and slow paths before making a
+            tail call in the FTL.
+
+            * ftl/FTLJSCallBase.cpp:
+            (JSC::FTL::JSCallBase::emit):
+
+         2. [ARM] REGRESSION(r190289): It made 374 tests crash on 32 bit ARM Linux
+            https://bugs.webkit.org/show_bug.cgi?id=149619
+
+            Reviewed by Filip Pizlo.
+
+            Need to check for ARMv7_TRADITIONAL and ARMv7 in addition to ARM in &quot;if&quot;
+            statement to handle platforms with a link register.
+            
+            * llint/LowLevelInterpreter.asm:
+            (prepareForTailCall):
+
</ins><span class="cx"> 2015-09-30  Keith Miller  &lt;keith_miller@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ES6] Add TypedArray.prototype functionality.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -539,6 +539,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLJSCall.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLJSCallBase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLJSCallVarargs.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\ftl\FTLJSTailCall.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLLink.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLLocation.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLLowerDFGToLLVM.cpp&quot; /&gt;
</span><span class="lines">@@ -1300,6 +1301,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLJSCall.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLJSCallBase.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLJSCallVarargs.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\ftl\FTLJSTailCall.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLLink.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLLocation.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLLowerDFGToLLVM.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxprojfilters"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -1584,6 +1584,9 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLJSCall.cpp&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;ftl&lt;/Filter&gt;
</span><span class="cx">     &lt;/ClCompile&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\ftl\FTLJSTailCall.cpp&quot;&gt;
+      &lt;Filter&gt;ftl&lt;/Filter&gt;
+    &lt;/ClCompile&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\ftl\FTLLink.cpp&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;ftl&lt;/Filter&gt;
</span><span class="cx">     &lt;/ClCompile&gt;
</span><span class="lines">@@ -4153,6 +4156,9 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLJSCall.h&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;ftl&lt;/Filter&gt;
</span><span class="cx">     &lt;/ClInclude&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\ftl\FTLJSTailCall.h&quot;&gt;
+      &lt;Filter&gt;ftl&lt;/Filter&gt;
+    &lt;/ClInclude&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\ftl\FTLLink.h&quot;&gt;
</span><span class="cx">       &lt;Filter&gt;ftl&lt;/Filter&gt;
</span><span class="cx">     &lt;/ClInclude&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -980,6 +980,8 @@
</span><span class="cx">                 623A37EC1B87A7C000754209 /* RegisterMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 623A37EB1B87A7BD00754209 /* RegisterMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 627673231B680C1E00FD9F2E /* CallMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 627673211B680C1E00FD9F2E /* CallMode.cpp */; };
</span><span class="cx">                 627673241B680C1E00FD9F2E /* CallMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 627673221B680C1E00FD9F2E /* CallMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                62774DAA1B8D4B190006F05A /* FTLJSTailCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62774DA81B8D4B190006F05A /* FTLJSTailCall.cpp */; };
+                62774DAB1B8D4B190006F05A /* FTLJSTailCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 62774DA91B8D4B190006F05A /* FTLJSTailCall.h */; };
</ins><span class="cx">                 62D2D38F1ADF103F000206C1 /* FunctionRareData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */; };
</span><span class="cx">                 62D2D3901ADF103F000206C1 /* FunctionRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = 62D2D38E1ADF103F000206C1 /* FunctionRareData.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 62D755D41B84FB3D001801FA /* CallFrameShuffler64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 62D755D31B84FB39001801FA /* CallFrameShuffler64.cpp */; };
</span><span class="lines">@@ -2804,6 +2806,8 @@
</span><span class="cx">                 623A37EB1B87A7BD00754209 /* RegisterMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterMap.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 627673211B680C1E00FD9F2E /* CallMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CallMode.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 627673221B680C1E00FD9F2E /* CallMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallMode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                62774DA81B8D4B190006F05A /* FTLJSTailCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLJSTailCall.cpp; path = ftl/FTLJSTailCall.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                62774DA91B8D4B190006F05A /* FTLJSTailCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLJSTailCall.h; path = ftl/FTLJSTailCall.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 62A9A29E1B0BED4800BD54CA /* DFGLazyNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGLazyNode.cpp; path = dfg/DFGLazyNode.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 62A9A29F1B0BED4800BD54CA /* DFGLazyNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGLazyNode.h; path = dfg/DFGLazyNode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 62D2D38D1ADF103F000206C1 /* FunctionRareData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FunctionRareData.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3982,6 +3986,8 @@
</span><span class="cx">                                 0FD1202E1A8AED12000F5280 /* FTLJSCallBase.h */,
</span><span class="cx">                                 0FD120311A8C85BD000F5280 /* FTLJSCallVarargs.cpp */,
</span><span class="cx">                                 0FD120321A8C85BD000F5280 /* FTLJSCallVarargs.h */,
</span><ins>+                                62774DA81B8D4B190006F05A /* FTLJSTailCall.cpp */,
+                                62774DA91B8D4B190006F05A /* FTLJSTailCall.h */,
</ins><span class="cx">                                 0F8F2B93172E049E007DBDA5 /* FTLLink.cpp */,
</span><span class="cx">                                 0F8F2B94172E049E007DBDA5 /* FTLLink.h */,
</span><span class="cx">                                 0FCEFADD180738C000472CE4 /* FTLLocation.cpp */,
</span><span class="lines">@@ -6330,6 +6336,7 @@
</span><span class="cx">                                 0F6B1CB6185FC9E900845D97 /* FTLJSCall.h in Headers */,
</span><span class="cx">                                 0FD120301A8AED12000F5280 /* FTLJSCallBase.h in Headers */,
</span><span class="cx">                                 0FD120341A8C85BD000F5280 /* FTLJSCallVarargs.h in Headers */,
</span><ins>+                                62774DAB1B8D4B190006F05A /* FTLJSTailCall.h in Headers */,
</ins><span class="cx">                                 0F8F2B96172E04A3007DBDA5 /* FTLLink.h in Headers */,
</span><span class="cx">                                 0FCEFAE0180738C000472CE4 /* FTLLocation.h in Headers */,
</span><span class="cx">                                 0FEA0A10170513DB00BB722C /* FTLLowerDFGToLLVM.h in Headers */,
</span><span class="lines">@@ -7702,6 +7709,7 @@
</span><span class="cx">                                 0F6B1CB5185FC9E900845D97 /* FTLJSCall.cpp in Sources */,
</span><span class="cx">                                 0FD1202F1A8AED12000F5280 /* FTLJSCallBase.cpp in Sources */,
</span><span class="cx">                                 0FD120331A8C85BD000F5280 /* FTLJSCallVarargs.cpp in Sources */,
</span><ins>+                                62774DAA1B8D4B190006F05A /* FTLJSTailCall.cpp in Sources */,
</ins><span class="cx">                                 0F8F2B95172E04A0007DBDA5 /* FTLLink.cpp in Sources */,
</span><span class="cx">                                 0FCEFADF180738C000472CE4 /* FTLLocation.cpp in Sources */,
</span><span class="cx">                                 0FEA0A0F170513DB00BB722C /* FTLLowerDFGToLLVM.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -1882,11 +1882,15 @@
</span><span class="cx">         m_currentIndex = nextOffset;
</span><span class="cx">         m_exitOK = true;
</span><span class="cx">         processSetLocalQueue(); // This only comes into play for intrinsics, since normal inlined code will leave an empty queue.
</span><del>-        addToGraph(Jump);
</del><ins>+        if (Node* terminal = m_currentBlock-&gt;terminal())
+            ASSERT_UNUSED(terminal, terminal-&gt;op() == TailCall || terminal-&gt;op() == TailCallVarargs);
+        else {
+            addToGraph(Jump);
+            landingBlocks.append(m_currentBlock);
+        }
</ins><span class="cx">         if (verbose)
</span><span class="cx">             dataLog(&quot;Marking &quot;, RawPointer(m_currentBlock), &quot; as linked (tail of poly inlinee)\n&quot;);
</span><span class="cx">         m_currentBlock-&gt;didLink();
</span><del>-        landingBlocks.append(m_currentBlock);
</del><span class="cx"> 
</span><span class="cx">         if (verbose)
</span><span class="cx">             dataLog(&quot;Finished inlining &quot;, callLinkStatus[i], &quot; at &quot;, currentCodeOrigin(), &quot;.\n&quot;);
</span><span class="lines">@@ -1919,8 +1923,12 @@
</span><span class="cx">     m_currentIndex = nextOffset;
</span><span class="cx">     m_exitOK = true; // Origin changed, so it's fine to exit again.
</span><span class="cx">     processSetLocalQueue();
</span><del>-    addToGraph(Jump);
-    landingBlocks.append(m_currentBlock);
</del><ins>+    if (Node* terminal = m_currentBlock-&gt;terminal())
+        ASSERT_UNUSED(terminal, terminal-&gt;op() == TailCall || terminal-&gt;op() == TailCallVarargs);
+    else {
+        addToGraph(Jump);
+        landingBlocks.append(m_currentBlock);
+    }
</ins><span class="cx">     
</span><span class="cx">     RefPtr&lt;BasicBlock&gt; continuationBlock = adoptRef(
</span><span class="cx">         new BasicBlock(UINT_MAX, m_numArguments, m_numLocals, PNaN));
</span><span class="lines">@@ -3664,7 +3672,7 @@
</span><span class="cx">                 // We could be the dummy jump to a return after a non-inlined, non-emulated tail call in a ternary operator
</span><span class="cx">                 Node* terminal = m_currentBlock-&gt;terminal();
</span><span class="cx">                 ASSERT_UNUSED(terminal, terminal-&gt;op() == TailCall || terminal-&gt;op() == TailCallVarargs);
</span><del>-                LAST_OPCODE(op_ret);
</del><ins>+                LAST_OPCODE(op_jmp);
</ins><span class="cx">             }
</span><span class="cx">             int relativeOffset = currentInstruction[1].u.operand;
</span><span class="cx">             addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -1035,8 +1035,6 @@
</span><span class="cx">         
</span><span class="cx">     case ThrowReferenceError:
</span><span class="cx">         write(SideState);
</span><del>-        read(HeapObjectCount);
-        write(HeapObjectCount);
</del><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case CountExecution:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -1118,6 +1118,14 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isFunctionTerminal()
+    {
+        if (isTerminal() &amp;&amp; !numSuccessors())
+            return true;
+
+        return false;
+    }
+
</ins><span class="cx">     unsigned targetBytecodeOffsetDuringParsing()
</span><span class="cx">     {
</span><span class="cx">         ASSERT(isJump());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -771,6 +771,7 @@
</span><span class="cx">             calleeGPR = callee.gpr();
</span><span class="cx">             callee.use();
</span><span class="cx"> 
</span><ins>+            shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
</ins><span class="cx">             shuffleData.numLocals = m_jit.graph().frameRegisterCount();
</span><span class="cx">             shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
</span><span class="cx">             shuffleData.args.resize(numPassedArgs);
</span><span class="lines">@@ -868,7 +869,7 @@
</span><span class="cx">         m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    callLinkInfo-&gt;setUpCall(callType, m_currentNode-&gt;origin.semantic,  calleeGPR);    
</del><ins>+    callLinkInfo-&gt;setUpCall(callType, m_currentNode-&gt;origin.semantic, calleeGPR);
</ins><span class="cx">     m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGTierUpCheckInjectionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             NodeAndIndex terminal = block-&gt;findTerminal();
</span><del>-            if (terminal.node-&gt;op() == Return) {
</del><ins>+            if (terminal.node-&gt;isFunctionTerminal()) {
</ins><span class="cx">                 insertionSet.insertNode(
</span><span class="cx">                     terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node-&gt;origin);
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -130,10 +130,16 @@
</span><span class="cx">     case NotifyWrite:
</span><span class="cx">     case StoreBarrier:
</span><span class="cx">     case Call:
</span><ins>+    case TailCall:
+    case TailCallInlinedCaller:
</ins><span class="cx">     case Construct:
</span><span class="cx">     case CallVarargs:
</span><ins>+    case TailCallVarargs:
+    case TailCallVarargsInlinedCaller:
+    case ConstructVarargs:
</ins><span class="cx">     case CallForwardVarargs:
</span><del>-    case ConstructVarargs:
</del><ins>+    case TailCallForwardVarargs:
+    case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx">     case ConstructForwardVarargs:
</span><span class="cx">     case LoadVarargs:
</span><span class="cx">     case ValueToInt32:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCompilecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLCompile.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -618,6 +618,22 @@
</span><span class="cx">             call.link(vm, linkBuffer, state.finalizer-&gt;handleExceptionsLinkBuffer-&gt;entrypoint());
</span><span class="cx">         });
</span><span class="cx">     }
</span><ins>+
+    adjustCallICsForStackmaps(state.jsTailCalls, recordMap);
+
+    for (unsigned i = state.jsTailCalls.size(); i--;) {
+        JSTailCall&amp; call = state.jsTailCalls[i];
+
+        CCallHelpers fastPathJIT(&amp;vm, codeBlock);
+        call.emit(*state.jitCode.get(), fastPathJIT);
+
+        char* startOfIC = bitwise_cast&lt;char*&gt;(generatedFunction) + call.m_instructionOffset;
+        size_t sizeOfIC = call.estimatedSize();
+
+        generateInlineIfPossibleOutOfLineIfNot(state, vm, codeBlock, fastPathJIT, startOfIC, sizeOfIC, &quot;tail call inline cache&quot;, [&amp;] (LinkBuffer&amp; linkBuffer, CCallHelpers&amp;, bool) {
+            call.link(vm, linkBuffer);
+        });
+    }
</ins><span class="cx">     
</span><span class="cx">     auto iter = recordMap.find(state.handleStackOverflowExceptionStackmapID);
</span><span class="cx">     // It's sort of remotely possible that we won't have an in-band exception handling
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheSizecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -82,6 +82,15 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+size_t sizeOfTailCallVarargs()
+{
+#if CPU(ARM64)
+    return 188 + sizeOfCallVarargs();
+#else
+    return 151 + sizeOfCallVarargs();
+#endif
+}
+
</ins><span class="cx"> size_t sizeOfCallForwardVarargs()
</span><span class="cx"> {
</span><span class="cx"> #if CPU(ARM64)
</span><span class="lines">@@ -91,6 +100,15 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+size_t sizeOfTailCallForwardVarargs()
+{
+#if CPU(ARM64)
+    return 188 + sizeOfCallForwardVarargs();
+#else
+    return 151 + sizeOfCallForwardVarargs();
+#endif
+}
+
</ins><span class="cx"> size_t sizeOfConstructVarargs()
</span><span class="cx"> {
</span><span class="cx">     return sizeOfCallVarargs(); // Should be the same size.
</span><span class="lines">@@ -121,9 +139,15 @@
</span><span class="cx">     case Construct:
</span><span class="cx">         return sizeOfCall();
</span><span class="cx">     case CallVarargs:
</span><ins>+    case TailCallVarargsInlinedCaller:
</ins><span class="cx">         return sizeOfCallVarargs();
</span><ins>+    case TailCallVarargs:
+        return sizeOfTailCallVarargs();
</ins><span class="cx">     case CallForwardVarargs:
</span><ins>+    case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx">         return sizeOfCallForwardVarargs();
</span><ins>+    case TailCallForwardVarargs:
+        return sizeOfTailCallForwardVarargs();
</ins><span class="cx">     case ConstructVarargs:
</span><span class="cx">         return sizeOfConstructVarargs();
</span><span class="cx">     case ConstructForwardVarargs:
</span><span class="lines">@@ -131,7 +155,7 @@
</span><span class="cx">     case In:
</span><span class="cx">         return sizeOfIn();
</span><span class="cx">     default:
</span><del>-        return 0;
</del><ins>+        RELEASE_ASSERT_NOT_REACHED();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLInlineCacheSizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLInlineCacheSize.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -40,7 +40,9 @@
</span><span class="cx"> size_t sizeOfPutById();
</span><span class="cx"> size_t sizeOfCall();
</span><span class="cx"> size_t sizeOfCallVarargs();
</span><ins>+size_t sizeOfTailCallVarargs();
</ins><span class="cx"> size_t sizeOfCallForwardVarargs();
</span><ins>+size_t sizeOfTailCallForwardVarargs();
</ins><span class="cx"> size_t sizeOfConstructVarargs();
</span><span class="cx"> size_t sizeOfConstructForwardVarargs();
</span><span class="cx"> size_t sizeOfIn();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCall.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx">     , m_stackmapID(stackmapID)
</span><span class="cx">     , m_instructionOffset(0)
</span><span class="cx"> {
</span><del>-    ASSERT(node-&gt;op() == Call || node-&gt;op() == Construct);
</del><ins>+    ASSERT(node-&gt;op() == Call || node-&gt;op() == Construct || node-&gt;op() == TailCallInlinedCaller);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JSCall::emit(CCallHelpers&amp; jit, unsigned stackSizeForLocals)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallBasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -52,19 +52,34 @@
</span><span class="cx"> {
</span><span class="cx">     m_callLinkInfo = jit.codeBlock()-&gt;addCallLinkInfo();
</span><span class="cx">     
</span><ins>+    if (CallLinkInfo::callModeFor(m_type) == CallMode::Tail)
+        jit.emitRestoreCalleeSaves();
+
</ins><span class="cx">     CCallHelpers::Jump slowPath = jit.branchPtrWithPatch(
</span><span class="cx">         CCallHelpers::NotEqual, GPRInfo::regT0, m_targetToCheck,
</span><span class="cx">         CCallHelpers::TrustedImmPtr(0));
</span><del>-    
-    m_fastCall = jit.nearCall();
-    CCallHelpers::Jump done = jit.jump();
-    
</del><ins>+
+    CCallHelpers::Jump done;
+
+    if (CallLinkInfo::callModeFor(m_type) == CallMode::Tail) {
+        jit.prepareForTailCallSlow();
+        m_fastCall = jit.nearTailCall();
+    } else {
+        m_fastCall = jit.nearCall();
+        done = jit.jump();
+    }
+
</ins><span class="cx">     slowPath.link(&amp;jit);
</span><del>-    
</del><ins>+
</ins><span class="cx">     jit.move(CCallHelpers::TrustedImmPtr(m_callLinkInfo), GPRInfo::regT2);
</span><span class="cx">     m_slowCall = jit.nearCall();
</span><del>-    
-    done.link(&amp;jit);
</del><ins>+
+    if (CallLinkInfo::callModeFor(m_type) == CallMode::Tail)
+        jit.abortWithReason(JITDidReturnFromTailCall);
+    else
+        done.link(&amp;jit);
+
+    m_callLinkInfo-&gt;setUpCall(m_type, m_origin, GPRInfo::regT0);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void JSCallBase::link(VM&amp; vm, LinkBuffer&amp; linkBuffer)
</span><span class="lines">@@ -72,9 +87,8 @@
</span><span class="cx">     linkBuffer.link(
</span><span class="cx">         m_slowCall, FunctionPtr(vm.getCTIStub(linkCallThunkGenerator).code().executableAddress()));
</span><span class="cx"> 
</span><del>-    m_callLinkInfo-&gt;setUpCallFromFTL(m_type, m_origin, linkBuffer.locationOfNearCall(m_slowCall),
-        linkBuffer.locationOf(m_targetToCheck), linkBuffer.locationOfNearCall(m_fastCall),
-        GPRInfo::regT0);
</del><ins>+    m_callLinkInfo-&gt;setCallLocations(linkBuffer.locationOfNearCall(m_slowCall),
+        linkBuffer.locationOf(m_targetToCheck), linkBuffer.locationOfNearCall(m_fastCall));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCallBase.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -50,7 +50,7 @@
</span><span class="cx">     void emit(CCallHelpers&amp;);
</span><span class="cx">     void link(VM&amp;, LinkBuffer&amp;);
</span><span class="cx">     
</span><del>-private:
</del><ins>+protected:
</ins><span class="cx">     CallLinkInfo::CallType m_type;
</span><span class="cx">     CodeOrigin m_origin;
</span><span class="cx">     CCallHelpers::DataLabelPtr m_targetToCheck;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSCallVarargscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSCallVarargs.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -51,12 +51,15 @@
</span><span class="cx">     , m_node(node)
</span><span class="cx">     , m_callBase(
</span><span class="cx">         (node-&gt;op() == ConstructVarargs || node-&gt;op() == ConstructForwardVarargs)
</span><del>-        ? CallLinkInfo::ConstructVarargs : CallLinkInfo::CallVarargs,
</del><ins>+        ? CallLinkInfo::ConstructVarargs : (node-&gt;op() == TailCallVarargs || node-&gt;op() == TailCallForwardVarargs)
+        ? CallLinkInfo::TailCallVarargs : CallLinkInfo::CallVarargs,
</ins><span class="cx">         node-&gt;origin.semantic)
</span><span class="cx">     , m_instructionOffset(0)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(
</span><span class="cx">         node-&gt;op() == CallVarargs || node-&gt;op() == CallForwardVarargs
</span><ins>+        || node-&gt;op() == TailCallVarargsInlinedCaller || node-&gt;op() == TailCallForwardVarargsInlinedCaller
+        || node-&gt;op() == TailCallVarargs || node-&gt;op() == TailCallForwardVarargs
</ins><span class="cx">         || node-&gt;op() == ConstructVarargs || node-&gt;op() == ConstructForwardVarargs);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -83,11 +86,15 @@
</span><span class="cx">     
</span><span class="cx">     switch (m_node-&gt;op()) {
</span><span class="cx">     case CallVarargs:
</span><ins>+    case TailCallVarargs:
+    case TailCallVarargsInlinedCaller:
</ins><span class="cx">     case ConstructVarargs:
</span><span class="cx">         argumentsGPR = GPRInfo::argumentGPR1;
</span><span class="cx">         thisGPR = GPRInfo::argumentGPR2;
</span><span class="cx">         break;
</span><span class="cx">     case CallForwardVarargs:
</span><ins>+    case TailCallForwardVarargs:
+    case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx">     case ConstructForwardVarargs:
</span><span class="cx">         thisGPR = GPRInfo::argumentGPR1;
</span><span class="cx">         forwarding = true;
</span><span class="lines">@@ -196,7 +203,7 @@
</span><span class="cx">     // Henceforth we make the call. The base FTL call machinery expects the callee in regT0 and for the
</span><span class="cx">     // stack frame to already be set up, which it is.
</span><span class="cx">     jit.store64(GPRInfo::regT0, CCallHelpers::calleeFrameSlot(JSStack::Callee));
</span><del>-    
</del><ins>+
</ins><span class="cx">     m_callBase.emit(jit);
</span><span class="cx">     
</span><span class="cx">     // Undo the damage we've done.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSTailCallcpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.cpp (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,326 @@
</span><ins>+/*
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;FTLJSTailCall.h&quot;
+
+#if ENABLE(FTL_JIT)
+
+#include &quot;CallFrameShuffler.h&quot;
+#include &quot;DFGNode.h&quot;
+#include &quot;FTLJITCode.h&quot;
+#include &quot;FTLLocation.h&quot;
+#include &quot;FTLStackMaps.h&quot;
+#include &quot;JSCJSValueInlines.h&quot;
+#include &quot;LinkBuffer.h&quot;
+
+namespace JSC { namespace FTL {
+
+using namespace DFG;
+
+namespace {
+
+FTL::Location getRegisterWithAddend(const ExitValue&amp; value, StackMaps::Record&amp; record, StackMaps&amp; stackmaps)
+{
+    if (value.kind() != ExitValueArgument)
+        return { };
+
+    auto location =
+        FTL::Location::forStackmaps(&amp;stackmaps, record.locations[value.exitArgument().argument()]);
+
+    if (location.kind() != Location::Register || !location.addend())
+        return { };
+
+    RELEASE_ASSERT(location.isGPR());
+    return location;
+}
+
+ValueRecovery recoveryFor(const ExitValue&amp; value, StackMaps::Record&amp; record, StackMaps&amp; stackmaps)
+{
+    switch (value.kind()) {
+    case ExitValueConstant:
+        return ValueRecovery::constant(value.constant());
+
+    case ExitValueArgument: {
+        auto location =
+            FTL::Location::forStackmaps(&amp;stackmaps, record.locations[value.exitArgument().argument()]);
+        auto format = value.exitArgument().format();
+
+        switch (location.kind()) {
+        case Location::Register:
+            // We handle the addend outside
+            return ValueRecovery::inRegister(location.dwarfReg().reg(), format);
+
+        case Location::Indirect:
+            // Oh LLVM, you crazy...
+            RELEASE_ASSERT(location.dwarfReg().reg() == Reg(MacroAssembler::framePointerRegister));
+            RELEASE_ASSERT(!(location.offset() % sizeof(void*)));
+            return ValueRecovery::displacedInJSStack(VirtualRegister { static_cast&lt;int&gt;(location.offset() / sizeof(void*)) }, format);
+
+        case Location::Constant:
+            return ValueRecovery::constant(JSValue::decode(location.constant()));
+
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
+
+    case ExitValueInJSStack:
+        return ValueRecovery::displacedInJSStack(value.virtualRegister(), DataFormatJS);
+
+    case ExitValueInJSStackAsInt32:
+        return ValueRecovery::displacedInJSStack(value.virtualRegister(), DataFormatInt32);
+
+    case ExitValueInJSStackAsInt52:
+        return ValueRecovery::displacedInJSStack(value.virtualRegister(), DataFormatInt52);
+
+    case ExitValueInJSStackAsDouble:
+        return ValueRecovery::displacedInJSStack(value.virtualRegister(), DataFormatDouble);
+
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
+// This computes an estimated size (in bits) for the sequence of
+// instructions required to load, box, and store a value of a given
+// type, assuming no spilling is required.
+uint32_t sizeFor(DataFormat format)
+{
+    switch (format) {
+    case DataFormatInt32:
+        // Boxing is zero-extending and tagging
+#if CPU(X86_64)
+        return 6 + sizeFor(DataFormatJS);
+#elif CPU(ARM64)
+        return 8 + sizeFor(DataFormatJS);
+#else
+        return sizeOfZeroExtend32 + sizeOfOrImm64 + sizeFor(DataFormatJS);
+#endif
+
+    case DataFormatInt52:
+        // Boxing is first a conversion to StrictInt52, then
+        // StrictInt52 boxing
+#if CPU(X86_64)
+        return 4 + sizeFor(DataFormatStrictInt52);
+#elif CPU(ARM64)
+        return 4 + sizeFor(DataFormatStrictInt52);
+#else
+        return sizeOfShiftImm32 + sizeFor(DataFormatStrictInt52);
+#endif
+
+    case DataFormatStrictInt52:
+        // Boxing is first a conversion to double, then double boxing
+#if CPU(X86_64)
+        return 8 + sizeFor(DataFormatDouble);
+#elif CPU(ARM64)
+        return 4 + sizeFor(DataFormatDouble);
+#else
+        return sizeOfConvertInt64ToDouble + sizeFor(DataFormatDouble);
+#endif
+
+    case DataFormatDouble:
+        // Boxing is purifying, moving to a GPR, and tagging
+#if CPU(X86_64)
+        return 38 + sizeFor(DataFormatJS);
+#elif CPU(ARM64)
+        return 28 + sizeFor(DataFormatJS);
+#else
+        return sizeOfPurifyNaN + sizeOfSubImm64 + sizeOfMoveDoubleTo64 + sizeFor(DataFormatJS);
+#endif
+
+    case DataFormatBoolean:
+        // Boxing is adding ValueFalse
+#if CPU(X86_64)
+        return 4 + sizeFor(DataFormatJS);
+#elif CPU(ARM64)
+        return 4 + sizeFor(DataFormatJS);
+#else
+        return sizeOfAddImm32 + sizeFor(DataFormatJS);
+#endif
+
+    case DataFormatJS:
+        // We will load (in a GPR or FPR) then store the value
+#if CPU(X86_64)
+        return 8;
+#elif CPU(ARM64)
+        return 8;
+#else
+        return sizeOfLoad + sizeOfStore;
+#endif
+
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+    }
+}
+
+} // anonymous namespace
+
+JSTailCall::JSTailCall(unsigned stackmapID, Node* node, Vector&lt;ExitValue&gt; arguments)
+    : JSCallBase(CallLinkInfo::TailCall, node-&gt;origin.semantic)
+    , m_stackmapID(stackmapID)
+    , m_arguments { WTF::move(arguments) }
+    , m_instructionOffset(0)
+{
+    ASSERT(node-&gt;op() == TailCall);
+    ASSERT(numArguments() == node-&gt;numChildren() - 1);
+
+    // Estimate the size of the inline cache, assuming that every
+    // value goes from the stack to the stack (in practice, this will
+    // seldom be true, giving us some amount of leeway) and that no
+    // spilling will occur (in practice, this will almost always be
+    // true).
+
+    // We first compute the new frame base and load the fp/lr
+    // registers final values. On debug builds, we also need to
+    // account for the fp-sp delta check (twice: fast and slow path).
+#if CPU(X86_64)
+    m_estimatedSize = 56;
+#if !ASSERT_DISABLED
+    m_estimatedSize += 26;
+#  endif
+#elif CPU(ARM64)
+    m_estimatedSize = 44;
+#if !ASSERT_DISABLED
+    m_estimatedSize += 24;
+#  endif
+#else
+    UNREACHABLE_FOR_PLATFORM();
+#endif
+
+    // Arguments will probably be loaded &amp; stored twice (fast &amp; slow)
+    for (ExitValue&amp; arg : m_arguments)
+        m_estimatedSize += 2 * sizeFor(arg.dataFormat());
+
+    // We also have the slow path check, the two calls, and the
+    // CallLinkInfo load for the slow path
+#if CPU(X86_64)
+    m_estimatedSize += 55;
+#elif CPU(ARM64)
+    m_estimatedSize += 44;
+#else
+    m_estimatedSize += sizeOfCall + sizeOfJump + sizeOfLoad + sizeOfSlowPathCheck;
+#endif
+}
+
+void JSTailCall::emit(JITCode&amp; jitCode, CCallHelpers&amp; jit)
+{
+    StackMaps::Record* record { nullptr };
+    
+    for (unsigned i = jitCode.stackmaps.records.size(); i--;) {
+        record = &amp;jitCode.stackmaps.records[i];
+        if (record-&gt;patchpointID == m_stackmapID)
+            break;
+    }
+
+    RELEASE_ASSERT(record-&gt;patchpointID == m_stackmapID);
+
+    m_callLinkInfo = jit.codeBlock()-&gt;addCallLinkInfo();
+
+    CallFrameShuffleData shuffleData;
+
+    // The callee was the first passed argument, and must be in a GPR because
+    // we used the &quot;anyregcc&quot; calling convention
+    auto calleeLocation =
+        FTL::Location::forStackmaps(nullptr, record-&gt;locations[0]);
+    GPRReg calleeGPR = calleeLocation.directGPR();
+    shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
+
+    // The tag type number was the second argument, if there was one
+    auto tagTypeNumberLocation =
+        FTL::Location::forStackmaps(&amp;jitCode.stackmaps, record-&gt;locations[1]);
+    if (tagTypeNumberLocation.isGPR() &amp;&amp; !tagTypeNumberLocation.addend())
+        shuffleData.tagTypeNumber = tagTypeNumberLocation.directGPR();
+
+    shuffleData.args.grow(numArguments());
+    HashMap&lt;Reg, Vector&lt;std::pair&lt;ValueRecovery*, int32_t&gt;&gt;&gt; withAddend;
+    size_t numAddends { 0 };
+    for (size_t i = 0; i &lt; numArguments(); ++i) {
+        shuffleData.args[i] = recoveryFor(m_arguments[i], *record, jitCode.stackmaps);
+        if (FTL::Location addend = getRegisterWithAddend(m_arguments[i], *record, jitCode.stackmaps)) {
+            withAddend.add(
+                addend.dwarfReg().reg(),
+                Vector&lt;std::pair&lt;ValueRecovery*, int32_t&gt;&gt;()).iterator-&gt;value.append(
+                    std::make_pair(&amp;shuffleData.args[i], addend.addend()));
+            numAddends++;
+        }
+    }
+
+    numAddends = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), numAddends);
+
+    shuffleData.numLocals = static_cast&lt;int64_t&gt;(jitCode.stackmaps.stackSizeForLocals()) / sizeof(void*) + numAddends;
+
+    ASSERT(!numAddends == withAddend.isEmpty());
+
+    if (!withAddend.isEmpty()) {
+        jit.subPtr(MacroAssembler::TrustedImm32(numAddends * sizeof(void*)), MacroAssembler::stackPointerRegister);
+        VirtualRegister spillBase { 1 - static_cast&lt;int&gt;(shuffleData.numLocals) };
+        for (auto entry : withAddend) {
+            for (auto pair : entry.value) {
+                ASSERT(numAddends &gt; 0);
+                VirtualRegister spillSlot { spillBase + --numAddends };
+                ASSERT(entry.key.isGPR());
+                jit.addPtr(MacroAssembler::TrustedImm32(pair.second), entry.key.gpr());
+                jit.storePtr(entry.key.gpr(), CCallHelpers::addressFor(spillSlot));
+                jit.subPtr(MacroAssembler::TrustedImm32(pair.second), entry.key.gpr());
+                *pair.first = ValueRecovery::displacedInJSStack(spillSlot, pair.first-&gt;dataFormat());
+            }
+        }
+        ASSERT(numAddends &lt; stackAlignmentRegisters());
+    }
+
+    shuffleData.args.resize(numArguments());
+    for (size_t i = 0; i &lt; numArguments(); ++i)
+        shuffleData.args[i] = recoveryFor(m_arguments[i], *record, jitCode.stackmaps);
+
+    shuffleData.setupCalleeSaveRegisters(jit.codeBlock());
+
+    CCallHelpers::Jump slowPath = jit.branchPtrWithPatch(
+        CCallHelpers::NotEqual, calleeGPR, m_targetToCheck,
+        CCallHelpers::TrustedImmPtr(0));
+
+    m_callLinkInfo-&gt;setFrameShuffleData(shuffleData);
+    CallFrameShuffler(jit, shuffleData).prepareForTailCall();
+
+    m_fastCall = jit.nearTailCall();
+
+    slowPath.link(&amp;jit);
+
+    CallFrameShuffler slowPathShuffler(jit, shuffleData);
+    slowPathShuffler.setCalleeJSValueRegs(JSValueRegs { GPRInfo::regT0 });
+    slowPathShuffler.prepareForSlowPath();
+
+    jit.move(CCallHelpers::TrustedImmPtr(m_callLinkInfo), GPRInfo::regT2);
+
+    m_slowCall = jit.nearCall();
+
+    jit.abortWithReason(JITDidReturnFromTailCall);
+
+    m_callLinkInfo-&gt;setUpCall(m_type, m_origin, calleeGPR);
+}
+
+} } // namespace JSC::FTL
+
+#endif // ENABLE(FTL_JIT)
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLJSTailCallh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.h (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/ftl/FTLJSTailCall.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,74 @@
</span><ins>+/*
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef FTLJSTailCall_h
+#define FTLJSTailCall_h
+
+#if ENABLE(FTL_JIT)
+
+#include &quot;FTLExitArgumentList.h&quot;
+#include &quot;FTLExitValue.h&quot;
+#include &quot;FTLJSCallBase.h&quot;
+
+namespace JSC {
+
+namespace DFG {
+struct Node;
+}
+
+namespace FTL {
+
+class JSTailCall : public JSCallBase {
+public:
+    JSTailCall(unsigned stackmapID, DFG::Node*, Vector&lt;ExitValue&gt; arguments);
+
+    void emit(JITCode&amp;, CCallHelpers&amp;);
+    
+    unsigned stackmapID() const { return m_stackmapID; }
+
+    unsigned estimatedSize() const { return m_estimatedSize; }
+
+    unsigned numArguments() const { return m_arguments.size(); }
+
+    bool operator&lt;(const JSTailCall&amp; other) const
+    {
+        return m_instructionOffset &lt; other.m_instructionOffset;
+    }
+    
+private:
+    unsigned m_stackmapID;
+    Vector&lt;ExitValue&gt; m_arguments;
+    unsigned m_estimatedSize;
+
+public:
+    uint32_t m_instructionOffset;
+};
+
+} } // namespace JSC::FTL
+
+#endif // ENABLE(FTL_JIT)
+
+#endif // FTLJSTailCall_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLocationh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLocation.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLocation.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLLocation.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -120,7 +120,9 @@
</span><span class="cx">         return u.constant;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool operator!() const { return kind() == Unprocessed &amp;&amp; !u.variable.offset; }
</del><ins>+    explicit operator bool() const { return kind() != Unprocessed || u.variable.offset; }
+
+    bool operator!() const { return !static_cast&lt;bool&gt;(*this); }
</ins><span class="cx">     
</span><span class="cx">     bool isHashTableDeletedValue() const { return kind() == Unprocessed &amp;&amp; u.variable.offset; }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -173,7 +173,11 @@
</span><span class="cx">             for (Node* node : *block) {
</span><span class="cx">                 switch (node-&gt;op()) {
</span><span class="cx">                 case CallVarargs:
</span><ins>+                case TailCallVarargs:
+                case TailCallVarargsInlinedCaller:
</ins><span class="cx">                 case CallForwardVarargs:
</span><ins>+                case TailCallForwardVarargs:
+                case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx">                 case ConstructVarargs:
</span><span class="cx">                 case ConstructForwardVarargs:
</span><span class="cx">                     hasVarargs = true;
</span><span class="lines">@@ -723,11 +727,19 @@
</span><span class="cx">             compileLogicalNot();
</span><span class="cx">             break;
</span><span class="cx">         case Call:
</span><ins>+        case TailCallInlinedCaller:
</ins><span class="cx">         case Construct:
</span><span class="cx">             compileCallOrConstruct();
</span><span class="cx">             break;
</span><ins>+        case TailCall:
+            compileTailCall();
+            break;
</ins><span class="cx">         case CallVarargs:
</span><span class="cx">         case CallForwardVarargs:
</span><ins>+        case TailCallVarargs:
+        case TailCallVarargsInlinedCaller:
+        case TailCallForwardVarargs:
+        case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx">         case ConstructVarargs:
</span><span class="cx">         case ConstructForwardVarargs:
</span><span class="cx">             compileCallOrConstructVarargs();
</span><span class="lines">@@ -4400,6 +4412,41 @@
</span><span class="cx">         
</span><span class="cx">         setJSValue(call);
</span><span class="cx">     }
</span><ins>+
+    void compileTailCall()
+    {
+        int numArgs = m_node-&gt;numChildren() - 1;
+        ExitArgumentList exitArguments;
+        exitArguments.reserveCapacity(numArgs + 6);
+
+        unsigned stackmapID = m_stackmapIDs++;
+        exitArguments.append(lowJSValue(m_graph.varArgChild(m_node, 0)));
+        exitArguments.append(m_tagTypeNumber);
+
+        Vector&lt;ExitValue&gt; callArguments(numArgs);
+
+        bool needsTagTypeNumber { false };
+        for (int i = 0; i &lt; numArgs; ++i) {
+            callArguments[i] =
+                exitValueForTailCall(exitArguments, m_graph.varArgChild(m_node, 1 + i).node());
+            if (callArguments[i].dataFormat() == DataFormatInt32)
+                needsTagTypeNumber = true;
+        }
+
+        JSTailCall tailCall(stackmapID, m_node, WTF::move(callArguments));
+
+        exitArguments.insert(0, m_out.constInt32(needsTagTypeNumber ? 2 : 1));
+        exitArguments.insert(0, constNull(m_out.ref8));
+        exitArguments.insert(0, m_out.constInt32(tailCall.estimatedSize()));
+        exitArguments.insert(0, m_out.constInt64(stackmapID));
+
+        LValue call =
+            m_out.call(m_out.patchpointVoidIntrinsic(), exitArguments);
+        setInstructionCallingConvention(call, LLVMAnyRegCallConv);
+        m_out.unreachable();
+
+        m_ftlState.jsTailCalls.append(tailCall);
+    }
</ins><span class="cx">     
</span><span class="cx">     void compileCallOrConstructVarargs()
</span><span class="cx">     {
</span><span class="lines">@@ -4410,10 +4457,14 @@
</span><span class="cx">         
</span><span class="cx">         switch (m_node-&gt;op()) {
</span><span class="cx">         case CallVarargs:
</span><ins>+        case TailCallVarargs:
+        case TailCallVarargsInlinedCaller:
</ins><span class="cx">         case ConstructVarargs:
</span><span class="cx">             jsArguments = lowJSValue(m_node-&gt;child2());
</span><span class="cx">             break;
</span><span class="cx">         case CallForwardVarargs:
</span><ins>+        case TailCallForwardVarargs:
+        case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx">         case ConstructForwardVarargs:
</span><span class="cx">             break;
</span><span class="cx">         default:
</span><span class="lines">@@ -4440,8 +4491,16 @@
</span><span class="cx">         setInstructionCallingConvention(call, LLVMCCallConv);
</span><span class="cx">         
</span><span class="cx">         m_ftlState.jsCallVarargses.append(JSCallVarargs(stackmapID, m_node));
</span><del>-        
-        setJSValue(call);
</del><ins>+
+        switch (m_node-&gt;op()) {
+        case TailCallVarargs:
+        case TailCallForwardVarargs:
+            m_out.unreachable();
+            break;
+
+        default:
+            setJSValue(call);
+        }
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void compileLoadVarargs()
</span><span class="lines">@@ -8256,7 +8315,14 @@
</span><span class="cx">     }
</span><span class="cx">     void callPreflight()
</span><span class="cx">     {
</span><del>-        callPreflight(m_node-&gt;origin.semantic);
</del><ins>+        CodeOrigin codeOrigin = m_node-&gt;origin.semantic;
+
+        if (m_node-&gt;op() == TailCallInlinedCaller
+            || m_node-&gt;op() == TailCallVarargsInlinedCaller
+            || m_node-&gt;op() == TailCallForwardVarargsInlinedCaller)
+            codeOrigin =*codeOrigin.inlineCallFrame-&gt;getCallerSkippingDeadFrames();
+
+        callPreflight(codeOrigin);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void callCheck()
</span><span class="lines">@@ -8527,13 +8593,46 @@
</span><span class="cx">         DFG_CRASH(m_graph, m_node, toCString(&quot;Cannot find value for node: &quot;, node).data());
</span><span class="cx">         return ExitValue::dead();
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     ExitValue exitArgument(ExitArgumentList&amp; arguments, DataFormat format, LValue value)
</span><span class="cx">     {
</span><span class="cx">         ExitValue result = ExitValue::exitArgument(ExitArgument(format, arguments.size()));
</span><span class="cx">         arguments.append(value);
</span><span class="cx">         return result;
</span><span class="cx">     }
</span><ins>+
+    ExitValue exitValueForTailCall(ExitArgumentList&amp; arguments, Node* node)
+    {
+        ASSERT(node-&gt;shouldGenerate());
+        ASSERT(node-&gt;hasResult());
+
+        switch (node-&gt;op()) {
+        case JSConstant:
+        case Int52Constant:
+        case DoubleConstant:
+            return ExitValue::constant(node-&gt;asJSValue());
+
+        default:
+            break;
+        }
+
+        LoweredNodeValue value = m_jsValueValues.get(node);
+        if (isValid(value))
+            return exitArgument(arguments, DataFormatJS, value.value());
+
+        value = m_int32Values.get(node);
+        if (isValid(value))
+            return exitArgument(arguments, DataFormatInt32, value.value());
+
+        value = m_booleanValues.get(node);
+        if (isValid(value)) {
+            LValue valueToPass = m_out.zeroExt(value.value(), m_out.int32);
+            return exitArgument(arguments, DataFormatBoolean, valueToPass);
+        }
+
+        // Doubles and Int52 have been converted by ValueRep()
+        DFG_CRASH(m_graph, m_node, toCString(&quot;Cannot find value for node: &quot;, node).data());
+    }
</ins><span class="cx">     
</span><span class="cx">     bool doesKill(Edge edge)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLStateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLState.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLState.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/ftl/FTLState.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> #include &quot;FTLJITFinalizer.h&quot;
</span><span class="cx"> #include &quot;FTLJSCall.h&quot;
</span><span class="cx"> #include &quot;FTLJSCallVarargs.h&quot;
</span><ins>+#include &quot;FTLJSTailCall.h&quot;
</ins><span class="cx"> #include &quot;FTLStackMaps.h&quot;
</span><span class="cx"> #include &quot;FTLState.h&quot;
</span><span class="cx"> #include &lt;wtf/Noncopyable.h&gt;
</span><span class="lines">@@ -79,6 +80,7 @@
</span><span class="cx">     SegmentedVector&lt;CheckInDescriptor&gt; checkIns;
</span><span class="cx">     Vector&lt;JSCall&gt; jsCalls;
</span><span class="cx">     Vector&lt;JSCallVarargs&gt; jsCallVarargses;
</span><ins>+    Vector&lt;JSTailCall&gt; jsTailCalls;
</ins><span class="cx">     Vector&lt;CString&gt; codeSectionNames;
</span><span class="cx">     Vector&lt;CString&gt; dataSectionNames;
</span><span class="cx">     void* unwindDataSection;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitAssemblyHelperscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/jit/AssemblyHelpers.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -338,7 +338,7 @@
</span><span class="cx">     
</span><span class="cx">     if (width == NormalJumpWidth)
</span><span class="cx">         return result;
</span><del>-    
</del><ins>+
</ins><span class="cx">     PatchableJump realJump = patchableJump();
</span><span class="cx">     result.link(this);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShuffleDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx">     Vector&lt;ValueRecovery&gt; args;
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">     RegisterMap&lt;ValueRecovery&gt; registers;
</span><ins>+    GPRReg tagTypeNumber { InvalidGPRReg };
</ins><span class="cx"> 
</span><span class="cx">     void setupCalleeSaveRegisters(CodeBlock*);
</span><span class="cx"> #endif
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShufflercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -71,6 +71,10 @@
</span><span class="cx">         else
</span><span class="cx">             addNew(reg.fpr(), data.registers[reg]);
</span><span class="cx">     }
</span><ins>+
+    m_tagTypeNumber = data.tagTypeNumber;
+    if (m_tagTypeNumber != InvalidGPRReg)
+        lockGPR(m_tagTypeNumber);
</ins><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -80,12 +84,12 @@
</span><span class="cx">     static const char* dangerDelimiter       = &quot; X-------------------------------X &quot;;
</span><span class="cx">     static const char* dangerBoundsDelimiter = &quot; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX &quot;;
</span><span class="cx">     static const char* emptySpace            = &quot;                                   &quot;;
</span><del>-    ASSERT(m_alignedNewFrameSize &lt;= numLocals());
</del><span class="cx">     out.print(&quot;          &quot;);
</span><span class="cx">     out.print(&quot;           Old frame               &quot;);
</span><span class="cx">     out.print(&quot;           New frame               &quot;);
</span><span class="cx">     out.print(&quot;\n&quot;);
</span><del>-    for (int i = 0; i &lt; m_alignedOldFrameSize + numLocals() + 3; ++i) {
</del><ins>+    int totalSize = m_alignedOldFrameSize + std::max(numLocals(), m_alignedNewFrameSize) + 3;
+    for (int i = 0; i &lt; totalSize; ++i) {
</ins><span class="cx">         VirtualRegister old { m_alignedOldFrameSize - i - 1 };
</span><span class="cx">         VirtualRegister newReg { old + m_frameDelta };
</span><span class="cx"> 
</span><span class="lines">@@ -204,6 +208,10 @@
</span><span class="cx">         out.print(&quot;   Old frame offset is &quot;, m_oldFrameOffset, &quot;\n&quot;);
</span><span class="cx">     if (m_newFrameOffset)
</span><span class="cx">         out.print(&quot;   New frame offset is &quot;, m_newFrameOffset, &quot;\n&quot;);
</span><ins>+#if USE(JSVALUE64)
+    if (m_tagTypeNumber != InvalidGPRReg)
+        out.print(&quot;   TagTypeNumber is currently in &quot;, m_tagTypeNumber, &quot;\n&quot;);
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> CachedRecovery* CallFrameShuffler::getCachedRecovery(ValueRecovery recovery)
</span><span class="lines">@@ -247,17 +255,26 @@
</span><span class="cx">     ASSERT(cachedRecovery.recovery().isInRegisters());
</span><span class="cx"> 
</span><span class="cx">     VirtualRegister spillSlot { 0 };
</span><del>-    for (VirtualRegister slot = firstOld(); slot &lt;= lastOld(); slot -= 1) {
-        ASSERT(slot &lt; newAsOld(firstNew()));
</del><ins>+    for (VirtualRegister slot = firstOld(); slot &lt;= lastOld(); slot += 1) {
+        if (slot &gt;= newAsOld(firstNew()))
+            break;
+
</ins><span class="cx">         if (getOld(slot))
</span><span class="cx">             continue;
</span><span class="cx"> 
</span><span class="cx">         spillSlot = slot;
</span><span class="cx">         break;
</span><span class="cx">     }
</span><del>-    // We must have enough slots to be able to fit the whole
-    // callee's frame for the slow path.
-    RELEASE_ASSERT(spillSlot.isLocal());
</del><ins>+    // We must have enough slots to be able to fit the whole callee's
+    // frame for the slow path - unless we are in the FTL. In that
+    // case, we are allowed to extend the frame *once*, since we are
+    // guaranteed to have enough available space for that.
+    if (spillSlot &gt;= newAsOld(firstNew()) || !spillSlot.isLocal()) {
+        RELEASE_ASSERT(!m_didExtendFrame);
+        extendFrameIfNeeded();
+        spill(cachedRecovery);
+        return;
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (verbose)
</span><span class="cx">         dataLog(&quot;   * Spilling &quot;, cachedRecovery.recovery(), &quot; into &quot;, spillSlot, &quot;\n&quot;);
</span><span class="lines">@@ -286,6 +303,38 @@
</span><span class="cx">         dataLog(&quot;  Skipping the fp-sp delta check since there is too much pressure&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CallFrameShuffler::extendFrameIfNeeded()
+{
+    ASSERT(!m_didExtendFrame);
+    ASSERT(!isUndecided());
+
+    VirtualRegister firstRead { firstOld() };
+    for (; firstRead &lt;= virtualRegisterForLocal(0); firstRead += 1) {
+        if (getOld(firstRead))
+            break;
+    }
+    size_t availableSize = static_cast&lt;size_t&gt;(firstRead.offset() - firstOld().offset());
+    size_t wantedSize = m_newFrame.size() + m_newFrameOffset;
+
+    if (availableSize &lt; wantedSize) {
+        size_t delta = WTF::roundUpToMultipleOf(stackAlignmentRegisters(), wantedSize - availableSize);
+        m_oldFrame.grow(m_oldFrame.size() + delta);
+        for (size_t i = 0; i &lt; delta; ++i)
+            m_oldFrame[m_oldFrame.size() - i - 1] = nullptr;
+        m_jit.subPtr(MacroAssembler::TrustedImm32(delta * sizeof(Register)), MacroAssembler::stackPointerRegister);
+
+        if (isSlowPath())
+            m_frameDelta = numLocals() + JSStack::CallerFrameAndPCSize;
+        else
+            m_oldFrameOffset = numLocals();
+
+        if (verbose)
+            dataLogF(&quot;  Not enough space - extending the old frame %zu slot\n&quot;, delta);
+    }
+
+    m_didExtendFrame = true;
+}
+
</ins><span class="cx"> void CallFrameShuffler::prepareForSlowPath()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(isUndecided());
</span><span class="lines">@@ -296,8 +345,16 @@
</span><span class="cx">     m_newFrameOffset = -JSStack::CallerFrameAndPCSize;
</span><span class="cx"> 
</span><span class="cx">     if (verbose)
</span><del>-        dataLog(&quot;\n\nPreparing frame for slow path call:\n&quot;, *this);
</del><ins>+        dataLog(&quot;\n\nPreparing frame for slow path call:\n&quot;);
</ins><span class="cx"> 
</span><ins>+    // When coming from the FTL, we need to extend the frame. In other
+    // cases, we may end up extending the frame if we previously
+    // spilled things (e.g. in polymorphic cache).
+    extendFrameIfNeeded();
+
+    if (verbose)
+        dataLog(*this);
+
</ins><span class="cx">     prepareAny();
</span><span class="cx"> 
</span><span class="cx">     if (verbose)
</span><span class="lines">@@ -646,6 +703,11 @@
</span><span class="cx">         ASSERT_UNUSED(writesOK, writesOK);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+#if USE(JSVALUE64)
+    if (m_tagTypeNumber != InvalidGPRReg &amp;&amp; m_newRegisters[m_tagTypeNumber])
+        releaseGPR(m_tagTypeNumber);
+#endif
+
</ins><span class="cx">     // Handle 2) by loading all registers. We don't have to do any
</span><span class="cx">     // writes, since they have been taken care of above.
</span><span class="cx">     if (verbose)
</span><span class="lines">@@ -660,6 +722,11 @@
</span><span class="cx">         ASSERT(cachedRecovery-&gt;targets().isEmpty());
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+#if USE(JSVALUE64)
+    if (m_tagTypeNumber != InvalidGPRReg)
+        releaseGPR(m_tagTypeNumber);
+#endif
+
</ins><span class="cx">     // At this point, we have read everything we cared about from the
</span><span class="cx">     // stack, and written everything we had to to the stack.
</span><span class="cx">     if (verbose)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShufflerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -73,6 +73,21 @@
</span><span class="cx">         m_lockedRegisters.clear(gpr);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void restoreGPR(GPRReg gpr)
+    {
+        if (!m_newRegisters[gpr])
+            return;
+
+        ensureGPR();
+#if USE(JSVALUE32_64)
+        GPRReg tempGPR { getFreeGPR() };
+        lockGPR(tempGPR);
+        ensureGPR();
+        releaseGPR(tempGPR);
+#endif
+        emitDisplace(*m_newRegisters[gpr]);
+    }
+
</ins><span class="cx">     // You can only take a snapshot if the recovery has not started
</span><span class="cx">     // yet. The only operations that are valid before taking a
</span><span class="cx">     // snapshot are lockGPR(), acquireGPR() and releaseGPR().
</span><span class="lines">@@ -309,6 +324,10 @@
</span><span class="cx">         return reg &gt;= firstOld() &amp;&amp; reg &lt;= lastOld();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool m_didExtendFrame { false };
+
+    void extendFrameIfNeeded();
+
</ins><span class="cx">     // This stores, for each slot in the new frame, information about
</span><span class="cx">     // the recovery for the value that should eventually go into that
</span><span class="cx">     // slot.
</span><span class="lines">@@ -385,13 +404,19 @@
</span><span class="cx">     // We also use this to lock registers temporarily, for instance to
</span><span class="cx">     // ensure that we have at least 2 available registers for loading
</span><span class="cx">     // a pair on 32bits.
</span><del>-    RegisterSet m_lockedRegisters;
</del><ins>+    mutable RegisterSet m_lockedRegisters;
</ins><span class="cx"> 
</span><span class="cx">     // This stores the current recoveries present in registers. A null
</span><span class="cx">     // CachedRecovery means we can trash the current value as we don't
</span><span class="cx">     // care about it. 
</span><span class="cx">     RegisterMap&lt;CachedRecovery*&gt; m_registers;
</span><span class="cx"> 
</span><ins>+#if USE(JSVALUE64)
+    mutable GPRReg m_tagTypeNumber;
+
+    bool tryAcquireTagTypeNumber();
+#endif
+
</ins><span class="cx">     // This stores, for each register, information about the recovery
</span><span class="cx">     // for the value that should eventually go into that register. The
</span><span class="cx">     // only registers that have a target recovery will be callee-save
</span><span class="lines">@@ -421,9 +446,26 @@
</span><span class="cx">                     nonTemp = reg;
</span><span class="cx">             }
</span><span class="cx">         }
</span><ins>+
+#if USE(JSVALUE64)
+        if (!nonTemp &amp;&amp; m_tagTypeNumber != InvalidGPRReg &amp;&amp; check(Reg { m_tagTypeNumber })) {
+            ASSERT(m_lockedRegisters.get(m_tagTypeNumber));
+            m_lockedRegisters.clear(m_tagTypeNumber);
+            nonTemp = Reg { m_tagTypeNumber };
+            m_tagTypeNumber = InvalidGPRReg;
+        }
+#endif
</ins><span class="cx">         return nonTemp;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    GPRReg getFreeTempGPR() const
+    {
+        Reg freeTempGPR { getFreeRegister([this] (Reg reg) { return reg.isGPR() &amp;&amp; !m_newRegisters[reg]; }) };
+        if (!freeTempGPR)
+            return InvalidGPRReg;
+        return freeTempGPR.gpr();
+    }
+
</ins><span class="cx">     GPRReg getFreeGPR() const
</span><span class="cx">     {
</span><span class="cx">         Reg freeGPR { getFreeRegister([] (Reg reg) { return reg.isGPR(); }) };
</span><span class="lines">@@ -519,6 +561,31 @@
</span><span class="cx">             });
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void ensureTempGPR()
+    {
+        if (getFreeTempGPR() != InvalidGPRReg)
+            return;
+
+        if (verbose)
+            dataLog(&quot;  Finding a temp GPR to spill\n&quot;);
+        ensureRegister(
+            [this] (const CachedRecovery&amp; cachedRecovery) {
+                if (cachedRecovery.recovery().isInGPR()) {
+                    return !m_lockedRegisters.get(cachedRecovery.recovery().gpr()) 
+                        &amp;&amp; !m_newRegisters[cachedRecovery.recovery().gpr()];
+                }
+#if USE(JSVALUE32_64)
+                if (cachedRecovery.recovery().technique() == InPair) {
+                    return !m_lockedRegisters.get(cachedRecovery.recovery().tagGPR())
+                        &amp;&amp; !m_lockedRegisters.get(cachedRecovery.recovery().payloadGPR())
+                        &amp;&amp; !m_newRegisters[cachedRecovery.recovery().tagGPR()]
+                        &amp;&amp; !m_newRegisters[cachedRecovery.recovery().payloadGPR()];
+                }
+#endif
+                return false;
+            });
+    }
+
</ins><span class="cx">     void ensureGPR()
</span><span class="cx">     {
</span><span class="cx">         if (getFreeGPR() != InvalidGPRReg)
</span><span class="lines">@@ -573,16 +640,24 @@
</span><span class="cx">     {
</span><span class="cx">         ASSERT(jsValueRegs &amp;&amp; !getNew(jsValueRegs));
</span><span class="cx">         CachedRecovery* cachedRecovery = addCachedRecovery(recovery);
</span><del>-        ASSERT(!cachedRecovery-&gt;wantedJSValueRegs());
-        cachedRecovery-&gt;setWantedJSValueRegs(jsValueRegs);
</del><span class="cx"> #if USE(JSVALUE64)
</span><ins>+        if (cachedRecovery-&gt;wantedJSValueRegs())
+            m_newRegisters[cachedRecovery-&gt;wantedJSValueRegs().gpr()] = nullptr;
</ins><span class="cx">         m_newRegisters[jsValueRegs.gpr()] = cachedRecovery;
</span><span class="cx"> #else
</span><ins>+        if (JSValueRegs oldRegs { cachedRecovery-&gt;wantedJSValueRegs() }) {
+            if (oldRegs.payloadGPR())
+                m_newRegisters[oldRegs.payloadGPR()] = nullptr;
+            if (oldRegs.tagGPR())
+                m_newRegisters[oldRegs.tagGPR()] = nullptr;
+        }
</ins><span class="cx">         if (jsValueRegs.payloadGPR() != InvalidGPRReg)
</span><span class="cx">             m_newRegisters[jsValueRegs.payloadGPR()] = cachedRecovery;
</span><span class="cx">         if (jsValueRegs.tagGPR() != InvalidGPRReg)
</span><span class="cx">             m_newRegisters[jsValueRegs.tagGPR()] = cachedRecovery;
</span><span class="cx"> #endif
</span><ins>+        ASSERT(!cachedRecovery-&gt;wantedJSValueRegs());
+        cachedRecovery-&gt;setWantedJSValueRegs(jsValueRegs);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void addNew(FPRReg fpr, ValueRecovery recovery)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShuffler64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler64.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -87,9 +87,15 @@
</span><span class="cx">             m_jit.zeroExtend32ToPtr(
</span><span class="cx">                 cachedRecovery.recovery().gpr(),
</span><span class="cx">                 cachedRecovery.recovery().gpr());
</span><del>-            // We have to do this the hard way.
-            m_jit.or64(MacroAssembler::TrustedImm64(TagTypeNumber),
-                cachedRecovery.recovery().gpr());
</del><ins>+            m_lockedRegisters.set(cachedRecovery.recovery().gpr());
+            if (tryAcquireTagTypeNumber())
+                m_jit.or64(m_tagTypeNumber, cachedRecovery.recovery().gpr());
+            else {
+                // We have to do this the hard way
+                m_jit.or64(MacroAssembler::TrustedImm64(TagTypeNumber),
+                    cachedRecovery.recovery().gpr());
+            }
+            m_lockedRegisters.clear(cachedRecovery.recovery().gpr());
</ins><span class="cx">             cachedRecovery.setRecovery(
</span><span class="cx">                 ValueRecovery::inGPR(cachedRecovery.recovery().gpr(), DataFormatJS));
</span><span class="cx">             if (verbose)
</span><span class="lines">@@ -141,7 +147,12 @@
</span><span class="cx">             ASSERT(resultGPR != InvalidGPRReg);
</span><span class="cx">             m_jit.purifyNaN(cachedRecovery.recovery().fpr());
</span><span class="cx">             m_jit.moveDoubleTo64(cachedRecovery.recovery().fpr(), resultGPR);
</span><del>-            m_jit.sub64(MacroAssembler::TrustedImm64(TagTypeNumber), resultGPR);
</del><ins>+            m_lockedRegisters.set(resultGPR);
+            if (tryAcquireTagTypeNumber())
+                m_jit.sub64(m_tagTypeNumber, resultGPR);
+            else
+                m_jit.sub64(MacroAssembler::TrustedImm64(TagTypeNumber), resultGPR);
+            m_lockedRegisters.clear(resultGPR);
</ins><span class="cx">             updateRecovery(cachedRecovery, ValueRecovery::inGPR(resultGPR, DataFormatJS));
</span><span class="cx">             if (verbose)
</span><span class="cx">                 dataLog(&quot; into &quot;, cachedRecovery.recovery(), &quot;\n&quot;);
</span><span class="lines">@@ -337,7 +348,22 @@
</span><span class="cx"> 
</span><span class="cx">     ASSERT(m_registers[wantedReg] == &amp;cachedRecovery);
</span><span class="cx"> }
</span><ins>+    
+bool CallFrameShuffler::tryAcquireTagTypeNumber()
+{
+    if (m_tagTypeNumber != InvalidGPRReg)
+        return true;
</ins><span class="cx"> 
</span><ins>+    m_tagTypeNumber = getFreeGPR();
+
+    if (m_tagTypeNumber == InvalidGPRReg)
+        return false;
+
+    m_lockedRegisters.set(m_tagTypeNumber);
+    m_jit.move(MacroAssembler::TrustedImm64(TagTypeNumber), m_tagTypeNumber);
+    return true;
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(JIT) &amp;&amp; USE(JSVALUE64)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCallcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCall.cpp (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCall.cpp        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/jit/JITCall.cpp        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -193,6 +193,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (opcodeID == op_tail_call) {
</span><span class="cx">         CallFrameShuffleData shuffleData;
</span><ins>+        shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
</ins><span class="cx">         shuffleData.numLocals =
</span><span class="cx">             instruction[4].u.operand - sizeof(CallerFrameAndPC) / sizeof(Register);
</span><span class="cx">         shuffleData.args.resize(instruction[3].u.operand);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRegh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/Reg.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/Reg.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/jit/Reg.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -55,6 +55,11 @@
</span><span class="cx">         : m_index(invalid())
</span><span class="cx">     {
</span><span class="cx">     }
</span><ins>+
+    Reg(WTF::HashTableDeletedValueType)
+        : m_index(deleted())
+    {
+    }
</ins><span class="cx">     
</span><span class="cx">     Reg(MacroAssembler::RegisterID reg)
</span><span class="cx">         : m_index(MacroAssembler::registerIndex(reg))
</span><span class="lines">@@ -102,6 +107,8 @@
</span><span class="cx">     bool isSet() const { return m_index != invalid(); }
</span><span class="cx">     bool operator!() const { return !isSet(); }
</span><span class="cx">     explicit operator bool() const { return isSet(); }
</span><ins>+
+    bool isHashTableDeletedValue() const { return m_index == deleted(); }
</ins><span class="cx">     
</span><span class="cx">     bool isGPR() const
</span><span class="cx">     {
</span><span class="lines">@@ -165,12 +172,34 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     static uint8_t invalid() { return 0xff; }
</span><ins>+
+    static uint8_t deleted() { return 0xfe; }
</ins><span class="cx">     
</span><span class="cx">     uint8_t m_index;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+struct RegHash {
+    static unsigned hash(const Reg&amp; key) { return key.hash(); }
+    static bool equal(const Reg&amp; a, const Reg&amp; b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><ins>+namespace WTF {
+
+template&lt;typename T&gt; struct DefaultHash;
+template&lt;&gt; struct DefaultHash&lt;JSC::Reg&gt; {
+    typedef JSC::RegHash Hash;
+};
+
+template&lt;typename T&gt; struct HashTraits;
+template&lt;&gt; struct HashTraits&lt;JSC::Reg&gt; : SimpleClassHashTraits&lt;JSC::Reg&gt; {
+    static const bool emptyValueIsZero = false;
+ };
+
+} // namespace WTF
+
</ins><span class="cx"> #endif // ENABLE(JIT)
</span><span class="cx"> 
</span><span class="cx"> #endif // Reg_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -753,7 +753,7 @@
</span><span class="cx">     addi StackAlignment - 1 + CallFrameHeaderSize, temp2
</span><span class="cx">     andi ~StackAlignmentMask, temp2
</span><span class="cx"> 
</span><del>-    if ARM or SH4 or ARM64 or C_LOOP or MIPS
</del><ins>+    if ARM or ARMv7_TRADITIONAL or ARMv7 or SH4 or ARM64 or C_LOOP or MIPS
</ins><span class="cx">         addp 2 * PtrSize, sp
</span><span class="cx">         subi 2 * PtrSize, temp2
</span><span class="cx">         loadp PtrSize[cfr], lr
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -128,7 +128,7 @@
</span><span class="cx">     v(bool, forceProfilerBytecodeGeneration, false, nullptr) \
</span><span class="cx">     \
</span><span class="cx">     v(bool, enableFunctionDotArguments, true, nullptr) \
</span><del>-    v(bool, enableTailCalls, false, nullptr) \
</del><ins>+    v(bool, enableTailCalls, true, nullptr) \
</ins><span class="cx">     \
</span><span class="cx">     /* showDisassembly implies showDFGDisassembly. */ \
</span><span class="cx">     v(bool, showDisassembly, false, &quot;dumps disassembly of all JIT compiled code upon compilation&quot;) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestses6yaml"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/es6.yaml (190369 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/es6.yaml        2015-09-30 22:11:25 UTC (rev 190369)
+++ trunk/Source/JavaScriptCore/tests/es6.yaml        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -877,9 +877,9 @@
</span><span class="cx"> - path: es6/Promise_Promise[Symbol.species].js
</span><span class="cx">   cmd: runES6 :fail
</span><span class="cx"> - path: es6/proper_tail_calls_tail_call_optimisation_direct_recursion.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/proper_tail_calls_tail_call_optimisation_mutual_recursion.js
</span><del>-  cmd: runES6 :fail
</del><ins>+  cmd: runES6 :normal
</ins><span class="cx"> - path: es6/prototype_of_bound_functions_arrow_functions.js
</span><span class="cx">   cmd: runES6 :fail
</span><span class="cx"> - path: es6/prototype_of_bound_functions_basic_functions.js
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressdfgtailcallsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+(function nonInlinedTailCall() {
+    function callee() { if (callee.caller != nonInlinedTailCall) throw new Error(); }
+    noInline(callee);
+
+    function caller() { &quot;use strict&quot;; return callee(); }
+
+    for (var i = 0; i &lt; 10000; ++i)
+        caller();
+
+    function loop(n) { &quot;use strict&quot;; if (n &gt; 0) return loop(n - 1); }
+    noInline(loop);
+
+    loop(1000000);
+})();
+
+(function inlinedTailCall() {
+    function callee() { if (callee.caller != inlinedTailCall) throw new Error(); }
+    function caller() { &quot;use strict&quot;; return callee(); }
+
+    for (var i = 0; i &lt; 10000; ++i)
+        caller();
+
+    function loop(n) { &quot;use strict&quot;; if (n &gt; 0) return loop(n - 1); }
+
+    loop(1000000);
+})();
+
+(function nonInlinedEmulatedTailCall() {
+    function emulator() { caller(); }
+    function callee() { if (callee.caller != emulator) throw new Error(); }
+    noInline(callee);
+    function caller() { &quot;use strict&quot;; return callee(); }
+
+    for (var i = 0; i &lt; 10000; ++i)
+        emulator();
+
+    function pad(n) { &quot;use strict&quot;; return loop(n); }
+    function loop(n) { &quot;use strict&quot;; if (n &gt; 0) return pad(n - 1); }
+    noInline(loop);
+
+    loop(1000000);
+})();
+
+(function inlinedEmulatedTailCall() {
+    function emulator() { caller(); }
+    function callee() { if (callee.caller != emulator) throw new Error(); }
+    function caller() { &quot;use strict&quot;; return callee(); }
+
+    for (var i = 0; i &lt; 10000; ++i)
+        emulator();
+
+    function pad(n) { &quot;use strict&quot;; return loop(n); }
+    function loop(n) { &quot;use strict&quot;; if (n &gt; 0) return pad(n - 1); }
+
+    loop(1000000);
+})();
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressmutualtailcallnostackoverflowjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,71 @@
</span><ins>+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+function sloppyCountdown(n) {
+    function even(n) {
+        if (n == 0)
+            return n;
+        return odd(n - 1);
+    }
+
+    function odd(n) {
+        if (n == 1)
+            return n;
+        return even(n - 1);
+    }
+
+    if (n % 2 === 0)
+        return even(n);
+    else
+        return odd(n);
+}
+
+function strictCountdown(n) {
+    &quot;use strict&quot;;
+
+    function even(n) {
+        if (n == 0)
+            return n;
+        return odd(n - 1);
+    }
+
+    function odd(n) {
+        if (n == 1)
+            return n;
+        return even(n - 1);
+    }
+
+    if (n % 2 === 0)
+        return even(n);
+    else
+        return odd(n);
+}
+
+shouldThrow(function () { sloppyCountdown(100000); }, &quot;RangeError: Maximum call stack size exceeded.&quot;);
+strictCountdown(100000);
+
+// Parity alterning
+function odd(n) {
+    &quot;use strict&quot;;
+    if (n &gt; 0)
+        return even(n, 0);
+}
+
+function even(n) {
+    &quot;use strict&quot;;
+    return odd(n - 1);
+}
+
+odd(100000);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstailcallnostackoverflowjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,45 @@
</span><ins>+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+function sloppyLoop(n) {
+    if (n &gt; 0)
+        return sloppyLoop(n - 1);
+}
+
+function strictLoop(n) {
+    &quot;use strict&quot;;
+    if (n &gt; 0)
+        return strictLoop(n - 1);
+}
+
+// We have two of these so that we can test different stack alignments
+function strictLoopArityFixup1(n, dummy) {
+    &quot;use strict&quot;;
+    if (n &gt; 0)
+        return strictLoopArityFixup1(n - 1);
+}
+
+function strictLoopArityFixup2(n, dummy1, dummy2) {
+    &quot;use strict&quot;;
+    if (n &gt; 0)
+        return strictLoopArityFixup2(n - 1);
+}
+
+shouldThrow(function () { sloppyLoop(100000); }, 'RangeError: Maximum call stack size exceeded.');
+
+// These should not throw
+strictLoop(100000);
+strictLoopArityFixup1(1000000);
+strictLoopArityFixup2(1000000);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstailcallrecognizejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tail-call-recognize.js (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tail-call-recognize.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tail-call-recognize.js        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,178 @@
</span><ins>+function callerMustBeRun() {
+    if (!Object.is(callerMustBeRun.caller, runTests))
+        throw Error(&quot;Wrong caller, expected run but got &quot;, callerMustBeRun.caller);
+}
+
+function callerMustBeStrict() {
+    var errorThrown = false;
+    try {
+        callerMustBeStrict.caller;
+    } catch (e) {
+        errorThrown = true;
+    }
+    if (!errorThrown)
+        throw Error(&quot;Wrong caller, expected strict caller but got &quot;, callerMustBeStrict.caller);
+}
+
+function runTests() {
+    // Statement tests
+    (function simpleTailCall() {
+        &quot;use strict&quot;;
+        return callerMustBeRun();
+    })();
+
+    (function noTailCallInTry() {
+        &quot;use strict&quot;;
+        try {
+            return callerMustBeStrict();
+        } catch (e) {
+            throw e;
+        }
+    })();
+
+    (function tailCallInCatch() {
+        &quot;use strict&quot;;
+        try { } catch (e) { return callerMustBeRun(); }
+    })();
+
+    (function tailCallInFinally() {
+        &quot;use strict&quot;;
+        try { } finally { return callerMustBeRun(); }
+    })();
+
+    (function tailCallInFinallyWithCatch() {
+        &quot;use strict&quot;;
+        try { } catch (e) { } finally { return callerMustBeRun(); }
+    })();
+
+    (function tailCallInFinallyWithCatchTaken() {
+        &quot;use strict&quot;;
+        try { throw null; } catch (e) { } finally { return callerMustBeRun(); }
+    })();
+
+    (function noTailCallInCatchIfFinally() {
+        &quot;use strict&quot;;
+        try { throw null; } catch (e) { return callerMustBeStrict(); } finally { }
+    })();
+
+    (function tailCallInFor() {
+        &quot;use strict&quot;;
+        for (var i = 0; i &lt; 10; ++i)
+            return callerMustBeRun();
+    })();
+
+    (function tailCallInWhile() {
+        &quot;use strict&quot;;
+        while (true)
+            return callerMustBeRun();
+    })();
+
+    (function tailCallInDoWhile() {
+        &quot;use strict&quot;;
+        do
+            return callerMustBeRun();
+        while (true);
+    })();
+
+    (function noTailCallInForIn() {
+        &quot;use strict&quot;;
+        for (var x in [1, 2])
+            return callerMustBeStrict();
+    })();
+
+    (function noTailCallInForOf() {
+        &quot;use strict&quot;;
+        for (var x of [1, 2])
+            return callerMustBeStrict();
+    })();
+
+    (function tailCallInIf() {
+        &quot;use strict&quot;;
+        if (true)
+            return callerMustBeRun();
+    })();
+
+    (function tailCallInElse() {
+        &quot;use strict&quot;;
+        if (false) throw new Error(&quot;WTF&quot;);
+        else return callerMustBeRun();
+    })();
+
+    (function tailCallInSwitchCase() {
+        &quot;use strict&quot;;
+        switch (0) {
+        case 0: return callerMustBeRun();
+        }
+    })();
+
+    (function tailCallInSwitchDefault() {
+        &quot;use strict&quot;;
+        switch (0) {
+        default: return callerMustBeRun();
+        }
+    })();
+
+    (function tailCallWithLabel() {
+        &quot;use strict&quot;;
+        dummy: return callerMustBeRun();
+    })();
+
+    // Expression tests, we don't enumerate all the cases where there
+    // *shouldn't* be a tail call
+
+    (function tailCallComma() {
+        &quot;use strict&quot;;
+        return callerMustBeStrict(), callerMustBeRun();
+    })();
+
+    (function tailCallTernaryLeft() {
+        &quot;use strict&quot;;
+        return true ? callerMustBeRun() : unreachable();
+    })();
+
+    (function tailCallTernaryRight() {
+        &quot;use strict&quot;;
+        return false ? unreachable() : callerMustBeRun();
+    })();
+
+    (function tailCallLogicalAnd() {
+        &quot;use strict&quot;;
+        return true &amp;&amp; callerMustBeRun();
+    })();
+
+    (function tailCallLogicalOr() {
+        &quot;use strict&quot;;
+        return false || callerMustBeRun();
+    })();
+
+    (function memberTailCall() {
+        &quot;use strict&quot;;
+        return { f: callerMustBeRun }.f();
+    })();
+
+    (function bindTailCall() {
+        &quot;use strict&quot;;
+        return callerMustBeRun.bind()();
+    })();
+
+    // Function.prototype tests
+
+    (function applyTailCall() {
+        &quot;use strict&quot;;
+        return callerMustBeRun.apply();
+    })();
+
+    (function callTailCall() {
+        &quot;use strict&quot;;
+        return callerMustBeRun.call();
+    })();
+
+    // No tail call for constructors
+    (function noTailConstruct() {
+        &quot;use strict&quot;;
+        return new callerMustBeStrict();
+    })();
+}
+
+for (var i = 0; i &lt; 10000; ++i)
+    runTests();
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstailcallvarargsnostackoverflowjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+function sloppyLoop(n) {
+    if (n &gt; 0)
+        return sloppyLoop(...[n - 1]);
+}
+
+function strictLoop(n) {
+    &quot;use strict&quot;;
+    if (n &gt; 0)
+        return strictLoop(...[n - 1]);
+}
+
+shouldThrow(function () { sloppyLoop(100000); }, 'RangeError: Maximum call stack size exceeded.');
+strictLoop(100000);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresstailcallsdontoverwritelivestackjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/tail-calls-dont-overwrite-live-stack.js (0 => 190370)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/tail-calls-dont-overwrite-live-stack.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/tail-calls-dont-overwrite-live-stack.js        2015-09-30 22:28:08 UTC (rev 190370)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+&quot;use strict&quot;;
+
+function tail(a, b) { }
+noInline(tail);
+
+var obj = {
+    method: function (x) {
+        return tail(x, x);
+    },
+
+    get fromNative() { return tail(0, 0); }
+};
+noInline(obj.method);
+
+function getThis(x) { return this; }
+noInline(getThis);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var that = getThis(obj.method(42));
+
+    if (!Object.is(that, undefined))
+        throw new Error(&quot;Wrong 'this' value in call, expected undefined but got &quot; + that);
+
+    that = getThis(obj.method(...[42]));
+    if (!Object.is(that, undefined))
+        throw new Error(&quot;Wrong 'this' value in varargs call, expected undefined but got &quot; + that);
+
+    if (!Object.is(obj.fromNative, undefined))
+        throw new Error(&quot;Wrong 'fromNative' value, expected undefined but got &quot; + obj.fromNative);
+}
</ins></span></pre>
</div>
</div>

</body>
</html>