Title: [201182] trunk
Revision
201182
Author
fpi...@apple.com
Date
2016-05-19 14:25:29 -0700 (Thu, 19 May 2016)

Log Message

DFG::LICMPhase shouldn't hoist type checks unless it knows that the check will succeed at the loop pre-header
https://bugs.webkit.org/show_bug.cgi?id=144527

Reviewed by Saam Barati.
        
Source/_javascript_Core:

This adds a control flow equivalence analysis (called ControlEquivalenceAnalysis) based on
dominator analysis over the backwards CFG. Two basic blocks are control flow equivalent if
the execution of one implies that the other one must also execute. It means that the two
blocks' forward and backward dominance are reciprocated: (A dom B and B backdom A) or (B dom
A and A backdom B). LICM now uses it to become more conservative about hoisting checks, if
this has caused problems in the past. If we hoist something that may exit from a block that
was not control equivalent to the pre-header then it's possible that the node's speculation
will fail even though it wouldn't have if it wasn't hoisted. So, we flag these nodes'
origins as being "wasHoisted" and we track all of their exits as "HoistingFailed". LICM will
turn off such speculative hoisting if the CodeBlock from which we are hoisting had the
HoistingFailed exit kind.
        
Note that this deliberately still allows us to hoist things that may exit even if they are
not control equivalent to the pre-header. This is necessary because the profitability of
hoisting is so huge in all of the cases that we're aware of that it's worth giving it a
shot.
        
This is neutral on macrobenchmarks since none of the benchmarks we track have a hoistable
operation that would exit only if hoisted. I added microbenchmarks to illustrate the problem
and two of them speed up by ~40% while one of them is neutral (Int52 saves us from having
problems on that program even though LICM previously did the wrong thing).

* _javascript_Core.xcodeproj/project.pbxproj:
* bytecode/ExitKind.cpp:
(JSC::exitKindToString):
* bytecode/ExitKind.h:
* dfg/DFGAtTailAbstractState.h:
(JSC::DFG::AtTailAbstractState::operator bool):
(JSC::DFG::AtTailAbstractState::initializeTo):
* dfg/DFGBackwardsCFG.h: Added.
(JSC::DFG::BackwardsCFG::BackwardsCFG):
* dfg/DFGBackwardsDominators.h: Added.
(JSC::DFG::BackwardsDominators::BackwardsDominators):
* dfg/DFGCommon.h:
(JSC::DFG::checkAndSet): Deleted.
* dfg/DFGControlEquivalenceAnalysis.h: Added.
(JSC::DFG::ControlEquivalenceAnalysis::ControlEquivalenceAnalysis):
(JSC::DFG::ControlEquivalenceAnalysis::dominatesEquivalently):
(JSC::DFG::ControlEquivalenceAnalysis::areEquivalent):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::dumpBlockHeader):
(JSC::DFG::Graph::invalidateCFG):
(JSC::DFG::Graph::substituteGetLocal):
(JSC::DFG::Graph::handleAssertionFailure):
(JSC::DFG::Graph::ensureDominators):
(JSC::DFG::Graph::ensurePrePostNumbering):
(JSC::DFG::Graph::ensureNaturalLoops):
(JSC::DFG::Graph::ensureBackwardsCFG):
(JSC::DFG::Graph::ensureBackwardsDominators):
(JSC::DFG::Graph::ensureControlEquivalenceAnalysis):
(JSC::DFG::Graph::methodOfGettingAValueProfileFor):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::hasDebuggerEnabled):
* dfg/DFGInPlaceAbstractState.h:
(JSC::DFG::InPlaceAbstractState::operator bool):
(JSC::DFG::InPlaceAbstractState::createValueForNode):
(JSC::DFG::InPlaceAbstractState::forNode):
* dfg/DFGLICMPhase.cpp:
(JSC::DFG::LICMPhase::run):
(JSC::DFG::LICMPhase::attemptHoist):
* dfg/DFGMayExit.cpp:
(JSC::DFG::mayExit):
* dfg/DFGMayExit.h:
* dfg/DFGNode.h:
* dfg/DFGNodeOrigin.cpp:
(JSC::DFG::NodeOrigin::dump):
* dfg/DFGNodeOrigin.h:
(JSC::DFG::NodeOrigin::takeValidExit):
(JSC::DFG::NodeOrigin::withWasHoisted):
(JSC::DFG::NodeOrigin::forInsertingAfter):
* dfg/DFGNullAbstractState.h: Added.
(JSC::DFG::NullAbstractState::NullAbstractState):
(JSC::DFG::NullAbstractState::operator bool):
(JSC::DFG::NullAbstractState::forNode):
* dfg/DFGOSRExit.cpp:
(JSC::DFG::OSRExit::OSRExit):
* dfg/DFGOSRExitBase.cpp:
(JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSiteSlow):
* dfg/DFGOSRExitBase.h:
(JSC::DFG::OSRExitBase::OSRExitBase):
* dfg/DFGTypeCheckHoistingPhase.cpp:
(JSC::DFG::TypeCheckHoistingPhase::run):
* ftl/FTLOSRExit.cpp:
(JSC::FTL::OSRExitDescriptor::prepareOSRExitHandle):
(JSC::FTL::OSRExit::OSRExit):
* ftl/FTLOSRExit.h:

Source/WTF:

This adds an adaptor for graphs called BackwardsGraph. The WTF graph framework is based on
passing around a Graph template argument that follows the protocol shared by DFG::CFG,
B3::CFG, and Air::CFG. These graphs always have a single root node but may have many leaf
nodes. This new BackwardsGraph adaptor reverses the graph by creating a synthetic return
node that it uses as the root in the inverted graph. This currently may resort to some
heuristics in programs that have an infinite loop, but other than that, it'll work well in
the general case.
        
This allows us to say Dominators<BackwardsGraph<some graph type>> as a way of computing
backwards dominators, which then allows us to easily answer control flow equivalence
queries.

* CMakeLists.txt:
* WTF.xcodeproj/project.pbxproj:
* wtf/BackwardsGraph.h: Added.
(WTF::BackwardsGraph::Node::Node):
(WTF::BackwardsGraph::Node::root):
(WTF::BackwardsGraph::Node::operator==):
(WTF::BackwardsGraph::Node::operator!=):
(WTF::BackwardsGraph::Node::operator bool):
(WTF::BackwardsGraph::Node::isRoot):
(WTF::BackwardsGraph::Node::node):
(WTF::BackwardsGraph::Set::Set):
(WTF::BackwardsGraph::Set::add):
(WTF::BackwardsGraph::Set::remove):
(WTF::BackwardsGraph::Set::contains):
(WTF::BackwardsGraph::Set::dump):
(WTF::BackwardsGraph::Map::Map):
(WTF::BackwardsGraph::Map::clear):
(WTF::BackwardsGraph::Map::size):
(WTF::BackwardsGraph::Map::operator[]):
(WTF::BackwardsGraph::BackwardsGraph):
(WTF::BackwardsGraph::root):
(WTF::BackwardsGraph::newMap):
(WTF::BackwardsGraph::successors):
(WTF::BackwardsGraph::predecessors):
(WTF::BackwardsGraph::index):
(WTF::BackwardsGraph::node):
(WTF::BackwardsGraph::numNodes):
(WTF::BackwardsGraph::dump):
* wtf/Dominators.h:
(WTF::Dominators::Dominators):
(WTF::Dominators::dump):
(WTF::Dominators::LengauerTarjan::computeDepthFirstPreNumbering):
* wtf/GraphNodeWorklist.h:
(WTF::GraphNodeWith::GraphNodeWith):
(WTF::GraphNodeWith::operator bool):
* wtf/StdLibExtras.h:
(WTF::callStatelessLambda):
(WTF::checkAndSet):

LayoutTests:

Add tests for LICM hoisting things that would only exit if hoisted.

* js/regress/licm-dragons-expected.txt: Added.
* js/regress/licm-dragons-out-of-bounds-expected.txt: Added.
* js/regress/licm-dragons-out-of-bounds.html: Added.
* js/regress/licm-dragons-overflow-expected.txt: Added.
* js/regress/licm-dragons-overflow.html: Added.
* js/regress/licm-dragons.html: Added.
* js/regress/script-tests/licm-dragons-out-of-bounds.js: Added.
(foo):
* js/regress/script-tests/licm-dragons-overflow.js: Added.
(foo):
* js/regress/script-tests/licm-dragons.js: Added.
(foo):

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (201181 => 201182)


--- trunk/LayoutTests/ChangeLog	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/LayoutTests/ChangeLog	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,3 +1,25 @@
+2016-05-18  Filip Pizlo  <fpi...@apple.com>
+
+        DFG::LICMPhase shouldn't hoist type checks unless it knows that the check will succeed at the loop pre-header
+        https://bugs.webkit.org/show_bug.cgi?id=144527
+
+        Reviewed by Saam Barati.
+        
+        Add tests for LICM hoisting things that would only exit if hoisted.
+
+        * js/regress/licm-dragons-expected.txt: Added.
+        * js/regress/licm-dragons-out-of-bounds-expected.txt: Added.
+        * js/regress/licm-dragons-out-of-bounds.html: Added.
+        * js/regress/licm-dragons-overflow-expected.txt: Added.
+        * js/regress/licm-dragons-overflow.html: Added.
+        * js/regress/licm-dragons.html: Added.
+        * js/regress/script-tests/licm-dragons-out-of-bounds.js: Added.
+        (foo):
+        * js/regress/script-tests/licm-dragons-overflow.js: Added.
+        (foo):
+        * js/regress/script-tests/licm-dragons.js: Added.
+        (foo):
+
 2016-05-19  Brian Burg  <bb...@apple.com>
 
         Web Inspector: use a consistent prefix for injected scripts

