<!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>[187166] branches/jsc-tailcall</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/187166">187166</a></dd>
<dt>Author</dt> <dd>basile_clement@apple.com</dd>
<dt>Date</dt> <dd>2015-07-22 10:56:22 -0700 (Wed, 22 Jul 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>jsc-tailcall: Add new opcodes for tail calls
https://bugs.webkit.org/show_bug.cgi?id=146484

Reviewed by Michael Saboff.

Source/JavaScriptCore:

This patch introduces two new opcodes, op_tail_call and
op_tail_call_varargs, to perform tail calls, and implements them in the
LLInt and baseline JIT. Their use prevents DFG and FTL compilation for
now. They are currently implemented by sliding the call frame and
masquerading as our own caller right before performing an actual call.

This required to change the operationLink family of operation to return
a SlowPathReturnType instead of a char* in order to distinguish between
exception cases (must not trash the caller frame) and actual call case
(must trash the caller frame).

This is also a semantics change, since the Function.caller property is
now leaking tail calls. Since tail calls are only used in strict mode,
which poisons this property, the only way of seeing this semantics
change is when a sloppy function calls a strict function that then
tail-calls a sloppy function. Previously, the second sloppy function's
caller would have been the strict function (i.e. raises a TypeError
when the .caller attribute is accessed), while it is now the first
sloppy function.

Finally, this patch adds a couple of tests to check that tail calls run
in constant stack space, as well as tests checking that tail calls are
recognized correctly. Those tests use the handy aforementioned leaking
of tail calls through Function.caller. Moreover, this patch also adds
(as per the spec) statements following a label as tail positions, and
removes the body of a with statement (in disagreement with the spec) as
a tail position since with statements are not allowed in strict mode.

* assembler/AbstractMacroAssembler.h:
* assembler/MacroAssemblerARM.h:
(JSC::MacroAssemblerARM::nearTailCall):
(JSC::MacroAssemblerARM::linkCall):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::nearTailCall):
(JSC::MacroAssemblerARM64::linkCall):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::nearTailCall):
(JSC::MacroAssemblerARMv7::linkCall):
* assembler/MacroAssemblerMIPS.h:
(JSC::MacroAssemblerMIPS::nearTailCall):
(JSC::MacroAssemblerMIPS::linkCall):
* assembler/MacroAssemblerSH4.h:
(JSC::MacroAssemblerSH4::nearTailCall):
(JSC::MacroAssemblerSH4::linkCall):
* assembler/MacroAssemblerX86.h:
(JSC::MacroAssemblerX86::linkCall):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::nearTailCall):
* assembler/MacroAssemblerX86_64.h:
(JSC::MacroAssemblerX86_64::linkCall):
* assembler/RepatchBuffer.h:
(JSC::RepatchBuffer::relink):
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CallLinkInfo.h:
(JSC::CallLinkInfo::callTypeFor):
(JSC::CallLinkInfo::isVarargsCallType):
(JSC::CallLinkInfo::isTailCallType):
(JSC::CallLinkInfo::setSlowStub):
(JSC::CallLinkInfo::clearSlowStub):
(JSC::CallLinkInfo::slowStub):
* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::computeFromLLInt):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitTailCall):
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitTailCallVarargs):
* bytecompiler/NodesCodegen.cpp:
(JSC::LabelNode::emitBytecode):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* ftl/FTLJSCallBase.cpp:
(JSC::FTL::JSCallBase::link):
* interpreter/Interpreter.h:
(JSC::Interpreter::isCallBytecode):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITCall.cpp:
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):
(JSC::JIT::emit_op_tail_call):
(JSC::JIT::emit_op_tail_call_varargs):
(JSC::JIT::emitSlow_op_tail_call):
(JSC::JIT::emitSlow_op_tail_call_varargs):
* jit/JITCall32_64.cpp:
(JSC::JIT::emitSlow_op_tail_call):
(JSC::JIT::emitSlow_op_tail_call_varargs):
(JSC::JIT::emit_op_tail_call):
(JSC::JIT::emit_op_tail_call_varargs):
(JSC::JIT::compileOpCall):
(JSC::JIT::compileOpCallSlowCase):
* jit/JITInlines.h:
(JSC::JIT::emitNakedTailCall):
* jit/JITOperations.cpp:
* jit/JITOperations.h:
(JSC::operationLinkFor):
(JSC::operationVirtualFor):
(JSC::operationLinkPolymorphicCallFor):
* jit/Repatch.cpp:
(JSC::generateByIdStub):
(JSC::linkSlowFor):
(JSC::linkFor):
(JSC::revertCall):
(JSC::unlinkFor):
(JSC::linkVirtualFor):
(JSC::linkPolymorphicCall):
* jit/ThunkGenerators.cpp:
(JSC::slowPathFor):
(JSC::linkThunkFor):
(JSC::linkCallThunk):
(JSC::linkCallThunkGenerator):
(JSC::linkConstructThunkGenerator):
(JSC::linkCallThatPreservesRegsThunkGenerator):
(JSC::linkConstructThatPreservesRegsThunkGenerator):
(JSC::linkPolymorphicCallThunkFor):
(JSC::linkPolymorphicCallThunk):
(JSC::linkPolymorphicCallThunkGenerator):
(JSC::linkPolymorphicCallThatPreservesRegsThunkGenerator):
(JSC::virtualThunkFor):
(JSC::virtualThunk):
(JSC::virtualCallThunkGenerator):
(JSC::virtualConstructThunkGenerator):
(JSC::virtualCallThatPreservesRegsThunkGenerator):
(JSC::virtualConstructThatPreservesRegsThunkGenerator):
(JSC::unreachableGenerator):
(JSC::prepareForTailCall):
* jit/ThunkGenerators.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* tests/stress/mutual-tail-call-no-stack-overflow.js: Added.
(shouldThrow):
(sloppyCountdown.even):
(sloppyCountdown.odd):
(strictCountdown.even):
(strictCountdown.odd):
(strictCountdown):
* tests/stress/tail-call-no-stack-overflow.js: Added.
(shouldThrow):
(strictLoop):
* tests/stress/tail-call-recognize.js: Added.
(callerMustBeRun):
(callerMustBeStrict):
(runTests):
* tests/stress/tail-call-varargs-no-stack-overflow.js: Added.
(shouldThrow):
(strictLoop):

LayoutTests:

