<!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>[215071] trunk/Source</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/215071">215071</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2017-04-06 17:11:16 -0700 (Thu, 06 Apr 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Linear scan should run liveness only once
https://bugs.webkit.org/show_bug.cgi?id=170569

Reviewed by Keith Miller.
        
Source/JavaScriptCore:

Air has a longstanding design bug that Tmps from different banks are indexed independently. This
means that all of our analyses over Tmps do separate GP and FP passes. This does have some
marginal benefits (the rest of the algorithm is specialized for Bank) but it's probably net bad.
However, I don't want to think about solving that general problem.
        
Instead, this just makes linear scan use a UnifiedTmpLiveness that uses a single &quot;linear&quot;
indexing for GP and FP. This lets me avoid the much larger refactoring (which would involve
substantial changes in graph coloring) while getting the bulk of the benefit (liveness runs once,
instead of twice, for linear scan).
        
This patch implements a lot of plumbing to make it possible for Liveness&lt;&gt; to view Tmps as having
a unified indexing scheme. Tmp calls this LinearlyIndexed (to match the naming convention of
AbsolutelyIndexed and Indexed), while AirLiveness calls this UnifiedTmpLiveness. With this
change, -O1 never does any liveness analysis that uses separate GP and FP passes. I think this
eliminates any urgency from the larger Tmp indexing bug. We can probably live with graph coloring
doing separate passes.
        
This is a ~6% speed-up for wasm -O1 compile times. I think this means that linear scan is no
longer the longest pole in the tent.

* JavaScriptCore.xcodeproj/project.pbxproj:
* b3/B3VariableLiveness.h:
(JSC::B3::VariableLivenessAdapter::prepareToCompute):
* b3/air/AirAllocateRegistersByLinearScan.cpp:
(JSC::B3::Air::allocateRegistersByLinearScan):
* b3/air/AirCode.h:
(JSC::B3::Air::Code::forEachTmp):
* b3/air/AirLiveness.h:
* b3/air/AirLivenessAdapter.h:
(JSC::B3::Air::LivenessAdapter::Actions::Actions):
(JSC::B3::Air::LivenessAdapter::LivenessAdapter):
(JSC::B3::Air::LivenessAdapter::adapter):
(JSC::B3::Air::LivenessAdapter::prepareToCompute):
(JSC::B3::Air::LivenessAdapter::actionsAt):
(JSC::B3::Air::LivenessAdapter::forEachUse):
(JSC::B3::Air::LivenessAdapter::forEachDef):
(JSC::B3::Air::TmpLivenessAdapter::numIndices):
(JSC::B3::Air::UnifiedTmpLivenessAdapter::UnifiedTmpLivenessAdapter):
(JSC::B3::Air::UnifiedTmpLivenessAdapter::numIndices):
(JSC::B3::Air::UnifiedTmpLivenessAdapter::acceptsBank):
(JSC::B3::Air::UnifiedTmpLivenessAdapter::acceptsRole):
(JSC::B3::Air::UnifiedTmpLivenessAdapter::valueToIndex):
(JSC::B3::Air::UnifiedTmpLivenessAdapter::indexToValue):
* b3/air/AirLivenessConstraints.h: Removed.
* b3/air/AirRegLiveness.h:
(JSC::B3::Air::RegLiveness::LocalCalc::LocalCalc):
* b3/air/AirTmp.cpp:
* b3/air/AirTmp.h:
* b3/air/AirTmpInlines.h:
(JSC::B3::Air::Tmp::LinearlyIndexed::LinearlyIndexed):
(JSC::B3::Air::Tmp::LinearlyIndexed::index):
(JSC::B3::Air::Tmp::linearlyIndexed):
(JSC::B3::Air::Tmp::indexEnd):
(JSC::B3::Air::Tmp::absoluteIndexEnd):
(JSC::B3::Air::Tmp::linearIndexEnd):
(JSC::B3::Air::Tmp::tmpForAbsoluteIndex):
(JSC::B3::Air::Tmp::tmpForLinearIndex):
* b3/air/AirTmpMap.h: Added.
(JSC::B3::Air::TmpMap::TmpMap):
(JSC::B3::Air::TmpMap::resize):
(JSC::B3::Air::TmpMap::clear):
(JSC::B3::Air::TmpMap::operator[]):
(JSC::B3::Air::TmpMap::append):

Source/WTF:

Have Liveness&lt;&gt; call Adapter::prepareToCompute(), since this makes it a lot easier to implement
constraint generation, since the constraint generator now gets to run after the Adapter is fully
constructed.
        
