<!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>[183207] trunk/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/183207">183207</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-04-23 13:47:31 -0700 (Thu, 23 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>DFG should insert Phantoms late using BytecodeKills and block-local OSR availability
https://bugs.webkit.org/show_bug.cgi?id=143735

Reviewed by Geoffrey Garen.
        
We've always had bugs arising from the fact that we would MovHint something into a local,
and then fail to keep it alive. We would then try to keep things alive by putting Phantoms
on those Nodes that were MovHinted. But this became increasingly tricky. Given the
sophistication of the transformations we are doing today, this approach is just not sound
anymore.
        
This comprehensively fixes these bugs by having the DFG backend automatically insert
Phantoms just before codegen based on bytecode liveness. To make this practical, this also
makes it much faster to query bytecode liveness.
        
It's about as perf-neutral as it gets for a change that increases compiler work without
actually optimizing anything. Later changes will remove the old Phantom-preserving logic,
which should then speed us up. I can't really report concrete slow-down numbers because
they are low enough to basically be in the noise. For example, a 20-iteration run of
SunSpider yields &quot;maybe 0.8% slower&quot;, whatever that means.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeLivenessAnalysis.cpp:
(JSC::BytecodeLivenessAnalysis::computeFullLiveness):
* bytecode/FullBytecodeLiveness.h:
(JSC::FullBytecodeLiveness::getLiveness):
* bytecode/VirtualRegister.h:
(JSC::VirtualRegister::operator+):
(JSC::VirtualRegister::operator-):
* dfg/DFGForAllKills.h:
(JSC::DFG::forAllLiveNodesAtTail):
(JSC::DFG::forAllKilledOperands):
(JSC::DFG::forAllKilledNodesAtNodeIndex):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::isLiveInBytecode):
(JSC::DFG::Graph::localsLiveInBytecode):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::forAllLocalsLiveInBytecode):
(JSC::DFG::Graph::forAllLiveInBytecode):
* dfg/DFGMayExit.cpp:
(JSC::DFG::mayExit):
* dfg/DFGMovHintRemovalPhase.cpp:
* dfg/DFGNodeType.h:
* dfg/DFGPhantomInsertionPhase.cpp: Added.
(JSC::DFG::performPhantomInsertion):
* dfg/DFGPhantomInsertionPhase.h: Added.
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGScoreBoard.h:
(JSC::DFG::ScoreBoard::sortFree):
(JSC::DFG::ScoreBoard::assertClear):
* dfg/DFGVirtualRegisterAllocationPhase.cpp:
(JSC::DFG::VirtualRegisterAllocationPhase::run):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::buildExitArguments):
* tests/stress/phantom-inadequacy.js: Added.
(bar):
(baz):
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeBytecodeLivenessAnalysiscpp">trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeFullBytecodeLivenessh">trunk/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeVirtualRegisterh">trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGForAllKillsh">trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMayExitcpp">trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMovHintRemovalPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlancpp">trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGScoreBoardh">trunk/Source/JavaScriptCore/dfg/DFGScoreBoard.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGVirtualRegisterAllocationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPhantomInsertionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPhantomInsertionPhaseh">trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressphantominadequacyjs">trunk/Source/JavaScriptCore/tests/stress/phantom-inadequacy.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -203,6 +203,7 @@
</span><span class="cx">     dfg/DFGObjectMaterializationData.cpp
</span><span class="cx">     dfg/DFGOperations.cpp
</span><span class="cx">     dfg/DFGPhantomCanonicalizationPhase.cpp
</span><ins>+    dfg/DFGPhantomInsertionPhase.cpp
</ins><span class="cx">     dfg/DFGPhantomRemovalPhase.cpp
</span><span class="cx">     dfg/DFGPhase.cpp
</span><span class="cx">     dfg/DFGPhiChildren.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -1,3 +1,67 @@
</span><ins>+2015-04-22  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG should insert Phantoms late using BytecodeKills and block-local OSR availability
+        https://bugs.webkit.org/show_bug.cgi?id=143735
+
+        Reviewed by Geoffrey Garen.
+        
+        We've always had bugs arising from the fact that we would MovHint something into a local,
+        and then fail to keep it alive. We would then try to keep things alive by putting Phantoms
+        on those Nodes that were MovHinted. But this became increasingly tricky. Given the
+        sophistication of the transformations we are doing today, this approach is just not sound
+        anymore.
+        
+        This comprehensively fixes these bugs by having the DFG backend automatically insert
+        Phantoms just before codegen based on bytecode liveness. To make this practical, this also
+        makes it much faster to query bytecode liveness.
+        
+        It's about as perf-neutral as it gets for a change that increases compiler work without
+        actually optimizing anything. Later changes will remove the old Phantom-preserving logic,
+        which should then speed us up. I can't really report concrete slow-down numbers because
+        they are low enough to basically be in the noise. For example, a 20-iteration run of
+        SunSpider yields &quot;maybe 0.8% slower&quot;, whatever that means.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/BytecodeLivenessAnalysis.cpp:
+        (JSC::BytecodeLivenessAnalysis::computeFullLiveness):
+        * bytecode/FullBytecodeLiveness.h:
+        (JSC::FullBytecodeLiveness::getLiveness):
+        * bytecode/VirtualRegister.h:
+        (JSC::VirtualRegister::operator+):
+        (JSC::VirtualRegister::operator-):
+        * dfg/DFGForAllKills.h:
+        (JSC::DFG::forAllLiveNodesAtTail):
+        (JSC::DFG::forAllKilledOperands):
+        (JSC::DFG::forAllKilledNodesAtNodeIndex):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::isLiveInBytecode):
+        (JSC::DFG::Graph::localsLiveInBytecode):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::forAllLocalsLiveInBytecode):
+        (JSC::DFG::Graph::forAllLiveInBytecode):
+        * dfg/DFGMayExit.cpp:
+        (JSC::DFG::mayExit):
+        * dfg/DFGMovHintRemovalPhase.cpp:
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPhantomInsertionPhase.cpp: Added.
+        (JSC::DFG::performPhantomInsertion):
+        * dfg/DFGPhantomInsertionPhase.h: Added.
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        * dfg/DFGScoreBoard.h:
+        (JSC::DFG::ScoreBoard::sortFree):
+        (JSC::DFG::ScoreBoard::assertClear):
+        * dfg/DFGVirtualRegisterAllocationPhase.cpp:
+        (JSC::DFG::VirtualRegisterAllocationPhase::run):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
+        * tests/stress/phantom-inadequacy.js: Added.
+        (bar):
+        (baz):
+        (foo):
+
</ins><span class="cx"> 2015-04-23  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rename HardPhantom to MustGenerate.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -447,6 +447,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGObjectAllocationSinkingPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGObjectMaterializationData.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPhantomCanonicalizationPhase.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\dfg\DFGPhantomInsertionPhase.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPhantomRemovalPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPhiChildren.cpp&quot; /&gt;
</span><span class="lines">@@ -1142,6 +1143,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGOSRExitJumpPlaceholder.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGOSRExitPreparation.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPhantomCanonicalizationPhase.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\dfg\DFGPhantomInsertionPhase.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPhantomRemovalPhase.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPhase.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPhiChildren.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -348,6 +348,8 @@
</span><span class="cx">                 0F620174143FCD330068B77C /* DFGVariableAccessData.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F620176143FCD3B0068B77C /* DFGBasicBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F620177143FCD3F0068B77C /* DFGAbstractValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F6237971AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */; };
+                0F6237981AE45CA700D402EA /* DFGPhantomInsertionPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F63943F15C75F19006A597C /* DFGTypeCheckHoistingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F63944015C75F1D006A597C /* DFGTypeCheckHoistingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */; };
</span><span class="cx">                 0F63945415D07055006A597C /* ArrayProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F63945115D07051006A597C /* ArrayProfile.cpp */; };
</span><span class="lines">@@ -2083,6 +2085,8 @@
</span><span class="cx">                 0F62016F143FCD2F0068B77C /* DFGAbstractValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAbstractValue.h; path = dfg/DFGAbstractValue.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F620170143FCD2F0068B77C /* DFGBasicBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBasicBlock.h; path = dfg/DFGBasicBlock.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGVariableAccessData.h; path = dfg/DFGVariableAccessData.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPhantomInsertionPhase.cpp; path = dfg/DFGPhantomInsertionPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPhantomInsertionPhase.h; path = dfg/DFGPhantomInsertionPhase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F63943C15C75F14006A597C /* DFGTypeCheckHoistingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGTypeCheckHoistingPhase.cpp; path = dfg/DFGTypeCheckHoistingPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F63943D15C75F14006A597C /* DFGTypeCheckHoistingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGTypeCheckHoistingPhase.h; path = dfg/DFGTypeCheckHoistingPhase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F63945115D07051006A597C /* ArrayProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayProfile.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5024,6 +5028,8 @@
</span><span class="cx">                                 0F235BEA17178E7300690C7F /* DFGOSRExitPreparation.h */,
</span><span class="cx">                                 0F7B365F197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.cpp */,
</span><span class="cx">                                 0F7B3660197C525C00ED1DDC /* DFGPhantomCanonicalizationPhase.h */,
</span><ins>+                                0F6237951AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp */,
+                                0F6237961AE45CA700D402EA /* DFGPhantomInsertionPhase.h */,
</ins><span class="cx">                                 0FBFDD02196C92BF007A5BFA /* DFGPhantomRemovalPhase.cpp */,
</span><span class="cx">                                 0FBFDD03196C92BF007A5BFA /* DFGPhantomRemovalPhase.h */,
</span><span class="cx">                                 0FFFC94F14EF909500C72532 /* DFGPhase.cpp */,
</span><span class="lines">@@ -6220,6 +6226,7 @@
</span><span class="cx">                                 BC18C42E0E16F5CD00B34460 /* JSWrapperObject.h in Headers */,
</span><span class="cx">                                 BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */,
</span><span class="cx">                                 A72FFD64139985A800E5365A /* KeywordLookup.h in Headers */,
</span><ins>+                                0F6237981AE45CA700D402EA /* DFGPhantomInsertionPhase.h in Headers */,
</ins><span class="cx">                                 969A072A0ED1CE6900F1F681 /* Label.h in Headers */,
</span><span class="cx">                                 960097A60EBABB58007A7297 /* LabelScope.h in Headers */,
</span><span class="cx">                                 0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */,
</span><span class="lines">@@ -7473,6 +7480,7 @@
</span><span class="cx">                                 95AB83560DA43C3000BC83F3 /* ProfileNode.cpp in Sources */,
</span><span class="cx">                                 0FF729AD166AD35C000F5BA3 /* ProfilerBytecode.cpp in Sources */,
</span><span class="cx">                                 0FF729AE166AD35C000F5BA3 /* ProfilerBytecodes.cpp in Sources */,
</span><ins>+                                0F6237971AE45CA700D402EA /* DFGPhantomInsertionPhase.cpp in Sources */,
</ins><span class="cx">                                 0F13912916771C33009CCB07 /* ProfilerBytecodeSequence.cpp in Sources */,
</span><span class="cx">                                 0FF729AF166AD35C000F5BA3 /* ProfilerCompilation.cpp in Sources */,
</span><span class="cx">                                 0FF729B0166AD35C000F5BA3 /* ProfilerCompilationKind.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeBytecodeLivenessAnalysiscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -237,7 +237,7 @@
</span><span class="cx"> {
</span><span class="cx">     FastBitVector out;
</span><span class="cx">     
</span><del>-    result.m_map.clear();
</del><ins>+    result.m_map.resize(m_codeBlock-&gt;instructions().size());
</ins><span class="cx">     
</span><span class="cx">     for (unsigned i = m_basicBlocks.size(); i--;) {
</span><span class="cx">         BytecodeBasicBlock* block = m_basicBlocks[i].get();
</span><span class="lines">@@ -249,7 +249,7 @@
</span><span class="cx">         for (unsigned i = block-&gt;bytecodeOffsets().size(); i--;) {
</span><span class="cx">             unsigned bytecodeOffset = block-&gt;bytecodeOffsets()[i];
</span><span class="cx">             stepOverInstruction(m_codeBlock, m_basicBlocks, bytecodeOffset, out);
</span><del>-            result.m_map.add(bytecodeOffset, out);
</del><ins>+            result.m_map[bytecodeOffset] = out;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeFullBytecodeLivenessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/bytecode/FullBytecodeLiveness.h        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -38,9 +38,7 @@
</span><span class="cx"> public:
</span><span class="cx">     const FastBitVector&amp; getLiveness(unsigned bytecodeIndex) const
</span><span class="cx">     {
</span><del>-        BytecodeToBitmapMap::const_iterator iter = m_map.find(bytecodeIndex);
-        ASSERT(iter != m_map.end());
-        return iter-&gt;value;
</del><ins>+        return m_map[bytecodeIndex];
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     bool operandIsLive(int operand, unsigned bytecodeIndex) const
</span><span class="lines">@@ -51,7 +49,7 @@
</span><span class="cx"> private:
</span><span class="cx">     friend class BytecodeLivenessAnalysis;
</span><span class="cx">     
</span><del>-    BytecodeToBitmapMap m_map;
</del><ins>+    Vector&lt;FastBitVector, 0, UnsafeVectorOverflow&gt; m_map;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeVirtualRegisterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -82,6 +82,14 @@
</span><span class="cx">     {
</span><span class="cx">         return VirtualRegister(offset() - value);
</span><span class="cx">     }
</span><ins>+    VirtualRegister operator+(VirtualRegister value) const
+    {
+        return VirtualRegister(offset() + value.offset());
+    }
+    VirtualRegister operator-(VirtualRegister value) const
+    {
+        return VirtualRegister(offset() - value.offset());
+    }
</ins><span class="cx">     VirtualRegister&amp; operator+=(int value)
</span><span class="cx">     {
</span><span class="cx">         return *this = *this + value;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGForAllKillsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -51,69 +51,88 @@
</span><span class="cx">     DFG_ASSERT(graph, block-&gt;terminal(), block-&gt;terminal()-&gt;origin.forExit.isSet());
</span><span class="cx">     
</span><span class="cx">     AvailabilityMap&amp; availabilityMap = block-&gt;ssa-&gt;availabilityAtTail;
</span><del>-    for (unsigned i = availabilityMap.m_locals.size(); i--;) {
-        VirtualRegister reg = availabilityMap.m_locals.virtualRegisterForIndex(i);
-        
-        if (!graph.isLiveInBytecode(reg, block-&gt;terminal()-&gt;origin.forExit))
-            continue;
-        
-        availabilityMap.closeStartingWithLocal(
-            reg,
-            [&amp;] (Node* node) -&gt; bool {
-                return seen.contains(node);
-            },
-            [&amp;] (Node* node) -&gt; bool {
-                if (!seen.add(node).isNewEntry)
-                    return false;
-                functor(node);
-                return true;
-            });
-    }
</del><ins>+    graph.forAllLocalsLiveInBytecode(
+        block-&gt;terminal()-&gt;origin.forExit,
+        [&amp;] (VirtualRegister reg) {
+            availabilityMap.closeStartingWithLocal(
+                reg,
+                [&amp;] (Node* node) -&gt; bool {
+                    return seen.contains(node);
+                },
+                [&amp;] (Node* node) -&gt; bool {
+                    if (!seen.add(node).isNewEntry)
+                        return false;
+                    functor(node);
+                    return true;
+                });
+        });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// This tells you those things that die on the boundary between nodeBefore and nodeAfter. It is
+// conservative in the sense that it might resort to telling you some things that are still live at
+// nodeAfter.
</ins><span class="cx"> template&lt;typename Functor&gt;
</span><del>-void forAllKilledOperands(Graph&amp; graph, CodeOrigin before, Node* nodeAfter, const Functor&amp; functor)
</del><ins>+void forAllKilledOperands(Graph&amp; graph, Node* nodeBefore, Node* nodeAfter, const Functor&amp; functor)
</ins><span class="cx"> {
</span><ins>+    CodeOrigin before = nodeBefore-&gt;origin.forExit;
</ins><span class="cx">     CodeOrigin after = nodeAfter-&gt;origin.forExit;
</span><span class="cx">     
</span><ins>+    VirtualRegister alreadyNoted;
+    if (!!after) {
+        // If we MovHint something that is live at the time, then we kill the old value.
+        if (nodeAfter-&gt;containsMovHint()) {
+            VirtualRegister reg = nodeAfter-&gt;unlinkedLocal();
+            if (graph.isLiveInBytecode(reg, after)) {
+                functor(reg);
+                alreadyNoted = reg;
+            }
+        }
+    }
+    
</ins><span class="cx">     if (!before) {
</span><span class="cx">         if (!after)
</span><span class="cx">             return;
</span><span class="cx">         // The true before-origin is the origin at predecessors that jump to us. But there can be
</span><span class="cx">         // many such predecessors and they will likely all have a different origin. So, it's better
</span><span class="cx">         // to do the conservative thing.
</span><del>-        for (unsigned i = graph.block(0)-&gt;variablesAtHead.numberOfLocals(); i--;) {
-            VirtualRegister reg = virtualRegisterForLocal(i);
-            if (graph.isLiveInBytecode(reg, after))
-                functor(reg);
-        }
</del><ins>+        graph.forAllLocalsLiveInBytecode(after, functor);
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    // If we MovHint something that is live at the time, then we kill the old value.
-    VirtualRegister alreadyNoted;
-    if (nodeAfter-&gt;containsMovHint()) {
-        VirtualRegister reg = nodeAfter-&gt;unlinkedLocal();
-        if (graph.isLiveInBytecode(reg, after)) {
-            functor(reg);
-            alreadyNoted = reg;
-        }
-    }
-    
</del><span class="cx">     if (before == after)
</span><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     // before could be unset even if after is, but the opposite cannot happen.
</span><span class="cx">     ASSERT(!!after);
</span><span class="cx">     
</span><ins>+    // It's easier to do this if the inline call frames are the same. This is way faster than the
+    // other loop, below.
+    if (before.inlineCallFrame == after.inlineCallFrame) {
+        int stackOffset = before.inlineCallFrame ? before.inlineCallFrame-&gt;stackOffset : 0;
+        CodeBlock* codeBlock = graph.baselineCodeBlockFor(before.inlineCallFrame);
+        FullBytecodeLiveness&amp; fullLiveness = graph.livenessFor(codeBlock);
+        const FastBitVector&amp; liveBefore = fullLiveness.getLiveness(before.bytecodeIndex);
+        const FastBitVector&amp; liveAfter = fullLiveness.getLiveness(after.bytecodeIndex);
+        
+        for (unsigned relativeLocal = codeBlock-&gt;m_numCalleeRegisters; relativeLocal--;) {
+            if (liveBefore.get(relativeLocal) &amp;&amp; !liveAfter.get(relativeLocal))
+                functor(virtualRegisterForLocal(relativeLocal) + stackOffset);
+        }
+        
+        return;
+    }
+    
</ins><span class="cx">     // Detect kills the super conservative way: it is killed if it was live before and dead after.
</span><del>-    for (unsigned i = graph.block(0)-&gt;variablesAtHead.numberOfLocals(); i--;) {
-        VirtualRegister reg = virtualRegisterForLocal(i);
-        if (reg == alreadyNoted)
-            continue;
-        if (graph.isLiveInBytecode(reg, before) &amp;&amp; !graph.isLiveInBytecode(reg, after))
</del><ins>+    BitVector liveAfter = graph.localsLiveInBytecode(after);
+    graph.forAllLocalsLiveInBytecode(
+        before,
+        [&amp;] (VirtualRegister reg) {
+            if (reg == alreadyNoted)
+                return;
+            if (liveAfter.get(reg.toLocal()))
+                return;
</ins><span class="cx">             functor(reg);
</span><del>-    }
</del><ins>+        });
</ins><span class="cx"> }
</span><span class="cx">     
</span><span class="cx"> // Tells you all of the nodes that would no longer be live across the node at this nodeIndex.
</span><span class="lines">@@ -140,9 +159,9 @@
</span><span class="cx">             }
</span><span class="cx">         });
</span><span class="cx"> 
</span><del>-    CodeOrigin before;
</del><ins>+    Node* before = nullptr;
</ins><span class="cx">     if (nodeIndex)
</span><del>-        before = block-&gt;at(nodeIndex - 1)-&gt;origin.forExit;
</del><ins>+        before = block-&gt;at(nodeIndex - 1);
</ins><span class="cx"> 
</span><span class="cx">     forAllKilledOperands(
</span><span class="cx">         graph, before, node,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -944,8 +944,6 @@
</span><span class="cx"> 
</span><span class="cx">         // Arguments are always live. This would be redundant if it wasn't for our
</span><span class="cx">         // op_call_varargs inlining.
</span><del>-        // FIXME: 'this' might not be live, but we don't have a way of knowing.
-        // https://bugs.webkit.org/show_bug.cgi?id=128519
</del><span class="cx">         if (reg.isArgument()
</span><span class="cx">             &amp;&amp; static_cast&lt;size_t&gt;(reg.toArgument()) &lt; inlineCallFrame-&gt;arguments.size())
</span><span class="cx">             return true;
</span><span class="lines">@@ -956,6 +954,19 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+BitVector Graph::localsLiveInBytecode(CodeOrigin codeOrigin)
+{
+    BitVector result;
+    result.ensureSize(block(0)-&gt;variablesAtHead.numberOfLocals());
+    forAllLocalsLiveInBytecode(
+        codeOrigin,
+        [&amp;] (VirtualRegister reg) {
+            ASSERT(reg.isLocal());
+            result.quickSet(reg.toLocal());
+        });
+    return result;
+}
+
</ins><span class="cx"> unsigned Graph::frameRegisterCount()
</span><span class="cx"> {
</span><span class="cx">     unsigned result = m_nextMachineLocal + std::max(m_parameterSlots, static_cast&lt;unsigned&gt;(maxFrameExtentForSlowPathCallInRegisters));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AssemblyHelpers.h&quot;
</span><ins>+#include &quot;BytecodeLivenessAnalysisInlines.h&quot;
</ins><span class="cx"> #include &quot;CodeBlock.h&quot;
</span><span class="cx"> #include &quot;DFGArgumentPosition.h&quot;
</span><span class="cx"> #include &quot;DFGBasicBlock.h&quot;
</span><span class="lines">@@ -41,6 +42,7 @@
</span><span class="cx"> #include &quot;DFGPlan.h&quot;
</span><span class="cx"> #include &quot;DFGPrePostNumbering.h&quot;
</span><span class="cx"> #include &quot;DFGScannable.h&quot;
</span><ins>+#include &quot;FullBytecodeLiveness.h&quot;
</ins><span class="cx"> #include &quot;JSStack.h&quot;
</span><span class="cx"> #include &quot;MethodOfGettingAValueProfile.h&quot;
</span><span class="cx"> #include &lt;unordered_map&gt;
</span><span class="lines">@@ -677,8 +679,84 @@
</span><span class="cx">     
</span><span class="cx">     FullBytecodeLiveness&amp; livenessFor(CodeBlock*);
</span><span class="cx">     FullBytecodeLiveness&amp; livenessFor(InlineCallFrame*);
</span><ins>+    
+    // Quickly query if a single local is live at the given point. This is faster than calling
+    // forAllLiveInBytecode() if you will only query one local. But, if you want to know all of the
+    // locals live, then calling this for each local is much slower than forAllLiveInBytecode().
</ins><span class="cx">     bool isLiveInBytecode(VirtualRegister, CodeOrigin);
</span><span class="cx">     
</span><ins>+    // Quickly get all of the non-argument locals live at the given point. This doesn't give you
+    // any arguments because those are all presumed live. You can call forAllLiveInBytecode() to
+    // also get the arguments. This is much faster than calling isLiveInBytecode() for each local.
+    template&lt;typename Functor&gt;
+    void forAllLocalsLiveInBytecode(CodeOrigin codeOrigin, const Functor&amp; functor)
+    {
+        // Support for not redundantly reporting arguments. Necessary because in case of a varargs
+        // call, only the callee knows that arguments are live while in the case of a non-varargs
+        // call, both callee and caller will see the variables live.
+        VirtualRegister exclusionStart;
+        VirtualRegister exclusionEnd;
+        
+        for (;;) {
+            InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame;
+            VirtualRegister stackOffset(inlineCallFrame ? inlineCallFrame-&gt;stackOffset : 0);
+            
+            if (inlineCallFrame) {
+                if (inlineCallFrame-&gt;isClosureCall)
+                    functor(stackOffset + JSStack::Callee);
+                if (inlineCallFrame-&gt;isVarargs())
+                    functor(stackOffset + JSStack::ArgumentCount);
+            }
+            
+            CodeBlock* codeBlock = baselineCodeBlockFor(inlineCallFrame);
+            FullBytecodeLiveness&amp; fullLiveness = livenessFor(codeBlock);
+            const FastBitVector&amp; liveness = fullLiveness.getLiveness(codeOrigin.bytecodeIndex);
+            for (unsigned relativeLocal = codeBlock-&gt;m_numCalleeRegisters; relativeLocal--;) {
+                VirtualRegister reg = stackOffset + virtualRegisterForLocal(relativeLocal);
+                
+                // Don't report if our callee already reported.
+                if (reg &gt;= exclusionStart &amp;&amp; reg &lt; exclusionEnd)
+                    continue;
+                
+                if (liveness.get(relativeLocal))
+                    functor(reg);
+            }
+            
+            if (!inlineCallFrame)
+                break;
+
+            // Arguments are always live. This would be redundant if it wasn't for our
+            // op_call_varargs inlining. See the comment above.
+            exclusionStart = stackOffset + CallFrame::argumentOffsetIncludingThis(0);
+            exclusionEnd = stackOffset + CallFrame::argumentOffsetIncludingThis(inlineCallFrame-&gt;arguments.size());
+            
+            // We will always have a &quot;this&quot; argument and exclusionStart should be a smaller stack
+            // offset than exclusionEnd.
+            ASSERT(exclusionStart &lt; exclusionEnd);
+
+            for (VirtualRegister reg = exclusionStart; reg &lt; exclusionEnd; reg += 1)
+                functor(reg);
+            
+            codeOrigin = inlineCallFrame-&gt;caller;
+        }
+    }
+    
+    // Get a BitVector of all of the non-argument locals live right now. This is mostly useful if
+    // you want to compare two sets of live locals from two different CodeOrigins.
+    BitVector localsLiveInBytecode(CodeOrigin);
+    
+    // Tells you all of the arguments and locals live at the given CodeOrigin. This is a small
+    // extension to forAllLocalsLiveInBytecode(), since all arguments are always presumed live.
+    template&lt;typename Functor&gt;
+    void forAllLiveInBytecode(CodeOrigin codeOrigin, const Functor&amp; functor)
+    {
+        forAllLocalsLiveInBytecode(codeOrigin, functor);
+        
+        // Report all arguments as being live.
+        for (unsigned argument = block(0)-&gt;variablesAtHead.numberOfArguments(); argument--;)
+            functor(virtualRegisterForArgument(argument));
+    }
+    
</ins><span class="cx">     BytecodeKills&amp; killsFor(CodeBlock*);
</span><span class="cx">     BytecodeKills&amp; killsFor(InlineCallFrame*);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMayExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -88,6 +88,9 @@
</span><span class="cx">     case GetScope:
</span><span class="cx">     case PhantomLocal:
</span><span class="cx">     case CountExecution:
</span><ins>+    case Jump:
+    case Branch:
+    case Unreachable:
</ins><span class="cx">         break;
</span><span class="cx">         
</span><span class="cx">     default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMovHintRemovalPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -80,13 +80,12 @@
</span><span class="cx">         
</span><span class="cx">         Epoch currentEpoch = Epoch::first();
</span><span class="cx">         
</span><del>-        for (unsigned i = m_state.size(); i--;) {
-            VirtualRegister reg = m_state.virtualRegisterForIndex(i);
-            if (m_graph.isLiveInBytecode(reg, block-&gt;terminal()-&gt;origin.forExit))
-                m_state[i] = currentEpoch;
-            else
-                m_state[i] = Epoch();
-        }
</del><ins>+        m_state.fill(Epoch());
+        m_graph.forAllLiveInBytecode(
+            block-&gt;terminal()-&gt;origin.forExit,
+            [&amp;] (VirtualRegister reg) {
+                m_state.operand(reg) = currentEpoch;
+            });
</ins><span class="cx">         
</span><span class="cx">         if (verbose)
</span><span class="cx">             dataLog(&quot;    Locals: &quot;, m_state, &quot;\n&quot;);
</span><span class="lines">@@ -114,7 +113,7 @@
</span><span class="cx">             
</span><span class="cx">             if (nodeIndex) {
</span><span class="cx">                 forAllKilledOperands(
</span><del>-                    m_graph, block-&gt;at(nodeIndex - 1)-&gt;origin.forExit, node,
</del><ins>+                    m_graph, block-&gt;at(nodeIndex - 1), node,
</ins><span class="cx">                     [&amp;] (VirtualRegister reg) {
</span><span class="cx">                         // This function is a bit sloppy - it might claim to kill a local even if
</span><span class="cx">                         // it's still live after. We need to protect against that.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -55,8 +55,13 @@
</span><span class="cx">     /* Nodes for local variable access. These nodes are linked together using Phi nodes. */\
</span><span class="cx">     /* Any two nodes that are part of the same Phi graph will share the same */\
</span><span class="cx">     /* VariableAccessData, and thus will share predictions. FIXME: We should come up with */\
</span><del>-    /* better names for a lot of these. https://bugs.webkit.org/show_bug.cgi?id=137307 */\
-    macro(GetLocal, NodeResultJS) \
</del><ins>+    /* better names for a lot of these. https://bugs.webkit.org/show_bug.cgi?id=137307. */\
+    /* Note that GetLocal is MustGenerate because it's our only way of knowing that some other */\
+    /* basic block might have read a local variable in bytecode. We only remove GetLocals if it */\
+    /* is redundant because of an earlier GetLocal or SetLocal in the same block. We could make */\
+    /* these not MustGenerate and use a more sophisticated analysis to insert PhantomLocals in */\
+    /* the same way that we insert Phantoms. https://bugs.webkit.org/show_bug.cgi?id=144086 */\
+    macro(GetLocal, NodeResultJS | NodeMustGenerate) \
</ins><span class="cx">     macro(SetLocal, 0) \
</span><span class="cx">     \
</span><span class="cx">     macro(PutStack, NodeMustGenerate) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPhantomInsertionPhasecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.cpp (0 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -0,0 +1,181 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;DFGPhantomInsertionPhase.h&quot;
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;BytecodeLivenessAnalysisInlines.h&quot;
+#include &quot;DFGForAllKills.h&quot;
+#include &quot;DFGGraph.h&quot;
+#include &quot;DFGInsertionSet.h&quot;
+#include &quot;DFGMayExit.h&quot;
+#include &quot;DFGPhase.h&quot;
+#include &quot;DFGPredictionPropagationPhase.h&quot;
+#include &quot;DFGVariableAccessDataDump.h&quot;
+#include &quot;JSCInlines.h&quot;
+#include &quot;OperandsInlines.h&quot;
+
+namespace JSC { namespace DFG {
+
+namespace {
+
+bool verbose = false;
+
+class PhantomInsertionPhase : public Phase {
+public:
+    PhantomInsertionPhase(Graph&amp; graph)
+        : Phase(graph, &quot;phantom insertion&quot;)
+        , m_insertionSet(graph)
+        , m_values(OperandsLike, graph.block(0)-&gt;variablesAtHead)
+    {
+    }
+    
+    bool run()
+    {
+        // We assume that DCE has already run. If we run before DCE then we think that all
+        // SetLocals execute, which is inaccurate. That causes us to insert too few Phantoms.
+        DFG_ASSERT(m_graph, nullptr, m_graph.m_refCountState == ExactRefCount);
+        
+        if (verbose) {
+            dataLog(&quot;Graph before Phantom insertion:\n&quot;);
+            m_graph.dump();
+        }
+        
+        m_graph.clearEpochs();
+        
+        for (BasicBlock* block : m_graph.blocksInNaturalOrder())
+            handleBlock(block);
+        
+        if (verbose) {
+            dataLog(&quot;Graph after Phantom insertion:\n&quot;);
+            m_graph.dump();
+        }
+        
+        return true;
+    }
+
+private:
+    void handleBlock(BasicBlock* block)
+    {
+        m_values.fill(nullptr);
+
+        Epoch currentEpoch = Epoch::first();
+        unsigned lastExitingIndex = 0;
+        for (unsigned nodeIndex = 0; nodeIndex &lt; block-&gt;size(); ++nodeIndex) {
+            Node* node = block-&gt;at(nodeIndex);
+            if (verbose)
+                dataLog(&quot;Considering &quot;, node, &quot;\n&quot;);
+            
+            switch (node-&gt;op()) {
+            case MovHint:
+                m_values.operand(node-&gt;unlinkedLocal()) = node-&gt;child1().node();
+                break;
+                
+            case ZombieHint:
+                m_values.operand(node-&gt;unlinkedLocal()) = nullptr;
+                break;
+
+            case SetLocal:
+            case GetLocal:
+            case SetArgument:
+                m_values.operand(node-&gt;local()) = nullptr;
+                break;
+                
+            default:
+                break;
+            }
+            
+            if (mayExit(m_graph, node)) {
+                currentEpoch.bump();
+                lastExitingIndex = nodeIndex;
+            }
+            
+            m_graph.doToChildren(
+                node,
+                [&amp;] (Edge edge) {
+                    edge-&gt;setEpoch(currentEpoch);
+                });
+            
+            node-&gt;setEpoch(currentEpoch);
+
+            auto killAction = [&amp;] (VirtualRegister reg) {
+                if (verbose)
+                    dataLog(&quot;    Killed operand: &quot;, reg, &quot;\n&quot;);
+                        
+                Node* killedNode = m_values.operand(reg);
+                if (!killedNode)
+                    return;
+                
+                // We only need to insert a Phantom if the node hasn't been used since the last
+                // exit, and was born before the last exit.
+                if (killedNode-&gt;epoch() == currentEpoch)
+                    return;
+                
+                if (verbose) {
+                    dataLog(
+                        &quot;    Inserting Phantom on &quot;, killedNode, &quot; after &quot;,
+                        block-&gt;at(lastExitingIndex), &quot;\n&quot;);
+                }
+                
+                // We have exact ref counts, so creating a new use means that we have to increment
+                // the ref count.
+                killedNode-&gt;postfixRef();
+                
+                m_insertionSet.insertNode(
+                    lastExitingIndex + 1, SpecNone, Phantom, block-&gt;at(lastExitingIndex)-&gt;origin,
+                    killedNode-&gt;defaultEdge());
+            };
+            
+            if (nodeIndex + 1 == block-&gt;size()) {
+                // Should a MovHinted value be kept alive? If the value has been SetLocal'd then
+                // the answer is no. But we may have a value that is live here and dead in
+                // successors because we had jettisoned those successors that would have used the
+                // value. Hence, anything live here should be kept alive.
+                m_graph.forAllLiveInBytecode(node-&gt;origin.forExit, killAction);
+            } else
+                forAllKilledOperands(m_graph, node, block-&gt;at(nodeIndex + 1), killAction);
+        }
+        
+        m_insertionSet.execute(block);
+    }
+    
+    InsertionSet m_insertionSet;
+    Operands&lt;Node*&gt; m_values;
+};
+
+} // anonymous namespace
+    
+bool performPhantomInsertion(Graph&amp; graph)
+{
+    SamplingRegion samplingRegion(&quot;DFG Phantom Insertion Phase&quot;);
+    return runPhase&lt;PhantomInsertionPhase&gt;(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPhantomInsertionPhaseh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.h (0 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPhantomInsertionPhase.h        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGPhantomInsertionPhase_h
+#define DFGPhantomInsertionPhase_h
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Inserts Phantoms based on bytecode liveness.
+
+bool performPhantomInsertion(Graph&amp;);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGPhantomInsertionPhase_h
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx"> #include &quot;DFGOSREntrypointCreationPhase.h&quot;
</span><span class="cx"> #include &quot;DFGObjectAllocationSinkingPhase.h&quot;
</span><span class="cx"> #include &quot;DFGPhantomCanonicalizationPhase.h&quot;
</span><ins>+#include &quot;DFGPhantomInsertionPhase.h&quot;
</ins><span class="cx"> #include &quot;DFGPhantomRemovalPhase.h&quot;
</span><span class="cx"> #include &quot;DFGPredictionInjectionPhase.h&quot;
</span><span class="cx"> #include &quot;DFGPredictionPropagationPhase.h&quot;
</span><span class="lines">@@ -320,6 +321,7 @@
</span><span class="cx">         performPhantomRemoval(dfg);
</span><span class="cx">         performCPSRethreading(dfg);
</span><span class="cx">         performDCE(dfg);
</span><ins>+        performPhantomInsertion(dfg);
</ins><span class="cx">         performStackLayout(dfg);
</span><span class="cx">         performVirtualRegisterAllocation(dfg);
</span><span class="cx">         performWatchpointCollection(dfg);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGScoreBoardh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGScoreBoard.h (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGScoreBoard.h        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGScoreBoard.h        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -55,21 +55,27 @@
</span><span class="cx">         assertClear();
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void sortFree()
+    {
+        std::sort(m_free.begin(), m_free.end());
+    }
+    
</ins><span class="cx">     void assertClear()
</span><span class="cx">     {
</span><del>-#if !ASSERT_DISABLED
</del><ins>+        if (ASSERT_DISABLED)
+            return;
+        
</ins><span class="cx">         // For every entry in the used list the use count of the virtual register should be zero, or max, due to it being a preserved local.
</span><span class="cx">         for (size_t i = 0; i &lt; m_used.size(); ++i)
</span><del>-            ASSERT(!m_used[i] || m_used[i] == max());
</del><ins>+            RELEASE_ASSERT(!m_used[i] || m_used[i] == max());
</ins><span class="cx">         // For every entry in the free list, the use count should be zero.
</span><span class="cx">         for (size_t i = 0; i &lt; m_free.size(); ++i)
</span><del>-            ASSERT(!m_used[m_free[i]]);
</del><ins>+            RELEASE_ASSERT(!m_used[m_free[i]]);
</ins><span class="cx">         // There must not be duplicates in the free list.
</span><span class="cx">         for (size_t i = 0; i &lt; m_free.size(); ++i) {
</span><span class="cx">             for (size_t j = i + 1; j &lt; m_free.size(); ++j)
</span><del>-                ASSERT(m_free[i] != m_free[j]);
</del><ins>+                RELEASE_ASSERT(m_free[i] != m_free[j]);
</ins><span class="cx">         }
</span><del>-#endif
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     VirtualRegister allocate()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGVirtualRegisterAllocationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -55,6 +55,10 @@
</span><span class="cx">                 continue;
</span><span class="cx">             if (!block-&gt;isReachable)
</span><span class="cx">                 continue;
</span><ins>+            if (!ASSERT_DISABLED) {
+                // Force usage of highest-numbered virtual registers.
+                scoreBoard.sortFree();
+            }
</ins><span class="cx">             for (size_t indexInBlock = 0; indexInBlock &lt; block-&gt;size(); ++indexInBlock) {
</span><span class="cx">                 Node* node = block-&gt;at(indexInBlock);
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (183206 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-04-23 20:30:24 UTC (rev 183206)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -7199,13 +7199,14 @@
</span><span class="cx">             arguments.append(lowValue.value());
</span><span class="cx">         
</span><span class="cx">         AvailabilityMap availabilityMap = this-&gt;availabilityMap();
</span><ins>+        availabilityMap.m_locals.fill(Availability());
</ins><span class="cx">         
</span><del>-        for (unsigned i = 0; i &lt; exit.m_values.size(); ++i) {
-            int operand = exit.m_values.operandForIndex(i);
-            bool isLive = m_graph.isLiveInBytecode(VirtualRegister(operand), codeOrigin);
-            if (!isLive)
-                availabilityMap.m_locals[i] = Availability();
-        }
</del><ins>+        m_graph.forAllLiveInBytecode(
+            codeOrigin,
+            [&amp;] (VirtualRegister reg) {
+                availabilityMap.m_locals.operand(reg) =
+                    this-&gt;availabilityMap().m_locals.operand(reg);
+            });
</ins><span class="cx">         
</span><span class="cx">         availabilityMap.prune();
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressphantominadequacyjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/phantom-inadequacy.js (0 => 183207)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/phantom-inadequacy.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/phantom-inadequacy.js        2015-04-23 20:47:31 UTC (rev 183207)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+function bar() {
+    return 42.5;
+}
+noInline(bar);
+
+function baz(value) {
+    if (value != 42.5)
+        throw &quot;Error: bad value: &quot; + value;
+}
+noInline(baz);
+
+var True = true;
+function foo(a) {
+    var x = bar();
+    var tmp = 0;
+    if (True) {
+        var tmp2 = x;
+        tmp = a + 1;
+        baz(tmp2);
+    }
+    return x + 1 + tmp;
+}
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var result = foo(1);
+    if (result != 42.5 + 1 + 1 + 1)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
+var result = foo(2147483647);
+if (result != 42.5 + 1 + 2147483647 + 1)
+    throw &quot;Error: bad result at end: &quot; + result;
</ins></span></pre>
</div>
</div>

</body>
</html>