<!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>[184311] 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/184311">184311</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-05-13 15:14:25 -0700 (Wed, 13 May 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>The liveness pruning done by ObjectAllocationSinkingPhase ignores the possibility of an object's bytecode liveness being longer than its DFG liveness
https://bugs.webkit.org/show_bug.cgi?id=144945

Reviewed by Michael Saboff.
        
We were making the mistake of using DFG liveness for object allocation sinking decisions.
This is wrong. In fact we almost never want to use DFG liveness directly. The only place
where that makes sense is pruning in DFG AI.
        
So, I created a CombinedLiveness class that combines the DFG liveness with bytecode
liveness.
        
In the process of doing this, I realized that the DFGForAllKills definition of combined
liveness at block tail was not strictly right; it was using the bytecode liveness at the
block terminal instead of the union of the bytecode live-at-heads of successor blocks. So,
I changed DFGForAllKills to work in terms of CombinedLiveness.
        
This allows me to unskip the test I added in <a href="http://trac.webkit.org/projects/webkit/changeset/184260">r184260</a>. I also added a new test that tries to
trigger this bug more directly.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGArgumentsEliminationPhase.cpp:
* dfg/DFGCombinedLiveness.cpp: Added.
(JSC::DFG::liveNodesAtHead):
(JSC::DFG::CombinedLiveness::CombinedLiveness):
* dfg/DFGCombinedLiveness.h: Added.
(JSC::DFG::CombinedLiveness::CombinedLiveness):
* dfg/DFGForAllKills.h:
(JSC::DFG::forAllKillsInBlock):
(JSC::DFG::forAllLiveNodesAtTail): Deleted.
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::performSinking):
(JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
(JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
(JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields):
* tests/stress/escape-object-in-diamond-then-exit.js: Added.
* tests/stress/sink-object-past-invalid-check-sneaky.js:</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="#trunkSourceJavaScriptCoredfgDFGArgumentsEliminationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGForAllKillsh">trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstresssinkobjectpastinvalidchecksneakyjs">trunk/Source/JavaScriptCore/tests/stress/sink-object-past-invalid-check-sneaky.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCombinedLivenesscpp">trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCombinedLivenessh">trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressescapeobjectindiamondthenexitjs">trunk/Source/JavaScriptCore/tests/stress/escape-object-in-diamond-then-exit.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 (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -145,6 +145,7 @@
</span><span class="cx">     dfg/DFGCleanUpPhase.cpp
</span><span class="cx">     dfg/DFGClobberSet.cpp
</span><span class="cx">     dfg/DFGClobberize.cpp
</span><ins>+    dfg/DFGCombinedLiveness.cpp
</ins><span class="cx">     dfg/DFGCommon.cpp
</span><span class="cx">     dfg/DFGCommonData.cpp
</span><span class="cx">     dfg/DFGCompilationKey.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -1,3 +1,45 @@
</span><ins>+2015-05-13  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        The liveness pruning done by ObjectAllocationSinkingPhase ignores the possibility of an object's bytecode liveness being longer than its DFG liveness
+        https://bugs.webkit.org/show_bug.cgi?id=144945
+
+        Reviewed by Michael Saboff.
+        
+        We were making the mistake of using DFG liveness for object allocation sinking decisions.
+        This is wrong. In fact we almost never want to use DFG liveness directly. The only place
+        where that makes sense is pruning in DFG AI.
+        
+        So, I created a CombinedLiveness class that combines the DFG liveness with bytecode
+        liveness.
+        
+        In the process of doing this, I realized that the DFGForAllKills definition of combined
+        liveness at block tail was not strictly right; it was using the bytecode liveness at the
+        block terminal instead of the union of the bytecode live-at-heads of successor blocks. So,
+        I changed DFGForAllKills to work in terms of CombinedLiveness.
+        
+        This allows me to unskip the test I added in r184260. I also added a new test that tries to
+        trigger this bug more directly.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * dfg/DFGArgumentsEliminationPhase.cpp:
+        * dfg/DFGCombinedLiveness.cpp: Added.
+        (JSC::DFG::liveNodesAtHead):
+        (JSC::DFG::CombinedLiveness::CombinedLiveness):
+        * dfg/DFGCombinedLiveness.h: Added.
+        (JSC::DFG::CombinedLiveness::CombinedLiveness):
+        * dfg/DFGForAllKills.h:
+        (JSC::DFG::forAllKillsInBlock):
+        (JSC::DFG::forAllLiveNodesAtTail): Deleted.
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        (JSC::DFG::ObjectAllocationSinkingPhase::performSinking):
+        (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
+        (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
+        (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields):
+        * tests/stress/escape-object-in-diamond-then-exit.js: Added.
+        * tests/stress/sink-object-past-invalid-check-sneaky.js:
+
</ins><span class="cx"> 2015-05-13  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         I skipped a wrong test in r184270. Fix that.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -383,6 +383,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGCleanUpPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGClobberize.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGClobberSet.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\dfg\DFGCombinedLiveness.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGCommon.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGCommonData.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGCompilationKey.cpp&quot; /&gt;
</span><span class="lines">@@ -1063,6 +1064,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGCleanUpPhase.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGClobberize.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGClobberSet.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\dfg\DFGCombinedLiveness.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGCommon.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGCommonData.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGCompilationKey.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -82,6 +82,8 @@
</span><span class="cx">                 0F0332C418B01763005F979A /* GetByIdVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0332C218B01763005F979A /* GetByIdVariant.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F0332C618B53FA9005F979A /* FTLWeight.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0332C518B53FA9005F979A /* FTLWeight.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F0332C818B546EC005F979A /* FTLWeightedTarget.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0332C718B546EC005F979A /* FTLWeightedTarget.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F04396D1B03DC0B009598B7 /* DFGCombinedLiveness.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F04396B1B03DC0B009598B7 /* DFGCombinedLiveness.cpp */; };
+                0F04396E1B03DC0B009598B7 /* DFGCombinedLiveness.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F04396C1B03DC0B009598B7 /* DFGCombinedLiveness.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F05C3B41683CF9200BAF45B /* DFGArrayifySlowPathGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F0776BF14FF002B00102332 /* JITCompilationEffort.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0776BD14FF002800102332 /* JITCompilationEffort.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F0B839C14BCF46300885B4F /* LLIntThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0B839714BCF45A00885B4F /* LLIntThunks.cpp */; };
</span><span class="lines">@@ -1816,6 +1818,8 @@
</span><span class="cx">                 0F0332C218B01763005F979A /* GetByIdVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetByIdVariant.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F0332C518B53FA9005F979A /* FTLWeight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLWeight.h; path = ftl/FTLWeight.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F0332C718B546EC005F979A /* FTLWeightedTarget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLWeightedTarget.h; path = ftl/FTLWeightedTarget.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F04396B1B03DC0B009598B7 /* DFGCombinedLiveness.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCombinedLiveness.cpp; path = dfg/DFGCombinedLiveness.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F04396C1B03DC0B009598B7 /* DFGCombinedLiveness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCombinedLiveness.h; path = dfg/DFGCombinedLiveness.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F05C3B21683CF8F00BAF45B /* DFGArrayifySlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayifySlowPathGenerator.h; path = dfg/DFGArrayifySlowPathGenerator.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F0776BD14FF002800102332 /* JITCompilationEffort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITCompilationEffort.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F0B839714BCF45A00885B4F /* LLIntThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LLIntThunks.cpp; path = llint/LLIntThunks.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4881,6 +4885,8 @@
</span><span class="cx">                                 A77A423917A0BBFD00A8DB81 /* DFGClobberize.h */,
</span><span class="cx">                                 A77A423A17A0BBFD00A8DB81 /* DFGClobberSet.cpp */,
</span><span class="cx">                                 A77A423B17A0BBFD00A8DB81 /* DFGClobberSet.h */,
</span><ins>+                                0F04396B1B03DC0B009598B7 /* DFGCombinedLiveness.cpp */,
+                                0F04396C1B03DC0B009598B7 /* DFGCombinedLiveness.h */,
</ins><span class="cx">                                 0FB4B51A16B62772003F696B /* DFGCommon.cpp */,
</span><span class="cx">                                 0FC0977E1469EBC400CF2442 /* DFGCommon.h */,
</span><span class="cx">                                 0FEA0A2D170D40BF00BB722C /* DFGCommonData.cpp */,
</span><span class="lines">@@ -6230,6 +6236,7 @@
</span><span class="cx">                                 0FC3CD0019ADA410006AC72A /* DFGBlockWorklist.h in Headers */,
</span><span class="cx">                                 0FE050181AA9091100D33B33 /* DirectArguments.h in Headers */,
</span><span class="cx">                                 FE20CE9E15F04A9500DF3430 /* LLIntCLoop.h in Headers */,
</span><ins>+                                0F04396E1B03DC0B009598B7 /* DFGCombinedLiveness.h in Headers */,
</ins><span class="cx">                                 0F4680CA14BBB16C00BFE272 /* LLIntCommon.h in Headers */,
</span><span class="cx">                                 0FBDB9AD1AB0FBC6000B57E5 /* DFGCallCreateDirectArgumentsSlowPathGenerator.h in Headers */,
</span><span class="cx">                                 0F4680D314BBD16700BFE272 /* LLIntData.h in Headers */,
</span><span class="lines">@@ -7514,6 +7521,7 @@
</span><span class="cx">                                 70EC0EC61AA0D7DA00B6AAFA /* StringIteratorPrototype.cpp in Sources */,
</span><span class="cx">                                 A5FD0067189AFE9C00633231 /* ScriptArguments.cpp in Sources */,
</span><span class="cx">                                 A5FD006D189B00AA00633231 /* ScriptCallFrame.cpp in Sources */,
</span><ins>+                                0F04396D1B03DC0B009598B7 /* DFGCombinedLiveness.cpp in Sources */,
</ins><span class="cx">                                 A5FD006F189B00AA00633231 /* ScriptCallStack.cpp in Sources */,
</span><span class="cx">                                 A5FD007D189B0B4C00633231 /* ScriptCallStackFactory.cpp in Sources */,
</span><span class="cx">                                 A503FA25188EFFFD00110F14 /* ScriptDebugServer.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGArgumentsEliminationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/dfg/DFGArgumentsEliminationPhase.cpp        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -33,6 +33,7 @@
</span><span class="cx"> #include &quot;DFGBasicBlockInlines.h&quot;
</span><span class="cx"> #include &quot;DFGBlockMapInlines.h&quot;
</span><span class="cx"> #include &quot;DFGClobberize.h&quot;
</span><ins>+#include &quot;DFGCombinedLiveness.h&quot;
</ins><span class="cx"> #include &quot;DFGForAllKills.h&quot;
</span><span class="cx"> #include &quot;DFGGraph.h&quot;
</span><span class="cx"> #include &quot;DFGInsertionSet.h&quot;
</span><span class="lines">@@ -226,6 +227,7 @@
</span><span class="cx">         performLivenessAnalysis(m_graph);
</span><span class="cx">         performOSRAvailabilityAnalysis(m_graph);
</span><span class="cx">         m_graph.initializeNodeOwners();
</span><ins>+        CombinedLiveness combinedLiveness(m_graph);
</ins><span class="cx">         
</span><span class="cx">         BlockMap&lt;Operands&lt;bool&gt;&gt; clobberedByBlock(m_graph);
</span><span class="cx">         for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
</span><span class="lines">@@ -264,7 +266,7 @@
</span><span class="cx">                 continue;
</span><span class="cx">             
</span><span class="cx">             forAllKillsInBlock(
</span><del>-                m_graph, block,
</del><ins>+                m_graph, combinedLiveness, block,
</ins><span class="cx">                 [&amp;] (unsigned nodeIndex, Node* candidate) {
</span><span class="cx">                     if (!m_candidates.contains(candidate))
</span><span class="cx">                         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCombinedLivenesscpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp (0 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.cpp        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -0,0 +1,81 @@
</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;DFGCombinedLiveness.h&quot;
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;DFGAvailabilityMap.h&quot;
+#include &quot;DFGBlockMapInlines.h&quot;
+#include &quot;FullBytecodeLiveness.h&quot;
+#include &quot;JSCInlines.h&quot;
+
+namespace JSC { namespace DFG {
+
+HashSet&lt;Node*&gt; liveNodesAtHead(Graph&amp; graph, BasicBlock* block)
+{
+    HashSet&lt;Node*&gt; seen;
+    for (Node* node : block-&gt;ssa-&gt;liveAtHead)
+        seen.add(node);
+    
+    AvailabilityMap&amp; availabilityMap = block-&gt;ssa-&gt;availabilityAtHead;
+    graph.forAllLocalsLiveInBytecode(
+        block-&gt;firstOrigin().forExit,
+        [&amp;] (VirtualRegister reg) {
+            availabilityMap.closeStartingWithLocal(
+                reg,
+                [&amp;] (Node* node) -&gt; bool {
+                    return seen.contains(node);
+                },
+                [&amp;] (Node* node) -&gt; bool {
+                    return seen.add(node).isNewEntry;
+                });
+        });
+    
+    return seen;
+}
+
+CombinedLiveness::CombinedLiveness(Graph&amp; graph)
+    : liveAtHead(graph)
+    , liveAtTail(graph)
+{
+    // First compute the liveAtHead for each block.
+    for (BasicBlock* block : graph.blocksInNaturalOrder())
+        liveAtHead[block] = liveNodesAtHead(graph, block);
+    
+    // Now compute the liveAtTail by unifying the liveAtHead of the successors.
+    for (BasicBlock* block : graph.blocksInNaturalOrder()) {
+        for (BasicBlock* successor : block-&gt;successors()) {
+            for (Node* node : liveAtHead[successor])
+                liveAtTail[block].add(node);
+        }
+    }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCombinedLivenessh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h (0 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGCombinedLiveness.h        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -0,0 +1,53 @@
</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 DFGCombinedLiveness_h
+#define DFGCombinedLiveness_h
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;DFGBlockMap.h&quot;
+#include &quot;DFGGraph.h&quot;
+
+namespace JSC { namespace DFG {
+
+// Returns the set of nodes live at tail, both due to due DFG and due to bytecode (i.e. OSR exit).
+HashSet&lt;Node*&gt; liveNodesAtHead(Graph&amp;, BasicBlock*);
+
+struct CombinedLiveness {
+    CombinedLiveness() { }
+    
+    CombinedLiveness(Graph&amp;);
+    
+    BlockMap&lt;HashSet&lt;Node*&gt;&gt; liveAtHead;
+    BlockMap&lt;HashSet&lt;Node*&gt;&gt; liveAtTail;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGCombinedLiveness_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGForAllKillsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -26,7 +26,7 @@
</span><span class="cx"> #ifndef DFGForAllKills_h
</span><span class="cx"> #define DFGForAllKills_h
</span><span class="cx"> 
</span><del>-#include &quot;BytecodeKills.h&quot;
</del><ins>+#include &quot;DFGCombinedLiveness.h&quot;
</ins><span class="cx"> #include &quot;DFGGraph.h&quot;
</span><span class="cx"> #include &quot;DFGOSRAvailabilityAnalysisPhase.h&quot;
</span><span class="cx"> #include &quot;FullBytecodeLiveness.h&quot;
</span><span class="lines">@@ -39,35 +39,6 @@
</span><span class="cx"> // node is killed. A prerequisite to using these utilities is having liveness and OSR availability
</span><span class="cx"> // computed.
</span><span class="cx"> 
</span><del>-template&lt;typename Functor&gt;
-void forAllLiveNodesAtTail(Graph&amp; graph, BasicBlock* block, const Functor&amp; functor)
-{
-    HashSet&lt;Node*&gt; seen;
-    for (Node* node : block-&gt;ssa-&gt;liveAtTail) {
-        if (seen.add(node).isNewEntry)
-            functor(node);
-    }
-    
-    DFG_ASSERT(graph, block-&gt;terminal(), block-&gt;terminal()-&gt;origin.forExit.isSet());
-    
-    AvailabilityMap&amp; availabilityMap = block-&gt;ssa-&gt;availabilityAtTail;
-    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;
-                });
-        });
-}
-
</del><span class="cx"> // This tells you those things that die on the boundary between nodeBefore and nodeAfter. It is
</span><span class="cx"> // conservative in the sense that it might resort to telling you some things that are still live at
</span><span class="cx"> // nodeAfter.
</span><span class="lines">@@ -192,13 +163,12 @@
</span><span class="cx"> // the value is either no longer live. This pretends that nodes are dead at the end of the block, so that
</span><span class="cx"> // you can use this to do per-basic-block analyses.
</span><span class="cx"> template&lt;typename Functor&gt;
</span><del>-void forAllKillsInBlock(Graph&amp; graph, BasicBlock* block, const Functor&amp; functor)
</del><ins>+void forAllKillsInBlock(
+    Graph&amp; graph, const CombinedLiveness&amp; combinedLiveness, BasicBlock* block,
+    const Functor&amp; functor)
</ins><span class="cx"> {
</span><del>-    forAllLiveNodesAtTail(
-        graph, block,
-        [&amp;] (Node* node) {
-            functor(block-&gt;size(), node);
-        });
</del><ins>+    for (Node* node : combinedLiveness.liveAtTail[block])
+        functor(block-&gt;size(), node);
</ins><span class="cx">     
</span><span class="cx">     LocalOSRAvailabilityCalculator localAvailability;
</span><span class="cx">     localAvailability.beginBlock(block);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -31,6 +31,7 @@
</span><span class="cx"> #include &quot;DFGAbstractHeap.h&quot;
</span><span class="cx"> #include &quot;DFGBlockMapInlines.h&quot;
</span><span class="cx"> #include &quot;DFGClobberize.h&quot;
</span><ins>+#include &quot;DFGCombinedLiveness.h&quot;
</ins><span class="cx"> #include &quot;DFGGraph.h&quot;
</span><span class="cx"> #include &quot;DFGInsertOSRHintsForUpdate.h&quot;
</span><span class="cx"> #include &quot;DFGInsertionSet.h&quot;
</span><span class="lines">@@ -107,6 +108,7 @@
</span><span class="cx">         m_graph.computeRefCounts();
</span><span class="cx">         performLivenessAnalysis(m_graph);
</span><span class="cx">         performOSRAvailabilityAnalysis(m_graph);
</span><ins>+        m_combinedLiveness = CombinedLiveness(m_graph);
</ins><span class="cx">         
</span><span class="cx">         CString graphBeforeSinking;
</span><span class="cx">         if (Options::verboseValidationFailure() &amp;&amp; Options::validateGraphAtEachPhase()) {
</span><span class="lines">@@ -189,7 +191,7 @@
</span><span class="cx">                 // So, we prune materialized-at-tail to only include things that are live.
</span><span class="cx">                 Vector&lt;Node*&gt; toRemove;
</span><span class="cx">                 for (auto pair : materialized) {
</span><del>-                    if (!block-&gt;ssa-&gt;liveAtTail.contains(pair.key))
</del><ins>+                    if (!m_combinedLiveness.liveAtTail[block].contains(pair.key))
</ins><span class="cx">                         toRemove.append(pair.key);
</span><span class="cx">                 }
</span><span class="cx">                 for (Node* key : toRemove)
</span><span class="lines">@@ -227,7 +229,7 @@
</span><span class="cx">                 if (pair.value)
</span><span class="cx">                     continue; // It was materialized.
</span><span class="cx">                 
</span><del>-                if (block-&gt;ssa-&gt;liveAtTail.contains(pair.key))
</del><ins>+                if (m_combinedLiveness.liveAtTail[block].contains(pair.key))
</ins><span class="cx">                     continue; // It might still get materialized in all of the successors.
</span><span class="cx">                 
</span><span class="cx">                 // We know that it died in this block and it wasn't materialized. That means that
</span><span class="lines">@@ -391,7 +393,7 @@
</span><span class="cx">         m_ssaCalculator.computePhis(
</span><span class="cx">             [&amp;] (SSACalculator::Variable* variable, BasicBlock* block) -&gt; Node* {
</span><span class="cx">                 Node* allocation = indexToNode[variable-&gt;index()];
</span><del>-                if (!block-&gt;ssa-&gt;liveAtHead.contains(allocation))
</del><ins>+                if (!m_combinedLiveness.liveAtHead[block].contains(allocation))
</ins><span class="cx">                     return nullptr;
</span><span class="cx">                 
</span><span class="cx">                 Node* phiNode = m_graph.addNode(allocation-&gt;prediction(), Phi, NodeOrigin());
</span><span class="lines">@@ -405,7 +407,7 @@
</span><span class="cx">         for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
</span><span class="cx">             HashMap&lt;Node*, Node*&gt; mapping;
</span><span class="cx">             
</span><del>-            for (Node* candidate : block-&gt;ssa-&gt;liveAtHead) {
</del><ins>+            for (Node* candidate : m_combinedLiveness.liveAtHead[block]) {
</ins><span class="cx">                 SSACalculator::Variable* variable = nodeToVariable.get(candidate);
</span><span class="cx">                 if (!variable)
</span><span class="cx">                     continue;
</span><span class="lines">@@ -714,7 +716,7 @@
</span><span class="cx">         m_ssaCalculator.computePhis(
</span><span class="cx">             [&amp;] (SSACalculator::Variable* variable, BasicBlock* block) -&gt; Node* {
</span><span class="cx">                 PromotedHeapLocation location = m_indexToLocation[variable-&gt;index()];
</span><del>-                if (!block-&gt;ssa-&gt;liveAtHead.contains(location.base()))
</del><ins>+                if (!m_combinedLiveness.liveAtHead[block].contains(location.base()))
</ins><span class="cx">                     return nullptr;
</span><span class="cx">                 
</span><span class="cx">                 Node* phiNode = m_graph.addNode(SpecHeapTop, Phi, NodeOrigin());
</span><span class="lines">@@ -1085,6 +1087,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    CombinedLiveness m_combinedLiveness;
</ins><span class="cx">     SSACalculator m_ssaCalculator;
</span><span class="cx">     HashSet&lt;Node*&gt; m_sinkCandidates;
</span><span class="cx">     HashMap&lt;Node*, Node*&gt; m_materializationToEscapee;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressescapeobjectindiamondthenexitjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/escape-object-in-diamond-then-exit.js (0 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/escape-object-in-diamond-then-exit.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/escape-object-in-diamond-then-exit.js        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+var global = null;
+
+function foo(p, q) {
+    var o = {f:42};
+    if (p)
+        global = o;
+    var tmp = q + 1;
+    return o.f + tmp;
+}
+
+noInline(foo);
+
+var lastObject = null;
+
+function validateEscape(when) {
+    if (global === lastObject)
+        throw &quot;Error: bad value in global &quot; + when + &quot;, identical to lastObject.&quot;;
+    if (global === null || !(typeof global == &quot;object&quot;))
+        throw &quot;Error: bad value in global &quot; + when + &quot;: it's not an object.&quot;;
+    if (global.f != 42)
+        throw &quot;Error: bad value in global &quot; + when + &quot;: f isn't 42, it's: &quot; + global.f;
+    lastObject = global;
+    global = null;
+}
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var escape = !!(i &amp; 1);
+    var result = foo(escape, 42);
+    if (result != 42 + 42 + 1)
+        throw &quot;Error: bad result: &quot; + result;
+    if (escape)
+        validateEscape(&quot;in loop&quot;);
+    else if (global !== null)
+        throw &quot;Error: bad value in global: &quot; + global;
+}
+
+var result = foo(true, 2147483647);
+if (result != 42 + 2147483647 + 1)
+    throw &quot;Error: bad result at end: &quot; + result;
+validateEscape(&quot;at end&quot;);
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstresssinkobjectpastinvalidchecksneakyjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tests/stress/sink-object-past-invalid-check-sneaky.js (184310 => 184311)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/sink-object-past-invalid-check-sneaky.js        2015-05-13 22:07:09 UTC (rev 184310)
+++ trunk/Source/JavaScriptCore/tests/stress/sink-object-past-invalid-check-sneaky.js        2015-05-13 22:14:25 UTC (rev 184311)
</span><span class="lines">@@ -1,6 +1,3 @@
</span><del>-// https://bugs.webkit.org/show_bug.cgi?id=144945
-//@ skip
-
</del><span class="cx"> function foo(p) {
</span><span class="cx">     var result = 0;
</span><span class="cx">     var o = {valueOf: function() { result = 1; }};
</span></span></pre>
</div>
</div>

</body>
</html>