Added: trunk/LayoutTests/js/regress/licm-dragons-expected.txt (0 => 201182)


--- trunk/LayoutTests/js/regress/licm-dragons-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/licm-dragons-expected.txt	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,10 @@
+JSRegress/licm-dragons
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/licm-dragons-out-of-bounds-expected.txt (0 => 201182)


--- trunk/LayoutTests/js/regress/licm-dragons-out-of-bounds-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/licm-dragons-out-of-bounds-expected.txt	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,10 @@
+JSRegress/licm-dragons-out-of-bounds
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/licm-dragons-out-of-bounds.html (0 => 201182)


--- trunk/LayoutTests/js/regress/licm-dragons-out-of-bounds.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/licm-dragons-out-of-bounds.html	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/licm-dragons-overflow-expected.txt (0 => 201182)


--- trunk/LayoutTests/js/regress/licm-dragons-overflow-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/regress/licm-dragons-overflow-expected.txt	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,10 @@
+JSRegress/licm-dragons-overflow
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/js/regress/licm-dragons-overflow.html (0 => 201182)


--- trunk/LayoutTests/js/regress/licm-dragons-overflow.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/licm-dragons-overflow.html	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/licm-dragons.html (0 => 201182)


--- trunk/LayoutTests/js/regress/licm-dragons.html	                        (rev 0)
+++ trunk/LayoutTests/js/regress/licm-dragons.html	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/regress/script-tests/licm-dragons-out-of-bounds.js (0 => 201182)


--- trunk/LayoutTests/js/regress/script-tests/licm-dragons-out-of-bounds.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/licm-dragons-out-of-bounds.js	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,30 @@
+function foo(p, o, i) {
+    var result = 0;
+    for (var j = 0; j < 1000; ++j) {
+        if (p)
+            result += o[i];
+        else
+            result++;
+    }
+    return result;
+}
+
+noInline(foo);
+
+var o = [42];
+
+var result = 0;
+
+for (var i = 0; i < 1000; ++i) {
+    result += foo(true, o, 0);
+    result += foo(false, o, 1);
+}
+
+for (var i = 0; i < 10000; ++i)
+    result += foo(false, o, 1);
+
+for (var i = 0; i < 20000; ++i)
+    result += foo(true, o, 0);
+
+if (result != 893000000)
+    throw "Error: bad result: " + result;

Added: trunk/LayoutTests/js/regress/script-tests/licm-dragons-overflow.js (0 => 201182)


--- trunk/LayoutTests/js/regress/script-tests/licm-dragons-overflow.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/licm-dragons-overflow.js	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,28 @@
+function foo(p, a, b) {
+    var result = 0;
+    for (var i = 0; i < 1000; ++i) {
+        if (p)
+            result += a + b;
+        else
+            result += a - b;
+    }
+    return result;
+}
+
+noInline(foo);
+
+var result = 0;
+
+for (var i = 0; i < 1000; ++i) {
+    result += foo(true, 1, 2);
+    result += foo(false, 2000000000, 2000000000);
+}
+
+for (var i = 0; i < 10000; ++i)
+    result += foo(false, 2000000000, 2000000000);
+
+for (var i = 0; i < 10000; ++i)
+    result += foo(true, 1, 2);
+
+if (result != 33000000)
+    throw "Error: bad result: " + result;

Added: trunk/LayoutTests/js/regress/script-tests/licm-dragons.js (0 => 201182)


--- trunk/LayoutTests/js/regress/script-tests/licm-dragons.js	                        (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/licm-dragons.js	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,31 @@
+function foo(p, o) {
+    var result = 0;
+    for (var i = 0; i < 1000; ++i) {
+        if (p)
+            result += o.f;
+        else
+            result++;
+    }
+    return result;
+}
+
+noInline(foo);
+
+var o = {f:42};
+var p = {};
+
+var result = 0;
+
+for (var i = 0; i < 1000; ++i) {
+    result += foo(true, o);
+    result += foo(false, p);
+}
+
+for (var i = 0; i < 10000; ++i)
+    result += foo(false, p);
+
+for (var i = 0; i < 30000; ++i)
+    result += foo(true, o);
+
+if (result != 1313000000)
+    throw "Error: bad result: " + result;

Modified: trunk/Source/_javascript_Core/ChangeLog (201181 => 201182)


--- trunk/Source/_javascript_Core/ChangeLog	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,3 +1,98 @@
+2016-05-18  Filip Pizlo  <fpi...@apple.com>
+
+        DFG::LICMPhase shouldn't hoist type checks unless it knows that the check will succeed at the loop pre-header
+        https://bugs.webkit.org/show_bug.cgi?id=144527
+
+        Reviewed by Saam Barati.
+        
+        This adds a control flow equivalence analysis (called ControlEquivalenceAnalysis) based on
+        dominator analysis over the backwards CFG. Two basic blocks are control flow equivalent if
+        the execution of one implies that the other one must also execute. It means that the two
+        blocks' forward and backward dominance are reciprocated: (A dom B and B backdom A) or (B dom
+        A and A backdom B). LICM now uses it to become more conservative about hoisting checks, if
+        this has caused problems in the past. If we hoist something that may exit from a block that
+        was not control equivalent to the pre-header then it's possible that the node's speculation
+        will fail even though it wouldn't have if it wasn't hoisted. So, we flag these nodes'
+        origins as being "wasHoisted" and we track all of their exits as "HoistingFailed". LICM will
+        turn off such speculative hoisting if the CodeBlock from which we are hoisting had the
+        HoistingFailed exit kind.
+        
+        Note that this deliberately still allows us to hoist things that may exit even if they are
+        not control equivalent to the pre-header. This is necessary because the profitability of
+        hoisting is so huge in all of the cases that we're aware of that it's worth giving it a
+        shot.
+        
+        This is neutral on macrobenchmarks since none of the benchmarks we track have a hoistable
+        operation that would exit only if hoisted. I added microbenchmarks to illustrate the problem
+        and two of them speed up by ~40% while one of them is neutral (Int52 saves us from having
+        problems on that program even though LICM previously did the wrong thing).
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * bytecode/ExitKind.cpp:
+        (JSC::exitKindToString):
+        * bytecode/ExitKind.h:
+        * dfg/DFGAtTailAbstractState.h:
+        (JSC::DFG::AtTailAbstractState::operator bool):
+        (JSC::DFG::AtTailAbstractState::initializeTo):
+        * dfg/DFGBackwardsCFG.h: Added.
+        (JSC::DFG::BackwardsCFG::BackwardsCFG):
+        * dfg/DFGBackwardsDominators.h: Added.
+        (JSC::DFG::BackwardsDominators::BackwardsDominators):
+        * dfg/DFGCommon.h:
+        (JSC::DFG::checkAndSet): Deleted.
+        * dfg/DFGControlEquivalenceAnalysis.h: Added.
+        (JSC::DFG::ControlEquivalenceAnalysis::ControlEquivalenceAnalysis):
+        (JSC::DFG::ControlEquivalenceAnalysis::dominatesEquivalently):
+        (JSC::DFG::ControlEquivalenceAnalysis::areEquivalent):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        (JSC::DFG::Graph::dumpBlockHeader):
+        (JSC::DFG::Graph::invalidateCFG):
+        (JSC::DFG::Graph::substituteGetLocal):
+        (JSC::DFG::Graph::handleAssertionFailure):
+        (JSC::DFG::Graph::ensureDominators):
+        (JSC::DFG::Graph::ensurePrePostNumbering):
+        (JSC::DFG::Graph::ensureNaturalLoops):
+        (JSC::DFG::Graph::ensureBackwardsCFG):
+        (JSC::DFG::Graph::ensureBackwardsDominators):
+        (JSC::DFG::Graph::ensureControlEquivalenceAnalysis):
+        (JSC::DFG::Graph::methodOfGettingAValueProfileFor):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::hasDebuggerEnabled):
+        * dfg/DFGInPlaceAbstractState.h:
+        (JSC::DFG::InPlaceAbstractState::operator bool):
+        (JSC::DFG::InPlaceAbstractState::createValueForNode):
+        (JSC::DFG::InPlaceAbstractState::forNode):
+        * dfg/DFGLICMPhase.cpp:
+        (JSC::DFG::LICMPhase::run):
+        (JSC::DFG::LICMPhase::attemptHoist):
+        * dfg/DFGMayExit.cpp:
+        (JSC::DFG::mayExit):
+        * dfg/DFGMayExit.h:
+        * dfg/DFGNode.h:
+        * dfg/DFGNodeOrigin.cpp:
+        (JSC::DFG::NodeOrigin::dump):
+        * dfg/DFGNodeOrigin.h:
+        (JSC::DFG::NodeOrigin::takeValidExit):
+        (JSC::DFG::NodeOrigin::withWasHoisted):
+        (JSC::DFG::NodeOrigin::forInsertingAfter):
+        * dfg/DFGNullAbstractState.h: Added.
+        (JSC::DFG::NullAbstractState::NullAbstractState):
+        (JSC::DFG::NullAbstractState::operator bool):
+        (JSC::DFG::NullAbstractState::forNode):
+        * dfg/DFGOSRExit.cpp:
+        (JSC::DFG::OSRExit::OSRExit):
+        * dfg/DFGOSRExitBase.cpp:
+        (JSC::DFG::OSRExitBase::considerAddingAsFrequentExitSiteSlow):
+        * dfg/DFGOSRExitBase.h:
+        (JSC::DFG::OSRExitBase::OSRExitBase):
+        * dfg/DFGTypeCheckHoistingPhase.cpp:
+        (JSC::DFG::TypeCheckHoistingPhase::run):
+        * ftl/FTLOSRExit.cpp:
+        (JSC::FTL::OSRExitDescriptor::prepareOSRExitHandle):
+        (JSC::FTL::OSRExit::OSRExit):
+        * ftl/FTLOSRExit.h:
+
 2016-05-19  Mark Lam  <mark....@apple.com>
 
         Code that null checks the VM pointer before any use should ref the VM.

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (201181 => 201182)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1998,6 +1998,10 @@
 		DC605B601CE26EA700593718 /* ProfilerUID.h in Headers */ = {isa = PBXBuildFile; fileRef = DC605B5C1CE26E9800593718 /* ProfilerUID.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		DC7997831CDE9FA0004D4A09 /* TagRegistersMode.h in Headers */ = {isa = PBXBuildFile; fileRef = DC7997821CDE9F9E004D4A09 /* TagRegistersMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		DC7997841CDE9FA2004D4A09 /* TagRegistersMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC7997811CDE9F9E004D4A09 /* TagRegistersMode.cpp */; };
+		DCEE22091CEB9895000C2396 /* DFGBackwardsCFG.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEE22061CEB9890000C2396 /* DFGBackwardsCFG.h */; };
+		DCEE220A1CEB9895000C2396 /* DFGBackwardsDominators.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEE22071CEB9890000C2396 /* DFGBackwardsDominators.h */; };
+		DCEE220B1CEB9895000C2396 /* DFGControlEquivalenceAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEE22081CEB9890000C2396 /* DFGControlEquivalenceAnalysis.h */; };
+		DCEE220D1CEBAF75000C2396 /* DFGNullAbstractState.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEE220C1CEBAF73000C2396 /* DFGNullAbstractState.h */; };
 		DCF3D5691CD2946D003D5C65 /* LazyClassStructure.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCF3D5641CD29468003D5C65 /* LazyClassStructure.cpp */; };
 		DCF3D56A1CD29470003D5C65 /* LazyClassStructure.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5651CD29468003D5C65 /* LazyClassStructure.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		DCF3D56B1CD29472003D5C65 /* LazyClassStructureInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF3D5661CD29468003D5C65 /* LazyClassStructureInlines.h */; };
