<!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>[187791] branches/jsc-tailcall/Source/JavaScriptCore</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/187791">187791</a></dd>
<dt>Author</dt> <dd>basile_clement@apple.com</dd>
<dt>Date</dt> <dd>2015-08-03 17:39:19 -0700 (Mon, 03 Aug 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>jsc-tailcall: Implement the tail call opcodes in the DFG
https://bugs.webkit.org/show_bug.cgi?id=146850
Reviewed by Michael Saboff.
This patch adds support for tail calls in the DFG. This requires a slightly high number of nodes:
- TailCall and TailCallVarargs are straightforward. They are terminal
nodes and have the semantics of an actual tail call.
- TailCallInlinedCaller and TailCallVarargsInlinedCaller are here to perform a
tail call inside an inlined function. They are non terminal nodes,
and are performing the call as a regular call after popping an
appropriate number of inlined tail call frames.
- TailCallForwardVarargs and TailCallForwardVarargsInlinedCaller are the
extension of TailCallVarargs and TailCallVarargsInlinedCaller to enable
the varargs forwarding optimization so that we don't lose
performance with a tail call instead of a regular call.
This also required two broad kind of changes:
- Changes in the JIT itself (DFGSpeculativeJIT) are pretty
straightforward since they are just an extension of the baseline JIT
changes introduced previously.
- Changes in the runtime are mostly related with handling inline call
frames. The idea here is that we have a special TailCall type for
call frames that indicates to the various pieces of code walking the
inline call frame that they should (recursively) skip the caller in
their analysis.
* bytecode/CallMode.h:
(JSC::specializationKindFor):
* bytecode/CodeOrigin.cpp:
(JSC::CodeOrigin::inlineDepthForCallFrame):
(JSC::CodeOrigin::isApproximatelyEqualTo):
(JSC::CodeOrigin::approximateHash):
(JSC::CodeOrigin::inlineStack):
(JSC::InlineCallFrame::dumpInContext):
(WTF::printInternal):
* bytecode/CodeOrigin.h:
(JSC::InlineCallFrame::callModeFor):
(JSC::InlineCallFrame::kindFor):
(JSC::InlineCallFrame::varargsKindFor):
(JSC::InlineCallFrame::specializationKindFor):
(JSC::InlineCallFrame::isVarargs):
(JSC::InlineCallFrame::isTail):
(JSC::InlineCallFrame::computeCallerSkippingDeadFrames):
(JSC::InlineCallFrame::getCallerSkippingDeadFrames):
(JSC::InlineCallFrame::getCallerInlineFrameSkippingDeadFrames):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGArgumentsEliminationPhase.cpp:
* dfg/DFGBasicBlock.h:
(JSC::DFG::BasicBlock::findTerminal):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::allInlineFramesAreTailCalls):
(JSC::DFG::ByteCodeParser::addCallWithoutSettingResult):
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
(JSC::DFG::ByteCodeParser::getPrediction):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleVarargsCall):
(JSC::DFG::ByteCodeParser::inliningCost):
(JSC::DFG::ByteCodeParser::inlineCall):
(JSC::DFG::ByteCodeParser::attemptToInlineCall):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
(JSC::DFG::ByteCodeParser::parseCodeBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::isLiveInBytecode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::forAllLocalsLiveInBytecode):
* dfg/DFGInPlaceAbstractState.cpp:
(JSC::DFG::InPlaceAbstractState::mergeToSuccessors):
* dfg/DFGNode.h:
(JSC::DFG::Node::hasCallVarargsData):
(JSC::DFG::Node::isTerminal):
(JSC::DFG::Node::hasHeapPrediction):
* dfg/DFGNodeType.h:
* dfg/DFGOSRExitCompilerCommon.cpp:
(JSC::DFG::handleExitCounts):
(JSC::DFG::reifyInlinedCallFrames):
* dfg/DFGOSRExitPreparation.cpp:
(JSC::DFG::prepareCodeOriginForOSRExit):
* dfg/DFGOperations.cpp:
* dfg/DFGPreciseLocalClobberize.h:
(JSC::DFG::PreciseLocalClobberizeAdaptor::readTop):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGVarargsForwardingPhase.cpp:
* interpreter/CallFrame.cpp:
(JSC::CallFrame::bytecodeOffsetFromCodeOriginIndex):
* interpreter/StackVisitor.cpp:
(JSC::StackVisitor::gotoNextFrame):
* jit/CCallHelpers.h:
* tests/stress/dfg-tail-calls.js: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreChangeLog">branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeCallModeh">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallMode.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeCodeOrigincpp">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorebytecodeCodeOriginh">branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGArgumentsEliminationPhasecpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGBasicBlockh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGBasicBlock.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGCapabilitiescpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGCapabilities.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGClobberizeh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGDoesGCcpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGFixupPhasecpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGGraphcpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGGraphh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGNodeh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGNodeTypeh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGOSRExitCompilerCommoncpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGOSRExitPreparationcpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitPreparation.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGOperationscpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGPreciseLocalClobberizeh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGSafeToExecuteh">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoredfgDFGVarargsForwardingPhasecpp">branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreinterpreterCallFramecpp">branches/jsc-tailcall/Source/JavaScriptCore/interpreter/CallFrame.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCoreinterpreterStackVisitorcpp">branches/jsc-tailcall/Source/JavaScriptCore/interpreter/StackVisitor.cpp</a></li>
<li><a href="#branchesjsctailcallSourceJavaScriptCorejitCCallHelpersh">branches/jsc-tailcall/Source/JavaScriptCore/jit/CCallHelpers.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#branchesjsctailcallSourceJavaScriptCoretestsstressdfgtailcallsjs">branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesjsctailcallSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/ChangeLog        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -1,3 +1,119 @@
</span><ins>+2015-07-31 Basile Clement <basile_clement@apple.com>
+
+ jsc-tailcall: Implement the tail call opcodes in the DFG
+ https://bugs.webkit.org/show_bug.cgi?id=146850
+
+ Reviewed by Michael Saboff.
+
+ This patch adds support for tail calls in the DFG. This requires a slightly high number of nodes:
+
+ - TailCall and TailCallVarargs are straightforward. They are terminal
+ nodes and have the semantics of an actual tail call.
+
+ - TailCallInlinedCaller and TailCallVarargsInlinedCaller are here to perform a
+ tail call inside an inlined function. They are non terminal nodes,
+ and are performing the call as a regular call after popping an
+ appropriate number of inlined tail call frames.
+
+ - TailCallForwardVarargs and TailCallForwardVarargsInlinedCaller are the
+ extension of TailCallVarargs and TailCallVarargsInlinedCaller to enable
+ the varargs forwarding optimization so that we don't lose
+ performance with a tail call instead of a regular call.
+
+ This also required two broad kind of changes:
+
+ - Changes in the JIT itself (DFGSpeculativeJIT) are pretty
+ straightforward since they are just an extension of the baseline JIT
+ changes introduced previously.
+
+ - Changes in the runtime are mostly related with handling inline call
+ frames. The idea here is that we have a special TailCall type for
+ call frames that indicates to the various pieces of code walking the
+ inline call frame that they should (recursively) skip the caller in
+ their analysis.
+
+ * bytecode/CallMode.h:
+ (JSC::specializationKindFor):
+ * bytecode/CodeOrigin.cpp:
+ (JSC::CodeOrigin::inlineDepthForCallFrame):
+ (JSC::CodeOrigin::isApproximatelyEqualTo):
+ (JSC::CodeOrigin::approximateHash):
+ (JSC::CodeOrigin::inlineStack):
+ (JSC::InlineCallFrame::dumpInContext):
+ (WTF::printInternal):
+ * bytecode/CodeOrigin.h:
+ (JSC::InlineCallFrame::callModeFor):
+ (JSC::InlineCallFrame::kindFor):
+ (JSC::InlineCallFrame::varargsKindFor):
+ (JSC::InlineCallFrame::specializationKindFor):
+ (JSC::InlineCallFrame::isVarargs):
+ (JSC::InlineCallFrame::isTail):
+ (JSC::InlineCallFrame::computeCallerSkippingDeadFrames):
+ (JSC::InlineCallFrame::getCallerSkippingDeadFrames):
+ (JSC::InlineCallFrame::getCallerInlineFrameSkippingDeadFrames):
+ * dfg/DFGAbstractInterpreterInlines.h:
+ (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+ * dfg/DFGArgumentsEliminationPhase.cpp:
+ * dfg/DFGBasicBlock.h:
+ (JSC::DFG::BasicBlock::findTerminal):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::allInlineFramesAreTailCalls):
+ (JSC::DFG::ByteCodeParser::addCallWithoutSettingResult):
+ (JSC::DFG::ByteCodeParser::addCall):
+ (JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
+ (JSC::DFG::ByteCodeParser::getPrediction):
+ (JSC::DFG::ByteCodeParser::handleCall):
+ (JSC::DFG::ByteCodeParser::handleVarargsCall):
+ (JSC::DFG::ByteCodeParser::inliningCost):
+ (JSC::DFG::ByteCodeParser::inlineCall):
+ (JSC::DFG::ByteCodeParser::attemptToInlineCall):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+ (JSC::DFG::ByteCodeParser::parseCodeBlock):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGClobberize.h:
+ (JSC::DFG::clobberize):
+ * dfg/DFGDoesGC.cpp:
+ (JSC::DFG::doesGC):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGGraph.cpp:
+ (JSC::DFG::Graph::isLiveInBytecode):
+ * dfg/DFGGraph.h:
+ (JSC::DFG::Graph::forAllLocalsLiveInBytecode):
+ * dfg/DFGInPlaceAbstractState.cpp:
+ (JSC::DFG::InPlaceAbstractState::mergeToSuccessors):
+ * dfg/DFGNode.h:
+ (JSC::DFG::Node::hasCallVarargsData):
+ (JSC::DFG::Node::isTerminal):
+ (JSC::DFG::Node::hasHeapPrediction):
+ * dfg/DFGNodeType.h:
+ * dfg/DFGOSRExitCompilerCommon.cpp:
+ (JSC::DFG::handleExitCounts):
+ (JSC::DFG::reifyInlinedCallFrames):
+ * dfg/DFGOSRExitPreparation.cpp:
+ (JSC::DFG::prepareCodeOriginForOSRExit):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGPreciseLocalClobberize.h:
+ (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSafeToExecute.h:
+ (JSC::DFG::safeToExecute):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGVarargsForwardingPhase.cpp:
+ * interpreter/CallFrame.cpp:
+ (JSC::CallFrame::bytecodeOffsetFromCodeOriginIndex):
+ * interpreter/StackVisitor.cpp:
+ (JSC::StackVisitor::gotoNextFrame):
+ * jit/CCallHelpers.h:
+ * tests/stress/dfg-tail-calls.js: Added.
+
</ins><span class="cx"> 2015-08-03 Basile Clement <basile_clement@apple.com>
</span><span class="cx">
</span><span class="cx"> jsc-tailcall: Kraken/stanford-crypto-ccm crashes
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeCallModeh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallMode.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallMode.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CallMode.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -26,12 +26,26 @@
</span><span class="cx"> #ifndef CallMode_h
</span><span class="cx"> #define CallMode_h
</span><span class="cx">
</span><ins>+#include "CodeSpecializationKind.h"
+
</ins><span class="cx"> namespace JSC {
</span><span class="cx">
</span><span class="cx"> enum class CallMode { Regular, Tail, Construct };
</span><span class="cx">
</span><span class="cx"> enum FrameAction { KeepTheFrame = 0, ReuseTheFrame };
</span><span class="cx">
</span><ins>+inline CodeSpecializationKind specializationKindFor(CallMode callMode)
+{
+ switch (callMode) {
+ case CallMode::Tail:
+ case CallMode::Regular:
+ return CodeForCall;
+
+ case CallMode::Construct:
+ return CodeForConstruct;
+ }
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx">
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeCodeOrigincpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> unsigned CodeOrigin::inlineDepthForCallFrame(InlineCallFrame* inlineCallFrame)
</span><span class="cx"> {
</span><span class="cx"> unsigned result = 1;
</span><del>- for (InlineCallFrame* current = inlineCallFrame; current; current = current->caller.inlineCallFrame)
</del><ins>+ for (InlineCallFrame* current = inlineCallFrame; current; current = current->directCaller.inlineCallFrame)
</ins><span class="cx"> result++;
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="lines">@@ -77,8 +77,8 @@
</span><span class="cx"> if (a.inlineCallFrame->executable.get() != b.inlineCallFrame->executable.get())
</span><span class="cx"> return false;
</span><span class="cx">
</span><del>- a = a.inlineCallFrame->caller;
- b = b.inlineCallFrame->caller;
</del><ins>+ a = a.inlineCallFrame->directCaller;
+ b = b.inlineCallFrame->directCaller;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -99,7 +99,7 @@
</span><span class="cx">
</span><span class="cx"> result += WTF::PtrHash<JSCell*>::hash(codeOrigin.inlineCallFrame->executable.get());
</span><span class="cx">
</span><del>- codeOrigin = codeOrigin.inlineCallFrame->caller;
</del><ins>+ codeOrigin = codeOrigin.inlineCallFrame->directCaller;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -108,8 +108,8 @@
</span><span class="cx"> Vector<CodeOrigin> result(inlineDepth());
</span><span class="cx"> result.last() = *this;
</span><span class="cx"> unsigned index = result.size() - 2;
</span><del>- for (InlineCallFrame* current = inlineCallFrame; current; current = current->caller.inlineCallFrame)
- result[index--] = current->caller;
</del><ins>+ for (InlineCallFrame* current = inlineCallFrame; current; current = current->directCaller.inlineCallFrame)
+ result[index--] = current->directCaller;
</ins><span class="cx"> RELEASE_ASSERT(!result[0].inlineCallFrame);
</span><span class="cx"> return result;
</span><span class="cx"> }
</span><span class="lines">@@ -190,7 +190,7 @@
</span><span class="cx"> out.print(briefFunctionInformation(), ":<", RawPointer(executable.get()));
</span><span class="cx"> if (executable->isStrictMode())
</span><span class="cx"> out.print(" (StrictMode)");
</span><del>- out.print(", bc#", caller.bytecodeIndex, ", ", kind);
</del><ins>+ out.print(", bc#", directCaller.bytecodeIndex, ", ", static_cast<Kind>(kind));
</ins><span class="cx"> if (isClosureCall)
</span><span class="cx"> out.print(", closure call");
</span><span class="cx"> else
</span><span class="lines">@@ -218,12 +218,18 @@
</span><span class="cx"> case JSC::InlineCallFrame::Construct:
</span><span class="cx"> out.print("Construct");
</span><span class="cx"> return;
</span><ins>+ case JSC::InlineCallFrame::TailCall:
+ out.print("TailCall");
+ return;
</ins><span class="cx"> case JSC::InlineCallFrame::CallVarargs:
</span><span class="cx"> out.print("CallVarargs");
</span><span class="cx"> return;
</span><span class="cx"> case JSC::InlineCallFrame::ConstructVarargs:
</span><span class="cx"> out.print("ConstructVarargs");
</span><span class="cx"> return;
</span><ins>+ case JSC::InlineCallFrame::TailCallVarargs:
+ out.print("TailCallVarargs");
+ return;
</ins><span class="cx"> case JSC::InlineCallFrame::GetterCall:
</span><span class="cx"> out.print("GetterCall");
</span><span class="cx"> return;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorebytecodeCodeOriginh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/bytecode/CodeOrigin.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #ifndef CodeOrigin_h
</span><span class="cx"> #define CodeOrigin_h
</span><span class="cx">
</span><ins>+#include "CallMode.h"
</ins><span class="cx"> #include "CodeBlockHash.h"
</span><span class="cx"> #include "CodeSpecializationKind.h"
</span><span class="cx"> #include "ValueRecovery.h"
</span><span class="lines">@@ -120,37 +121,58 @@
</span><span class="cx"> enum Kind {
</span><span class="cx"> Call,
</span><span class="cx"> Construct,
</span><ins>+ TailCall,
</ins><span class="cx"> CallVarargs,
</span><span class="cx"> ConstructVarargs,
</span><ins>+ TailCallVarargs,
</ins><span class="cx">
</span><span class="cx"> // For these, the stackOffset incorporates the argument count plus the true return PC
</span><span class="cx"> // slot.
</span><span class="cx"> GetterCall,
</span><span class="cx"> SetterCall
</span><span class="cx"> };
</span><del>-
- static Kind kindFor(CodeSpecializationKind kind)
</del><ins>+
+ static CallMode callModeFor(Kind kind)
</ins><span class="cx"> {
</span><span class="cx"> switch (kind) {
</span><del>- case CodeForCall:
</del><ins>+ case Call:
+ case CallVarargs:
+ case GetterCall:
+ case SetterCall:
+ return CallMode::Regular;
+ case TailCall:
+ case TailCallVarargs:
+ return CallMode::Tail;
+ case Construct:
+ case ConstructVarargs:
+ return CallMode::Construct;
+ }
+ }
+
+ static Kind kindFor(CallMode callMode)
+ {
+ switch (callMode) {
+ case CallMode::Regular:
</ins><span class="cx"> return Call;
</span><del>- case CodeForConstruct:
</del><ins>+ case CallMode::Construct:
</ins><span class="cx"> return Construct;
</span><ins>+ case CallMode::Tail:
+ return TailCall;
</ins><span class="cx"> }
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><del>- return Call;
</del><span class="cx"> }
</span><span class="cx">
</span><del>- static Kind varargsKindFor(CodeSpecializationKind kind)
</del><ins>+ static Kind varargsKindFor(CallMode callMode)
</ins><span class="cx"> {
</span><del>- switch (kind) {
- case CodeForCall:
</del><ins>+ switch (callMode) {
+ case CallMode::Regular:
</ins><span class="cx"> return CallVarargs;
</span><del>- case CodeForConstruct:
</del><ins>+ case CallMode::Construct:
</ins><span class="cx"> return ConstructVarargs;
</span><ins>+ case CallMode::Tail:
+ return TailCallVarargs;
</ins><span class="cx"> }
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><del>- return Call;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static CodeSpecializationKind specializationKindFor(Kind kind)
</span><span class="lines">@@ -158,6 +180,8 @@
</span><span class="cx"> switch (kind) {
</span><span class="cx"> case Call:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
</ins><span class="cx"> case GetterCall:
</span><span class="cx"> case SetterCall:
</span><span class="cx"> return CodeForCall;
</span><span class="lines">@@ -166,7 +190,6 @@
</span><span class="cx"> return CodeForConstruct;
</span><span class="cx"> }
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><del>- return CodeForCall;
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> static bool isVarargs(Kind kind)
</span><span class="lines">@@ -174,6 +197,7 @@
</span><span class="cx"> switch (kind) {
</span><span class="cx"> case CallVarargs:
</span><span class="cx"> case ConstructVarargs:
</span><ins>+ case TailCallVarargs:
</ins><span class="cx"> return true;
</span><span class="cx"> default:
</span><span class="cx"> return false;
</span><span class="lines">@@ -183,11 +207,49 @@
</span><span class="cx"> {
</span><span class="cx"> return isVarargs(static_cast<Kind>(kind));
</span><span class="cx"> }
</span><ins>+
+ static bool isTail(Kind kind)
+ {
+ switch (kind) {
+ case TailCall:
+ case TailCallVarargs:
+ return true;
+ default:
+ return false;
+ }
+ }
+ bool isTail() const
+ {
+ return isTail(static_cast<Kind>(kind));
+ }
+
+ static CodeOrigin* computeCallerSkippingDeadFrames(InlineCallFrame* inlineCallFrame)
+ {
+ CodeOrigin* codeOrigin;
+ bool tailCallee;
+ do {
+ tailCallee = inlineCallFrame->isTail();
+ codeOrigin = &inlineCallFrame->directCaller;
+ inlineCallFrame = codeOrigin->inlineCallFrame;
+ } while (inlineCallFrame && tailCallee);
+ if (tailCallee)
+ return nullptr;
+ return codeOrigin;
+ }
+ CodeOrigin* getCallerSkippingDeadFrames()
+ {
+ return computeCallerSkippingDeadFrames(this);
+ }
+ InlineCallFrame* getCallerInlineFrameSkippingDeadFrames()
+ {
+ CodeOrigin* caller = getCallerSkippingDeadFrames();
+ return caller ? caller->inlineCallFrame : nullptr;
+ }
</ins><span class="cx">
</span><span class="cx"> Vector<ValueRecovery> arguments; // Includes 'this'.
</span><span class="cx"> WriteBarrier<ScriptExecutable> executable;
</span><span class="cx"> ValueRecovery calleeRecovery;
</span><del>- CodeOrigin caller;
</del><ins>+ CodeOrigin directCaller;
</ins><span class="cx">
</span><span class="cx"> signed stackOffset : 28;
</span><span class="cx"> unsigned kind : 3; // real type is Kind
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -1442,6 +1442,13 @@
</span><span class="cx"> case Return:
</span><span class="cx"> m_state.setIsValid(false);
</span><span class="cx"> break;
</span><ins>+
+ case TailCall:
+ case TailCallVarargs:
+ case TailCallForwardVarargs:
+ clobberWorld(node->origin.semantic, clobberLimit);
+ m_state.setIsValid(false);
+ break;
</ins><span class="cx">
</span><span class="cx"> case Throw:
</span><span class="cx"> case ThrowReferenceError:
</span><span class="lines">@@ -2253,13 +2260,16 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case Call:
</span><ins>+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case NativeCall:
</span><span class="cx"> case NativeConstruct:
</span><span class="cx"> case CallVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><ins>+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case ConstructForwardVarargs:
</span><ins>+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> clobberWorld(node->origin.semantic, clobberLimit);
</span><span class="cx"> forNode(node).makeHeapTop();
</span><span class="cx"> break;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGArgumentsEliminationPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -167,6 +167,8 @@
</span><span class="cx">
</span><span class="cx"> case CallVarargs:
</span><span class="cx"> case ConstructVarargs:
</span><ins>+ case TailCallVarargs:
+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> escape(node->child1());
</span><span class="cx"> escape(node->child3());
</span><span class="cx"> break;
</span><span class="lines">@@ -553,7 +555,9 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case CallVarargs:
</span><del>- case ConstructVarargs: {
</del><ins>+ case ConstructVarargs:
+ case TailCallVarargs:
+ case TailCallVarargsInlinedCaller: {
</ins><span class="cx"> Node* candidate = node->child2().node();
</span><span class="cx"> if (!m_candidates.contains(candidate))
</span><span class="cx"> break;
</span><span class="lines">@@ -578,16 +582,44 @@
</span><span class="cx"> m_graph.m_varArgChildren.append(node->child3());
</span><span class="cx"> for (Node* argument : arguments)
</span><span class="cx"> m_graph.m_varArgChildren.append(Edge(argument));
</span><del>- node->setOpAndDefaultFlags(
- node->op() == CallVarargs ? Call : Construct);
</del><ins>+ switch (node->op()) {
+ case CallVarargs:
+ node->setOpAndDefaultFlags(Call);
+ break;
+ case ConstructVarargs:
+ node->setOpAndDefaultFlags(Construct);
+ break;
+ case TailCallVarargs:
+ node->setOpAndDefaultFlags(TailCall);
+ break;
+ case TailCallVarargsInlinedCaller:
+ node->setOpAndDefaultFlags(TailCallInlinedCaller);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
</ins><span class="cx"> node->children = AdjacencyList(
</span><span class="cx"> AdjacencyList::Variable,
</span><span class="cx"> firstChild, m_graph.m_varArgChildren.size() - firstChild);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- node->setOpAndDefaultFlags(
- node->op() == CallVarargs ? CallForwardVarargs : ConstructForwardVarargs);
</del><ins>+ switch (node->op()) {
+ case CallVarargs:
+ node->setOpAndDefaultFlags(CallForwardVarargs);
+ break;
+ case ConstructVarargs:
+ node->setOpAndDefaultFlags(ConstructForwardVarargs);
+ break;
+ case TailCallVarargs:
+ node->setOpAndDefaultFlags(TailCallForwardVarargs);
+ break;
+ case TailCallVarargsInlinedCaller:
+ node->setOpAndDefaultFlags(TailCallForwardVarargsInlinedCaller);
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ }
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGBasicBlockh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGBasicBlock.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGBasicBlock.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGBasicBlock.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -92,6 +92,8 @@
</span><span class="cx"> case Branch:
</span><span class="cx"> case Switch:
</span><span class="cx"> case Return:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
</ins><span class="cx"> case Unreachable:
</span><span class="cx"> return NodeAndIndex(node, i);
</span><span class="cx"> // The bitter end can contain Phantoms and the like. There will probably only be one or two nodes after the terminal. They are all no-ops and will not have any checked children.
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -180,14 +180,14 @@
</span><span class="cx"> Node* callTarget, int argCount, int registerOffset, CallLinkStatus,
</span><span class="cx"> SpeculatedType prediction);
</span><span class="cx"> void handleCall(
</span><del>- int result, NodeType op, InlineCallFrame::Kind, unsigned instructionSize,
</del><ins>+ int result, NodeType op, CallMode, unsigned instructionSize,
</ins><span class="cx"> Node* callTarget, int argCount, int registerOffset, CallLinkStatus);
</span><del>- void handleCall(int result, NodeType op, CodeSpecializationKind, unsigned instructionSize, int callee, int argCount, int registerOffset);
- void handleCall(Instruction* pc, NodeType op, CodeSpecializationKind);
- void handleVarargsCall(Instruction* pc, NodeType op, CodeSpecializationKind);
</del><ins>+ void handleCall(int result, NodeType op, CallMode, unsigned instructionSize, int callee, int argCount, int registerOffset);
+ void handleCall(Instruction* pc, NodeType op, CallMode);
+ void handleVarargsCall(Instruction* pc, NodeType op, CallMode);
</ins><span class="cx"> void emitFunctionChecks(CallVariant, Node* callTarget, VirtualRegister thisArgumnt);
</span><span class="cx"> void emitArgumentPhantoms(int registerOffset, int argumentCountIncludingThis);
</span><del>- unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CodeSpecializationKind); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.
</del><ins>+ unsigned inliningCost(CallVariant, int argumentCountIncludingThis, CallMode); // Return UINT_MAX if it's not an inlining candidate. By convention, intrinsics have a cost of 1.
</ins><span class="cx"> // Handle inlining. Return true if it succeeded, false if we need to plant a call.
</span><span class="cx"> bool handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus&, int registerOffset, VirtualRegister thisArgument, VirtualRegister argumentsArgument, unsigned argumentsOffset, int argumentCountIncludingThis, unsigned nextOffset, NodeType callOp, InlineCallFrame::Kind, SpeculatedType prediction);
</span><span class="cx"> enum CallerLinkability { CallerDoesNormalLinking, CallerLinksManually };
</span><span class="lines">@@ -600,6 +600,11 @@
</span><span class="cx"> return m_inlineStackTop->m_inlineCallFrame;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ bool allInlineFramesAreTailCalls()
+ {
+ return !inlineCallFrame() || !inlineCallFrame()->getCallerSkippingDeadFrames();
+ }
+
</ins><span class="cx"> CodeOrigin currentCodeOrigin()
</span><span class="cx"> {
</span><span class="cx"> return CodeOrigin(m_currentIndex, inlineCallFrame());
</span><span class="lines">@@ -680,7 +685,7 @@
</span><span class="cx">
</span><span class="cx"> Node* addCallWithoutSettingResult(
</span><span class="cx"> NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset,
</span><del>- SpeculatedType prediction)
</del><ins>+ OpInfo prediction)
</ins><span class="cx"> {
</span><span class="cx"> addVarArgChild(callee);
</span><span class="cx"> size_t frameSize = JSStack::CallFrameHeaderSize + argCount;
</span><span class="lines">@@ -693,15 +698,22 @@
</span><span class="cx"> for (int i = 0; i < argCount; ++i)
</span><span class="cx"> addVarArgChild(get(virtualRegisterForArgument(i, registerOffset)));
</span><span class="cx">
</span><del>- return addToGraph(Node::VarArg, op, opInfo, OpInfo(prediction));
</del><ins>+ return addToGraph(Node::VarArg, op, opInfo, prediction);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> Node* addCall(
</span><span class="cx"> int result, NodeType op, OpInfo opInfo, Node* callee, int argCount, int registerOffset,
</span><span class="cx"> SpeculatedType prediction)
</span><span class="cx"> {
</span><ins>+ if (op == TailCall) {
+ if (allInlineFramesAreTailCalls())
+ return addCallWithoutSettingResult(op, OpInfo(), callee, argCount, registerOffset, OpInfo());
+ op = TailCallInlinedCaller;
+ }
+
+
</ins><span class="cx"> Node* call = addCallWithoutSettingResult(
</span><del>- op, opInfo, callee, argCount, registerOffset, prediction);
</del><ins>+ op, opInfo, callee, argCount, registerOffset, OpInfo(prediction));
</ins><span class="cx"> VirtualRegister resultReg(result);
</span><span class="cx"> if (resultReg.isValid())
</span><span class="cx"> set(resultReg, call);
</span><span class="lines">@@ -717,14 +729,62 @@
</span><span class="cx">
</span><span class="cx"> SpeculatedType getPredictionWithoutOSRExit(unsigned bytecodeIndex)
</span><span class="cx"> {
</span><del>- ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
- return m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex);
</del><ins>+ SpeculatedType prediction;
+ CodeBlock* profiledBlock = nullptr;
+
+ {
+ ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
+ prediction = m_inlineStackTop->m_profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex);
+
+ if (prediction == SpecNone) {
+ // If we have no information about the values this
+ // node generates, we check if by any chance it is
+ // a tail call opcode. In that case, we walk up the
+ // inline frames to find a call higher in the call
+ // chain and use its prediction. If we only have
+ // inlined tail call frames, we use SpecFullTop
+ // to avoid a spurious OSR exit.
+ Instruction* instruction = m_inlineStackTop->m_profiledBlock->instructions().begin() + bytecodeIndex;
+ OpcodeID opcodeID = m_vm->interpreter->getOpcodeID(instruction->u.opcode);
+
+ switch (opcodeID) {
+ case op_tail_call:
+ case op_tail_call_varargs: {
+ if (!inlineCallFrame()) {
+ prediction = SpecFullTop;
+ break;
+ }
+ CodeOrigin* codeOrigin = inlineCallFrame()->getCallerSkippingDeadFrames();
+ if (!codeOrigin) {
+ prediction = SpecFullTop;
+ break;
+ }
+ InlineStackEntry* stack = m_inlineStackTop;
+ while (stack->m_inlineCallFrame != codeOrigin->inlineCallFrame)
+ stack = stack->m_caller;
+ bytecodeIndex = codeOrigin->bytecodeIndex;
+ profiledBlock = stack->m_profiledBlock;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if (profiledBlock) {
+ ConcurrentJITLocker locker(profiledBlock->m_lock);
+ prediction = profiledBlock->valueProfilePredictionForBytecodeOffset(locker, bytecodeIndex);
+ }
+
+ return prediction;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> SpeculatedType getPrediction(unsigned bytecodeIndex)
</span><span class="cx"> {
</span><span class="cx"> SpeculatedType prediction = getPredictionWithoutOSRExit(bytecodeIndex);
</span><del>-
</del><ins>+
</ins><span class="cx"> if (prediction == SpecNone) {
</span><span class="cx"> // We have no information about what values this node generates. Give up
</span><span class="cx"> // on executing this code, since we're likely to do more damage than good.
</span><span class="lines">@@ -1014,16 +1074,17 @@
</span><span class="cx"> m_currentIndex += OPCODE_LENGTH(name); \
</span><span class="cx"> return shouldContinueParsing
</span><span class="cx">
</span><del>-void ByteCodeParser::handleCall(Instruction* pc, NodeType op, CodeSpecializationKind kind)
</del><ins>+void ByteCodeParser::handleCall(Instruction* pc, NodeType op, CallMode callMode)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
</span><ins>+ ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_tail_call));
</ins><span class="cx"> handleCall(
</span><del>- pc[1].u.operand, op, kind, OPCODE_LENGTH(op_call),
</del><ins>+ pc[1].u.operand, op, callMode, OPCODE_LENGTH(op_call),
</ins><span class="cx"> pc[2].u.operand, pc[3].u.operand, -pc[4].u.operand);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void ByteCodeParser::handleCall(
</span><del>- int result, NodeType op, CodeSpecializationKind kind, unsigned instructionSize,
</del><ins>+ int result, NodeType op, CallMode callMode, unsigned instructionSize,
</ins><span class="cx"> int callee, int argumentCountIncludingThis, int registerOffset)
</span><span class="cx"> {
</span><span class="cx"> Node* callTarget = get(VirtualRegister(callee));
</span><span class="lines">@@ -1033,17 +1094,17 @@
</span><span class="cx"> m_inlineStackTop->m_callLinkInfos, m_callContextMap);
</span><span class="cx">
</span><span class="cx"> handleCall(
</span><del>- result, op, InlineCallFrame::kindFor(kind), instructionSize, callTarget,
</del><ins>+ result, op, callMode, instructionSize, callTarget,
</ins><span class="cx"> argumentCountIncludingThis, registerOffset, callLinkStatus);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> void ByteCodeParser::handleCall(
</span><del>- int result, NodeType op, InlineCallFrame::Kind kind, unsigned instructionSize,
</del><ins>+ int result, NodeType op, CallMode callMode, unsigned instructionSize,
</ins><span class="cx"> Node* callTarget, int argumentCountIncludingThis, int registerOffset,
</span><span class="cx"> CallLinkStatus callLinkStatus)
</span><span class="cx"> {
</span><span class="cx"> handleCall(
</span><del>- result, op, kind, instructionSize, callTarget, argumentCountIncludingThis,
</del><ins>+ result, op, InlineCallFrame::kindFor(callMode), instructionSize, callTarget, argumentCountIncludingThis,
</ins><span class="cx"> registerOffset, callLinkStatus, getPrediction());
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -1063,7 +1124,7 @@
</span><span class="cx"> if (!callLinkStatus.canOptimize()) {
</span><span class="cx"> // Oddly, this conflates calls that haven't executed with calls that behaved sufficiently polymorphically
</span><span class="cx"> // that we cannot optimize them.
</span><del>-
</del><ins>+
</ins><span class="cx"> addCall(result, op, OpInfo(), callTarget, argumentCountIncludingThis, registerOffset, prediction);
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="lines">@@ -1096,13 +1157,14 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><del>-
</del><ins>+
</ins><span class="cx"> addCall(result, op, callOpInfo, callTarget, argumentCountIncludingThis, registerOffset, prediction);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CodeSpecializationKind kind)
</del><ins>+void ByteCodeParser::handleVarargsCall(Instruction* pc, NodeType op, CallMode callMode)
</ins><span class="cx"> {
</span><span class="cx"> ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_construct_varargs));
</span><ins>+ ASSERT(OPCODE_LENGTH(op_call_varargs) == OPCODE_LENGTH(op_tail_call_varargs));
</ins><span class="cx">
</span><span class="cx"> int result = pc[1].u.operand;
</span><span class="cx"> int callee = pc[2].u.operand;
</span><span class="lines">@@ -1125,7 +1187,7 @@
</span><span class="cx"> dataLog(" Varargs call link status at ", currentCodeOrigin(), ": ", callLinkStatus, "\n");
</span><span class="cx">
</span><span class="cx"> if (callLinkStatus.canOptimize()
</span><del>- && handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor(kind), prediction)) {
</del><ins>+ && handleInlining(callTarget, result, callLinkStatus, firstFreeReg, VirtualRegister(thisReg), VirtualRegister(arguments), firstVarArgOffset, 0, m_currentIndex + OPCODE_LENGTH(op_call_varargs), op, InlineCallFrame::varargsKindFor(callMode), prediction)) {
</ins><span class="cx"> if (m_graph.compilation())
</span><span class="cx"> m_graph.compilation()->noticeInlinedCall();
</span><span class="cx"> return;
</span><span class="lines">@@ -1135,7 +1197,15 @@
</span><span class="cx"> data->firstVarArgOffset = firstVarArgOffset;
</span><span class="cx">
</span><span class="cx"> Node* thisChild = get(VirtualRegister(thisReg));
</span><del>-
</del><ins>+
+ if (op == TailCallVarargs) {
+ if (allInlineFramesAreTailCalls()) {
+ addToGraph(op, OpInfo(data), OpInfo(), callTarget, get(VirtualRegister(arguments)), thisChild);
+ return;
+ }
+ op = TailCallVarargsInlinedCaller;
+ }
+
</ins><span class="cx"> Node* call = addToGraph(op, OpInfo(data), OpInfo(prediction), callTarget, get(VirtualRegister(arguments)), thisChild);
</span><span class="cx"> VirtualRegister resultReg(result);
</span><span class="cx"> if (resultReg.isValid())
</span><span class="lines">@@ -1170,8 +1240,9 @@
</span><span class="cx"> addToGraph(Phantom, get(virtualRegisterForArgument(i, registerOffset)));
</span><span class="cx"> }
</span><span class="cx">
</span><del>-unsigned ByteCodeParser::inliningCost(CallVariant callee, int argumentCountIncludingThis, CodeSpecializationKind kind)
</del><ins>+unsigned ByteCodeParser::inliningCost(CallVariant callee, int argumentCountIncludingThis, CallMode callMode)
</ins><span class="cx"> {
</span><ins>+ CodeSpecializationKind kind = specializationKindFor(callMode);
</ins><span class="cx"> if (verbose)
</span><span class="cx"> dataLog("Considering inlining ", callee, " into ", currentCodeOrigin(), "\n");
</span><span class="cx">
</span><span class="lines">@@ -1213,7 +1284,7 @@
</span><span class="cx"> CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel(
</span><span class="cx"> codeBlock, kind, callee.isClosureCall());
</span><span class="cx"> if (verbose) {
</span><del>- dataLog(" Kind: ", kind, "\n");
</del><ins>+ dataLog(" Call mode: ", callMode, "\n");
</ins><span class="cx"> dataLog(" Is closure call: ", callee.isClosureCall(), "\n");
</span><span class="cx"> dataLog(" Capability level: ", capabilityLevel, "\n");
</span><span class="cx"> dataLog(" Might inline function: ", mightInlineFunctionFor(codeBlock, kind), "\n");
</span><span class="lines">@@ -1284,7 +1355,7 @@
</span><span class="cx"> {
</span><span class="cx"> CodeSpecializationKind specializationKind = InlineCallFrame::specializationKindFor(kind);
</span><span class="cx">
</span><del>- ASSERT(inliningCost(callee, argumentCountIncludingThis, specializationKind) != UINT_MAX);
</del><ins>+ ASSERT(inliningCost(callee, argumentCountIncludingThis, InlineCallFrame::callModeFor(kind)) != UINT_MAX);
</ins><span class="cx">
</span><span class="cx"> CodeBlock* codeBlock = callee.functionExecutable()->baselineCodeBlockFor(specializationKind);
</span><span class="cx"> insertChecks(codeBlock);
</span><span class="lines">@@ -1379,7 +1450,7 @@
</span><span class="cx"> m_currentBlock = m_graph.lastBlock();
</span><span class="cx"> return;
</span><span class="cx"> }
</span><del>-
</del><ins>+
</ins><span class="cx"> if (Options::verboseDFGByteCodeParsing())
</span><span class="cx"> dataLog(" Creating new block after inlining.\n");
</span><span class="cx">
</span><span class="lines">@@ -1486,7 +1557,7 @@
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span><del>- unsigned myInliningCost = inliningCost(callee, argumentCountIncludingThis, specializationKind);
</del><ins>+ unsigned myInliningCost = inliningCost(callee, argumentCountIncludingThis, InlineCallFrame::callModeFor(kind));
</ins><span class="cx"> if (myInliningCost > inliningBalance)
</span><span class="cx"> return false;
</span><span class="cx">
</span><span class="lines">@@ -3354,6 +3425,12 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case op_ret:
</span><ins>+ if (m_currentBlock->terminal()) {
+ // We could be the dummy return after a non-inlined, non-emulated tail call
+ Node* terminal = m_currentBlock->terminal();
+ ASSERT_UNUSED(terminal, terminal->op() == Return || terminal->op() == TailCall || terminal->op() == TailCallVarargs);
+ LAST_OPCODE(op_ret);
+ }
</ins><span class="cx"> if (inlineCallFrame()) {
</span><span class="cx"> flushForReturn();
</span><span class="cx"> if (m_inlineStackTop->m_returnValue.isValid())
</span><span class="lines">@@ -3401,22 +3478,37 @@
</span><span class="cx"> LAST_OPCODE(op_throw_static_error);
</span><span class="cx">
</span><span class="cx"> case op_call:
</span><del>- handleCall(currentInstruction, Call, CodeForCall);
</del><ins>+ handleCall(currentInstruction, Call, CallMode::Regular);
</ins><span class="cx"> // Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction
</span><span class="cx"> ASSERT(m_currentInstruction == currentInstruction);
</span><span class="cx"> NEXT_OPCODE(op_call);
</span><del>-
</del><ins>+
+ case op_tail_call:
+ flushForReturn();
+ handleCall(currentInstruction, TailCall, CallMode::Tail);
+ // Verify that handleCall(), which could have inlined the callee, didn't trash m_currentInstruction
+ ASSERT(m_currentInstruction == currentInstruction);
+ // We let the following op_ret handle cases related to
+ // inlining to keep things simple.
+ NEXT_OPCODE(op_tail_call);
+
</ins><span class="cx"> case op_construct:
</span><del>- handleCall(currentInstruction, Construct, CodeForConstruct);
</del><ins>+ handleCall(currentInstruction, Construct, CallMode::Construct);
</ins><span class="cx"> NEXT_OPCODE(op_construct);
</span><span class="cx">
</span><span class="cx"> case op_call_varargs: {
</span><del>- handleVarargsCall(currentInstruction, CallVarargs, CodeForCall);
</del><ins>+ handleVarargsCall(currentInstruction, CallVarargs, CallMode::Regular);
</ins><span class="cx"> NEXT_OPCODE(op_call_varargs);
</span><span class="cx"> }
</span><ins>+
+ case op_tail_call_varargs: {
+ flushForReturn();
+ handleVarargsCall(currentInstruction, TailCallVarargs, CallMode::Tail);
+ NEXT_OPCODE(op_tail_call_varargs);
+ }
</ins><span class="cx">
</span><span class="cx"> case op_construct_varargs: {
</span><del>- handleVarargsCall(currentInstruction, ConstructVarargs, CodeForConstruct);
</del><ins>+ handleVarargsCall(currentInstruction, ConstructVarargs, CallMode::Construct);
</ins><span class="cx"> NEXT_OPCODE(op_construct_varargs);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -4038,7 +4130,7 @@
</span><span class="cx"> m_inlineCallFrame->isClosureCall = false;
</span><span class="cx"> } else
</span><span class="cx"> m_inlineCallFrame->isClosureCall = true;
</span><del>- m_inlineCallFrame->caller = byteCodeParser->currentCodeOrigin();
</del><ins>+ m_inlineCallFrame->directCaller = byteCodeParser->currentCodeOrigin();
</ins><span class="cx"> m_inlineCallFrame->arguments.resizeToFit(argumentCountIncludingThis); // Set the number of arguments including this, but don't configure the value recoveries, yet.
</span><span class="cx"> m_inlineCallFrame->kind = kind;
</span><span class="cx">
</span><span class="lines">@@ -4113,7 +4205,7 @@
</span><span class="cx"> if (UNLIKELY(Options::dumpSourceAtDFGTime())) {
</span><span class="cx"> Vector<DeferredSourceDump>& deferredSourceDump = m_graph.m_plan.callback->ensureDeferredSourceDump();
</span><span class="cx"> if (inlineCallFrame()) {
</span><del>- DeferredSourceDump dump(codeBlock->baselineVersion(), m_codeBlock, JITCode::DFGJIT, inlineCallFrame()->caller);
</del><ins>+ DeferredSourceDump dump(codeBlock->baselineVersion(), m_codeBlock, JITCode::DFGJIT, inlineCallFrame()->directCaller);
</ins><span class="cx"> deferredSourceDump.append(dump);
</span><span class="cx"> } else
</span><span class="cx"> deferredSourceDump.append(DeferredSourceDump(codeBlock->baselineVersion()));
</span><span class="lines">@@ -4124,7 +4216,7 @@
</span><span class="cx"> if (inlineCallFrame()) {
</span><span class="cx"> dataLog(
</span><span class="cx"> " for inlining at ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT),
</span><del>- " ", inlineCallFrame()->caller);
</del><ins>+ " ", inlineCallFrame()->directCaller);
</ins><span class="cx"> }
</span><span class="cx"> dataLog(
</span><span class="cx"> ": needsActivation = ", codeBlock->needsActivation(),
</span><span class="lines">@@ -4208,7 +4300,7 @@
</span><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- m_currentBlock = 0;
</del><ins>+ m_currentBlock = nullptr;
</ins><span class="cx"> } while (m_currentIndex < limit);
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGCapabilities.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -179,8 +179,10 @@
</span><span class="cx"> case op_throw:
</span><span class="cx"> case op_throw_static_error:
</span><span class="cx"> case op_call:
</span><ins>+ case op_tail_call:
</ins><span class="cx"> case op_construct:
</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_create_direct_arguments:
</span><span class="cx"> case op_create_scoped_arguments:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGClobberize.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -376,11 +376,14 @@
</span><span class="cx"> case ArrayPush:
</span><span class="cx"> case ArrayPop:
</span><span class="cx"> case Call:
</span><ins>+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case NativeCall:
</span><span class="cx"> case NativeConstruct:
</span><span class="cx"> case CallVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><ins>+ case TailCallVarargsInlinedCaller:
+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case ConstructForwardVarargs:
</span><span class="cx"> case ToPrimitive:
</span><span class="lines">@@ -389,6 +392,13 @@
</span><span class="cx"> read(World);
</span><span class="cx"> write(Heap);
</span><span class="cx"> return;
</span><ins>+
+ case TailCall:
+ case TailCallVarargs:
+ case TailCallForwardVarargs:
+ read(World);
+ write(SideState);
+ return;
</ins><span class="cx">
</span><span class="cx"> case GetGetter:
</span><span class="cx"> read(GetterSetter_getter);
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -117,12 +117,16 @@
</span><span class="cx"> case CompareEqConstant:
</span><span class="cx"> case CompareStrictEq:
</span><span class="cx"> case Call:
</span><ins>+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case LoadVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><span class="cx"> case ConstructForwardVarargs:
</span><ins>+ case TailCallForwardVarargs:
+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case NativeCall:
</span><span class="cx"> case NativeConstruct:
</span><span class="cx"> case Breakpoint:
</span><span class="lines">@@ -149,6 +153,8 @@
</span><span class="cx"> case Branch:
</span><span class="cx"> case Switch:
</span><span class="cx"> case Return:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
</ins><span class="cx"> case Throw:
</span><span class="cx"> case CountExecution:
</span><span class="cx"> case ForceOSRExit:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -1278,11 +1278,15 @@
</span><span class="cx"> case NotifyWrite:
</span><span class="cx"> case VarInjectionWatchpoint:
</span><span class="cx"> case Call:
</span><ins>+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><span class="cx"> case ConstructForwardVarargs:
</span><ins>+ case TailCallForwardVarargs:
+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case LoadVarargs:
</span><span class="cx"> case ProfileControlFlow:
</span><span class="cx"> case NativeCall:
</span><span class="lines">@@ -1302,6 +1306,8 @@
</span><span class="cx"> case CreateClonedArguments:
</span><span class="cx"> case Jump:
</span><span class="cx"> case Return:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
</ins><span class="cx"> case Throw:
</span><span class="cx"> case ThrowReferenceError:
</span><span class="cx"> case CountExecution:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -884,30 +884,31 @@
</span><span class="cx">
</span><span class="cx"> bool Graph::isLiveInBytecode(VirtualRegister operand, CodeOrigin codeOrigin)
</span><span class="cx"> {
</span><ins>+ CodeOrigin* codeOriginPtr = &codeOrigin;
</ins><span class="cx"> for (;;) {
</span><span class="cx"> VirtualRegister reg = VirtualRegister(
</span><del>- operand.offset() - codeOrigin.stackOffset());
</del><ins>+ operand.offset() - codeOriginPtr->stackOffset());
</ins><span class="cx">
</span><del>- if (operand.offset() < codeOrigin.stackOffset() + JSStack::CallFrameHeaderSize) {
</del><ins>+ if (operand.offset() < codeOriginPtr->stackOffset() + JSStack::CallFrameHeaderSize) {
</ins><span class="cx"> if (reg.isArgument()) {
</span><span class="cx"> RELEASE_ASSERT(reg.offset() < JSStack::CallFrameHeaderSize);
</span><span class="cx">
</span><del>- if (codeOrigin.inlineCallFrame->isClosureCall
</del><ins>+ if (codeOriginPtr->inlineCallFrame->isClosureCall
</ins><span class="cx"> && reg.offset() == JSStack::Callee)
</span><span class="cx"> return true;
</span><span class="cx">
</span><del>- if (codeOrigin.inlineCallFrame->isVarargs()
</del><ins>+ if (codeOriginPtr->inlineCallFrame->isVarargs()
</ins><span class="cx"> && reg.offset() == JSStack::ArgumentCount)
</span><span class="cx"> return true;
</span><span class="cx">
</span><span class="cx"> return false;
</span><span class="cx"> }
</span><span class="cx">
</span><del>- return livenessFor(codeOrigin.inlineCallFrame).operandIsLive(
- reg.offset(), codeOrigin.bytecodeIndex);
</del><ins>+ return livenessFor(codeOriginPtr->inlineCallFrame).operandIsLive(
+ reg.offset(), codeOriginPtr->bytecodeIndex);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>- InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
</del><ins>+ InlineCallFrame* inlineCallFrame = codeOriginPtr->inlineCallFrame;
</ins><span class="cx"> if (!inlineCallFrame)
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="lines">@@ -917,7 +918,11 @@
</span><span class="cx"> && static_cast<size_t>(reg.toArgument()) < inlineCallFrame->arguments.size())
</span><span class="cx"> return true;
</span><span class="cx">
</span><del>- codeOrigin = inlineCallFrame->caller;
</del><ins>+ codeOriginPtr = inlineCallFrame->getCallerSkippingDeadFrames();
+
+ // The first inline call frame could be an inline tail call
+ if (!codeOriginPtr)
+ break;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> return true;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGGraph.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -696,9 +696,11 @@
</span><span class="cx"> // call, both callee and caller will see the variables live.
</span><span class="cx"> VirtualRegister exclusionStart;
</span><span class="cx"> VirtualRegister exclusionEnd;
</span><ins>+
+ CodeOrigin* codeOriginPtr = &codeOrigin;
</ins><span class="cx">
</span><span class="cx"> for (;;) {
</span><del>- InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
</del><ins>+ InlineCallFrame* inlineCallFrame = codeOriginPtr->inlineCallFrame;
</ins><span class="cx"> VirtualRegister stackOffset(inlineCallFrame ? inlineCallFrame->stackOffset : 0);
</span><span class="cx">
</span><span class="cx"> if (inlineCallFrame) {
</span><span class="lines">@@ -710,7 +712,7 @@
</span><span class="cx">
</span><span class="cx"> CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame);
</span><span class="cx"> FullBytecodeLiveness& fullLiveness = livenessFor(codeBlock);
</span><del>- const FastBitVector& liveness = fullLiveness.getLiveness(codeOrigin.bytecodeIndex);
</del><ins>+ const FastBitVector& liveness = fullLiveness.getLiveness(codeOriginPtr->bytecodeIndex);
</ins><span class="cx"> for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) {
</span><span class="cx"> VirtualRegister reg = stackOffset + virtualRegisterForLocal(relativeLocal);
</span><span class="cx">
</span><span class="lines">@@ -737,7 +739,11 @@
</span><span class="cx"> for (VirtualRegister reg = exclusionStart; reg < exclusionEnd; reg += 1)
</span><span class="cx"> functor(reg);
</span><span class="cx">
</span><del>- codeOrigin = inlineCallFrame->caller;
</del><ins>+ codeOriginPtr = inlineCallFrame->getCallerSkippingDeadFrames();
+
+ // The first inline call frame could be an inline tail call
+ if (!codeOriginPtr)
+ break;
</ins><span class="cx"> }
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -393,6 +393,8 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> case Return:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
</ins><span class="cx"> case Unreachable:
</span><span class="cx"> ASSERT(basicBlock->cfaBranchDirection == InvalidBranchDirection);
</span><span class="cx"> return false;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNode.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNode.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNode.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -995,6 +995,10 @@
</span><span class="cx"> switch (op()) {
</span><span class="cx"> case CallVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><ins>+ case TailCallVarargs:
+ case TailCallForwardVarargs:
+ case TailCallVarargsInlinedCaller:
+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case ConstructForwardVarargs:
</span><span class="cx"> return true;
</span><span class="lines">@@ -1092,6 +1096,8 @@
</span><span class="cx"> case Branch:
</span><span class="cx"> case Switch:
</span><span class="cx"> case Return:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
</ins><span class="cx"> case Unreachable:
</span><span class="cx"> return true;
</span><span class="cx"> default:
</span><span class="lines">@@ -1242,10 +1248,13 @@
</span><span class="cx"> case GetByIdFlush:
</span><span class="cx"> case GetByVal:
</span><span class="cx"> case Call:
</span><ins>+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><ins>+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case NativeCall:
</span><span class="cx"> case NativeConstruct:
</span><span class="cx"> case GetByOffset:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNodeType.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -239,6 +239,9 @@
</span><span class="cx"> macro(CallForwardVarargs, NodeResultJS | NodeMustGenerate) \
</span><span class="cx"> macro(ConstructVarargs, NodeResultJS | NodeMustGenerate) \
</span><span class="cx"> macro(ConstructForwardVarargs, NodeResultJS | NodeMustGenerate) \
</span><ins>+ macro(TailCallInlinedCaller, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
+ macro(TailCallVarargsInlinedCaller, NodeResultJS | NodeMustGenerate) \
+ macro(TailCallForwardVarargsInlinedCaller, NodeResultJS | NodeMustGenerate) \
</ins><span class="cx"> macro(NativeCall, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
</span><span class="cx"> macro(NativeConstruct, NodeResultJS | NodeMustGenerate | NodeHasVarArgs) \
</span><span class="cx"> \
</span><span class="lines">@@ -304,6 +307,9 @@
</span><span class="cx"> macro(Branch, NodeMustGenerate) \
</span><span class="cx"> macro(Switch, NodeMustGenerate) \
</span><span class="cx"> macro(Return, NodeMustGenerate) \
</span><ins>+ macro(TailCall, NodeMustGenerate | NodeHasVarArgs) \
+ macro(TailCallVarargs, NodeMustGenerate) \
+ macro(TailCallForwardVarargs, NodeMustGenerate) \
</ins><span class="cx"> macro(Unreachable, NodeMustGenerate) \
</span><span class="cx"> \
</span><span class="cx"> /* Count execution. */\
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGOSRExitCompilerCommoncpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -64,7 +64,7 @@
</span><span class="cx">
</span><span class="cx"> AssemblyHelpers::JumpList loopThreshold;
</span><span class="cx">
</span><del>- for (InlineCallFrame* inlineCallFrame = exit.m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) {
</del><ins>+ for (InlineCallFrame* inlineCallFrame = exit.m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) {
</ins><span class="cx"> loopThreshold.append(
</span><span class="cx"> jit.branchTest8(
</span><span class="cx"> AssemblyHelpers::NonZero,
</span><span class="lines">@@ -136,63 +136,80 @@
</span><span class="cx">
</span><span class="cx"> void reifyInlinedCallFrames(CCallHelpers& jit, const OSRExitBase& exit)
</span><span class="cx"> {
</span><ins>+ // FIXME: We shouldn't leave holes on the stack when performing an OSR exit
+ // in presence of inlined tail calls.
+ // https://bugs.webkit.org/show_bug.cgi?id=147511
</ins><span class="cx"> ASSERT(jit.baselineCodeBlock()->jitType() == JITCode::BaselineJIT);
</span><span class="cx"> jit.storePtr(AssemblyHelpers::TrustedImmPtr(jit.baselineCodeBlock()), AssemblyHelpers::addressFor((VirtualRegister)JSStack::CodeBlock));
</span><span class="cx">
</span><del>- CodeOrigin codeOrigin;
- for (codeOrigin = exit.m_codeOrigin; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) {
- InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
- CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(codeOrigin);
- CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(inlineCallFrame->caller);
- void* jumpTarget = nullptr;
</del><ins>+ const CodeOrigin* codeOrigin;
+ for (codeOrigin = &exit.m_codeOrigin; codeOrigin && codeOrigin->inlineCallFrame; codeOrigin = codeOrigin->inlineCallFrame->getCallerSkippingDeadFrames()) {
+ InlineCallFrame* inlineCallFrame = codeOrigin->inlineCallFrame;
+ CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(*codeOrigin);
+ CodeOrigin* trueCaller = inlineCallFrame->getCallerSkippingDeadFrames();
</ins><span class="cx"> void* trueReturnPC = nullptr;
</span><del>-
- unsigned callBytecodeIndex = inlineCallFrame->caller.bytecodeIndex;
-
- switch (inlineCallFrame->kind) {
- case InlineCallFrame::Call:
- case InlineCallFrame::Construct:
- case InlineCallFrame::CallVarargs:
- case InlineCallFrame::ConstructVarargs: {
- CallLinkInfo* callLinkInfo =
- baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex);
- RELEASE_ASSERT(callLinkInfo);
-
- jumpTarget = callLinkInfo->callReturnLocation().executableAddress();
- break;
- }
-
- case InlineCallFrame::GetterCall:
- case InlineCallFrame::SetterCall: {
- StructureStubInfo* stubInfo =
- baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex));
- RELEASE_ASSERT(stubInfo);
-
</del><ins>+ GPRReg callerFrameGPR = GPRInfo::callFrameRegister;
+
+ if (!trueCaller) {
+ ASSERT(inlineCallFrame->isTail());
+ jit.loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, CallFrame::returnPCOffset()), GPRInfo::regT3);
+ jit.storePtr(GPRInfo::regT3, AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset()));
+ jit.loadPtr(AssemblyHelpers::Address(GPRInfo::callFrameRegister, CallFrame::callerFrameOffset()), GPRInfo::regT3);
+ callerFrameGPR = GPRInfo::regT3;
+ } else {
+ CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(*trueCaller);
+ unsigned callBytecodeIndex = trueCaller->bytecodeIndex;
+ void* jumpTarget = nullptr;
+
</ins><span class="cx"> switch (inlineCallFrame->kind) {
</span><ins>+ case InlineCallFrame::Call:
+ case InlineCallFrame::Construct:
+ case InlineCallFrame::CallVarargs:
+ case InlineCallFrame::ConstructVarargs:
+ case InlineCallFrame::TailCall:
+ case InlineCallFrame::TailCallVarargs: {
+ CallLinkInfo* callLinkInfo =
+ baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex);
+ RELEASE_ASSERT(callLinkInfo);
+
+ jumpTarget = callLinkInfo->callReturnLocation().executableAddress();
+ break;
+ }
+
</ins><span class="cx"> case InlineCallFrame::GetterCall:
</span><del>- jumpTarget = jit.vm()->getCTIStub(baselineGetterReturnThunkGenerator).code().executableAddress();
</del><ins>+ case InlineCallFrame::SetterCall: {
+ StructureStubInfo* stubInfo =
+ baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex));
+ RELEASE_ASSERT(stubInfo);
+
+ switch (inlineCallFrame->kind) {
+ case InlineCallFrame::GetterCall:
+ jumpTarget = jit.vm()->getCTIStub(baselineGetterReturnThunkGenerator).code().executableAddress();
+ break;
+ case InlineCallFrame::SetterCall:
+ jumpTarget = jit.vm()->getCTIStub(baselineSetterReturnThunkGenerator).code().executableAddress();
+ break;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ break;
+ }
+
+ trueReturnPC = stubInfo->callReturnLocation.labelAtOffset(
+ stubInfo->patch.deltaCallToDone).executableAddress();
</ins><span class="cx"> break;
</span><del>- case InlineCallFrame::SetterCall:
- jumpTarget = jit.vm()->getCTIStub(baselineSetterReturnThunkGenerator).code().executableAddress();
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
</del><ins>+ } }
+
+ if (trueCaller->inlineCallFrame) {
+ jit.addPtr(
+ AssemblyHelpers::TrustedImm32(trueCaller->inlineCallFrame->stackOffset * sizeof(EncodedJSValue)),
+ GPRInfo::callFrameRegister,
+ GPRInfo::regT3);
+ callerFrameGPR = GPRInfo::regT3;
</ins><span class="cx"> }
</span><del>-
- trueReturnPC = stubInfo->callReturnLocation.labelAtOffset(
- stubInfo->patch.deltaCallToDone).executableAddress();
- break;
- } }
</del><span class="cx">
</span><del>- GPRReg callerFrameGPR;
- if (inlineCallFrame->caller.inlineCallFrame) {
- jit.addPtr(AssemblyHelpers::TrustedImm32(inlineCallFrame->caller.inlineCallFrame->stackOffset * sizeof(EncodedJSValue)), GPRInfo::callFrameRegister, GPRInfo::regT3);
- callerFrameGPR = GPRInfo::regT3;
- } else
- callerFrameGPR = GPRInfo::callFrameRegister;
-
- jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset()));
</del><ins>+ jit.storePtr(AssemblyHelpers::TrustedImmPtr(jumpTarget), AssemblyHelpers::addressForByteOffset(inlineCallFrame->returnPCOffset()));
+ }
+
</ins><span class="cx"> if (trueReturnPC)
</span><span class="cx"> jit.storePtr(AssemblyHelpers::TrustedImmPtr(trueReturnPC), AssemblyHelpers::addressFor(inlineCallFrame->stackOffset + virtualRegisterForArgument(inlineCallFrame->arguments.size()).offset()));
</span><span class="cx">
</span><span class="lines">@@ -202,13 +219,13 @@
</span><span class="cx"> jit.store32(AssemblyHelpers::TrustedImm32(inlineCallFrame->arguments.size()), AssemblyHelpers::payloadFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount)));
</span><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx"> jit.store64(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset()));
</span><del>- uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin.bytecodeIndex);
</del><ins>+ uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin->bytecodeIndex);
</ins><span class="cx"> jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount)));
</span><span class="cx"> if (!inlineCallFrame->isClosureCall)
</span><span class="cx"> jit.store64(AssemblyHelpers::TrustedImm64(JSValue::encode(JSValue(inlineCallFrame->calleeConstant()))), AssemblyHelpers::addressFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
</span><span class="cx"> #else // USE(JSVALUE64) // so this is the 32-bit part
</span><span class="cx"> jit.storePtr(callerFrameGPR, AssemblyHelpers::addressForByteOffset(inlineCallFrame->callerFrameOffset()));
</span><del>- Instruction* instruction = baselineCodeBlock->instructions().begin() + codeOrigin.bytecodeIndex;
</del><ins>+ Instruction* instruction = baselineCodeBlock->instructions().begin() + codeOrigin->bytecodeIndex;
</ins><span class="cx"> uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction);
</span><span class="cx"> jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::ArgumentCount)));
</span><span class="cx"> jit.store32(AssemblyHelpers::TrustedImm32(JSValue::CellTag), AssemblyHelpers::tagFor((VirtualRegister)(inlineCallFrame->stackOffset + JSStack::Callee)));
</span><span class="lines">@@ -217,13 +234,16 @@
</span><span class="cx"> #endif // USE(JSVALUE64) // ending the #else part, so directly above is the 32-bit part
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ // Don't need to set the toplevel code origin if we only did inline tail calls
+ if (codeOrigin) {
</ins><span class="cx"> #if USE(JSVALUE64)
</span><del>- uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin.bytecodeIndex);
</del><ins>+ uint32_t locationBits = CallFrame::Location::encodeAsBytecodeOffset(codeOrigin->bytecodeIndex);
</ins><span class="cx"> #else
</span><del>- Instruction* instruction = jit.baselineCodeBlock()->instructions().begin() + codeOrigin.bytecodeIndex;
- uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction);
</del><ins>+ Instruction* instruction = jit.baselineCodeBlock()->instructions().begin() + codeOrigin->bytecodeIndex;
+ uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction);
</ins><span class="cx"> #endif
</span><del>- jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(JSStack::ArgumentCount)));
</del><ins>+ jit.store32(AssemblyHelpers::TrustedImm32(locationBits), AssemblyHelpers::tagFor((VirtualRegister)(JSStack::ArgumentCount)));
+ }
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> #if ENABLE(GGC)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGOSRExitPreparationcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitPreparation.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitPreparation.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOSRExitPreparation.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx"> VM& vm = exec->vm();
</span><span class="cx"> DeferGC deferGC(vm.heap);
</span><span class="cx">
</span><del>- for (; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->caller) {
</del><ins>+ for (; codeOrigin.inlineCallFrame; codeOrigin = codeOrigin.inlineCallFrame->directCaller) {
</ins><span class="cx"> FunctionExecutable* executable =
</span><span class="cx"> static_cast<FunctionExecutable*>(codeOrigin.inlineCallFrame->executable.get());
</span><span class="cx"> CodeBlock* codeBlock = executable->baselineCodeBlockFor(
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOperations.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOperations.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGOperations.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -1276,7 +1276,7 @@
</span><span class="cx"> ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
</span><span class="cx">
</span><span class="cx"> bool didTryToEnterIntoInlinedLoops = false;
</span><del>- for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) {
</del><ins>+ for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) {
</ins><span class="cx"> if (inlineCallFrame->executable->didTryToEnterInLoop()) {
</span><span class="cx"> didTryToEnterIntoInlinedLoops = true;
</span><span class="cx"> break;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGPreciseLocalClobberizeh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -111,7 +111,9 @@
</span><span class="cx"> case GetMyArgumentByVal:
</span><span class="cx"> case ForwardVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><del>- case ConstructForwardVarargs: {
</del><ins>+ case ConstructForwardVarargs:
+ case TailCallForwardVarargs:
+ case TailCallForwardVarargsInlinedCaller: {
</ins><span class="cx"> InlineCallFrame* inlineCallFrame = m_node->child1()->origin.semantic.inlineCallFrame;
</span><span class="cx"> if (!inlineCallFrame) {
</span><span class="cx"> // Read the outermost arguments and argument count.
</span><span class="lines">@@ -138,7 +140,7 @@
</span><span class="cx"> m_read(VirtualRegister(i));
</span><span class="cx">
</span><span class="cx"> // Read all of the inline arguments and call frame headers that we didn't already capture.
</span><del>- for (InlineCallFrame* inlineCallFrame = m_node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->caller.inlineCallFrame) {
</del><ins>+ for (InlineCallFrame* inlineCallFrame = m_node->origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->getCallerInlineFrameSkippingDeadFrames()) {
</ins><span class="cx"> for (unsigned i = inlineCallFrame->arguments.size(); i-- > 1;)
</span><span class="cx"> m_read(VirtualRegister(inlineCallFrame->stackOffset + virtualRegisterForArgument(i).offset()));
</span><span class="cx"> if (inlineCallFrame->isClosureCall)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -194,11 +194,14 @@
</span><span class="cx"> case MultiGetByOffset:
</span><span class="cx"> case GetDirectPname:
</span><span class="cx"> case Call:
</span><ins>+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><span class="cx"> case ConstructForwardVarargs:
</span><ins>+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case NativeCall:
</span><span class="cx"> case NativeConstruct:
</span><span class="cx"> case GetGlobalVar:
</span><span class="lines">@@ -630,6 +633,9 @@
</span><span class="cx"> case PutClosureVar:
</span><span class="cx"> case PutToArguments:
</span><span class="cx"> case Return:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
+ case TailCallForwardVarargs:
</ins><span class="cx"> case Throw:
</span><span class="cx"> case PutById:
</span><span class="cx"> case PutByIdFlush:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -191,8 +191,11 @@
</span><span class="cx"> case CompareEqConstant:
</span><span class="cx"> case CompareStrictEq:
</span><span class="cx"> case Call:
</span><ins>+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCallVarargsInlinedCaller:
+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case LoadVarargs:
</span><span class="cx"> case CallForwardVarargs:
</span><span class="lines">@@ -235,6 +238,9 @@
</span><span class="cx"> case Branch:
</span><span class="cx"> case Switch:
</span><span class="cx"> case Return:
</span><ins>+ case TailCall:
+ case TailCallVarargs:
+ case TailCallForwardVarargs:
</ins><span class="cx"> case Throw:
</span><span class="cx"> case ThrowReferenceError:
</span><span class="cx"> case CountExecution:
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -644,10 +644,20 @@
</span><span class="cx"> CallLinkInfo::CallType callType;
</span><span class="cx"> bool isVarargs = false;
</span><span class="cx"> bool isForwardVarargs = false;
</span><ins>+ bool isTail = false;
+ bool isEmulatedTail = false;
</ins><span class="cx"> switch (node->op()) {
</span><span class="cx"> case Call:
</span><span class="cx"> callType = CallLinkInfo::Call;
</span><span class="cx"> break;
</span><ins>+ case TailCall:
+ callType = CallLinkInfo::TailCall;
+ isTail = true;
+ break;
+ case TailCallInlinedCaller:
+ callType = CallLinkInfo::Call;
+ isEmulatedTail = true;
+ break;
</ins><span class="cx"> case Construct:
</span><span class="cx"> callType = CallLinkInfo::Construct;
</span><span class="cx"> break;
</span><span class="lines">@@ -655,6 +665,16 @@
</span><span class="cx"> callType = CallLinkInfo::CallVarargs;
</span><span class="cx"> isVarargs = true;
</span><span class="cx"> break;
</span><ins>+ case TailCallVarargs:
+ callType = CallLinkInfo::TailCallVarargs;
+ isVarargs = true;
+ isTail = true;
+ break;
+ case TailCallVarargsInlinedCaller:
+ callType = CallLinkInfo::CallVarargs;
+ isVarargs = true;
+ isEmulatedTail = true;
+ break;
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> callType = CallLinkInfo::ConstructVarargs;
</span><span class="cx"> isVarargs = true;
</span><span class="lines">@@ -663,6 +683,16 @@
</span><span class="cx"> callType = CallLinkInfo::CallVarargs;
</span><span class="cx"> isForwardVarargs = true;
</span><span class="cx"> break;
</span><ins>+ case TailCallForwardVarargs:
+ callType = CallLinkInfo::TailCallVarargs;
+ isTail = true;
+ isForwardVarargs = true;
+ break;
+ case TailCallForwardVarargsInlinedCaller:
+ callType = CallLinkInfo::CallVarargs;
+ isEmulatedTail = true;
+ isForwardVarargs = true;
+ break;
</ins><span class="cx"> case ConstructForwardVarargs:
</span><span class="cx"> callType = CallLinkInfo::ConstructVarargs;
</span><span class="cx"> isForwardVarargs = true;
</span><span class="lines">@@ -785,7 +815,14 @@
</span><span class="cx"> m_jit.store32(calleePayloadGPR, m_jit.calleeFramePayloadSlot(JSStack::Callee));
</span><span class="cx"> m_jit.store32(calleeTagGPR, m_jit.calleeFrameTagSlot(JSStack::Callee));
</span><span class="cx">
</span><del>- flushRegisters();
</del><ins>+ // FIXME: We should do an efficient move of the arguments into
+ // their target stack position instead of building then memmoving
+ // the callee frame.
+ // https://bugs.webkit.org/show_bug.cgi?id=147508
+ if (isTail)
+ ASSERT(isFlushed());
+ else
+ flushRegisters();
</ins><span class="cx">
</span><span class="cx"> GPRFlushedCallResult resultPayload(this);
</span><span class="cx"> GPRFlushedCallResult2 resultTag(this);
</span><span class="lines">@@ -795,15 +832,30 @@
</span><span class="cx"> JITCompiler::DataLabelPtr targetToCheck;
</span><span class="cx"> JITCompiler::JumpList slowPath;
</span><span class="cx">
</span><del>- m_jit.emitStoreCodeOrigin(node->origin.semantic);
</del><ins>+ CodeOrigin staticOrigin = node->origin.semantic;
+ ASSERT(!isTail || !staticOrigin.inlineCallFrame || !staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames());
+ ASSERT(!isEmulatedTail || (staticOrigin.inlineCallFrame && staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames()));
+ CodeOrigin dynamicOrigin =
+ isEmulatedTail ? *staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames() : staticOrigin;
+
+ m_jit.emitStoreCodeOrigin(dynamicOrigin);
</ins><span class="cx">
</span><span class="cx"> CallLinkInfo* info = m_jit.codeBlock()->addCallLinkInfo();
</span><span class="cx">
</span><span class="cx"> slowPath.append(m_jit.branchIfNotCell(callee.jsValueRegs()));
</span><span class="cx"> slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
</span><span class="cx">
</span><del>- JITCompiler::Call fastCall = m_jit.nearCall();
</del><ins>+ if (isTail) {
+ m_jit.emitRestoreCalleeSaves();
+ // FIXME: We should do an efficient move of the arguments into
+ // their target stack position instead of building then memmoving
+ // the callee frame.
+ // https://bugs.webkit.org/show_bug.cgi?id=147508
+ m_jit.prepareForTailCallSlow();
+ }
</ins><span class="cx">
</span><ins>+ JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
+
</ins><span class="cx"> JITCompiler::Jump done = m_jit.jump();
</span><span class="cx">
</span><span class="cx"> slowPath.link(&m_jit);
</span><span class="lines">@@ -825,17 +877,22 @@
</span><span class="cx">
</span><span class="cx"> done.link(&m_jit);
</span><span class="cx">
</span><del>- m_jit.setupResults(resultPayloadGPR, resultTagGPR);
</del><ins>+ if (isTail)
+ m_jit.breakpoint();
+ else {
+ m_jit.setupResults(resultPayloadGPR, resultTagGPR);
</ins><span class="cx">
</span><del>- jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly);
</del><ins>+ jsValueResult(resultTagGPR, resultPayloadGPR, node, DataFormatJS, UseChildrenCalledExplicitly);
</ins><span class="cx">
</span><ins>+ // After the calls are done, we need to reestablish our stack
+ // pointer. We rely on this for varargs calls, calls with arity
+ // mismatch (the callframe is slided) and tail calls.
+ m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
+ }
+
</ins><span class="cx"> info->setUpCall(callType, node->origin.semantic, calleePayloadGPR);
</span><span class="cx"> m_jit.addJSCall(fastCall, slowCall, targetToCheck, info);
</span><del>-
- // After the calls are done, we need to reestablish our stack
- // pointer. We rely on this for varargs calls, calls with arity
- // mismatch (the callframe is slided) and tail calls.
- m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
</del><ins>+
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<bool strict>
</span><span class="lines">@@ -4219,10 +4276,16 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case Call:
</span><ins>+ case TailCall:
+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCallVarargs:
+ case TailCallVarargsInlinedCaller:
+ case ConstructVarargs:
</ins><span class="cx"> case CallForwardVarargs:
</span><del>- case ConstructVarargs:
</del><ins>+ case TailCallForwardVarargs:
+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> case ConstructForwardVarargs:
</span><span class="cx"> emitCall(node);
</span><span class="cx"> break;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -630,10 +630,20 @@
</span><span class="cx"> CallLinkInfo::CallType callType;
</span><span class="cx"> bool isVarargs = false;
</span><span class="cx"> bool isForwardVarargs = false;
</span><ins>+ bool isTail = false;
+ bool isEmulatedTail = false;
</ins><span class="cx"> switch (node->op()) {
</span><span class="cx"> case Call:
</span><span class="cx"> callType = CallLinkInfo::Call;
</span><span class="cx"> break;
</span><ins>+ case TailCall:
+ callType = CallLinkInfo::TailCall;
+ isTail = true;
+ break;
+ case TailCallInlinedCaller:
+ callType = CallLinkInfo::Call;
+ isEmulatedTail = true;
+ break;
</ins><span class="cx"> case Construct:
</span><span class="cx"> callType = CallLinkInfo::Construct;
</span><span class="cx"> break;
</span><span class="lines">@@ -641,6 +651,16 @@
</span><span class="cx"> callType = CallLinkInfo::CallVarargs;
</span><span class="cx"> isVarargs = true;
</span><span class="cx"> break;
</span><ins>+ case TailCallVarargs:
+ callType = CallLinkInfo::TailCallVarargs;
+ isVarargs = true;
+ isTail = true;
+ break;
+ case TailCallVarargsInlinedCaller:
+ callType = CallLinkInfo::CallVarargs;
+ isVarargs = true;
+ isEmulatedTail = true;
+ break;
</ins><span class="cx"> case ConstructVarargs:
</span><span class="cx"> callType = CallLinkInfo::ConstructVarargs;
</span><span class="cx"> isVarargs = true;
</span><span class="lines">@@ -653,6 +673,16 @@
</span><span class="cx"> callType = CallLinkInfo::ConstructVarargs;
</span><span class="cx"> isForwardVarargs = true;
</span><span class="cx"> break;
</span><ins>+ case TailCallForwardVarargs:
+ callType = CallLinkInfo::TailCallVarargs;
+ isTail = true;
+ isForwardVarargs = true;
+ break;
+ case TailCallForwardVarargsInlinedCaller:
+ callType = CallLinkInfo::CallVarargs;
+ isEmulatedTail = true;
+ isForwardVarargs = true;
+ break;
</ins><span class="cx"> default:
</span><span class="cx"> DFG_CRASH(m_jit.graph(), node, "bad node type");
</span><span class="cx"> break;
</span><span class="lines">@@ -761,23 +791,43 @@
</span><span class="cx"> GPRReg calleeGPR = callee.gpr();
</span><span class="cx"> callee.use();
</span><span class="cx"> m_jit.store64(calleeGPR, JITCompiler::calleeFrameSlot(JSStack::Callee));
</span><del>-
- flushRegisters();
</del><span class="cx">
</span><ins>+ // FIXME: We should do an efficient move of the arguments into
+ // their target stack position instead of building then memmoving
+ // the callee frame.
+ // https://bugs.webkit.org/show_bug.cgi?id=147508
+ if (isTail)
+ ASSERT(isFlushed());
+ else
+ flushRegisters();
+
</ins><span class="cx"> GPRFlushedCallResult result(this);
</span><span class="cx"> GPRReg resultGPR = result.gpr();
</span><span class="cx">
</span><del>- JITCompiler::DataLabelPtr targetToCheck;
- JITCompiler::Jump slowPath;
</del><ins>+ CodeOrigin staticOrigin = node->origin.semantic;
+ ASSERT(!isTail || !staticOrigin.inlineCallFrame || !staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames());
+ ASSERT(!isEmulatedTail || (staticOrigin.inlineCallFrame && staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames()));
+ CodeOrigin dynamicOrigin =
+ isEmulatedTail ? *staticOrigin.inlineCallFrame->getCallerSkippingDeadFrames() : staticOrigin;
</ins><span class="cx">
</span><del>- m_jit.emitStoreCodeOrigin(node->origin.semantic);
</del><ins>+ m_jit.emitStoreCodeOrigin(dynamicOrigin);
</ins><span class="cx">
</span><span class="cx"> CallLinkInfo* callLinkInfo = m_jit.codeBlock()->addCallLinkInfo();
</span><del>-
- slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0));
</del><span class="cx">
</span><del>- JITCompiler::Call fastCall = m_jit.nearCall();
</del><ins>+ JITCompiler::DataLabelPtr targetToCheck;
+ JITCompiler::Jump slowPath = m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleeGPR, targetToCheck, MacroAssembler::TrustedImmPtr(0));
</ins><span class="cx">
</span><ins>+ if (isTail) {
+ m_jit.emitRestoreCalleeSaves();
+ // FIXME: We should do an efficient move of the arguments into
+ // their target stack position instead of building then memmoving
+ // the callee frame.
+ // https://bugs.webkit.org/show_bug.cgi?id=147508
+ m_jit.prepareForTailCallSlow();
+ }
+
+ JITCompiler::Call fastCall = isTail ? m_jit.nearTailCall() : m_jit.nearCall();
+
</ins><span class="cx"> JITCompiler::Jump done = m_jit.jump();
</span><span class="cx">
</span><span class="cx"> slowPath.link(&m_jit);
</span><span class="lines">@@ -785,20 +835,25 @@
</span><span class="cx"> m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
</span><span class="cx"> m_jit.move(MacroAssembler::TrustedImmPtr(callLinkInfo), GPRInfo::regT2); // Link info needs to be in regT2
</span><span class="cx"> JITCompiler::Call slowCall = m_jit.nearCall();
</span><del>-
</del><ins>+
</ins><span class="cx"> done.link(&m_jit);
</span><del>-
- m_jit.move(GPRInfo::returnValueGPR, resultGPR);
-
- jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly);
-
</del><ins>+
+ if (isTail)
+ m_jit.breakpoint();
+ else {
+ m_jit.move(GPRInfo::returnValueGPR, resultGPR);
+
+ jsValueResult(resultGPR, m_currentNode, DataFormatJS, UseChildrenCalledExplicitly);
+
+ // After the calls are done, we need to reestablish our stack
+ // pointer. We rely on this for varargs calls, calls with arity
+ // mismatch (the callframe is slided) and tail calls.
+ m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
+ }
+
</ins><span class="cx"> callLinkInfo->setUpCall(callType, m_currentNode->origin.semantic, calleeGPR);
</span><span class="cx"> m_jit.addJSCall(fastCall, slowCall, targetToCheck, callLinkInfo);
</span><span class="cx">
</span><del>- // After the calls are done, we need to reestablish our stack
- // pointer. We rely on this for varargs calls, calls with arity
- // mismatch (the callframe is slided) and tail calls.
- m_jit.addPtr(TrustedImm32(m_jit.graph().stackPointerOffset() * sizeof(Register)), GPRInfo::callFrameRegister, JITCompiler::stackPointerRegister);
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Clang should allow unreachable [[clang::fallthrough]] in template functions if any template expansion uses it
</span><span class="lines">@@ -4231,14 +4286,20 @@
</span><span class="cx"> break;
</span><span class="cx">
</span><span class="cx"> case Call:
</span><ins>+ case TailCall:
+ case TailCallInlinedCaller:
</ins><span class="cx"> case Construct:
</span><span class="cx"> case CallVarargs:
</span><ins>+ case TailCallVarargs:
+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> case CallForwardVarargs:
</span><span class="cx"> case ConstructVarargs:
</span><span class="cx"> case ConstructForwardVarargs:
</span><ins>+ case TailCallForwardVarargs:
+ case TailCallForwardVarargsInlinedCaller:
</ins><span class="cx"> emitCall(node);
</span><span class="cx"> break;
</span><del>-
</del><ins>+
</ins><span class="cx"> case LoadVarargs: {
</span><span class="cx"> LoadVarargsData* data = node->loadVarargsData();
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoredfgDFGVarargsForwardingPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/dfg/DFGVarargsForwardingPhase.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -135,6 +135,8 @@
</span><span class="cx">
</span><span class="cx"> case CallVarargs:
</span><span class="cx"> case ConstructVarargs:
</span><ins>+ case TailCallVarargs:
+ case TailCallVarargsInlinedCaller:
</ins><span class="cx"> if (node->child1() == candidate || node->child3() == candidate) {
</span><span class="cx"> if (verbose)
</span><span class="cx"> dataLog(" Escape at ", node, "\n");
</span><span class="lines">@@ -282,7 +284,19 @@
</span><span class="cx"> break;
</span><span class="cx"> node->setOpAndDefaultFlags(ConstructForwardVarargs);
</span><span class="cx"> break;
</span><del>-
</del><ins>+
+ case TailCallVarargs:
+ if (node->child2() != candidate)
+ break;
+ node->setOpAndDefaultFlags(TailCallForwardVarargs);
+ break;
+
+ case TailCallVarargsInlinedCaller:
+ if (node->child2() != candidate)
+ break;
+ node->setOpAndDefaultFlags(TailCallForwardVarargsInlinedCaller);
+ break;
+
</ins><span class="cx"> case SetLocal:
</span><span class="cx"> // This is super odd. We don't have to do anything here, since in DFG IR, the phantom
</span><span class="cx"> // arguments nodes do produce a JSValue. Also, we know that if this SetLocal referenecs a
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreinterpreterCallFramecpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/interpreter/CallFrame.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/interpreter/CallFrame.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/interpreter/CallFrame.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -85,7 +85,7 @@
</span><span class="cx"> if (inlineCallFrame->baselineCodeBlock() == codeBlock)
</span><span class="cx"> return codeOrigin.bytecodeIndex;
</span><span class="cx">
</span><del>- codeOrigin = inlineCallFrame->caller;
</del><ins>+ codeOrigin = *inlineCallFrame->getCallerSkippingDeadFrames();
</ins><span class="cx"> inlineCallFrame = codeOrigin.inlineCallFrame;
</span><span class="cx"> }
</span><span class="cx"> return codeOrigin.bytecodeIndex;
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoreinterpreterStackVisitorcpp"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/interpreter/StackVisitor.cpp (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/interpreter/StackVisitor.cpp        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/interpreter/StackVisitor.cpp        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -59,8 +59,16 @@
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx"> if (m_frame.isInlinedFrame()) {
</span><span class="cx"> InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame();
</span><del>- CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller;
- readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
</del><ins>+ CodeOrigin* callerCodeOrigin = inlineCallFrame->getCallerSkippingDeadFrames();
+ if (!callerCodeOrigin) {
+ while (inlineCallFrame) {
+ readInlinedFrame(m_frame.callFrame(), &inlineCallFrame->directCaller);
+ inlineCallFrame = m_frame.inlineCallFrame();
+ }
+ m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
+ readFrame(m_frame.callerFrame());
+ } else
+ readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
</ins><span class="cx"> return;
</span><span class="cx"> }
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCorejitCCallHelpersh"></a>
<div class="modfile"><h4>Modified: branches/jsc-tailcall/Source/JavaScriptCore/jit/CCallHelpers.h (187790 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/jit/CCallHelpers.h        2015-08-04 00:30:45 UTC (rev 187790)
+++ branches/jsc-tailcall/Source/JavaScriptCore/jit/CCallHelpers.h        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -2067,6 +2067,8 @@
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx"> COMPILE_ASSERT(sizeof(void*) * 2 == sizeof(Register), Register_is_two_pointers_sized);
</span><span class="cx"> lshift32(TrustedImm32(1), temp2);
</span><ins>+#else
+ COMPILE_ASSERT(sizeof(void*) == sizeof(Register), Register_is_one_pointer_sized);
</ins><span class="cx"> #endif
</span><span class="cx">
</span><span class="cx"> // Do the sliding
</span></span></pre></div>
<a id="branchesjsctailcallSourceJavaScriptCoretestsstressdfgtailcallsjs"></a>
<div class="addfile"><h4>Added: branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js (0 => 187791)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js         (rev 0)
+++ branches/jsc-tailcall/Source/JavaScriptCore/tests/stress/dfg-tail-calls.js        2015-08-04 00:39:19 UTC (rev 187791)
</span><span class="lines">@@ -0,0 +1,56 @@
</span><ins>+(function nonInlinedTailCall() {
+ function callee() { if (callee.caller != nonInlinedTailCall) throw new Error(); }
+ noInline(callee);
+
+ function caller() { "use strict"; return callee(); }
+
+ for (var i = 0; i < 10000; ++i)
+ caller();
+
+ function loop(n) { "use strict"; if (n > 0) return loop(n - 1); }
+ noInline(loop);
+
+ loop(1000000);
+})();
+
+(function inlinedTailCall() {
+ function callee() { if (callee.caller != inlinedTailCall) throw new Error(); }
+ function caller() { "use strict"; return callee(); }
+
+ for (var i = 0; i < 10000; ++i)
+ caller();
+
+ function loop(n) { "use strict"; if (n > 0) return loop(n - 1); }
+
+ loop(1000000);
+})();
+
+(function nonInlinedEmulatedTailCall() {
+ function emulator() { caller(); }
+ function callee() { if (callee.caller != emulator) throw new Error(); }
+ noInline(callee);
+ function caller() { "use strict"; return callee(); }
+
+ for (var i = 0; i < 10000; ++i)
+ emulator();
+
+ function pad(n) { "use strict"; return loop(n); }
+ function loop(n) { "use strict"; if (n > 0) return pad(n - 1); }
+ noInline(loop);
+
+ loop(1000000);
+})();
+
+(function inlinedEmulatedTailCall() {
+ function emulator() { caller(); }
+ function callee() { if (callee.caller != emulator) throw new Error(); }
+ function caller() { "use strict"; return callee(); }
+
+ for (var i = 0; i < 10000; ++i)
+ emulator();
+
+ function pad(n) { "use strict"; return loop(n); }
+ function loop(n) { "use strict"; if (n > 0) return pad(n - 1); }
+
+ loop(1000000);
+})();
</ins></span></pre>
</div>
</div>
</body>
</html>