<!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>[171106] branches/ftlopt</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/171106">171106</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-07-15 08:48:44 -0700 (Tue, 15 Jul 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[ftlopt] DFG should be able to do GCSE in SSA and this should be unified with the CSE in CPS, and both of these things should use abstract heaps for reasoning about effects
https://bugs.webkit.org/show_bug.cgi?id=134677

Reviewed by Sam Weinig.

Source/JavaScriptCore: 
        
This removes the old local CSE phase, which was based on manually written backward-search 
rules for all of the different kinds of things we cared about, and adds a new local/global
CSE (local for CPS and global for SSA) that leaves the node semantics almost entirely up to
clobberize(). Thus, the CSE phase itself just worries about the algorithms and data
structures used for storing sets of available values. This results in a large reduction in
code size in CSEPhase.cpp while greatly increasing the phase's power (since it now does
global CSE) and reducing compile time (since local CSE is now rewritten to use smarter data
structures). Even though LLVM was already running GVN, the extra GCSE at DFG IR level means
that this is a significant (~0.7%) throughput improvement.
        
This work is based on the concept of &quot;def&quot; to clobberize(). If clobberize() calls def(), it
means that the node being analyzed makes available some value in some DFG node, and that
future attempts to compute that value can simply use that node. In other words, it
establishes an available value mapping of the form value=&gt;node. There are two kinds of
values that can be passed to def():
        
PureValue. This captures everything needed to determine whether two pure nodes - nodes that
    neither read nor write, and produce a value that is a CSE candidate - are identical. It
    carries the NodeType, an AdjacencyList, and one word of meta-data. The meta-data is
    usually used for things like the arithmetic mode or constant pointer. Passing a
    PureValue to def() means that the node produces a value that is valid anywhere that the
    node dominates.
        
HeapLocation. This describes a location in the heap that could be written to or read from.
    Both stores and loads can def() a HeapLocation. HeapLocation carries around an abstract
    heap that both serves as part of the &quot;name&quot; of the heap location (together with the
    other fields of HeapLocation) and also tells us what write()'s to watch for. If someone
    write()'s to an abstract heap that overlaps the heap associated with the HeapLocation,
    then it means that the values for that location are no longer available.
        
This approach is sufficiently clever that the CSEPhase itself can focus on the mechanism of
tracking the PureValue=&gt;node and HeapLocation=&gt;node maps, without having to worry about
interpreting the semantics of different DFG node types - that is now almost entirely in
clobberize(). The only things we special-case inside CSEPhase are the Identity node, which
CSE is traditionally responsible for eliminating even though it has nothing to do with CSE,
and the LocalCSE rule for turning PutByVal into PutByValAlias.
        
This is a slight Octane, SunSpider, and Kraken speed-up - all somewhere arond 0.7% . It's
not a bigger win because LLVM was already giving us most of what we needed in its GVN.
Also, the SunSpider speed-up isn't from GCSE as much as it's a clean-up of local CSE - that
is no longer O(n^2). Basically this is purely good: it reduces the amount of LLVM IR we
generate, it removes the old CSE's heap modeling (which was a constant source of bugs), and
it improves both the quality of the code we generate and the speed with which we generate
it. Also, any future optimizations that depend on GCSE will now be easier to implement.
        
During the development of this patch I also rationalized some other stuff, like Graph's
ordered traversals - we now have preorder and postorder rather than just &quot;depth first&quot;.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractHeap.h:
* dfg/DFGAdjacencyList.h:
(JSC::DFG::AdjacencyList::hash):
(JSC::DFG::AdjacencyList::operator==):
* dfg/DFGBasicBlock.h:
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::performLocalCSE):
(JSC::DFG::performGlobalCSE):
(JSC::DFG::CSEPhase::CSEPhase): Deleted.
(JSC::DFG::CSEPhase::run): Deleted.
(JSC::DFG::CSEPhase::endIndexForPureCSE): Deleted.
(JSC::DFG::CSEPhase::pureCSE): Deleted.
(JSC::DFG::CSEPhase::constantCSE): Deleted.
(JSC::DFG::CSEPhase::constantStoragePointerCSE): Deleted.
(JSC::DFG::CSEPhase::getCalleeLoadElimination): Deleted.
(JSC::DFG::CSEPhase::getArrayLengthElimination): Deleted.
(JSC::DFG::CSEPhase::globalVarLoadElimination): Deleted.
(JSC::DFG::CSEPhase::scopedVarLoadElimination): Deleted.
(JSC::DFG::CSEPhase::varInjectionWatchpointElimination): Deleted.
(JSC::DFG::CSEPhase::getByValLoadElimination): Deleted.
(JSC::DFG::CSEPhase::checkFunctionElimination): Deleted.
(JSC::DFG::CSEPhase::checkExecutableElimination): Deleted.
(JSC::DFG::CSEPhase::checkStructureElimination): Deleted.
(JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): Deleted.
(JSC::DFG::CSEPhase::getByOffsetLoadElimination): Deleted.
(JSC::DFG::CSEPhase::getGetterSetterByOffsetLoadElimination): Deleted.
(JSC::DFG::CSEPhase::getPropertyStorageLoadElimination): Deleted.
(JSC::DFG::CSEPhase::checkArrayElimination): Deleted.
(JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination): Deleted.
(JSC::DFG::CSEPhase::getInternalFieldLoadElimination): Deleted.
(JSC::DFG::CSEPhase::getMyScopeLoadElimination): Deleted.
(JSC::DFG::CSEPhase::getLocalLoadElimination): Deleted.
(JSC::DFG::CSEPhase::invalidationPointElimination): Deleted.
(JSC::DFG::CSEPhase::setReplacement): Deleted.
(JSC::DFG::CSEPhase::eliminate): Deleted.
(JSC::DFG::CSEPhase::performNodeCSE): Deleted.
(JSC::DFG::CSEPhase::performBlockCSE): Deleted.
(JSC::DFG::performCSE): Deleted.
* dfg/DFGCSEPhase.h:
* dfg/DFGClobberSet.cpp:
(JSC::DFG::addReads):
(JSC::DFG::addWrites):
(JSC::DFG::addReadsAndWrites):
(JSC::DFG::readsOverlap):
(JSC::DFG::writesOverlap):
* dfg/DFGClobberize.cpp:
(JSC::DFG::doesWrites):
(JSC::DFG::accessesOverlap):
(JSC::DFG::writesOverlap):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
(JSC::DFG::NoOpClobberize::operator()):
(JSC::DFG::CheckClobberize::operator()):
(JSC::DFG::ReadMethodClobberize::ReadMethodClobberize):
(JSC::DFG::ReadMethodClobberize::operator()):
(JSC::DFG::WriteMethodClobberize::WriteMethodClobberize):
(JSC::DFG::WriteMethodClobberize::operator()):
(JSC::DFG::DefMethodClobberize::DefMethodClobberize):
(JSC::DFG::DefMethodClobberize::operator()):
* dfg/DFGDCEPhase.cpp:
(JSC::DFG::DCEPhase::run):
(JSC::DFG::DCEPhase::fixupBlock):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::getBlocksInPreOrder):
(JSC::DFG::Graph::getBlocksInPostOrder):
(JSC::DFG::Graph::addForDepthFirstSort): Deleted.
(JSC::DFG::Graph::getBlocksInDepthFirstOrder): Deleted.
* dfg/DFGGraph.h:
* dfg/DFGHeapLocation.cpp: Added.
(JSC::DFG::HeapLocation::dump):
(WTF::printInternal):
* dfg/DFGHeapLocation.h: Added.
(JSC::DFG::HeapLocation::HeapLocation):
(JSC::DFG::HeapLocation::operator!):
(JSC::DFG::HeapLocation::kind):
(JSC::DFG::HeapLocation::heap):
(JSC::DFG::HeapLocation::base):
(JSC::DFG::HeapLocation::index):
(JSC::DFG::HeapLocation::hash):
(JSC::DFG::HeapLocation::operator==):
(JSC::DFG::HeapLocation::isHashTableDeletedValue):
(JSC::DFG::HeapLocationHash::hash):
(JSC::DFG::HeapLocationHash::equal):
* dfg/DFGLICMPhase.cpp:
(JSC::DFG::LICMPhase::run):
* dfg/DFGNode.h:
(JSC::DFG::Node::replaceWith):
(JSC::DFG::Node::convertToPhantomUnchecked): Deleted.
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPureValue.cpp: Added.
(JSC::DFG::PureValue::dump):
* dfg/DFGPureValue.h: Added.
(JSC::DFG::PureValue::PureValue):
(JSC::DFG::PureValue::operator!):
(JSC::DFG::PureValue::op):
(JSC::DFG::PureValue::children):
(JSC::DFG::PureValue::info):
(JSC::DFG::PureValue::hash):
(JSC::DFG::PureValue::operator==):
(JSC::DFG::PureValue::isHashTableDeletedValue):
(JSC::DFG::PureValueHash::hash):
(JSC::DFG::PureValueHash::equal):
* dfg/DFGSSAConversionPhase.cpp:
(JSC::DFG::SSAConversionPhase::run):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::lower):

LayoutTests: 