@@ -4216,6 +4220,10 @@
 		DC605B5C1CE26E9800593718 /* ProfilerUID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerUID.h; path = profiler/ProfilerUID.h; sourceTree = "<group>"; };
 		DC7997811CDE9F9E004D4A09 /* TagRegistersMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TagRegistersMode.cpp; sourceTree = "<group>"; };
 		DC7997821CDE9F9E004D4A09 /* TagRegistersMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TagRegistersMode.h; sourceTree = "<group>"; };
+		DCEE22061CEB9890000C2396 /* DFGBackwardsCFG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBackwardsCFG.h; path = dfg/DFGBackwardsCFG.h; sourceTree = "<group>"; };
+		DCEE22071CEB9890000C2396 /* DFGBackwardsDominators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBackwardsDominators.h; path = dfg/DFGBackwardsDominators.h; sourceTree = "<group>"; };
+		DCEE22081CEB9890000C2396 /* DFGControlEquivalenceAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGControlEquivalenceAnalysis.h; path = dfg/DFGControlEquivalenceAnalysis.h; sourceTree = "<group>"; };
+		DCEE220C1CEBAF73000C2396 /* DFGNullAbstractState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNullAbstractState.h; path = dfg/DFGNullAbstractState.h; sourceTree = "<group>"; };
 		DCF3D5641CD29468003D5C65 /* LazyClassStructure.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyClassStructure.cpp; sourceTree = "<group>"; };
 		DCF3D5651CD29468003D5C65 /* LazyClassStructure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyClassStructure.h; sourceTree = "<group>"; };
 		DCF3D5661CD29468003D5C65 /* LazyClassStructureInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LazyClassStructureInlines.h; sourceTree = "<group>"; };
@@ -6131,6 +6139,8 @@
 				0F666EC31835672B00D017F1 /* DFGAvailability.h */,
 				0F2B9CD619D0BA7D00B1D1B5 /* DFGAvailabilityMap.cpp */,
 				0F2B9CD719D0BA7D00B1D1B5 /* DFGAvailabilityMap.h */,
+				DCEE22061CEB9890000C2396 /* DFGBackwardsCFG.h */,
+				DCEE22071CEB9890000C2396 /* DFGBackwardsDominators.h */,
 				0F714CA116EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.cpp */,
 				0F714CA216EA92ED00F3EBEB /* DFGBackwardsPropagationPhase.h */,
 				A7D89CE317A0B8CC00773AD8 /* DFGBasicBlock.cpp */,
@@ -6177,6 +6187,7 @@
 				0F3B3A18153E68EF003ED0FF /* DFGConstantFoldingPhase.h */,
 				0FED67B71B26256D0066CE15 /* DFGConstantHoistingPhase.cpp */,
 				0FED67B81B26256D0066CE15 /* DFGConstantHoistingPhase.h */,
+				DCEE22081CEB9890000C2396 /* DFGControlEquivalenceAnalysis.h */,
 				0FBE0F6B16C1DB010082C5E8 /* DFGCPSRethreadingPhase.cpp */,
 				0FBE0F6C16C1DB010082C5E8 /* DFGCPSRethreadingPhase.h */,
 				A7D89CE617A0B8CC00773AD8 /* DFGCriticalEdgeBreakingPhase.cpp */,
@@ -6288,6 +6299,7 @@
 				0F5D085C1B8CF99D001143B4 /* DFGNodeOrigin.cpp */,
 				0F300B7718AB051100A6D72E /* DFGNodeOrigin.h */,
 				0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */,
+				DCEE220C1CEBAF73000C2396 /* DFGNullAbstractState.h */,
 				0F2B9CDA19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.cpp */,
 				0F2B9CDB19D0BA7D00B1D1B5 /* DFGObjectAllocationSinkingPhase.h */,
 				0F2B9CDC19D0BA7D00B1D1B5 /* DFGObjectMaterializationData.cpp */,
@@ -6955,6 +6967,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				0FFA549816B8835300B3A982 /* A64DOpcode.h in Headers */,
+				DCEE220A1CEB9895000C2396 /* DFGBackwardsDominators.h in Headers */,
 				0F1FE51C1922A3BC006987C5 /* AbortReason.h in Headers */,
 				860161E30F3A83C100F84710 /* AbstractMacroAssembler.h in Headers */,
 				0F55F0F514D1063C00AC7649 /* AbstractPC.h in Headers */,
@@ -6999,6 +7012,7 @@
 				BC18C3E50E16F5CD00B34460 /* APICast.h in Headers */,
 				FE3A06BE1C11041200390FDD /* JITLeftShiftGenerator.h in Headers */,
 				BCF605140E203EF800B9A64D /* ArgList.h in Headers */,
+				DCEE22091CEB9895000C2396 /* DFGBackwardsCFG.h in Headers */,
 				0FE050141AA9091100D33B33 /* ArgumentsMode.h in Headers */,
 				0F6B1CB91861244C00845D97 /* ArityCheckMode.h in Headers */,
 				A1A009C11831A26E00CF8711 /* ARM64Assembler.h in Headers */,
@@ -7912,6 +7926,7 @@
 				0FF729B9166AD360000F5BA3 /* ProfilerBytecodes.h in Headers */,
 				0F13912A16771C36009CCB07 /* ProfilerBytecodeSequence.h in Headers */,
 				0FB387901BFBC44D00E3AB1E /* AirOptimizeBlockOrder.h in Headers */,
+				DCEE220D1CEBAF75000C2396 /* DFGNullAbstractState.h in Headers */,
 				0FF729BA166AD360000F5BA3 /* ProfilerCompilation.h in Headers */,
 				0FF729BB166AD360000F5BA3 /* ProfilerCompilationKind.h in Headers */,
 				0F4A38FA1C8E13DF00190318 /* SuperSampler.h in Headers */,
@@ -8056,6 +8071,7 @@
 				141448CD13A1783700F5BA1A /* TinyBloomFilter.h in Headers */,
 				2684D4381C00161C0081D663 /* AirLiveness.h in Headers */,
 				0F55989817C86C5800A1E543 /* ToNativeFromValue.h in Headers */,
+				DCEE220B1CEB9895000C2396 /* DFGControlEquivalenceAnalysis.h in Headers */,
 				0F2D4DE919832DAC007D4B19 /* ToThisStatus.h in Headers */,
 				0F952ABD1B487A7700C367C5 /* TrackedReferences.h in Headers */,
 				0F2B670617B6B5AB00A7AE3F /* TypedArrayAdaptors.h in Headers */,

Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/bytecode/ExitKind.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -76,6 +76,8 @@
         return "VarargsOverflow";
     case TDZFailure:
         return "TDZFailure";
+    case HoistingFailed:
+        return "HoistingFailed";
     case Uncountable:
         return "Uncountable";
     case UncountableInvalidation:

Modified: trunk/Source/_javascript_Core/bytecode/ExitKind.h (201181 => 201182)