* wtf/IndexMap.h:
(WTF::IndexMap::append): Also make this a bit more versatile.
* wtf/Liveness.h:
(WTF::Liveness::LocalCalc::Iterable::contains):
(WTF::Liveness::Iterable::contains):
(WTF::Liveness::compute):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3B3VariableLivenessh">trunk/Source/JavaScriptCore/b3/B3VariableLiveness.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirAllocateRegistersByLinearScancpp">trunk/Source/JavaScriptCore/b3/air/AirAllocateRegistersByLinearScan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirCodeh">trunk/Source/JavaScriptCore/b3/air/AirCode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirLivenessh">trunk/Source/JavaScriptCore/b3/air/AirLiveness.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirLivenessAdapterh">trunk/Source/JavaScriptCore/b3/air/AirLivenessAdapter.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirRegLivenessh">trunk/Source/JavaScriptCore/b3/air/AirRegLiveness.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirTmpcpp">trunk/Source/JavaScriptCore/b3/air/AirTmp.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirTmph">trunk/Source/JavaScriptCore/b3/air/AirTmp.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreb3airAirTmpInlinesh">trunk/Source/JavaScriptCore/b3/air/AirTmpInlines.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfIndexMaph">trunk/Source/WTF/wtf/IndexMap.h</a></li>
<li><a href="#trunkSourceWTFwtfLivenessh">trunk/Source/WTF/wtf/Liveness.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3airAirTmpMaph">trunk/Source/JavaScriptCore/b3/air/AirTmpMap.h</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreb3airAirLivenessConstraintsh">trunk/Source/JavaScriptCore/b3/air/AirLivenessConstraints.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -1,3 +1,74 @@
</span><ins>+2017-04-06  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Linear scan should run liveness only once
+        https://bugs.webkit.org/show_bug.cgi?id=170569
+
+        Reviewed by Keith Miller.
+        
+        Air has a longstanding design bug that Tmps from different banks are indexed independently. This
+        means that all of our analyses over Tmps do separate GP and FP passes. This does have some
+        marginal benefits (the rest of the algorithm is specialized for Bank) but it's probably net bad.
+        However, I don't want to think about solving that general problem.
+        
+        Instead, this just makes linear scan use a UnifiedTmpLiveness that uses a single &quot;linear&quot;
+        indexing for GP and FP. This lets me avoid the much larger refactoring (which would involve
+        substantial changes in graph coloring) while getting the bulk of the benefit (liveness runs once,
+        instead of twice, for linear scan).
+        
+        This patch implements a lot of plumbing to make it possible for Liveness&lt;&gt; to view Tmps as having
+        a unified indexing scheme. Tmp calls this LinearlyIndexed (to match the naming convention of
+        AbsolutelyIndexed and Indexed), while AirLiveness calls this UnifiedTmpLiveness. With this
+        change, -O1 never does any liveness analysis that uses separate GP and FP passes. I think this
+        eliminates any urgency from the larger Tmp indexing bug. We can probably live with graph coloring
+        doing separate passes.
+        
+        This is a ~6% speed-up for wasm -O1 compile times. I think this means that linear scan is no
+        longer the longest pole in the tent.
+
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * b3/B3VariableLiveness.h:
+        (JSC::B3::VariableLivenessAdapter::prepareToCompute):
+        * b3/air/AirAllocateRegistersByLinearScan.cpp:
+        (JSC::B3::Air::allocateRegistersByLinearScan):
+        * b3/air/AirCode.h:
+        (JSC::B3::Air::Code::forEachTmp):
+        * b3/air/AirLiveness.h:
+        * b3/air/AirLivenessAdapter.h:
+        (JSC::B3::Air::LivenessAdapter::Actions::Actions):
+        (JSC::B3::Air::LivenessAdapter::LivenessAdapter):
+        (JSC::B3::Air::LivenessAdapter::adapter):
+        (JSC::B3::Air::LivenessAdapter::prepareToCompute):
+        (JSC::B3::Air::LivenessAdapter::actionsAt):
+        (JSC::B3::Air::LivenessAdapter::forEachUse):
+        (JSC::B3::Air::LivenessAdapter::forEachDef):
+        (JSC::B3::Air::TmpLivenessAdapter::numIndices):
+        (JSC::B3::Air::UnifiedTmpLivenessAdapter::UnifiedTmpLivenessAdapter):
+        (JSC::B3::Air::UnifiedTmpLivenessAdapter::numIndices):
+        (JSC::B3::Air::UnifiedTmpLivenessAdapter::acceptsBank):
+        (JSC::B3::Air::UnifiedTmpLivenessAdapter::acceptsRole):
+        (JSC::B3::Air::UnifiedTmpLivenessAdapter::valueToIndex):
+        (JSC::B3::Air::UnifiedTmpLivenessAdapter::indexToValue):
+        * b3/air/AirLivenessConstraints.h: Removed.
+        * b3/air/AirRegLiveness.h:
+        (JSC::B3::Air::RegLiveness::LocalCalc::LocalCalc):
+        * b3/air/AirTmp.cpp:
+        * b3/air/AirTmp.h:
+        * b3/air/AirTmpInlines.h:
+        (JSC::B3::Air::Tmp::LinearlyIndexed::LinearlyIndexed):
+        (JSC::B3::Air::Tmp::LinearlyIndexed::index):
+        (JSC::B3::Air::Tmp::linearlyIndexed):
+        (JSC::B3::Air::Tmp::indexEnd):
+        (JSC::B3::Air::Tmp::absoluteIndexEnd):
+        (JSC::B3::Air::Tmp::linearIndexEnd):
+        (JSC::B3::Air::Tmp::tmpForAbsoluteIndex):
+        (JSC::B3::Air::Tmp::tmpForLinearIndex):
+        * b3/air/AirTmpMap.h: Added.
+        (JSC::B3::Air::TmpMap::TmpMap):
+        (JSC::B3::Air::TmpMap::resize):
+        (JSC::B3::Air::TmpMap::clear):
+        (JSC::B3::Air::TmpMap::operator[]):
+        (JSC::B3::Air::TmpMap::append):
+
</ins><span class="cx"> 2017-04-06  Ryan Haddad  &lt;ryanhaddad@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed, rolling out r215046.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -119,7 +119,6 @@
</span><span class="cx">                 0F15F15F14B7A73E005DE37D /* CommonSlowPaths.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F1725FF1B48719A00AC3A55 /* DFGMinifiedGraph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1725FE1B48719A00AC3A55 /* DFGMinifiedGraph.cpp */; };
</span><span class="cx">                 0F1829691E92EE54005B1EA8 /* AirLivenessAdapter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1829681E92EE51005B1EA8 /* AirLivenessAdapter.h */; };
</span><del>-                0F18296B1E92F6DC005B1EA8 /* AirLivenessConstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F18296A1E92F6DA005B1EA8 /* AirLivenessConstraints.h */; };
</del><span class="cx">                 0F18D3CF1B55A6E0002C5C9F /* DFGAdaptiveStructureWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F18D3CD1B55A6E0002C5C9F /* DFGAdaptiveStructureWatchpoint.cpp */; };
</span><span class="cx">                 0F18D3D01B55A6E0002C5C9F /* DFGAdaptiveStructureWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F18D3CE1B55A6E0002C5C9F /* DFGAdaptiveStructureWatchpoint.h */; };
</span><span class="cx">                 0F190CAC189D82F6000AE5F0 /* ProfilerJettisonReason.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F190CAA189D82F6000AE5F0 /* ProfilerJettisonReason.cpp */; };
</span><span class="lines">@@ -455,6 +454,7 @@
</span><span class="cx">                 0F5A6284188C98D40072C9DF /* FTLValueRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5A6282188C98D40072C9DF /* FTLValueRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F5AE2C41DF4F2800066EFE1 /* VMInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = FE90BB3A1B7CF64E006B3F03 /* VMInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F5B4A331C84F0D600F1B17E /* SlowPathReturnType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5B4A321C84F0D600F1B17E /* SlowPathReturnType.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F5CF9811E96F17F00C18692 /* AirTmpMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5CF9801E96F17D00C18692 /* AirTmpMap.h */; };
</ins><span class="cx">                 0F5D085D1B8CF99D001143B4 /* DFGNodeOrigin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5D085C1B8CF99D001143B4 /* DFGNodeOrigin.cpp */; };
</span><span class="cx">                 0F5EF91E16878F7A003E5C25 /* JITThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F5EF91B16878F78003E5C25 /* JITThunks.cpp */; };
</span><span class="cx">                 0F5EF91F16878F7D003E5C25 /* JITThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5EF91C16878F78003E5C25 /* JITThunks.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="lines">@@ -2659,7 +2659,6 @@
</span><span class="cx">                 0F15F15D14B7A73A005DE37D /* CommonSlowPaths.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonSlowPaths.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F1725FE1B48719A00AC3A55 /* DFGMinifiedGraph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGMinifiedGraph.cpp; path = dfg/DFGMinifiedGraph.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F1829681E92EE51005B1EA8 /* AirLivenessAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirLivenessAdapter.h; path = b3/air/AirLivenessAdapter.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                0F18296A1E92F6DA005B1EA8 /* AirLivenessConstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirLivenessConstraints.h; path = b3/air/AirLivenessConstraints.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><span class="cx">                 0F18D3CD1B55A6E0002C5C9F /* DFGAdaptiveStructureWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGAdaptiveStructureWatchpoint.cpp; path = dfg/DFGAdaptiveStructureWatchpoint.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F18D3CE1B55A6E0002C5C9F /* DFGAdaptiveStructureWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdaptiveStructureWatchpoint.h; path = dfg/DFGAdaptiveStructureWatchpoint.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F190CAA189D82F6000AE5F0 /* ProfilerJettisonReason.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerJettisonReason.cpp; path = profiler/ProfilerJettisonReason.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -2991,6 +2990,7 @@
</span><span class="cx">                 0F5A6281188C98D40072C9DF /* FTLValueRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FTLValueRange.cpp; path = ftl/FTLValueRange.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F5A6282188C98D40072C9DF /* FTLValueRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FTLValueRange.h; path = ftl/FTLValueRange.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F5B4A321C84F0D600F1B17E /* SlowPathReturnType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlowPathReturnType.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F5CF9801E96F17D00C18692 /* AirTmpMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AirTmpMap.h; path = b3/air/AirTmpMap.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F5D085C1B8CF99D001143B4 /* DFGNodeOrigin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGNodeOrigin.cpp; path = dfg/DFGNodeOrigin.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F5EF91B16878F78003E5C25 /* JITThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITThunks.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F5EF91C16878F78003E5C25 /* JITThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITThunks.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5623,7 +5623,6 @@
</span><span class="cx">                                 0FDF67D51D9DC43E001B9825 /* AirKind.h */,
</span><span class="cx">                                 2684D4371C00161C0081D663 /* AirLiveness.h */,
</span><span class="cx">                                 0F1829681E92EE51005B1EA8 /* AirLivenessAdapter.h */,
</span><del>-                                0F18296A1E92F6DA005B1EA8 /* AirLivenessConstraints.h */,
</del><span class="cx">                                 0FE34C171C4B39AE0003A512 /* AirLogRegisterPressure.cpp */,
</span><span class="cx">                                 0FE34C181C4B39AE0003A512 /* AirLogRegisterPressure.h */,
</span><span class="cx">                                 0F6183251C45BF070072450B /* AirLowerAfterRegAlloc.cpp */,
</span><span class="lines">@@ -5658,6 +5657,7 @@
</span><span class="cx">                                 0FEC85681BDACDC70080FF74 /* AirTmp.cpp */,
</span><span class="cx">                                 0FEC85691BDACDC70080FF74 /* AirTmp.h */,
</span><span class="cx">                                 0FEC856A1BDACDC70080FF74 /* AirTmpInlines.h */,
</span><ins>+                                0F5CF9801E96F17D00C18692 /* AirTmpMap.h */,
</ins><span class="cx">                                 0F9C03D41E9476F000CD9125 /* AirTmpSet.h */,
</span><span class="cx">                                 0FE0E4AB1C24C94A002E17B6 /* AirTmpWidth.cpp */,
</span><span class="cx">                                 0FE0E4AC1C24C94A002E17B6 /* AirTmpWidth.h */,
</span><span class="lines">@@ -8985,7 +8985,6 @@
</span><span class="cx">                                 2A4BB7F318A41179008A0FCD /* JSManagedValueInternal.h in Headers */,
</span><span class="cx">                                 A700874217CBE8EB00C3E643 /* JSMap.h in Headers */,
</span><span class="cx">                                 A74DEF96182D991400522C22 /* JSMapIterator.h in Headers */,
</span><del>-                                0F18296B1E92F6DC005B1EA8 /* AirLivenessConstraints.h in Headers */,
</del><span class="cx">                                 9959E92D1BD17FA4001AA413 /* jsmin.py in Headers */,
</span><span class="cx">                                 E3D239C91B829C1C00BBEF67 /* JSModuleEnvironment.h in Headers */,
</span><span class="cx">                                 D9722752DC54459B9125B539 /* JSModuleLoader.h in Headers */,
</span><span class="lines">@@ -9186,6 +9185,7 @@
</span><span class="cx">                                 0FBB73B81DEF3AAE002C009E /* PreventCollectionScope.h in Headers */,
</span><span class="cx">                                 868916B0155F286300CB2B9A /* PrivateName.h in Headers */,
</span><span class="cx">                                 0FF729A5166AD351000F5BA3 /* ProfilerBytecode.h in Headers */,
</span><ins>+                                0F5CF9811E96F17F00C18692 /* AirTmpMap.h in Headers */,
</ins><span class="cx">                                 0FF729B9166AD360000F5BA3 /* ProfilerBytecodes.h in Headers */,
</span><span class="cx">                                 0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */,
</span><span class="cx">                                 0FF729BA166AD360000F5BA3 /* ProfilerCompilation.h in Headers */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3B3VariableLivenessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/B3VariableLiveness.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/B3VariableLiveness.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/B3VariableLiveness.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -47,6 +47,10 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void prepareToCompute()
+    {
+    }
+    
</ins><span class="cx">     unsigned numIndices()
</span><span class="cx">     {
</span><span class="cx">         return proc.variables().size();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirAllocateRegistersByLinearScancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirAllocateRegistersByLinearScan.cpp (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirAllocateRegistersByLinearScan.cpp        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirAllocateRegistersByLinearScan.cpp        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> #include &quot;AirPhaseScope.h&quot;
</span><span class="cx"> #include &quot;AirRegLiveness.h&quot;
</span><span class="cx"> #include &quot;AirTmpInlines.h&quot;
</span><ins>+#include &quot;AirTmpMap.h&quot;
</ins><span class="cx"> #include &lt;wtf/ListDump.h&gt;
</span><span class="cx"> #include &lt;wtf/Range.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -105,13 +106,12 @@
</span><span class="cx">     RegisterSet regs;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-template&lt;Bank bank&gt;
</del><span class="cx"> class LinearScan {
</span><span class="cx"> public:
</span><span class="cx">     LinearScan(Code&amp; code)
</span><span class="cx">         : m_code(code)
</span><span class="cx">         , m_startIndex(code.size())
</span><del>-        , m_map(code.numTmps(bank))
</del><ins>+        , m_map(code)
</ins><span class="cx">         , m_insertionSets(code.size())
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="lines">@@ -127,7 +127,11 @@
</span><span class="cx">         }
</span><span class="cx">         for (;;) {
</span><span class="cx">             prepareIntervals();
</span><del>-            attemptScan();
</del><ins>+            m_didSpill = false;
+            forEachBank(
+                [&amp;] (Bank bank) {
+                    attemptScan(bank);
+                });
</ins><span class="cx">             if (!m_didSpill)
</span><span class="cx">                 break;
</span><span class="cx">             emitSpillCode();
</span><span class="lines">@@ -139,8 +143,12 @@
</span><span class="cx"> private:
</span><span class="cx">     void buildRegisterSet()
</span><span class="cx">     {
</span><del>-        m_registers = m_code.regsInPriorityOrder(bank);
-        m_registerSet.setAll(m_registers);
</del><ins>+        forEachBank(
+            [&amp;] (Bank bank) {
+                m_registers[bank] = m_code.regsInPriorityOrder(bank);
+                m_registerSet[bank].setAll(m_registers[bank]);
+                m_unifiedRegisterSet.merge(m_registerSet[bank]);
+            });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void buildIndices()
</span><span class="lines">@@ -178,7 +186,7 @@
</span><span class="cx">     
</span><span class="cx">     void buildIntervals()
</span><span class="cx">     {
</span><del>-        TmpLiveness&lt;bank&gt; liveness(m_code);
</del><ins>+        UnifiedTmpLiveness liveness(m_code);
</ins><span class="cx">         
</span><span class="cx">         for (BasicBlock* block : m_code) {
</span><span class="cx">             size_t indexOfHead = this-&gt;indexOfHead(block);
</span><span class="lines">@@ -201,11 +209,9 @@
</span><span class="cx">                 Inst&amp; inst = block-&gt;at(instIndex);
</span><span class="cx">                 size_t indexOfEarly = indexOfHead + instIndex * 2;
</span><span class="cx">                 inst.forEachTmp(
</span><del>-                    [&amp;] (Tmp&amp; tmp, Arg::Role role, Bank tmpBank, Width) {
</del><ins>+                    [&amp;] (Tmp&amp; tmp, Arg::Role role, Bank, Width) {
</ins><span class="cx">                         if (tmp.isReg())
</span><span class="cx">                             return;
</span><del>-                        if (tmpBank != bank)
-                            return;
</del><span class="cx">                         m_map[tmp].interval |= interval(indexOfEarly, Arg::timing(role));
</span><span class="cx">                     });
</span><span class="cx">             }
</span><span class="lines">@@ -223,7 +229,7 @@
</span><span class="cx">                         });
</span><span class="cx">                     if (prev-&gt;kind.opcode == Patch)
</span><span class="cx">                         prevRegs.merge(prev-&gt;extraClobberedRegs());
</span><del>-                    prevRegs.filter(m_registerSet);
</del><ins>+                    prevRegs.filter(m_unifiedRegisterSet);
</ins><span class="cx">                     if (!prevRegs.isEmpty())
</span><span class="cx">                         m_clobbers.append(Clobber(indexOfHead + instIndex * 2 - 1, prevRegs));
</span><span class="cx">                 }
</span><span class="lines">@@ -256,10 +262,10 @@
</span><span class="cx">         
</span><span class="cx">         if (verbose()) {
</span><span class="cx">             dataLog(&quot;Intervals:\n&quot;);
</span><del>-            for (unsigned tmpIndex = 0; tmpIndex &lt; m_code.numTmps(bank); ++tmpIndex) {
-                Tmp tmp = Tmp::tmpForIndex(bank, tmpIndex);
-                dataLog(&quot;    &quot;, tmp, &quot;: &quot;, m_map[tmp], &quot;\n&quot;);
-            }
</del><ins>+            m_code.forEachTmp(
+                [&amp;] (Tmp tmp) {
+                    dataLog(&quot;    &quot;, tmp, &quot;: &quot;, m_map[tmp], &quot;\n&quot;);
+                });
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -276,8 +282,10 @@
</span><span class="cx">     
</span><span class="cx">     void spillEverything()
</span><span class="cx">     {
</span><del>-        for (unsigned tmpIndex = 0; tmpIndex &lt; m_code.numTmps(bank); ++tmpIndex)
-            spill(Tmp::tmpForIndex(bank, tmpIndex));
</del><ins>+        m_code.forEachTmp(
+            [&amp;] (Tmp tmp) {
+                spill(tmp);
+            });
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void prepareIntervals()
</span><span class="lines">@@ -284,15 +292,15 @@
</span><span class="cx">     {
</span><span class="cx">         m_tmps.resize(0);
</span><span class="cx">         
</span><del>-        for (unsigned tmpIndex = 0; tmpIndex &lt; m_code.numTmps(bank); ++tmpIndex) {
-            Tmp tmp = Tmp::tmpForIndex(bank, tmpIndex);
-            TmpData&amp; data = m_map[tmp];
-            if (data.spilled)
-                continue;
-            
-            data.assigned = Reg();
-            m_tmps.append(tmp);
-        }
</del><ins>+        m_code.forEachTmp(
+            [&amp;] (Tmp tmp) {
+                TmpData&amp; data = m_map[tmp];
+                if (data.spilled)
+                    return;
+                
+                data.assigned = Reg();
+                m_tmps.append(tmp);
+            });
</ins><span class="cx">         
</span><span class="cx">         std::sort(
</span><span class="cx">             m_tmps.begin(), m_tmps.end(),
</span><span class="lines">@@ -306,7 +314,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    Tmp addSpillTmpWithInterval(Interval interval)
</del><ins>+    Tmp addSpillTmpWithInterval(Bank bank, Interval interval)
</ins><span class="cx">     {
</span><span class="cx">         TmpData data;
</span><span class="cx">         data.interval = interval;
</span><span class="lines">@@ -317,17 +325,19 @@
</span><span class="cx">         return tmp;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void attemptScan()
</del><ins>+    void attemptScan(Bank bank)
</ins><span class="cx">     {
</span><span class="cx">         // This is modeled after LinearScanRegisterAllocation in Fig. 1 in
</span><span class="cx">         // http://dl.acm.org/citation.cfm?id=330250.
</span><span class="cx"> 
</span><del>-        m_didSpill = false;
</del><span class="cx">         m_active.clear();
</span><span class="cx">         m_activeRegs = RegisterSet();
</span><span class="cx">         
</span><span class="cx">         size_t clobberIndex = 0;
</span><span class="cx">         for (Tmp&amp; tmp : m_tmps) {
</span><ins>+            if (tmp.bank() != bank)
+                continue;
+            
</ins><span class="cx">             TmpData&amp; entry = m_map[tmp];
</span><span class="cx">             size_t index = entry.interval.begin();
</span><span class="cx">             
</span><span class="lines">@@ -381,7 +391,7 @@
</span><span class="cx">                 while (clobberIndex &lt; m_clobbers.size() &amp;&amp; m_clobbers[clobberIndex].index &lt; index)
</span><span class="cx">                     clobberIndex++;
</span><span class="cx">                 
</span><del>-                RegisterSet possibleRegs = m_registerSet;
</del><ins>+                RegisterSet possibleRegs = m_registerSet[bank];
</ins><span class="cx">                 for (size_t i = clobberIndex; i &lt; m_clobbers.size() &amp;&amp; m_clobbers[i].index &lt; entry.interval.end(); ++i)
</span><span class="cx">                     possibleRegs.exclude(m_clobbers[i].regs);
</span><span class="cx">                 
</span><span class="lines">@@ -393,9 +403,9 @@
</span><span class="cx">                 dataLog(&quot;  Possible regs: &quot;, entry.possibleRegs, &quot;\n&quot;);
</span><span class="cx">             
</span><span class="cx">             // Find a free register that we are allowed to use.
</span><del>-            if (m_active.size() != m_registers.size()) {
</del><ins>+            if (m_active.size() != m_registers[bank].size()) {
</ins><span class="cx">                 bool didAssign = false;
</span><del>-                for (Reg reg : m_registers) {
</del><ins>+                for (Reg reg : m_registers[bank]) {
</ins><span class="cx">                     // FIXME: Could do priority coloring here.
</span><span class="cx">                     // https://bugs.webkit.org/show_bug.cgi?id=170304
</span><span class="cx">                     if (!m_activeRegs.contains(reg) &amp;&amp; entry.possibleRegs.contains(reg)) {
</span><span class="lines">@@ -481,8 +491,6 @@
</span><span class="cx">                         continue;
</span><span class="cx">                     if (arg.isReg())
</span><span class="cx">                         continue;
</span><del>-                    if (arg.bank() != bank)
-                        continue;
</del><span class="cx">                     StackSlot* spilled = m_map[arg.tmp()].spilled;
</span><span class="cx">                     if (!spilled)
</span><span class="cx">                         continue;
</span><span class="lines">@@ -493,16 +501,14 @@
</span><span class="cx">                 
</span><span class="cx">                 // Fall back on the hard way.
</span><span class="cx">                 inst.forEachTmp(
</span><del>-                    [&amp;] (Tmp&amp; tmp, Arg::Role role, Bank tmpBank, Width) {
</del><ins>+                    [&amp;] (Tmp&amp; tmp, Arg::Role role, Bank bank, Width) {
</ins><span class="cx">                         if (tmp.isReg())
</span><span class="cx">                             return;
</span><del>-                        if (tmpBank != bank)
-                            return;
</del><span class="cx">                         StackSlot* spilled = m_map[tmp].spilled;
</span><span class="cx">                         if (!spilled)
</span><span class="cx">                             return;
</span><span class="cx">                         Opcode move = bank == GP ? Move : MoveDouble;
</span><del>-                        tmp = addSpillTmpWithInterval(interval(indexOfEarly, Arg::timing(role)));
</del><ins>+                        tmp = addSpillTmpWithInterval(bank, interval(indexOfEarly, Arg::timing(role)));
</ins><span class="cx">                         if (role == Arg::Scratch)
</span><span class="cx">                             return;
</span><span class="cx">                         if (Arg::isAnyUse(role))
</span><span class="lines">@@ -524,10 +530,10 @@
</span><span class="cx">     {
</span><span class="cx">         if (verbose()) {
</span><span class="cx">             dataLog(&quot;About to allocate registers. State of all tmps:\n&quot;);
</span><del>-            for (unsigned tmpIndex = 0; tmpIndex &lt; m_code.numTmps(bank); ++tmpIndex) {
-                Tmp tmp = Tmp::tmpForIndex(bank, tmpIndex);
-                dataLog(&quot;    &quot;, tmp, &quot;: &quot;, m_map[tmp], &quot;\n&quot;);
-            }
</del><ins>+            m_code.forEachTmp(
+                [&amp;] (Tmp tmp) {
+                    dataLog(&quot;    &quot;, tmp, &quot;: &quot;, m_map[tmp], &quot;\n&quot;);
+                });
</ins><span class="cx">             dataLog(&quot;IR:\n&quot;);
</span><span class="cx">             dataLog(m_code);
</span><span class="cx">         }
</span><span class="lines">@@ -540,8 +546,6 @@
</span><span class="cx">                     [&amp;] (Tmp&amp; tmp) {
</span><span class="cx">                         if (tmp.isReg())
</span><span class="cx">                             return;
</span><del>-                        if (tmp.bank() != bank)
-                            return;
</del><span class="cx">                         
</span><span class="cx">                         Reg reg = m_map[tmp].assigned;
</span><span class="cx">                         if (!reg) {
</span><span class="lines">@@ -555,10 +559,11 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     Code&amp; m_code;
</span><del>-    Vector&lt;Reg&gt; m_registers;
-    RegisterSet m_registerSet;
</del><ins>+    Vector&lt;Reg&gt; m_registers[numBanks];
+    RegisterSet m_registerSet[numBanks];
+    RegisterSet m_unifiedRegisterSet;
</ins><span class="cx">     IndexMap&lt;BasicBlock*, size_t&gt; m_startIndex;
</span><del>-    IndexMap&lt;Tmp::Indexed&lt;bank&gt;, TmpData&gt; m_map;
</del><ins>+    TmpMap&lt;TmpData&gt; m_map;
</ins><span class="cx">     IndexMap&lt;BasicBlock*, PhaseInsertionSet&gt; m_insertionSets;
</span><span class="cx">     Vector&lt;Clobber&gt; m_clobbers; // After we allocate this, we happily point pointers into it.
</span><span class="cx">     Vector&lt;Tmp&gt; m_tmps;
</span><span class="lines">@@ -567,15 +572,14 @@
</span><span class="cx">     bool m_didSpill { false };
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-template&lt;Bank bank&gt;
</del><span class="cx"> void runLinearScan(Code&amp; code)
</span><span class="cx"> {
</span><span class="cx">     if (verbose())
</span><del>-        dataLog(&quot;Air before linear scan for &quot;, bank, &quot;:\n&quot;, code);
-    LinearScan&lt;bank&gt; linearScan(code);
</del><ins>+        dataLog(&quot;Air before linear scan:\n&quot;, code);
+    LinearScan linearScan(code);
</ins><span class="cx">     linearScan.run();
</span><span class="cx">     if (verbose())
</span><del>-        dataLog(&quot;Air after linear scan for &quot;, bank, &quot;:\n&quot;, code);
</del><ins>+        dataLog(&quot;Air after linear scan:\n&quot;, code);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // anonymous namespace
</span><span class="lines">@@ -584,8 +588,7 @@
</span><span class="cx"> {
</span><span class="cx">     PhaseScope phaseScope(code, &quot;allocateRegistersByLinearScan&quot;);
</span><span class="cx">     padInterference(code);
</span><del>-    runLinearScan&lt;FP&gt;(code);
-    runLinearScan&lt;GP&gt;(code);
</del><ins>+    runLinearScan(code);
</ins><span class="cx">     fixSpillsAfterTerminals(code);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirCodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirCode.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirCode.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirCode.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -130,6 +130,17 @@
</span><span class="cx">         }
</span><span class="cx">         ASSERT_NOT_REACHED();
</span><span class="cx">     }
</span><ins>+    
+    template&lt;typename Func&gt;
+    void forEachTmp(const Func&amp; func)
+    {
+        for (unsigned bankIndex = 0; bankIndex &lt; numBanks; ++bankIndex) {
+            Bank bank = static_cast&lt;Bank&gt;(bankIndex);
+            unsigned numTmps = this-&gt;numTmps(bank);
+            for (unsigned i = 0; i &lt; numTmps; ++i)
+                func(Tmp::tmpForIndex(bank, i));
+        }
+    }
</ins><span class="cx"> 
</span><span class="cx">     unsigned callArgAreaSizeInBytes() const { return m_callArgAreaSize; }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirLivenessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirLiveness.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirLiveness.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirLiveness.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx"> 
</span><span class="cx"> typedef Liveness&lt;TmpLivenessAdapter&lt;GP&gt;&gt; GPLiveness;
</span><span class="cx"> typedef Liveness&lt;TmpLivenessAdapter&lt;FP&gt;&gt; FPLiveness;
</span><ins>+typedef Liveness&lt;UnifiedTmpLivenessAdapter&gt; UnifiedTmpLiveness;
</ins><span class="cx"> typedef Liveness&lt;StackSlotLivenessAdapter&gt; StackSlotLiveness;
</span><span class="cx"> 
</span><span class="cx"> } } } // namespace JSC::B3::Air
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirLivenessAdapterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirLivenessAdapter.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirLivenessAdapter.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirLivenessAdapter.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -31,7 +31,6 @@
</span><span class="cx"> #include &quot;AirCFG.h&quot;
</span><span class="cx"> #include &quot;AirCode.h&quot;
</span><span class="cx"> #include &quot;AirInstInlines.h&quot;
</span><del>-#include &quot;AirLivenessConstraints.h&quot;
</del><span class="cx"> #include &quot;AirStackSlot.h&quot;
</span><span class="cx"> #include &quot;AirTmpInlines.h&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -41,12 +40,61 @@
</span><span class="cx"> struct LivenessAdapter {
</span><span class="cx">     typedef Air::CFG CFG;
</span><span class="cx">     
</span><ins>+    typedef Vector&lt;unsigned, 4&gt; ActionsList;
+    
+    struct Actions {
+        Actions() { }
+        
+        ActionsList use;
+        ActionsList def;
+    };
+    
+    typedef Vector&lt;Actions, 0, UnsafeVectorOverflow&gt; ActionsForBoundary;
+    
</ins><span class="cx">     LivenessAdapter(Code&amp; code)
</span><span class="cx">         : code(code)
</span><del>-        , constraints(code)
</del><ins>+        , m_actions(code.size())
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    Adapter&amp; adapter()
+    {
+        return *static_cast&lt;Adapter*&gt;(this);
+    }
+    
+    void prepareToCompute()
+    {
+        for (BasicBlock* block : code) {
+            ActionsForBoundary&amp; actionsForBoundary = m_actions[block];
+            actionsForBoundary.resize(block-&gt;size() + 1);
+            
+            for (size_t instIndex = block-&gt;size(); instIndex--;) {
+                Inst&amp; inst = block-&gt;at(instIndex);
+                inst.forEach&lt;typename Adapter::Thing&gt;(
+                    [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Bank bank, Width) {
+                        if (!Adapter::acceptsBank(bank) || !Adapter::acceptsRole(role))
+                            return;
+                        
+                        unsigned index = adapter().valueToIndex(thing);
+                        
+                        if (Arg::isEarlyUse(role))
+                            actionsForBoundary[instIndex].use.appendIfNotContains(index);
+                        if (Arg::isEarlyDef(role))
+                            actionsForBoundary[instIndex].def.appendIfNotContains(index);
+                        if (Arg::isLateUse(role))
+                            actionsForBoundary[instIndex + 1].use.appendIfNotContains(index);
+                        if (Arg::isLateDef(role))
+                            actionsForBoundary[instIndex + 1].def.appendIfNotContains(index);
+                    });
+            }
+        }
+    }
+    
+    Actions&amp; actionsAt(BasicBlock* block, unsigned instBoundaryIndex)
+    {
+        return m_actions[block][instBoundaryIndex];
+    }
+    
</ins><span class="cx">     unsigned blockSize(BasicBlock* block)
</span><span class="cx">     {
</span><span class="cx">         return block-&gt;size();
</span><span class="lines">@@ -55,7 +103,7 @@
</span><span class="cx">     template&lt;typename Func&gt;
</span><span class="cx">     void forEachUse(BasicBlock* block, size_t instBoundaryIndex, const Func&amp; func)
</span><span class="cx">     {
</span><del>-        for (unsigned index : constraints.at(block, instBoundaryIndex).use)
</del><ins>+        for (unsigned index : actionsAt(block, instBoundaryIndex).use)
</ins><span class="cx">             func(index);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -62,12 +110,12 @@
</span><span class="cx">     template&lt;typename Func&gt;
</span><span class="cx">     void forEachDef(BasicBlock* block, size_t instBoundaryIndex, const Func&amp; func)
</span><span class="cx">     {
</span><del>-        for (unsigned index : constraints.at(block, instBoundaryIndex).def)
</del><ins>+        for (unsigned index : actionsAt(block, instBoundaryIndex).def)
</ins><span class="cx">             func(index);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     Code&amp; code;
</span><del>-    LivenessConstraints&lt;Adapter&gt; constraints;
</del><ins>+    IndexMap&lt;BasicBlock*, ActionsForBoundary&gt; m_actions;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template&lt;Bank adapterBank, Arg::Temperature minimumTemperature = Arg::Cold&gt;
</span><span class="lines">@@ -84,8 +132,7 @@
</span><span class="cx"> 
</span><span class="cx">     unsigned numIndices()
</span><span class="cx">     {
</span><del>-        unsigned numTmps = Base::code.numTmps(adapterBank);
-        return AbsoluteTmpMapper&lt;adapterBank&gt;::absoluteIndex(numTmps);
</del><ins>+        return Tmp::absoluteIndexEnd(Base::code, adapterBank);
</ins><span class="cx">     }
</span><span class="cx">     static bool acceptsBank(Bank bank) { return bank == adapterBank; }
</span><span class="cx">     static bool acceptsRole(Arg::Role role) { return Arg::temperature(role) &gt;= minimumTemperature; }
</span><span class="lines">@@ -93,6 +140,29 @@
</span><span class="cx">     static Tmp indexToValue(unsigned index) { return AbsoluteTmpMapper&lt;adapterBank&gt;::tmpFromAbsoluteIndex(index); }
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+struct UnifiedTmpLivenessAdapter : LivenessAdapter&lt;UnifiedTmpLivenessAdapter&gt; {
+    typedef LivenessAdapter&lt;UnifiedTmpLivenessAdapter&gt; Base;
+    
+    static constexpr const char* name = &quot;UnifiedTmpLiveness&quot;;
+
+    typedef Tmp Thing;
+    
+    UnifiedTmpLivenessAdapter(Code&amp; code)
+        : Base(code)
+    {
+    }
+    
+    unsigned numIndices()
+    {
+        return Tmp::linearIndexEnd(code);
+    }
+    
+    static bool acceptsBank(Bank) { return true; }
+    static bool acceptsRole(Arg::Role) { return true; }
+    unsigned valueToIndex(Tmp tmp) { return tmp.linearlyIndexed(code).index(); }
+    Tmp indexToValue(unsigned index) { return Tmp::tmpForLinearIndex(code, index); }
+};
+
</ins><span class="cx"> struct StackSlotLivenessAdapter : LivenessAdapter&lt;StackSlotLivenessAdapter&gt; {
</span><span class="cx">     static constexpr const char* name = &quot;StackSlotLiveness&quot;;
</span><span class="cx">     typedef StackSlot* Thing;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirLivenessConstraintsh"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/b3/air/AirLivenessConstraints.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirLivenessConstraints.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirLivenessConstraints.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -1,94 +0,0 @@
</span><del>-/*
- * Copyright (C) 2017 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.
- */
-
-#pragma once
-
-#if ENABLE(B3_JIT)
-
-#include &quot;AirBasicBlock.h&quot;
-#include &quot;AirCode.h&quot;
-#include &quot;AirInstInlines.h&quot;
-#include &lt;wtf/IndexMap.h&gt;
-
-namespace JSC { namespace B3 { namespace Air {
-
-template&lt;typename Adapter&gt;
-class LivenessConstraints {
-public:
-    typedef Vector&lt;unsigned, 4&gt; ActionsList;
-    
-    struct Actions {
-        Actions() { }
-        
-        ActionsList use;
-        ActionsList def;
-    };
-    
-    typedef Vector&lt;Actions, 0, UnsafeVectorOverflow&gt; ActionsForBoundary;
-    
-    LivenessConstraints(Code&amp; code)
-        : m_code(code)
-        , m_actions(code.size())
-    {
-        for (BasicBlock* block : m_code) {
-            ActionsForBoundary&amp; actionsForBoundary = m_actions[block];
-            actionsForBoundary.resize(block-&gt;size() + 1);
-            
-            for (size_t instIndex = block-&gt;size(); instIndex--;) {
-                Inst&amp; inst = block-&gt;at(instIndex);
-                inst.forEach&lt;typename Adapter::Thing&gt;(
-                    [&amp;] (typename Adapter::Thing&amp; thing, Arg::Role role, Bank bank, Width) {
-                        if (!Adapter::acceptsBank(bank) || !Adapter::acceptsRole(role))
-                            return;
-                        
-                        unsigned index = Adapter::valueToIndex(thing);
-                        
-                        if (Arg::isEarlyUse(role))
-                            actionsForBoundary[instIndex].use.appendIfNotContains(index);
-                        if (Arg::isEarlyDef(role))
-                            actionsForBoundary[instIndex].def.appendIfNotContains(index);
-                        if (Arg::isLateUse(role))
-                            actionsForBoundary[instIndex + 1].use.appendIfNotContains(index);
-                        if (Arg::isLateDef(role))
-                            actionsForBoundary[instIndex + 1].def.appendIfNotContains(index);
-                    });
-            }
-        }
-    }
-    
-    Actions&amp; at(BasicBlock* block, unsigned instBoundaryIndex)
-    {
-        return m_actions[block][instBoundaryIndex];
-    }
-    
-private:
-    Code&amp; m_code;
-    IndexMap&lt;BasicBlock*, ActionsForBoundary&gt; m_actions;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirRegLivenessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirRegLiveness.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirRegLiveness.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirRegLiveness.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -68,6 +68,15 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         
</span><ins>+        LocalCalc(UnifiedTmpLiveness&amp; liveness, BasicBlock* block)
+            : m_block(block)
+        {
+            for (Tmp tmp : liveness.liveAtTail(block)) {
+                if (tmp.isReg())
+                    m_workset.set(tmp.reg());
+            }
+        }
+        
</ins><span class="cx">         const RegisterSet&amp; live() const
</span><span class="cx">         {
</span><span class="cx">             return m_workset;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirTmpcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirTmp.cpp (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirTmp.cpp        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirTmp.cpp        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> template&lt;&gt; const char* const Tmp::Indexed&lt;FP&gt;::dumpPrefix = &quot;%ftmp&quot;;
</span><span class="cx"> template&lt;&gt; const char* const Tmp::AbsolutelyIndexed&lt;GP&gt;::dumpPrefix = &quot;%abs&quot;;
</span><span class="cx"> template&lt;&gt; const char* const Tmp::AbsolutelyIndexed&lt;FP&gt;::dumpPrefix = &quot;%fabs&quot;;
</span><ins>+const char* const Tmp::LinearlyIndexed::dumpPrefix = &quot;%ltmp&quot;;
</ins><span class="cx"> 
</span><span class="cx"> void Tmp::dump(PrintStream&amp; out) const
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirTmph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirTmp.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirTmp.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirTmp.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="cx"> 
</span><span class="cx"> class Arg;
</span><ins>+class Code;
</ins><span class="cx"> 
</span><span class="cx"> // A Tmp is a generalization of a register. It can be used to refer to any GPR or FPR. It can also
</span><span class="cx"> // be used to refer to an unallocated register (i.e. a temporary). Like many Air classes, we use
</span><span class="lines">@@ -165,6 +166,7 @@
</span><span class="cx">     
</span><span class="cx">     template&lt;Bank bank&gt; class Indexed;
</span><span class="cx">     template&lt;Bank bank&gt; class AbsolutelyIndexed;
</span><ins>+    class LinearlyIndexed;
</ins><span class="cx">     
</span><span class="cx">     template&lt;Bank bank&gt;
</span><span class="cx">     Indexed&lt;bank&gt; indexed() const;
</span><span class="lines">@@ -172,6 +174,12 @@
</span><span class="cx">     template&lt;Bank bank&gt;
</span><span class="cx">     AbsolutelyIndexed&lt;bank&gt; absolutelyIndexed() const;
</span><span class="cx">     
</span><ins>+    LinearlyIndexed linearlyIndexed(Code&amp;) const;
+
+    static unsigned indexEnd(Code&amp;, Bank);
+    static unsigned absoluteIndexEnd(Code&amp;, Bank);
+    static unsigned linearIndexEnd(Code&amp;);
+    
</ins><span class="cx">     bool isAlive() const
</span><span class="cx">     {
</span><span class="cx">         return !!*this;
</span><span class="lines">@@ -214,7 +222,9 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     static Tmp tmpForAbsoluteIndex(Bank, unsigned);
</span><del>-
</del><ins>+    
+    static Tmp tmpForLinearIndex(Code&amp;, unsigned);
+    
</ins><span class="cx"> private:
</span><span class="cx">     static int encodeGP(unsigned index)
</span><span class="cx">     {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirTmpInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/b3/air/AirTmpInlines.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirTmpInlines.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/JavaScriptCore/b3/air/AirTmpInlines.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> #if ENABLE(B3_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;AirArg.h&quot;
</span><ins>+#include &quot;AirCode.h&quot;
</ins><span class="cx"> #include &quot;AirTmp.h&quot;
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace B3 { namespace Air {
</span><span class="lines">@@ -124,6 +125,27 @@
</span><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+class Tmp::LinearlyIndexed : public Tmp {
+public:
+    static const char* const dumpPrefix;
+    
+    LinearlyIndexed(Tmp tmp, Code&amp; code)
+        : Tmp(tmp)
+        , m_code(&amp;code)
+    {
+    }
+    
+    ALWAYS_INLINE unsigned index() const
+    {
+        if (isGP())
+            return AbsoluteTmpMapper&lt;GP&gt;::absoluteIndex(*this);
+        return absoluteIndexEnd(*m_code, GP) + AbsoluteTmpMapper&lt;FP&gt;::absoluteIndex(*this);
+    }
+
+private:
+    Code* m_code;
+};
+
</ins><span class="cx"> template&lt;Bank theBank&gt;
</span><span class="cx"> inline Tmp::Indexed&lt;theBank&gt; Tmp::indexed() const
</span><span class="cx"> {
</span><span class="lines">@@ -136,14 +158,44 @@
</span><span class="cx">     return AbsolutelyIndexed&lt;theBank&gt;(*this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-inline Tmp Tmp::tmpForAbsoluteIndex(Bank bank, unsigned index)
</del><ins>+inline Tmp::LinearlyIndexed Tmp::linearlyIndexed(Code&amp; code) const
</ins><span class="cx"> {
</span><ins>+    return LinearlyIndexed(*this, code);
+}
+
+ALWAYS_INLINE unsigned Tmp::indexEnd(Code&amp; code, Bank bank)
+{
+    return code.numTmps(bank);
+}
+
+ALWAYS_INLINE unsigned Tmp::absoluteIndexEnd(Code&amp; code, Bank bank)
+{
</ins><span class="cx">     if (bank == GP)
</span><ins>+        return AbsoluteTmpMapper&lt;GP&gt;::absoluteIndex(code.numTmps(GP));
+    return AbsoluteTmpMapper&lt;FP&gt;::absoluteIndex(code.numTmps(FP));
+}
+
+ALWAYS_INLINE unsigned Tmp::linearIndexEnd(Code&amp; code)
+{
+    return absoluteIndexEnd(code, GP) + absoluteIndexEnd(code, FP);
+}
+
+ALWAYS_INLINE Tmp Tmp::tmpForAbsoluteIndex(Bank bank, unsigned index)
+{
+    if (bank == GP)
</ins><span class="cx">         return AbsoluteTmpMapper&lt;GP&gt;::tmpFromAbsoluteIndex(index);
</span><span class="cx">     ASSERT(bank == FP);
</span><span class="cx">     return AbsoluteTmpMapper&lt;FP&gt;::tmpFromAbsoluteIndex(index);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ALWAYS_INLINE Tmp Tmp::tmpForLinearIndex(Code&amp; code, unsigned index)
+{
+    unsigned gpEnd = absoluteIndexEnd(code, GP);
+    if (index &lt; gpEnd)
+        return tmpForAbsoluteIndex(GP, index);
+    return tmpForAbsoluteIndex(FP, index - gpEnd);
+}
+
</ins><span class="cx"> } } } // namespace JSC::B3::Air
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(B3_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreb3airAirTmpMaph"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/b3/air/AirTmpMap.h (0 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/b3/air/AirTmpMap.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/b3/air/AirTmpMap.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -0,0 +1,98 @@
</span><ins>+/*
+ * Copyright (C) 2017 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. 
+ */
+
+#pragma once
+
+#if ENABLE(B3_JIT)
+
+#include &quot;AirCode.h&quot;
+#include &quot;AirTmp.h&quot;
+#include &lt;wtf/IndexMap.h&gt;
+
+namespace JSC { namespace B3 { namespace Air {
+
+// As an alternative to this, you could use IndexMap&lt;Tmp::LinearlyIndexed, ...&gt;, but this would fail
+// as soon as you added a new GP tmp.
+
+template&lt;typename Value&gt;
+class TmpMap {
+public:
+    TmpMap()
+    {
+    }
+    
+    template&lt;typename... Args&gt;
+    TmpMap(Code&amp; code, const Args&amp;... args)
+        : m_gp(Tmp::absoluteIndexEnd(code, GP), args...)
+        , m_fp(Tmp::absoluteIndexEnd(code, FP), args...)
+    {
+    }
+    
+    template&lt;typename... Args&gt;
+    void resize(Code&amp; code, const Args&amp;... args)
+    {
+        m_gp.resize(Tmp::absoluteIndexEnd(code, GP), args...);
+        m_fp.resize(Tmp::absoluteIndexEnd(code, FP), args...);
+    }
+    
+    template&lt;typename... Args&gt;
+    void clear(const Args&amp;... args)
+    {
+        m_gp.clear(args...);
+        m_fp.clear(args...);
+    }
+    
+    const Value&amp; operator[](Tmp tmp) const
+    {
+        if (tmp.isGP())
+            return m_gp[tmp];
+        return m_fp[tmp];
+    }
+
+    Value&amp; operator[](Tmp tmp)
+    {
+        if (tmp.isGP())
+            return m_gp[tmp];
+        return m_fp[tmp];
+    }
+    
+    template&lt;typename PassedValue&gt;
+    void append(Tmp tmp, PassedValue&amp;&amp; value)
+    {
+        if (tmp.isGP())
+            m_gp.append(tmp, std::forward&lt;PassedValue&gt;(value));
+        else
+            m_fp.append(tmp, std::forward&lt;PassedValue&gt;(value));
+    }
+
+private:
+    IndexMap&lt;Tmp::AbsolutelyIndexed&lt;GP&gt;, Value&gt; m_gp;
+    IndexMap&lt;Tmp::AbsolutelyIndexed&lt;FP&gt;, Value&gt; m_fp;
+};
+
+} } } // namespace JSC::B3::Air
+
+#endif // ENABLE(B3_JIT)
+
</ins></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/WTF/ChangeLog        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -1,3 +1,21 @@
</span><ins>+2017-04-06  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        Linear scan should run liveness only once
+        https://bugs.webkit.org/show_bug.cgi?id=170569
+
+        Reviewed by Keith Miller.
+        
+        Have Liveness&lt;&gt; call Adapter::prepareToCompute(), since this makes it a lot easier to implement
+        constraint generation, since the constraint generator now gets to run after the Adapter is fully
+        constructed.
+        
+        * wtf/IndexMap.h:
+        (WTF::IndexMap::append): Also make this a bit more versatile.
+        * wtf/Liveness.h:
+        (WTF::Liveness::LocalCalc::Iterable::contains):
+        (WTF::Liveness::Iterable::contains):
+        (WTF::Liveness::compute):
+
</ins><span class="cx"> 2017-04-06  Andreas Kling  &lt;akling@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Kill any WebContent process using over 16 GB of memory.
</span></span></pre></div>
<a id="trunkSourceWTFwtfIndexMaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/IndexMap.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/IndexMap.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/WTF/wtf/IndexMap.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -81,10 +81,11 @@
</span><span class="cx">         return m_vector[IndexKeyType&lt;Key&gt;::index(key)];
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void append(const Key&amp; key, Value value)
</del><ins>+    template&lt;typename PassedValue&gt;
+    void append(const Key&amp; key, PassedValue&amp;&amp; value)
</ins><span class="cx">     {
</span><span class="cx">         RELEASE_ASSERT(IndexKeyType&lt;Key&gt;::index(key) == m_vector.size());
</span><del>-        m_vector.append(value);
</del><ins>+        m_vector.append(std::forward&lt;PassedValue&gt;(value));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceWTFwtfLivenessh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Liveness.h (215070 => 215071)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Liveness.h        2017-04-07 00:04:10 UTC (rev 215070)
+++ trunk/Source/WTF/wtf/Liveness.h        2017-04-07 00:11:16 UTC (rev 215071)
</span><span class="lines">@@ -105,7 +105,7 @@
</span><span class="cx">             
</span><span class="cx">             bool contains(const typename Adapter::Thing&amp; thing) const
</span><span class="cx">             {
</span><del>-                return m_liveness.m_workset.contains(Adapter::valueToIndex(thing));
</del><ins>+                return m_liveness.m_workset.contains(m_liveness.valueToIndex(thing));
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">         private:
</span><span class="lines">@@ -210,7 +210,7 @@
</span><span class="cx"> 
</span><span class="cx">         bool contains(const typename Adapter::Thing&amp; thing) const
</span><span class="cx">         {
</span><del>-            return m_liveness.m_workset.contains(Adapter::valueToIndex(thing));
</del><ins>+            return m_liveness.m_workset.contains(m_liveness.valueToIndex(thing));
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">     private:
</span><span class="lines">@@ -258,6 +258,8 @@
</span><span class="cx"> protected:
</span><span class="cx">     void compute()
</span><span class="cx">     {
</span><ins>+        Adapter::prepareToCompute();
+        
</ins><span class="cx">         // The liveAtTail of each block automatically contains the LateUse's of the terminal.
</span><span class="cx">         for (unsigned blockIndex = m_cfg.numNodes(); blockIndex--;) {
</span><span class="cx">             typename CFG::Node block = m_cfg.node(blockIndex);
</span></span></pre>
</div>
</div>

</body>
</html>