* js/regress/gcse-expected.txt: Added.
* js/regress/gcse-poly-get-expected.txt: Added.
* js/regress/gcse-poly-get-less-obvious-expected.txt: Added.
* js/regress/gcse-poly-get-less-obvious.html: Added.
* js/regress/gcse-poly-get.html: Added.
* js/regress/gcse.html: Added.
* js/regress/script-tests/gcse-poly-get-less-obvious.js: Added.
* js/regress/script-tests/gcse-poly-get.js: Added.
* js/regress/script-tests/gcse.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsChangeLog">branches/ftlopt/LayoutTests/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreCMakeListstxt">branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreChangeLog">branches/ftlopt/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAbstractHeaph">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGAdjacencyListh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGAdjacencyList.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGBasicBlockh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGBasicBlock.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGCSEPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGCSEPhaseh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGClobberSetcpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberSet.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGClobberizecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGClobberizeh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGDCEPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGGraphcpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGGraphh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGLICMPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGNodeh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGPlancpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGSSAConversionPhasecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#branchesftloptLayoutTestsjsregressgcseexpectedtxt">branches/ftlopt/LayoutTests/js/regress/gcse-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgcsepolygetexpectedtxt">branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgcsepolygetlessobviousexpectedtxt">branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious-expected.txt</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgcsepolygetlessobvioushtml">branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgcsepolygethtml">branches/ftlopt/LayoutTests/js/regress/gcse-poly-get.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressgcsehtml">branches/ftlopt/LayoutTests/js/regress/gcse.html</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsgcsepolygetlessobviousjs">branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get-less-obvious.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsgcsepolygetjs">branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get.js</a></li>
<li><a href="#branchesftloptLayoutTestsjsregressscripttestsgcsejs">branches/ftlopt/LayoutTests/js/regress/script-tests/gcse.js</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGHeapLocationcpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGHeapLocationh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.h</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGPureValuecpp">branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.cpp</a></li>
<li><a href="#branchesftloptSourceJavaScriptCoredfgDFGPureValueh">branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="branchesftloptLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/LayoutTests/ChangeLog (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/ChangeLog        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/LayoutTests/ChangeLog        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -1,3 +1,20 @@
</span><ins>+2014-07-13  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        [ftlopt] DFG should be able to do GCSE in SSA and this should be unified with the CSE in CPS, and both of these things should use abstract heaps for reasoning about effects
+        https://bugs.webkit.org/show_bug.cgi?id=134677
+
+        Reviewed by Sam Weinig.
+
+        * js/regress/gcse-expected.txt: Added.
+        * js/regress/gcse-poly-get-expected.txt: Added.
+        * js/regress/gcse-poly-get-less-obvious-expected.txt: Added.
+        * js/regress/gcse-poly-get-less-obvious.html: Added.
+        * js/regress/gcse-poly-get.html: Added.
+        * js/regress/gcse.html: Added.
+        * js/regress/script-tests/gcse-poly-get-less-obvious.js: Added.
+        * js/regress/script-tests/gcse-poly-get.js: Added.
+        * js/regress/script-tests/gcse.js: Added.
+
</ins><span class="cx"> 2014-07-04  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [ftlopt] Infer immutable object properties
</span></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgcseexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/gcse-expected.txt (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/gcse-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/gcse-expected.txt        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/gcse
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgcsepolygetexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-expected.txt (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-expected.txt        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/gcse-poly-get
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgcsepolygetlessobviousexpectedtxt"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious-expected.txt (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious-expected.txt                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious-expected.txt        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/gcse-poly-get-less-obvious
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgcsepolygetlessobvioushtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious.html (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/gcse-poly-get-less-obvious.html        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/gcse-poly-get-less-obvious.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgcsepolygethtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/gcse-poly-get.html (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/gcse-poly-get.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/gcse-poly-get.html        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/gcse-poly-get.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressgcsehtml"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/gcse.html (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/gcse.html                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/gcse.html        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/gcse.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsgcsepolygetlessobviousjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get-less-obvious.js (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get-less-obvious.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get-less-obvious.js        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+(function(o, p) {
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0 ; i &lt; n; ++i) {
+        var a = o.f;
+        var b = o.f;
+        var c = o.f;
+        var d = o.f;
+        if (d) {
+            var e = o.f;
+            var f = o.f;
+            var g = o.f;
+            var h = o.f;
+            if (h) {
+                var j = o.f;
+                var k = o.f;
+                var l = o.f;
+                var m = o.f;
+                if (m) {
+                    var q = o.f;
+                    var r = o.f;
+                    var s = o.f;
+                    var t = o.f;
+                    if (t)
+                        result += r;
+                }
+            }
+        }
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != (n / 2) * o.f + (n / 2) * p.f)
+        throw &quot;Error: bad result: &quot; + result;
+})({f:42, g:0}, {g:0, f:43});
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsgcsepolygetjs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get.js (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/gcse-poly-get.js        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+(function(){
+    var o = {f:42, g:0};
+    var p = {g:0, f:43};
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0 ; i &lt; n; ++i) {
+        var a = o.f;
+        var b = o.f;
+        var c = o.f;
+        var d = o.f;
+        if (d) {
+            var e = o.f;
+            var f = o.f;
+            var g = o.f;
+            var h = o.f;
+            if (h) {
+                var j = o.f;
+                var k = o.f;
+                var l = o.f;
+                var m = o.f;
+                if (m) {
+                    var q = o.f;
+                    var r = o.f;
+                    var s = o.f;
+                    var t = o.f;
+                    if (t)
+                        result += r;
+                }
+            }
+        }
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != (n / 2) * o.f + (n / 2) * p.f)
+        throw &quot;Error: bad result: &quot; + result;
+})();
</ins></span></pre></div>
<a id="branchesftloptLayoutTestsjsregressscripttestsgcsejs"></a>
<div class="addfile"><h4>Added: branches/ftlopt/LayoutTests/js/regress/script-tests/gcse.js (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/LayoutTests/js/regress/script-tests/gcse.js                                (rev 0)
+++ branches/ftlopt/LayoutTests/js/regress/script-tests/gcse.js        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+(function(){
+    var o = {f:42};
+    var p = {f:43};
+    var result = 0;
+    var n = 1000000;
+    for (var i = 0 ; i &lt; n; ++i) {
+        var a = o.f;
+        var b = o.f;
+        var c = o.f;
+        var d = o.f;
+        if (d) {
+            var e = o.f;
+            var f = o.f;
+            var g = o.f;
+            var h = o.f;
+            if (h) {
+                var j = o.f;
+                var k = o.f;
+                var l = o.f;
+                var m = o.f;
+                if (m) {
+                    var q = o.f;
+                    var r = o.f;
+                    var s = o.f;
+                    var t = o.f;
+                    if (t)
+                        result += r;
+                }
+            }
+        }
+        var tmp = o;
+        o = p;
+        p = tmp;
+    }
+    if (result != (n / 2) * o.f + (n / 2) * p.f)
+        throw &quot;Error: bad result: &quot; + result;
+})();
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/CMakeLists.txt        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -152,6 +152,7 @@
</span><span class="cx">     dfg/DFGFunctionWhitelist.cpp
</span><span class="cx">     dfg/DFGGraph.cpp
</span><span class="cx">     dfg/DFGGraphSafepoint.cpp
</span><ins>+    dfg/DFGHeapLocation.cpp
</ins><span class="cx">     dfg/DFGInPlaceAbstractState.cpp
</span><span class="cx">     dfg/DFGIntegerCheckCombiningPhase.cpp
</span><span class="cx">     dfg/DFGInvalidationPointInjectionPhase.cpp
</span><span class="lines">@@ -186,6 +187,7 @@
</span><span class="cx">     dfg/DFGPlan.cpp
</span><span class="cx">     dfg/DFGPredictionInjectionPhase.cpp
</span><span class="cx">     dfg/DFGPredictionPropagationPhase.cpp
</span><ins>+    dfg/DFGPureValue.cpp
</ins><span class="cx">     dfg/DFGResurrectionForValidationPhase.cpp
</span><span class="cx">     dfg/DFGSSAConversionPhase.cpp
</span><span class="cx">     dfg/DFGSSALoweringPhase.cpp
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ChangeLog (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/ChangeLog        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -1,5 +1,171 @@
</span><span class="cx"> 2014-07-13  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        [ftlopt] DFG should be able to do GCSE in SSA and this should be unified with the CSE in CPS, and both of these things should use abstract heaps for reasoning about effects
+        https://bugs.webkit.org/show_bug.cgi?id=134677
+
+        Reviewed by Sam Weinig.
+        
+        This removes the old local CSE phase, which was based on manually written backward-search 
+        rules for all of the different kinds of things we cared about, and adds a new local/global
+        CSE (local for CPS and global for SSA) that leaves the node semantics almost entirely up to
+        clobberize(). Thus, the CSE phase itself just worries about the algorithms and data
+        structures used for storing sets of available values. This results in a large reduction in
+        code size in CSEPhase.cpp while greatly increasing the phase's power (since it now does
+        global CSE) and reducing compile time (since local CSE is now rewritten to use smarter data
+        structures). Even though LLVM was already running GVN, the extra GCSE at DFG IR level means
+        that this is a significant (~0.7%) throughput improvement.
+        
+        This work is based on the concept of &quot;def&quot; to clobberize(). If clobberize() calls def(), it
+        means that the node being analyzed makes available some value in some DFG node, and that
+        future attempts to compute that value can simply use that node. In other words, it
+        establishes an available value mapping of the form value=&gt;node. There are two kinds of
+        values that can be passed to def():
+        
+        PureValue. This captures everything needed to determine whether two pure nodes - nodes that
+            neither read nor write, and produce a value that is a CSE candidate - are identical. It
+            carries the NodeType, an AdjacencyList, and one word of meta-data. The meta-data is
+            usually used for things like the arithmetic mode or constant pointer. Passing a
+            PureValue to def() means that the node produces a value that is valid anywhere that the
+            node dominates.
+        
+        HeapLocation. This describes a location in the heap that could be written to or read from.
+            Both stores and loads can def() a HeapLocation. HeapLocation carries around an abstract
+            heap that both serves as part of the &quot;name&quot; of the heap location (together with the
+            other fields of HeapLocation) and also tells us what write()'s to watch for. If someone
+            write()'s to an abstract heap that overlaps the heap associated with the HeapLocation,
+            then it means that the values for that location are no longer available.
+        
+        This approach is sufficiently clever that the CSEPhase itself can focus on the mechanism of
+        tracking the PureValue=&gt;node and HeapLocation=&gt;node maps, without having to worry about
+        interpreting the semantics of different DFG node types - that is now almost entirely in
+        clobberize(). The only things we special-case inside CSEPhase are the Identity node, which
+        CSE is traditionally responsible for eliminating even though it has nothing to do with CSE,
+        and the LocalCSE rule for turning PutByVal into PutByValAlias.
+        
+        This is a slight Octane, SunSpider, and Kraken speed-up - all somewhere arond 0.7% . It's
+        not a bigger win because LLVM was already giving us most of what we needed in its GVN.
+        Also, the SunSpider speed-up isn't from GCSE as much as it's a clean-up of local CSE - that
+        is no longer O(n^2). Basically this is purely good: it reduces the amount of LLVM IR we
+        generate, it removes the old CSE's heap modeling (which was a constant source of bugs), and
+        it improves both the quality of the code we generate and the speed with which we generate
+        it. Also, any future optimizations that depend on GCSE will now be easier to implement.
+        
+        During the development of this patch I also rationalized some other stuff, like Graph's
+        ordered traversals - we now have preorder and postorder rather than just &quot;depth first&quot;.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * dfg/DFGAbstractHeap.h:
+        * dfg/DFGAdjacencyList.h:
+        (JSC::DFG::AdjacencyList::hash):
+        (JSC::DFG::AdjacencyList::operator==):
+        * dfg/DFGBasicBlock.h:
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::performLocalCSE):
+        (JSC::DFG::performGlobalCSE):
+        (JSC::DFG::CSEPhase::CSEPhase): Deleted.
+        (JSC::DFG::CSEPhase::run): Deleted.
+        (JSC::DFG::CSEPhase::endIndexForPureCSE): Deleted.
+        (JSC::DFG::CSEPhase::pureCSE): Deleted.
+        (JSC::DFG::CSEPhase::constantCSE): Deleted.
+        (JSC::DFG::CSEPhase::constantStoragePointerCSE): Deleted.
+        (JSC::DFG::CSEPhase::getCalleeLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::getArrayLengthElimination): Deleted.
+        (JSC::DFG::CSEPhase::globalVarLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::scopedVarLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::varInjectionWatchpointElimination): Deleted.
+        (JSC::DFG::CSEPhase::getByValLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::checkFunctionElimination): Deleted.
+        (JSC::DFG::CSEPhase::checkExecutableElimination): Deleted.
+        (JSC::DFG::CSEPhase::checkStructureElimination): Deleted.
+        (JSC::DFG::CSEPhase::structureTransitionWatchpointElimination): Deleted.
+        (JSC::DFG::CSEPhase::getByOffsetLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::getGetterSetterByOffsetLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::getPropertyStorageLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::checkArrayElimination): Deleted.
+        (JSC::DFG::CSEPhase::getIndexedPropertyStorageLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::getInternalFieldLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::getMyScopeLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::getLocalLoadElimination): Deleted.
+        (JSC::DFG::CSEPhase::invalidationPointElimination): Deleted.
+        (JSC::DFG::CSEPhase::setReplacement): Deleted.
+        (JSC::DFG::CSEPhase::eliminate): Deleted.
+        (JSC::DFG::CSEPhase::performNodeCSE): Deleted.
+        (JSC::DFG::CSEPhase::performBlockCSE): Deleted.
+        (JSC::DFG::performCSE): Deleted.
+        * dfg/DFGCSEPhase.h:
+        * dfg/DFGClobberSet.cpp:
+        (JSC::DFG::addReads):
+        (JSC::DFG::addWrites):
+        (JSC::DFG::addReadsAndWrites):
+        (JSC::DFG::readsOverlap):
+        (JSC::DFG::writesOverlap):
+        * dfg/DFGClobberize.cpp:
+        (JSC::DFG::doesWrites):
+        (JSC::DFG::accessesOverlap):
+        (JSC::DFG::writesOverlap):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        (JSC::DFG::NoOpClobberize::operator()):
+        (JSC::DFG::CheckClobberize::operator()):
+        (JSC::DFG::ReadMethodClobberize::ReadMethodClobberize):
+        (JSC::DFG::ReadMethodClobberize::operator()):
+        (JSC::DFG::WriteMethodClobberize::WriteMethodClobberize):
+        (JSC::DFG::WriteMethodClobberize::operator()):
+        (JSC::DFG::DefMethodClobberize::DefMethodClobberize):
+        (JSC::DFG::DefMethodClobberize::operator()):
+        * dfg/DFGDCEPhase.cpp:
+        (JSC::DFG::DCEPhase::run):
+        (JSC::DFG::DCEPhase::fixupBlock):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::getBlocksInPreOrder):
+        (JSC::DFG::Graph::getBlocksInPostOrder):
+        (JSC::DFG::Graph::addForDepthFirstSort): Deleted.
+        (JSC::DFG::Graph::getBlocksInDepthFirstOrder): Deleted.
+        * dfg/DFGGraph.h:
+        * dfg/DFGHeapLocation.cpp: Added.
+        (JSC::DFG::HeapLocation::dump):
+        (WTF::printInternal):
+        * dfg/DFGHeapLocation.h: Added.
+        (JSC::DFG::HeapLocation::HeapLocation):
+        (JSC::DFG::HeapLocation::operator!):
+        (JSC::DFG::HeapLocation::kind):
+        (JSC::DFG::HeapLocation::heap):
+        (JSC::DFG::HeapLocation::base):
+        (JSC::DFG::HeapLocation::index):
+        (JSC::DFG::HeapLocation::hash):
+        (JSC::DFG::HeapLocation::operator==):
+        (JSC::DFG::HeapLocation::isHashTableDeletedValue):
+        (JSC::DFG::HeapLocationHash::hash):
+        (JSC::DFG::HeapLocationHash::equal):
+        * dfg/DFGLICMPhase.cpp:
+        (JSC::DFG::LICMPhase::run):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::replaceWith):
+        (JSC::DFG::Node::convertToPhantomUnchecked): Deleted.
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        * dfg/DFGPureValue.cpp: Added.
+        (JSC::DFG::PureValue::dump):
+        * dfg/DFGPureValue.h: Added.
+        (JSC::DFG::PureValue::PureValue):
+        (JSC::DFG::PureValue::operator!):
+        (JSC::DFG::PureValue::op):
+        (JSC::DFG::PureValue::children):
+        (JSC::DFG::PureValue::info):
+        (JSC::DFG::PureValue::hash):
+        (JSC::DFG::PureValue::operator==):
+        (JSC::DFG::PureValue::isHashTableDeletedValue):
+        (JSC::DFG::PureValueHash::hash):
+        (JSC::DFG::PureValueHash::equal):
+        * dfg/DFGSSAConversionPhase.cpp:
+        (JSC::DFG::SSAConversionPhase::run):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::lower):
+
+2014-07-13  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
</ins><span class="cx">         Unreviewed, revert unintended change in r171051.
</span><span class="cx"> 
</span><span class="cx">         * dfg/DFGCSEPhase.cpp:
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -403,6 +403,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGFunctionWhitelist.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGGraph.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGGraphSafepoint.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\dfg\DFGHeapLocation.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGInPlaceAbstractState.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGIntegerCheckCombiningPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGInvalidationPointInjectionPhase.cpp&quot; /&gt;
</span><span class="lines">@@ -437,6 +438,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPlan.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPredictionInjectionPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPredictionPropagationPhase.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\dfg\DFGPureValue.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGResurrectionForValidationPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGSafepoint.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGSpeculativeJIT.cpp&quot; /&gt;
</span><span class="lines">@@ -975,6 +977,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGGPRInfo.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGGraph.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGGraphSafepoint.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\dfg\DFGHeapLocation.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGInPlaceAbstractState.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGInsertionSet.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGIntegerCheckCombiningPhase.h&quot; /&gt;
</span><span class="lines">@@ -1015,6 +1018,7 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPlan.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPredictionInjectionPhase.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPredictionPropagationPhase.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\dfg\DFGPureValue.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGRegisterBank.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGRegisterSet.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGResurrectionForValidationPhase.h&quot; /&gt;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -432,6 +432,10 @@
</span><span class="cx">                 0FB14E1F18124ACE009B6B4D /* JITInlineCacheGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E1D18124ACE009B6B4D /* JITInlineCacheGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FB14E211812570B009B6B4D /* DFGInlineCacheWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FB14E2318130955009B6B4D /* DFGInlineCacheWrapperInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0FB17660196B8F9E0091052A /* DFGHeapLocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB1765C196B8F9E0091052A /* DFGHeapLocation.cpp */; };
+                0FB17661196B8F9E0091052A /* DFGHeapLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB1765D196B8F9E0091052A /* DFGHeapLocation.h */; settings = {ATTRIBUTES = (Private, ); }; };
+                0FB17662196B8F9E0091052A /* DFGPureValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */; };
+                0FB17663196B8F9E0091052A /* DFGPureValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB1765F196B8F9E0091052A /* DFGPureValue.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0FB438A319270B1D00E1FBC9 /* StructureSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */; };
</span><span class="cx">                 0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467614F59AD1002C2989 /* LazyOperandValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */; };
</span><span class="lines">@@ -2609,6 +2613,10 @@
</span><span class="cx">                 0FB14E1D18124ACE009B6B4D /* JITInlineCacheGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlineCacheGenerator.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInlineCacheWrapper.h; path = dfg/DFGInlineCacheWrapper.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInlineCacheWrapperInlines.h; path = dfg/DFGInlineCacheWrapperInlines.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0FB1765C196B8F9E0091052A /* DFGHeapLocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGHeapLocation.cpp; path = dfg/DFGHeapLocation.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FB1765D196B8F9E0091052A /* DFGHeapLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGHeapLocation.h; path = dfg/DFGHeapLocation.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPureValue.cpp; path = dfg/DFGPureValue.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0FB1765F196B8F9E0091052A /* DFGPureValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPureValue.h; path = dfg/DFGPureValue.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0FB438A219270B1D00E1FBC9 /* StructureSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureSet.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGMinifiedID.h; path = dfg/DFGMinifiedID.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0FB4B51916B62772003F696B /* DFGAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAllocator.h; path = dfg/DFGAllocator.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -5114,6 +5122,8 @@
</span><span class="cx">                                 86EC9DB81328DF82002B2AD7 /* DFGGraph.h */,
</span><span class="cx">                                 0F2FCCF218A60070001A27F8 /* DFGGraphSafepoint.cpp */,
</span><span class="cx">                                 0F2FCCF318A60070001A27F8 /* DFGGraphSafepoint.h */,
</span><ins>+                                0FB1765C196B8F9E0091052A /* DFGHeapLocation.cpp */,
+                                0FB1765D196B8F9E0091052A /* DFGHeapLocation.h */,
</ins><span class="cx">                                 0FB14E201812570B009B6B4D /* DFGInlineCacheWrapper.h */,
</span><span class="cx">                                 0FB14E2218130955009B6B4D /* DFGInlineCacheWrapperInlines.h */,
</span><span class="cx">                                 A704D90017A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp */,
</span><span class="lines">@@ -5190,6 +5200,8 @@
</span><span class="cx">                                 0FBE0F6E16C1DB010082C5E8 /* DFGPredictionInjectionPhase.h */,
</span><span class="cx">                                 0FFFC95114EF909500C72532 /* DFGPredictionPropagationPhase.cpp */,
</span><span class="cx">                                 0FFFC95214EF909500C72532 /* DFGPredictionPropagationPhase.h */,
</span><ins>+                                0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */,
+                                0FB1765F196B8F9E0091052A /* DFGPureValue.h */,
</ins><span class="cx">                                 86EC9DC11328DF82002B2AD7 /* DFGRegisterBank.h */,
</span><span class="cx">                                 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */,
</span><span class="cx">                                 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */,
</span><span class="lines">@@ -6117,6 +6129,7 @@
</span><span class="cx">                                 0FF0F19B16B729FA005DF95B /* DFGLongLivedState.h in Headers */,
</span><span class="cx">                                 A767B5B617A0B9650063D940 /* DFGLoopPreHeaderCreationPhase.h in Headers */,
</span><span class="cx">                                 A704D90717A0BAA8006BA554 /* DFGMergeMode.h in Headers */,
</span><ins>+                                0FB17663196B8F9E0091052A /* DFGPureValue.h in Headers */,
</ins><span class="cx">                                 0F2BDC451522801B00CD8910 /* DFGMinifiedGraph.h in Headers */,
</span><span class="cx">                                 0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */,
</span><span class="cx">                                 0F2BDC461522802000CD8910 /* DFGMinifiedNode.h in Headers */,
</span><span class="lines">@@ -6654,6 +6667,7 @@
</span><span class="cx">                                 86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */,
</span><span class="cx">                                 0F2B670517B6B5AB00A7AE3F /* SimpleTypedArrayController.h in Headers */,
</span><span class="cx">                                 14BA78F113AAB88F005B7C2C /* SlotVisitor.h in Headers */,
</span><ins>+                                0FB17661196B8F9E0091052A /* DFGHeapLocation.h in Headers */,
</ins><span class="cx">                                 C2160FE715F7E95E00942DFC /* SlotVisitorInlines.h in Headers */,
</span><span class="cx">                                 A709F2F017A0AC0400512E98 /* SlowPathCall.h in Headers */,
</span><span class="cx">                                 933040040E6A749400786E6A /* SmallStrings.h in Headers */,
</span><span class="lines">@@ -7740,11 +7754,13 @@
</span><span class="cx">                                 0F93B4A918B92C4D00178A3F /* PutByIdVariant.cpp in Sources */,
</span><span class="cx">                                 0FD8A32717D51F5700CA2C40 /* DFGTierUpCheckInjectionPhase.cpp in Sources */,
</span><span class="cx">                                 0FD8A32917D51F5700CA2C40 /* DFGToFTLDeferredCompilationCallback.cpp in Sources */,
</span><ins>+                                0FB17662196B8F9E0091052A /* DFGPureValue.cpp in Sources */,
</ins><span class="cx">                                 0FD8A32B17D51F5700CA2C40 /* DFGToFTLForOSREntryDeferredCompilationCallback.cpp in Sources */,
</span><span class="cx">                                 0F63944015C75F1D006A597C /* DFGTypeCheckHoistingPhase.cpp in Sources */,
</span><span class="cx">                                 0FBE0F7616C1DB0F0082C5E8 /* DFGUnificationPhase.cpp in Sources */,
</span><span class="cx">                                 0F34B14916D42010001CDA5A /* DFGUseKind.cpp in Sources */,
</span><span class="cx">                                 0F3B3A2B15475000003ED0FF /* DFGValidate.cpp in Sources */,
</span><ins>+                                0FB17660196B8F9E0091052A /* DFGHeapLocation.cpp in Sources */,
</ins><span class="cx">                                 0F2BDC4F15228BF300CD8910 /* DFGValueSource.cpp in Sources */,
</span><span class="cx">                                 0FDDBFB51666EED800C55FEF /* DFGVariableAccessDataDump.cpp in Sources */,
</span><span class="cx">                                 0F5874ED194FEB1200AAB2C1 /* DFGMayExit.cpp in Sources */,
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAbstractHeaph"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAbstractHeap.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -42,31 +42,22 @@
</span><span class="cx"> #define FOR_EACH_ABSTRACT_HEAP_KIND(macro) \
</span><span class="cx">     macro(InvalidAbstractHeap) \
</span><span class="cx">     macro(World) \
</span><del>-    macro(Arguments_numArguments) \
-    macro(Arguments_overrideLength) \
</del><span class="cx">     macro(Arguments_registers) \
</span><del>-    macro(Arguments_slowArguments) \
-    macro(ArrayBuffer_data) \
-    macro(Butterfly_arrayBuffer) \
</del><span class="cx">     macro(Butterfly_publicLength) \
</span><span class="cx">     macro(Butterfly_vectorLength) \
</span><span class="cx">     macro(GetterSetter_getter) \
</span><span class="cx">     macro(GetterSetter_setter) \
</span><del>-    macro(JSArrayBufferView_length) \
-    macro(JSArrayBufferView_mode) \
-    macro(JSArrayBufferView_vector) \
</del><span class="cx">     macro(JSCell_structureID) \
</span><span class="cx">     macro(JSCell_indexingType) \
</span><span class="cx">     macro(JSCell_typeInfoFlags) \
</span><span class="cx">     macro(JSCell_typeInfoType) \
</span><del>-    macro(JSFunction_executable) \
-    macro(JSFunction_scopeChain) \
</del><span class="cx">     macro(JSObject_butterfly) \
</span><span class="cx">     macro(JSVariableObject_registers) \
</span><span class="cx">     macro(NamedProperties) \
</span><span class="cx">     macro(IndexedInt32Properties) \
</span><span class="cx">     macro(IndexedDoubleProperties) \
</span><span class="cx">     macro(IndexedContiguousProperties) \
</span><ins>+    macro(IndexedArrayStorageProperties) \
</ins><span class="cx">     macro(ArrayStorageProperties) \
</span><span class="cx">     macro(Variables) \
</span><span class="cx">     macro(TypedArrayProperties) \
</span><span class="lines">@@ -76,7 +67,7 @@
</span><span class="cx">     macro(Absolute) \
</span><span class="cx">     /* Use this for writes only, to indicate that this may fire watchpoints. Usually this is never directly written but instead we test to see if a node clobbers this; it just so happens that you have to write world to clobber it. */\
</span><span class="cx">     macro(Watchpoint_fire) \
</span><del>-    /* Use this for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\
</del><ins>+    /* Use these for reads only, just to indicate that if the world got clobbered, then this operation will not work. */\
</ins><span class="cx">     macro(MiscFields) \
</span><span class="cx">     /* Use this for writes only, just to indicate that hoisting the node is invalid. This works because we don't hoist anything that has any side effects at all. */\
</span><span class="cx">     macro(SideState)
</span><span class="lines">@@ -207,7 +198,7 @@
</span><span class="cx">         return payloadImpl();
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool isDisjoint(const AbstractHeap&amp; other)
</del><ins>+    bool isDisjoint(const AbstractHeap&amp; other) const
</ins><span class="cx">     {
</span><span class="cx">         ASSERT(kind() != InvalidAbstractHeap);
</span><span class="cx">         ASSERT(other.kind() != InvalidAbstractHeap);
</span><span class="lines">@@ -220,7 +211,7 @@
</span><span class="cx">         return payload().isDisjoint(other.payload());
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool overlaps(const AbstractHeap&amp; other)
</del><ins>+    bool overlaps(const AbstractHeap&amp; other) const
</ins><span class="cx">     {
</span><span class="cx">         return !isDisjoint(other);
</span><span class="cx">     }
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGAdjacencyListh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGAdjacencyList.h (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGAdjacencyList.h        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGAdjacencyList.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -52,7 +52,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    AdjacencyList(Kind kind, Edge child1, Edge child2, Edge child3)
</del><ins>+    AdjacencyList(Kind kind, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
</ins><span class="cx">     {
</span><span class="cx">         ASSERT_UNUSED(kind, kind == Fixed);
</span><span class="cx">         initialize(child1, child2, child3);
</span><span class="lines">@@ -151,6 +151,41 @@
</span><span class="cx">         m_words[1].m_encodedWord = numChildren;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    AdjacencyList sanitized() const
+    {
+        return AdjacencyList(Fixed, child1().sanitized(), child2().sanitized(), child3().sanitized());
+    }
+    
+    unsigned hash() const
+    {
+        unsigned result = 0;
+        if (!child1())
+            return result;
+        
+        result += child1().hash();
+        
+        if (!child2())
+            return result;
+        
+        result *= 3;
+        result += child2().hash();
+        
+        if (!child3())
+            return result;
+        
+        result *= 3;
+        result += child3().hash();
+        
+        return result;
+    }
+    
+    bool operator==(const AdjacencyList&amp; other) const
+    {
+        return child1() == other.child1()
+            &amp;&amp; child2() == other.child2()
+            &amp;&amp; child3() == other.child3();
+    }
+    
</ins><span class="cx"> private:
</span><span class="cx">     Edge m_words[Size];
</span><span class="cx"> };
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGBasicBlockh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGBasicBlock.h (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGBasicBlock.h        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGBasicBlock.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -171,8 +171,8 @@
</span><span class="cx">         SSAData(BasicBlock*);
</span><span class="cx">         ~SSAData();
</span><span class="cx">     };
</span><del>-    OwnPtr&lt;SSAData&gt; ssa;
-
</del><ins>+    std::unique_ptr&lt;SSAData&gt; ssa;
+    
</ins><span class="cx"> private:
</span><span class="cx">     friend class InsertionSet;
</span><span class="cx">     Vector&lt;Node*, 8&gt; m_nodes;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGCSEPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> #if ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &quot;DFGAbstractHeap.h&quot;
</span><ins>+#include &quot;DFGClobberSet.h&quot;
</ins><span class="cx"> #include &quot;DFGClobberize.h&quot;
</span><span class="cx"> #include &quot;DFGEdgeUsesStructure.h&quot;
</span><span class="cx"> #include &quot;DFGGraph.h&quot;
</span><span class="lines">@@ -39,984 +40,642 @@
</span><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><del>-class CSEPhase : public Phase {
</del><ins>+// This file contains two CSE implementations: local and global. LocalCSE typically runs when we're
+// in DFG mode, i.e. we want to compile quickly. LocalCSE contains a lot of optimizations for
+// compile time. GlobalCSE, on the other hand, is fairly straight-forward. It will find more
+// optimization opportunities by virtue of being global.
+
+namespace {
+
+const bool verbose = false;
+
+class ClobberFilter {
</ins><span class="cx"> public:
</span><del>-    CSEPhase(Graph&amp; graph)
-        : Phase(graph, &quot;common subexpression elimination&quot;)
</del><ins>+    ClobberFilter(AbstractHeap heap)
+        : m_heap(heap)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool run()
</del><ins>+    bool operator()(const ImpureMap::KeyValuePairType&amp; pair) const
</ins><span class="cx">     {
</span><del>-        ASSERT(m_graph.m_fixpointState != BeforeFixpoint);
-        
-        m_changed = false;
-        
-        m_graph.clearReplacements();
-        
-        if (m_graph.m_form == SSA) {
-            Vector&lt;BasicBlock*&gt; depthFirst;
-            m_graph.getBlocksInDepthFirstOrder(depthFirst);
-            for (unsigned i = 0; i &lt; depthFirst.size(); ++i)
-                performBlockCSE(depthFirst[i]);
-        } else {
-            for (unsigned blockIndex = 0; blockIndex &lt; m_graph.numBlocks(); ++blockIndex)
-                performBlockCSE(m_graph.block(blockIndex));
-        }
-        
-        return m_changed;
</del><ins>+        return m_heap.overlaps(pair.key.heap());
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx"> private:
</span><del>-    
-    unsigned endIndexForPureCSE()
-    {
-        unsigned result = m_lastSeen[m_currentNode-&gt;op()];
-        if (result == UINT_MAX)
-            result = 0;
-        else
-            result++;
-        ASSERT(result &lt;= m_indexInBlock);
-        return result;
-    }
</del><ins>+    AbstractHeap m_heap;
+};
</ins><span class="cx"> 
</span><del>-    Node* pureCSE(Node* node)
-    {
-        Edge child1 = node-&gt;child1().sanitized();
-        Edge child2 = node-&gt;child2().sanitized();
-        Edge child3 = node-&gt;child3().sanitized();
-        
-        for (unsigned i = endIndexForPureCSE(); i--;) {
-            Node* otherNode = m_currentBlock-&gt;at(i);
-            if (otherNode == child1 || otherNode == child2 || otherNode == child3)
-                break;
</del><ins>+inline void clobber(ImpureMap&amp; map, AbstractHeap heap)
+{
+    ClobberFilter filter(heap);
+    map.removeIf(filter);
+}
</ins><span class="cx"> 
</span><del>-            if (node-&gt;op() != otherNode-&gt;op())
-                continue;
-            
-            Edge otherChild = otherNode-&gt;child1().sanitized();
-            if (!otherChild)
-                return otherNode;
-            if (otherChild != child1)
-                continue;
-            
-            otherChild = otherNode-&gt;child2().sanitized();
-            if (!otherChild)
-                return otherNode;
-            if (otherChild != child2)
-                continue;
-            
-            otherChild = otherNode-&gt;child3().sanitized();
-            if (!otherChild)
-                return otherNode;
-            if (otherChild != child3)
-                continue;
-            
-            return otherNode;
-        }
-        return 0;
</del><ins>+class LocalCSEPhase : public Phase {
+public:
+    LocalCSEPhase(Graph&amp; graph)
+        : Phase(graph, &quot;local common subexpression elimination&quot;)
+        , m_smallBlock(graph)
+        , m_largeBlock(graph)
+    {
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* constantCSE(Node* node)
</del><ins>+    bool run()
</ins><span class="cx">     {
</span><del>-        for (unsigned i = endIndexForPureCSE(); i--;) {
-            Node* otherNode = m_currentBlock-&gt;at(i);
-            if (otherNode-&gt;op() != node-&gt;op())
</del><ins>+        ASSERT(m_graph.m_fixpointState == FixpointNotConverged);
+        ASSERT(m_graph.m_form == ThreadedCPS || m_graph.m_form == LoadStore);
+        
+        bool changed = false;
+        
+        m_graph.clearReplacements();
+        
+        for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
</ins><span class="cx">                 continue;
</span><span class="cx">             
</span><del>-            if (otherNode-&gt;constant() != node-&gt;constant())
-                continue;
-            
-            return otherNode;
</del><ins>+            if (block-&gt;size() &lt;= SmallMaps::capacity)
+                changed |= m_smallBlock.run(block);
+            else
+                changed |= m_largeBlock.run(block);
</ins><span class="cx">         }
</span><del>-        return 0;
</del><ins>+        
+        return changed;
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* constantStoragePointerCSE(Node* node)
-    {
-        for (unsigned i = endIndexForPureCSE(); i--;) {
-            Node* otherNode = m_currentBlock-&gt;at(i);
-            if (otherNode-&gt;op() != ConstantStoragePointer)
-                continue;
-            
-            if (otherNode-&gt;storagePointer() != node-&gt;storagePointer())
-                continue;
-            
-            return otherNode;
</del><ins>+private:
+    class SmallMaps {
+    public:
+        // This permits SmallMaps to be used for blocks that have up to 100 nodes. In practice,
+        // fewer than half of the nodes in a block have pure defs, and even fewer have impure defs.
+        // Thus, a capacity limit of 100 probably means that somewhere around ~40 things may end up
+        // in one of these &quot;small&quot; list-based maps. That number still seems largeish, except that
+        // the overhead of HashMaps can be quite high currently: clearing them, or even removing
+        // enough things from them, deletes (or resizes) their backing store eagerly. Hence
+        // HashMaps induce a lot of malloc traffic.
+        static const unsigned capacity = 100;
+    
+        SmallMaps()
+            : m_pureLength(0)
+            , m_impureLength(0)
+        {
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
</del><span class="cx">     
</span><del>-    Node* getCalleeLoadElimination()
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            switch (node-&gt;op()) {
-            case GetCallee:
-                return node;
-            default:
-                break;
-            }
</del><ins>+        void clear()
+        {
+            m_pureLength = 0;
+            m_impureLength = 0;
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
</del><span class="cx">     
</span><del>-    Node* getArrayLengthElimination(Node* array)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            switch (node-&gt;op()) {
-            case GetArrayLength:
-                if (node-&gt;child1() == array)
-                    return node;
-                break;
-                
-            case PutByValDirect:
-            case PutByVal:
-                if (!m_graph.byValIsPure(node))
-                    return 0;
-                if (node-&gt;arrayMode().mayStoreToHole())
-                    return 0;
-                break;
-                
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return 0;
</del><ins>+        void write(AbstractHeap heap)
+        {
+            for (unsigned i = 0; i &lt; m_impureLength; ++i) {
+                if (heap.overlaps(m_impureMap[i].key.heap()))
+                    m_impureMap[i--] = m_impureMap[--m_impureLength];
</ins><span class="cx">             }
</span><span class="cx">         }
</span><del>-        return 0;
-    }
</del><span class="cx">     
</span><del>-    Node* globalVarLoadElimination(WriteBarrier&lt;Unknown&gt;* registerPointer)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            switch (node-&gt;op()) {
-            case GetGlobalVar:
-                if (node-&gt;registerPointer() == registerPointer)
-                    return node;
-                break;
-            case PutGlobalVar:
-                if (node-&gt;registerPointer() == registerPointer)
-                    return node-&gt;child1().node();
-                break;
-            default:
-                break;
</del><ins>+        Node* addPure(PureValue value, Node* node)
+        {
+            for (unsigned i = m_pureLength; i--;) {
+                if (m_pureMap[i].key == value)
+                    return m_pureMap[i].value;
</ins><span class="cx">             }
</span><del>-            if (m_graph.clobbersWorld(node))
-                break;
</del><ins>+        
+            ASSERT(m_pureLength &lt; capacity);
+            m_pureMap[m_pureLength++] = WTF::KeyValuePair&lt;PureValue, Node*&gt;(value, node);
+            return nullptr;
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
-    
-    Node* scopedVarLoadElimination(Node* registers, int varNumber)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            switch (node-&gt;op()) {
-            case GetClosureVar: {
-                if (node-&gt;child1() == registers &amp;&amp; node-&gt;varNumber() == varNumber)
-                    return node;
-                break;
-            } 
-            case PutClosureVar: {
-                if (node-&gt;varNumber() != varNumber)
-                    break;
-                if (node-&gt;child2() == registers)
-                    return node-&gt;child3().node();
-                return 0;
</del><ins>+        
+        Node* findReplacement(HeapLocation location)
+        {
+            for (unsigned i = m_impureLength; i--;) {
+                if (m_impureMap[i].key == location)
+                    return m_impureMap[i].value;
</ins><span class="cx">             }
</span><del>-            case SetLocal: {
-                VariableAccessData* variableAccessData = node-&gt;variableAccessData();
-                if (variableAccessData-&gt;isCaptured()
-                    &amp;&amp; variableAccessData-&gt;local() == static_cast&lt;VirtualRegister&gt;(varNumber))
-                    return 0;
-                break;
-            }
-            default:
-                break;
-            }
-            if (m_graph.clobbersWorld(node))
-                break;
</del><ins>+            return nullptr;
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
</del><span class="cx">     
</span><del>-    bool varInjectionWatchpointElimination()
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node-&gt;op() == VarInjectionWatchpoint)
-                return true;
-            if (m_graph.clobbersWorld(node))
-                break;
</del><ins>+        Node* addImpure(HeapLocation location, Node* node)
+        {
+            if (Node* result = findReplacement(location))
+                return result;
+            ASSERT(m_impureLength &lt; capacity);
+            m_impureMap[m_impureLength++] = WTF::KeyValuePair&lt;HeapLocation, Node*&gt;(location, node);
+            return nullptr;
</ins><span class="cx">         }
</span><del>-        return false;
-    }
</del><span class="cx">     
</span><del>-    Node* getByValLoadElimination(Node* child1, Node* child2, ArrayMode arrayMode)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1 || node == child2) 
-                break;
</del><ins>+    private:
+        WTF::KeyValuePair&lt;PureValue, Node*&gt; m_pureMap[capacity];
+        WTF::KeyValuePair&lt;HeapLocation, Node*&gt; m_impureMap[capacity];
+        unsigned m_pureLength;
+        unsigned m_impureLength;
+    };
</ins><span class="cx"> 
</span><del>-            switch (node-&gt;op()) {
-            case GetByVal:
-                if (!m_graph.byValIsPure(node))
-                    return 0;
-                if (node-&gt;child1() == child1
-                    &amp;&amp; node-&gt;child2() == child2
-                    &amp;&amp; node-&gt;arrayMode().type() == arrayMode.type())
-                    return node;
-                break;
-                    
-            case PutByValDirect:
-            case PutByVal:
-            case PutByValAlias: {
-                if (!m_graph.byValIsPure(node))
-                    return 0;
-                // Typed arrays 
-                if (arrayMode.typedArrayType() != NotTypedArray)
-                    return 0;
-                if (m_graph.varArgChild(node, 0) == child1
-                    &amp;&amp; m_graph.varArgChild(node, 1) == child2
-                    &amp;&amp; node-&gt;arrayMode().type() == arrayMode.type())
-                    return m_graph.varArgChild(node, 2).node();
-                // We must assume that the PutByVal will clobber the location we're getting from.
-                // FIXME: We can do better; if we know that the PutByVal is accessing an array of a
-                // different type than the GetByVal, then we know that they won't clobber each other.
-                // ... except of course for typed arrays, where all typed arrays clobber all other
-                // typed arrays!  An Int32Array can alias a Float64Array for example, and so on.
-                return 0;
-            }
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return 0;
-                break;
-            }
</del><ins>+    class LargeMaps {
+    public:
+        LargeMaps()
+        {
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
-
-    bool checkFunctionElimination(FrozenValue* function, Node* child1)
-    {
-        for (unsigned i = endIndexForPureCSE(); i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1) 
-                break;
-
-            if (node-&gt;op() == CheckFunction &amp;&amp; node-&gt;child1() == child1 &amp;&amp; node-&gt;function() == function)
-                return true;
</del><ins>+    
+        void clear()
+        {
+            m_pureMap.clear();
+            m_impureMap.clear();
</ins><span class="cx">         }
</span><del>-        return false;
-    }
</del><span class="cx">     
</span><del>-    bool checkExecutableElimination(ExecutableBase* executable, Node* child1)
-    {
-        for (unsigned i = endIndexForPureCSE(); i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1)
-                break;
-
-            if (node-&gt;op() == CheckExecutable &amp;&amp; node-&gt;child1() == child1 &amp;&amp; node-&gt;executable() == executable)
-                return true;
</del><ins>+        void write(AbstractHeap heap)
+        {
+            clobber(m_impureMap, heap);
</ins><span class="cx">         }
</span><del>-        return false;
-    }
-
-    bool checkStructureElimination(const StructureSet&amp; structureSet, Node* child1)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1) 
-                break;
-
-            switch (node-&gt;op()) {
-            case CheckStructure:
-                if (node-&gt;child1() == child1
-                    &amp;&amp; structureSet.isSupersetOf(node-&gt;structureSet()))
-                    return true;
-                break;
-                
-            case PutStructure:
-                if (node-&gt;child1() == child1
-                    &amp;&amp; structureSet.contains(node-&gt;transition()-&gt;next))
-                    return true;
-                if (structureSet.contains(node-&gt;transition()-&gt;previous))
-                    return false;
-                break;
-                
-            case PutByOffset:
-                // Setting a property cannot change the structure.
-                break;
-                
-            case MultiPutByOffset:
-                if (node-&gt;multiPutByOffsetData().writesStructures())
-                    return false;
-                break;
-                
-            case PutByValDirect:
-            case PutByVal:
-            case PutByValAlias:
-                if (m_graph.byValIsPure(node)) {
-                    // If PutByVal speculates that it's accessing an array with an
-                    // integer index, then it's impossible for it to cause a structure
-                    // change.
-                    break;
-                }
-                return false;
-                
-            case Arrayify:
-            case ArrayifyToStructure:
-                // We could check if the arrayification could affect our structures.
-                // But that seems like it would take Effort.
-                return false;
-                
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return false;
-                break;
-            }
</del><ins>+    
+        Node* addPure(PureValue value, Node* node)
+        {
+            auto result = m_pureMap.add(value, node);
+            if (result.isNewEntry)
+                return nullptr;
+            return result.iterator-&gt;value;
</ins><span class="cx">         }
</span><del>-        return false;
-    }
</del><ins>+        
+        Node* findReplacement(HeapLocation location)
+        {
+            return m_impureMap.get(location);
+        }
</ins><span class="cx">     
</span><del>-    bool structureTransitionWatchpointElimination(Structure* structure, Node* child1)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1) 
-                break;
</del><ins>+        Node* addImpure(HeapLocation location, Node* node)
+        {
+            auto result = m_impureMap.add(location, node);
+            if (result.isNewEntry)
+                return nullptr;
+            return result.iterator-&gt;value;
+        }
</ins><span class="cx"> 
</span><del>-            switch (node-&gt;op()) {
-            case CheckStructure:
-                if (node-&gt;child1() == child1
-                    &amp;&amp; node-&gt;structureSet().isSubsetOf(StructureSet(structure)))
-                    return true;
-                break;
-                
-            case PutStructure:
-                ASSERT(node-&gt;transition()-&gt;previous != structure);
-                break;
-                
-            case PutByOffset:
-                // Setting a property cannot change the structure.
-                break;
-                    
-            case MultiPutByOffset:
-                if (node-&gt;multiPutByOffsetData().writesStructures())
-                    return false;
-                break;
-                
-            case PutByValDirect:
-            case PutByVal:
-            case PutByValAlias:
-                if (m_graph.byValIsPure(node)) {
-                    // If PutByVal speculates that it's accessing an array with an
-                    // integer index, then it's impossible for it to cause a structure
-                    // change.
-                    break;
-                }
-                return false;
-                
-            case Arrayify:
-            case ArrayifyToStructure:
-                // We could check if the arrayification could affect our structures.
-                // But that seems like it would take Effort.
-                return false;
-                
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return false;
-                break;
-            }
</del><ins>+    private:
+        HashMap&lt;PureValue, Node*&gt; m_pureMap;
+        HashMap&lt;HeapLocation, Node*&gt; m_impureMap;
+    };
+
+    template&lt;typename Maps&gt;
+    class BlockCSE {
+    public:
+        BlockCSE(Graph&amp; graph)
+            : m_graph(graph)
+        {
</ins><span class="cx">         }
</span><del>-        return false;
-    }
</del><span class="cx">     
</span><del>-    Node* getByOffsetLoadElimination(unsigned identifierNumber, Node* base)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == base)
-                break;
</del><ins>+        bool run(BasicBlock* block)
+        {
+            m_maps.clear();
+            m_changed = false;
+        
+            for (unsigned nodeIndex = 0; nodeIndex &lt; block-&gt;size(); ++nodeIndex) {
+                m_node = block-&gt;at(nodeIndex);
+                m_graph.performSubstitution(m_node);
+            
+                if (m_node-&gt;op() == Identity) {
+                    m_node-&gt;replaceWith(m_node-&gt;child1().node());
+                    m_changed = true;
+                } else {
+                    // This rule only makes sense for local CSE, since in SSA form we have already
+                    // factored the bounds check out of the PutByVal. It's kind of gross, but we
+                    // still have reason to believe that PutByValAlias is a good optimization and
+                    // that it's better to do it with a single node rather than separating out the
+                    // CheckInBounds.
+                    if (m_node-&gt;op() == PutByVal || m_node-&gt;op() == PutByValDirect) {
+                        HeapLocation heap;
+                        
+                        Node* base = m_graph.varArgChild(m_node, 0).node();
+                        Node* index = m_graph.varArgChild(m_node, 1).node();
+                        
+                        ArrayMode mode = m_node-&gt;arrayMode();
+                        switch (mode.type()) {
+                        case Array::Int32:
+                            if (!mode.isInBounds())
+                                break;
+                            heap = HeapLocation(
+                                IndexedPropertyLoc, IndexedInt32Properties, base, index);
+                            break;
+                            
+                        case Array::Double:
+                            if (!mode.isInBounds())
+                                break;
+                            heap = HeapLocation(
+                                IndexedPropertyLoc, IndexedDoubleProperties, base, index);
+                            break;
+                            
+                        case Array::Contiguous:
+                            if (!mode.isInBounds())
+                                break;
+                            heap = HeapLocation(
+                                IndexedPropertyLoc, IndexedContiguousProperties, base, index);
+                            break;
+                            
+                        case Array::Int8Array:
+                        case Array::Int16Array:
+                        case Array::Int32Array:
+                        case Array::Uint8Array:
+                        case Array::Uint8ClampedArray:
+                        case Array::Uint16Array:
+                        case Array::Uint32Array:
+                        case Array::Float32Array:
+                        case Array::Float64Array:
+                            if (!mode.isInBounds())
+                                break;
+                            heap = HeapLocation(
+                                IndexedPropertyLoc, TypedArrayProperties, base, index);
+                            break;
+                            
+                        default:
+                            break;
+                        }
</ins><span class="cx"> 
</span><del>-            switch (node-&gt;op()) {
-            case GetByOffset:
-                if (node-&gt;child2() == base
-                    &amp;&amp; m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber == identifierNumber)
-                    return node;
-                break;
-                
-            case MultiGetByOffset:
-                if (node-&gt;child1() == base
-                    &amp;&amp; node-&gt;multiGetByOffsetData().identifierNumber == identifierNumber)
-                    return node;
-                break;
-                
-            case PutByOffset:
-                if (m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber == identifierNumber) {
-                    if (node-&gt;child2() == base) // Must be same property storage.
-                        return node-&gt;child3().node();
-                    return 0;
</del><ins>+                        if (!!heap &amp;&amp; m_maps.findReplacement(heap))
+                            m_node-&gt;setOp(PutByValAlias);
+                    }
+
+                    clobberize(m_graph, m_node, *this);
</ins><span class="cx">                 }
</span><del>-                break;
-                
-            case MultiPutByOffset:
-                if (node-&gt;multiPutByOffsetData().identifierNumber == identifierNumber) {
-                    if (node-&gt;child1() == base)
-                        return node-&gt;child2().node();
-                    return 0;
-                }
-                break;
-                    
-            case PutByValDirect:
-            case PutByVal:
-            case PutByValAlias:
-                if (m_graph.byValIsPure(node)) {
-                    // If PutByVal speculates that it's accessing an array with an
-                    // integer index, then it's impossible for it to cause a structure
-                    // change.
-                    break;
-                }
-                return 0;
-                
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return 0;
-                break;
</del><span class="cx">             }
</span><ins>+        
+            return m_changed;
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
</del><span class="cx">     
</span><del>-    Node* getGetterSetterByOffsetLoadElimination(unsigned identifierNumber, Node* base)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == base)
-                break;
</del><ins>+        void read(AbstractHeap) { }
+    
+        void write(AbstractHeap heap)
+        {
+            m_maps.write(heap);
+        }
+        
+        void def(PureValue value)
+        {
+            Node* match = m_maps.addPure(value, m_node);
+            if (!match)
+                return;
</ins><span class="cx"> 
</span><del>-            switch (node-&gt;op()) {
-            case GetGetterSetterByOffset:
-                if (node-&gt;child2() == base
-                    &amp;&amp; m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber == identifierNumber)
-                    return node;
-                break;
-                    
-            case PutByValDirect:
-            case PutByVal:
-            case PutByValAlias:
-                if (m_graph.byValIsPure(node)) {
-                    // If PutByVal speculates that it's accessing an array with an
-                    // integer index, then it's impossible for it to cause a structure
-                    // change.
-                    break;
-                }
-                return 0;
-                
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return 0;
-                break;
-            }
</del><ins>+            m_node-&gt;replaceWith(match);
+            m_changed = true;
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
</del><span class="cx">     
</span><del>-    Node* getPropertyStorageLoadElimination(Node* child1)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1) 
-                break;
-
-            switch (node-&gt;op()) {
-            case GetButterfly:
-                if (node-&gt;child1() == child1)
-                    return node;
-                break;
-
-            case AllocatePropertyStorage:
-            case ReallocatePropertyStorage:
-                // If we can cheaply prove this is a change to our object's storage, we
-                // can optimize and use its result.
-                if (node-&gt;child1() == child1)
-                    return node;
-                // Otherwise, we currently can't prove that this doesn't change our object's
-                // storage, so we conservatively assume that it may change the storage
-                // pointer of any object, including ours.
-                return 0;
-                    
-            case PutByValDirect:
-            case PutByVal:
-            case PutByValAlias:
-                if (m_graph.byValIsPure(node)) {
-                    // If PutByVal speculates that it's accessing an array with an
-                    // integer index, then it's impossible for it to cause a structure
-                    // change.
-                    break;
-                }
-                return 0;
-                
-            case Arrayify:
-            case ArrayifyToStructure:
-                // We could check if the arrayification could affect our butterfly.
-                // But that seems like it would take Effort.
-                return 0;
-                
-            case MultiPutByOffset:
-                if (node-&gt;multiPutByOffsetData().reallocatesStorage())
-                    return 0;
-                break;
-                
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return 0;
-                break;
</del><ins>+        void def(HeapLocation location, Node* value)
+        {
+            Node* match = m_maps.addImpure(location, value);
+            if (!match)
+                return;
+        
+            if (m_node-&gt;op() == GetLocal) {
+                // For uncaptured locals, usually the CPS rethreading phase does this. But it's OK
+                // for us to mess with locals - regardless of their capturedness - so long as:
+                // 
+                // - We dethread the graph. Any changes we make may invalidate the assumptions of
+                //   our CPS form, particularly if this GetLocal is linked to the variablesAtTail.
+                //
+                // - We don't introduce a Phantom for the child of the GetLocal. This wouldn't be
+                //   totally wrong but it would pessimize the code. Just because there is a
+                //   GetLocal doesn't mean that the child was live. Simply rerouting the all uses
+                //   of this GetLocal will preserve the live-at-exit information just fine.
+                //
+                // We accomplish the latter by just clearing the child; then the Phantom that we
+                // introduce won't have children and so it will eventually just be deleted.
+            
+                m_node-&gt;child1() = Edge();
+                m_graph.dethread();
</ins><span class="cx">             }
</span><ins>+        
+            m_node-&gt;replaceWith(match);
+            m_changed = true;
</ins><span class="cx">         }
</span><del>-        return 0;
-    }
</del><span class="cx">     
</span><del>-    bool checkArrayElimination(Node* child1, ArrayMode arrayMode)
-    {
-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1) 
-                break;
</del><ins>+    private:
+        Graph&amp; m_graph;
+        
+        bool m_changed;
+        Node* m_node;
+    
+        Maps m_maps;
+    };
</ins><span class="cx"> 
</span><del>-            switch (node-&gt;op()) {
-            case CheckArray:
-                if (node-&gt;child1() == child1 &amp;&amp; node-&gt;arrayMode() == arrayMode)
-                    return true;
-                break;
-                
-            case Arrayify:
-            case ArrayifyToStructure:
-                // We could check if the arrayification could affect our array.
-                // But that seems like it would take Effort.
-                return false;
-                
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return false;
-                break;
-            }
-        }
-        return false;
-    }
</del><ins>+    BlockCSE&lt;SmallMaps&gt; m_smallBlock;
+    BlockCSE&lt;LargeMaps&gt; m_largeBlock;
+};
</ins><span class="cx"> 
</span><del>-    Node* getIndexedPropertyStorageLoadElimination(Node* child1, ArrayMode arrayMode)
</del><ins>+class GlobalCSEPhase : public Phase {
+public:
+    GlobalCSEPhase(Graph&amp; graph)
+        : Phase(graph, &quot;global common subexpression elimination&quot;)
</ins><span class="cx">     {
</span><del>-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1) 
-                break;
-
-            switch (node-&gt;op()) {
-            case GetIndexedPropertyStorage: {
-                if (node-&gt;child1() == child1 &amp;&amp; node-&gt;arrayMode() == arrayMode)
-                    return node;
-                break;
-            }
-
-            default:
-                if (m_graph.clobbersWorld(node))
-                    return 0;
-                break;
-            }
-        }
-        return 0;
</del><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* getInternalFieldLoadElimination(NodeType op, Node* child1)
</del><ins>+    bool run()
</ins><span class="cx">     {
</span><del>-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node == child1) 
-                break;
</del><ins>+        ASSERT(m_graph.m_fixpointState == FixpointNotConverged);
+        ASSERT(m_graph.m_form == SSA);
+        
+        m_graph.initializeNodeOwners();
+        m_graph.m_dominators.computeIfNecessary(m_graph);
+        
+        m_graph.getBlocksInPreOrder(m_preOrder);
+        
+        m_impureDataMap.resize(m_graph.numBlocks());
+        
+        // First figure out what gets clobbered by blocks. Node that this uses the preOrder list
+        // for convenience only.
+        for (unsigned i = m_preOrder.size(); i--;) {
+            m_block = m_preOrder[i];
+            m_impureData = &amp;m_impureDataMap[m_block-&gt;index];
+            for (unsigned nodeIndex = m_block-&gt;size(); nodeIndex--;)
+                addWrites(m_graph, m_block-&gt;at(nodeIndex), m_impureData-&gt;writes);
+        }
+        
+        // Based on my experience doing this before, what follows might have to be made iterative.
+        // Right now it doesn't have to be iterative because everything is dominator-bsed. But when
+        // validation is enabled, we check if iterating would find new CSE opportunities.
</ins><span class="cx"> 
</span><del>-            if (node-&gt;op() == op &amp;&amp; node-&gt;child1() == child1)
-                return node;
-
-            if (m_graph.clobbersWorld(node))
-                return 0;
</del><ins>+        bool changed = iterate();
+        
+        // Iterating a second time should not find new CSE opportunities, unless we have a bug.
+        if (validationEnabled()) {
+            reset();
+            DFG_ASSERT(m_graph, nullptr, !iterate());
</ins><span class="cx">         }
</span><del>-        return 0;
</del><ins>+        
+        return changed;
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* getMyScopeLoadElimination()
</del><ins>+    void reset()
</ins><span class="cx">     {
</span><del>-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            switch (node-&gt;op()) {
-            case CreateActivation:
-                // This may cause us to return a different scope.
-                return 0;
-            case GetMyScope:
-                return node;
-            default:
-                break;
-            }
</del><ins>+        m_pureValues.clear();
+        
+        for (unsigned i = m_impureDataMap.size(); i--;) {
+            m_impureDataMap[i].availableAtTail.clear();
+            m_impureDataMap[i].didVisit = false;
</ins><span class="cx">         }
</span><del>-        return 0;
</del><span class="cx">     }
</span><span class="cx">     
</span><del>-    Node* getLocalLoadElimination(VirtualRegister local, Node*&amp; relevantLocalOp, bool careAboutClobbering)
</del><ins>+    bool iterate()
</ins><span class="cx">     {
</span><del>-        relevantLocalOp = 0;
</del><ins>+        if (verbose)
+            dataLog(&quot;Performing iteration.\n&quot;);
</ins><span class="cx">         
</span><del>-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            switch (node-&gt;op()) {
-            case GetLocal:
-                if (node-&gt;local() == local) {
-                    relevantLocalOp = node;
-                    return node;
-                }
-                break;
</del><ins>+        m_changed = false;
+        m_graph.clearReplacements();
+        
+        for (unsigned i = 0; i &lt; m_preOrder.size(); ++i) {
+            m_block = m_preOrder[i];
+            m_impureData = &amp;m_impureDataMap[m_block-&gt;index];
+            m_writesSoFar.clear();
+            
+            if (verbose)
+                dataLog(&quot;Processing block &quot;, *m_block, &quot;:\n&quot;);
+
+            for (unsigned nodeIndex = 0; nodeIndex &lt; m_block-&gt;size(); ++nodeIndex) {
+                m_node = m_block-&gt;at(nodeIndex);
+                if (verbose)
+                    dataLog(&quot;  Looking at node &quot;, m_node, &quot;:\n&quot;);
</ins><span class="cx">                 
</span><del>-            case GetLocalUnlinked:
-                if (node-&gt;unlinkedLocal() == local) {
-                    relevantLocalOp = node;
-                    return node;
-                }
-                break;
</del><ins>+                m_graph.performSubstitution(m_node);
</ins><span class="cx">                 
</span><del>-            case SetLocal:
-                if (node-&gt;local() == local) {
-                    relevantLocalOp = node;
-                    return node-&gt;child1().node();
-                }
-                break;
-                
-            case GetClosureVar:
-            case PutClosureVar:
-                if (static_cast&lt;VirtualRegister&gt;(node-&gt;varNumber()) == local)
-                    return 0;
-                break;
-                
-            default:
-                if (careAboutClobbering &amp;&amp; m_graph.clobbersWorld(node))
-                    return 0;
-                break;
</del><ins>+                if (m_node-&gt;op() == Identity) {
+                    m_node-&gt;replaceWith(m_node-&gt;child1().node());
+                    m_changed = true;
+                } else
+                    clobberize(m_graph, m_node, *this);
</ins><span class="cx">             }
</span><ins>+            
+            m_impureData-&gt;didVisit = true;
</ins><span class="cx">         }
</span><del>-        return 0;
</del><ins>+        
+        return m_changed;
</ins><span class="cx">     }
</span><ins>+
+    void read(AbstractHeap) { }
</ins><span class="cx">     
</span><del>-    bool invalidationPointElimination()
</del><ins>+    void write(AbstractHeap heap)
</ins><span class="cx">     {
</span><del>-        for (unsigned i = m_indexInBlock; i--;) {
-            Node* node = m_currentBlock-&gt;at(i);
-            if (node-&gt;op() == InvalidationPoint)
-                return true;
-            if (writesOverlap(m_graph, node, Watchpoint_fire))
-                break;
-        }
-        return false;
</del><ins>+        clobber(m_impureData-&gt;availableAtTail, heap);
+        m_writesSoFar.add(heap);
+        if (verbose)
+            dataLog(&quot;    Clobbered, new tail map: &quot;, mapDump(m_impureData-&gt;availableAtTail), &quot;\n&quot;);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    bool setReplacement(Node* replacement)
</del><ins>+    void def(PureValue value)
</ins><span class="cx">     {
</span><del>-        if (!replacement)
-            return false;
</del><ins>+        // With pure values we do not have to worry about the possibility of some control flow path
+        // clobbering the value. So, we just search for all of the like values that have been
+        // computed. We pick one that is in a block that dominates ours. Note that this means that
+        // a PureValue will map to a list of nodes, since there may be many places in the control
+        // flow graph that compute a value but only one of them that dominates us. we may build up
+        // a large list of nodes that compute some value in the case of gnarly control flow. This
+        // is probably OK.
</ins><span class="cx">         
</span><del>-        m_currentNode-&gt;convertToPhantom();
</del><ins>+        auto result = m_pureValues.add(value, Vector&lt;Node*&gt;());
+        if (result.isNewEntry) {
+            result.iterator-&gt;value.append(m_node);
+            return;
+        }
</ins><span class="cx">         
</span><del>-        // At this point we will eliminate all references to this node.
-        m_currentNode-&gt;replacement = replacement;
</del><ins>+        for (unsigned i = result.iterator-&gt;value.size(); i--;) {
+            Node* candidate = result.iterator-&gt;value[i];
+            if (m_graph.m_dominators.dominates(candidate-&gt;owner, m_block)) {
+                m_node-&gt;replaceWith(candidate);
+                m_changed = true;
+                return;
+            }
+        }
</ins><span class="cx">         
</span><del>-        m_changed = true;
-        
-        return true;
</del><ins>+        result.iterator-&gt;value.append(m_node);
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    void eliminate()
</del><ins>+    Node* findReplacement(HeapLocation location)
</ins><span class="cx">     {
</span><del>-        ASSERT(m_currentNode-&gt;mustGenerate());
-        m_currentNode-&gt;convertToPhantom();
</del><ins>+        // At this instant, our &quot;availableAtTail&quot; reflects the set of things that are available in
+        // this block so far. We check this map to find block-local CSE opportunities before doing
+        // a global search.
+        Node* match = m_impureData-&gt;availableAtTail.get(location);
+        if (match) {
+            if (verbose)
+                dataLog(&quot;      Found local match: &quot;, match, &quot;\n&quot;);
+            return match;
+        }
</ins><span class="cx">         
</span><del>-        m_changed = true;
-    }
-    
-    void eliminate(Node* node, NodeType phantomType = Phantom)
-    {
-        if (!node)
-            return;
-        ASSERT(node-&gt;mustGenerate());
-        node-&gt;setOpAndDefaultFlags(phantomType);
</del><ins>+        // If it's not available at this point in the block, and at some prior point in the block
+        // we have clobbered this heap location, then there is no point in doing a global search.
+        if (m_writesSoFar.overlaps(location.heap())) {
+            if (verbose)
+                dataLog(&quot;      Not looking globally because of local clobber: &quot;, m_writesSoFar, &quot;\n&quot;);
+            return nullptr;
+        }
</ins><span class="cx">         
</span><del>-        m_changed = true;
-    }
-    
-    void performNodeCSE(Node* node)
-    {
-        m_graph.performSubstitution(node);
</del><ins>+        // This perfoms a backward search over the control flow graph to find some possible
+        // non-local def() that matches our heap location. Such a match is only valid if there does
+        // not exist any path from that def() to our block that contains a write() that overlaps
+        // our heap. This algorithm looks for both of these things (the matching def and the
+        // overlapping writes) in one backwards DFS pass.
+        //
+        // This starts by looking at the starting block's predecessors, and then it continues along
+        // their predecessors. As soon as this finds a possible def() - one that defines the heap
+        // location we want while dominating our starting block - it assumes that this one must be
+        // the match. It then lets the DFS over predecessors complete, but it doesn't add the
+        // def()'s predecessors; this ensures that any blocks we visit thereafter are on some path
+        // from the def() to us. As soon as the DFG finds a write() that overlaps the location's
+        // heap, it stops, assuming that there is no possible match. Note that the write() case may
+        // trigger before we find a def(), or after. Either way, the write() case causes this
+        // function to immediately return nullptr.
+        //
+        // If the write() is found before we find the def(), then we know that any def() we would
+        // find would have a path to us that trips over the write() and hence becomes invalid. This
+        // is just a direct outcome of us looking for a def() that dominates us. Given a block A
+        // that dominates block B - so that A is the one that would have the def() and B is our
+        // starting block - we know that any other block must either be on the path from A to B, or
+        // it must be on a path from the root to A, but not both. So, if we haven't found A yet but
+        // we already have found a block C that has a write(), then C must be on some path from A
+        // to B, which means that A's def() is invalid for our purposes. Hence, before we find the
+        // def(), stopping on write() is the right thing to do.
+        //
+        // Stopping on write() is also the right thing to do after we find the def(). After we find
+        // the def(), we don't add that block's predecessors to the search worklist. That means
+        // that henceforth the only blocks we will see in the search are blocks on the path from
+        // the def() to us. If any such block has a write() that clobbers our heap then we should
+        // give up.
+        //
+        // Hence this graph search algorithm ends up being deceptively simple: any overlapping
+        // write() causes us to immediately return nullptr, and a matching def() means that we just
+        // record it and neglect to visit its precessors.
</ins><span class="cx">         
</span><del>-        switch (node-&gt;op()) {
</del><ins>+        Vector&lt;BasicBlock*, 8&gt; worklist;
+        Vector&lt;BasicBlock*, 8&gt; seenList;
+        BitVector seen;
</ins><span class="cx">         
</span><del>-        case Identity:
-            setReplacement(node-&gt;child1().node());
-            break;
-            
-        // Handle the pure nodes. These nodes never have any side-effects.
-        case BitAnd:
-        case BitOr:
-        case BitXor:
-        case BitRShift:
-        case BitLShift:
-        case BitURShift:
-        case ArithAbs:
-        case ArithMin:
-        case ArithMax:
-        case ArithSqrt:
-        case ArithFRound:
-        case ArithSin:
-        case ArithCos:
-        case StringCharAt:
-        case StringCharCodeAt:
-        case IsUndefined:
-        case IsBoolean:
-        case IsNumber:
-        case IsString:
-        case IsObject:
-        case IsFunction:
-        case LogicalNot:
-        case SkipTopScope:
-        case SkipScope:
-        case GetClosureRegisters:
-        case GetScope:
-        case TypeOf:
-        case CompareEqConstant:
-        case ValueToInt32:
-        case MakeRope:
-        case DoubleRep:
-        case ValueRep:
-        case Int52Rep:
-            setReplacement(pureCSE(node));
-            break;
-            
-        case ArithAdd:
-        case ArithSub:
-        case ArithNegate:
-        case ArithMul:
-        case ArithDiv:
-        case ArithMod:
-        case UInt32ToNumber:
-        case DoubleAsInt32: {
-            Node* candidate = pureCSE(node);
-            if (!candidate)
-                break;
-            if (!subsumes(candidate-&gt;arithMode(), node-&gt;arithMode())) {
-                if (!subsumes(node-&gt;arithMode(), candidate-&gt;arithMode()))
-                    break;
-                candidate-&gt;setArithMode(node-&gt;arithMode());
</del><ins>+        for (unsigned i = m_block-&gt;predecessors.size(); i--;) {
+            BasicBlock* predecessor = m_block-&gt;predecessors[i];
+            if (!seen.get(predecessor-&gt;index)) {
+                worklist.append(predecessor);
+                seen.set(predecessor-&gt;index);
</ins><span class="cx">             }
</span><del>-            setReplacement(candidate);
-            break;
</del><span class="cx">         }
</span><ins>+        
+        while (!worklist.isEmpty()) {
+            BasicBlock* block = worklist.takeLast();
+            seenList.append(block);
</ins><span class="cx">             
</span><del>-        case GetCallee:
-            setReplacement(getCalleeLoadElimination());
-            break;
-
-        case GetLocal: {
-            VariableAccessData* variableAccessData = node-&gt;variableAccessData();
-            if (!variableAccessData-&gt;isCaptured())
-                break;
-            Node* relevantLocalOp;
-            Node* possibleReplacement = getLocalLoadElimination(variableAccessData-&gt;local(), relevantLocalOp, variableAccessData-&gt;isCaptured());
-            if (!relevantLocalOp)
-                break;
-            if (relevantLocalOp-&gt;op() != GetLocalUnlinked
-                &amp;&amp; relevantLocalOp-&gt;variableAccessData() != variableAccessData)
-                break;
-            Node* phi = node-&gt;child1().node();
-            if (!setReplacement(possibleReplacement))
-                break;
</del><ins>+            if (verbose)
+                dataLog(&quot;      Searching in block &quot;, *block, &quot;\n&quot;);
+            ImpureBlockData&amp; data = m_impureDataMap[block-&gt;index];
</ins><span class="cx">             
</span><del>-            m_graph.dethread();
</del><ins>+            // We require strict domination because this would only see things in our own block if
+            // they came *after* our position in the block. Clearly, while our block dominates
+            // itself, the things in the block after us don't dominate us.
+            if (m_graph.m_dominators.dominates(block, m_block) &amp;&amp; block != m_block) {
+                if (verbose)
+                    dataLog(&quot;        It strictly dominates.\n&quot;);
+                DFG_ASSERT(m_graph, m_node, data.didVisit);
+                DFG_ASSERT(m_graph, m_node, !match);
+                if (verbose)
+                    dataLog(&quot;        Availability map: &quot;, mapDump(data.availableAtTail), &quot;\n&quot;);
+                match = data.availableAtTail.get(location);
+                if (verbose)
+                    dataLog(&quot;        Availability: &quot;, match, &quot;\n&quot;);
+                if (match) {
+                    // Don't examine the predecessors of a match. At this point we just want to
+                    // establish that other blocks on the path from here to there don't clobber
+                    // the location we're interested in.
+                    continue;
+                }
+            }
</ins><span class="cx">             
</span><del>-            // If we replace a GetLocal with a GetLocalUnlinked, then turn the GetLocalUnlinked
-            // into a GetLocal.
-            if (relevantLocalOp-&gt;op() == GetLocalUnlinked)
-                relevantLocalOp-&gt;convertToGetLocal(variableAccessData, phi);
-
-            m_changed = true;
-            break;
-        }
-            
-        case GetLocalUnlinked: {
-            Node* relevantLocalOpIgnored;
-            setReplacement(getLocalLoadElimination(node-&gt;unlinkedLocal(), relevantLocalOpIgnored, true));
-            break;
-        }
-            
-        case JSConstant:
-        case DoubleConstant:
-        case Int52Constant:
-            // This is strange, but necessary. Some phases will convert nodes to constants,
-            // which may result in duplicated constants. We use CSE to clean this up.
-            setReplacement(constantCSE(node));
-            break;
-            
-        case ConstantStoragePointer:
-            setReplacement(constantStoragePointerCSE(node));
-            break;
-            
-        case GetArrayLength:
-            setReplacement(getArrayLengthElimination(node-&gt;child1().node()));
-            break;
-
-        case GetMyScope:
-            setReplacement(getMyScopeLoadElimination());
-            break;
-            
-        // Handle nodes that are conditionally pure: these are pure, and can
-        // be CSE'd, so long as the prediction is the one we want.
-        case CompareLess:
-        case CompareLessEq:
-        case CompareGreater:
-        case CompareGreaterEq:
-        case CompareEq: {
-            if (m_graph.isPredictedNumerical(node)) {
-                Node* replacement = pureCSE(node);
-                if (replacement &amp;&amp; m_graph.isPredictedNumerical(replacement))
-                    setReplacement(replacement);
</del><ins>+            if (verbose)
+                dataLog(&quot;        Dealing with write set &quot;, data.writes, &quot;\n&quot;);
+            if (data.writes.overlaps(location.heap())) {
+                if (verbose)
+                    dataLog(&quot;        Clobbered.\n&quot;);
+                return nullptr;
</ins><span class="cx">             }
</span><del>-            break;
-        }
</del><span class="cx">             
</span><del>-        // Finally handle heap accesses. These are not quite pure, but we can still
-        // optimize them provided that some subtle conditions are met.
-        case GetGlobalVar:
-            setReplacement(globalVarLoadElimination(node-&gt;registerPointer()));
-            break;
-
-        case GetClosureVar: {
-            setReplacement(scopedVarLoadElimination(node-&gt;child1().node(), node-&gt;varNumber()));
-            break;
-        }
-
-        case VarInjectionWatchpoint:
-            if (varInjectionWatchpointElimination())
-                eliminate();
-            break;
-            
-        case GetByVal:
-            if (m_graph.byValIsPure(node))
-                setReplacement(getByValLoadElimination(node-&gt;child1().node(), node-&gt;child2().node(), node-&gt;arrayMode()));
-            break;
-                
-        case PutByValDirect:
-        case PutByVal: {
-            Edge child1 = m_graph.varArgChild(node, 0);
-            Edge child2 = m_graph.varArgChild(node, 1);
-            if (node-&gt;arrayMode().canCSEStorage()) {
-                Node* replacement = getByValLoadElimination(child1.node(), child2.node(), node-&gt;arrayMode());
-                if (!replacement)
-                    break;
-                node-&gt;setOp(PutByValAlias);
</del><ins>+            for (unsigned i = block-&gt;predecessors.size(); i--;) {
+                BasicBlock* predecessor = block-&gt;predecessors[i];
+                if (!seen.get(predecessor-&gt;index)) {
+                    worklist.append(predecessor);
+                    seen.set(predecessor-&gt;index);
+                }
</ins><span class="cx">             }
</span><del>-            break;
</del><span class="cx">         }
</span><del>-            
-        case CheckStructure:
-            if (checkStructureElimination(node-&gt;structureSet(), node-&gt;child1().node()))
-                eliminate();
-            break;
-            
-        case CheckFunction:
-            if (checkFunctionElimination(node-&gt;function(), node-&gt;child1().node()))
-                eliminate();
-            break;
-                
-        case CheckExecutable:
-            if (checkExecutableElimination(node-&gt;executable(), node-&gt;child1().node()))
-                eliminate();
-            break;
-                
-        case CheckArray:
-            if (checkArrayElimination(node-&gt;child1().node(), node-&gt;arrayMode()))
-                eliminate();
-            break;
-            
-        case GetIndexedPropertyStorage: {
-            setReplacement(getIndexedPropertyStorageLoadElimination(node-&gt;child1().node(), node-&gt;arrayMode()));
-            break;
-        }
-            
-        case GetTypedArrayByteOffset:
-        case GetGetter:
-        case GetSetter: {
-            setReplacement(getInternalFieldLoadElimination(node-&gt;op(), node-&gt;child1().node()));
-            break;
-        }
-
-        case GetButterfly:
-            setReplacement(getPropertyStorageLoadElimination(node-&gt;child1().node()));
-            break;
-
-        case GetByOffset:
-            setReplacement(getByOffsetLoadElimination(m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber, node-&gt;child2().node()));
-            break;
-            
-        case GetGetterSetterByOffset:
-            setReplacement(getGetterSetterByOffsetLoadElimination(m_graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber, node-&gt;child2().node()));
-            break;
-            
-        case MultiGetByOffset:
-            setReplacement(getByOffsetLoadElimination(node-&gt;multiGetByOffsetData().identifierNumber, node-&gt;child1().node()));
-            break;
-            
-        case InvalidationPoint:
-            if (invalidationPointElimination())
-                eliminate();
-            break;
-            
-        default:
-            // do nothing.
-            break;
-        }
</del><span class="cx">         
</span><del>-        m_lastSeen[node-&gt;op()] = m_indexInBlock;
</del><ins>+        if (!match)
+            return nullptr;
+        
+        // Cache the results for next time. We cache them both for this block and for all of our
+        // predecessors, since even though we've already visited our predecessors, our predecessors
+        // probably have successors other than us.
+        // FIXME: Consider caching failed searches as well, when match is null. It's not clear that
+        // the reduction in compile time would warrant the increase in complexity, though.
+        // https://bugs.webkit.org/show_bug.cgi?id=134876
+        for (BasicBlock* block : seenList)
+            m_impureDataMap[block-&gt;index].availableAtTail.add(location, match);
+        m_impureData-&gt;availableAtTail.add(location, match);
+        
+        return match;
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    void performBlockCSE(BasicBlock* block)
</del><ins>+    void def(HeapLocation location, Node* value)
</ins><span class="cx">     {
</span><del>-        if (!block)
-            return;
-        if (!block-&gt;isReachable)
-            return;
</del><ins>+        if (verbose)
+            dataLog(&quot;    Got heap location def: &quot;, location, &quot; -&gt; &quot;, value, &quot;\n&quot;);
</ins><span class="cx">         
</span><del>-        m_currentBlock = block;
-        for (unsigned i = 0; i &lt; LastNodeType; ++i)
-            m_lastSeen[i] = UINT_MAX;
</del><ins>+        Node* match = findReplacement(location);
</ins><span class="cx">         
</span><del>-        for (m_indexInBlock = 0; m_indexInBlock &lt; block-&gt;size(); ++m_indexInBlock) {
-            m_currentNode = block-&gt;at(m_indexInBlock);
-            performNodeCSE(m_currentNode);
</del><ins>+        if (verbose)
+            dataLog(&quot;      Got match: &quot;, match, &quot;\n&quot;);
+        
+        if (!match) {
+            if (verbose)
+                dataLog(&quot;      Adding at-tail mapping: &quot;, location, &quot; -&gt; &quot;, value, &quot;\n&quot;);
+            auto result = m_impureData-&gt;availableAtTail.add(location, value);
+            ASSERT_UNUSED(result, result.isNewEntry);
+            return;
</ins><span class="cx">         }
</span><ins>+        
+        m_node-&gt;replaceWith(match);
+        m_changed = true;
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    BasicBlock* m_currentBlock;
-    Node* m_currentNode;
-    unsigned m_indexInBlock;
-    std::array&lt;unsigned, LastNodeType&gt; m_lastSeen;
-    bool m_changed; // Only tracks changes that have a substantive effect on other optimizations.
</del><ins>+    struct ImpureBlockData {
+        ImpureBlockData()
+            : didVisit(false)
+        {
+        }
+        
+        ClobberSet writes;
+        ImpureMap availableAtTail;
+        bool didVisit;
+    };
+    
+    Vector&lt;BasicBlock*&gt; m_preOrder;
+
+    PureMultiMap m_pureValues;
+    Vector&lt;ImpureBlockData&gt; m_impureDataMap;
+    
+    BasicBlock* m_block;
+    Node* m_node;
+    ImpureBlockData* m_impureData;
+    ClobberSet m_writesSoFar;
+    
+    bool m_changed;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-bool performCSE(Graph&amp; graph)
</del><ins>+} // anonymous namespace
+
+bool performLocalCSE(Graph&amp; graph)
</ins><span class="cx"> {
</span><del>-    SamplingRegion samplingRegion(&quot;DFG CSE Phase&quot;);
-    return runPhase&lt;CSEPhase&gt;(graph);
</del><ins>+    SamplingRegion samplingRegion(&quot;DFG LocalCSE Phase&quot;);
+    return runPhase&lt;LocalCSEPhase&gt;(graph);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool performGlobalCSE(Graph&amp; graph)
+{
+    SamplingRegion samplingRegion(&quot;DFG GlobalCSE Phase&quot;);
+    return runPhase&lt;GlobalCSEPhase&gt;(graph);
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><del>-
-
</del></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGCSEPhaseh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.h (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.h        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGCSEPhase.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -34,12 +34,21 @@
</span><span class="cx"> 
</span><span class="cx"> class Graph;
</span><span class="cx"> 
</span><del>-// Block-local common subexpression elimination. This is an optional phase, but
-// it is rather profitable. It has fairly accurate heap modeling and will match
-// a wide range of subexpression similarities. It's known to produce big wins
-// on a few benchmarks, and is relatively cheap to run.
-bool performCSE(Graph&amp;);
</del><ins>+// Block-local common subexpression elimination. It uses clobberize() for heap
+// modeling, which is quite precise. This phase is known to produce big wins on
+// a few benchmarks, and is relatively cheap to run.
+//
+// Note that this phase also gets rid of Identity nodes, which means that it's
+// currently not an optional phase. Basically, DFG IR doesn't have use-lists,
+// so there is no instantaneous replaceAllUsesWith operation. Instead, you turn
+// a node into an Identity and wait for CSE to clean it up.
+bool performLocalCSE(Graph&amp;);
</ins><span class="cx"> 
</span><ins>+// Same, but global. Only works for SSA. This will find common subexpressions
+// both in the same block and in any block that dominates the current block. It
+// has no limits on how far it will look for load-elimination opportunities.
+bool performGlobalCSE(Graph&amp;);
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGClobberSetcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberSet.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberSet.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberSet.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -122,37 +122,38 @@
</span><span class="cx"> void addReads(Graph&amp; graph, Node* node, ClobberSet&amp; readSet)
</span><span class="cx"> {
</span><span class="cx">     ClobberSetAdd addRead(readSet);
</span><del>-    NoOpClobberize addWrite;
-    clobberize(graph, node, addRead, addWrite);
</del><ins>+    NoOpClobberize noOp;
+    clobberize(graph, node, addRead, noOp, noOp);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void addWrites(Graph&amp; graph, Node* node, ClobberSet&amp; writeSet)
</span><span class="cx"> {
</span><del>-    NoOpClobberize addRead;
</del><ins>+    NoOpClobberize noOp;
</ins><span class="cx">     ClobberSetAdd addWrite(writeSet);
</span><del>-    clobberize(graph, node, addRead, addWrite);
</del><ins>+    clobberize(graph, node, noOp, addWrite, noOp);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void addReadsAndWrites(Graph&amp; graph, Node* node, ClobberSet&amp; readSet, ClobberSet&amp; writeSet)
</span><span class="cx"> {
</span><span class="cx">     ClobberSetAdd addRead(readSet);
</span><span class="cx">     ClobberSetAdd addWrite(writeSet);
</span><del>-    clobberize(graph, node, addRead, addWrite);
</del><ins>+    NoOpClobberize noOp;
+    clobberize(graph, node, addRead, addWrite, noOp);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool readsOverlap(Graph&amp; graph, Node* node, ClobberSet&amp; readSet)
</span><span class="cx"> {
</span><span class="cx">     ClobberSetOverlaps addRead(readSet);
</span><del>-    NoOpClobberize addWrite;
-    clobberize(graph, node, addRead, addWrite);
</del><ins>+    NoOpClobberize noOp;
+    clobberize(graph, node, addRead, noOp, noOp);
</ins><span class="cx">     return addRead.result();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool writesOverlap(Graph&amp; graph, Node* node, ClobberSet&amp; writeSet)
</span><span class="cx"> {
</span><del>-    NoOpClobberize addRead;
</del><ins>+    NoOpClobberize noOp;
</ins><span class="cx">     ClobberSetOverlaps addWrite(writeSet);
</span><del>-    clobberize(graph, node, addRead, addWrite);
</del><ins>+    clobberize(graph, node, noOp, addWrite, noOp);
</ins><span class="cx">     return addWrite.result();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGClobberizecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -34,24 +34,25 @@
</span><span class="cx"> 
</span><span class="cx"> bool doesWrites(Graph&amp; graph, Node* node)
</span><span class="cx"> {
</span><del>-    NoOpClobberize addRead;
</del><ins>+    NoOpClobberize noOp;
</ins><span class="cx">     CheckClobberize addWrite;
</span><del>-    clobberize(graph, node, addRead, addWrite);
</del><ins>+    clobberize(graph, node, noOp, addWrite, noOp);
</ins><span class="cx">     return addWrite.result();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool accessesOverlap(Graph&amp; graph, Node* node, AbstractHeap heap)
</span><span class="cx"> {
</span><ins>+    NoOpClobberize noOp;
</ins><span class="cx">     AbstractHeapOverlaps addAccess(heap);
</span><del>-    clobberize(graph, node, addAccess, addAccess);
</del><ins>+    clobberize(graph, node, addAccess, addAccess, noOp);
</ins><span class="cx">     return addAccess.result();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool writesOverlap(Graph&amp; graph, Node* node, AbstractHeap heap)
</span><span class="cx"> {
</span><del>-    NoOpClobberize addRead;
</del><ins>+    NoOpClobberize noOp;
</ins><span class="cx">     AbstractHeapOverlaps addWrite(heap);
</span><del>-    clobberize(graph, node, addRead, addWrite);
</del><ins>+    clobberize(graph, node, noOp, addWrite, noOp);
</ins><span class="cx">     return addWrite.result();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -31,11 +31,13 @@
</span><span class="cx"> #include &quot;DFGAbstractHeap.h&quot;
</span><span class="cx"> #include &quot;DFGEdgeUsesStructure.h&quot;
</span><span class="cx"> #include &quot;DFGGraph.h&quot;
</span><ins>+#include &quot;DFGHeapLocation.h&quot;
+#include &quot;DFGPureValue.h&quot;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><del>-template&lt;typename ReadFunctor, typename WriteFunctor&gt;
-void clobberize(Graph&amp; graph, Node* node, ReadFunctor&amp; read, WriteFunctor&amp; write)
</del><ins>+template&lt;typename ReadFunctor, typename WriteFunctor, typename DefFunctor&gt;
+void clobberize(Graph&amp; graph, Node* node, ReadFunctor&amp; read, WriteFunctor&amp; write, DefFunctor&amp; def)
</ins><span class="cx"> {
</span><span class="cx">     // Some notes:
</span><span class="cx">     //
</span><span class="lines">@@ -69,6 +71,29 @@
</span><span class="cx">     //   prior to type inference - though they probably could be if we did some
</span><span class="cx">     //   small hacking.
</span><span class="cx">     
</span><ins>+    // While read() and write() are fairly self-explanatory - they track what sorts of things the
+    // node may read or write - the def() functor is more tricky. It tells you the heap locations
+    // (not just abstract heaps) that are defined by a node. A heap location comprises an abstract
+    // heap, some nodes, and a LocationKind. Briefly, a location defined by a node is a location
+    // whose value can be deduced from looking at the node itself. The locations returned must obey
+    // the following properties:
+    //
+    // - If someone wants to CSE a load from the heap, then a HeapLocation object should be
+    //   sufficient to find a single matching node.
+    //
+    // - The abstract heap is the only abstract heap that could be clobbered to invalidate any such
+    //   CSE attempt. I.e. if clobberize() reports that on every path between some node and a node
+    //   that defines a HeapLocation that it wanted, there were no writes to any abstract heap that
+    //   overlap the location's heap, then we have a sound match. Effectively, the semantics of
+    //   write() and def() are intertwined such that for them to be sound they must agree on what
+    //   is CSEable.
+    //
+    // read(), write(), and def() for heap locations is enough to do GCSE on effectful things. To
+    // keep things simple, this code will also def() pure things. def() must be overloaded to also
+    // accept PureValue. This way, a client of clobberize() can implement GCSE entirely using the
+    // information that clobberize() passes to write() and def(). Other clients of clobberize() can
+    // just ignore def() by using a NoOpClobberize functor.
+
</ins><span class="cx">     if (edgesUseStructure(graph, node))
</span><span class="cx">         read(JSCell_structureID);
</span><span class="cx">     
</span><span class="lines">@@ -76,23 +101,23 @@
</span><span class="cx">     case JSConstant:
</span><span class="cx">     case DoubleConstant:
</span><span class="cx">     case Int52Constant:
</span><ins>+        def(PureValue(node, node-&gt;constant()));
+        return;
+        
</ins><span class="cx">     case Identity:
</span><span class="cx">     case Phantom:
</span><span class="cx">     case HardPhantom:
</span><ins>+    case Check:
+    case ExtractOSREntryLocal:
+        return;
+        
</ins><span class="cx">     case BitAnd:
</span><span class="cx">     case BitOr:
</span><span class="cx">     case BitXor:
</span><span class="cx">     case BitLShift:
</span><span class="cx">     case BitRShift:
</span><span class="cx">     case BitURShift:
</span><del>-    case ValueToInt32:
-    case ArithAdd:
-    case ArithSub:
-    case ArithNegate:
-    case ArithMul:
</del><span class="cx">     case ArithIMul:
</span><del>-    case ArithDiv:
-    case ArithMod:
</del><span class="cx">     case ArithAbs:
</span><span class="cx">     case ArithMin:
</span><span class="cx">     case ArithMax:
</span><span class="lines">@@ -100,30 +125,49 @@
</span><span class="cx">     case ArithFRound:
</span><span class="cx">     case ArithSin:
</span><span class="cx">     case ArithCos:
</span><ins>+    case ValueToInt32:
</ins><span class="cx">     case GetScope:
</span><span class="cx">     case SkipScope:
</span><del>-    case CheckFunction:
</del><ins>+    case CompareEqConstant:
+    case CompareStrictEq:
</ins><span class="cx">     case StringCharCodeAt:
</span><span class="cx">     case StringFromCharCode:
</span><del>-    case CompareEqConstant:
-    case CompareStrictEq:
</del><span class="cx">     case IsUndefined:
</span><span class="cx">     case IsBoolean:
</span><span class="cx">     case IsNumber:
</span><span class="cx">     case IsString:
</span><span class="cx">     case LogicalNot:
</span><del>-    case ExtractOSREntryLocal:
</del><span class="cx">     case CheckInBounds:
</span><del>-    case ConstantStoragePointer:
-    case UInt32ToNumber:
-    case DoubleAsInt32:
-    case Check:
</del><span class="cx">     case DoubleRep:
</span><span class="cx">     case ValueRep:
</span><span class="cx">     case Int52Rep:
</span><span class="cx">     case MakeRope:
</span><ins>+        def(PureValue(node));
</ins><span class="cx">         return;
</span><span class="cx">         
</span><ins>+    case ArithAdd:
+    case ArithSub:
+    case ArithNegate:
+    case ArithMul:
+    case ArithDiv:
+    case ArithMod:
+    case DoubleAsInt32:
+    case UInt32ToNumber:
+        def(PureValue(node, node-&gt;arithMode()));
+        return;
+
+    case CheckFunction:
+        def(PureValue(CheckFunction, AdjacencyList(AdjacencyList::Fixed, node-&gt;child1()), node-&gt;function()));
+        return;
+        
+    case CheckExecutable:
+        def(PureValue(node, node-&gt;executable()));
+        return;
+        
+    case ConstantStoragePointer:
+        def(PureValue(node, node-&gt;storagePointer()));
+        return;
+        
</ins><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><span class="cx">     case Upsilon:
</span><span class="lines">@@ -142,7 +186,6 @@
</span><span class="cx">     case CheckTierUpAtReturn:
</span><span class="cx">     case CheckTierUpAndOSREnter:
</span><span class="cx">     case LoopHint:
</span><del>-    case InvalidationPoint:
</del><span class="cx">     case Breakpoint:
</span><span class="cx">     case ProfileWillCall:
</span><span class="cx">     case ProfileDidCall:
</span><span class="lines">@@ -151,6 +194,11 @@
</span><span class="cx">         write(SideState);
</span><span class="cx">         return;
</span><span class="cx">         
</span><ins>+    case InvalidationPoint:
+        write(SideState);
+        def(HeapLocation(InvalidationPointLoc, Watchpoint_fire), node);
+        return;
+
</ins><span class="cx">     case Flush:
</span><span class="cx">         read(AbstractHeap(Variables, node-&gt;local()));
</span><span class="cx">         write(SideState);
</span><span class="lines">@@ -194,13 +242,30 @@
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="cx">     case VarInjectionWatchpoint:
</span><ins>+        read(MiscFields);
+        def(HeapLocation(VarInjectionWatchpointLoc, MiscFields), node);
+        return;
+
</ins><span class="cx">     case AllocationProfileWatchpoint:
</span><ins>+        read(MiscFields);
+        def(HeapLocation(AllocationProfileWatchpointLoc, MiscFields), node);
+        return;
+        
</ins><span class="cx">     case IsObject:
</span><ins>+        read(MiscFields);
+        def(HeapLocation(IsObjectLoc, MiscFields, node-&gt;child1()), node);
+        return;
+        
</ins><span class="cx">     case IsFunction:
</span><ins>+        read(MiscFields);
+        def(HeapLocation(IsFunctionLoc, MiscFields, node-&gt;child1()), node);
+        return;
+        
</ins><span class="cx">     case TypeOf:
</span><span class="cx">         read(MiscFields);
</span><ins>+        def(HeapLocation(TypeOfLoc, MiscFields, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><del>-        
</del><ins>+
</ins><span class="cx">     case GetById:
</span><span class="cx">     case GetByIdFlush:
</span><span class="cx">     case PutById:
</span><span class="lines">@@ -223,27 +288,33 @@
</span><span class="cx">         
</span><span class="cx">     case GetGetter:
</span><span class="cx">         read(GetterSetter_getter);
</span><ins>+        def(HeapLocation(GetterLoc, GetterSetter_getter, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetSetter:
</span><span class="cx">         read(GetterSetter_setter);
</span><ins>+        def(HeapLocation(SetterLoc, GetterSetter_setter, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetCallee:
</span><span class="cx">         read(AbstractHeap(Variables, JSStack::Callee));
</span><ins>+        def(HeapLocation(VariableLoc, AbstractHeap(Variables, JSStack::Callee)), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetLocal:
</span><span class="cx">     case GetArgument:
</span><span class="cx">         read(AbstractHeap(Variables, node-&gt;local()));
</span><ins>+        def(HeapLocation(VariableLoc, AbstractHeap(Variables, node-&gt;local())), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case SetLocal:
</span><span class="cx">         write(AbstractHeap(Variables, node-&gt;local()));
</span><ins>+        def(HeapLocation(VariableLoc, AbstractHeap(Variables, node-&gt;local())), node-&gt;child1().node());
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetLocalUnlinked:
</span><span class="cx">         read(AbstractHeap(Variables, node-&gt;unlinkedLocal()));
</span><ins>+        def(HeapLocation(VariableLoc, AbstractHeap(Variables, node-&gt;unlinkedLocal())), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetByVal: {
</span><span class="lines">@@ -273,18 +344,20 @@
</span><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">             // This appears to read nothing because it's only reading immutable data.
</span><ins>+            def(PureValue(node, mode.asWord()));
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::Arguments:
</span><span class="cx">             read(Arguments_registers);
</span><span class="cx">             read(Variables);
</span><ins>+            def(HeapLocation(IndexedPropertyLoc, Variables, node-&gt;child1(), node-&gt;child2()), node);
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::Int32:
</span><span class="cx">             if (mode.isInBounds()) {
</span><span class="cx">                 read(Butterfly_publicLength);
</span><del>-                read(Butterfly_vectorLength);
</del><span class="cx">                 read(IndexedInt32Properties);
</span><ins>+                def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, node-&gt;child1(), node-&gt;child2()), node);
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">             read(World);
</span><span class="lines">@@ -294,8 +367,8 @@
</span><span class="cx">         case Array::Double:
</span><span class="cx">             if (mode.isInBounds()) {
</span><span class="cx">                 read(Butterfly_publicLength);
</span><del>-                read(Butterfly_vectorLength);
</del><span class="cx">                 read(IndexedDoubleProperties);
</span><ins>+                def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, node-&gt;child1(), node-&gt;child2()), node);
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">             read(World);
</span><span class="lines">@@ -305,8 +378,8 @@
</span><span class="cx">         case Array::Contiguous:
</span><span class="cx">             if (mode.isInBounds()) {
</span><span class="cx">                 read(Butterfly_publicLength);
</span><del>-                read(Butterfly_vectorLength);
</del><span class="cx">                 read(IndexedContiguousProperties);
</span><ins>+                def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, node-&gt;child1(), node-&gt;child2()), node);
</ins><span class="cx">                 return;
</span><span class="cx">             }
</span><span class="cx">             read(World);
</span><span class="lines">@@ -315,7 +388,11 @@
</span><span class="cx">             
</span><span class="cx">         case Array::ArrayStorage:
</span><span class="cx">         case Array::SlowPutArrayStorage:
</span><del>-            // Give up on life for now.
</del><ins>+            if (mode.isInBounds()) {
+                read(Butterfly_vectorLength);
+                read(IndexedArrayStorageProperties);
+                return;
+            }
</ins><span class="cx">             read(World);
</span><span class="cx">             write(World);
</span><span class="cx">             return;
</span><span class="lines">@@ -330,8 +407,8 @@
</span><span class="cx">         case Array::Float32Array:
</span><span class="cx">         case Array::Float64Array:
</span><span class="cx">             read(TypedArrayProperties);
</span><del>-            read(JSArrayBufferView_vector);
-            read(JSArrayBufferView_length);
</del><ins>+            read(MiscFields);
+            def(HeapLocation(IndexedPropertyLoc, TypedArrayProperties, node-&gt;child1(), node-&gt;child2()), node);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="lines">@@ -342,6 +419,9 @@
</span><span class="cx">     case PutByVal:
</span><span class="cx">     case PutByValAlias: {
</span><span class="cx">         ArrayMode mode = node-&gt;arrayMode();
</span><ins>+        Node* base = graph.varArgChild(node, 0).node();
+        Node* index = graph.varArgChild(node, 1).node();
+        Node* value = graph.varArgChild(node, 2).node();
</ins><span class="cx">         switch (mode.modeForPut().type()) {
</span><span class="cx">         case Array::SelectUsingPredictions:
</span><span class="cx">         case Array::Unprofiled:
</span><span class="lines">@@ -363,9 +443,9 @@
</span><span class="cx">             
</span><span class="cx">         case Array::Arguments:
</span><span class="cx">             read(Arguments_registers);
</span><del>-            read(Arguments_numArguments);
-            read(Arguments_slowArguments);
</del><ins>+            read(MiscFields);
</ins><span class="cx">             write(Variables);
</span><ins>+            def(HeapLocation(IndexedPropertyLoc, Variables, base, index), value);
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::Int32:
</span><span class="lines">@@ -378,6 +458,9 @@
</span><span class="cx">             read(Butterfly_vectorLength);
</span><span class="cx">             read(IndexedInt32Properties);
</span><span class="cx">             write(IndexedInt32Properties);
</span><ins>+            if (node-&gt;arrayMode().mayStoreToHole())
+                write(Butterfly_publicLength);
+            def(HeapLocation(IndexedPropertyLoc, IndexedInt32Properties, base, index), value);
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::Double:
</span><span class="lines">@@ -390,6 +473,9 @@
</span><span class="cx">             read(Butterfly_vectorLength);
</span><span class="cx">             read(IndexedDoubleProperties);
</span><span class="cx">             write(IndexedDoubleProperties);
</span><ins>+            if (node-&gt;arrayMode().mayStoreToHole())
+                write(Butterfly_publicLength);
+            def(HeapLocation(IndexedPropertyLoc, IndexedDoubleProperties, base, index), value);
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::Contiguous:
</span><span class="lines">@@ -402,6 +488,9 @@
</span><span class="cx">             read(Butterfly_vectorLength);
</span><span class="cx">             read(IndexedContiguousProperties);
</span><span class="cx">             write(IndexedContiguousProperties);
</span><ins>+            if (node-&gt;arrayMode().mayStoreToHole())
+                write(Butterfly_publicLength);
+            def(HeapLocation(IndexedPropertyLoc, IndexedContiguousProperties, base, index), value);
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::ArrayStorage:
</span><span class="lines">@@ -420,9 +509,10 @@
</span><span class="cx">         case Array::Uint32Array:
</span><span class="cx">         case Array::Float32Array:
</span><span class="cx">         case Array::Float64Array:
</span><del>-            read(JSArrayBufferView_vector);
-            read(JSArrayBufferView_length);
</del><ins>+            read(MiscFields);
</ins><span class="cx">             write(TypedArrayProperties);
</span><ins>+            // FIXME: We can't def() anything here because these operations truncate their inputs.
+            // https://bugs.webkit.org/show_bug.cgi?id=134737
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="lines">@@ -430,7 +520,6 @@
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case CheckStructure:
</span><del>-    case InstanceOf:
</del><span class="cx">         read(JSCell_structureID);
</span><span class="cx">         return;
</span><span class="cx"> 
</span><span class="lines">@@ -442,12 +531,14 @@
</span><span class="cx"> 
</span><span class="cx">     case CheckHasInstance:
</span><span class="cx">         read(JSCell_typeInfoFlags);
</span><ins>+        def(HeapLocation(CheckHasInstanceLoc, JSCell_typeInfoFlags, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    case CheckExecutable:
-        read(JSFunction_executable);
</del><ins>+    case InstanceOf:
+        read(JSCell_structureID);
+        def(HeapLocation(InstanceOfLoc, JSCell_structureID, node-&gt;child1(), node-&gt;child2()), node);
</ins><span class="cx">         return;
</span><del>-        
</del><ins>+
</ins><span class="cx">     case PutStructure:
</span><span class="cx">         write(JSCell_structureID);
</span><span class="cx">         write(JSCell_typeInfoType);
</span><span class="lines">@@ -457,15 +548,18 @@
</span><span class="cx">         
</span><span class="cx">     case AllocatePropertyStorage:
</span><span class="cx">         write(JSObject_butterfly);
</span><ins>+        def(HeapLocation(ButterflyLoc, JSObject_butterfly, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case ReallocatePropertyStorage:
</span><span class="cx">         read(JSObject_butterfly);
</span><span class="cx">         write(JSObject_butterfly);
</span><ins>+        def(HeapLocation(ButterflyLoc, JSObject_butterfly, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetButterfly:
</span><span class="cx">         read(JSObject_butterfly);
</span><ins>+        def(HeapLocation(ButterflyLoc, JSObject_butterfly, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case Arrayify:
</span><span class="lines">@@ -479,42 +573,59 @@
</span><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetIndexedPropertyStorage:
</span><del>-        if (node-&gt;arrayMode().type() == Array::String)
</del><ins>+        if (node-&gt;arrayMode().type() == Array::String) {
+            def(PureValue(node, node-&gt;arrayMode().asWord()));
</ins><span class="cx">             return;
</span><del>-        read(JSArrayBufferView_vector);
</del><ins>+        }
+        read(MiscFields);
+        def(HeapLocation(IndexedPropertyStorageLoc, MiscFields, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetTypedArrayByteOffset:
</span><del>-        read(JSArrayBufferView_vector);
-        read(JSArrayBufferView_mode);
-        read(Butterfly_arrayBuffer);
-        read(ArrayBuffer_data);
</del><ins>+        read(MiscFields);
+        def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetByOffset:
</span><del>-    case GetGetterSetterByOffset:
-        read(AbstractHeap(NamedProperties, graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber));
</del><ins>+    case GetGetterSetterByOffset: {
+        unsigned identifierNumber =
+            graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber;
+        AbstractHeap heap(NamedProperties, identifierNumber);
+        read(heap);
+        def(HeapLocation(NamedPropertyLoc, heap, node-&gt;child2()), node);
</ins><span class="cx">         return;
</span><ins>+    }
</ins><span class="cx">         
</span><del>-    case MultiGetByOffset:
</del><ins>+    case MultiGetByOffset: {
</ins><span class="cx">         read(JSCell_structureID);
</span><span class="cx">         read(JSObject_butterfly);
</span><del>-        read(AbstractHeap(NamedProperties, node-&gt;multiGetByOffsetData().identifierNumber));
</del><ins>+        AbstractHeap heap(NamedProperties, node-&gt;multiGetByOffsetData().identifierNumber);
+        read(heap);
+        def(HeapLocation(NamedPropertyLoc, heap, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><ins>+    }
</ins><span class="cx">         
</span><del>-    case MultiPutByOffset:
</del><ins>+    case MultiPutByOffset: {
</ins><span class="cx">         read(JSCell_structureID);
</span><span class="cx">         read(JSObject_butterfly);
</span><del>-        write(AbstractHeap(NamedProperties, node-&gt;multiPutByOffsetData().identifierNumber));
</del><ins>+        AbstractHeap heap(NamedProperties, node-&gt;multiPutByOffsetData().identifierNumber);
+        write(heap);
</ins><span class="cx">         if (node-&gt;multiPutByOffsetData().writesStructures())
</span><span class="cx">             write(JSCell_structureID);
</span><span class="cx">         if (node-&gt;multiPutByOffsetData().reallocatesStorage())
</span><span class="cx">             write(JSObject_butterfly);
</span><ins>+        def(HeapLocation(NamedPropertyLoc, heap, node-&gt;child1()), node-&gt;child2().node());
</ins><span class="cx">         return;
</span><ins>+    }
</ins><span class="cx">         
</span><del>-    case PutByOffset:
-        write(AbstractHeap(NamedProperties, graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber));
</del><ins>+    case PutByOffset: {
+        unsigned identifierNumber =
+            graph.m_storageAccessData[node-&gt;storageAccessDataIndex()].identifierNumber;
+        AbstractHeap heap(NamedProperties, identifierNumber);
+        write(heap);
+        def(HeapLocation(NamedPropertyLoc, heap, node-&gt;child2()), node-&gt;child3().node());
</ins><span class="cx">         return;
</span><ins>+    }
</ins><span class="cx">         
</span><span class="cx">     case GetArrayLength: {
</span><span class="cx">         ArrayMode mode = node-&gt;arrayMode();
</span><span class="lines">@@ -525,78 +636,90 @@
</span><span class="cx">         case Array::ArrayStorage:
</span><span class="cx">         case Array::SlowPutArrayStorage:
</span><span class="cx">             read(Butterfly_publicLength);
</span><ins>+            def(HeapLocation(ArrayLengthLoc, Butterfly_publicLength, node-&gt;child1()), node);
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::String:
</span><ins>+            def(PureValue(node, mode.asWord()));
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case Array::Arguments:
</span><del>-            read(Arguments_overrideLength);
-            read(Arguments_numArguments);
</del><ins>+            read(MiscFields);
+            def(HeapLocation(ArrayLengthLoc, MiscFields, node-&gt;child1()), node);
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         default:
</span><del>-            read(JSArrayBufferView_length);
</del><ins>+            ASSERT(mode.typedArrayType() != NotTypedArray);
+            read(MiscFields);
+            def(HeapLocation(ArrayLengthLoc, MiscFields, node-&gt;child1()), node);
</ins><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">         
</span><span class="cx">     case GetMyScope:
</span><del>-        read(AbstractHeap(Variables, JSStack::ScopeChain));
</del><ins>+        if (graph.m_codeBlock-&gt;needsActivation()) {
+            read(AbstractHeap(Variables, JSStack::ScopeChain));
+            def(HeapLocation(VariableLoc, AbstractHeap(Variables, JSStack::ScopeChain)), node);
+        } else
+            def(PureValue(node));
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case SkipTopScope:
</span><span class="cx">         read(AbstractHeap(Variables, graph.activationRegister()));
</span><ins>+        def(HeapLocation(SkipTopScopeLoc, AbstractHeap(Variables, graph.activationRegister()), node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetClosureRegisters:
</span><span class="cx">         read(JSVariableObject_registers);
</span><ins>+        def(HeapLocation(ClosureRegistersLoc, JSVariableObject_registers, node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><del>-        
</del><ins>+
</ins><span class="cx">     case GetClosureVar:
</span><span class="cx">         read(AbstractHeap(Variables, node-&gt;varNumber()));
</span><ins>+        def(HeapLocation(ClosureVariableLoc, AbstractHeap(Variables, node-&gt;varNumber()), node-&gt;child1()), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case PutClosureVar:
</span><span class="cx">         write(AbstractHeap(Variables, node-&gt;varNumber()));
</span><ins>+        def(HeapLocation(ClosureVariableLoc, AbstractHeap(Variables, node-&gt;varNumber()), node-&gt;child2()), node-&gt;child3().node());
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetGlobalVar:
</span><span class="cx">         read(AbstractHeap(Absolute, node-&gt;registerPointer()));
</span><ins>+        def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node-&gt;registerPointer())), node);
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case PutGlobalVar:
</span><span class="cx">         write(AbstractHeap(Absolute, node-&gt;registerPointer()));
</span><ins>+        def(HeapLocation(GlobalVariableLoc, AbstractHeap(Absolute, node-&gt;registerPointer())), node-&gt;child1().node());
</ins><span class="cx">         return;
</span><span class="cx"> 
</span><del>-    case NewObject:
</del><span class="cx">     case NewArray:
</span><span class="cx">     case NewArrayWithSize:
</span><span class="cx">     case NewArrayBuffer:
</span><ins>+    case NewTypedArray:
+        // FIXME: Enable CSE for these nodes. We can't do this right now because there is no way
+        // for us to claim an index node and a value node. We could make this work if we lowered
+        // these nodes or if we had a more flexible way of def()'ing.
+        // https://bugs.webkit.org/show_bug.cgi?id=134737
+        read(HeapObjectCount);
+        write(HeapObjectCount);
+        return;
+
+    case NewObject:
</ins><span class="cx">     case NewRegexp:
</span><span class="cx">     case NewStringObject:
</span><ins>+        read(HeapObjectCount);
+        write(HeapObjectCount);
+        return;
+        
</ins><span class="cx">     case NewFunctionNoCheck:
</span><span class="cx">     case NewFunction:
</span><span class="cx">     case NewFunctionExpression:
</span><span class="cx">         read(HeapObjectCount);
</span><span class="cx">         write(HeapObjectCount);
</span><span class="cx">         return;
</span><del>-        
-    case NewTypedArray:
-        read(HeapObjectCount);
-        write(HeapObjectCount);
-        switch (node-&gt;child1().useKind()) {
-        case Int32Use:
-            return;
-        case UntypedUse:
-            read(World);
-            write(World);
-            return;
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-            return;
-        }
-        
</del><ins>+
</ins><span class="cx">     case RegExpExec:
</span><span class="cx">     case RegExpTest:
</span><span class="cx">         read(RegExpState);
</span><span class="lines">@@ -609,6 +732,7 @@
</span><span class="cx">             write(World);
</span><span class="cx">             return;
</span><span class="cx">         }
</span><ins>+        def(PureValue(node));
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case CompareEq:
</span><span class="lines">@@ -616,8 +740,10 @@
</span><span class="cx">     case CompareLessEq:
</span><span class="cx">     case CompareGreater:
</span><span class="cx">     case CompareGreaterEq:
</span><del>-        if (!node-&gt;isBinaryUseKind(UntypedUse))
</del><ins>+        if (!node-&gt;isBinaryUseKind(UntypedUse)) {
+            def(PureValue(node));
</ins><span class="cx">             return;
</span><ins>+        }
</ins><span class="cx">         read(World);
</span><span class="cx">         write(World);
</span><span class="cx">         return;
</span><span class="lines">@@ -626,6 +752,8 @@
</span><span class="cx">         switch (node-&gt;child1().useKind()) {
</span><span class="cx">         case StringObjectUse:
</span><span class="cx">         case StringOrStringObjectUse:
</span><ins>+            // These don't def a pure value, unfortunately. I'll avoid load-eliminating these for
+            // now.
</ins><span class="cx">             return;
</span><span class="cx">             
</span><span class="cx">         case CellUse:
</span><span class="lines">@@ -652,10 +780,16 @@
</span><span class="cx">     case GetMyArgumentsLength:
</span><span class="cx">         read(AbstractHeap(Variables, graph.argumentsRegisterFor(node-&gt;origin.semantic)));
</span><span class="cx">         read(AbstractHeap(Variables, JSStack::ArgumentCount));
</span><ins>+        // FIXME: We could def() this by specifying the code origin as a kind of m_info, like we
+        // have for PureValue.
+        // https://bugs.webkit.org/show_bug.cgi?id=134797
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetMyArgumentByVal:
</span><span class="cx">         read(Variables);
</span><ins>+        // FIXME: We could def() this by specifying the code origin as a kind of m_info, like we
+        // have for PureValue.
+        // https://bugs.webkit.org/show_bug.cgi?id=134797
</ins><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case CheckArgumentsNotCreated:
</span><span class="lines">@@ -685,7 +819,8 @@
</span><span class="cx"> class NoOpClobberize {
</span><span class="cx"> public:
</span><span class="cx">     NoOpClobberize() { }
</span><del>-    void operator()(AbstractHeap) { }
</del><ins>+    template&lt;typename... T&gt;
+    void operator()(T...) { }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class CheckClobberize {
</span><span class="lines">@@ -695,7 +830,8 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(AbstractHeap) { m_result = true; }
</del><ins>+    template&lt;typename... T&gt;
+    void operator()(T...) { m_result = true; }
</ins><span class="cx">     
</span><span class="cx">     bool result() const { return m_result; }
</span><span class="cx">     
</span><span class="lines">@@ -730,6 +866,72 @@
</span><span class="cx"> bool accessesOverlap(Graph&amp;, Node*, AbstractHeap);
</span><span class="cx"> bool writesOverlap(Graph&amp;, Node*, AbstractHeap);
</span><span class="cx"> 
</span><ins>+// We would have used bind() for these, but because of the overlaoding that we are doing,
+// it's quite a bit of clearer to just write this out the traditional way.
+
+template&lt;typename T&gt;
+class ReadMethodClobberize {
+public:
+    ReadMethodClobberize(T&amp; value)
+        : m_value(value)
+    {
+    }
+    
+    void operator()(AbstractHeap heap)
+    {
+        m_value.read(heap);
+    }
+private:
+    T&amp; m_value;
+};
+
+template&lt;typename T&gt;
+class WriteMethodClobberize {
+public:
+    WriteMethodClobberize(T&amp; value)
+        : m_value(value)
+    {
+    }
+    
+    void operator()(AbstractHeap heap)
+    {
+        m_value.write(heap);
+    }
+private:
+    T&amp; m_value;
+};
+
+template&lt;typename T&gt;
+class DefMethodClobberize {
+public:
+    DefMethodClobberize(T&amp; value)
+        : m_value(value)
+    {
+    }
+    
+    void operator()(PureValue value)
+    {
+        m_value.def(value);
+    }
+    
+    void operator()(HeapLocation location, Node* node)
+    {
+        m_value.def(location, node);
+    }
+
+private:
+    T&amp; m_value;
+};
+
+template&lt;typename Adaptor&gt;
+void clobberize(Graph&amp; graph, Node* node, Adaptor&amp; adaptor)
+{
+    ReadMethodClobberize&lt;Adaptor&gt; read(adaptor);
+    WriteMethodClobberize&lt;Adaptor&gt; write(adaptor);
+    DefMethodClobberize&lt;Adaptor&gt; def(adaptor);
+    clobberize(graph, node, read, write, def);
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGDCEPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -109,7 +109,7 @@
</span><span class="cx">             // Need to process the graph in reverse DFS order, so that we get to the uses
</span><span class="cx">             // of a node before we get to the node itself.
</span><span class="cx">             Vector&lt;BasicBlock*&gt; depthFirst;
</span><del>-            m_graph.getBlocksInDepthFirstOrder(depthFirst);
</del><ins>+            m_graph.getBlocksInPreOrder(depthFirst);
</ins><span class="cx">             for (unsigned i = depthFirst.size(); i--;)
</span><span class="cx">                 fixupBlock(depthFirst[i]);
</span><span class="cx">         } else {
</span><span class="lines">@@ -220,7 +220,7 @@
</span><span class="cx">                         m_insertionSet.insertNode(indexInBlock, SpecNone, Phantom, node-&gt;origin, edge);
</span><span class="cx">                     }
</span><span class="cx"> 
</span><del>-                    node-&gt;convertToPhantomUnchecked();
</del><ins>+                    node-&gt;convertToPhantom();
</ins><span class="cx">                     node-&gt;children.reset();
</span><span class="cx">                     node-&gt;setRefCount(1);
</span><span class="cx">                     break;
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -639,28 +639,78 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Graph::addForDepthFirstSort(Vector&lt;BasicBlock*&gt;&amp; result, Vector&lt;BasicBlock*, 16&gt;&amp; worklist, HashSet&lt;BasicBlock*&gt;&amp; seen, BasicBlock* block)
</del><ins>+// Utilities for pre- and post-order traversals.
+namespace {
+
+inline void addForPreOrder(Vector&lt;BasicBlock*&gt;&amp; result, Vector&lt;BasicBlock*, 16&gt;&amp; worklist, BitVector&amp; seen, BasicBlock* block)
</ins><span class="cx"> {
</span><del>-    if (seen.contains(block))
</del><ins>+    if (seen.get(block-&gt;index))
</ins><span class="cx">         return;
</span><span class="cx">     
</span><span class="cx">     result.append(block);
</span><span class="cx">     worklist.append(block);
</span><del>-    seen.add(block);
</del><ins>+    seen.set(block-&gt;index);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Graph::getBlocksInDepthFirstOrder(Vector&lt;BasicBlock*&gt;&amp; result)
</del><ins>+enum PostOrderTaskKind {
+    PostOrderFirstVisit,
+    PostOrderAddToResult
+};
+
+struct PostOrderTask {
+    PostOrderTask(BasicBlock* block = nullptr, PostOrderTaskKind kind = PostOrderFirstVisit)
+        : m_block(block)
+        , m_kind(kind)
+    {
+    }
+    
+    BasicBlock* m_block;
+    PostOrderTaskKind m_kind;
+};
+
+inline void addForPostOrder(Vector&lt;PostOrderTask, 16&gt;&amp; worklist, BitVector&amp; seen, BasicBlock* block)
</ins><span class="cx"> {
</span><ins>+    if (seen.get(block-&gt;index))
+        return;
+    
+    worklist.append(PostOrderTask(block, PostOrderFirstVisit));
+    seen.set(block-&gt;index);
+}
+
+} // anonymous namespace
+
+void Graph::getBlocksInPreOrder(Vector&lt;BasicBlock*&gt;&amp; result)
+{
</ins><span class="cx">     Vector&lt;BasicBlock*, 16&gt; worklist;
</span><del>-    HashSet&lt;BasicBlock*&gt; seen;
-    addForDepthFirstSort(result, worklist, seen, block(0));
</del><ins>+    BitVector seen;
+    addForPreOrder(result, worklist, seen, block(0));
</ins><span class="cx">     while (!worklist.isEmpty()) {
</span><span class="cx">         BasicBlock* block = worklist.takeLast();
</span><span class="cx">         for (unsigned i = block-&gt;numSuccessors(); i--;)
</span><del>-            addForDepthFirstSort(result, worklist, seen, block-&gt;successor(i));
</del><ins>+            addForPreOrder(result, worklist, seen, block-&gt;successor(i));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void Graph::getBlocksInPostOrder(Vector&lt;BasicBlock*&gt;&amp; result)
+{
+    Vector&lt;PostOrderTask, 16&gt; worklist;
+    BitVector seen;
+    addForPostOrder(worklist, seen, block(0));
+    while (!worklist.isEmpty()) {
+        PostOrderTask task = worklist.takeLast();
+        switch (task.m_kind) {
+        case PostOrderFirstVisit:
+            worklist.append(PostOrderTask(task.m_block, PostOrderAddToResult));
+            for (unsigned i = task.m_block-&gt;numSuccessors(); i--;)
+                addForPostOrder(worklist, seen, task.m_block-&gt;successor(i));
+            break;
+        case PostOrderAddToResult:
+            result.append(task.m_block);
+            break;
+        }
+    }
+}
+
</ins><span class="cx"> void Graph::clearReplacements()
</span><span class="cx"> {
</span><span class="cx">     for (BlockIndex blockIndex = numBlocks(); blockIndex--;) {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGGraph.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -663,7 +663,8 @@
</span><span class="cx">     void clearReplacements();
</span><span class="cx">     void initializeNodeOwners();
</span><span class="cx">     
</span><del>-    void getBlocksInDepthFirstOrder(Vector&lt;BasicBlock*&gt;&amp; result);
</del><ins>+    void getBlocksInPreOrder(Vector&lt;BasicBlock*&gt;&amp; result);
+    void getBlocksInPostOrder(Vector&lt;BasicBlock*&gt;&amp; result);
</ins><span class="cx">     
</span><span class="cx">     Profiler::Compilation* compilation() { return m_plan.compilation.get(); }
</span><span class="cx">     
</span><span class="lines">@@ -751,7 +752,6 @@
</span><span class="cx"> private:
</span><span class="cx">     
</span><span class="cx">     void handleSuccessor(Vector&lt;BasicBlock*, 16&gt;&amp; worklist, BasicBlock*, BasicBlock* successor);
</span><del>-    void addForDepthFirstSort(Vector&lt;BasicBlock*&gt;&amp; result, Vector&lt;BasicBlock*, 16&gt;&amp; worklist, HashSet&lt;BasicBlock*&gt;&amp; seen, BasicBlock*);
</del><span class="cx">     
</span><span class="cx">     AddSpeculationMode addImmediateShouldSpeculateInt32(Node* add, bool variableShouldSpeculateInt32, Node* immediate)
</span><span class="cx">     {
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGHeapLocationcpp"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,158 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;DFGHeapLocation.h&quot;
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+void HeapLocation::dump(PrintStream&amp; out) const
+{
+    out.print(m_kind, &quot;:&quot;, m_heap);
+    
+    if (!m_base)
+        return;
+    
+    out.print(&quot;[&quot;, m_base);
+    if (m_index)
+        out.print(&quot;, &quot;, m_index);
+    out.print(&quot;]&quot;);
+}
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+using namespace JSC::DFG;
+
+void printInternal(PrintStream&amp; out, LocationKind kind)
+{
+    switch (kind) {
+    case InvalidLocationKind:
+        out.print(&quot;InvalidLocationKind&quot;);
+        return;
+        
+    case InvalidationPointLoc:
+        out.print(&quot;InvalidationPointLoc&quot;);
+        return;
+        
+    case IsObjectLoc:
+        out.print(&quot;IsObjectLoc&quot;);
+        return;
+        
+    case IsFunctionLoc:
+        out.print(&quot;IsFunctionLoc&quot;);
+        return;
+        
+    case TypeOfLoc:
+        out.print(&quot;TypeOfLoc&quot;);
+        return;
+        
+    case GetterLoc:
+        out.print(&quot;GetterLoc&quot;);
+        return;
+        
+    case SetterLoc:
+        out.print(&quot;SetterLoc&quot;);
+        return;
+        
+    case VariableLoc:
+        out.print(&quot;VariableLoc&quot;);
+        return;
+        
+    case ArrayLengthLoc:
+        out.print(&quot;ArrayLengthLoc&quot;);
+        return;
+        
+    case ButterflyLoc:
+        out.print(&quot;ButterflyLoc&quot;);
+        return;
+        
+    case CheckHasInstanceLoc:
+        out.print(&quot;CheckHasInstanceLoc&quot;);
+        return;
+        
+    case ClosureRegistersLoc:
+        out.print(&quot;ClosureRegistersLoc&quot;);
+        return;
+        
+    case ClosureVariableLoc:
+        out.print(&quot;ClosureVariableLoc&quot;);
+        return;
+        
+    case GlobalVariableLoc:
+        out.print(&quot;GlobalVariableLoc&quot;);
+        return;
+        
+    case IndexedPropertyLoc:
+        out.print(&quot;IndexedPorpertyLoc&quot;);
+        return;
+        
+    case IndexedPropertyStorageLoc:
+        out.print(&quot;IndexedPropertyStorageLoc&quot;);
+        return;
+        
+    case InstanceOfLoc:
+        out.print(&quot;InstanceOfLoc&quot;);
+        return;
+        
+    case MyArgumentByValLoc:
+        out.print(&quot;MyArgumentByValLoc&quot;);
+        return;
+        
+    case MyArgumentsLengthLoc:
+        out.print(&quot;MyArgumentsLengthLoc&quot;);
+        return;
+        
+    case NamedPropertyLoc:
+        out.print(&quot;NamedPropertyLoc&quot;);
+        return;
+        
+    case SkipTopScopeLoc:
+        out.print(&quot;SkipTopScopeLoc&quot;);
+        return;
+        
+    case TypedArrayByteOffsetLoc:
+        out.print(&quot;TypedArrayByteOffsetLoc&quot;);
+        return;
+        
+    case VarInjectionWatchpointLoc:
+        out.print(&quot;VarInjectionWatchpointLoc&quot;);
+        return;
+        
+    case AllocationProfileWatchpointLoc:
+        out.print(&quot;AllocationProfileWatchpointLoc&quot;);
+        return;
+    }
+    
+    RELEASE_ASSERT_NOT_REACHED();
+}
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGHeapLocationh"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.h (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.h                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGHeapLocation.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,160 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGHeapLocation_h
+#define DFGHeapLocation_h
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;DFGAbstractHeap.h&quot;
+#include &quot;DFGNode.h&quot;
+
+namespace JSC { namespace DFG {
+
+enum LocationKind {
+    InvalidLocationKind,
+    
+    AllocationProfileWatchpointLoc,
+    ArrayLengthLoc,
+    ButterflyLoc,
+    CheckHasInstanceLoc,
+    ClosureRegistersLoc,
+    ClosureVariableLoc,
+    GetterLoc,
+    GlobalVariableLoc,
+    IndexedPropertyLoc,
+    IndexedPropertyStorageLoc,
+    InstanceOfLoc,
+    InvalidationPointLoc,
+    IsFunctionLoc,
+    IsObjectLoc,
+    MyArgumentByValLoc,
+    MyArgumentsLengthLoc,
+    NamedPropertyLoc,
+    SetterLoc,
+    SkipTopScopeLoc,
+    TypeOfLoc,
+    TypedArrayByteOffsetLoc,
+    VarInjectionWatchpointLoc,
+    VariableLoc
+};
+
+class HeapLocation {
+public:
+    HeapLocation(
+        LocationKind kind = InvalidLocationKind,
+        AbstractHeap heap = AbstractHeap(),
+        Node* base = nullptr, Node* index = nullptr)
+        : m_kind(kind)
+        , m_heap(heap)
+        , m_base(base)
+        , m_index(index)
+    {
+        ASSERT((kind == InvalidLocationKind) == !heap);
+        ASSERT(!!m_heap || !m_base);
+        ASSERT(m_base || !m_index);
+    }
+    
+    HeapLocation(LocationKind kind, AbstractHeap heap, Edge base, Edge index = Edge())
+        : HeapLocation(kind, heap, base.node(), index.node())
+    {
+    }
+    
+    HeapLocation(WTF::HashTableDeletedValueType)
+        : m_kind(InvalidLocationKind)
+        , m_heap(WTF::HashTableDeletedValue)
+        , m_base(nullptr)
+        , m_index(nullptr)
+    {
+    }
+    
+    bool operator!() const { return !m_heap; }
+    
+    LocationKind kind() const { return m_kind; }
+    AbstractHeap heap() const { return m_heap; }
+    Node* base() const { return m_base; }
+    Node* index() const { return m_index; }
+    
+    unsigned hash() const
+    {
+        return m_kind + m_heap.hash() + WTF::PtrHash&lt;Node*&gt;::hash(m_index) + m_kind;
+    }
+    
+    bool operator==(const HeapLocation&amp; other) const
+    {
+        return m_kind == other.m_kind
+            &amp;&amp; m_heap == other.m_heap
+            &amp;&amp; m_base == other.m_base
+            &amp;&amp; m_index == other.m_index;
+    }
+    
+    bool isHashTableDeletedValue() const
+    {
+        return m_heap.isHashTableDeletedValue();
+    }
+    
+    void dump(PrintStream&amp; out) const;
+    
+private:
+    LocationKind m_kind;
+    AbstractHeap m_heap;
+    Node* m_base;
+    Node* m_index;
+};
+
+struct HeapLocationHash {
+    static unsigned hash(const HeapLocation&amp; key) { return key.hash(); }
+    static bool equal(const HeapLocation&amp; a, const HeapLocation&amp; b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+void printInternal(PrintStream&amp;, JSC::DFG::LocationKind);
+
+template&lt;typename T&gt; struct DefaultHash;
+template&lt;&gt; struct DefaultHash&lt;JSC::DFG::HeapLocation&gt; {
+    typedef JSC::DFG::HeapLocationHash Hash;
+};
+
+template&lt;typename T&gt; struct HashTraits;
+template&lt;&gt; struct HashTraits&lt;JSC::DFG::HeapLocation&gt; : SimpleClassHashTraits&lt;JSC::DFG::HeapLocation&gt; {
+    static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
+namespace JSC { namespace DFG {
+
+typedef HashMap&lt;HeapLocation, Node*&gt; ImpureMap;
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGHeapLocation_h
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGLICMPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -151,7 +151,7 @@
</span><span class="cx">         // For maximum profit, we walk blocks in DFS order to ensure that we generally
</span><span class="cx">         // tend to hoist dominators before dominatees.
</span><span class="cx">         Vector&lt;BasicBlock*&gt; depthFirst;
</span><del>-        m_graph.getBlocksInDepthFirstOrder(depthFirst);
</del><ins>+        m_graph.getBlocksInPreOrder(depthFirst);
</ins><span class="cx">         Vector&lt;const NaturalLoop*&gt; loopStack;
</span><span class="cx">         bool changed = false;
</span><span class="cx">         for (
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGNode.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -373,10 +373,11 @@
</span><span class="cx">     {
</span><span class="cx">         setOpAndDefaultFlags(Phantom);
</span><span class="cx">     }
</span><del>-
-    void convertToPhantomUnchecked()
</del><ins>+    
+    void replaceWith(Node* other)
</ins><span class="cx">     {
</span><del>-        setOpAndDefaultFlags(Phantom);
</del><ins>+        convertToPhantom();
+        replacement = other;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void convertToIdentity();
</span><span class="lines">@@ -443,6 +444,7 @@
</span><span class="cx">         ASSERT(op() == GetIndexedPropertyStorage);
</span><span class="cx">         m_op = ConstantStoragePointer;
</span><span class="cx">         m_opInfo = bitwise_cast&lt;uintptr_t&gt;(pointer);
</span><ins>+        children.reset();
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void convertToGetLocalUnlinked(VirtualRegister local)
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGPlan.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -250,14 +250,14 @@
</span><span class="cx">         validate(dfg);
</span><span class="cx">         
</span><span class="cx">     performStrengthReduction(dfg);
</span><del>-    performCSE(dfg);
</del><ins>+    performLocalCSE(dfg);
</ins><span class="cx">     performArgumentsSimplification(dfg);
</span><span class="cx">     performCPSRethreading(dfg);
</span><span class="cx">     performCFA(dfg);
</span><span class="cx">     performConstantFolding(dfg);
</span><span class="cx">     bool changed = false;
</span><span class="cx">     changed |= performCFGSimplification(dfg);
</span><del>-    changed |= performCSE(dfg);
</del><ins>+    changed |= performLocalCSE(dfg);
</ins><span class="cx">     
</span><span class="cx">     if (validationEnabled())
</span><span class="cx">         validate(dfg);
</span><span class="lines">@@ -316,7 +316,7 @@
</span><span class="cx">         performCPSRethreading(dfg);
</span><span class="cx">         performSSAConversion(dfg);
</span><span class="cx">         performSSALowering(dfg);
</span><del>-        performCSE(dfg);
</del><ins>+        performGlobalCSE(dfg);
</ins><span class="cx">         performLivenessAnalysis(dfg);
</span><span class="cx">         performCFA(dfg);
</span><span class="cx">         performConstantFolding(dfg);
</span><span class="lines">@@ -329,7 +329,7 @@
</span><span class="cx">         performLICM(dfg);
</span><span class="cx">         performPhantomRemoval(dfg);
</span><span class="cx">         performIntegerCheckCombining(dfg);
</span><del>-        performCSE(dfg);
</del><ins>+        performGlobalCSE(dfg);
</ins><span class="cx">         
</span><span class="cx">         // At this point we're not allowed to do any further code motion because our reasoning
</span><span class="cx">         // about code motion assumes that it's OK to insert GC points in random places.
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGPureValuecpp"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.cpp (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.cpp                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;DFGPureValue.h&quot;
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;DFGGraph.h&quot;
+
+namespace JSC { namespace DFG {
+
+void PureValue::dump(PrintStream&amp; out) const
+{
+    out.print(Graph::opName(op()));
+    out.print(&quot;(&quot;);
+    CommaPrinter comma;
+    for (unsigned i = 0; i &lt; AdjacencyList::Size; ++i) {
+        if (children().child(i))
+            out.print(comma, children().child(i));
+    }
+    if (m_info)
+        out.print(comma, m_info);
+    out.print(&quot;)&quot;);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGPureValueh"></a>
<div class="addfile"><h4>Added: branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.h (0 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.h                                (rev 0)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGPureValue.h        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -0,0 +1,145 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGPureValue_h
+#define DFGPureValue_h
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;DFGNode.h&quot;
+
+namespace JSC { namespace DFG {
+
+class PureValue {
+public:
+    PureValue()
+        : m_op(LastNodeType)
+        , m_info(0)
+    {
+    }
+    
+    PureValue(NodeType op, const AdjacencyList&amp; children, uintptr_t info)
+        : m_op(op)
+        , m_children(children.sanitized())
+        , m_info(info)
+    {
+        ASSERT(!(defaultFlags(op) &amp; NodeHasVarArgs));
+    }
+    
+    PureValue(NodeType op, const AdjacencyList&amp; children, const void* ptr)
+        : PureValue(op, children, bitwise_cast&lt;uintptr_t&gt;(ptr))
+    {
+    }
+    
+    PureValue(NodeType op, const AdjacencyList&amp; children)
+        : PureValue(op, children, static_cast&lt;uintptr_t&gt;(0))
+    {
+    }
+    
+    PureValue(Node* node, uintptr_t info)
+        : PureValue(node-&gt;op(), node-&gt;children, info)
+    {
+    }
+    
+    PureValue(Node* node, const void* ptr)
+        : PureValue(node-&gt;op(), node-&gt;children, ptr)
+    {
+    }
+    
+    PureValue(Node* node)
+        : PureValue(node-&gt;op(), node-&gt;children)
+    {
+    }
+    
+    PureValue(WTF::HashTableDeletedValueType)
+        : m_op(LastNodeType)
+        , m_info(1)
+    {
+    }
+    
+    bool operator!() const { return m_op == LastNodeType &amp;&amp; !m_info; }
+    
+    NodeType op() const { return m_op; }
+    const AdjacencyList&amp; children() const { return m_children; }
+    uintptr_t info() const { return m_info; }
+
+    unsigned hash() const
+    {
+        return WTF::IntHash&lt;int&gt;::hash(static_cast&lt;int&gt;(m_op)) + m_children.hash() + m_info;
+    }
+    
+    bool operator==(const PureValue&amp; other) const
+    {
+        return m_op == other.m_op
+            &amp;&amp; m_children == other.m_children
+            &amp;&amp; m_info == other.m_info;
+    }
+    
+    bool isHashTableDeletedValue() const
+    {
+        return m_op == LastNodeType &amp;&amp; m_info;
+    }
+    
+    void dump(PrintStream&amp; out) const;
+    
+private:
+    NodeType m_op;
+    AdjacencyList m_children;
+    uintptr_t m_info;
+};
+
+struct PureValueHash {
+    static unsigned hash(const PureValue&amp; key) { return key.hash(); }
+    static bool equal(const PureValue&amp; a, const PureValue&amp; b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+template&lt;typename T&gt; struct DefaultHash;
+template&lt;&gt; struct DefaultHash&lt;JSC::DFG::PureValue&gt; {
+    typedef JSC::DFG::PureValueHash Hash;
+};
+
+template&lt;typename T&gt; struct HashTraits;
+template&lt;&gt; struct HashTraits&lt;JSC::DFG::PureValue&gt; : SimpleClassHashTraits&lt;JSC::DFG::PureValue&gt; {
+    static const bool emptyValueIsZero = false;
+};
+
+} // namespace WTF
+
+namespace JSC { namespace DFG {
+
+typedef HashMap&lt;PureValue, Node*&gt; PureMap;
+typedef HashMap&lt;PureValue, Vector&lt;Node*&gt;&gt; PureMultiMap;
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGPureValue_h
+
</ins></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoredfgDFGSSAConversionPhasecpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -398,7 +398,7 @@
</span><span class="cx">             block-&gt;variablesAtTail.clear();
</span><span class="cx">             block-&gt;valuesAtHead.clear();
</span><span class="cx">             block-&gt;valuesAtHead.clear();
</span><del>-            block-&gt;ssa = adoptPtr(new BasicBlock::SSAData(block));
</del><ins>+            block-&gt;ssa = std::make_unique&lt;BasicBlock::SSAData&gt;(block);
</ins><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         m_graph.m_arguments.clear();
</span></span></pre></div>
<a id="branchesftloptSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (171105 => 171106)</h4>
<pre class="diff"><span>
<span class="info">--- branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-07-15 14:59:58 UTC (rev 171105)
+++ branches/ftlopt/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2014-07-15 15:48:44 UTC (rev 171106)
</span><span class="lines">@@ -145,7 +145,7 @@
</span><span class="cx">         createPhiVariables();
</span><span class="cx"> 
</span><span class="cx">         Vector&lt;BasicBlock*&gt; depthFirst;
</span><del>-        m_graph.getBlocksInDepthFirstOrder(depthFirst);
</del><ins>+        m_graph.getBlocksInPreOrder(depthFirst);
</ins><span class="cx"> 
</span><span class="cx">         int maxNumberOfArguments = -1;
</span><span class="cx">         for (unsigned blockIndex = depthFirst.size(); blockIndex--; ) {
</span></span></pre>
</div>
</div>

</body>
</html>