<!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>[162788] branches/jsCStack/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/162788">162788</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-01-25 16:44:46 -0800 (Sat, 25 Jan 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>FTL should do polyvariant Call/Construct inlining
https://bugs.webkit.org/show_bug.cgi?id=127335
Reviewed by Oliver Hunt.
Imagine that you have a call stack like foo calls bar, which calls baz. Lets say that
there's another call stack where bar calls something other than baz at the same
callsite, but whenver bar is called from foo, it always calls baz.
This bar->baz callsite can be said to be polymorphic, because it may call things other
than baz in some cases.
But if we conduct a polyvariant analysis - that is, one that accounts for the call
stack when reporting results - then this call appears monomorphic whenever bar gets
called from foo. A polyvariant analysis of callsites will report results of the form
"when statement S ran on a call stack that included functions f, g, etc then the set
of possible callees is bounded by ...". This is in contrast to a monovariant analysis
that will attempt to construct a bounding set of callees without adding the call stack
as a contingency.
Prior to this patch, all inlining decisions were made based on a monovariant dynamic
analysis.
This patch allows the FTL to make its Call/Construct inlining decisions based on a
polyvariant analysis. That analysis is cleverly simple: we just ask the DFG to do the
same "analysis" that the LLInt and Baseline JIT perform. That "analysis" is just an
inline cache plus a slow-path count. But the DFG has performed inlining. Hence each
callsite that the DFG reports information for is actually sitting on a static call
stack. When the DFG reports the status of its call inline caches, it can report the
information with a (short) snippet of call stack as a kind of contingency, much like a
polyvariant analysis would.
Consider the foo->bar->baz example. Lets say that foo's call to bar is trivially
monomorphic, and the DFG inlines it. The DFG won't be able to then inline the call
from foo->bar to baz because when we ask the Baseline JIT profiling what the status of
the bar->baz call is, the profiling will say "polymorphic". That's because that
profiling doesn't have any context sensitivity, and so it doesn't know that the call
would be monomorphic if foo was bar's caller.
But, with this patch, once we tier-up from the DFG to the FTL, the FTL will be able to
ask the DFG: "hey, what do you know about the callsite to baz in foo->bar?" The DFG
had, as we said above, inlined bar into foo and so it sees that callsite in its
proper context. That call inline cache would be monomorphic. The FTL would then be
able to inline baz into foo->bar.
This will eventually benefit V8v7/raytrace, but we still have some more things to do
before we can close the loop on this. Right now, the callsite in question is not an
inlining candidate because it's op_call_varargs. We'll fix that eventually.
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::computeFor):
(JSC::CallLinkStatus::computeDFGStatuses):
* bytecode/CallLinkStatus.h:
(JSC::CallLinkStatus::makeClosureCall):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::specialFastCaseProfileForBytecodeOffset):
* bytecode/CodeOrigin.cpp:
(JSC::CodeOrigin::isApproximatelyEqualTo):
(JSC::CodeOrigin::approximateHash):
* bytecode/CodeOrigin.h:
(JSC::CodeOrigin::CodeOrigin):
(JSC::CodeOrigin::deletedMarker):
(JSC::CodeOriginApproximateHash::hash):
(JSC::CodeOriginApproximateHash::equal):
* bytecode/DFGExitProfile.cpp:
(JSC::DFG::ExitProfile::add):
(JSC::DFG::ExitProfile::hasExitSite):
* bytecode/DFGExitProfile.h:
(JSC::DFG::FrequentExitSite::FrequentExitSite):
(JSC::DFG::FrequentExitSite::operator==):
(JSC::DFG::FrequentExitSite::subsumes):
(JSC::DFG::FrequentExitSite::hash):
(JSC::DFG::FrequentExitSite::jitType):
(JSC::DFG::FrequentExitSite::withJITType):
(JSC::DFG::QueryableExitProfile::hasExitSite):
* bytecode/ExitKind.h:
* bytecode/ExitingJITType.h: Added.
(JSC::exitingJITTypeFor):
* bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp:
(JSC::ProfiledCodeBlockJettisoningWatchpoint::fireInternal):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGCapabilities.h:
(JSC::DFG::inlineFunctionForCallCapabilityLevel):
(JSC::DFG::inlineFunctionForClosureCallCapabilityLevel):
(JSC::DFG::inlineFunctionForConstructCapabilityLevel):
(JSC::DFG::inlineFunctionForCapabilityLevel):
* dfg/DFGCommon.h:
* dfg/DFGDriver.cpp:
(JSC::DFG::compileImpl):
(JSC::DFG::compile):
* dfg/DFGDriver.h:
* dfg/DFGFailedFinalizer.cpp:
(JSC::DFG::FailedFinalizer::codeSize):
* dfg/DFGFailedFinalizer.h:
* dfg/DFGFinalizer.h:
* dfg/DFGJITCode.h:
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::currentJSCallIndex):
* dfg/DFGJITFinalizer.cpp:
(JSC::DFG::JITFinalizer::codeSize):
* dfg/DFGJITFinalizer.h:
* dfg/DFGOSRExit.h:
(JSC::DFG::OSRExit::considerAddingAsFrequentExitSite):
* dfg/DFGOSRExitBase.cpp:
(JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSiteSlow):
* dfg/DFGOSRExitBase.h:
(JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite):
* dfg/DFGOperations.cpp:
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::Plan):
(JSC::DFG::Plan::compileInThread):
* dfg/DFGPlan.h:
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::prepareJITCodeForTierUp):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* ftl/FTLJITFinalizer.cpp:
(JSC::FTL::JITFinalizer::codeSize):
* ftl/FTLJITFinalizer.h:
* ftl/FTLOSRExit.h:
(JSC::FTL::OSRExit::considerAddingAsFrequentExitSite):
* jit/JITCode.h:
* jit/JITOperations.cpp:
* runtime/Options.h:
* tests/stress/simple-polyvariant-call-inlining-example.js: Added.
(foo):
(fuzz):
(bar):
(baz1):
(baz2):</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesjsCStackSourceJavaScriptCoreChangeLog">branches/jsCStack/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">branches/jsCStack/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeCallLinkStatuscpp">branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeCallLinkStatush">branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeCodeBlockh">branches/jsCStack/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeCodeOrigincpp">branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeCodeOriginh">branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeDFGExitProfilecpp">branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeDFGExitProfileh">branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeExitKindh">branches/jsCStack/Source/JavaScriptCore/bytecode/ExitKind.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeProfiledCodeBlockJettisoningWatchpointcpp">branches/jsCStack/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGByteCodeParsercpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGCapabilitiescpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGCapabilitiesh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGCommonh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGCommon.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGDrivercpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGDriverh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGFailedFinalizercpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGFailedFinalizerh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGFinalizerh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGFinalizer.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGJITCodeh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCode.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGJITCompilercpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGJITCompilerh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGJITFinalizercpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGJITFinalizerh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGOSRExith">branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExit.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGOSRExitBasecpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGOSRExitBaseh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGOperationscpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGOperations.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGPlancpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGPlanh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJITcpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJITh">branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreftlFTLJITFinalizercpp">branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreftlFTLJITFinalizerh">branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreftlFTLOSRExith">branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExit.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITCodeh">branches/jsCStack/Source/JavaScriptCore/jit/JITCode.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCorejitJITOperationscpp">branches/jsCStack/Source/JavaScriptCore/jit/JITOperations.cpp</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoreruntimeOptionsh">branches/jsCStack/Source/JavaScriptCore/runtime/Options.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#branchesjsCStackSourceJavaScriptCorebytecodeExitingJITTypeh">branches/jsCStack/Source/JavaScriptCore/bytecode/ExitingJITType.h</a></li>
<li><a href="#branchesjsCStackSourceJavaScriptCoretestsstresssimplepolyvariantcallinliningexamplejs">branches/jsCStack/Source/JavaScriptCore/tests/stress/simple-polyvariant-call-inlining-example.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesjsCStackSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ChangeLog (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ChangeLog        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/ChangeLog        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1,3 +1,146 @@
</span><ins>+2014-01-25 Filip Pizlo <fpizlo@apple.com>
+
+ FTL should do polyvariant Call/Construct inlining
+ https://bugs.webkit.org/show_bug.cgi?id=127335
+
+ Reviewed by Oliver Hunt.
+
+ Imagine that you have a call stack like foo calls bar, which calls baz. Lets say that
+ there's another call stack where bar calls something other than baz at the same
+ callsite, but whenver bar is called from foo, it always calls baz.
+
+ This bar->baz callsite can be said to be polymorphic, because it may call things other
+ than baz in some cases.
+
+ But if we conduct a polyvariant analysis - that is, one that accounts for the call
+ stack when reporting results - then this call appears monomorphic whenever bar gets
+ called from foo. A polyvariant analysis of callsites will report results of the form
+ "when statement S ran on a call stack that included functions f, g, etc then the set
+ of possible callees is bounded by ...". This is in contrast to a monovariant analysis
+ that will attempt to construct a bounding set of callees without adding the call stack
+ as a contingency.
+
+ Prior to this patch, all inlining decisions were made based on a monovariant dynamic
+ analysis.
+
+ This patch allows the FTL to make its Call/Construct inlining decisions based on a
+ polyvariant analysis. That analysis is cleverly simple: we just ask the DFG to do the
+ same "analysis" that the LLInt and Baseline JIT perform. That "analysis" is just an
+ inline cache plus a slow-path count. But the DFG has performed inlining. Hence each
+ callsite that the DFG reports information for is actually sitting on a static call
+ stack. When the DFG reports the status of its call inline caches, it can report the
+ information with a (short) snippet of call stack as a kind of contingency, much like a
+ polyvariant analysis would.
+
+ Consider the foo->bar->baz example. Lets say that foo's call to bar is trivially
+ monomorphic, and the DFG inlines it. The DFG won't be able to then inline the call
+ from foo->bar to baz because when we ask the Baseline JIT profiling what the status of
+ the bar->baz call is, the profiling will say "polymorphic". That's because that
+ profiling doesn't have any context sensitivity, and so it doesn't know that the call
+ would be monomorphic if foo was bar's caller.
+
+ But, with this patch, once we tier-up from the DFG to the FTL, the FTL will be able to
+ ask the DFG: "hey, what do you know about the callsite to baz in foo->bar?" The DFG
+ had, as we said above, inlined bar into foo and so it sees that callsite in its
+ proper context. That call inline cache would be monomorphic. The FTL would then be
+ able to inline baz into foo->bar.
+
+ This will eventually benefit V8v7/raytrace, but we still have some more things to do
+ before we can close the loop on this. Right now, the callsite in question is not an
+ inlining candidate because it's op_call_varargs. We'll fix that eventually.
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * bytecode/CallLinkStatus.cpp:
+ (JSC::CallLinkStatus::computeFor):
+ (JSC::CallLinkStatus::computeDFGStatuses):
+ * bytecode/CallLinkStatus.h:
+ (JSC::CallLinkStatus::makeClosureCall):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::specialFastCaseProfileForBytecodeOffset):
+ * bytecode/CodeOrigin.cpp:
+ (JSC::CodeOrigin::isApproximatelyEqualTo):
+ (JSC::CodeOrigin::approximateHash):
+ * bytecode/CodeOrigin.h:
+ (JSC::CodeOrigin::CodeOrigin):
+ (JSC::CodeOrigin::deletedMarker):
+ (JSC::CodeOriginApproximateHash::hash):
+ (JSC::CodeOriginApproximateHash::equal):
+ * bytecode/DFGExitProfile.cpp:
+ (JSC::DFG::ExitProfile::add):
+ (JSC::DFG::ExitProfile::hasExitSite):
+ * bytecode/DFGExitProfile.h:
+ (JSC::DFG::FrequentExitSite::FrequentExitSite):
+ (JSC::DFG::FrequentExitSite::operator==):
+ (JSC::DFG::FrequentExitSite::subsumes):
+ (JSC::DFG::FrequentExitSite::hash):
+ (JSC::DFG::FrequentExitSite::jitType):
+ (JSC::DFG::FrequentExitSite::withJITType):
+ (JSC::DFG::QueryableExitProfile::hasExitSite):
+ * bytecode/ExitKind.h:
+ * bytecode/ExitingJITType.h: Added.
+ (JSC::exitingJITTypeFor):
+ * bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp:
+ (JSC::ProfiledCodeBlockJettisoningWatchpoint::fireInternal):
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::handleCall):
+ (JSC::DFG::ByteCodeParser::handleInlining):
+ (JSC::DFG::ByteCodeParser::parse):
+ * dfg/DFGCapabilities.cpp:
+ (JSC::DFG::capabilityLevel):
+ * dfg/DFGCapabilities.h:
+ (JSC::DFG::inlineFunctionForCallCapabilityLevel):
+ (JSC::DFG::inlineFunctionForClosureCallCapabilityLevel):
+ (JSC::DFG::inlineFunctionForConstructCapabilityLevel):
+ (JSC::DFG::inlineFunctionForCapabilityLevel):
+ * dfg/DFGCommon.h:
+ * dfg/DFGDriver.cpp:
+ (JSC::DFG::compileImpl):
+ (JSC::DFG::compile):
+ * dfg/DFGDriver.h:
+ * dfg/DFGFailedFinalizer.cpp:
+ (JSC::DFG::FailedFinalizer::codeSize):
+ * dfg/DFGFailedFinalizer.h:
+ * dfg/DFGFinalizer.h:
+ * dfg/DFGJITCode.h:
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::link):
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::JITCompiler::currentJSCallIndex):
+ * dfg/DFGJITFinalizer.cpp:
+ (JSC::DFG::JITFinalizer::codeSize):
+ * dfg/DFGJITFinalizer.h:
+ * dfg/DFGOSRExit.h:
+ (JSC::DFG::OSRExit::considerAddingAsFrequentExitSite):
+ * dfg/DFGOSRExitBase.cpp:
+ (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSiteSlow):
+ * dfg/DFGOSRExitBase.h:
+ (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSite):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGPlan.cpp:
+ (JSC::DFG::Plan::Plan):
+ (JSC::DFG::Plan::compileInThread):
+ * dfg/DFGPlan.h:
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::prepareJITCodeForTierUp):
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT.h:
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * ftl/FTLJITFinalizer.cpp:
+ (JSC::FTL::JITFinalizer::codeSize):
+ * ftl/FTLJITFinalizer.h:
+ * ftl/FTLOSRExit.h:
+ (JSC::FTL::OSRExit::considerAddingAsFrequentExitSite):
+ * jit/JITCode.h:
+ * jit/JITOperations.cpp:
+ * runtime/Options.h:
+ * tests/stress/simple-polyvariant-call-inlining-example.js: Added.
+ (foo):
+ (fuzz):
+ (bar):
+ (baz1):
+ (baz2):
+
</ins><span class="cx"> 2014-01-24 Filip Pizlo <fpizlo@apple.com>
</span><span class="cx">
</span><span class="cx"> DFG should allow inlining of op_call_varargs calls
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -210,6 +210,7 @@
</span><span class="cx">                 0F38B01917CFE75500B144D3 /* DFGCompilationMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F38B01517CFE75500B144D3 /* DFGCompilationMode.cpp */; };
</span><span class="cx">                 0F38B01A17CFE75500B144D3 /* DFGCompilationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F38B01617CFE75500B144D3 /* DFGCompilationMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F3AC752183EA1040032029F /* StackAlignment.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3AC751183EA1040032029F /* StackAlignment.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F3AC754188E5EC80032029F /* ExitingJITType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3AC753188E5EC80032029F /* ExitingJITType.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */; };
</span><span class="cx">                 0F3B3A1B153E68F4003ED0FF /* DFGConstantFoldingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3B3A18153E68EF003ED0FF /* DFGConstantFoldingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F3B3A271544C995003ED0FF /* DFGCFGSimplificationPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B3A241544C991003ED0FF /* DFGCFGSimplificationPhase.cpp */; };
</span><span class="lines">@@ -1604,6 +1605,7 @@
</span><span class="cx">                 0F38B01517CFE75500B144D3 /* DFGCompilationMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCompilationMode.cpp; path = dfg/DFGCompilationMode.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 0F38B01617CFE75500B144D3 /* DFGCompilationMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCompilationMode.h; path = dfg/DFGCompilationMode.h; sourceTree = "<group>"; };
</span><span class="cx">                 0F3AC751183EA1040032029F /* StackAlignment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackAlignment.h; sourceTree = "<group>"; };
</span><ins>+                0F3AC753188E5EC80032029F /* ExitingJITType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExitingJITType.h; sourceTree = "<group>"; };
</ins><span class="cx">                 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGConstantFoldingPhase.cpp; path = dfg/DFGConstantFoldingPhase.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 0F3B3A18153E68EF003ED0FF /* DFGConstantFoldingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGConstantFoldingPhase.h; path = dfg/DFGConstantFoldingPhase.h; sourceTree = "<group>"; };
</span><span class="cx">                 0F3B3A241544C991003ED0FF /* DFGCFGSimplificationPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFGSimplificationPhase.cpp; path = dfg/DFGCFGSimplificationPhase.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -4341,6 +4343,7 @@
</span><span class="cx">                                 969A07920ED1D3AE00F1F681 /* EvalCodeCache.h */,
</span><span class="cx">                                 0F56A1D415001CF2002992B1 /* ExecutionCounter.cpp */,
</span><span class="cx">                                 0F56A1D115000F31002992B1 /* ExecutionCounter.h */,
</span><ins>+                                0F3AC753188E5EC80032029F /* ExitingJITType.h */,
</ins><span class="cx">                                 0FB105821675480C00F8AB6E /* ExitKind.cpp */,
</span><span class="cx">                                 0FB105831675480C00F8AB6E /* ExitKind.h */,
</span><span class="cx">                                 0F0B83AA14BCF5B900885B4F /* ExpressionRangeInfo.h */,
</span><span class="lines">@@ -4967,6 +4970,7 @@
</span><span class="cx">                                 BC18C4230E16F5CD00B34460 /* JSLock.h in Headers */,
</span><span class="cx">                                 C25D709C16DE99F400FCA6BC /* JSManagedValue.h in Headers */,
</span><span class="cx">                                 A700874217CBE8EB00C3E643 /* JSMap.h in Headers */,
</span><ins>+                                0F3AC754188E5EC80032029F /* ExitingJITType.h in Headers */,
</ins><span class="cx">                                 0F6B1CC41862C47800845D97 /* FTLRegisterAtOffset.h in Headers */,
</span><span class="cx">                                 14874AE415EBDE4A002E3587 /* JSNameScope.h in Headers */,
</span><span class="cx">                                 BC18C4240E16F5CD00B34460 /* JSObject.h in Headers */,
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeCallLinkStatuscpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -26,13 +26,17 @@
</span><span class="cx"> #include "config.h"
</span><span class="cx"> #include "CallLinkStatus.h"
</span><span class="cx">
</span><ins>+#include "CallLinkInfo.h"
</ins><span class="cx"> #include "CodeBlock.h"
</span><ins>+#include "DFGJITCode.h"
</ins><span class="cx"> #include "LLIntCallLinkInfo.h"
</span><span class="cx"> #include "Operations.h"
</span><span class="cx"> #include <wtf/CommaPrinter.h>
</span><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><ins>+static const bool verbose = false;
+
</ins><span class="cx"> CallLinkStatus::CallLinkStatus(JSValue value)
</span><span class="cx"> : m_callTarget(value)
</span><span class="cx"> , m_executable(0)
</span><span class="lines">@@ -126,23 +130,107 @@
</span><span class="cx"> return takesSlowPath();
</span><span class="cx">
</span><span class="cx"> CallLinkInfo& callLinkInfo = profiledBlock->getCallLinkInfo(bytecodeIndex);
</span><ins>+
+ CallLinkStatus result = computeFor(locker, callLinkInfo);
+ if (!result)
+ return computeFromLLInt(locker, profiledBlock, bytecodeIndex);
+
+ if (profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadFunction)))
+ result.makeClosureCall();
+
+ return result;
+#else
+ return CallLinkStatus();
+#endif
+}
+
+CallLinkStatus CallLinkStatus::computeFor(const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo)
+{
</ins><span class="cx"> if (callLinkInfo.stub)
</span><span class="cx"> return CallLinkStatus(callLinkInfo.stub->executable(), callLinkInfo.stub->structure());
</span><span class="cx">
</span><span class="cx"> JSFunction* target = callLinkInfo.lastSeenCallee.get();
</span><span class="cx"> if (!target)
</span><del>- return computeFromLLInt(locker, profiledBlock, bytecodeIndex);
</del><ins>+ return CallLinkStatus();
</ins><span class="cx">
</span><del>- if (callLinkInfo.hasSeenClosure
- || profiledBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadFunction)))
</del><ins>+ if (callLinkInfo.hasSeenClosure)
</ins><span class="cx"> return CallLinkStatus(target->executable(), target->structure());
</span><span class="cx">
</span><span class="cx"> return CallLinkStatus(target);
</span><del>-#else
- return CallLinkStatus();
-#endif
</del><span class="cx"> }
</span><span class="cx">
</span><ins>+void CallLinkStatus::computeDFGStatuses(
+ CodeBlock* dfgCodeBlock, CallLinkStatus::ContextMap& map)
+{
+#if ENABLE(DFG_JIT)
+ RELEASE_ASSERT(dfgCodeBlock->jitType() == JITCode::DFGJIT);
+ CodeBlock* baselineCodeBlock = dfgCodeBlock->alternative();
+ DFG::JITCode* jitCode = dfgCodeBlock->jitCode()->dfg();
+ RELEASE_ASSERT(dfgCodeBlock->numberOfCallLinkInfos() <= jitCode->slowPathCalls.size());
+
+ for (size_t i = dfgCodeBlock->numberOfCallLinkInfos(); i--;) {
+ CallLinkInfo& info = dfgCodeBlock->callLinkInfo(i);
+ CodeOrigin codeOrigin = info.codeOrigin;
+
+ bool takeSlowPath;
+ bool badFunction;
+
+ // Check if we had already previously made a terrible mistake in the FTL for this
+ // code origin. Note that this is approximate because we could have a monovariant
+ // inline in the FTL that ended up failing. We should fix that at some point by
+ // having data structures to track the context of frequent exits. This is currently
+ // challenging because it would require creating a CodeOrigin-based database in
+ // baseline CodeBlocks, but those CodeBlocks don't really have a place to put the
+ // InlineCallFrames.
+ {
+ ConcurrentJITLocker locker(baselineCodeBlock->m_lock);
+ CodeBlock* currentBaseline =
+ baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, baselineCodeBlock);
+ takeSlowPath =
+ currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadCache, ExitFromFTL))
+ || currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadCacheWatchpoint, ExitFromFTL))
+ || currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadExecutable, ExitFromFTL));
+ badFunction =
+ currentBaseline->hasExitSite(locker, DFG::FrequentExitSite(codeOrigin.bytecodeIndex, BadFunction, ExitFromFTL));
+ }
+
+ {
+ ConcurrentJITLocker locker(dfgCodeBlock->m_lock);
+ if (takeSlowPath || jitCode->slowPathCalls[i] >= Options::couldTakeSlowCaseMinimumCount())
+ map.add(info.codeOrigin, takesSlowPath());
+ else {
+ CallLinkStatus status = computeFor(locker, info);
+ if (status.isSet()) {
+ if (badFunction)
+ status.makeClosureCall();
+ map.add(info.codeOrigin, status);
+ }
+ }
+ }
+ }
+#endif // ENABLE(DFG_JIT)
+
+ if (verbose) {
+ dataLog("Context map:\n");
+ ContextMap::iterator iter = map.begin();
+ ContextMap::iterator end = map.end();
+ for (; iter != end; ++iter) {
+ dataLog(" ", iter->key, ":\n");
+ dataLog(" ", iter->value, "\n");
+ }
+ }
+}
+
+CallLinkStatus CallLinkStatus::computeFor(
+ CodeBlock* profiledBlock, CodeOrigin codeOrigin, const CallLinkStatus::ContextMap& map)
+{
+ ContextMap::const_iterator iter = map.find(codeOrigin);
+ if (iter != map.end())
+ return iter->value;
+
+ return computeFor(profiledBlock, codeOrigin.bytecodeIndex);
+}
+
</ins><span class="cx"> void CallLinkStatus::dump(PrintStream& out) const
</span><span class="cx"> {
</span><span class="cx"> if (!isSet()) {
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeCallLinkStatush"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/CallLinkStatus.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -26,6 +26,7 @@
</span><span class="cx"> #ifndef CallLinkStatus_h
</span><span class="cx"> #define CallLinkStatus_h
</span><span class="cx">
</span><ins>+#include "CodeOrigin.h"
</ins><span class="cx"> #include "CodeSpecializationKind.h"
</span><span class="cx"> #include "ConcurrentJITLock.h"
</span><span class="cx"> #include "Intrinsic.h"
</span><span class="lines">@@ -38,6 +39,7 @@
</span><span class="cx"> class InternalFunction;
</span><span class="cx"> class JSFunction;
</span><span class="cx"> class Structure;
</span><ins>+struct CallLinkInfo;
</ins><span class="cx">
</span><span class="cx"> class CallLinkStatus {
</span><span class="cx"> public:
</span><span class="lines">@@ -75,6 +77,20 @@
</span><span class="cx">
</span><span class="cx"> static CallLinkStatus computeFor(CodeBlock*, unsigned bytecodeIndex);
</span><span class="cx">
</span><ins>+ // Computes the status assuming that we never took slow path and never previously
+ // exited.
+ static CallLinkStatus computeFor(const ConcurrentJITLocker&, CallLinkInfo&);
+
+ typedef HashMap<CodeOrigin, CallLinkStatus, CodeOriginApproximateHash> ContextMap;
+
+ // Computes all of the statuses of the DFG code block. Doesn't include statuses that had
+ // no information. Currently we use this when compiling FTL code, to enable polyvariant
+ // inlining.
+ static void computeDFGStatuses(CodeBlock* dfgCodeBlock, ContextMap&);
+
+ // Helper that first consults the ContextMap and then does computeFor().
+ static CallLinkStatus computeFor(CodeBlock*, CodeOrigin, const ContextMap&);
+
</ins><span class="cx"> bool isSet() const { return m_callTarget || m_executable || m_couldTakeSlowPath; }
</span><span class="cx">
</span><span class="cx"> bool operator!() const { return !isSet(); }
</span><span class="lines">@@ -94,6 +110,13 @@
</span><span class="cx"> void dump(PrintStream&) const;
</span><span class="cx">
</span><span class="cx"> private:
</span><ins>+ void makeClosureCall()
+ {
+ ASSERT(!m_isProved);
+ // Turn this into a closure call.
+ m_callTarget = JSValue();
+ }
+
</ins><span class="cx"> static CallLinkStatus computeFromLLInt(const ConcurrentJITLocker&, CodeBlock*, unsigned bytecodeIndex);
</span><span class="cx">
</span><span class="cx"> JSValue m_callTarget;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/CodeBlock.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -489,8 +489,8 @@
</span><span class="cx"> RareCaseProfile* specialFastCaseProfileForBytecodeOffset(int bytecodeOffset)
</span><span class="cx"> {
</span><span class="cx"> return tryBinarySearch<RareCaseProfile, int>(
</span><del>- m_specialFastCaseProfiles, m_specialFastCaseProfiles.size(), bytecodeOffset,
- getRareCaseProfileBytecodeOffset);
</del><ins>+ m_specialFastCaseProfiles, m_specialFastCaseProfiles.size(), bytecodeOffset,
+ getRareCaseProfileBytecodeOffset);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> bool likelyToTakeSpecialFastCase(int bytecodeOffset)
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeCodeOrigincpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -45,7 +45,64 @@
</span><span class="cx"> {
</span><span class="cx"> return inlineDepthForCallFrame(inlineCallFrame);
</span><span class="cx"> }
</span><ins>+
+bool CodeOrigin::isApproximatelyEqualTo(const CodeOrigin& other) const
+{
+ CodeOrigin a = *this;
+ CodeOrigin b = other;
+
+ if (!a.isSet())
+ return !b.isSet();
+ if (!b.isSet())
+ return false;
</ins><span class="cx">
</span><ins>+ if (a.isHashTableDeletedValue())
+ return b.isHashTableDeletedValue();
+ if (b.isHashTableDeletedValue())
+ return false;
+
+ for (;;) {
+ ASSERT(a.isSet());
+ ASSERT(b.isSet());
+
+ if (a.bytecodeIndex != b.bytecodeIndex)
+ return false;
+
+ if ((!!a.inlineCallFrame) != (!!b.inlineCallFrame))
+ return false;
+
+ if (!a.inlineCallFrame)
+ return true;
+
+ if (a.inlineCallFrame->executable != b.inlineCallFrame->executable)
+ return false;
+
+ a = a.inlineCallFrame->caller;
+ b = b.inlineCallFrame->caller;
+ }
+}
+
+unsigned CodeOrigin::approximateHash() const
+{
+ if (!isSet())
+ return 0;
+ if (isHashTableDeletedValue())
+ return 1;
+
+ unsigned result = 2;
+ CodeOrigin codeOrigin = *this;
+ for (;;) {
+ result += codeOrigin.bytecodeIndex;
+
+ if (!codeOrigin.inlineCallFrame)
+ return result;
+
+ result += WTF::PtrHash<JSCell*>::hash(codeOrigin.inlineCallFrame->executable.get());
+
+ codeOrigin = codeOrigin.inlineCallFrame->caller;
+ }
+}
+
</ins><span class="cx"> Vector<CodeOrigin> CodeOrigin::inlineStack() const
</span><span class="cx"> {
</span><span class="cx"> Vector<CodeOrigin> result(inlineDepth());
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeCodeOriginh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/CodeOrigin.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -63,7 +63,7 @@
</span><span class="cx">
</span><span class="cx"> CodeOrigin(WTF::HashTableDeletedValueType)
</span><span class="cx"> : bytecodeIndex(invalidBytecodeIndex)
</span><del>- , inlineCallFrame(bitwise_cast<InlineCallFrame*>(static_cast<uintptr_t>(1)))
</del><ins>+ , inlineCallFrame(deletedMarker())
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -97,11 +97,23 @@
</span><span class="cx"> bool operator==(const CodeOrigin& other) const;
</span><span class="cx"> bool operator!=(const CodeOrigin& other) const { return !(*this == other); }
</span><span class="cx">
</span><ins>+ // This checks if the two code origins correspond to the same stack trace snippets,
+ // but ignore whether the InlineCallFrame's are identical.
+ bool isApproximatelyEqualTo(const CodeOrigin& other) const;
+
+ unsigned approximateHash() const;
+
</ins><span class="cx"> // Get the inline stack. This is slow, and is intended for debugging only.
</span><span class="cx"> Vector<CodeOrigin> inlineStack() const;
</span><span class="cx">
</span><span class="cx"> void dump(PrintStream&) const;
</span><span class="cx"> void dumpInContext(PrintStream&, DumpContext*) const;
</span><ins>+
+private:
+ static InlineCallFrame* deletedMarker()
+ {
+ return bitwise_cast<InlineCallFrame*>(static_cast<uintptr_t>(1));
+ }
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> struct InlineCallFrame {
</span><span class="lines">@@ -185,6 +197,12 @@
</span><span class="cx"> static const bool safeToCompareToEmptyOrDeleted = true;
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+struct CodeOriginApproximateHash {
+ static unsigned hash(const CodeOrigin& key) { return key.approximateHash(); }
+ static bool equal(const CodeOrigin& a, const CodeOrigin& b) { return a.isApproximatelyEqualTo(b); }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx">
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeDFGExitProfilecpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -37,6 +37,8 @@
</span><span class="cx">
</span><span class="cx"> bool ExitProfile::add(const ConcurrentJITLocker&, const FrequentExitSite& site)
</span><span class="cx"> {
</span><ins>+ ASSERT(site.jitType() != ExitFromAnything);
+
</ins><span class="cx"> // If we've never seen any frequent exits then create the list and put this site
</span><span class="cx"> // into it.
</span><span class="cx"> if (!m_frequentExitSites) {
</span><span class="lines">@@ -78,7 +80,7 @@
</span><span class="cx"> return false;
</span><span class="cx">
</span><span class="cx"> for (unsigned i = m_frequentExitSites->size(); i--;) {
</span><del>- if (m_frequentExitSites->at(i) == site)
</del><ins>+ if (site.subsumes(m_frequentExitSites->at(i)))
</ins><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx"> return false;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeDFGExitProfileh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/DFGExitProfile.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx">
</span><span class="cx"> #include "ConcurrentJITLock.h"
</span><span class="cx"> #include "ExitKind.h"
</span><ins>+#include "ExitingJITType.h"
</ins><span class="cx"> #include <wtf/HashSet.h>
</span><span class="cx"> #include <wtf/OwnPtr.h>
</span><span class="cx"> #include <wtf/Vector.h>
</span><span class="lines">@@ -39,18 +40,22 @@
</span><span class="cx"> FrequentExitSite()
</span><span class="cx"> : m_bytecodeOffset(0) // 0 = empty value
</span><span class="cx"> , m_kind(ExitKindUnset)
</span><ins>+ , m_jitType(ExitFromAnything)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> FrequentExitSite(WTF::HashTableDeletedValueType)
</span><span class="cx"> : m_bytecodeOffset(1) // 1 = deleted value
</span><span class="cx"> , m_kind(ExitKindUnset)
</span><ins>+ , m_jitType(ExitFromAnything)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><del>- explicit FrequentExitSite(unsigned bytecodeOffset, ExitKind kind)
</del><ins>+ explicit FrequentExitSite(
+ unsigned bytecodeOffset, ExitKind kind, ExitingJITType jitType = ExitFromAnything)
</ins><span class="cx"> : m_bytecodeOffset(bytecodeOffset)
</span><span class="cx"> , m_kind(kind)
</span><ins>+ , m_jitType(jitType)
</ins><span class="cx"> {
</span><span class="cx"> if (m_kind == ArgumentsEscaped) {
</span><span class="cx"> // Count this one globally. It doesn't matter where in the code block the arguments excaped;
</span><span class="lines">@@ -61,9 +66,10 @@
</span><span class="cx">
</span><span class="cx"> // Use this constructor if you wish for the exit site to be counted globally within its
</span><span class="cx"> // code block.
</span><del>- explicit FrequentExitSite(ExitKind kind)
</del><ins>+ explicit FrequentExitSite(ExitKind kind, ExitingJITType jitType = ExitFromAnything)
</ins><span class="cx"> : m_bytecodeOffset(0)
</span><span class="cx"> , m_kind(kind)
</span><ins>+ , m_jitType(jitType)
</ins><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -75,16 +81,36 @@
</span><span class="cx"> bool operator==(const FrequentExitSite& other) const
</span><span class="cx"> {
</span><span class="cx"> return m_bytecodeOffset == other.m_bytecodeOffset
</span><del>- && m_kind == other.m_kind;
</del><ins>+ && m_kind == other.m_kind
+ && m_jitType == other.m_jitType;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+ bool subsumes(const FrequentExitSite& other) const
+ {
+ if (m_bytecodeOffset != other.m_bytecodeOffset)
+ return false;
+ if (m_kind != other.m_kind)
+ return false;
+ if (m_jitType == ExitFromAnything)
+ return true;
+ return m_jitType == other.m_jitType;
+ }
+
</ins><span class="cx"> unsigned hash() const
</span><span class="cx"> {
</span><del>- return WTF::intHash(m_bytecodeOffset) + m_kind;
</del><ins>+ return WTF::intHash(m_bytecodeOffset) + m_kind + m_jitType * 7;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> unsigned bytecodeOffset() const { return m_bytecodeOffset; }
</span><span class="cx"> ExitKind kind() const { return m_kind; }
</span><ins>+ ExitingJITType jitType() const { return m_jitType; }
+
+ FrequentExitSite withJITType(ExitingJITType jitType) const
+ {
+ FrequentExitSite result = *this;
+ result.m_jitType = jitType;
+ return result;
+ }
</ins><span class="cx">
</span><span class="cx"> bool isHashTableDeletedValue() const
</span><span class="cx"> {
</span><span class="lines">@@ -94,6 +120,7 @@
</span><span class="cx"> private:
</span><span class="cx"> unsigned m_bytecodeOffset;
</span><span class="cx"> ExitKind m_kind;
</span><ins>+ ExitingJITType m_jitType;
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> struct FrequentExitSiteHash {
</span><span class="lines">@@ -166,6 +193,10 @@
</span><span class="cx">
</span><span class="cx"> bool hasExitSite(const FrequentExitSite& site) const
</span><span class="cx"> {
</span><ins>+ if (site.jitType() == ExitFromAnything) {
+ return hasExitSite(site.withJITType(ExitFromDFG))
+ || hasExitSite(site.withJITType(ExitFromFTL));
+ }
</ins><span class="cx"> return m_frequentExitSites.find(site) != m_frequentExitSites.end();
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeExitKindh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/ExitKind.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/ExitKind.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/ExitKind.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC {
</span><span class="cx">
</span><del>-enum ExitKind {
</del><ins>+enum ExitKind : uint8_t {
</ins><span class="cx"> ExitKindUnset,
</span><span class="cx"> BadType, // We exited because a type prediction was wrong.
</span><span class="cx"> BadFunction, // We exited because we made an incorrect assumption about what function we would see.
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeExitingJITTypeh"></a>
<div class="addfile"><h4>Added: branches/jsCStack/Source/JavaScriptCore/bytecode/ExitingJITType.h (0 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/ExitingJITType.h         (rev 0)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/ExitingJITType.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ExitingJITType_h
+#define ExitingJITType_h
+
+#include "JITCode.h"
+
+namespace JSC {
+
+enum ExitingJITType : uint8_t {
+ ExitFromAnything,
+ ExitFromDFG,
+ ExitFromFTL
+};
+
+inline ExitingJITType exitingJITTypeFor(JITCode::JITType type)
+{
+ switch (type) {
+ case JITCode::DFGJIT:
+ return ExitFromDFG;
+ case JITCode::FTLJIT:
+ return ExitFromFTL;
+ default:
+ RELEASE_ASSERT_NOT_REACHED();
+ return ExitFromAnything;
+ }
+}
+
+} // namespace JSC
+
+#endif // ExitingJITType_h
+
</ins></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorebytecodeProfiledCodeBlockJettisoningWatchpointcpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/bytecode/ProfiledCodeBlockJettisoningWatchpoint.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -49,7 +49,9 @@
</span><span class="cx">
</span><span class="cx"> if (sourceBaselineCodeBlock) {
</span><span class="cx"> sourceBaselineCodeBlock->addFrequentExitSite(
</span><del>- DFG::FrequentExitSite(m_codeOrigin.bytecodeIndex, m_exitKind));
</del><ins>+ DFG::FrequentExitSite(
+ m_codeOrigin.bytecodeIndex, m_exitKind,
+ exitingJITTypeFor(m_codeBlock->jitType())));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> m_codeBlock->jettison(CountReoptimization);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1136,6 +1136,8 @@
</span><span class="cx"> // work-around for the fact that JSValueMap can't handle "empty" values.
</span><span class="cx"> unsigned m_emptyJSValueIndex;
</span><span class="cx">
</span><ins>+ CallLinkStatus::ContextMap m_callContextMap;
+
</ins><span class="cx"> Instruction* m_currentInstruction;
</span><span class="cx"> };
</span><span class="cx">
</span><span class="lines">@@ -1165,10 +1167,13 @@
</span><span class="cx">
</span><span class="cx"> CallLinkStatus callLinkStatus;
</span><span class="cx">
</span><del>- if (m_graph.isConstant(callTarget))
- callLinkStatus = CallLinkStatus(m_graph.valueOfJSConstant(callTarget)).setIsProved(true);
- else
- callLinkStatus = CallLinkStatus::computeFor(m_inlineStackTop->m_profiledBlock, m_currentIndex);
</del><ins>+ if (m_graph.isConstant(callTarget)) {
+ callLinkStatus = CallLinkStatus(
+ m_graph.valueOfJSConstant(callTarget)).setIsProved(true);
+ } else {
+ callLinkStatus = CallLinkStatus::computeFor(
+ m_inlineStackTop->m_profiledBlock, currentCodeOrigin(), m_callContextMap);
+ }
</ins><span class="cx">
</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="lines">@@ -1251,30 +1256,32 @@
</span><span class="cx">
</span><span class="cx"> bool ByteCodeParser::handleInlining(Node* callTargetNode, int resultOperand, const CallLinkStatus& callLinkStatus, int registerOffset, int argumentCountIncludingThis, unsigned nextOffset, CodeSpecializationKind kind)
</span><span class="cx"> {
</span><ins>+ static const bool verbose = false;
+
+ if (verbose)
+ dataLog("Considering inlining ", callLinkStatus, " into ", currentCodeOrigin(), "\n");
+
</ins><span class="cx"> // First, the really simple checks: do we have an actual JS function?
</span><del>- if (!callLinkStatus.executable())
</del><ins>+ if (!callLinkStatus.executable()) {
+ if (verbose)
+ dataLog(" Failing because there is no executable.\n");
</ins><span class="cx"> return false;
</span><del>- if (callLinkStatus.executable()->isHostFunction())
</del><ins>+ }
+ if (callLinkStatus.executable()->isHostFunction()) {
+ if (verbose)
+ dataLog(" Failing because it's a host function.\n");
</ins><span class="cx"> return false;
</span><ins>+ }
</ins><span class="cx">
</span><span class="cx"> FunctionExecutable* executable = jsCast<FunctionExecutable*>(callLinkStatus.executable());
</span><span class="cx">
</span><span class="cx"> // Does the number of arguments we're passing match the arity of the target? We currently
</span><span class="cx"> // inline only if the number of arguments passed is greater than or equal to the number
</span><span class="cx"> // arguments expected.
</span><del>- if (static_cast<int>(executable->parameterCount()) + 1 > argumentCountIncludingThis)
</del><ins>+ if (static_cast<int>(executable->parameterCount()) + 1 > argumentCountIncludingThis) {
+ if (verbose)
+ dataLog(" Failing because of arity mismatch.\n");
</ins><span class="cx"> return false;
</span><del>-
- // Have we exceeded inline stack depth, or are we trying to inline a recursive call?
- // If either of these are detected, then don't inline.
- unsigned depth = 0;
- for (InlineStackEntry* entry = m_inlineStackTop; entry; entry = entry->m_caller) {
- ++depth;
- if (depth >= Options::maximumInliningDepth())
- return false; // Depth exceeded.
-
- if (entry->executable() == executable)
- return false; // Recursion detected.
</del><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> // Do we have a code block, and does the code block's size match the heuristics/requirements for
</span><span class="lines">@@ -1284,11 +1291,61 @@
</span><span class="cx"> // global function, where watchpointing gives us static information. Overall, it's a rare case
</span><span class="cx"> // because we expect that any hot callees would have already been compiled.
</span><span class="cx"> CodeBlock* codeBlock = executable->baselineCodeBlockFor(kind);
</span><del>- if (!codeBlock)
</del><ins>+ if (!codeBlock) {
+ if (verbose)
+ dataLog(" Failing because no code block available.\n");
</ins><span class="cx"> return false;
</span><del>- if (!canInlineFunctionFor(codeBlock, kind, callLinkStatus.isClosureCall()))
</del><ins>+ }
+ CapabilityLevel capabilityLevel = inlineFunctionForCapabilityLevel(
+ codeBlock, kind, callLinkStatus.isClosureCall());
+ if (!canInline(capabilityLevel)) {
+ if (verbose)
+ dataLog(" Failing because the function is not inlineable.\n");
</ins><span class="cx"> return false;
</span><ins>+ }
</ins><span class="cx">
</span><ins>+ // FIXME: this should be better at predicting how much bloat we will introduce by inlining
+ // this function.
+ // https://bugs.webkit.org/show_bug.cgi?id=127627
+
+ // Have we exceeded inline stack depth, or are we trying to inline a recursive call to
+ // too many levels? If either of these are detected, then don't inline. We adjust our
+ // heuristics if we are dealing with a function that cannot otherwise be compiled.
+
+ unsigned depthLimit;
+ unsigned recursionLimit;
+ if (canCompile(capabilityLevel)) {
+ depthLimit = Options::maximumInliningDepth();
+ recursionLimit = Options::maximumInliningRecursion();
+ } else {
+ depthLimit = Options::maximumInliningDepthForMustInline();
+ recursionLimit = Options::maximumInliningRecursionForMustInline();
+ }
+
+ unsigned depth = 0;
+ unsigned recursion = 0;
+
+ for (InlineStackEntry* entry = m_inlineStackTop; entry; entry = entry->m_caller) {
+ ++depth;
+ if (depth >= Options::maximumInliningDepth()) {
+ if (verbose)
+ dataLog(" Failing because depth exceeded.\n");
+ return false;
+ }
+
+ if (entry->executable() == executable) {
+ ++recursion;
+ if (recursion >= Options::maximumInliningRecursion()) {
+ if (verbose)
+ dataLog(" Failing because recursion detected.\n");
+ return false;
+ }
+ }
+ }
+
+ if (verbose)
+ dataLog(" Committing to inlining.\n");
+
</ins><span class="cx"> // Now we know without a doubt that we are committed to inlining. So begin the process
</span><span class="cx"> // by checking the callee (if necessary) and making sure that arguments and the callee
</span><span class="cx"> // are flushed.
</span><span class="lines">@@ -3660,6 +3717,13 @@
</span><span class="cx"> // Set during construction.
</span><span class="cx"> ASSERT(!m_currentIndex);
</span><span class="cx">
</span><ins>+ if (isFTL(m_graph.m_plan.mode)
+ && !!m_graph.m_plan.profiledDFGCodeBlock
+ && Options::enablePolyvariantCallInlining()) {
+ CallLinkStatus::computeDFGStatuses(
+ m_graph.m_plan.profiledDFGCodeBlock.get(), m_callContextMap);
+ }
+
</ins><span class="cx"> if (m_codeBlock->captureCount()) {
</span><span class="cx"> SymbolTable* symbolTable = m_codeBlock->symbolTable();
</span><span class="cx"> ConcurrentJITLocker locker(symbolTable->m_lock);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -198,6 +198,8 @@
</span><span class="cx"> case op_call_varargs:
</span><span class="cx"> if (codeBlock->usesArguments() && pc[4].u.operand == codeBlock->argumentsRegister().offset())
</span><span class="cx"> return CanInline;
</span><ins>+ // FIXME: We should handle this.
+ // https://bugs.webkit.org/show_bug.cgi?id=127626
</ins><span class="cx"> return CannotCompile;
</span><span class="cx">
</span><span class="cx"> case op_new_regexp:
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGCapabilitiesh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGCapabilities.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -96,19 +96,28 @@
</span><span class="cx"> return capabilityLevel(codeBlock);
</span><span class="cx"> }
</span><span class="cx">
</span><del>-inline bool canInlineFunctionForCall(CodeBlock* codeBlock)
</del><ins>+inline CapabilityLevel inlineFunctionForCallCapabilityLevel(CodeBlock* codeBlock)
</ins><span class="cx"> {
</span><del>- return mightInlineFunctionForCall(codeBlock) && canInline(capabilityLevel(codeBlock));
</del><ins>+ if (!mightInlineFunctionForCall(codeBlock))
+ return CannotCompile;
+
+ return capabilityLevel(codeBlock);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-inline bool canInlineFunctionForClosureCall(CodeBlock* codeBlock)
</del><ins>+inline CapabilityLevel inlineFunctionForClosureCallCapabilityLevel(CodeBlock* codeBlock)
</ins><span class="cx"> {
</span><del>- return mightInlineFunctionForClosureCall(codeBlock) && canInline(capabilityLevel(codeBlock));
</del><ins>+ if (!mightInlineFunctionForClosureCall(codeBlock))
+ return CannotCompile;
+
+ return capabilityLevel(codeBlock);
</ins><span class="cx"> }
</span><span class="cx">
</span><del>-inline bool canInlineFunctionForConstruct(CodeBlock* codeBlock)
</del><ins>+inline CapabilityLevel inlineFunctionForConstructCapabilityLevel(CodeBlock* codeBlock)
</ins><span class="cx"> {
</span><del>- return mightInlineFunctionForConstruct(codeBlock) && canInline(capabilityLevel(codeBlock));
</del><ins>+ if (!mightInlineFunctionForConstruct(codeBlock))
+ return CannotCompile;
+
+ return capabilityLevel(codeBlock);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> inline bool mightInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind kind)
</span><span class="lines">@@ -124,16 +133,16 @@
</span><span class="cx"> return mightInlineFunctionFor(codeBlock, codeBlock->specializationKind());
</span><span class="cx"> }
</span><span class="cx">
</span><del>-inline bool canInlineFunctionFor(CodeBlock* codeBlock, CodeSpecializationKind kind, bool isClosureCall)
</del><ins>+inline CapabilityLevel inlineFunctionForCapabilityLevel(CodeBlock* codeBlock, CodeSpecializationKind kind, bool isClosureCall)
</ins><span class="cx"> {
</span><span class="cx"> if (isClosureCall) {
</span><span class="cx"> ASSERT(kind == CodeForCall);
</span><del>- return canInlineFunctionForClosureCall(codeBlock);
</del><ins>+ return inlineFunctionForClosureCallCapabilityLevel(codeBlock);
</ins><span class="cx"> }
</span><span class="cx"> if (kind == CodeForCall)
</span><del>- return canInlineFunctionForCall(codeBlock);
</del><ins>+ return inlineFunctionForCallCapabilityLevel(codeBlock);
</ins><span class="cx"> ASSERT(kind == CodeForConstruct);
</span><del>- return canInlineFunctionForConstruct(codeBlock);
</del><ins>+ return inlineFunctionForConstructCapabilityLevel(codeBlock);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGCommonh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGCommon.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGCommon.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGCommon.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -226,7 +226,13 @@
</span><span class="cx">
</span><span class="cx"> // Put things here that must be defined even if ENABLE(DFG_JIT) is false.
</span><span class="cx">
</span><del>-enum CapabilityLevel { CannotCompile, CanInline, CanCompile, CanCompileAndInline, CapabilityLevelNotSet };
</del><ins>+enum CapabilityLevel {
+ CannotCompile,
+ CanInline,
+ CanCompile,
+ CanCompileAndInline,
+ CapabilityLevelNotSet
+};
</ins><span class="cx">
</span><span class="cx"> inline bool canCompile(CapabilityLevel level)
</span><span class="cx"> {
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGDrivercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -55,8 +55,8 @@
</span><span class="cx">
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx"> static CompilationResult compileImpl(
</span><del>- VM& vm, CodeBlock* codeBlock, CompilationMode mode, unsigned osrEntryBytecodeIndex,
- const Operands<JSValue>& mustHandleValues,
</del><ins>+ VM& vm, CodeBlock* codeBlock, CodeBlock* profiledDFGCodeBlock, CompilationMode mode,
+ unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues,
</ins><span class="cx"> PassRefPtr<DeferredCompilationCallback> callback)
</span><span class="cx"> {
</span><span class="cx"> SamplingRegion samplingRegion("DFG Compilation (Driver)");
</span><span class="lines">@@ -66,6 +66,7 @@
</span><span class="cx"> ASSERT(codeBlock);
</span><span class="cx"> ASSERT(codeBlock->alternative());
</span><span class="cx"> ASSERT(codeBlock->alternative()->jitType() == JITCode::BaselineJIT);
</span><ins>+ ASSERT(!profiledDFGCodeBlock || profiledDFGCodeBlock->jitType() == JITCode::DFGJIT);
</ins><span class="cx">
</span><span class="cx"> if (!Options::useDFGJIT() || !MacroAssembler::supportsFloatingPoint())
</span><span class="cx"> return CompilationFailed;
</span><span class="lines">@@ -95,7 +96,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> RefPtr<Plan> plan = adoptRef(
</span><del>- new Plan(codeBlock, mode, osrEntryBytecodeIndex, mustHandleValues));
</del><ins>+ new Plan(codeBlock, profiledDFGCodeBlock, mode, osrEntryBytecodeIndex, mustHandleValues));
</ins><span class="cx">
</span><span class="cx"> bool enableConcurrentJIT;
</span><span class="cx"> #if ENABLE(CONCURRENT_JIT)
</span><span class="lines">@@ -117,7 +118,7 @@
</span><span class="cx"> }
</span><span class="cx"> #else // ENABLE(DFG_JIT)
</span><span class="cx"> static CompilationResult compileImpl(
</span><del>- VM&, CodeBlock*, CompilationMode, unsigned, const Operands<JSValue>&,
</del><ins>+ VM&, CodeBlock*, CodeBlock*, CompilationMode, unsigned, const Operands<JSValue>&,
</ins><span class="cx"> PassRefPtr<DeferredCompilationCallback>)
</span><span class="cx"> {
</span><span class="cx"> return CompilationFailed;
</span><span class="lines">@@ -125,13 +126,14 @@
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx">
</span><span class="cx"> CompilationResult compile(
</span><del>- VM& vm, CodeBlock* codeBlock, CompilationMode mode, unsigned osrEntryBytecodeIndex,
- const Operands<JSValue>& mustHandleValues,
</del><ins>+ VM& vm, CodeBlock* codeBlock, CodeBlock* profiledDFGCodeBlock, CompilationMode mode,
+ unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues,
</ins><span class="cx"> PassRefPtr<DeferredCompilationCallback> passedCallback)
</span><span class="cx"> {
</span><span class="cx"> RefPtr<DeferredCompilationCallback> callback = passedCallback;
</span><span class="cx"> CompilationResult result = compileImpl(
</span><del>- vm, codeBlock, mode, osrEntryBytecodeIndex, mustHandleValues, callback);
</del><ins>+ vm, codeBlock, profiledDFGCodeBlock, mode, osrEntryBytecodeIndex, mustHandleValues,
+ callback);
</ins><span class="cx"> if (result != CompilationDeferred)
</span><span class="cx"> callback->compilationDidComplete(codeBlock, result);
</span><span class="cx"> return result;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGDriverh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGDriver.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -45,8 +45,9 @@
</span><span class="cx"> // If the worklist is non-null, we do a concurrent compile. Otherwise we do a synchronous
</span><span class="cx"> // compile. Even if we do a synchronous compile, we call the callback with the result.
</span><span class="cx"> CompilationResult compile(
</span><del>- VM&, CodeBlock*, CompilationMode, unsigned osrEntryBytecodeIndex,
- const Operands<JSValue>& mustHandleValues, PassRefPtr<DeferredCompilationCallback>);
</del><ins>+ VM&, CodeBlock*, CodeBlock* profiledDFGCodeBlock, CompilationMode,
+ unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues,
+ PassRefPtr<DeferredCompilationCallback>);
</ins><span class="cx">
</span><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGFailedFinalizercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -39,6 +39,11 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+size_t FailedFinalizer::codeSize()
+{
+ return 0;
+}
+
</ins><span class="cx"> bool FailedFinalizer::finalize()
</span><span class="cx"> {
</span><span class="cx"> return false;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGFailedFinalizerh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGFailedFinalizer.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> FailedFinalizer(Plan&);
</span><span class="cx"> virtual ~FailedFinalizer();
</span><span class="cx">
</span><ins>+ virtual size_t codeSize() override;
</ins><span class="cx"> virtual bool finalize() override;
</span><span class="cx"> virtual bool finalizeFunction() override;
</span><span class="cx"> };
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGFinalizerh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGFinalizer.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGFinalizer.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGFinalizer.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -46,6 +46,7 @@
</span><span class="cx"> Finalizer(Plan&);
</span><span class="cx"> virtual ~Finalizer();
</span><span class="cx">
</span><ins>+ virtual size_t codeSize() = 0;
</ins><span class="cx"> virtual bool finalize() = 0;
</span><span class="cx"> virtual bool finalizeFunction() = 0;
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGJITCodeh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCode.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCode.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCode.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -119,6 +119,7 @@
</span><span class="cx"> Vector<DFG::OSREntryData> osrEntry;
</span><span class="cx"> SegmentedVector<DFG::OSRExit, 8> osrExit;
</span><span class="cx"> Vector<DFG::SpeculationRecovery> speculationRecovery;
</span><ins>+ Vector<unsigned> slowPathCalls;
</ins><span class="cx"> DFG::VariableEventStream variableEventStream;
</span><span class="cx"> DFG::MinifiedGraph minifiedDFG;
</span><span class="cx"> #if ENABLE(FTL_JIT)
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGJITCompilercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -232,6 +232,7 @@
</span><span class="cx"> info.patch.deltaCallToSlowCase = differenceBetweenCodePtr(callReturnLocation, linkBuffer.locationOf(m_ins[i].m_slowPathGenerator->label()));
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ RELEASE_ASSERT(!m_graph.m_plan.willTryToTierUp || m_jitCode->slowPathCalls.size() >= m_jsCalls.size());
</ins><span class="cx"> m_codeBlock->setNumberOfCallLinkInfos(m_jsCalls.size());
</span><span class="cx"> for (unsigned i = 0; i < m_jsCalls.size(); ++i) {
</span><span class="cx"> CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGJITCompilerh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITCompiler.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -221,6 +221,11 @@
</span><span class="cx"> {
</span><span class="cx"> m_ins.append(record);
</span><span class="cx"> }
</span><ins>+
+ unsigned currentJSCallIndex() const
+ {
+ return m_jsCalls.size();
+ }
</ins><span class="cx">
</span><span class="cx"> void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
</span><span class="cx"> {
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGJITFinalizercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -46,6 +46,11 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+size_t JITFinalizer::codeSize()
+{
+ return m_linkBuffer->size();
+}
+
</ins><span class="cx"> bool JITFinalizer::finalize()
</span><span class="cx"> {
</span><span class="cx"> m_jitCode->initializeCodeRef(
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGJITFinalizerh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGJITFinalizer.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -42,6 +42,7 @@
</span><span class="cx"> JITFinalizer(Plan&, PassRefPtr<JITCode>, PassOwnPtr<LinkBuffer>, MacroAssemblerCodePtr withArityCheck = MacroAssemblerCodePtr(MacroAssemblerCodePtr::EmptyValue));
</span><span class="cx"> virtual ~JITFinalizer();
</span><span class="cx">
</span><ins>+ virtual size_t codeSize() override;
</ins><span class="cx"> virtual bool finalize() override;
</span><span class="cx"> virtual bool finalizeFunction() override;
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGOSRExith"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExit.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExit.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExit.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -105,6 +105,11 @@
</span><span class="cx"> unsigned m_streamIndex;
</span><span class="cx">
</span><span class="cx"> RefPtr<ValueRecoveryOverride> m_valueRecoveryOverride;
</span><ins>+
+ bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
+ {
+ return OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromDFG);
+ }
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> struct SpeculationFailureDebugInfo {
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGOSRExitBasecpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx">
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx">
</span><del>-bool OSRExitBase::considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock)
</del><ins>+bool OSRExitBase::considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock, ExitingJITType jitType)
</ins><span class="cx"> {
</span><span class="cx"> CodeBlock* sourceProfiledCodeBlock =
</span><span class="cx"> baselineCodeBlockForOriginAndBaselineCodeBlock(
</span><span class="lines">@@ -43,7 +43,7 @@
</span><span class="cx"> if (!sourceProfiledCodeBlock)
</span><span class="cx"> return false;
</span><span class="cx"> return sourceProfiledCodeBlock->addFrequentExitSite(
</span><del>- FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind));
</del><ins>+ FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind, jitType));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGOSRExitBaseh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGOSRExitBase.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -58,15 +58,16 @@
</span><span class="cx"> CodeOrigin m_codeOrigin;
</span><span class="cx"> CodeOrigin m_codeOriginForExitProfile;
</span><span class="cx">
</span><del>- bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
</del><ins>+protected:
+ bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock, ExitingJITType jitType)
</ins><span class="cx"> {
</span><span class="cx"> if (!m_count)
</span><span class="cx"> return false;
</span><del>- return considerAddingAsFrequentExitSiteSlow(profiledCodeBlock);
</del><ins>+ return considerAddingAsFrequentExitSiteSlow(profiledCodeBlock, jitType);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> private:
</span><del>- bool considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock);
</del><ins>+ bool considerAddingAsFrequentExitSiteSlow(CodeBlock* profiledCodeBlock, ExitingJITType jitType);
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::DFG
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGOperationscpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGOperations.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGOperations.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGOperations.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1169,8 +1169,8 @@
</span><span class="cx">
</span><span class="cx"> // We need to compile the code.
</span><span class="cx"> compile(
</span><del>- *vm, codeBlock->newReplacement().get(), FTLMode, UINT_MAX, Operands<JSValue>(),
- ToFTLDeferredCompilationCallback::create(codeBlock));
</del><ins>+ *vm, codeBlock->newReplacement().get(), codeBlock, FTLMode, UINT_MAX,
+ Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> char* JIT_OPERATION triggerOSREntryNow(
</span><span class="lines">@@ -1255,7 +1255,7 @@
</span><span class="cx"> jitCode->reconstruct(
</span><span class="cx"> exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues);
</span><span class="cx"> CompilationResult forEntryResult = compile(
</span><del>- *vm, codeBlock->newReplacement().get(), FTLForOSREntryMode, bytecodeIndex,
</del><ins>+ *vm, codeBlock->newReplacement().get(), codeBlock, FTLForOSREntryMode, bytecodeIndex,
</ins><span class="cx"> mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(codeBlock));
</span><span class="cx">
</span><span class="cx"> // But we also want to trigger a replacement compile. Of course, we don't want to
</span><span class="lines">@@ -1272,8 +1272,8 @@
</span><span class="cx"> && (!worklist
</span><span class="cx"> || worklist->compilationState(keyForReplacement) == Worklist::NotKnown)) {
</span><span class="cx"> compile(
</span><del>- *vm, codeBlock->newReplacement().get(), FTLMode, UINT_MAX, Operands<JSValue>(),
- ToFTLDeferredCompilationCallback::create(codeBlock));
</del><ins>+ *vm, codeBlock->newReplacement().get(), codeBlock, FTLMode, UINT_MAX,
+ Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock));
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> if (forEntryResult != CompilationSuccessful)
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -108,10 +108,12 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> Plan::Plan(
</span><del>- PassRefPtr<CodeBlock> passedCodeBlock, CompilationMode mode,
- unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues)
</del><ins>+ PassRefPtr<CodeBlock> passedCodeBlock, CodeBlock* profiledDFGCodeBlock,
+ CompilationMode mode, unsigned osrEntryBytecodeIndex,
+ const Operands<JSValue>& mustHandleValues)
</ins><span class="cx"> : vm(*passedCodeBlock->vm())
</span><span class="cx"> , codeBlock(passedCodeBlock)
</span><ins>+ , profiledDFGCodeBlock(profiledDFGCodeBlock)
</ins><span class="cx"> , mode(mode)
</span><span class="cx"> , osrEntryBytecodeIndex(osrEntryBytecodeIndex)
</span><span class="cx"> , mustHandleValues(mustHandleValues)
</span><span class="lines">@@ -167,7 +169,7 @@
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> double now = currentTimeMS();
</span><del>- dataLog("Optimized ", *codeBlock, " using ", mode, " with ", pathName, " in ", now - before, " ms");
</del><ins>+ dataLog("Optimized ", *codeBlock, " using ", mode, " with ", pathName, " into ", finalizer->codeSize(), " bytes in ", now - before, " ms");
</ins><span class="cx"> if (path == FTLPath)
</span><span class="cx"> dataLog(" (DFG: ", beforeFTL - before, ", LLVM: ", now - beforeFTL, ")");
</span><span class="cx"> dataLog(".\n");
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGPlanh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGPlan.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx"> *
</span><span class="cx"> * Redistribution and use in source and binary forms, with or without
</span><span class="cx"> * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -55,7 +55,8 @@
</span><span class="cx">
</span><span class="cx"> struct Plan : public ThreadSafeRefCounted<Plan> {
</span><span class="cx"> Plan(
</span><del>- PassRefPtr<CodeBlock>, CompilationMode, unsigned osrEntryBytecodeIndex,
</del><ins>+ PassRefPtr<CodeBlock> codeBlockToCompile, CodeBlock* profiledDFGCodeBlock,
+ CompilationMode, unsigned osrEntryBytecodeIndex,
</ins><span class="cx"> const Operands<JSValue>& mustHandleValues);
</span><span class="cx"> ~Plan();
</span><span class="cx">
</span><span class="lines">@@ -70,6 +71,7 @@
</span><span class="cx">
</span><span class="cx"> VM& vm;
</span><span class="cx"> RefPtr<CodeBlock> codeBlock;
</span><ins>+ RefPtr<CodeBlock> profiledDFGCodeBlock;
</ins><span class="cx"> CompilationMode mode;
</span><span class="cx"> const unsigned osrEntryBytecodeIndex;
</span><span class="cx"> Operands<JSValue> mustHandleValues;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1534,10 +1534,40 @@
</span><span class="cx"> m_isCheckingArgumentTypes = false;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+void SpeculativeJIT::prepareJITCodeForTierUp()
+{
+ unsigned numberOfCalls = 0;
+
+ for (BlockIndex blockIndex = m_jit.graph().numBlocks(); blockIndex--;) {
+ BasicBlock* block = m_jit.graph().block(blockIndex);
+ if (!block)
+ continue;
+
+ for (unsigned nodeIndex = block->size(); nodeIndex--;) {
+ Node* node = block->at(nodeIndex);
+
+ switch (node->op()) {
+ case Call:
+ case Construct:
+ numberOfCalls++;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ m_jit.jitCode()->slowPathCalls.fill(0, numberOfCalls);
+}
+
</ins><span class="cx"> bool SpeculativeJIT::compile()
</span><span class="cx"> {
</span><span class="cx"> checkArgumentTypes();
</span><del>-
</del><ins>+
+ if (m_jit.graph().m_plan.willTryToTierUp)
+ prepareJITCodeForTierUp();
+
</ins><span class="cx"> ASSERT(!m_currentNode);
</span><span class="cx"> for (BlockIndex blockIndex = 0; blockIndex < m_jit.graph().numBlocks(); ++blockIndex) {
</span><span class="cx"> m_jit.setForBlockIndex(blockIndex);
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -119,6 +119,9 @@
</span><span class="cx"> ~SpeculativeJIT();
</span><span class="cx">
</span><span class="cx"> bool compile();
</span><ins>+
+ void prepareJITCodeForTierUp();
+
</ins><span class="cx"> void createOSREntries();
</span><span class="cx"> void linkOSREntries(LinkBuffer&);
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -695,6 +695,13 @@
</span><span class="cx">
</span><span class="cx"> slowPath.link(&m_jit);
</span><span class="cx">
</span><ins>+ if (m_jit.graph().m_plan.willTryToTierUp) {
+ m_jit.add32(
+ TrustedImm32(1),
+ MacroAssembler::AbsoluteAddress(
+ m_jit.jitCode()->slowPathCalls.begin() + m_jit.currentJSCallIndex()));
+ }
+
</ins><span class="cx"> m_jit.move(calleeGPR, GPRInfo::regT0); // Callee needs to be in regT0
</span><span class="cx"> JITCompiler::Call slowCall = m_jit.nearCall();
</span><span class="cx">
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreftlFTLJITFinalizercpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -45,6 +45,22 @@
</span><span class="cx"> {
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+size_t JITFinalizer::codeSize()
+{
+ size_t result = 0;
+
+ result += exitThunksLinkBuffer->size();
+ result += entrypointLinkBuffer->size();
+ if (sideCodeLinkBuffer)
+ result += sideCodeLinkBuffer->size();
+ result += handleExceptionsLinkBuffer->size();
+
+ for (unsigned i = jitCode->handles().size(); i--;)
+ result += jitCode->handles()[i]->sizeInBytes();
+
+ return result;
+}
+
</ins><span class="cx"> bool JITFinalizer::finalize()
</span><span class="cx"> {
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreftlFTLJITFinalizerh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/ftl/FTLJITFinalizer.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -46,8 +46,9 @@
</span><span class="cx"> JITFinalizer(DFG::Plan&);
</span><span class="cx"> virtual ~JITFinalizer();
</span><span class="cx">
</span><del>- bool finalize();
- bool finalizeFunction();
</del><ins>+ size_t codeSize() override;
+ bool finalize() override;
+ bool finalizeFunction() override;
</ins><span class="cx">
</span><span class="cx"> OwnPtr<LinkBuffer> exitThunksLinkBuffer;
</span><span class="cx"> OwnPtr<LinkBuffer> entrypointLinkBuffer;
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreftlFTLOSRExith"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExit.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExit.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/ftl/FTLOSRExit.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -166,6 +166,11 @@
</span><span class="cx"> uint32_t m_stackmapID;
</span><span class="cx">
</span><span class="cx"> CodeLocationJump codeLocationForRepatch(CodeBlock* ftlCodeBlock) const;
</span><ins>+
+ bool considerAddingAsFrequentExitSite(CodeBlock* profiledCodeBlock)
+ {
+ return OSRExitBase::considerAddingAsFrequentExitSite(profiledCodeBlock, ExitFromFTL);
+ }
</ins><span class="cx"> };
</span><span class="cx">
</span><span class="cx"> } } // namespace JSC::FTL
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITCodeh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JITCode.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JITCode.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JITCode.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -54,7 +54,14 @@
</span><span class="cx"> typedef MacroAssemblerCodeRef CodeRef;
</span><span class="cx"> typedef MacroAssemblerCodePtr CodePtr;
</span><span class="cx">
</span><del>- enum JITType { None, HostCallThunk, InterpreterThunk, BaselineJIT, DFGJIT, FTLJIT };
</del><ins>+ enum JITType : uint8_t {
+ None,
+ HostCallThunk,
+ InterpreterThunk,
+ BaselineJIT,
+ DFGJIT,
+ FTLJIT
+ };
</ins><span class="cx">
</span><span class="cx"> static JITType bottomTierJIT()
</span><span class="cx"> {
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCorejitJITOperationscpp"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/jit/JITOperations.cpp (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/jit/JITOperations.cpp        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/jit/JITOperations.cpp        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -1186,7 +1186,7 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> CompilationResult result = DFG::compile(
</span><del>- vm, codeBlock->newReplacement().get(), DFG::DFGMode, bytecodeIndex,
</del><ins>+ vm, codeBlock->newReplacement().get(), 0, DFG::DFGMode, bytecodeIndex,
</ins><span class="cx"> mustHandleValues, JITToDFGDeferredCompilationCallback::create());
</span><span class="cx">
</span><span class="cx"> if (result != CompilationSuccessful)
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: branches/jsCStack/Source/JavaScriptCore/runtime/Options.h (162787 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/runtime/Options.h        2014-01-26 00:36:23 UTC (rev 162787)
+++ branches/jsCStack/Source/JavaScriptCore/runtime/Options.h        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -171,7 +171,12 @@
</span><span class="cx"> \
</span><span class="cx"> /* Depth of inline stack, so 1 = no inlining, 2 = one level, etc. */ \
</span><span class="cx"> v(unsigned, maximumInliningDepth, 5) \
</span><ins>+ v(unsigned, maximumInliningRecursion, 2) \
+ v(unsigned, maximumInliningDepthForMustInline, 7) \
+ v(unsigned, maximumInliningRecursionForMustInline, 3) \
</ins><span class="cx"> \
</span><ins>+ v(bool, enablePolyvariantCallInlining, true) \
+ \
</ins><span class="cx"> v(unsigned, maximumBinaryStringSwitchCaseLength, 50) \
</span><span class="cx"> v(unsigned, maximumBinaryStringSwitchTotalLength, 2000) \
</span><span class="cx"> \
</span></span></pre></div>
<a id="branchesjsCStackSourceJavaScriptCoretestsstresssimplepolyvariantcallinliningexamplejs"></a>
<div class="addfile"><h4>Added: branches/jsCStack/Source/JavaScriptCore/tests/stress/simple-polyvariant-call-inlining-example.js (0 => 162788)</h4>
<pre class="diff"><span>
<span class="info">--- branches/jsCStack/Source/JavaScriptCore/tests/stress/simple-polyvariant-call-inlining-example.js         (rev 0)
+++ branches/jsCStack/Source/JavaScriptCore/tests/stress/simple-polyvariant-call-inlining-example.js        2014-01-26 00:44:46 UTC (rev 162788)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+function foo(baz) {
+ return bar(baz);
+}
+
+function fuzz(baz) {
+ return bar(baz);
+}
+
+function bar(baz) {
+ return baz();
+}
+
+function baz1() {
+ return 42;
+}
+
+function baz2() {
+ return 24;
+}
+
+noInline(foo);
+noInline(fuzz);
+
+for (var i = 0; i < 100000; ++i) {
+ var result = foo(baz1);
+ if (result != 42)
+ throw "Error: bad result: " + result;
+ var result = fuzz(baz2);
+ if (result != 24)
+ throw "Error: bad result: " + result;
+}
+
</ins></span></pre>
</div>
</div>
</body>
</html>