--- trunk/Source/_javascript_Core/bytecode/ExitKind.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/bytecode/ExitKind.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,6 +50,7 @@
     NotStringObject, // We exited because we shouldn't have attempted to optimize string object access.
     VarargsOverflow, // We exited because a varargs call passed more arguments than we expected.
     TDZFailure, // We exited because we were in the TDZ and accessed the variable.
+    HoistingFailed, // Something that was hoisted exited. So, assume that hoisting is a bad idea.
     Uncountable, // We exited for none of the above reasons, and we should not count it. Most uses of this should be viewed as a FIXME.
     UncountableInvalidation, // We exited because the code block was invalidated; this means that we've already counted the reasons why the code block was invalidated.
     WatchdogTimerFired, // We exited because we need to service the watchdog timer.

Modified: trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -40,6 +40,8 @@
     
     ~AtTailAbstractState();
     
+    explicit operator bool() const { return true; }
+    
     void initializeTo(BasicBlock* block)
     {
         m_block = block;

Added: trunk/Source/_javascript_Core/dfg/DFGBackwardsCFG.h (0 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGBackwardsCFG.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGBackwardsCFG.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 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 DFGBackwardsCFG_h
+#define DFGBackwardsCFG_h
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCFG.h"
+#include <wtf/BackwardsGraph.h>
+
+namespace JSC { namespace DFG {
+
+class BackwardsCFG : public BackwardsGraph<CFG> {
+    WTF_MAKE_NONCOPYABLE(BackwardsCFG);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    BackwardsCFG(Graph& graph)
+        : BackwardsGraph<CFG>(*graph.m_cfg)
+    {
+    }
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGBackwardsCFG_h
+

Added: trunk/Source/_javascript_Core/dfg/DFGBackwardsDominators.h (0 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGBackwardsDominators.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGBackwardsDominators.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 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 DFGBackwardsDominators_h
+#define DFGBackwardsDominators_h
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGBackwardsCFG.h"
+#include <wtf/Dominators.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Noncopyable.h>
+
+namespace JSC { namespace DFG {
+
+class BackwardsDominators : public WTF::Dominators<BackwardsCFG> {
+    WTF_MAKE_NONCOPYABLE(BackwardsDominators);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    BackwardsDominators(Graph& graph)
+        : WTF::Dominators<BackwardsCFG>(graph.ensureBackwardsCFG())
+    {
+    }
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGDominators_h

Modified: trunk/Source/_javascript_Core/dfg/DFGCommon.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGCommon.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGCommon.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -255,15 +255,6 @@
     AfterFixup
 };
 
-template<typename T, typename U>
-bool checkAndSet(T& left, U right)
-{
-    if (left == right)
-        return false;
-    left = right;
-    return true;
-}
-
 // If possible, this will acquire a lock to make sure that if multiple threads
 // start crashing at the same time, you get coherent dump output. Use this only
 // when you're forcing a crash with diagnostics.

Added: trunk/Source/_javascript_Core/dfg/DFGControlEquivalenceAnalysis.h (0 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGControlEquivalenceAnalysis.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGControlEquivalenceAnalysis.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 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 DFGControlEquivalenceAnalysis_h
+#define DFGControlEquivalenceAnalysis_h
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGBackwardsDominators.h"
+#include "DFGDominators.h"
+
+namespace JSC { namespace DFG {
+
+class ControlEquivalenceAnalysis {
+    WTF_MAKE_NONCOPYABLE(ControlEquivalenceAnalysis);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    ControlEquivalenceAnalysis(Graph& graph)
+        : m_dominators(graph.ensureDominators())
+        , m_backwardsDominators(graph.ensureBackwardsDominators())
+    {
+    }
+    
+    // This returns true iff:
+    //
+    // - If b executes then a must have executed before it (a dominates b).
+    // - If a executes then b will execute after it (b backwards-dominates a).
+    //
+    // Note that like Dominators and BackwardsDominators, this analysis ignores OSR:
+    //
+    // - This may return true even if we OSR enter in beteen a and b. OSR entry would mean that b
+    //   could execute even if a had not executed. This is impossible in DFG SSA but it's possible
+    //   in DFG CPS.
+    // - This may return true even if we OSR exit in between a and b. OSR exit would mean that a
+    //   could execute even though b will not execute. This is possible in all forms of DFG IR.
+    //
+    // In DFG SSA you only have to worry about the definition being weaked by exits. This is usually
+    // OK, since we use this analysis to determine the cost of moving exits from one block to
+    // another. If we move an exit from b to a and a equivalently dominates b then at worst we have
+    // made the exit happen sooner. If we move an exit from b to a and a dominates b but not
+    // equivalently then we've done something much worse: the program may now exit even if it would
+    // not have ever exited before.
+    bool dominatesEquivalently(BasicBlock* a, BasicBlock* b)
+    {
+        return m_dominators.dominates(a, b)
+            && m_backwardsDominators.dominates(b, a);
+    }
+    
+    // This returns true iff the execution of a implies that b also executes and vice-versa.
+    bool areEquivalent(BasicBlock* a, BasicBlock* b)
+    {
+        return dominatesEquivalently(a, b)
+            || dominatesEquivalently(b, a);
+    }
+
+private:
+    Dominators& m_dominators;
+    BackwardsDominators& m_backwardsDominators;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGControlEquivalenceAnalysis_h
+

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -32,10 +32,13 @@
 #include "BytecodeLivenessAnalysisInlines.h"
 #include "CodeBlock.h"
 #include "CodeBlockWithJITType.h"
+#include "DFGBackwardsCFG.h"
+#include "DFGBackwardsDominators.h"
 #include "DFGBlockWorklist.h"
+#include "DFGCFG.h"
 #include "DFGClobberSet.h"
 #include "DFGClobbersExitState.h"
-#include "DFGCFG.h"
+#include "DFGControlEquivalenceAnalysis.h"
 #include "DFGDominators.h"
 #include "DFGJITCode.h"
 #include "DFGMayExit.h"
@@ -375,6 +378,8 @@
     }
     if (!node->origin.exitOK)
         out.print(comma, "ExitInvalid");
+    if (node->origin.wasHoisted)
+        out.print(comma, "WasHoisted");
     out.print(")");
 
     if (node->hasVariableAccessData(*this) && node->tryGetVariableAccessData())
@@ -419,6 +424,18 @@
         out.print(prefix, "  Dominance Frontier: ", m_dominators->dominanceFrontierOf(block), "\n");
         out.print(prefix, "  Iterated Dominance Frontier: ", m_dominators->iteratedDominanceFrontierOf(BlockList(1, block)), "\n");
     }
+    if (m_backwardsDominators && terminalsAreValid()) {
+        out.print(prefix, "  Backwards dominates by: ", m_backwardsDominators->dominatorsOf(block), "\n");
+        out.print(prefix, "  Backwards dominates: ", m_backwardsDominators->blocksDominatedBy(block), "\n");
+    }
+    if (m_controlEquivalenceAnalysis && terminalsAreValid()) {
+        out.print(prefix, "  Control equivalent to:");
+        for (BasicBlock* otherBlock : blocksInNaturalOrder()) {
+            if (m_controlEquivalenceAnalysis->areEquivalent(block, otherBlock))
+                out.print(" ", *otherBlock);
+        }
+        out.print("\n");
+    }
     if (m_prePostNumbering)
         out.print(prefix, "  Pre/Post Numbering: ", m_prePostNumbering->preNumber(block), "/", m_prePostNumbering->postNumber(block), "\n");
     if (m_naturalLoops) {
@@ -753,6 +770,9 @@
     m_dominators = nullptr;
     m_naturalLoops = nullptr;
     m_prePostNumbering = nullptr;
+    m_controlEquivalenceAnalysis = nullptr;
+    m_backwardsDominators = nullptr;
+    m_backwardsCFG = nullptr;
 }
 
 void Graph::substituteGetLocal(BasicBlock& block, unsigned startIndexInBlock, VariableAccessData* variableAccessData, Node* newGetLocal)
@@ -1426,25 +1446,49 @@
     crash(*this, toCString("While handling block ", pointerDump(block), "\n\n"), file, line, function, assertion);
 }
 
-void Graph::ensureDominators()
+Dominators& Graph::ensureDominators()
 {
     if (!m_dominators)
         m_dominators = std::make_unique<Dominators>(*this);
+    return *m_dominators;
 }
 
-void Graph::ensurePrePostNumbering()
+PrePostNumbering& Graph::ensurePrePostNumbering()
 {
     if (!m_prePostNumbering)
         m_prePostNumbering = std::make_unique<PrePostNumbering>(*this);
+    return *m_prePostNumbering;
 }
 
-void Graph::ensureNaturalLoops()
+NaturalLoops& Graph::ensureNaturalLoops()
 {
     ensureDominators();
     if (!m_naturalLoops)
         m_naturalLoops = std::make_unique<NaturalLoops>(*this);
+    return *m_naturalLoops;
 }
 
+BackwardsCFG& Graph::ensureBackwardsCFG()
+{
+    if (!m_backwardsCFG)
+        m_backwardsCFG = std::make_unique<BackwardsCFG>(*this);
+    return *m_backwardsCFG;
+}
+
+BackwardsDominators& Graph::ensureBackwardsDominators()
+{
+    if (!m_backwardsDominators)
+        m_backwardsDominators = std::make_unique<BackwardsDominators>(*this);
+    return *m_backwardsDominators;
+}
+
+ControlEquivalenceAnalysis& Graph::ensureControlEquivalenceAnalysis()
+{
+    if (!m_controlEquivalenceAnalysis)
+        m_controlEquivalenceAnalysis = std::make_unique<ControlEquivalenceAnalysis>(*this);
+    return *m_controlEquivalenceAnalysis;
+}
+
 MethodOfGettingAValueProfile Graph::methodOfGettingAValueProfileFor(Node* node)
 {
     while (node) {

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -56,7 +56,10 @@
 
 namespace DFG {
 
+class BackwardsCFG;
+class BackwardsDominators;
 class CFG;
+class ControlEquivalenceAnalysis;
 class Dominators;
 class NaturalLoops;
 class PrePostNumbering;
@@ -800,9 +803,12 @@
 
     bool hasDebuggerEnabled() const { return m_hasDebuggerEnabled; }
 
-    void ensureDominators();
-    void ensurePrePostNumbering();
-    void ensureNaturalLoops();
+    Dominators& ensureDominators();
+    PrePostNumbering& ensurePrePostNumbering();
+    NaturalLoops& ensureNaturalLoops();
+    BackwardsCFG& ensureBackwardsCFG();
+    BackwardsDominators& ensureBackwardsDominators();
+    ControlEquivalenceAnalysis& ensureControlEquivalenceAnalysis();
 
     // This function only makes sense to call after bytecode parsing
     // because it queries the m_hasExceptionHandlers boolean whose value
@@ -879,6 +885,9 @@
     std::unique_ptr<PrePostNumbering> m_prePostNumbering;
     std::unique_ptr<NaturalLoops> m_naturalLoops;
     std::unique_ptr<CFG> m_cfg;
+    std::unique_ptr<BackwardsCFG> m_backwardsCFG;
+    std::unique_ptr<BackwardsDominators> m_backwardsDominators;
+    std::unique_ptr<ControlEquivalenceAnalysis> m_controlEquivalenceAnalysis;
     unsigned m_localVars;
     unsigned m_nextMachineLocal;
     unsigned m_parameterSlots;

Modified: trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -42,6 +42,8 @@
     
     ~InPlaceAbstractState();
     
+    explicit operator bool() const { return true; }
+    
     void createValueForNode(Node*) { }
     
     AbstractValue& forNode(Node* node)

Modified: trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,9 +33,11 @@
 #include "DFGBasicBlockInlines.h"
 #include "DFGClobberSet.h"
 #include "DFGClobberize.h"
+#include "DFGControlEquivalenceAnalysis.h"
 #include "DFGEdgeDominates.h"
 #include "DFGGraph.h"
 #include "DFGInsertionSet.h"
+#include "DFGMayExit.h"
 #include "DFGNaturalLoops.h"
 #include "DFGPhase.h"
 #include "DFGSafeToExecute.h"
@@ -74,6 +76,7 @@
         
         m_graph.ensureDominators();
         m_graph.ensureNaturalLoops();
+        m_graph.ensureControlEquivalenceAnalysis();
 
         if (verbose) {
             dataLog("Graph before LICM:\n");
@@ -260,43 +263,6 @@
         // we could still hoist just the checks.
         // https://bugs.webkit.org/show_bug.cgi?id=144525
         
-        // FIXME: If a node has a type check - even something like a CheckStructure - then we should
-        // only hoist the node if we know that it will execute on every loop iteration or if we know
-        // that the type check will always succeed at the loop pre-header through some other means
-        // (like looking at prediction propagation results). Otherwise, we might make a mistake like
-        // this:
-        //
-        // var o = ...; // sometimes null and sometimes an object with structure S1.
-        // for (...) {
-        //     if (o)
-        //         ... = o.f; // CheckStructure and GetByOffset, which we will currently hoist.
-        // }
-        //
-        // When we encounter such code, we'll hoist the CheckStructure and GetByOffset and then we
-        // will have a recompile. We'll then end up thinking that the get_by_id needs to be
-        // polymorphic, which is false.
-        //
-        // We can counter this by either having a control flow equivalence check, or by consulting
-        // prediction propagation to see if the check would always succeed. Prediction propagation
-        // would not be enough for things like:
-        //
-        // var p = ...; // some boolean predicate
-        // var o = {};
-        // if (p)
-        //     o.f = 42;
-        // for (...) {
-        //     if (p)
-        //         ... = o.f;
-        // }
-        //
-        // Prediction propagation can't tell us anything about the structure, and the CheckStructure
-        // will appear to be hoistable because the loop doesn't clobber structures. The cell check
-        // in the CheckStructure will be hoistable though, since prediction propagation can tell us
-        // that o is always SpecFinalObject. In cases like this, control flow equivalence is the
-        // only effective guard.
-        //
-        // https://bugs.webkit.org/show_bug.cgi?id=144527
-        
         if (readsOverlap(m_graph, node, data.writes)) {
             if (verbose) {
                 dataLog(
@@ -315,6 +281,25 @@
             return false;
         }
         
+        NodeOrigin originalOrigin = node->origin;
+
+        // NOTE: We could just use BackwardsDominators here directly, since we already know that the
+        // preHeader dominates fromBlock. But we wouldn't get anything from being so clever, since
+        // dominance checks are O(1) and only a few integer compares.
+        bool addsBlindSpeculation = mayExit(m_graph, node, m_state)
+            && !m_graph.m_controlEquivalenceAnalysis->dominatesEquivalently(data.preHeader, fromBlock);
+        
+        if (addsBlindSpeculation
+            && m_graph.baselineCodeBlockFor(originalOrigin.semantic)->hasExitSite(FrequentExitSite(HoistingFailed))) {
+            if (verbose) {
+                dataLog(
+                    "    Not hoisting ", node, " because it may exit and the pre-header (",
+                    *data.preHeader, ") is not control equivalent to the node's original block (",
+                    *fromBlock, ") and hoisting had previously failed.\n");
+            }
+            return false;
+        }
+        
         if (verbose) {
             dataLog(
                 "    Hoisting ", node, " from ", *fromBlock, " to ", *data.preHeader,
@@ -326,8 +311,9 @@
         // https://bugs.webkit.org/show_bug.cgi?id=148544
         data.preHeader->insertBeforeTerminal(node);
         node->owner = data.preHeader;
-        NodeOrigin originalOrigin = node->origin;
-        node->origin = data.preHeader->terminal()->origin.withSemantic(node->origin.semantic);
+        NodeOrigin terminalOrigin = data.preHeader->terminal()->origin;
+        node->origin = terminalOrigin.withSemantic(node->origin.semantic);
+        node->origin.wasHoisted |= addsBlindSpeculation;
         
         // Modify the states at the end of the preHeader of the loop we hoisted to,
         // and all pre-headers inside the loop. This isn't a stability bottleneck right now

Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,60 +28,18 @@
 
 #if ENABLE(DFG_JIT)
 
+#include "DFGAtTailAbstractState.h"
 #include "DFGGraph.h"
 #include "DFGNode.h"
+#include "DFGNullAbstractState.h"
 #include "Operations.h"
 
 namespace JSC { namespace DFG {
 
 namespace {
 
-class EdgeMayExit {
-public:
-    EdgeMayExit()
-        : m_result(false)
-    {
-    }
-    
-    void operator()(Node*, Edge edge)
-    {
-        // FIXME: Maybe this should call mayHaveTypeCheck(edge.useKind()) instead.
-        // https://bugs.webkit.org/show_bug.cgi?id=148545
-        if (edge.willHaveCheck()) {
-            m_result = true;
-            return;
-        }
-
-        switch (edge.useKind()) {
-        // These are shady because nodes that have these use kinds will typically exit for
-        // unrelated reasons. For example CompareEq doesn't usually exit, but if it uses ObjectUse
-        // then it will.
-        case ObjectUse:
-        case ObjectOrOtherUse:
-            m_result = true;
-            break;
-            
-        // These are shady because they check the structure even if the type of the child node
-        // passes the StringObject type filter.
-        case StringObjectUse:
-        case StringOrStringObjectUse:
-            m_result = true;
-            break;
-            
-        default:
-            break;
-        }
-    }
-    
-    bool result() const { return m_result; }
-    
-private:
-    bool m_result;
-};
-
-} // anonymous namespace
-
-ExitMode mayExit(Graph& graph, Node* node)
+template<typename StateType>
+ExitMode mayExitImpl(Graph& graph, Node* node, StateType& state)
 {
     ExitMode result = DoesNotExit;
     
@@ -154,15 +112,68 @@
         // If in doubt, return true.
         return Exits;
     }
+    
+    graph.doToChildren(
+        node,
+        [&] (Edge& edge) {
+            if (state) {
+                // Ignore the Check flag on the edge. This is important because that flag answers
+                // the question: "would this edge have had a check if it executed wherever it
+                // currently resides in control flow?" But when a state is passed, we want to ask a
+                // different question: "would this edge have a check if it executed wherever this
+                // state is?" Using the Check flag for this purpose wouldn't even be conservatively
+                // correct. It would be wrong in both directions.
+                if (mayHaveTypeCheck(edge.useKind())
+                    && (state.forNode(edge).m_type & ~typeFilterFor(edge.useKind()))) {
+                    result = Exits;
+                    return;
+                }
+            } else {
+                // FIXME: Maybe this should call mayHaveTypeCheck(edge.useKind()) instead.
+                // https://bugs.webkit.org/show_bug.cgi?id=148545
+                if (edge.willHaveCheck()) {
+                    result = Exits;
+                    return;
+                }
+            }
+            
+            switch (edge.useKind()) {
+            // These are shady because nodes that have these use kinds will typically exit for
+            // unrelated reasons. For example CompareEq doesn't usually exit, but if it uses
+            // ObjectUse then it will.
+            case ObjectUse:
+            case ObjectOrOtherUse:
+                result = Exits;
+                break;
+                
+            // These are shady because they check the structure even if the type of the child node
+            // passes the StringObject type filter.
+            case StringObjectUse:
+            case StringOrStringObjectUse:
+                result = Exits;
+                break;
+                
+            default:
+                break;
+            }
+        });
 
-    EdgeMayExit functor;
-    DFG_NODE_DO_TO_CHILDREN(graph, node, functor);
-    if (functor.result())
-        result = Exits;
-    
     return result;
 }
 
+} // anonymous namespace
+
+ExitMode mayExit(Graph& graph, Node* node)
+{
+    NullAbstractState state;
+    return mayExitImpl(graph, node, state);
+}
+
+ExitMode mayExit(Graph& graph, Node* node, AtTailAbstractState& state)
+{
+    return mayExitImpl(graph, node, state);
+}
+
 } } // namespace JSC::DFG
 
 namespace WTF {

Modified: trunk/Source/_javascript_Core/dfg/DFGMayExit.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGMayExit.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGMayExit.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,6 +30,7 @@
 
 namespace JSC { namespace DFG {
 
+class AtTailAbstractState;
 class Graph;
 struct Node;
 
@@ -74,6 +75,11 @@
 
 ExitMode mayExit(Graph&, Node*);
 
+// Like mayExit(), but instead of using the Check: flag to determine if something exits, it
+// evaluates whether it will exit based on the tail state. This is useful for LICM. This *may* also
+// use the AtTailAbstractState to return more precise answers for other nodes.
+ExitMode mayExit(Graph&, Node*, AtTailAbstractState&);
+
 } } // namespace JSC::DFG
 
 namespace WTF {

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -2299,7 +2299,7 @@
 
 private:
     unsigned m_op : 10; // real type is NodeType
-    unsigned m_flags : 22;
+    unsigned m_flags : 20;
     // The virtual register number (spill location) associated with this .
     VirtualRegister m_virtualRegister;
     // The number of uses of the result of this operation (+1 for 'must generate' nodes, which have side-effects).

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeOrigin.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGNodeOrigin.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeOrigin.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -32,7 +32,7 @@
 
 void NodeOrigin::dump(PrintStream& out) const
 {
-    out.print("{semantic: ", semantic, ", forExit: ", forExit, ", exitOK: ", exitOK, "}");
+    out.print("{semantic: ", semantic, ", forExit: ", forExit, ", exitOK: ", exitOK, ", wasHoisted: ", wasHoisted, "}");
 }
 
 } } // namespace JSC::DFG

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeOrigin.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGNodeOrigin.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeOrigin.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -92,6 +92,13 @@
         return withExitOK(exitOK & std::exchange(canExit, false));
     }
     
+    NodeOrigin withWasHoisted() const
+    {
+        NodeOrigin result = *this;
+        result.wasHoisted = true;
+        return result;
+    }
+    
     NodeOrigin forInsertingAfter(Graph& graph, Node* node) const
     {
         NodeOrigin result = *this;
@@ -121,6 +128,8 @@
     CodeOrigin forExit;
     // Whether or not it is legal to exit here.
     bool exitOK { false };
+    // Whether or not the node has been hoisted.
+    bool wasHoisted { false };
 };
 
 } } // namespace JSC::DFG

Added: trunk/Source/_javascript_Core/dfg/DFGNullAbstractState.h (0 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGNullAbstractState.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGNullAbstractState.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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 DFGNullAbstractState_h
+#define DFGNullAbstractState_h
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Edge;
+struct AbstractValue;
+struct Node;
+
+// Use this as a stub for things that can optionally take some kind of abstract state but you wish
+// to not pass any abstract state. This works if the templatized code also does a check (using the
+// operator bool) to see if the state is valid.
+class NullAbstractState {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    NullAbstractState() { }
+    
+    explicit operator bool() const { return false; }
+    
+    AbstractValue& forNode(Node*)
+    {
+        RELEASE_ASSERT_NOT_REACHED();
+        return *bitwise_cast<AbstractValue*>(static_cast<intptr_t>(0x1234));
+    }
+    
+    AbstractValue& forNode(Edge)
+    {
+        return forNode(nullptr);
+    }
+    
+    // It's valid to add more stub methods here as needed.
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGNullAbstractState_h
+

Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -37,7 +37,7 @@
 namespace JSC { namespace DFG {
 
 OSRExit::OSRExit(ExitKind kind, JSValueSource jsValueSource, MethodOfGettingAValueProfile valueProfile, SpeculativeJIT* jit, unsigned streamIndex, unsigned recoveryIndex)
-    : OSRExitBase(kind, jit->m_origin.forExit, jit->m_origin.semantic)
+    : OSRExitBase(kind, jit->m_origin.forExit, jit->m_origin.semantic, jit->m_origin.wasHoisted)
     , m_jsValueSource(jsValueSource)
     , m_valueProfile(valueProfile)
     , m_patchableCodeOffset(0)

Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitBase.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGOSRExitBase.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitBase.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -41,8 +41,14 @@
     CodeBlock* sourceProfiledCodeBlock =
         baselineCodeBlockForOriginAndBaselineCodeBlock(
             m_codeOriginForExitProfile, profiledCodeBlock);
-    if (sourceProfiledCodeBlock)
-        sourceProfiledCodeBlock->addFrequentExitSite(FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind, jitType));
+    if (sourceProfiledCodeBlock) {
+        FrequentExitSite site;
+        if (m_wasHoisted)
+            site = FrequentExitSite(HoistingFailed, jitType);
+        else
+            site = FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind, jitType);
+        sourceProfiledCodeBlock->addFrequentExitSite(site);
+    }
 }
 
 } } // namespace JSC::DFG

Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExitBase.h (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGOSRExitBase.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExitBase.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -40,9 +40,10 @@
 // and the FTL.
 
 struct OSRExitBase {
-    OSRExitBase(ExitKind kind, CodeOrigin origin, CodeOrigin originForProfile)
+    OSRExitBase(ExitKind kind, CodeOrigin origin, CodeOrigin originForProfile, bool wasHoisted)
         : m_kind(kind)
         , m_count(0)
+        , m_wasHoisted(wasHoisted)
         , m_codeOrigin(origin)
         , m_codeOriginForExitProfile(originForProfile)
     {
@@ -52,6 +53,7 @@
     
     ExitKind m_kind;
     uint32_t m_count;
+    bool m_wasHoisted;
     
     CodeOrigin m_codeOrigin;
     CodeOrigin m_codeOriginForExitProfile;

Modified: trunk/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/dfg/DFGTypeCheckHoistingPhase.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -88,7 +88,7 @@
     bool run()
     {
         ASSERT(m_graph.m_form == ThreadedCPS);
-
+        
         clearVariableVotes();
         identifyRedundantStructureChecks();
         disableHoistingForVariablesWithInsufficientVotes<StructureTypeCheck>();

Modified: trunk/Source/_javascript_Core/ftl/FTLOSRExit.cpp (201181 => 201182)


--- trunk/Source/_javascript_Core/ftl/FTLOSRExit.cpp	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/ftl/FTLOSRExit.cpp	2016-05-19 21:25:29 UTC (rev 201182)
@@ -92,7 +92,7 @@
 {
     unsigned index = state.jitCode->osrExit.size();
     OSRExit& exit = state.jitCode->osrExit.alloc(
-        this, exitKind, nodeOrigin.forExit, nodeOrigin.semantic);
+        this, exitKind, nodeOrigin.forExit, nodeOrigin.semantic, nodeOrigin.wasHoisted);
     RefPtr<OSRExitHandle> handle = adoptRef(new OSRExitHandle(index, exit));
     for (unsigned i = offset; i < params.size(); ++i)
         exit.m_valueReps.append(params[i]);
@@ -101,9 +101,9 @@
 }
 
 OSRExit::OSRExit(
-    OSRExitDescriptor* descriptor,
-    ExitKind exitKind, CodeOrigin codeOrigin, CodeOrigin codeOriginForExitProfile)
-    : OSRExitBase(exitKind, codeOrigin, codeOriginForExitProfile)
+    OSRExitDescriptor* descriptor, ExitKind exitKind, CodeOrigin codeOrigin,
+    CodeOrigin codeOriginForExitProfile, bool wasHoisted)
+    : OSRExitBase(exitKind, codeOrigin, codeOriginForExitProfile, wasHoisted)
     , m_descriptor(descriptor)
 {
 }

Modified: trunk/Source/_javascript_Core/ftl/FTLOSRExit.h (201181 => 201182)


--- trunk/Source/_javascript_Core/ftl/FTLOSRExit.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/_javascript_Core/ftl/FTLOSRExit.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -117,10 +117,7 @@
 };
 
 struct OSRExit : public DFG::OSRExitBase {
-    OSRExit(
-        OSRExitDescriptor*, ExitKind,
-        CodeOrigin, CodeOrigin codeOriginForExitProfile
-        );
+    OSRExit(OSRExitDescriptor*, ExitKind, CodeOrigin, CodeOrigin codeOriginForExitProfile, bool wasHoisted);
 
     OSRExitDescriptor* m_descriptor;
     MacroAssemblerCodeRef m_code;

Modified: trunk/Source/WTF/ChangeLog (201181 => 201182)


--- trunk/Source/WTF/ChangeLog	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/WTF/ChangeLog	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,3 +1,61 @@
+2016-05-18  Filip Pizlo  <fpi...@apple.com>
+
+        DFG::LICMPhase shouldn't hoist type checks unless it knows that the check will succeed at the loop pre-header
+        https://bugs.webkit.org/show_bug.cgi?id=144527
+
+        Reviewed by Saam Barati.
+        
+        This adds an adaptor for graphs called BackwardsGraph. The WTF graph framework is based on
+        passing around a Graph template argument that follows the protocol shared by DFG::CFG,
+        B3::CFG, and Air::CFG. These graphs always have a single root node but may have many leaf
+        nodes. This new BackwardsGraph adaptor reverses the graph by creating a synthetic return
+        node that it uses as the root in the inverted graph. This currently may resort to some
+        heuristics in programs that have an infinite loop, but other than that, it'll work well in
+        the general case.
+        
+        This allows us to say Dominators<BackwardsGraph<some graph type>> as a way of computing
+        backwards dominators, which then allows us to easily answer control flow equivalence
+        queries.
+
+        * CMakeLists.txt:
+        * WTF.xcodeproj/project.pbxproj:
+        * wtf/BackwardsGraph.h: Added.
+        (WTF::BackwardsGraph::Node::Node):
+        (WTF::BackwardsGraph::Node::root):
+        (WTF::BackwardsGraph::Node::operator==):
+        (WTF::BackwardsGraph::Node::operator!=):
+        (WTF::BackwardsGraph::Node::operator bool):
+        (WTF::BackwardsGraph::Node::isRoot):
+        (WTF::BackwardsGraph::Node::node):
+        (WTF::BackwardsGraph::Set::Set):
+        (WTF::BackwardsGraph::Set::add):
+        (WTF::BackwardsGraph::Set::remove):
+        (WTF::BackwardsGraph::Set::contains):
+        (WTF::BackwardsGraph::Set::dump):
+        (WTF::BackwardsGraph::Map::Map):
+        (WTF::BackwardsGraph::Map::clear):
+        (WTF::BackwardsGraph::Map::size):
+        (WTF::BackwardsGraph::Map::operator[]):
+        (WTF::BackwardsGraph::BackwardsGraph):
+        (WTF::BackwardsGraph::root):
+        (WTF::BackwardsGraph::newMap):
+        (WTF::BackwardsGraph::successors):
+        (WTF::BackwardsGraph::predecessors):
+        (WTF::BackwardsGraph::index):
+        (WTF::BackwardsGraph::node):
+        (WTF::BackwardsGraph::numNodes):
+        (WTF::BackwardsGraph::dump):
+        * wtf/Dominators.h:
+        (WTF::Dominators::Dominators):
+        (WTF::Dominators::dump):
+        (WTF::Dominators::LengauerTarjan::computeDepthFirstPreNumbering):
+        * wtf/GraphNodeWorklist.h:
+        (WTF::GraphNodeWith::GraphNodeWith):
+        (WTF::GraphNodeWith::operator bool):
+        * wtf/StdLibExtras.h:
+        (WTF::callStatelessLambda):
+        (WTF::checkAndSet):
+
 2016-05-18  Saam barati  <sbar...@apple.com>
 
         StringBuilder::appendQuotedJSONString doesn't properly protect against the math it's doing. Make the math fit the assertion.

Modified: trunk/Source/WTF/WTF.xcodeproj/project.pbxproj (201181 => 201182)


--- trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/WTF/WTF.xcodeproj/project.pbxproj	2016-05-19 21:25:29 UTC (rev 201182)
@@ -301,6 +301,7 @@
 		CD5497AD15857D0300B5BC30 /* MediaTime.h in Headers */ = {isa = PBXBuildFile; fileRef = CD5497AB15857D0300B5BC30 /* MediaTime.h */; };
 		CE46516E19DB1FB4003ECA05 /* NSMapTableSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = CE46516D19DB1FB4003ECA05 /* NSMapTableSPI.h */; };
 		CE73E02519DCB7AB00580D5C /* XPCSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = CE73E02419DCB7AB00580D5C /* XPCSPI.h */; };
+		DCEE22051CEB9869000C2396 /* BackwardsGraph.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEE22041CEB9869000C2396 /* BackwardsGraph.h */; };
 		DCEE21FB1CEA7538000C2396 /* CFBundleSPI.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEE21FA1CEA7538000C2396 /* CFBundleSPI.h */; };
 		DCEE22001CEA7551000C2396 /* BlockObjCExceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEE21FC1CEA7551000C2396 /* BlockObjCExceptions.h */; };
 		DCEE22011CEA7551000C2396 /* BlockObjCExceptions.mm in Sources */ = {isa = PBXBuildFile; fileRef = DCEE21FD1CEA7551000C2396 /* BlockObjCExceptions.mm */; };
@@ -627,6 +628,7 @@
 		CD5497AB15857D0300B5BC30 /* MediaTime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MediaTime.h; sourceTree = "<group>"; };
 		CE46516D19DB1FB4003ECA05 /* NSMapTableSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSMapTableSPI.h; sourceTree = "<group>"; };
 		CE73E02419DCB7AB00580D5C /* XPCSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XPCSPI.h; sourceTree = "<group>"; };
+		DCEE22041CEB9869000C2396 /* BackwardsGraph.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BackwardsGraph.h; sourceTree = "<group>"; };
 		DCEE21FA1CEA7538000C2396 /* CFBundleSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CFBundleSPI.h; path = cf/CFBundleSPI.h; sourceTree = "<group>"; };
 		DCEE21FC1CEA7551000C2396 /* BlockObjCExceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockObjCExceptions.h; sourceTree = "<group>"; };
 		DCEE21FD1CEA7551000C2396 /* BlockObjCExceptions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BlockObjCExceptions.mm; sourceTree = "<group>"; };
@@ -773,6 +775,7 @@
 				A8A4725D151A825A004123FF /* Atomics.h */,
 				1469419A16EAB10A0024E146 /* AutodrainedPool.h */,
 				1469419B16EAB10A0024E146 /* AutodrainedPoolMac.mm */,
+				DCEE22041CEB9869000C2396 /* BackwardsGraph.h */,
 				0FB14E18180FA218009B6B4D /* Bag.h */,
 				0FB14E1A1810E1DA009B6B4D /* BagToHashMap.h */,
 				A8A4725F151A825A004123FF /* Bitmap.h */,
@@ -1179,6 +1182,7 @@
 				A8A47391151A825B004123FF /* BumpPointerAllocator.h in Headers */,
 				EB95E1F0161A72410089A2F5 /* ByteOrder.h in Headers */,
 				A8A473AD151A825B004123FF /* cached-powers.h in Headers */,
+				DCEE22051CEB9869000C2396 /* BackwardsGraph.h in Headers */,
 				A8A4745E151A825B004123FF /* CharacterNames.h in Headers */,
 				A8A47394151A825B004123FF /* CheckedArithmetic.h in Headers */,
 				A8A47395151A825B004123FF /* CheckedBoolean.h in Headers */,

Added: trunk/Source/WTF/wtf/BackwardsGraph.h (0 => 201182)


--- trunk/Source/WTF/wtf/BackwardsGraph.h	                        (rev 0)
+++ trunk/Source/WTF/wtf/BackwardsGraph.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2016 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 WTF_BackwardsGraph_h
+#define WTF_BackwardsGraph_h
+
+#include <wtf/FastMalloc.h>
+#include <wtf/GraphNodeWorklist.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Optional.h>
+#include <wtf/StdLibExtras.h>
+
+namespace WTF {
+
+template<typename Graph>
+class BackwardsGraph {
+    WTF_MAKE_NONCOPYABLE(BackwardsGraph);
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    // We use "#end" to refer to the synthetic root we have created.
+    static const char* rootName = "#end";
+
+    class Node {
+    public:
+        Node(typename Graph::Node node = typename Graph::Node())
+            : m_node(node)
+        {
+        }
+
+        static Node root()
+        {
+            Node result;
+            result.m_node = 0;
+            result.m_isRoot = true;
+            return result;
+        }
+
+        bool operator==(const Node& other) const
+        {
+            return m_node == other.m_node
+                && m_isRoot == other.m_isRoot;
+        }
+
+        bool operator!=(const Node& other) const
+        {
+            return !(*this == other);
+        }
+
+        explicit operator bool() const { return *this != Node(); }
+
+        bool isRoot() const
+        {
+            return m_isRoot;
+        }
+
+        typename Graph::Node node() const { return m_node; }
+
+    private:
+        typename Graph::Node m_node;
+        bool m_isRoot { false };
+    };
+
+    class Set {
+    public:
+        Set()
+        {
+        }
+        
+        bool add(const Node& node)
+        {
+            if (node.isRoot())
+                return checkAndSet(m_hasRoot, true);
+            return m_set.add(node.node());
+        }
+
+        bool remove(const Node& node)
+        {
+            if (node.isRoot())
+                return checkAndSet(m_hasRoot, false);
+            return m_set.remove(node.node());
+        }
+
+        bool contains(const Node& node)
+        {
+            if (node.isRoot())
+                return m_hasRoot;
+            return m_set.contains(node.node());
+        }
+
+        void dump(PrintStream& out) const
+        {
+            if (m_hasRoot)
+                out.print(rootName, " ");
+            out.print(m_set);
+        }
+        
+    private:
+        typename Graph::Set m_set;
+        bool m_hasRoot { false };
+    };
+
+    template<typename T>
+    class Map {
+    public:
+        Map(Graph& graph)
+            : m_map(graph.template newMap<T>())
+        {
+        }
+
+        void clear()
+        {
+            m_map.clear();
+            m_root = T();
+        }
+
+        size_t size() const { return m_map.size() + 1; }
+
+        T& operator[](size_t index)
+        {
+            if (!index)
+                return m_root;
+            return m_map[index - 1];
+        }
+
+        const T& operator[](size_t index) const
+        {
+            return (*const_cast<Map*>(this))[index];
+        }
+
+        T& operator[](const Node& node)
+        {
+            if (node.isRoot())
+                return m_root;
+            return m_map[node.node()];
+        }
+
+        const T& operator[](const Node& node) const
+        {
+            return (*const_cast<Map*>(this))[node];
+        }
+        
+    private:
+        typename Graph::template Map<T> m_map;
+        T m_root;
+    };
+
+    typedef Vector<Node, 4> List;
+
+    BackwardsGraph(Graph& graph)
+        : m_graph(graph)
+    {
+        GraphNodeWorklist<typename Graph::Node, typename Graph::Set> worklist;
+
+        auto addRootSuccessor = [&] (typename Graph::Node node) {
+            if (worklist.push(node)) {
+                m_rootSuccessorList.append(node);
+                m_rootSuccessorSet.add(node);
+                while (typename Graph::Node node = worklist.pop())
+                    worklist.pushAll(graph.predecessors(node));
+            }
+        };
+
+        for (unsigned i = 0; i < graph.numNodes(); ++i) {
+            if (typename Graph::Node node = graph.node(i)) {
+                if (!graph.successors(node).size())
+                    addRootSuccessor(node);
+            }
+        }
+
+        // At this point there will be some nodes in the graph that aren't known to the worklist. We
+        // could add any or all of them to the root successors list. Adding all of them would be a bad
+        // pessimisation. Ideally we would pick the ones that have backward edges but no forward
+        // edges. That would require thinking, so we just use a rough heuristic: add the highest
+        // numbered nodes first, which is totally fine if the input program is already sorted nicely.
+        for (unsigned i = graph.numNodes(); i--;) {
+            if (typename Graph::Node node = graph.node(i))
+                addRootSuccessor(node);
+        }
+    }
+
+    Node root() { return Node::root(); }
+
+    template<typename T>
+    Map<T> newMap() { return Map<T>(m_graph); }
+
+    List successors(const Node& node) const
+    {
+        if (node.isRoot())
+            return m_rootSuccessorList;
+        List result;
+        for (typename Graph::Node predecessor : m_graph.predecessors(node.node()))
+            result.append(predecessor);
+        return result;
+    }
+
+    List predecessors(const Node& node) const
+    {
+        if (node.isRoot())
+            return { };
+
+        List result;
+        
+        if (m_rootSuccessorSet.contains(node.node()))
+            result.append(Node::root());
+
+        for (typename Graph::Node successor : m_graph.successors(node.node()))
+            result.append(successor);
+
+        return result;
+    }
+
+    unsigned index(const Node& node) const
+    {
+        if (node.isRoot())
+            return 0;
+        return m_graph.index(node.node()) + 1;
+    }
+
+    Node node(unsigned index) const
+    {
+        if (!index)
+            return Node::root();
+        return m_graph.node(index - 1);
+    }
+
+    unsigned numNodes() const
+    {
+        return m_graph.numNodes() + 1;
+    }
+
+    CString dump(Node node) const
+    {
+        StringPrintStream out;
+        if (!node)
+            out.print("<null>");
+        else if (node.isRoot())
+            out.print(rootName);
+        else
+            out.print(m_graph.dump(node.node()));
+        return out.toCString();
+    }
+
+    void dump(PrintStream& out) const
+    {
+        for (unsigned i = 0; i < numNodes(); ++i) {
+            Node node = this->node(i);
+            if (!node)
+                continue;
+            out.print(dump(node), ":\n");
+            out.print("    Preds: ");
+            CommaPrinter comma;
+            for (Node predecessor : predecessors(node))
+                out.print(comma, dump(predecessor));
+            out.print("\n");
+            out.print("    Succs: ");
+            comma = CommaPrinter();
+            for (Node successor : successors(node))
+                out.print(comma, dump(successor));
+            out.print("\n");
+        }
+    }
+
+private:
+    Graph& m_graph;
+    List m_rootSuccessorList;
+    typename Graph::Set m_rootSuccessorSet;
+};
+
+} // namespace WTF
+
+using WTF::BackwardsGraph;
+
+#endif // WTF_BackwardsGraph_h
+

Modified: trunk/Source/WTF/wtf/CMakeLists.txt (201181 => 201182)


--- trunk/Source/WTF/wtf/CMakeLists.txt	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/WTF/wtf/CMakeLists.txt	2016-05-19 21:25:29 UTC (rev 201182)
@@ -2,6 +2,7 @@
     ASCIICType.h
     Assertions.h
     Atomics.h
+    BackwardsGraph.h
     Bag.h
     BagToHashMap.h
     BitVector.h

Modified: trunk/Source/WTF/wtf/Dominators.h (201181 => 201182)


--- trunk/Source/WTF/wtf/Dominators.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/WTF/wtf/Dominators.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2014, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2014-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -41,6 +41,7 @@
 public:
     Dominators(Graph& graph, bool selfCheck = false)
         : m_graph(graph)
+        , m_data(graph.template newMap<BlockData>())
     {
         LengauerTarjan lengauerTarjan(m_graph);
         lengauerTarjan.compute();
@@ -67,7 +68,7 @@
     
         // Plain stack-based worklist because we are guaranteed to see each block exactly once anyway.
         Vector<GraphNodeWithOrder<typename Graph::Node>> worklist;
-        worklist.append(GraphNodeWithOrder<typename Graph::Node>(m_graph.node(0), GraphVisitOrder::Pre));
+        worklist.append(GraphNodeWithOrder<typename Graph::Node>(m_graph.root(), GraphVisitOrder::Pre));
         while (!worklist.isEmpty()) {
             GraphNodeWithOrder<typename Graph::Node> item = worklist.takeLast();
             switch (item.order) {
@@ -279,10 +280,10 @@
             if (m_data[blockIndex].preNumber == UINT_MAX)
                 continue;
             
-            out.print("    Block #", blockIndex, ": idom = ", pointerDump(m_data[blockIndex].idomParent), ", idomKids = [");
+            out.print("    Block #", blockIndex, ": idom = ", m_graph.dump(m_data[blockIndex].idomParent), ", idomKids = [");
             CommaPrinter comma;
             for (unsigned i = 0; i < m_data[blockIndex].idomKids.size(); ++i)
-                out.print(comma, *m_data[blockIndex].idomKids[i]);
+                out.print(comma, m_graph.dump(m_data[blockIndex].idomKids[i]));
             out.print("], pre/post = ", m_data[blockIndex].preNumber, "/", m_data[blockIndex].postNumber, "\n");
         }
     }
@@ -347,7 +348,7 @@
             // of not noticing A->C until we're done processing B.
 
             ExtendedGraphNodeWorklist<typename Graph::Node, unsigned, typename Graph::Set> worklist;
-            worklist.push(m_graph.node(0), 0);
+            worklist.push(m_graph.root(), 0);
         
             while (GraphNodeWith<typename Graph::Node, unsigned> item = worklist.pop()) {
                 typename Graph::Node block = item.node;

Modified: trunk/Source/WTF/wtf/GraphNodeWorklist.h (201181 => 201182)


--- trunk/Source/WTF/wtf/GraphNodeWorklist.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/WTF/wtf/GraphNodeWorklist.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -83,7 +83,7 @@
     {
     }
 
-    explicit operator bool() const { return node; }
+    explicit operator bool() const { return !!node; }
     
     Node node;
     T data;

Modified: trunk/Source/WTF/wtf/StdLibExtras.h (201181 => 201182)


--- trunk/Source/WTF/wtf/StdLibExtras.h	2016-05-19 21:11:02 UTC (rev 201181)
+++ trunk/Source/WTF/wtf/StdLibExtras.h	2016-05-19 21:25:29 UTC (rev 201182)
@@ -299,6 +299,15 @@
     return (*bitwise_cast<Func*>(data))(std::forward<ArgumentTypes>(arguments)...);
 }
 
+template<typename T, typename U>
+bool checkAndSet(T& left, U right)
+{
+    if (left == right)
+        return false;
+    left = right;
+    return true;
+}
+
 } // namespace WTF
 
 // This version of placement new omits a 0 check.
@@ -409,17 +418,18 @@
 
 using WTF::KB;
 using WTF::MB;
+using WTF::approximateBinarySearch;
+using WTF::binarySearch;
+using WTF::bitwise_cast;
+using WTF::callStatelessLambda;
+using WTF::checkAndSet;
+using WTF::insertIntoBoundedVector;
 using WTF::isCompilationThread;
-using WTF::insertIntoBoundedVector;
 using WTF::isPointerAligned;
+using WTF::isStatelessLambda;
 using WTF::is8ByteAligned;
-using WTF::binarySearch;
+using WTF::safeCast;
 using WTF::tryBinarySearch;
-using WTF::approximateBinarySearch;
-using WTF::bitwise_cast;
-using WTF::safeCast;
-using WTF::isStatelessLambda;
-using WTF::callStatelessLambda;
 
 #if COMPILER_SUPPORTS(CXX_USER_LITERALS)
 // We normally don't want to bring in entire std namespaces, but literals are an exception.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to