* js/caller-property-expected.txt:
* js/script-tests/caller-property.js: Function.caller has had semantics change: it nows leaks tail calls
(strictCaller):
(strictTailCaller):
* js/script-tests/class-syntax-super.js:
* js/script-tests/dfg-strict-mode-to-this.js: Temporarily disabled since it has a tail call and requires DFG</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesjsctailcallLayoutTestsChangeLog">branches/jsc-tailcall/LayoutTests/ChangeLog</a></li>
<li><a href="#branchesjsctailcallLayoutTestsjscallerpropertyexpectedtxt">branches/jsc-tailcall/LayoutTests/js/caller-property-expected.txt</a></li>
<li><a href="#branchesjsctailcallLayoutTestsjsscripttestscallerpropertyjs">branches/jsc-tailcall/LayoutTests/js/script-tests/caller-property.js</a></li>
<li><a href="#branchesjsctailcallLayoutTestsjsscripttestsclasssyntaxsuperjs">branches/jsc-tailcall/LayoutTests/js/script-tests/class-syntax-super.js</a></li>
<li><a href="#branchesjsctailcallLayoutTestsjsscripttestsdfgstrictmodetothisjs">branches/jsc-tailcall/LayoutTests/js/script-tests/dfg-strict-mode-to-this.js</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreChangeLog">branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerAbstractMacroAssemblerh">branches/jsc-tailcall/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerARMh">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerARM64h">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerARMv7h">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerMIPSh">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerSH4h">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerX86h">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerX86_64h">branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreassemblerRepatchBufferh">branches/jsc-tailcall/Source/JavaScriptCore/assembler/RepatchBuffer.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeBytecodeListjson">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeList.json</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeBytecodeUseDefh">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeUseDef.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeCallLinkInfoh">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkInfo.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeCallLinkStatuscpp">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeCodeBlockcpp">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecompilerNodesCodegencpp">branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGJITCompilercpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreftlFTLJSCallBasecpp">branches/jsc-tailcall/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreinterpreterInterpreterh">branches/jsc-tailcall/Source/JavaScriptCore/interpreter/Interpreter.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitJITcpp">branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitJITh">branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitJITCallcpp">branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitJITCall32_64cpp">branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall32_64.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitJITInlinesh">branches/jsc-tailcall/Source/JavaScriptCore/jit/JITInlines.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitJITOperationscpp">branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitJITOperationsh">branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitRepatchcpp">branches/jsc-tailcall/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitThunkGeneratorscpp">branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitThunkGeneratorsh">branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorellintLowLevelInterpreterasm">branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter.asm</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorellintLowLevelInterpreter32_64asm">branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorellintLowLevelInterpreter64asm">branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesjsctailcallSourceJavaScriptCoretestsstressmutualtailcallnostackoverflowjs">branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoretestsstresstailcallnostackoverflowjs">branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoretestsstresstailcallrecognizejs">branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-recognize.js</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoretestsstresstailcalltriggerjs">branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-trigger.js</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoretestsstresstailcallvarargsnostackoverflowjs">branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesjsctailcallLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/LayoutTests/ChangeLog (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/LayoutTests/ChangeLog        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/LayoutTests/ChangeLog        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2015-07-21  Basile Clement  &lt;basile_clement@apple.com&gt;
+
+        jsc-tailcall: Add new opcodes for tail calls
+        https://bugs.webkit.org/show_bug.cgi?id=146484
+
+        Reviewed by Michael Saboff.
+
+        * js/caller-property-expected.txt:
+        * js/script-tests/caller-property.js: Function.caller has had semantics change: it nows leaks tail calls
+        (strictCaller):
+        (strictTailCaller):
+        * js/script-tests/class-syntax-super.js: 
+        * js/script-tests/dfg-strict-mode-to-this.js: Temporarily disabled since it has a tail call and requires DFG
+
</ins><span class="cx"> 2015-07-09  Michael Saboff  &lt;msaboff@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION (r180248): Repro Crash: com.apple.WebKit.WebContent at com.apple.JavaScriptCore: JSC::createRangeError + 20
</span></span></pre></div>
<a id="branchesjsctailcallLayoutTestsjscallerpropertyexpectedtxt"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/LayoutTests/js/caller-property-expected.txt (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/LayoutTests/js/caller-property-expected.txt        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/LayoutTests/js/caller-property-expected.txt        2015-07-22 17:56:22 UTC (rev 187166)
</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="branchesjsctailcallLayoutTestsjsscripttestscallerpropertyjs"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/LayoutTests/js/script-tests/caller-property.js (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/LayoutTests/js/script-tests/caller-property.js        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/LayoutTests/js/script-tests/caller-property.js        2015-07-22 17:56:22 UTC (rev 187166)
</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="branchesjsctailcallLayoutTestsjsscripttestsclasssyntaxsuperjs"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/LayoutTests/js/script-tests/class-syntax-super.js (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/LayoutTests/js/script-tests/class-syntax-super.js        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/LayoutTests/js/script-tests/class-syntax-super.js        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1,4 +1,3 @@
</span><del>-
</del><span class="cx"> description('Tests for ES6 class syntax &quot;super&quot;');
</span><span class="cx"> 
</span><span class="cx"> var baseMethodValue = {};
</span></span></pre></div>
<a id="branchesjsctailcallLayoutTestsjsscripttestsdfgstrictmodetothisjs"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/LayoutTests/js/script-tests/dfg-strict-mode-to-this.js (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/LayoutTests/js/script-tests/dfg-strict-mode-to-this.js        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/LayoutTests/js/script-tests/dfg-strict-mode-to-this.js        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1,3 +1,5 @@
</span><ins>+//@ skip
+
</ins><span class="cx"> description(&quot;Tests that doing to-this conversion in strict mode doesn't cause us to believe that if the input is an object then the output is also an object.&quot;);
</span><span class="cx"> 
</span><span class="cx"> function thingy() {
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1,3 +1,165 @@
</span><ins>+2015-07-21  Basile Clement  &lt;basile_clement@apple.com&gt;
+
+        jsc-tailcall: Add new opcodes for tail calls
+        https://bugs.webkit.org/show_bug.cgi?id=146484
+
+        Reviewed by Michael Saboff.
+
+        This patch introduces two new opcodes, op_tail_call and
+        op_tail_call_varargs, to perform tail calls, and implements them in the
+        LLInt and baseline JIT. Their use prevents DFG and FTL compilation for
+        now. They are currently implemented by sliding the call frame and
+        masquerading as our own caller right before performing an actual call.
+
+        This required to change the operationLink family of operation to return
+        a SlowPathReturnType instead of a char* in order to distinguish between
+        exception cases (must not trash the caller frame) and actual call case
+        (must trash the caller frame).
+
+        This is also a semantics change, since the Function.caller property is
+        now leaking tail calls. Since tail calls are only used in strict mode,
+        which poisons this property, the only way of seeing this semantics
+        change is when a sloppy function calls a strict function that then
+        tail-calls a sloppy function. Previously, the second sloppy function's
+        caller would have been the strict function (i.e. raises a TypeError
+        when the .caller attribute is accessed), while it is now the first
+        sloppy function.
+
+        Finally, this patch adds a couple of tests to check that tail calls run
+        in constant stack space, as well as tests checking that tail calls are
+        recognized correctly. Those tests use the handy aforementioned leaking
+        of tail calls through Function.caller. Moreover, this patch also adds
+        (as per the spec) statements following a label as tail positions, and
+        removes the body of a with statement (in disagreement with the spec) as
+        a tail position since with statements are not allowed in strict mode.
+
+        * assembler/AbstractMacroAssembler.h:
+        * assembler/MacroAssemblerARM.h:
+        (JSC::MacroAssemblerARM::nearTailCall):
+        (JSC::MacroAssemblerARM::linkCall):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::nearTailCall):
+        (JSC::MacroAssemblerARM64::linkCall):
+        * assembler/MacroAssemblerARMv7.h:
+        (JSC::MacroAssemblerARMv7::nearTailCall):
+        (JSC::MacroAssemblerARMv7::linkCall):
+        * assembler/MacroAssemblerMIPS.h:
+        (JSC::MacroAssemblerMIPS::nearTailCall):
+        (JSC::MacroAssemblerMIPS::linkCall):
+        * assembler/MacroAssemblerSH4.h:
+        (JSC::MacroAssemblerSH4::nearTailCall):
+        (JSC::MacroAssemblerSH4::linkCall):
+        * assembler/MacroAssemblerX86.h:
+        (JSC::MacroAssemblerX86::linkCall):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::nearTailCall):
+        * assembler/MacroAssemblerX86_64.h:
+        (JSC::MacroAssemblerX86_64::linkCall):
+        * assembler/RepatchBuffer.h:
+        (JSC::RepatchBuffer::relink):
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CallLinkInfo.h:
+        (JSC::CallLinkInfo::callTypeFor):
+        (JSC::CallLinkInfo::isVarargsCallType):
+        (JSC::CallLinkInfo::isTailCallType):
+        (JSC::CallLinkInfo::setSlowStub):
+        (JSC::CallLinkInfo::clearSlowStub):
+        (JSC::CallLinkInfo::slowStub):
+        * bytecode/CallLinkStatus.cpp:
+        (JSC::CallLinkStatus::computeFromLLInt):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        (JSC::CodeBlock::CodeBlock):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitTailCall):
+        (JSC::BytecodeGenerator::emitCall):
+        (JSC::BytecodeGenerator::emitTailCallVarargs):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::LabelNode::emitBytecode):
+        * dfg/DFGJITCompiler.cpp:
+        (JSC::DFG::JITCompiler::link):
+        * ftl/FTLJSCallBase.cpp:
+        (JSC::FTL::JSCallBase::link):
+        * interpreter/Interpreter.h:
+        (JSC::Interpreter::isCallBytecode):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JIT.h:
+        * jit/JITCall.cpp:
+        (JSC::JIT::compileOpCall):
+        (JSC::JIT::compileOpCallSlowCase):
+        (JSC::JIT::emit_op_tail_call):
+        (JSC::JIT::emit_op_tail_call_varargs):
+        (JSC::JIT::emitSlow_op_tail_call):
+        (JSC::JIT::emitSlow_op_tail_call_varargs):
+        * jit/JITCall32_64.cpp:
+        (JSC::JIT::emitSlow_op_tail_call):
+        (JSC::JIT::emitSlow_op_tail_call_varargs):
+        (JSC::JIT::emit_op_tail_call):
+        (JSC::JIT::emit_op_tail_call_varargs):
+        (JSC::JIT::compileOpCall):
+        (JSC::JIT::compileOpCallSlowCase):
+        * jit/JITInlines.h:
+        (JSC::JIT::emitNakedTailCall):
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        (JSC::operationLinkFor):
+        (JSC::operationVirtualFor):
+        (JSC::operationLinkPolymorphicCallFor):
+        * jit/Repatch.cpp:
+        (JSC::generateByIdStub):
+        (JSC::linkSlowFor):
+        (JSC::linkFor):
+        (JSC::revertCall):
+        (JSC::unlinkFor):
+        (JSC::linkVirtualFor):
+        (JSC::linkPolymorphicCall):
+        * jit/ThunkGenerators.cpp:
+        (JSC::slowPathFor):
+        (JSC::linkThunkFor):
+        (JSC::linkCallThunk):
+        (JSC::linkCallThunkGenerator):
+        (JSC::linkConstructThunkGenerator):
+        (JSC::linkCallThatPreservesRegsThunkGenerator):
+        (JSC::linkConstructThatPreservesRegsThunkGenerator):
+        (JSC::linkPolymorphicCallThunkFor):
+        (JSC::linkPolymorphicCallThunk):
+        (JSC::linkPolymorphicCallThunkGenerator):
+        (JSC::linkPolymorphicCallThatPreservesRegsThunkGenerator):
+        (JSC::virtualThunkFor):
+        (JSC::virtualThunk):
+        (JSC::virtualCallThunkGenerator):
+        (JSC::virtualConstructThunkGenerator):
+        (JSC::virtualCallThatPreservesRegsThunkGenerator):
+        (JSC::virtualConstructThatPreservesRegsThunkGenerator):
+        (JSC::unreachableGenerator):
+        (JSC::prepareForTailCall):
+        * jit/ThunkGenerators.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * tests/stress/mutual-tail-call-no-stack-overflow.js: Added.
+        (shouldThrow):
+        (sloppyCountdown.even):
+        (sloppyCountdown.odd):
+        (strictCountdown.even):
+        (strictCountdown.odd):
+        (strictCountdown):
+        * tests/stress/tail-call-no-stack-overflow.js: Added.
+        (shouldThrow):
+        (strictLoop):
+        * tests/stress/tail-call-recognize.js: Added.
+        (callerMustBeRun):
+        (callerMustBeStrict):
+        (runTests):
+        * tests/stress/tail-call-varargs-no-stack-overflow.js: Added.
+        (shouldThrow):
+        (strictLoop):
+
</ins><span class="cx"> 2015-07-15  Basile Clement  &lt;basile_clement@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         jsc-tailcall: Change sizeof(Register) to sizeof(void*)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerAbstractMacroAssemblerh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/AbstractMacroAssembler.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -507,7 +507,9 @@
</span><span class="cx">             None = 0x0,
</span><span class="cx">             Linkable = 0x1,
</span><span class="cx">             Near = 0x2,
</span><ins>+            Tail = 0x4,
</ins><span class="cx">             LinkableNear = 0x3,
</span><ins>+            LinkableNearTail = 0x7,
</ins><span class="cx">         };
</span><span class="cx"> 
</span><span class="cx">         Call()
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerARMh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -904,6 +904,11 @@
</span><span class="cx">         return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Call nearTailCall()
+    {
+        return Call(m_assembler.jmp(), Call::LinkableNearTail);
+    }
+
</ins><span class="cx">     Call call(RegisterID target)
</span><span class="cx">     {
</span><span class="cx">         return Call(m_assembler.blx(target), Call::None);
</span><span class="lines">@@ -1483,7 +1488,10 @@
</span><span class="cx"> 
</span><span class="cx">     static void linkCall(void* code, Call call, FunctionPtr function)
</span><span class="cx">     {
</span><del>-        ARMAssembler::linkCall(code, call.m_label, function.value());
</del><ins>+        if (call.isFlagSet(Call::Tail))
+            ARMAssembler::linkJump(code, call.m_label, function.value());
+        else
+            ARMAssembler::linkCall(code, call.m_label, function.value());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -2204,6 +2204,13 @@
</span><span class="cx">         return Call(m_assembler.label(), Call::LinkableNear);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE Call nearTailCall()
+    {
+        AssemblerLabel label = m_assembler.label();
+        m_assembler.b();
+        return Call(label, Call::LinkableNearTail);
+    }
+
</ins><span class="cx">     ALWAYS_INLINE void ret()
</span><span class="cx">     {
</span><span class="cx">         m_assembler.ret();
</span><span class="lines">@@ -2856,10 +2863,12 @@
</span><span class="cx"> 
</span><span class="cx">     static void linkCall(void* code, Call call, FunctionPtr function)
</span><span class="cx">     {
</span><del>-        if (call.isFlagSet(Call::Near))
</del><ins>+        if (!call.isFlagSet(Call::Near))
+            ARM64Assembler::linkPointer(code, call.m_label.labelAtOffset(REPATCH_OFFSET_CALL_TO_POINTER), function.value());
+        else if (call.isFlagSet(Call::Tail))
+            ARM64Assembler::linkJump(code, call.m_label, function.value());
+        else
</ins><span class="cx">             ARM64Assembler::linkCall(code, call.m_label, function.value());
</span><del>-        else
-            ARM64Assembler::linkPointer(code, call.m_label.labelAtOffset(REPATCH_OFFSET_CALL_TO_POINTER), function.value());
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerARMv7h"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1677,6 +1677,12 @@
</span><span class="cx">         return Call(m_assembler.blx(dataTempRegister), Call::LinkableNear);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    ALWAYS_INLINE Call nearTailCall()
+    {
+        moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
+        return Call(m_assembler.bx(dataTempRegister), Call::LinkableNearTail);
+    }
+
</ins><span class="cx">     ALWAYS_INLINE Call call()
</span><span class="cx">     {
</span><span class="cx">         moveFixedWidthEncoding(TrustedImm32(0), dataTempRegister);
</span><span class="lines">@@ -2007,7 +2013,10 @@
</span><span class="cx"> 
</span><span class="cx">     static void linkCall(void* code, Call call, FunctionPtr function)
</span><span class="cx">     {
</span><del>-        ARMv7Assembler::linkCall(code, call.m_label, function.value());
</del><ins>+        if (call.isFlagSet(Call::Tail))
+            ARMv7Assembler::linkJump(code, call.m_label, function.value());
+        else
+            ARMv7Assembler::linkCall(code, call.m_label, function.value());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerMIPSh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1975,6 +1975,16 @@
</span><span class="cx">         return Call(m_assembler.label(), Call::LinkableNear);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Call nearTailCall()
+    {
+        m_assembler.nop();
+        m_assembler.nop();
+        m_assembler.beq(MIPSRegisters::zero, MIPSRegisters::zero, 0);
+        m_assembler.nop();
+        insertRelaxationWords();
+        return Call(m_assembler.label(), Call::LinkableNearTail);
+    }
+
</ins><span class="cx">     Call call()
</span><span class="cx">     {
</span><span class="cx">         m_assembler.lui(MIPSRegisters::t9, 0);
</span><span class="lines">@@ -2800,7 +2810,10 @@
</span><span class="cx"> 
</span><span class="cx">     static void linkCall(void* code, Call call, FunctionPtr function)
</span><span class="cx">     {
</span><del>-        MIPSAssembler::linkCall(code, call.m_label, function.value());
</del><ins>+        if (call.isFlagSet(Call::Tail))
+            MIPSAssembler::linkJump(code, call.m_label, function.value());
+        else
+            MIPSAssembler::linkCall(code, call.m_label, function.value());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerSH4h"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerSH4.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -2403,6 +2403,11 @@
</span><span class="cx">         return Call(m_assembler.call(), Call::Linkable);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Call nearTailCall()
+    {
+        return Call(m_assembler.jump(), Call::LinkableNearTail);
+    }
+
</ins><span class="cx">     Call nearCall()
</span><span class="cx">     {
</span><span class="cx">         return Call(m_assembler.call(), Call::LinkableNear);
</span><span class="lines">@@ -2608,7 +2613,10 @@
</span><span class="cx"> 
</span><span class="cx">     static void linkCall(void* code, Call call, FunctionPtr function)
</span><span class="cx">     {
</span><del>-        SH4Assembler::linkCall(code, call.m_label, function.value());
</del><ins>+        if (call.isFlagSet(Call::Tail))
+            SH4Assembler::linkJump(code, call.m_label, function.value());
+        else
+            SH4Assembler::linkCall(code, call.m_label, function.value());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerX86h"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -351,7 +351,10 @@
</span><span class="cx"> 
</span><span class="cx">     static void linkCall(void* code, Call call, FunctionPtr function)
</span><span class="cx">     {
</span><del>-        X86Assembler::linkCall(code, call.m_label, function.value());
</del><ins>+        if (call.isFlagSet(Call::Tail))
+            X86Assembler::linkJump(code, call.m_label, function.value());
+        else
+            X86Assembler::linkCall(code, call.m_label, function.value());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static void repatchCall(CodeLocationCall call, CodeLocationLabel destination)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1403,6 +1403,11 @@
</span><span class="cx">         m_assembler.int3();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Call nearTailCall()
+    {
+        return Call(m_assembler.jmp(), Call::LinkableNearTail);
+    }
+
</ins><span class="cx">     Call nearCall()
</span><span class="cx">     {
</span><span class="cx">         return Call(m_assembler.call(), Call::LinkableNear);
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerMacroAssemblerX86_64h"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/MacroAssemblerX86_64.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -852,6 +852,8 @@
</span><span class="cx">     {
</span><span class="cx">         if (!call.isFlagSet(Call::Near))
</span><span class="cx">             X86Assembler::linkPointer(code, call.m_label.labelAtOffset(-REPTACH_OFFSET_CALL_R11), function.value());
</span><ins>+        else if (call.isFlagSet(Call::Tail))
+            X86Assembler::linkJump(code, call.m_label, function.value());
</ins><span class="cx">         else
</span><span class="cx">             X86Assembler::linkCall(code, call.m_label, function.value());
</span><span class="cx">     }
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreassemblerRepatchBufferh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/assembler/RepatchBuffer.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/assembler/RepatchBuffer.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/assembler/RepatchBuffer.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -80,14 +80,17 @@
</span><span class="cx">         MacroAssembler::repatchCall(call, destination);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void relink(CodeLocationNearCall nearCall, CodePtr destination)
</del><ins>+    void relink(CodeLocationNearCall nearCall, CodePtr destination, CallLinkInfo::CallType callType)
</ins><span class="cx">     {
</span><del>-        MacroAssembler::repatchNearCall(nearCall, CodeLocationLabel(destination));
</del><ins>+        relink(nearCall, CodeLocationLabel(destination), callType);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void relink(CodeLocationNearCall nearCall, CodeLocationLabel destination)
</del><ins>+    void relink(CodeLocationNearCall nearCall, CodeLocationLabel destination, CallLinkInfo::CallType callType)
</ins><span class="cx">     {
</span><del>-        MacroAssembler::repatchNearCall(nearCall, destination);
</del><ins>+        if (CallLinkInfo::isTailCallType(callType))
+            MacroAssembler::repatchJump(CodeLocationJump(nearCall.dataLocation()), destination);
+        else
+            MacroAssembler::repatchNearCall(nearCall, destination);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void repatch(CodeLocationDataLabel32 dataLabel32, int32_t value)
</span><span class="lines">@@ -120,11 +123,6 @@
</span><span class="cx">         relink(CodeLocationCall(CodePtr(returnAddress)), function);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodeLocationLabel label)
-    {
-        relink(CodeLocationNearCall(CodePtr(returnAddress)), label);
-    }
-    
</del><span class="cx">     void relinkNearCallerToTrampoline(ReturnAddressPtr returnAddress, CodePtr newCalleeFunction)
</span><span class="cx">     {
</span><span class="cx">         relinkNearCallerToTrampoline(returnAddress, CodeLocationLabel(newCalleeFunction));
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeBytecodeListjson"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeList.json (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeList.json        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeList.json        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -98,8 +98,10 @@
</span><span class="cx">             { &quot;name&quot; : &quot;op_new_func&quot;, &quot;length&quot; : 4 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_new_func_exp&quot;, &quot;length&quot; : 4 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_call&quot;, &quot;length&quot; : 9 },
</span><ins>+            { &quot;name&quot; : &quot;op_tail_call&quot;, &quot;length&quot; : 9 },
</ins><span class="cx">             { &quot;name&quot; : &quot;op_call_eval&quot;, &quot;length&quot; : 9 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_call_varargs&quot;, &quot;length&quot; : 9 },
</span><ins>+            { &quot;name&quot; : &quot;op_tail_call_varargs&quot;, &quot;length&quot; : 9 },
</ins><span class="cx">             { &quot;name&quot; : &quot;op_ret&quot;, &quot;length&quot; : 2 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_construct&quot;, &quot;length&quot; : 9 },
</span><span class="cx">             { &quot;name&quot; : &quot;op_construct_varargs&quot;, &quot;length&quot; : 9 },
</span><span class="lines">@@ -149,7 +151,8 @@
</span><span class="cx">             { &quot;name&quot; : &quot;llint_cloop_did_return_from_js_5&quot; },
</span><span class="cx">             { &quot;name&quot; : &quot;llint_cloop_did_return_from_js_6&quot; },
</span><span class="cx">             { &quot;name&quot; : &quot;llint_cloop_did_return_from_js_7&quot; },
</span><del>-            { &quot;name&quot; : &quot;llint_cloop_did_return_from_js_8&quot; }
</del><ins>+            { &quot;name&quot; : &quot;llint_cloop_did_return_from_js_8&quot; },
+            { &quot;name&quot; : &quot;llint_cloop_did_return_from_js_9&quot; }
</ins><span class="cx">         ]
</span><span class="cx">     },
</span><span class="cx">     {
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeBytecodeUseDefh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeUseDef.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeUseDef.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/BytecodeUseDef.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -187,7 +187,8 @@
</span><span class="cx">     }
</span><span class="cx">     case op_has_structure_property:
</span><span class="cx">     case op_construct_varargs:
</span><del>-    case op_call_varargs: {
</del><ins>+    case op_call_varargs:
+    case op_tail_call_varargs: {
</ins><span class="cx">         functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
</span><span class="cx">         functor(codeBlock, instruction, opcodeID, instruction[3].u.operand);
</span><span class="cx">         functor(codeBlock, instruction, opcodeID, instruction[4].u.operand);
</span><span class="lines">@@ -216,7 +217,8 @@
</span><span class="cx">     }
</span><span class="cx">     case op_construct:
</span><span class="cx">     case op_call_eval:
</span><del>-    case op_call: {
</del><ins>+    case op_call:
+    case op_tail_call: {
</ins><span class="cx">         functor(codeBlock, instruction, opcodeID, instruction[2].u.operand);
</span><span class="cx">         int argCount = instruction[3].u.operand;
</span><span class="cx">         int registerOffset = -instruction[4].u.operand;
</span><span class="lines">@@ -311,9 +313,11 @@
</span><span class="cx">     case op_new_func:
</span><span class="cx">     case op_new_func_exp:
</span><span class="cx">     case op_call_varargs:
</span><ins>+    case op_tail_call_varargs:
</ins><span class="cx">     case op_construct_varargs:
</span><span class="cx">     case op_get_from_scope:
</span><span class="cx">     case op_call:
</span><ins>+    case op_tail_call:
</ins><span class="cx">     case op_call_eval:
</span><span class="cx">     case op_construct:
</span><span class="cx">     case op_get_by_id:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeCallLinkInfoh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkInfo.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkInfo.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkInfo.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -43,18 +43,47 @@
</span><span class="cx"> 
</span><span class="cx"> class CallLinkInfo : public BasicRawSentinelNode&lt;CallLinkInfo&gt; {
</span><span class="cx"> public:
</span><del>-    enum CallType { None, Call, CallVarargs, Construct, ConstructVarargs };
</del><ins>+    enum CallType { None, Call, CallVarargs, Construct, ConstructVarargs, TailCall, TailCallVarargs };
</ins><span class="cx">     static CallType callTypeFor(OpcodeID opcodeID)
</span><span class="cx">     {
</span><span class="cx">         if (opcodeID == op_call || opcodeID == op_call_eval)
</span><span class="cx">             return Call;
</span><ins>+        if (opcodeID == op_call_varargs)
+            return CallVarargs;
</ins><span class="cx">         if (opcodeID == op_construct)
</span><span class="cx">             return Construct;
</span><span class="cx">         if (opcodeID == op_construct_varargs)
</span><span class="cx">             return ConstructVarargs;
</span><del>-        ASSERT(opcodeID == op_call_varargs);
-        return CallVarargs;
</del><ins>+        if (opcodeID == op_tail_call)
+            return TailCall;
+        ASSERT(opcodeID == op_tail_call_varargs);
+        return TailCallVarargs;
</ins><span class="cx">     }
</span><ins>+
+    static bool isVarargsCallType(CallType callType)
+    {
+        switch (callType) {
+        case CallVarargs:
+        case ConstructVarargs:
+        case TailCallVarargs:
+            return true;
+
+        default:
+            return false;
+        }
+    }
+
+    static bool isTailCallType(CallType callType)
+    {
+        switch (callType) {
+        case TailCall:
+        case TailCallVarargs:
+            return true;
+
+        default:
+            return false;
+        }
+    }
</ins><span class="cx">     
</span><span class="cx">     CallLinkInfo()
</span><span class="cx">         : m_isFTL(false)
</span><span class="lines">@@ -178,6 +207,21 @@
</span><span class="cx">         return m_stub.get();
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    void setSlowStub(PassRefPtr&lt;GCAwareJITStubRoutine&gt; newStub)
+    {
+        m_slowStub = newStub;
+    }
+
+    void clearSlowStub()
+    {
+        m_slowStub = nullptr;
+    }
+
+    GCAwareJITStubRoutine* slowStub()
+    {
+        return m_slowStub.get();
+    }
+
</ins><span class="cx">     bool seenOnce()
</span><span class="cx">     {
</span><span class="cx">         return m_hasSeenShouldRepatch;
</span><span class="lines">@@ -269,6 +313,7 @@
</span><span class="cx">     JITWriteBarrier&lt;JSFunction&gt; m_callee;
</span><span class="cx">     WriteBarrier&lt;JSFunction&gt; m_lastSeenCallee;
</span><span class="cx">     RefPtr&lt;PolymorphicCallStubRoutine&gt; m_stub;
</span><ins>+    RefPtr&lt;GCAwareJITStubRoutine&gt; m_slowStub;
</ins><span class="cx">     bool m_isFTL : 1;
</span><span class="cx">     bool m_hasSeenShouldRepatch : 1;
</span><span class="cx">     bool m_hasSeenClosure : 1;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeCallLinkStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -68,7 +68,7 @@
</span><span class="cx">     
</span><span class="cx">     Instruction* instruction = profiledBlock-&gt;instructions().begin() + bytecodeIndex;
</span><span class="cx">     OpcodeID op = vm.interpreter-&gt;getOpcodeID(instruction[0].u.opcode);
</span><del>-    if (op != op_call &amp;&amp; op != op_construct)
</del><ins>+    if (op != op_call &amp;&amp; op != op_construct &amp;&amp; op != op_tail_call)
</ins><span class="cx">         return CallLinkStatus();
</span><span class="cx">     
</span><span class="cx">     LLIntCallLinkInfo* callLinkInfo = instruction[5].u.callLinkInfo;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeBlock.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1333,13 +1333,18 @@
</span><span class="cx">             printCallOp(out, exec, location, it, &quot;call&quot;, DumpCaches, hasPrintedProfiling, callLinkInfos);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><ins>+        case op_tail_call: {
+            printCallOp(out, exec, location, it, &quot;tail_call&quot;, DumpCaches, hasPrintedProfiling, callLinkInfos);
+            break;
+        }
</ins><span class="cx">         case op_call_eval: {
</span><span class="cx">             printCallOp(out, exec, location, it, &quot;call_eval&quot;, DontDumpCaches, hasPrintedProfiling, callLinkInfos);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case op_construct_varargs:
</span><del>-        case op_call_varargs: {
</del><ins>+        case op_call_varargs:
+        case op_tail_call_varargs: {
</ins><span class="cx">             int result = (++it)-&gt;u.operand;
</span><span class="cx">             int callee = (++it)-&gt;u.operand;
</span><span class="cx">             int thisValue = (++it)-&gt;u.operand;
</span><span class="lines">@@ -1347,7 +1352,7 @@
</span><span class="cx">             int firstFreeRegister = (++it)-&gt;u.operand;
</span><span class="cx">             int varArgOffset = (++it)-&gt;u.operand;
</span><span class="cx">             ++it;
</span><del>-            printLocationAndOp(out, exec, location, it, opcode == op_call_varargs ? &quot;call_varargs&quot; : &quot;construct_varargs&quot;);
</del><ins>+            printLocationAndOp(out, exec, location, it, opcode == op_call_varargs ? &quot;call_varargs&quot; : opcode == op_construct_varargs ? &quot;construct_varargs&quot; : &quot;tail_call_varargs&quot;);
</ins><span class="cx">             out.printf(&quot;%s, %s, %s, %s, %d, %d&quot;, registerName(result).data(), registerName(callee).data(), registerName(thisValue).data(), registerName(arguments).data(), firstFreeRegister, varArgOffset);
</span><span class="cx">             dumpValueProfiling(out, it, hasPrintedProfiling);
</span><span class="cx">             break;
</span><span class="lines">@@ -1895,6 +1900,7 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">         case op_call_varargs:
</span><ins>+        case op_tail_call_varargs:
</ins><span class="cx">         case op_construct_varargs:
</span><span class="cx">         case op_get_by_val: {
</span><span class="cx">             int arrayProfileIndex = pc[opLength - 2].u.operand;
</span><span class="lines">@@ -1944,6 +1950,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_call:
</span><ins>+        case op_tail_call:
</ins><span class="cx">         case op_call_eval: {
</span><span class="cx">             ValueProfile* profile = &amp;m_valueProfiles[pc[opLength - 1].u.operand];
</span><span class="cx">             ASSERT(profile-&gt;m_bytecodeOffset == -1);
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1838,9 +1838,7 @@
</span><span class="cx"> 
</span><span class="cx"> RegisterID* BytecodeGenerator::emitTailCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments&amp; callArguments, const JSTextPosition&amp; divot, const JSTextPosition&amp; divotStart, const JSTextPosition&amp; divotEnd)
</span><span class="cx"> {
</span><del>-    // FIXME: We should be emitting a new op_tail_call here
-    // https://bugs.webkit.org/show_bug.cgi?id=146484
-    return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd);
</del><ins>+    return emitCall(op_tail_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RegisterID* BytecodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, CallArguments&amp; callArguments, const JSTextPosition&amp; divot, const JSTextPosition&amp; divotStart, const JSTextPosition&amp; divotEnd)
</span><span class="lines">@@ -1925,7 +1923,7 @@
</span><span class="cx"> 
</span><span class="cx"> RegisterID* BytecodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments&amp; callArguments, const JSTextPosition&amp; divot, const JSTextPosition&amp; divotStart, const JSTextPosition&amp; divotEnd)
</span><span class="cx"> {
</span><del>-    ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
</del><ins>+    ASSERT(opcodeID == op_call || opcodeID == op_call_eval || opcodeID == op_tail_call);
</ins><span class="cx">     ASSERT(func-&gt;refCount());
</span><span class="cx"> 
</span><span class="cx">     if (m_shouldEmitProfileHooks)
</span><span class="lines">@@ -1941,6 +1939,8 @@
</span><span class="cx">             RefPtr&lt;RegisterID&gt; argumentRegister;
</span><span class="cx">             argumentRegister = expression-&gt;emitBytecode(*this, callArguments.argumentRegister(0));
</span><span class="cx">             RefPtr&lt;RegisterID&gt; thisRegister = emitMove(newTemporary(), callArguments.thisRegister());
</span><ins>+            if (opcodeID == op_tail_call)
+                return emitTailCallVarargs(dst, func, callArguments.thisRegister(), argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd);
</ins><span class="cx">             return emitCallVarargs(dst, func, callArguments.thisRegister(), argumentRegister.get(), newTemporary(), 0, callArguments.profileHookRegister(), divot, divotStart, divotEnd);
</span><span class="cx">         }
</span><span class="cx">         for (; n; n = n-&gt;m_next)
</span><span class="lines">@@ -1994,9 +1994,7 @@
</span><span class="cx"> 
</span><span class="cx"> RegisterID* BytecodeGenerator::emitTailCallVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition&amp; divot, const JSTextPosition&amp; divotStart, const JSTextPosition&amp; divotEnd)
</span><span class="cx"> {
</span><del>-    // FIXME: We should be emitting a new op_tail_call_varargs here
-    // https://bugs.webkit.org/show_bug.cgi?id=146484
-    return emitCallVarargs(op_call_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd);
</del><ins>+    return emitCallVarargs(op_tail_call_varargs, dst, func, thisRegister, arguments, firstFreeRegister, firstVarArgOffset, profileHookRegister, divot, divotStart, divotEnd);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> RegisterID* BytecodeGenerator::emitConstructVarargs(RegisterID* dst, RegisterID* func, RegisterID* thisRegister, RegisterID* arguments, RegisterID* firstFreeRegister, int32_t firstVarArgOffset, RegisterID* profileHookRegister, const JSTextPosition&amp; divot, const JSTextPosition&amp; divotStart, const JSTextPosition&amp; divotEnd)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -2876,14 +2876,14 @@
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ LabelNode ------------------------------------
</span><span class="cx"> 
</span><del>-void LabelNode::emitBytecode(BytecodeGenerator&amp; generator, RegisterID* dst, TailCallMode)
</del><ins>+void LabelNode::emitBytecode(BytecodeGenerator&amp; generator, RegisterID* dst, TailCallMode tailCallMode)
</ins><span class="cx"> {
</span><span class="cx">     generator.emitDebugHook(WillExecuteStatement, firstLine(), startOffset(), lineStartOffset());
</span><span class="cx"> 
</span><span class="cx">     ASSERT(!generator.breakTarget(m_name));
</span><span class="cx"> 
</span><span class="cx">     LabelScopePtr scope = generator.newLabelScope(LabelScope::NamedLabel, &amp;m_name);
</span><del>-    generator.emitNode(dst, m_statement);
</del><ins>+    generator.emitNode(dst, m_statement, tailCallMode);
</ins><span class="cx"> 
</span><span class="cx">     generator.emitLabel(scope-&gt;breakTarget());
</span><span class="cx"> }
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGJITCompilercpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -243,10 +243,9 @@
</span><span class="cx">     for (unsigned i = 0; i &lt; m_jsCalls.size(); ++i) {
</span><span class="cx">         JSCallRecord&amp; record = m_jsCalls[i];
</span><span class="cx">         CallLinkInfo&amp; info = *record.m_info;
</span><del>-        ThunkGenerator generator = linkThunkGeneratorFor(
-            info.specializationKind(),
-            RegisterPreservationNotRequired);
-        linkBuffer.link(record.m_slowCall, FunctionPtr(m_vm-&gt;getCTIStub(generator).code().executableAddress()));
</del><ins>+        linkBuffer.link(
+            record.m_slowCall,
+            FunctionPtr(linkCallThunk(vm(), info, info.specializationKind(), RegisterPreservationNotRequired).code().executableAddress()));
</ins><span class="cx">         info.setCallLocations(linkBuffer.locationOfNearCall(record.m_slowCall),
</span><span class="cx">             linkBuffer.locationOf(record.m_targetToCheck),
</span><span class="cx">             linkBuffer.locationOfNearCall(record.m_fastCall));
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreftlFTLJSCallBasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/ftl/FTLJSCallBase.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -69,11 +69,11 @@
</span><span class="cx"> 
</span><span class="cx"> void JSCallBase::link(VM&amp; vm, LinkBuffer&amp; linkBuffer)
</span><span class="cx"> {
</span><del>-    ThunkGenerator generator = linkThunkGeneratorFor(
-        CallLinkInfo::specializationKindFor(m_type), MustPreserveRegisters);
</del><ins>+    MacroAssemblerCodeRef codeRef =
+        linkCallThunk(&amp;vm, *m_callLinkInfo, CallLinkInfo::specializationKindFor(m_type), MustPreserveRegisters);
</ins><span class="cx">     
</span><span class="cx">     linkBuffer.link(
</span><del>-        m_slowCall, FunctionPtr(vm.getCTIStub(generator).code().executableAddress()));
</del><ins>+        m_slowCall, FunctionPtr(codeRef.code().executableAddress()));
</ins><span class="cx"> 
</span><span class="cx">     m_callLinkInfo-&gt;setUpCallFromFTL(m_type, m_origin, linkBuffer.locationOfNearCall(m_slowCall),
</span><span class="cx">         linkBuffer.locationOf(m_targetToCheck), linkBuffer.locationOfNearCall(m_fastCall),
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreinterpreterInterpreterh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/interpreter/Interpreter.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/interpreter/Interpreter.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/interpreter/Interpreter.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -243,7 +243,7 @@
</span><span class="cx"> 
</span><span class="cx">         void dumpRegisters(CallFrame*);
</span><span class="cx">         
</span><del>-        bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
</del><ins>+        bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval) || opcode == getOpcode(op_tail_call); }
</ins><span class="cx"> 
</span><span class="cx">         void enableSampler();
</span><span class="cx">         int m_sampleEntryDepth;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitJITcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -53,12 +53,6 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-void ctiPatchNearCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction)
-{
-    RepatchBuffer repatchBuffer(codeblock);
-    repatchBuffer.relinkNearCallerToTrampoline(returnAddress, newCalleeFunction);
-}
-
</del><span class="cx"> void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction)
</span><span class="cx"> {
</span><span class="cx">     RepatchBuffer repatchBuffer(codeblock);
</span><span class="lines">@@ -201,8 +195,10 @@
</span><span class="cx">         DEFINE_OP(op_bitor)
</span><span class="cx">         DEFINE_OP(op_bitxor)
</span><span class="cx">         DEFINE_OP(op_call)
</span><ins>+        DEFINE_OP(op_tail_call)
</ins><span class="cx">         DEFINE_OP(op_call_eval)
</span><span class="cx">         DEFINE_OP(op_call_varargs)
</span><ins>+        DEFINE_OP(op_tail_call_varargs)
</ins><span class="cx">         DEFINE_OP(op_construct_varargs)
</span><span class="cx">         DEFINE_OP(op_catch)
</span><span class="cx">         DEFINE_OP(op_construct)
</span><span class="lines">@@ -381,8 +377,10 @@
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_bitor)
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_bitxor)
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_call)
</span><ins>+        DEFINE_SLOWCASE_OP(op_tail_call)
</ins><span class="cx">         DEFINE_SLOWCASE_OP(op_call_eval)
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_call_varargs)
</span><ins>+        DEFINE_SLOWCASE_OP(op_tail_call_varargs)
</ins><span class="cx">         DEFINE_SLOWCASE_OP(op_construct_varargs)
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_construct)
</span><span class="cx">         DEFINE_SLOWCASE_OP(op_to_this)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitJITh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/JIT.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -173,7 +173,6 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     // Near calls can only be patched to other JIT code, regular calls can be patched to JIT code or relinked to stub functions.
</span><del>-    void ctiPatchNearCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction);
</del><span class="cx">     void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, MacroAssemblerCodePtr newCalleeFunction);
</span><span class="cx">     void ctiPatchCallByReturnAddress(CodeBlock* codeblock, ReturnAddressPtr returnAddress, FunctionPtr newCalleeFunction);
</span><span class="cx"> 
</span><span class="lines">@@ -462,8 +461,10 @@
</span><span class="cx">         void emit_op_bitor(Instruction*);
</span><span class="cx">         void emit_op_bitxor(Instruction*);
</span><span class="cx">         void emit_op_call(Instruction*);
</span><ins>+        void emit_op_tail_call(Instruction*);
</ins><span class="cx">         void emit_op_call_eval(Instruction*);
</span><span class="cx">         void emit_op_call_varargs(Instruction*);
</span><ins>+        void emit_op_tail_call_varargs(Instruction*);
</ins><span class="cx">         void emit_op_construct_varargs(Instruction*);
</span><span class="cx">         void emit_op_catch(Instruction*);
</span><span class="cx">         void emit_op_construct(Instruction*);
</span><span class="lines">@@ -573,8 +574,10 @@
</span><span class="cx">         void emitSlow_op_bitor(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><span class="cx">         void emitSlow_op_bitxor(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><span class="cx">         void emitSlow_op_call(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><ins>+        void emitSlow_op_tail_call(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</ins><span class="cx">         void emitSlow_op_call_eval(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><span class="cx">         void emitSlow_op_call_varargs(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><ins>+        void emitSlow_op_tail_call_varargs(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</ins><span class="cx">         void emitSlow_op_construct_varargs(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><span class="cx">         void emitSlow_op_construct(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><span class="cx">         void emitSlow_op_to_this(Instruction*, Vector&lt;SlowCaseEntry&gt;::iterator&amp;);
</span><span class="lines">@@ -778,6 +781,7 @@
</span><span class="cx">         void updateTopCallFrame();
</span><span class="cx"> 
</span><span class="cx">         Call emitNakedCall(CodePtr function = CodePtr());
</span><ins>+        Call emitNakedTailCall(CodePtr function = CodePtr());
</ins><span class="cx"> 
</span><span class="cx">         // Loads the character value of a single character string into dst.
</span><span class="cx">         void emitLoadCharacterString(RegisterID src, RegisterID dst, JumpList&amp; failures);
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitJITCallcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -143,7 +143,9 @@
</span><span class="cx">     COMPILE_ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct), call_and_construct_opcodes_must_be_same_length);
</span><span class="cx">     COMPILE_ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_varargs), call_and_call_varargs_opcodes_must_be_same_length);
</span><span class="cx">     COMPILE_ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct_varargs), call_and_construct_varargs_opcodes_must_be_same_length);
</span><del>-    if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs)
</del><ins>+    COMPILE_ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call), call_and_tail_call_opcodes_must_be_same_length);
+    COMPILE_ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call_varargs), call_and_tail_call_varargs_opcodes_must_be_same_length);
+    if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs || opcodeID == op_tail_call_varargs)
</ins><span class="cx">         compileSetupVarargsFrame(instruction, info);
</span><span class="cx">     else {
</span><span class="cx">         int argCount = instruction[3].u.operand;
</span><span class="lines">@@ -167,7 +169,7 @@
</span><span class="cx">     emitGetVirtualRegister(callee, regT0); // regT0 holds callee.
</span><span class="cx"> 
</span><span class="cx">     store64(regT0, Address(stackPointerRegister, JSStack::Callee * static_cast&lt;int&gt;(sizeof(Register)) - sizeof(CallerFrameAndPC)));
</span><del>-    
</del><ins>+
</ins><span class="cx">     if (opcodeID == op_call_eval) {
</span><span class="cx">         compileCallEval(instruction);
</span><span class="cx">         return;
</span><span class="lines">@@ -183,6 +185,14 @@
</span><span class="cx">     m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
</span><span class="cx">     m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
</span><span class="cx"> 
</span><ins>+    if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
+        prepareForTailCall(*this);
+        m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedTailCall();
+        // We must never come back here
+        breakpoint();
+        return;
+    }
+
</ins><span class="cx">     m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
</span><span class="cx"> 
</span><span class="cx">     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="lines">@@ -202,13 +212,21 @@
</span><span class="cx"> 
</span><span class="cx">     linkSlowCase(iter);
</span><span class="cx"> 
</span><del>-    ThunkGenerator generator = linkThunkGeneratorFor(
-        (opcodeID == op_construct || opcodeID == op_construct_varargs) ? CodeForConstruct : CodeForCall,
-        RegisterPreservationNotRequired);
-    
</del><ins>+    MacroAssemblerCodeRef codeRef =
+        linkCallThunk(m_vm, *m_callCompilationInfo[callLinkInfoIndex].callLinkInfo,
+            opcodeID == op_construct || opcodeID == op_construct_varargs ? CodeForConstruct : CodeForCall,
+            RegisterPreservationNotRequired);
+
</ins><span class="cx">     move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
</span><del>-    m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm-&gt;getCTIStub(generator).code());
</del><span class="cx"> 
</span><ins>+    m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(codeRef.code());
+
+    if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
+        // We must never come back here
+        breakpoint();
+        return;
+    }
+
</ins><span class="cx">     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="cx">     checkStackPointerAlignment();
</span><span class="cx"> 
</span><span class="lines">@@ -222,6 +240,11 @@
</span><span class="cx">     compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JIT::emit_op_tail_call(Instruction* currentInstruction)
+{
+    compileOpCall(op_tail_call, currentInstruction, m_callLinkInfoIndex++);
+}
+
</ins><span class="cx"> void JIT::emit_op_call_eval(Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex);
</span><span class="lines">@@ -231,7 +254,12 @@
</span><span class="cx"> {
</span><span class="cx">     compileOpCall(op_call_varargs, currentInstruction, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><del>-    
</del><ins>+
+void JIT::emit_op_tail_call_varargs(Instruction* currentInstruction)
+{
+    compileOpCall(op_tail_call_varargs, currentInstruction, m_callLinkInfoIndex++);
+}
+
</ins><span class="cx"> void JIT::emit_op_construct_varargs(Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     compileOpCall(op_construct_varargs, currentInstruction, m_callLinkInfoIndex++);
</span><span class="lines">@@ -247,6 +275,11 @@
</span><span class="cx">     compileOpCallSlowCase(op_call, currentInstruction, iter, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JIT::emitSlow_op_tail_call(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
+{
+    compileOpCallSlowCase(op_tail_call, currentInstruction, iter, m_callLinkInfoIndex++);
+}
+
</ins><span class="cx"> void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
</span><span class="cx"> {
</span><span class="cx">     compileOpCallSlowCase(op_call_eval, currentInstruction, iter, m_callLinkInfoIndex);
</span><span class="lines">@@ -256,6 +289,11 @@
</span><span class="cx"> {
</span><span class="cx">     compileOpCallSlowCase(op_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><ins>+
+void JIT::emitSlow_op_tail_call_varargs(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
+{
+    compileOpCallSlowCase(op_tail_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
+}
</ins><span class="cx">     
</span><span class="cx"> void JIT::emitSlow_op_construct_varargs(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
</span><span class="cx"> {
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitJITCall32_64cpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall32_64.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall32_64.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/JITCall32_64.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -69,6 +69,11 @@
</span><span class="cx">     compileOpCallSlowCase(op_call, currentInstruction, iter, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JIT::emitSlow_op_tail_call(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
+{
+    compileOpCallSlowCase(op_tail_call, currentInstruction, iter, m_callLinkInfoIndex++);
+}
+
</ins><span class="cx"> void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
</span><span class="cx"> {
</span><span class="cx">     compileOpCallSlowCase(op_call_eval, currentInstruction, iter, m_callLinkInfoIndex);
</span><span class="lines">@@ -78,6 +83,11 @@
</span><span class="cx"> {
</span><span class="cx">     compileOpCallSlowCase(op_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><ins>+
+void JIT::emitSlow_op_tail_call_varargs(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
+{
+    compileOpCallSlowCase(op_tail_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
+}
</ins><span class="cx">     
</span><span class="cx"> void JIT::emitSlow_op_construct_varargs(Instruction* currentInstruction, Vector&lt;SlowCaseEntry&gt;::iterator&amp; iter)
</span><span class="cx"> {
</span><span class="lines">@@ -94,6 +104,11 @@
</span><span class="cx">     compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JIT::emit_op_tail_call(Instruction* currentInstruction)
+{
+    compileOpCall(op_tail_call, currentInstruction, m_callLinkInfoIndex++);
+}
+
</ins><span class="cx"> void JIT::emit_op_call_eval(Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="cx">     compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex);
</span><span class="lines">@@ -103,6 +118,11 @@
</span><span class="cx"> {
</span><span class="cx">     compileOpCall(op_call_varargs, currentInstruction, m_callLinkInfoIndex++);
</span><span class="cx"> }
</span><ins>+
+void JIT::emit_op_tail_call_varargs(Instruction* currentInstruction)
+{
+    compileOpCall(op_tail_call_varargs, currentInstruction, m_callLinkInfoIndex++);
+}
</ins><span class="cx">     
</span><span class="cx"> void JIT::emit_op_construct_varargs(Instruction* currentInstruction)
</span><span class="cx"> {
</span><span class="lines">@@ -204,7 +224,7 @@
</span><span class="cx">         - Caller restores callFrameRegister after return.
</span><span class="cx">     */
</span><span class="cx">     
</span><del>-    if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs)
</del><ins>+    if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs || opcodeID == op_tail_call_varargs)
</ins><span class="cx">         compileSetupVarargsFrame(instruction, info);
</span><span class="cx">     else {
</span><span class="cx">         int argCount = instruction[3].u.operand;
</span><span class="lines">@@ -249,6 +269,14 @@
</span><span class="cx">     m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
</span><span class="cx"> 
</span><span class="cx">     checkStackPointerAlignment();
</span><ins>+    if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
+        prepareForTailCall(*this);
+        m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedTailCall();
+        // We must never come back here
+        breakpoint();
+        return;
+    }
+
</ins><span class="cx">     m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
</span><span class="cx"> 
</span><span class="cx">     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="lines">@@ -268,13 +296,21 @@
</span><span class="cx">     linkSlowCase(iter);
</span><span class="cx">     linkSlowCase(iter);
</span><span class="cx"> 
</span><del>-    ThunkGenerator generator = linkThunkGeneratorFor(
-        (opcodeID == op_construct || opcodeID == op_construct_varargs) ? CodeForConstruct : CodeForCall,
-        RegisterPreservationNotRequired);
</del><ins>+    MacroAssemblerCodeRef codeRef =
+        linkCallThunk(m_vm, *m_callCompilationInfo[callLinkInfoIndex].callLinkInfo,
+            opcodeID == op_construct || opcodeID == op_construct_varargs ? CodeForConstruct : CodeForCall,
+            RegisterPreservationNotRequired);
</ins><span class="cx">     
</span><span class="cx">     move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
</span><del>-    m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm-&gt;getCTIStub(generator).code());
</del><span class="cx"> 
</span><ins>+    m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(codeRef.code());
+
+    if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
+        // We must never come back here
+        breakpoint();
+        return;
+    }
+
</ins><span class="cx">     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
</span><span class="cx">     checkStackPointerAlignment();
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitJITInlinesh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/JITInlines.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/JITInlines.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/JITInlines.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -125,6 +125,14 @@
</span><span class="cx">     return nakedCall;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE JIT::Call JIT::emitNakedTailCall(CodePtr function)
+{
+    ASSERT(m_bytecodeOffset != std::numeric_limits&lt;unsigned&gt;::max()); // This method should only be called during hot/cold path generation, so that m_bytecodeOffset is set.
+    Call nakedCall = nearTailCall();
+    m_calls.append(CallRecord(nakedCall, m_bytecodeOffset, function.executableAddress()));
+    return nakedCall;
+}
+
</ins><span class="cx"> ALWAYS_INLINE void JIT::updateTopCallFrame()
</span><span class="cx"> {
</span><span class="cx">     ASSERT(static_cast&lt;int&gt;(m_bytecodeOffset) &gt;= 0);
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitJITOperationscpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -705,7 +705,7 @@
</span><span class="cx">     return JSValue::encode(result);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind)
</del><ins>+static SlowPathReturnType handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind)
</ins><span class="cx"> {
</span><span class="cx">     ExecState* exec = execCallee-&gt;callerFrame();
</span><span class="cx">     VM* vm = &amp;exec-&gt;vm();
</span><span class="lines">@@ -723,14 +723,14 @@
</span><span class="cx">             execCallee-&gt;setCallee(asObject(callee));
</span><span class="cx">             vm-&gt;hostCallReturnValue = JSValue::decode(callData.native.function(execCallee));
</span><span class="cx">             if (vm-&gt;exception())
</span><del>-                return vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
</del><ins>+                return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx"> 
</span><del>-            return reinterpret_cast&lt;void*&gt;(getHostCallReturnValue);
</del><ins>+            return encodeResult(bitwise_cast&lt;void*&gt;(getHostCallReturnValue), reinterpret_cast&lt;void*&gt;(1));
</ins><span class="cx">         }
</span><span class="cx">     
</span><span class="cx">         ASSERT(callType == CallTypeNone);
</span><span class="cx">         exec-&gt;vm().throwException(exec, createNotAFunctionError(exec, callee));
</span><del>-        return vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
</del><ins>+        return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ASSERT(kind == CodeForConstruct);
</span><span class="lines">@@ -745,17 +745,17 @@
</span><span class="cx">         execCallee-&gt;setCallee(asObject(callee));
</span><span class="cx">         vm-&gt;hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee));
</span><span class="cx">         if (vm-&gt;exception())
</span><del>-            return vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
</del><ins>+            return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx"> 
</span><del>-        return reinterpret_cast&lt;void*&gt;(getHostCallReturnValue);
</del><ins>+        return encodeResult(bitwise_cast&lt;void*&gt;(getHostCallReturnValue), reinterpret_cast&lt;void*&gt;(1));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     ASSERT(constructType == ConstructTypeNone);
</span><span class="cx">     exec-&gt;vm().throwException(exec, createNotAConstructorError(exec, callee));
</span><del>-    return vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
</del><ins>+    return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline char* linkFor(
</del><ins>+inline SlowPathReturnType linkFor(
</ins><span class="cx">     ExecState* execCallee, CallLinkInfo* callLinkInfo, CodeSpecializationKind kind,
</span><span class="cx">     RegisterPreservationMode registers)
</span><span class="cx"> {
</span><span class="lines">@@ -769,7 +769,7 @@
</span><span class="cx">         // FIXME: We should cache these kinds of calls. They can be common and currently they are
</span><span class="cx">         // expensive.
</span><span class="cx">         // https://bugs.webkit.org/show_bug.cgi?id=144458
</span><del>-        return reinterpret_cast&lt;char*&gt;(handleHostCall(execCallee, calleeAsValue, kind));
</del><ins>+        return handleHostCall(execCallee, calleeAsValue, kind);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     JSFunction* callee = jsCast&lt;JSFunction*&gt;(calleeAsFunctionCell);
</span><span class="lines">@@ -785,17 +785,17 @@
</span><span class="cx"> 
</span><span class="cx">         if (!isCall(kind) &amp;&amp; functionExecutable-&gt;isBuiltinFunction()) {
</span><span class="cx">             exec-&gt;vm().throwException(exec, createNotAConstructorError(exec, callee));
</span><del>-            return reinterpret_cast&lt;char*&gt;(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
</del><ins>+            return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         JSObject* error = functionExecutable-&gt;prepareForExecution(execCallee, callee, scope, kind);
</span><span class="cx">         if (error) {
</span><span class="cx">             exec-&gt;vm().throwException(exec, error);
</span><del>-            return reinterpret_cast&lt;char*&gt;(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
</del><ins>+            return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx">         }
</span><span class="cx">         codeBlock = functionExecutable-&gt;codeBlockFor(kind);
</span><span class="cx">         ArityCheckMode arity;
</span><del>-        if (execCallee-&gt;argumentCountIncludingThis() &lt; static_cast&lt;size_t&gt;(codeBlock-&gt;numParameters()) || callLinkInfo-&gt;callType() == CallLinkInfo::CallVarargs || callLinkInfo-&gt;callType() == CallLinkInfo::ConstructVarargs)
</del><ins>+        if (execCallee-&gt;argumentCountIncludingThis() &lt; static_cast&lt;size_t&gt;(codeBlock-&gt;numParameters()) || CallLinkInfo::isVarargsCallType(callLinkInfo-&gt;callType()))
</ins><span class="cx">             arity = MustCheckArity;
</span><span class="cx">         else
</span><span class="cx">             arity = ArityCheckNotRequired;
</span><span class="lines">@@ -805,31 +805,31 @@
</span><span class="cx">         callLinkInfo-&gt;setSeen();
</span><span class="cx">     else
</span><span class="cx">         linkFor(execCallee, *callLinkInfo, codeBlock, callee, codePtr, kind, registers);
</span><del>-    
-    return reinterpret_cast&lt;char*&gt;(codePtr.executableAddress());
</del><ins>+
+    return encodeResult(codePtr.executableAddress(), reinterpret_cast&lt;void*&gt;(1));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationLinkCall(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</del><ins>+SlowPathReturnType JIT_OPERATION operationLinkCall(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</ins><span class="cx"> {
</span><span class="cx">     return linkFor(execCallee, callLinkInfo, CodeForCall, RegisterPreservationNotRequired);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationLinkConstruct(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</del><ins>+SlowPathReturnType JIT_OPERATION operationLinkConstruct(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</ins><span class="cx"> {
</span><span class="cx">     return linkFor(execCallee, callLinkInfo, CodeForConstruct, RegisterPreservationNotRequired);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationLinkCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</del><ins>+SlowPathReturnType JIT_OPERATION operationLinkCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</ins><span class="cx"> {
</span><span class="cx">     return linkFor(execCallee, callLinkInfo, CodeForCall, MustPreserveRegisters);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationLinkConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</del><ins>+SlowPathReturnType JIT_OPERATION operationLinkConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</ins><span class="cx"> {
</span><span class="cx">     return linkFor(execCallee, callLinkInfo, CodeForConstruct, MustPreserveRegisters);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline char* virtualForWithFunction(
</del><ins>+inline SlowPathReturnType virtualForWithFunction(
</ins><span class="cx">     ExecState* execCallee, CodeSpecializationKind kind, RegisterPreservationMode registers,
</span><span class="cx">     JSCell*&amp; calleeAsFunctionCell)
</span><span class="cx"> {
</span><span class="lines">@@ -840,7 +840,7 @@
</span><span class="cx">     JSValue calleeAsValue = execCallee-&gt;calleeAsValue();
</span><span class="cx">     calleeAsFunctionCell = getJSFunction(calleeAsValue);
</span><span class="cx">     if (UNLIKELY(!calleeAsFunctionCell))
</span><del>-        return reinterpret_cast&lt;char*&gt;(handleHostCall(execCallee, calleeAsValue, kind));
</del><ins>+        return handleHostCall(execCallee, calleeAsValue, kind);
</ins><span class="cx">     
</span><span class="cx">     JSFunction* function = jsCast&lt;JSFunction*&gt;(calleeAsFunctionCell);
</span><span class="cx">     JSScope* scope = function-&gt;scopeUnchecked();
</span><span class="lines">@@ -850,62 +850,62 @@
</span><span class="cx"> 
</span><span class="cx">         if (!isCall(kind) &amp;&amp; functionExecutable-&gt;isBuiltinFunction()) {
</span><span class="cx">             exec-&gt;vm().throwException(exec, createNotAConstructorError(exec, function));
</span><del>-            return reinterpret_cast&lt;char*&gt;(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
</del><ins>+            return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         JSObject* error = functionExecutable-&gt;prepareForExecution(execCallee, function, scope, kind);
</span><span class="cx">         if (error) {
</span><span class="cx">             exec-&gt;vm().throwException(exec, error);
</span><del>-            return reinterpret_cast&lt;char*&gt;(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
</del><ins>+            return encodeResult(vm-&gt;getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(), reinterpret_cast&lt;void*&gt;(0));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-    return reinterpret_cast&lt;char*&gt;(executable-&gt;entrypointFor(
-        *vm, kind, MustCheckArity, registers).executableAddress());
</del><ins>+    return encodeResult(executable-&gt;entrypointFor(
+        *vm, kind, MustCheckArity, registers).executableAddress(), reinterpret_cast&lt;void*&gt;(1));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline char* virtualFor(
</del><ins>+inline SlowPathReturnType virtualFor(
</ins><span class="cx">     ExecState* execCallee, CodeSpecializationKind kind, RegisterPreservationMode registers)
</span><span class="cx"> {
</span><span class="cx">     JSCell* calleeAsFunctionCellIgnored;
</span><span class="cx">     return virtualForWithFunction(execCallee, kind, registers, calleeAsFunctionCellIgnored);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationLinkPolymorphicCall(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</del><ins>+SlowPathReturnType JIT_OPERATION operationLinkPolymorphicCall(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</ins><span class="cx"> {
</span><span class="cx">     JSCell* calleeAsFunctionCell;
</span><del>-    char* result = virtualForWithFunction(execCallee, CodeForCall, RegisterPreservationNotRequired, calleeAsFunctionCell);
</del><ins>+    SlowPathReturnType result = virtualForWithFunction(execCallee, CodeForCall, RegisterPreservationNotRequired, calleeAsFunctionCell);
</ins><span class="cx"> 
</span><span class="cx">     linkPolymorphicCall(execCallee, *callLinkInfo, CallVariant(calleeAsFunctionCell), RegisterPreservationNotRequired);
</span><span class="cx">     
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationVirtualCall(ExecState* execCallee, CallLinkInfo*)
</del><ins>+SlowPathReturnType JIT_OPERATION operationVirtualCall(ExecState* execCallee, CallLinkInfo*)
</ins><span class="cx"> {    
</span><span class="cx">     return virtualFor(execCallee, CodeForCall, RegisterPreservationNotRequired);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationVirtualConstruct(ExecState* execCallee, CallLinkInfo*)
</del><ins>+SlowPathReturnType JIT_OPERATION operationVirtualConstruct(ExecState* execCallee, CallLinkInfo*)
</ins><span class="cx"> {
</span><span class="cx">     return virtualFor(execCallee, CodeForConstruct, RegisterPreservationNotRequired);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationLinkPolymorphicCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</del><ins>+SlowPathReturnType JIT_OPERATION operationLinkPolymorphicCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
</ins><span class="cx"> {
</span><span class="cx">     JSCell* calleeAsFunctionCell;
</span><del>-    char* result = virtualForWithFunction(execCallee, CodeForCall, MustPreserveRegisters, calleeAsFunctionCell);
</del><ins>+    SlowPathReturnType result = virtualForWithFunction(execCallee, CodeForCall, MustPreserveRegisters, calleeAsFunctionCell);
</ins><span class="cx"> 
</span><span class="cx">     linkPolymorphicCall(execCallee, *callLinkInfo, CallVariant(calleeAsFunctionCell), MustPreserveRegisters);
</span><span class="cx">     
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationVirtualCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo*)
</del><ins>+SlowPathReturnType JIT_OPERATION operationVirtualCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo*)
</ins><span class="cx"> {    
</span><span class="cx">     return virtualFor(execCallee, CodeForCall, MustPreserveRegisters);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-char* JIT_OPERATION operationVirtualConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo*)
</del><ins>+SlowPathReturnType JIT_OPERATION operationVirtualConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo*)
</ins><span class="cx"> {
</span><span class="cx">     return virtualFor(execCallee, CodeForConstruct, MustPreserveRegisters);
</span><span class="cx"> }
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitJITOperationsh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/JITOperations.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -225,6 +225,7 @@
</span><span class="cx"> typedef char* JIT_OPERATION (*P_JITOperation_EStSS)(ExecState*, Structure*, size_t, size_t);
</span><span class="cx"> typedef char* JIT_OPERATION (*P_JITOperation_EStZ)(ExecState*, Structure*, int32_t);
</span><span class="cx"> typedef char* JIT_OPERATION (*P_JITOperation_EZZ)(ExecState*, int32_t, int32_t);
</span><ins>+typedef SlowPathReturnType JIT_OPERATION (*Sprt_JITOperation_ECli)(ExecState*, CallLinkInfo*);
</ins><span class="cx"> typedef StringImpl* JIT_OPERATION (*T_JITOperation_EJss)(ExecState*, JSString*);
</span><span class="cx"> typedef JSString* JIT_OPERATION (*Jss_JITOperation_EZ)(ExecState*, int32_t);
</span><span class="cx"> 
</span><span class="lines">@@ -263,16 +264,16 @@
</span><span class="cx"> void JIT_OPERATION operationPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
</span><span class="cx"> void JIT_OPERATION operationDirectPutByValGeneric(ExecState*, EncodedJSValue, EncodedJSValue, EncodedJSValue, ArrayProfile*) WTF_INTERNAL;
</span><span class="cx"> EncodedJSValue JIT_OPERATION operationCallEval(ExecState*, ExecState*) WTF_INTERNAL;
</span><del>-char* JIT_OPERATION operationLinkCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationLinkPolymorphicCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationVirtualCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationVirtualConstruct(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationLinkConstruct(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationLinkCallThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationLinkPolymorphicCallThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationVirtualCallThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationVirtualConstructThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
-char* JIT_OPERATION operationLinkConstructThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
</del><ins>+SlowPathReturnType JIT_OPERATION operationLinkCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationLinkPolymorphicCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationVirtualCall(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationVirtualConstruct(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationLinkConstruct(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationLinkCallThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationLinkPolymorphicCallThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationVirtualCallThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationVirtualConstructThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
+SlowPathReturnType JIT_OPERATION operationLinkConstructThatPreservesRegs(ExecState*, CallLinkInfo*) WTF_INTERNAL;
</ins><span class="cx"> 
</span><span class="cx"> size_t JIT_OPERATION operationCompareLess(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</span><span class="cx"> size_t JIT_OPERATION operationCompareLessEq(ExecState*, EncodedJSValue, EncodedJSValue) WTF_INTERNAL;
</span><span class="lines">@@ -356,7 +357,7 @@
</span><span class="cx"> 
</span><span class="cx"> } // extern &quot;C&quot;
</span><span class="cx"> 
</span><del>-inline P_JITOperation_ECli operationLinkFor(
</del><ins>+inline Sprt_JITOperation_ECli operationLinkFor(
</ins><span class="cx">     CodeSpecializationKind kind, RegisterPreservationMode registers)
</span><span class="cx"> {
</span><span class="cx">     switch (kind) {
</span><span class="lines">@@ -381,7 +382,7 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline P_JITOperation_ECli operationVirtualFor(
</del><ins>+inline Sprt_JITOperation_ECli operationVirtualFor(
</ins><span class="cx">     CodeSpecializationKind kind, RegisterPreservationMode registers)
</span><span class="cx"> {
</span><span class="cx">     switch (kind) {
</span><span class="lines">@@ -406,7 +407,7 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline P_JITOperation_ECli operationLinkPolymorphicCallFor(RegisterPreservationMode registers)
</del><ins>+inline Sprt_JITOperation_ECli operationLinkPolymorphicCallFor(RegisterPreservationMode registers)
</ins><span class="cx"> {
</span><span class="cx">     switch (registers) {
</span><span class="cx">     case RegisterPreservationNotRequired:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/Repatch.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/Repatch.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/Repatch.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -586,10 +586,10 @@
</span><span class="cx">             patchBuffer.locationOf(addressOfLinkFunctionCheck),
</span><span class="cx">             patchBuffer.locationOfNearCall(fastPathCall));
</span><span class="cx"> 
</span><del>-        ThunkGenerator generator = linkThunkGeneratorFor(
-            CodeForCall, RegisterPreservationNotRequired);
</del><span class="cx">         patchBuffer.link(
</span><del>-            slowPathCall, CodeLocationLabel(vm-&gt;getCTIStub(generator).code()));
</del><ins>+            slowPathCall, FunctionPtr(linkCallThunk(vm, *callLinkInfo, CodeForCall, RegisterPreservationNotRequired).code().executableAddress()));
+        // This should always use a global stub from the VM
+        ASSERT(!callLinkInfo-&gt;slowStub());
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     MacroAssemblerCodeRef code = FINALIZE_CODE_FOR(
</span><span class="lines">@@ -1601,17 +1601,13 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void linkSlowFor(
</span><del>-    RepatchBuffer&amp; repatchBuffer, VM* vm, CallLinkInfo&amp; callLinkInfo, ThunkGenerator generator)
-{
-    repatchBuffer.relink(
-        callLinkInfo.callReturnLocation(), vm-&gt;getCTIStub(generator).code());
-}
-
-static void linkSlowFor(
</del><span class="cx">     RepatchBuffer&amp; repatchBuffer, VM* vm, CallLinkInfo&amp; callLinkInfo,
</span><span class="cx">     CodeSpecializationKind kind, RegisterPreservationMode registers)
</span><span class="cx"> {
</span><del>-    linkSlowFor(repatchBuffer, vm, callLinkInfo, virtualThunkGeneratorFor(kind, registers));
</del><ins>+    repatchBuffer.relink(
+        callLinkInfo.callReturnLocation(),
+        virtualThunk(vm, callLinkInfo, kind, registers).code(),
+        callLinkInfo.callType());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void linkFor(
</span><span class="lines">@@ -1632,18 +1628,21 @@
</span><span class="cx">     callLinkInfo.setLastSeenCallee(exec-&gt;callerFrame()-&gt;vm(), callerCodeBlock-&gt;ownerExecutable(), callee);
</span><span class="cx">     if (shouldShowDisassemblyFor(callerCodeBlock))
</span><span class="cx">         dataLog(&quot;Linking call in &quot;, *callerCodeBlock, &quot; at &quot;, callLinkInfo.codeOrigin(), &quot; to &quot;, pointerDump(calleeCodeBlock), &quot;, entrypoint at &quot;, codePtr, &quot;\n&quot;);
</span><del>-    repatchBuffer.relink(callLinkInfo.hotPathOther(), codePtr);
</del><ins>+    repatchBuffer.relink(callLinkInfo.hotPathOther(), codePtr, callLinkInfo.callType());
</ins><span class="cx">     
</span><span class="cx">     if (calleeCodeBlock)
</span><span class="cx">         calleeCodeBlock-&gt;linkIncomingCall(exec-&gt;callerFrame(), &amp;callLinkInfo);
</span><span class="cx">     
</span><span class="cx">     if (kind == CodeForCall) {
</span><del>-        linkSlowFor(
-            repatchBuffer, vm, callLinkInfo, linkPolymorphicCallThunkGeneratorFor(registers));
</del><ins>+        repatchBuffer.relink(
+            callLinkInfo.callReturnLocation(),
+            linkPolymorphicCallThunk(vm, callLinkInfo, registers).code(),
+            callLinkInfo.callType());
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     ASSERT(kind == CodeForConstruct);
</span><ins>+    ASSERT(!CallLinkInfo::isTailCallType(callLinkInfo.callType()));
</ins><span class="cx">     linkSlowFor(repatchBuffer, vm, callLinkInfo, CodeForConstruct, registers);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1660,15 +1659,17 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void revertCall(
</span><del>-    RepatchBuffer&amp; repatchBuffer, VM* vm, CallLinkInfo&amp; callLinkInfo, ThunkGenerator generator)
</del><ins>+    RepatchBuffer&amp; repatchBuffer, CallLinkInfo&amp; callLinkInfo, MacroAssemblerCodeRef codeRef)
</ins><span class="cx"> {
</span><span class="cx">     repatchBuffer.revertJumpReplacementToBranchPtrWithPatch(
</span><span class="cx">         RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo.hotPathBegin()),
</span><span class="cx">         static_cast&lt;MacroAssembler::RegisterID&gt;(callLinkInfo.calleeGPR()), 0);
</span><del>-    linkSlowFor(repatchBuffer, vm, callLinkInfo, generator);
</del><ins>+    repatchBuffer.relink(
+        callLinkInfo.callReturnLocation(), codeRef.code(), callLinkInfo.callType());
</ins><span class="cx">     callLinkInfo.clearSeen();
</span><span class="cx">     callLinkInfo.clearCallee();
</span><span class="cx">     callLinkInfo.clearStub();
</span><ins>+    callLinkInfo.clearSlowStub();
</ins><span class="cx">     if (callLinkInfo.isOnList())
</span><span class="cx">         callLinkInfo.remove();
</span><span class="cx"> }
</span><span class="lines">@@ -1681,8 +1682,8 @@
</span><span class="cx">         dataLog(&quot;Unlinking call from &quot;, callLinkInfo.callReturnLocation(), &quot; in request from &quot;, pointerDump(repatchBuffer.codeBlock()), &quot;\n&quot;);
</span><span class="cx">     
</span><span class="cx">     revertCall(
</span><del>-        repatchBuffer, repatchBuffer.codeBlock()-&gt;vm(), callLinkInfo,
-        linkThunkGeneratorFor(kind, registers));
</del><ins>+        repatchBuffer, callLinkInfo,
+        linkCallThunk(repatchBuffer.codeBlock()-&gt;vm(), callLinkInfo, kind, registers));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void linkVirtualFor(
</span><span class="lines">@@ -1691,15 +1692,15 @@
</span><span class="cx"> {
</span><span class="cx">     // FIXME: We could generate a virtual call stub here. This would lead to faster virtual calls
</span><span class="cx">     // by eliminating the branch prediction bottleneck inside the shared virtual call thunk.
</span><del>-    
</del><ins>+
</ins><span class="cx">     CodeBlock* callerCodeBlock = exec-&gt;callerFrame()-&gt;codeBlock();
</span><span class="cx">     VM* vm = callerCodeBlock-&gt;vm();
</span><del>-    
</del><ins>+
</ins><span class="cx">     if (shouldShowDisassemblyFor(callerCodeBlock))
</span><span class="cx">         dataLog(&quot;Linking virtual call at &quot;, *callerCodeBlock, &quot; &quot;, exec-&gt;callerFrame()-&gt;codeOrigin(), &quot;\n&quot;);
</span><span class="cx">     
</span><span class="cx">     RepatchBuffer repatchBuffer(callerCodeBlock);
</span><del>-    revertCall(repatchBuffer, vm, callLinkInfo, virtualThunkGeneratorFor(kind, registers));
</del><ins>+    revertCall(repatchBuffer, callLinkInfo, virtualThunk(vm, callLinkInfo, kind, registers));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> namespace {
</span><span class="lines">@@ -1758,7 +1759,7 @@
</span><span class="cx">             
</span><span class="cx">             // If we cannot handle a callee, assume that it's better for this whole thing to be a
</span><span class="cx">             // virtual call.
</span><del>-            if (exec-&gt;argumentCountIncludingThis() &lt; static_cast&lt;size_t&gt;(codeBlock-&gt;numParameters()) || callLinkInfo.callType() == CallLinkInfo::CallVarargs || callLinkInfo.callType() == CallLinkInfo::ConstructVarargs) {
</del><ins>+            if (exec-&gt;argumentCountIncludingThis() &lt; static_cast&lt;size_t&gt;(codeBlock-&gt;numParameters()) || CallLinkInfo::isVarargsCallType(callLinkInfo.callType())) {
</ins><span class="cx">                 linkVirtualFor(exec, callLinkInfo, CodeForCall, registers);
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="lines">@@ -1881,7 +1882,11 @@
</span><span class="cx">                 CCallHelpers::TrustedImm32(1),
</span><span class="cx">                 CCallHelpers::Address(fastCountsBaseGPR, caseIndex * sizeof(uint32_t)));
</span><span class="cx">         }
</span><del>-        calls[caseIndex].call = stubJit.nearCall();
</del><ins>+        if (CallLinkInfo::isTailCallType(callLinkInfo.callType())) {
+            prepareForTailCall(stubJit);
+            calls[caseIndex].call = stubJit.nearTailCall();
+        } else
+            calls[caseIndex].call = stubJit.nearCall();
</ins><span class="cx">         calls[caseIndex].codePtr = codePtr;
</span><span class="cx">         done.append(stubJit.jump());
</span><span class="cx">     }
</span><span class="lines">@@ -1913,7 +1918,11 @@
</span><span class="cx">         patchBuffer.link(done, callLinkInfo.callReturnLocation().labelAtOffset(0));
</span><span class="cx">     else
</span><span class="cx">         patchBuffer.link(done, callLinkInfo.hotPathOther().labelAtOffset(0));
</span><del>-    patchBuffer.link(slow, CodeLocationLabel(vm-&gt;getCTIStub(linkPolymorphicCallThunkGeneratorFor(registers)).code()));
</del><ins>+    // This can set the callLinkInfo's slow path stub while this does
+    // not technically takes the slow path. But we repatch the slow
+    // path to take this as well.
+    MacroAssemblerCodePtr slowPathCodePtr = linkPolymorphicCallThunk(vm, callLinkInfo, registers).code();
+    patchBuffer.link(slow, CodeLocationLabel(slowPathCodePtr));
</ins><span class="cx">     
</span><span class="cx">     RefPtr&lt;PolymorphicCallStubRoutine&gt; stubRoutine = adoptRef(new PolymorphicCallStubRoutine(
</span><span class="cx">         FINALIZE_CODE_FOR(
</span><span class="lines">@@ -1929,8 +1938,14 @@
</span><span class="cx">     repatchBuffer.replaceWithJump(
</span><span class="cx">         RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo.hotPathBegin()),
</span><span class="cx">         CodeLocationLabel(stubRoutine-&gt;code().code()));
</span><del>-    // This is weird. The original slow path should no longer be reachable.
-    linkSlowFor(repatchBuffer, vm, callLinkInfo, CodeForCall, registers);
</del><ins>+
+    // The real slow path is unreachable on 64 bit platforms, but not
+    // on 32 bit platform, since the cell check is performed before
+    // taking the polymorphic path on 32 bit platforms
+    repatchBuffer.relink(
+        callLinkInfo.callReturnLocation(),
+        slowPathCodePtr,
+        callLinkInfo.callType());
</ins><span class="cx">     
</span><span class="cx">     // If there had been a previous stub routine, that one will die as soon as the GC runs and sees
</span><span class="cx">     // that it's no longer on stack.
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitThunkGeneratorscpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.cpp (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.cpp        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -77,7 +77,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void slowPathFor(
</span><del>-    CCallHelpers&amp; jit, VM* vm, P_JITOperation_ECli slowPathFunction)
</del><ins>+    CCallHelpers&amp; jit, VM* vm, Sprt_JITOperation_ECli slowPathFunction, CallLinkInfo::CallType callType)
</ins><span class="cx"> {
</span><span class="cx">     jit.emitFunctionPrologue();
</span><span class="cx">     jit.storePtr(GPRInfo::callFrameRegister, &amp;vm-&gt;topCallFrame);
</span><span class="lines">@@ -89,80 +89,166 @@
</span><span class="cx">     jit.call(GPRInfo::nonArgGPR0);
</span><span class="cx">     if (maxFrameExtentForSlowPathCall)
</span><span class="cx">         jit.addPtr(CCallHelpers::TrustedImm32(maxFrameExtentForSlowPathCall), CCallHelpers::stackPointerRegister);
</span><del>-    
</del><ins>+
</ins><span class="cx">     // This slow call will return the address of one of the following:
</span><span class="cx">     // 1) Exception throwing thunk.
</span><span class="cx">     // 2) Host call return value returner thingy.
</span><span class="cx">     // 3) The function to call.
</span><ins>+    // The second return value GPR will hold a zero value in case 1
+    // (we must not trash our own frame, since we won't ever perform
+    // the actual call) and a non-zero value in all other cases (we
+    // must replace our own frame).
+
</ins><span class="cx">     emitPointerValidation(jit, GPRInfo::returnValueGPR);
</span><span class="cx">     jit.emitFunctionEpilogue();
</span><ins>+
+    CCallHelpers::Jump doNotTrash = jit.branchTestPtr(CCallHelpers::Zero, GPRInfo::returnValueGPR2);
+
+    if (CallLinkInfo::isTailCallType(callType)) {
+        jit.preserveReturnAddressAfterCall(GPRInfo::nonPreservedNonReturnGPR);
+        jit.move(GPRInfo::returnValueGPR, GPRInfo::regT4); // FIXME
+        prepareForTailCall(jit);
+        jit.jump(GPRInfo::regT4);
+    }
+    doNotTrash.link(&amp;jit);
</ins><span class="cx">     jit.jump(GPRInfo::returnValueGPR);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static MacroAssemblerCodeRef linkForThunkGenerator(
-    VM* vm, CodeSpecializationKind kind, RegisterPreservationMode registers)
</del><ins>+static MacroAssemblerCodeRef linkThunkFor(
+    VM* vm, CallLinkInfo&amp; callLinkInfo, CodeSpecializationKind kind, RegisterPreservationMode registers)
</ins><span class="cx"> {
</span><span class="cx">     // The return address is on the stack or in the link register. We will hence
</span><span class="cx">     // save the return address to the call frame while we make a C++ function call
</span><span class="cx">     // to perform linking and lazy compilation if necessary. We expect the callee
</span><span class="cx">     // to be in regT0/regT1 (payload/tag), the CallFrame to have already
</span><span class="cx">     // been adjusted, and all other registers to be available for use.
</span><del>-    
</del><span class="cx">     CCallHelpers jit(vm);
</span><span class="cx">     
</span><del>-    slowPathFor(jit, vm, operationLinkFor(kind, registers));
</del><ins>+    slowPathFor(jit, vm, operationLinkFor(kind, registers), callLinkInfo.callType());
</ins><span class="cx">     
</span><span class="cx">     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><span class="cx">     return FINALIZE_CODE(
</span><span class="cx">         patchBuffer,
</span><del>-        (&quot;Link %s%s slow path thunk&quot;, kind == CodeForCall ? &quot;call&quot; : &quot;construct&quot;, registers == MustPreserveRegisters ? &quot; that preserves registers&quot; : &quot;&quot;));
</del><ins>+        (&quot;Link %s%s%s slow path thunk&quot;,
+            CallLinkInfo::isTailCallType(callLinkInfo.callType()) ? &quot;tail &quot; : &quot;&quot;,
+            kind == CodeForCall ? &quot;call&quot; : &quot;construct&quot;,
+            registers == MustPreserveRegisters ? &quot; that preserves registers&quot; : &quot;&quot;));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MacroAssemblerCodeRef linkCallThunk(
+    VM* vm, CallLinkInfo&amp; callLinkInfo, CodeSpecializationKind kind, RegisterPreservationMode registers)
+{
+    if (CallLinkInfo::isTailCallType(callLinkInfo.callType())) {
+        RefPtr&lt;GCAwareJITStubRoutine&gt; stubRoutine =
+            adoptRef(new GCAwareJITStubRoutine(
+                linkThunkFor(vm, callLinkInfo, kind, registers), *vm));
+        callLinkInfo.setSlowStub(stubRoutine.release());
+        return callLinkInfo.slowStub()-&gt;code();
+    }
+
+    callLinkInfo.clearSlowStub();
+
+    ThunkGenerator generator;
+
+    switch (kind) {
+    case CodeForCall:
+        switch (registers) {
+        case RegisterPreservationNotRequired:
+            generator = linkCallThunkGenerator;
+            break;
+        case MustPreserveRegisters:
+            generator = linkCallThatPreservesRegsThunkGenerator;
+            break;
+        }
+        break;
+    case CodeForConstruct:
+        switch (registers) {
+        case RegisterPreservationNotRequired:
+            generator = linkConstructThunkGenerator;
+            break;
+        case MustPreserveRegisters:
+            generator = linkConstructThatPreservesRegsThunkGenerator;
+            break;
+        }
+        break;
+    }
+
+    return vm-&gt;getCTIStub(generator);
+}
+
</ins><span class="cx"> MacroAssemblerCodeRef linkCallThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return linkForThunkGenerator(vm, CodeForCall, RegisterPreservationNotRequired);
</del><ins>+    return linkThunkFor(vm, CallLinkInfo::dummy(), CodeForCall, RegisterPreservationNotRequired);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef linkConstructThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return linkForThunkGenerator(vm, CodeForConstruct, RegisterPreservationNotRequired);
</del><ins>+    return linkThunkFor(vm, CallLinkInfo::dummy(), CodeForConstruct, RegisterPreservationNotRequired);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef linkCallThatPreservesRegsThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return linkForThunkGenerator(vm, CodeForCall, MustPreserveRegisters);
</del><ins>+    return linkThunkFor(vm, CallLinkInfo::dummy(), CodeForCall, MustPreserveRegisters);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef linkConstructThatPreservesRegsThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return linkForThunkGenerator(vm, CodeForConstruct, MustPreserveRegisters);
</del><ins>+    return linkThunkFor(vm, CallLinkInfo::dummy(), CodeForConstruct, MustPreserveRegisters);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static MacroAssemblerCodeRef linkPolymorphicCallForThunkGenerator(
-    VM* vm, RegisterPreservationMode registers)
</del><ins>+// For closure optimizations, we only include calls, since if you're using closures for
+// object construction then you're going to lose big time anyway.
+static MacroAssemblerCodeRef linkPolymorphicCallThunkFor(VM* vm, CallLinkInfo&amp; callLinkInfo, RegisterPreservationMode registers)
</ins><span class="cx"> {
</span><span class="cx">     CCallHelpers jit(vm);
</span><span class="cx">     
</span><del>-    slowPathFor(jit, vm, operationLinkPolymorphicCallFor(registers));
</del><ins>+    slowPathFor(jit, vm, operationLinkPolymorphicCallFor(registers), callLinkInfo.callType());
</ins><span class="cx">     
</span><span class="cx">     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><del>-    return FINALIZE_CODE(patchBuffer, (&quot;Link polymorphic call %s slow path thunk&quot;, registers == MustPreserveRegisters ? &quot; that preserves registers&quot; : &quot;&quot;));
</del><ins>+    return FINALIZE_CODE(patchBuffer,
+        (&quot;Link polymorphic %s%s slow path thunk&quot;,
+            CallLinkInfo::isTailCallType(callLinkInfo.callType()) ? &quot;tail call&quot; : &quot;call&quot;,
+            registers == MustPreserveRegisters ? &quot; that preserves registers&quot; : &quot;&quot;));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-// For closure optimizations, we only include calls, since if you're using closures for
-// object construction then you're going to lose big time anyway.
</del><ins>+MacroAssemblerCodeRef linkPolymorphicCallThunk(VM* vm, CallLinkInfo&amp; callLinkInfo, RegisterPreservationMode registers)
+{
+    if (CallLinkInfo::isTailCallType(callLinkInfo.callType())) {
+        RefPtr&lt;GCAwareJITStubRoutine&gt; stubRoutine =
+            adoptRef(new GCAwareJITStubRoutine(
+                linkPolymorphicCallThunkFor(vm, callLinkInfo, registers), *vm));
+        callLinkInfo.setSlowStub(stubRoutine.release());
+        return callLinkInfo.slowStub()-&gt;code();
+    }
+
+    callLinkInfo.clearSlowStub();
+
+    ThunkGenerator generator;
+
+    switch (registers) {
+    case RegisterPreservationNotRequired:
+        generator = linkPolymorphicCallThunkGenerator;
+        break;
+    case MustPreserveRegisters:
+        generator = linkPolymorphicCallThatPreservesRegsThunkGenerator;
+        break;
+    }
+
+    return vm-&gt;getCTIStub(generator);
+}
+
</ins><span class="cx"> MacroAssemblerCodeRef linkPolymorphicCallThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return linkPolymorphicCallForThunkGenerator(vm, RegisterPreservationNotRequired);
</del><ins>+    return linkPolymorphicCallThunkFor(vm, CallLinkInfo::dummy(), RegisterPreservationNotRequired);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef linkPolymorphicCallThatPreservesRegsThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return linkPolymorphicCallForThunkGenerator(vm, MustPreserveRegisters);
</del><ins>+    return linkPolymorphicCallThunkFor(vm, CallLinkInfo::dummy(), MustPreserveRegisters);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static MacroAssemblerCodeRef virtualForThunkGenerator(
-    VM* vm, CodeSpecializationKind kind, RegisterPreservationMode registers)
</del><ins>+static MacroAssemblerCodeRef virtualThunkFor(
+    VM* vm, CallLinkInfo&amp; callLinkInfo, CodeSpecializationKind kind, RegisterPreservationMode registers)
</ins><span class="cx"> {
</span><span class="cx">     // The callee is in regT0 (for JSVALUE32_64, the tag is in regT1).
</span><span class="cx">     // The return address is on the stack, or in the link register. We will hence
</span><span class="lines">@@ -217,38 +303,86 @@
</span><span class="cx">     
</span><span class="cx">     // Make a tail call. This will return back to JIT code.
</span><span class="cx">     emitPointerValidation(jit, GPRInfo::regT4);
</span><ins>+    if (CallLinkInfo::isTailCallType(callLinkInfo.callType())) {
+        jit.preserveReturnAddressAfterCall(GPRInfo::regT0);
+        prepareForTailCall(jit);
+    }
</ins><span class="cx">     jit.jump(GPRInfo::regT4);
</span><span class="cx"> 
</span><span class="cx">     slowCase.link(&amp;jit);
</span><span class="cx">     
</span><span class="cx">     // Here we don't know anything, so revert to the full slow path.
</span><ins>+
+    slowPathFor(jit, vm, operationVirtualFor(kind, registers), callLinkInfo.callType());
</ins><span class="cx">     
</span><del>-    slowPathFor(jit, vm, operationVirtualFor(kind, registers));
-    
</del><span class="cx">     LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
</span><span class="cx">     return FINALIZE_CODE(
</span><span class="cx">         patchBuffer,
</span><del>-        (&quot;Virtual %s%s slow path thunk&quot;, kind == CodeForCall ? &quot;call&quot; : &quot;construct&quot;, registers == MustPreserveRegisters ? &quot; that preserves registers&quot; : &quot;&quot;));
</del><ins>+        (&quot;Virtual %s%s%s slow path thunk&quot;,
+            CallLinkInfo::isTailCallType(callLinkInfo.callType()) ? &quot;tail &quot; : &quot;&quot;,
+            kind == CodeForCall ? &quot;call&quot; : &quot;construct&quot;,
+            registers == MustPreserveRegisters ? &quot; that preserves registers&quot; : &quot;&quot;));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MacroAssemblerCodeRef virtualThunk(
+    VM* vm, CallLinkInfo&amp; callLinkInfo, CodeSpecializationKind kind, RegisterPreservationMode registers)
+{
+    if (CallLinkInfo::isTailCallType(callLinkInfo.callType())) {
+        RefPtr&lt;GCAwareJITStubRoutine&gt; stubRoutine =
+            adoptRef(new GCAwareJITStubRoutine(
+                virtualThunkFor(vm, callLinkInfo, kind, registers), *vm));
+        callLinkInfo.setSlowStub(stubRoutine.release());
+        return callLinkInfo.slowStub()-&gt;code();
+    }
+
+    callLinkInfo.clearSlowStub();
+
+    ThunkGenerator generator;
+
+    switch (kind) {
+    case CodeForCall:
+        switch (registers) {
+        case RegisterPreservationNotRequired:
+            generator = virtualCallThunkGenerator;
+            break;
+        case MustPreserveRegisters:
+            generator = virtualCallThatPreservesRegsThunkGenerator;
+            break;
+        }
+        break;
+    case CodeForConstruct:
+        switch (registers) {
+        case RegisterPreservationNotRequired:
+            generator = virtualConstructThunkGenerator;
+            break;
+        case MustPreserveRegisters:
+            generator = virtualConstructThatPreservesRegsThunkGenerator;
+            break;
+        }
+        break;
+    }
+
+    return vm-&gt;getCTIStub(generator);
+}
+
</ins><span class="cx"> MacroAssemblerCodeRef virtualCallThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return virtualForThunkGenerator(vm, CodeForCall, RegisterPreservationNotRequired);
</del><ins>+    return virtualThunkFor(vm, CallLinkInfo::dummy(), CodeForCall, RegisterPreservationNotRequired);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef virtualConstructThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return virtualForThunkGenerator(vm, CodeForConstruct, RegisterPreservationNotRequired);
</del><ins>+    return virtualThunkFor(vm, CallLinkInfo::dummy(), CodeForConstruct, RegisterPreservationNotRequired);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef virtualCallThatPreservesRegsThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return virtualForThunkGenerator(vm, CodeForCall, MustPreserveRegisters);
</del><ins>+    return virtualThunkFor(vm, CallLinkInfo::dummy(), CodeForCall, MustPreserveRegisters);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> MacroAssemblerCodeRef virtualConstructThatPreservesRegsThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><del>-    return virtualForThunkGenerator(vm, CodeForConstruct, MustPreserveRegisters);
</del><ins>+    return virtualThunkFor(vm, CallLinkInfo::dummy(), CodeForConstruct, MustPreserveRegisters);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> enum ThunkEntryType { EnterViaCall, EnterViaJump };
</span><span class="lines">@@ -489,6 +623,61 @@
</span><span class="cx">     return FINALIZE_CODE(patchBuffer, (&quot;fixup arity&quot;));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+MacroAssemblerCodeRef unreachableGenerator(VM* vm)
+{
+    JSInterfaceJIT jit(vm);
+
+    jit.breakpoint();
+
+    LinkBuffer patchBuffer(*vm, jit, GLOBAL_THUNK_ID);
+    return FINALIZE_CODE(patchBuffer, (&quot;unreachable thunk&quot;));
+}
+
+void prepareForTailCall(CCallHelpers&amp; jit)
+{
+    jit.subPtr(CCallHelpers::TrustedImm32(sizeof(CallerFrameAndPC)), JSInterfaceJIT::stackPointerRegister);
+    jit.loadPtr(CCallHelpers::Address(JSInterfaceJIT::callFrameRegister), JSInterfaceJIT::regT1);
+    jit.storePtr(JSInterfaceJIT::regT1, CCallHelpers::Address(JSInterfaceJIT::stackPointerRegister));
+    jit.loadPtr(CCallHelpers::Address(JSInterfaceJIT::callFrameRegister, sizeof(void*)), JSInterfaceJIT::regT1);
+    jit.storePtr(JSInterfaceJIT::regT1, CCallHelpers::Address(JSInterfaceJIT::stackPointerRegister, sizeof(void*)));
+
+    // Now stackPointerRegister points to a valid call frame for the callee
+    // and callFrameRegister points to our own call frame.
+    // We now slide the callee's call frame over our own call frame,
+    // starting with the top to avoid unwanted overwrites
+
+    // Move the callFrameRegister to the top of our (trashed) call frame
+    jit.load32(CCallHelpers::Address(JSInterfaceJIT::callFrameRegister, JSStack::ArgumentCount * static_cast&lt;int&gt;(sizeof(Register)) + PayloadOffset),
+        JSInterfaceJIT::regT1);
+    jit.add32(CCallHelpers::TrustedImm32(stackAlignmentRegisters() + JSStack::CallFrameHeaderSize - 1), JSInterfaceJIT::regT1);
+    jit.and32(CCallHelpers::TrustedImm32(-stackAlignmentRegisters()), JSInterfaceJIT::regT1);
+    jit.mul32(CCallHelpers::TrustedImm32(sizeof(Register)), JSInterfaceJIT::regT1, JSInterfaceJIT::regT1);
+    jit.addPtr(JSInterfaceJIT::regT1, JSInterfaceJIT::callFrameRegister);
+
+    // Compute the call frame size of the callee's call frame
+    jit.load32(CCallHelpers::Address(JSInterfaceJIT::stackPointerRegister, JSStack::ArgumentCount * static_cast&lt;int&gt;(sizeof(Register)) + PayloadOffset),
+        JSInterfaceJIT::regT2);
+    jit.add32(CCallHelpers::TrustedImm32(stackAlignmentRegisters() + JSStack::CallFrameHeaderSize - 1), JSInterfaceJIT::regT2);
+    jit.and32(CCallHelpers::TrustedImm32(-stackAlignmentRegisters()), JSInterfaceJIT::regT2);
+
+#if USE(JSVALUE32_64)
+    COMPILE_ASSERT(sizeof(void*) * 2 == sizeof(Register), Register_is_two_pointers_sized);
+    jit.lshift32(CCallHelpers::TrustedImm32(1), JSInterfaceJIT::regT2);
+#endif
+
+    // Do the sliding
+    MacroAssembler::Label copyLoop(jit.label());
+
+    jit.subPtr(CCallHelpers::TrustedImm32(sizeof(void*)), JSInterfaceJIT::callFrameRegister);
+    jit.sub32(CCallHelpers::TrustedImm32(1), JSInterfaceJIT::regT2);
+    jit.loadPtr(CCallHelpers::BaseIndex(JSInterfaceJIT::stackPointerRegister, JSInterfaceJIT::regT2, MacroAssembler::timesPtr()), JSInterfaceJIT::regT1);
+    jit.storePtr(JSInterfaceJIT::regT1, CCallHelpers::Address(JSInterfaceJIT::callFrameRegister));
+
+    jit.branchTest32(MacroAssembler::NonZero, JSInterfaceJIT::regT2).linkTo(copyLoop, &amp;jit);
+
+    jit.emitFunctionEpilogue();
+}
+
</ins><span class="cx"> MacroAssemblerCodeRef baselineGetterReturnThunkGenerator(VM* vm)
</span><span class="cx"> {
</span><span class="cx">     JSInterfaceJIT jit(vm);
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitThunkGeneratorsh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.h (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.h        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/ThunkGenerators.h        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -33,88 +33,35 @@
</span><span class="cx"> #if ENABLE(JIT)
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+class CallLinkInfo;
+class CCallHelpers;
+
</ins><span class="cx"> MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(VM*);
</span><span class="cx"> 
</span><ins>+MacroAssemblerCodeRef linkCallThunk(VM*, CallLinkInfo&amp;, CodeSpecializationKind, RegisterPreservationMode);
</ins><span class="cx"> MacroAssemblerCodeRef linkCallThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef linkConstructThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef linkCallThatPreservesRegsThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef linkConstructThatPreservesRegsThunkGenerator(VM*);
</span><span class="cx"> 
</span><del>-inline ThunkGenerator linkThunkGeneratorFor(
-    CodeSpecializationKind kind, RegisterPreservationMode registers)
-{
-    switch (kind) {
-    case CodeForCall:
-        switch (registers) {
-        case RegisterPreservationNotRequired:
-            return linkCallThunkGenerator;
-        case MustPreserveRegisters:
-            return linkCallThatPreservesRegsThunkGenerator;
-        }
-        break;
-    case CodeForConstruct:
-        switch (registers) {
-        case RegisterPreservationNotRequired:
-            return linkConstructThunkGenerator;
-        case MustPreserveRegisters:
-            return linkConstructThatPreservesRegsThunkGenerator;
-        }
-        break;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return 0;
-}
-
</del><ins>+MacroAssemblerCodeRef linkPolymorphicCallThunk(VM*, CallLinkInfo&amp;, RegisterPreservationMode);
</ins><span class="cx"> MacroAssemblerCodeRef linkPolymorphicCallThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef linkPolymorphicCallThatPreservesRegsThunkGenerator(VM*);
</span><span class="cx"> 
</span><del>-inline ThunkGenerator linkPolymorphicCallThunkGeneratorFor(RegisterPreservationMode registers)
-{
-    switch (registers) {
-    case RegisterPreservationNotRequired:
-        return linkPolymorphicCallThunkGenerator;
-    case MustPreserveRegisters:
-        return linkPolymorphicCallThatPreservesRegsThunkGenerator;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return 0;
-}
-
</del><ins>+MacroAssemblerCodeRef virtualThunk(VM*, CallLinkInfo&amp;, CodeSpecializationKind, RegisterPreservationMode);
</ins><span class="cx"> MacroAssemblerCodeRef virtualCallThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef virtualConstructThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef virtualCallThatPreservesRegsThunkGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef virtualConstructThatPreservesRegsThunkGenerator(VM*);
</span><span class="cx"> 
</span><del>-inline ThunkGenerator virtualThunkGeneratorFor(
-    CodeSpecializationKind kind, RegisterPreservationMode registers)
-{
-    switch (kind) {
-    case CodeForCall:
-        switch (registers) {
-        case RegisterPreservationNotRequired:
-            return virtualCallThunkGenerator;
-        case MustPreserveRegisters:
-            return virtualCallThatPreservesRegsThunkGenerator;
-        }
-        break;
-    case CodeForConstruct:
-        switch (registers) {
-        case RegisterPreservationNotRequired:
-            return virtualConstructThunkGenerator;
-        case MustPreserveRegisters:
-            return virtualConstructThatPreservesRegsThunkGenerator;
-        }
-        break;
-    }
-    RELEASE_ASSERT_NOT_REACHED();
-    return 0;
-}
-
</del><span class="cx"> MacroAssemblerCodeRef nativeCallGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef nativeConstructGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef nativeTailCallGenerator(VM*);
</span><span class="cx"> MacroAssemblerCodeRef arityFixupGenerator(VM*);
</span><ins>+MacroAssemblerCodeRef unreachableGenerator(VM*);
</ins><span class="cx"> 
</span><ins>+void prepareForTailCall(CCallHelpers&amp; jit);
+
</ins><span class="cx"> MacroAssemblerCodeRef baselineGetterReturnThunkGenerator(VM* vm);
</span><span class="cx"> MacroAssemblerCodeRef baselineSetterReturnThunkGenerator(VM* vm);
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorellintLowLevelInterpreterasm"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter.asm (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter.asm        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -595,36 +595,60 @@
</span><span class="cx">     end
</span><span class="cx"> end
</span><span class="cx"> 
</span><del>-macro callTargetFunction(callLinkInfo, calleeFramePtr)
-    move calleeFramePtr, sp
</del><ins>+macro callTargetFunction(callee)
</ins><span class="cx">     if C_LOOP
</span><del>-        cloopCallJSFunction LLIntCallLinkInfo::machineCodeTarget[callLinkInfo]
</del><ins>+        cloopCallJSFunction callee
</ins><span class="cx">     else
</span><del>-        call LLIntCallLinkInfo::machineCodeTarget[callLinkInfo]
</del><ins>+        call callee
</ins><span class="cx">     end
</span><span class="cx">     restoreStackPointerAfterCall()
</span><span class="cx">     dispatchAfterCall()
</span><span class="cx"> end
</span><span class="cx"> 
</span><del>-macro slowPathForCall(slowPath)
</del><ins>+macro prepareForRegularCall(callee, temp1, temp2)
+    addp CallerFrameAndPCSize, sp
+end
+
+macro getFrameSize(frame, dst)
+    loadi PayloadOffset + ArgumentCount[frame], dst
+    mulp SlotSize, dst
+    addp StackAlignment - 1 + CallFrameHeaderSize, dst
+    andp ~StackAlignmentMask, dst
+end
+
+# sp points to the new frame
+macro prepareForTailCall(callee, temp1, temp2)
+    # Masquerade ourselves as our own caller
+    loadp CallerFrame[cfr], temp1
+    loadp ReturnPC[cfr], temp2
+    storep temp1, CallerFrame[sp]
+    storep temp2, ReturnPC[sp]
+
+    # Slide the new call frame over the old one
+    getFrameSize(cfr, temp1)
+    addp temp1, cfr
+    getFrameSize(sp, temp2)
+
+.copyLoop:
+    subp PtrSize, cfr
+    subp PtrSize, temp2
+    loadp [sp, temp2, 1], temp1
+    storep temp1, [cfr]
+    btpnz temp2, .copyLoop
+    move cfr, sp
+    functionEpilogue()
+    jmp callee
+end
+
+macro slowPathForCall(slowPath, prepareCall)
</ins><span class="cx">     callCallSlowPath(
</span><span class="cx">         slowPath,
</span><del>-        macro (callee, calleeFrame)
-            btpz calleeFrame, .dontUpdateSP
-            if ARMv7
-                addp CallerFrameAndPCSize, calleeFrame, calleeFrame
-                move calleeFrame, sp
-            else
-                addp CallerFrameAndPCSize, calleeFrame, sp
-            end
</del><ins>+        macro (callee, calleeFramePtr)
+            btpz calleeFramePtr, .dontUpdateSP
+            move calleeFramePtr, sp
+            prepareCall(callee, t3, t4)
</ins><span class="cx">         .dontUpdateSP:
</span><del>-            if C_LOOP
-                cloopCallJSFunction callee
-            else
-                call callee
-            end
-            restoreStackPointerAfterCall()
-            dispatchAfterCall()
</del><ins>+            callTargetFunction(callee)
</ins><span class="cx">         end)
</span><span class="cx"> end
</span><span class="cx"> 
</span><span class="lines">@@ -1283,16 +1307,18 @@
</span><span class="cx"> _llint_op_call:
</span><span class="cx">     traceExecution()
</span><span class="cx">     arrayProfileForCall()
</span><del>-    doCall(_llint_slow_path_call)
</del><ins>+    doCall(_llint_slow_path_call, prepareForRegularCall)
</ins><span class="cx"> 
</span><ins>+_llint_op_tail_call:
+    traceExecution()
+    arrayProfileForCall()
+    doCall(_llint_slow_path_call, prepareForTailCall)
</ins><span class="cx"> 
</span><span class="cx"> _llint_op_construct:
</span><span class="cx">     traceExecution()
</span><del>-    doCall(_llint_slow_path_construct)
</del><ins>+    doCall(_llint_slow_path_construct, prepareForRegularCall)
</ins><span class="cx"> 
</span><del>-
-_llint_op_call_varargs:
-    traceExecution()
</del><ins>+macro doCallVarargs(slowPath, prepareCall)
</ins><span class="cx">     callSlowPath(_llint_slow_path_size_frame_for_varargs)
</span><span class="cx">     branchIfException(_llint_throw_from_slow_path_trampoline)
</span><span class="cx">     # calleeFrame in r1
</span><span class="lines">@@ -1307,25 +1333,22 @@
</span><span class="cx">             subp r1, CallerFrameAndPCSize, sp
</span><span class="cx">         end
</span><span class="cx">     end
</span><del>-    slowPathForCall(_llint_slow_path_call_varargs)
</del><ins>+    slowPathForCall(slowPath, prepareCall)
+end
</ins><span class="cx"> 
</span><ins>+_llint_op_call_varargs:
+    traceExecution()
+    doCallVarargs(_llint_slow_path_call_varargs, prepareForRegularCall)
+
+_llint_op_tail_call_varargs:
+    traceExecution()
+    # We lie and perform the tail call instead of preparing it since we can't
+    # prepare the frame for a call opcode
+    doCallVarargs(_llint_slow_path_call_varargs, prepareForTailCall)
+
</ins><span class="cx"> _llint_op_construct_varargs:
</span><span class="cx">     traceExecution()
</span><del>-    callSlowPath(_llint_slow_path_size_frame_for_varargs)
-    branchIfException(_llint_throw_from_slow_path_trampoline)
-    # calleeFrame in r1
-    if JSVALUE64
-        move r1, sp
-    else
-        # The calleeFrame is not stack aligned, move down by CallerFrameAndPCSize to align
-        if ARMv7
-            subp r1, CallerFrameAndPCSize, t2
-            move t2, sp
-        else
-            subp r1, CallerFrameAndPCSize, sp
-        end
-    end
-    slowPathForCall(_llint_slow_path_construct_varargs)
</del><ins>+    doCallVarargs(_llint_slow_path_construct_varargs, prepareForRegularCall)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _llint_op_call_eval:
</span><span class="lines">@@ -1364,7 +1387,7 @@
</span><span class="cx">     # and a PC to call, and that PC may be a dummy thunk that just
</span><span class="cx">     # returns the JS value that the eval returned.
</span><span class="cx">     
</span><del>-    slowPathForCall(_llint_slow_path_call_eval)
</del><ins>+    slowPathForCall(_llint_slow_path_call_eval, prepareForRegularCall)
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> _llint_generic_return_point:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorellintLowLevelInterpreter32_64asm"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1819,7 +1819,7 @@
</span><span class="cx"> .done:
</span><span class="cx"> end
</span><span class="cx"> 
</span><del>-macro doCall(slowPath)
</del><ins>+macro doCall(slowPath, prepareCall)
</ins><span class="cx">     loadi 8[PC], t0
</span><span class="cx">     loadi 20[PC], t1
</span><span class="cx">     loadp LLIntCallLinkInfo::callee[t1], t2
</span><span class="lines">@@ -1834,14 +1834,14 @@
</span><span class="cx">     storei PC, ArgumentCount + TagOffset[cfr]
</span><span class="cx">     storei t2, ArgumentCount + PayloadOffset[t3]
</span><span class="cx">     storei CellTag, Callee + TagOffset[t3]
</span><del>-    addp CallerFrameAndPCSize, t3
-    callTargetFunction(t1, t3)
</del><ins>+    move t3, sp
+    prepareCall(LLIntCallLinkInfo::machineCodeTarget[t1], t2, t3)
+    callTargetFunction(LLIntCallLinkInfo::machineCodeTarget[t1])
</ins><span class="cx"> 
</span><span class="cx"> .opCallSlow:
</span><del>-    slowPathForCall(slowPath)
</del><ins>+    slowPathForCall(slowPath, prepareCall)
</ins><span class="cx"> end
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> _llint_op_ret:
</span><span class="cx">     traceExecution()
</span><span class="cx">     checkSwitchToJITForEpilogue()
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (187165 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-07-22 17:21:14 UTC (rev 187165)
+++ branches/jsc-tailcall/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -1713,7 +1713,7 @@
</span><span class="cx"> .done:
</span><span class="cx"> end
</span><span class="cx"> 
</span><del>-macro doCall(slowPath)
</del><ins>+macro doCall(slowPath, prepareCall)
</ins><span class="cx">     loadisFromInstruction(2, t0)
</span><span class="cx">     loadpFromInstruction(5, t1)
</span><span class="cx">     loadp LLIntCallLinkInfo::callee[t1], t2
</span><span class="lines">@@ -1727,14 +1727,14 @@
</span><span class="cx">     loadisFromInstruction(3, t2)
</span><span class="cx">     storei PC, ArgumentCount + TagOffset[cfr]
</span><span class="cx">     storei t2, ArgumentCount + PayloadOffset[t3]
</span><del>-    addp CallerFrameAndPCSize, t3
-    callTargetFunction(t1, t3)
</del><ins>+    move t3, sp
+    prepareCall(LLIntCallLinkInfo::machineCodeTarget[t1], t2, t3)
+    callTargetFunction(LLIntCallLinkInfo::machineCodeTarget[t1])
</ins><span class="cx"> 
</span><span class="cx"> .opCallSlow:
</span><del>-    slowPathForCall(slowPath)
</del><ins>+    slowPathForCall(slowPath, prepareCall)
</ins><span class="cx"> end
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> _llint_op_ret:
</span><span class="cx">     traceExecution()
</span><span class="cx">     checkSwitchToJITForEpilogue()
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoretestsstressmutualtailcallnostackoverflowjs"></a>
<div class="addfile"><h4>Added: branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js (0 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js                                (rev 0)
+++ branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/mutual-tail-call-no-stack-overflow.js        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -0,0 +1,57 @@
</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);
</ins></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoretestsstresstailcallnostackoverflowjs"></a>
<div class="addfile"><h4>Added: branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js (0 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js                                (rev 0)
+++ branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-no-stack-overflow.js        2015-07-22 17:56:22 UTC (rev 187166)
</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="branchesjsctailcallSourceJavaScriptCoretestsstresstailcallrecognizejs"></a>
<div class="addfile"><h4>Added: branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-recognize.js (0 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-recognize.js                                (rev 0)
+++ branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-recognize.js        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -0,0 +1,177 @@
</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();
+    })();
+}
+
+runTests();
</ins></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoretestsstresstailcalltriggerjs"></a>
<div class="addfile"><h4>Added: branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-trigger.js (0 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-trigger.js                                (rev 0)
+++ branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-trigger.js        2015-07-22 17:56:22 UTC (rev 187166)
</span><span class="lines">@@ -0,0 +1,177 @@
</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();
+    })();
+}
+
+runTests();
</ins></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoretestsstresstailcallvarargsnostackoverflowjs"></a>
<div class="addfile"><h4>Added: branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js (0 => 187166)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js                                (rev 0)
+++ branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/tail-call-varargs-no-stack-overflow.js        2015-07-22 17:56:22 UTC (rev 187166)
</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>
</div>

</body>
</html>