Title: [208373] trunk
Revision
208373
Author
fpi...@apple.com
Date
2016-11-03 22:28:35 -0700 (Thu, 03 Nov 2016)

Log Message

DFG plays fast and loose with the shadow values of a Phi
https://bugs.webkit.org/show_bug.cgi?id=164309

Reviewed by Saam Barati.
        
JSTests:

This test demonstrates why the DFG needs to recognize the shadow value of a Phi.

* stress/dfg-ssa-swap.js: Added.
(foo):

Source/_javascript_Core:

Oh boy, what an embarrassing mistake! The style of SSA I like to use avoids block/value
tuples as parameters of a Phi, thereby simplifying CFG transformations and making Phi largely
not a special case for most compiler transforms. It does this by introducing another value
called Upsilon, which stores a value into some Phi.
        
B3 uses this also. The easiest way to understand what Upsilon/Phi behave like is to look at
the B3->Air lowering. Air is not SSA - it has Tmps that you can assign to and use as many
times as you like. B3 allocates one Tmp per Value, and an extra "phiTmp" for Phis, so that
Phis get two Tmps total. Upsilon stores the value into the phiTmp of the Phi, while Phi moves
the value from its phiTmp to its tmp.
        
This is necessary to support scenarios like this:
        
    a: Phi()
    b: Upsilon(@x, ^a)
    c: Use(@a)
        
Here, we want @c to see @a's value before @b. That's a very basic requirement of SSA: that
the a value (like @a) doesn't change during its lifetime.
        
Unfortunately, DFG's liveness analysis, abstract interpreter, and integer range optimization
all failed to correctly model Upsilon/Phi this way. They would assume that it's accurate to
model the Upsilon as storing into the Phi directly.
        
Because DFG does flow analysis over SSA, making it correct means enabling it to speak of the
shadow value. This change addresses this problem by introducing the concept of a
NodeFlowProjection. This is a key that lets us speak of both a Node's primary value and its
optional "shadow" value. Liveness, AI, and integer range are now keyed by NodeFlowProjection
rather than Node*. Conceptually this turns out to be a very simple change, but it does touch
a good amount of code.
        
This looks to be perf-neutral.

Rolled back in after fixing the debug build.

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* b3/air/AirLiveness.h:
(JSC::B3::Air::TmpLivenessAdapter::numIndices):
(JSC::B3::Air::StackSlotLivenessAdapter::numIndices):
(JSC::B3::Air::RegLivenessAdapter::numIndices):
(JSC::B3::Air::AbstractLiveness::AbstractLiveness):
(JSC::B3::Air::TmpLivenessAdapter::maxIndex): Deleted.
(JSC::B3::Air::StackSlotLivenessAdapter::maxIndex): Deleted.
(JSC::B3::Air::RegLivenessAdapter::maxIndex): Deleted.
* dfg/DFGAbstractInterpreter.h:
(JSC::DFG::AbstractInterpreter::forNode):
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::forAllValues):
(JSC::DFG::AbstractInterpreter<AbstractStateType>::dump):
* dfg/DFGAtTailAbstractState.cpp:
(JSC::DFG::AtTailAbstractState::createValueForNode):
(JSC::DFG::AtTailAbstractState::forNode):
* dfg/DFGAtTailAbstractState.h:
* dfg/DFGBasicBlock.h:
* dfg/DFGCombinedLiveness.cpp:
(JSC::DFG::liveNodesAtHead):
* dfg/DFGCombinedLiveness.h:
* dfg/DFGFlowIndexing.cpp: Added.
(JSC::DFG::FlowIndexing::FlowIndexing):
(JSC::DFG::FlowIndexing::~FlowIndexing):
(JSC::DFG::FlowIndexing::recompute):
* dfg/DFGFlowIndexing.h: Added.
(JSC::DFG::FlowIndexing::graph):
(JSC::DFG::FlowIndexing::numIndices):
(JSC::DFG::FlowIndexing::index):
(JSC::DFG::FlowIndexing::shadowIndex):
(JSC::DFG::FlowIndexing::nodeProjection):
* dfg/DFGFlowMap.h: Added.
(JSC::DFG::FlowMap::FlowMap):
(JSC::DFG::FlowMap::resize):
(JSC::DFG::FlowMap::graph):
(JSC::DFG::FlowMap::at):
(JSC::DFG::FlowMap::atShadow):
(WTF::printInternal):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::Graph):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::abstractValuesCache): Deleted.
* dfg/DFGInPlaceAbstractState.cpp:
(JSC::DFG::InPlaceAbstractState::InPlaceAbstractState):
(JSC::DFG::InPlaceAbstractState::beginBasicBlock):
(JSC::DFG::setLiveValues):
(JSC::DFG::InPlaceAbstractState::endBasicBlock):
(JSC::DFG::InPlaceAbstractState::merge):
* dfg/DFGInPlaceAbstractState.h:
(JSC::DFG::InPlaceAbstractState::createValueForNode):
(JSC::DFG::InPlaceAbstractState::forNode):
* dfg/DFGIntegerRangeOptimizationPhase.cpp:
* dfg/DFGLivenessAnalysisPhase.cpp:
(JSC::DFG::LivenessAnalysisPhase::LivenessAnalysisPhase):
(JSC::DFG::LivenessAnalysisPhase::run):
(JSC::DFG::LivenessAnalysisPhase::processBlock):
(JSC::DFG::LivenessAnalysisPhase::addChildUse): Deleted.
* dfg/DFGNode.h:
(JSC::DFG::NodeComparator::operator()):
(JSC::DFG::nodeListDump):
(JSC::DFG::nodeMapDump):
(JSC::DFG::nodeValuePairListDump):
(JSC::DFG::nodeComparator): Deleted.
* dfg/DFGNodeAbstractValuePair.cpp: Added.
(JSC::DFG::NodeAbstractValuePair::dump):
* dfg/DFGNodeAbstractValuePair.h: Added.
(JSC::DFG::NodeAbstractValuePair::NodeAbstractValuePair):
* dfg/DFGNodeFlowProjection.cpp: Added.
(JSC::DFG::NodeFlowProjection::dump):
* dfg/DFGNodeFlowProjection.h: Added.
(JSC::DFG::NodeFlowProjection::NodeFlowProjection):
(JSC::DFG::NodeFlowProjection::operator bool):
(JSC::DFG::NodeFlowProjection::kind):
(JSC::DFG::NodeFlowProjection::node):
(JSC::DFG::NodeFlowProjection::operator*):
(JSC::DFG::NodeFlowProjection::operator->):
(JSC::DFG::NodeFlowProjection::hash):
(JSC::DFG::NodeFlowProjection::operator==):
(JSC::DFG::NodeFlowProjection::operator!=):
(JSC::DFG::NodeFlowProjection::operator<):
(JSC::DFG::NodeFlowProjection::operator>):
(JSC::DFG::NodeFlowProjection::operator<=):
(JSC::DFG::NodeFlowProjection::operator>=):
(JSC::DFG::NodeFlowProjection::isHashTableDeletedValue):
(JSC::DFG::NodeFlowProjection::isStillValid):
(JSC::DFG::NodeFlowProjection::forEach):
(JSC::DFG::NodeFlowProjectionHash::hash):
(JSC::DFG::NodeFlowProjectionHash::equal):
* dfg/DFGStoreBarrierInsertionPhase.cpp:

Source/WTF:

Made this API use size rather than maxIndex as its initialization parameter, because that's
less confusing.

* wtf/IndexSparseSet.h:
(WTF::IndexSparseSet<OverflowHandler>::IndexSparseSet):

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (208372 => 208373)


--- trunk/JSTests/ChangeLog	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/JSTests/ChangeLog	2016-11-04 05:28:35 UTC (rev 208373)
@@ -1,3 +1,15 @@
+2016-11-03  Filip Pizlo  <fpi...@apple.com>
+
+        DFG plays fast and loose with the shadow values of a Phi
+        https://bugs.webkit.org/show_bug.cgi?id=164309
+
+        Reviewed by Saam Barati.
+        
+        This test demonstrates why the DFG needs to recognize the shadow value of a Phi.
+
+        * stress/dfg-ssa-swap.js: Added.
+        (foo):
+
 2016-11-03  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r208364.

Added: trunk/JSTests/stress/dfg-ssa-swap.js (0 => 208373)


--- trunk/JSTests/stress/dfg-ssa-swap.js	                        (rev 0)
+++ trunk/JSTests/stress/dfg-ssa-swap.js	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,8 @@
+var i,c=0;
+function foo()
+{
+    var a=1,b;for(i=0;i<2;++i){[a,b]=[b,a];c++}if(!a^b)throw c
+}
+noInline(foo);
+for(var k = 0; k < 10000; ++k)
+    foo()

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (208372 => 208373)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2016-11-04 05:28:35 UTC (rev 208373)
@@ -312,6 +312,7 @@
     dfg/DFGFailedFinalizer.cpp
     dfg/DFGFinalizer.cpp
     dfg/DFGFixupPhase.cpp
+    dfg/DFGFlowIndexing.cpp
     dfg/DFGFlushFormat.cpp
     dfg/DFGFlushedAt.cpp
     dfg/DFGLiveCatchVariablePreservationPhase.cpp
@@ -343,7 +344,9 @@
     dfg/DFGMultiGetByOffsetData.cpp
     dfg/DFGNaturalLoops.cpp
     dfg/DFGNode.cpp
+    dfg/DFGNodeAbstractValuePair.cpp
     dfg/DFGNodeFlags.cpp
+    dfg/DFGNodeFlowProjection.cpp
     dfg/DFGNodeOrigin.cpp
     dfg/DFGOSRAvailabilityAnalysisPhase.cpp
     dfg/DFGOSREntry.cpp

Modified: trunk/Source/_javascript_Core/ChangeLog (208372 => 208373)


--- trunk/Source/_javascript_Core/ChangeLog	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-11-04 05:28:35 UTC (rev 208373)
@@ -1,3 +1,138 @@
+2016-11-03  Filip Pizlo  <fpi...@apple.com>
+
+        DFG plays fast and loose with the shadow values of a Phi
+        https://bugs.webkit.org/show_bug.cgi?id=164309
+
+        Reviewed by Saam Barati.
+        
+        Oh boy, what an embarrassing mistake! The style of SSA I like to use avoids block/value
+        tuples as parameters of a Phi, thereby simplifying CFG transformations and making Phi largely
+        not a special case for most compiler transforms. It does this by introducing another value
+        called Upsilon, which stores a value into some Phi.
+        
+        B3 uses this also. The easiest way to understand what Upsilon/Phi behave like is to look at
+        the B3->Air lowering. Air is not SSA - it has Tmps that you can assign to and use as many
+        times as you like. B3 allocates one Tmp per Value, and an extra "phiTmp" for Phis, so that
+        Phis get two Tmps total. Upsilon stores the value into the phiTmp of the Phi, while Phi moves
+        the value from its phiTmp to its tmp.
+        
+        This is necessary to support scenarios like this:
+        
+            a: Phi()
+            b: Upsilon(@x, ^a)
+            c: Use(@a)
+        
+        Here, we want @c to see @a's value before @b. That's a very basic requirement of SSA: that
+        the a value (like @a) doesn't change during its lifetime.
+        
+        Unfortunately, DFG's liveness analysis, abstract interpreter, and integer range optimization
+        all failed to correctly model Upsilon/Phi this way. They would assume that it's accurate to
+        model the Upsilon as storing into the Phi directly.
+        
+        Because DFG does flow analysis over SSA, making it correct means enabling it to speak of the
+        shadow value. This change addresses this problem by introducing the concept of a
+        NodeFlowProjection. This is a key that lets us speak of both a Node's primary value and its
+        optional "shadow" value. Liveness, AI, and integer range are now keyed by NodeFlowProjection
+        rather than Node*. Conceptually this turns out to be a very simple change, but it does touch
+        a good amount of code.
+        
+        This looks to be perf-neutral.
+
+        Rolled back in after fixing the debug build.
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * b3/air/AirLiveness.h:
+        (JSC::B3::Air::TmpLivenessAdapter::numIndices):
+        (JSC::B3::Air::StackSlotLivenessAdapter::numIndices):
+        (JSC::B3::Air::RegLivenessAdapter::numIndices):
+        (JSC::B3::Air::AbstractLiveness::AbstractLiveness):
+        (JSC::B3::Air::TmpLivenessAdapter::maxIndex): Deleted.
+        (JSC::B3::Air::StackSlotLivenessAdapter::maxIndex): Deleted.
+        (JSC::B3::Air::RegLivenessAdapter::maxIndex): Deleted.
+        * dfg/DFGAbstractInterpreter.h:
+        (JSC::DFG::AbstractInterpreter::forNode):
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::forAllValues):
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::dump):
+        * dfg/DFGAtTailAbstractState.cpp:
+        (JSC::DFG::AtTailAbstractState::createValueForNode):
+        (JSC::DFG::AtTailAbstractState::forNode):
+        * dfg/DFGAtTailAbstractState.h:
+        * dfg/DFGBasicBlock.h:
+        * dfg/DFGCombinedLiveness.cpp:
+        (JSC::DFG::liveNodesAtHead):
+        * dfg/DFGCombinedLiveness.h:
+        * dfg/DFGFlowIndexing.cpp: Added.
+        (JSC::DFG::FlowIndexing::FlowIndexing):
+        (JSC::DFG::FlowIndexing::~FlowIndexing):
+        (JSC::DFG::FlowIndexing::recompute):
+        * dfg/DFGFlowIndexing.h: Added.
+        (JSC::DFG::FlowIndexing::graph):
+        (JSC::DFG::FlowIndexing::numIndices):
+        (JSC::DFG::FlowIndexing::index):
+        (JSC::DFG::FlowIndexing::shadowIndex):
+        (JSC::DFG::FlowIndexing::nodeProjection):
+        * dfg/DFGFlowMap.h: Added.
+        (JSC::DFG::FlowMap::FlowMap):
+        (JSC::DFG::FlowMap::resize):
+        (JSC::DFG::FlowMap::graph):
+        (JSC::DFG::FlowMap::at):
+        (JSC::DFG::FlowMap::atShadow):
+        (WTF::printInternal):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::Graph):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::abstractValuesCache): Deleted.
+        * dfg/DFGInPlaceAbstractState.cpp:
+        (JSC::DFG::InPlaceAbstractState::InPlaceAbstractState):
+        (JSC::DFG::InPlaceAbstractState::beginBasicBlock):
+        (JSC::DFG::setLiveValues):
+        (JSC::DFG::InPlaceAbstractState::endBasicBlock):
+        (JSC::DFG::InPlaceAbstractState::merge):
+        * dfg/DFGInPlaceAbstractState.h:
+        (JSC::DFG::InPlaceAbstractState::createValueForNode):
+        (JSC::DFG::InPlaceAbstractState::forNode):
+        * dfg/DFGIntegerRangeOptimizationPhase.cpp:
+        * dfg/DFGLivenessAnalysisPhase.cpp:
+        (JSC::DFG::LivenessAnalysisPhase::LivenessAnalysisPhase):
+        (JSC::DFG::LivenessAnalysisPhase::run):
+        (JSC::DFG::LivenessAnalysisPhase::processBlock):
+        (JSC::DFG::LivenessAnalysisPhase::addChildUse): Deleted.
+        * dfg/DFGNode.h:
+        (JSC::DFG::NodeComparator::operator()):
+        (JSC::DFG::nodeListDump):
+        (JSC::DFG::nodeMapDump):
+        (JSC::DFG::nodeValuePairListDump):
+        (JSC::DFG::nodeComparator): Deleted.
+        * dfg/DFGNodeAbstractValuePair.cpp: Added.
+        (JSC::DFG::NodeAbstractValuePair::dump):
+        * dfg/DFGNodeAbstractValuePair.h: Added.
+        (JSC::DFG::NodeAbstractValuePair::NodeAbstractValuePair):
+        * dfg/DFGNodeFlowProjection.cpp: Added.
+        (JSC::DFG::NodeFlowProjection::dump):
+        * dfg/DFGNodeFlowProjection.h: Added.
+        (JSC::DFG::NodeFlowProjection::NodeFlowProjection):
+        (JSC::DFG::NodeFlowProjection::operator bool):
+        (JSC::DFG::NodeFlowProjection::kind):
+        (JSC::DFG::NodeFlowProjection::node):
+        (JSC::DFG::NodeFlowProjection::operator*):
+        (JSC::DFG::NodeFlowProjection::operator->):
+        (JSC::DFG::NodeFlowProjection::hash):
+        (JSC::DFG::NodeFlowProjection::operator==):
+        (JSC::DFG::NodeFlowProjection::operator!=):
+        (JSC::DFG::NodeFlowProjection::operator<):
+        (JSC::DFG::NodeFlowProjection::operator>):
+        (JSC::DFG::NodeFlowProjection::operator<=):
+        (JSC::DFG::NodeFlowProjection::operator>=):
+        (JSC::DFG::NodeFlowProjection::isHashTableDeletedValue):
+        (JSC::DFG::NodeFlowProjection::isStillValid):
+        (JSC::DFG::NodeFlowProjection::forEach):
+        (JSC::DFG::NodeFlowProjectionHash::hash):
+        (JSC::DFG::NodeFlowProjectionHash::equal):
+        * dfg/DFGStoreBarrierInsertionPhase.cpp:
+
 2016-11-03  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r208364.

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (208372 => 208373)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2016-11-04 05:28:35 UTC (rev 208373)
@@ -129,6 +129,13 @@
 		0F1E3A471534CBB9000F9456 /* DFGDoubleFormatState.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */; };
 		0F1E3A67153A21E2000F9456 /* DFGSilentRegisterSavePlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1E3A65153A21DF000F9456 /* DFGSilentRegisterSavePlan.h */; };
 		0F1FE51C1922A3BC006987C5 /* AbortReason.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F1FE51B1922A3BC006987C5 /* AbortReason.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		0F20177F1DCADC3300EA5950 /* DFGFlowIndexing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F20177D1DCADC3000EA5950 /* DFGFlowIndexing.cpp */; };
+		0F2017801DCADC3500EA5950 /* DFGFlowIndexing.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F20177E1DCADC3000EA5950 /* DFGFlowIndexing.h */; };
+		0F2017821DCADD4200EA5950 /* DFGFlowMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2017811DCADD4000EA5950 /* DFGFlowMap.h */; };
+		0F2017851DCAE14900EA5950 /* DFGNodeFlowProjection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2017841DCAE14700EA5950 /* DFGNodeFlowProjection.h */; };
+		0F2017861DCAE14C00EA5950 /* DFGNodeFlowProjection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2017831DCAE14700EA5950 /* DFGNodeFlowProjection.cpp */; };
+		0F2017891DCB942400EA5950 /* DFGNodeAbstractValuePair.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2017881DCB942200EA5950 /* DFGNodeAbstractValuePair.h */; };
+		0F20178A1DCB942600EA5950 /* DFGNodeAbstractValuePair.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2017871DCB942200EA5950 /* DFGNodeAbstractValuePair.cpp */; };
 		0F20C2591A8013AB00DA3229 /* VirtualRegister.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F20C2581A8013AB00DA3229 /* VirtualRegister.cpp */; };
 		0F21C27D14BE727A00ADC64B /* CodeSpecializationKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C27914BE727300ADC64B /* CodeSpecializationKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F21C27F14BEAA8200ADC64B /* BytecodeConventions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -2517,6 +2524,13 @@
 		0F1E3A501537C2CB000F9456 /* DFGSlowPathGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSlowPathGenerator.h; path = dfg/DFGSlowPathGenerator.h; sourceTree = "<group>"; };
 		0F1E3A65153A21DF000F9456 /* DFGSilentRegisterSavePlan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGSilentRegisterSavePlan.h; path = dfg/DFGSilentRegisterSavePlan.h; sourceTree = "<group>"; };
 		0F1FE51B1922A3BC006987C5 /* AbortReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbortReason.h; sourceTree = "<group>"; };
+		0F20177D1DCADC3000EA5950 /* DFGFlowIndexing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGFlowIndexing.cpp; path = dfg/DFGFlowIndexing.cpp; sourceTree = "<group>"; };
+		0F20177E1DCADC3000EA5950 /* DFGFlowIndexing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFlowIndexing.h; path = dfg/DFGFlowIndexing.h; sourceTree = "<group>"; };
+		0F2017811DCADD4000EA5950 /* DFGFlowMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFlowMap.h; path = dfg/DFGFlowMap.h; sourceTree = "<group>"; };
+		0F2017831DCAE14700EA5950 /* DFGNodeFlowProjection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGNodeFlowProjection.cpp; path = dfg/DFGNodeFlowProjection.cpp; sourceTree = "<group>"; };
+		0F2017841DCAE14700EA5950 /* DFGNodeFlowProjection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeFlowProjection.h; path = dfg/DFGNodeFlowProjection.h; sourceTree = "<group>"; };
+		0F2017871DCB942200EA5950 /* DFGNodeAbstractValuePair.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGNodeAbstractValuePair.cpp; path = dfg/DFGNodeAbstractValuePair.cpp; sourceTree = "<group>"; };
+		0F2017881DCB942200EA5950 /* DFGNodeAbstractValuePair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGNodeAbstractValuePair.h; path = dfg/DFGNodeAbstractValuePair.h; sourceTree = "<group>"; };
 		0F20C2581A8013AB00DA3229 /* VirtualRegister.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VirtualRegister.cpp; sourceTree = "<group>"; };
 		0F21C27914BE727300ADC64B /* CodeSpecializationKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeSpecializationKind.h; sourceTree = "<group>"; };
 		0F21C27E14BEAA8000ADC64B /* BytecodeConventions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeConventions.h; sourceTree = "<group>"; };
@@ -6729,8 +6743,6 @@
 				0FFFC94E14EF909500C72532 /* DFGCSEPhase.h */,
 				0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */,
 				0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */,
-				E322E5A01DA64435006E7709 /* DFGDOMJITPatchpointParams.cpp */,
-				E322E5A11DA64435006E7709 /* DFGDOMJITPatchpointParams.h */,
 				0F8F2B97172F04FD007DBDA5 /* DFGDesiredIdentifiers.cpp */,
 				0F8F2B98172F04FD007DBDA5 /* DFGDesiredIdentifiers.h */,
 				0FFC92131B94E83E0071DD66 /* DFGDesiredInferredType.h */,
@@ -6745,6 +6757,8 @@
 				0F5A1271192D9FDF008764A3 /* DFGDoesGC.cpp */,
 				0F5A1272192D9FDF008764A3 /* DFGDoesGC.h */,
 				0FD81AD0154FB4EB00983E72 /* DFGDominators.h */,
+				E322E5A01DA64435006E7709 /* DFGDOMJITPatchpointParams.cpp */,
+				E322E5A11DA64435006E7709 /* DFGDOMJITPatchpointParams.h */,
 				0F1E3A441534CBAD000F9456 /* DFGDoubleFormatState.h */,
 				0FD3C82014115CF800FD81CB /* DFGDriver.cpp */,
 				0FD3C82214115D0E00FD81CB /* DFGDriver.h */,
@@ -6761,6 +6775,9 @@
 				A78A976F179738B8009DF744 /* DFGFinalizer.h */,
 				0F2BDC12151C5D4A00CD8910 /* DFGFixupPhase.cpp */,
 				0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */,
+				0F20177D1DCADC3000EA5950 /* DFGFlowIndexing.cpp */,
+				0F20177E1DCADC3000EA5950 /* DFGFlowIndexing.h */,
+				0F2017811DCADD4000EA5950 /* DFGFlowMap.h */,
 				0F9D339417FFC4E60073C2BC /* DFGFlushedAt.cpp */,
 				0F9D339517FFC4E60073C2BC /* DFGFlushedAt.h */,
 				A7D89CE817A0B8CC00773AD8 /* DFGFlushFormat.cpp */,
@@ -6828,9 +6845,13 @@
 				A737810B1799EA2E00817533 /* DFGNaturalLoops.h */,
 				0FB4B51E16B62772003F696B /* DFGNode.cpp */,
 				86ECA3E9132DEF1C002B2AD7 /* DFGNode.h */,
+				0F2017871DCB942200EA5950 /* DFGNodeAbstractValuePair.cpp */,
+				0F2017881DCB942200EA5950 /* DFGNodeAbstractValuePair.h */,
 				0FB4B51F16B62772003F696B /* DFGNodeAllocator.h */,
 				0FA581B7150E952A00B9A2D9 /* DFGNodeFlags.cpp */,
 				0FA581B8150E952A00B9A2D9 /* DFGNodeFlags.h */,
+				0F2017831DCAE14700EA5950 /* DFGNodeFlowProjection.cpp */,
+				0F2017841DCAE14700EA5950 /* DFGNodeFlowProjection.h */,
 				0F5D085C1B8CF99D001143B4 /* DFGNodeOrigin.cpp */,
 				0F300B7718AB051100A6D72E /* DFGNodeOrigin.h */,
 				0FA581B9150E952A00B9A2D9 /* DFGNodeType.h */,
@@ -7612,6 +7633,7 @@
 				0FEC85721BDACDC70080FF74 /* AirBasicBlock.h in Headers */,
 				0F338DFA1BE96AA80013C88F /* B3CCallValue.h in Headers */,
 				0F338E161BF0276C0013C88F /* B3ValueKeyInlines.h in Headers */,
+				0F2017821DCADD4200EA5950 /* DFGFlowMap.h in Headers */,
 				0FEC85741BDACDC70080FF74 /* AirCCallSpecial.h in Headers */,
 				0FEC85761BDACDC70080FF74 /* AirCode.h in Headers */,
 				0F3730931C0D67EE00052BFA /* AirUseCounts.h in Headers */,
@@ -8498,6 +8520,7 @@
 				A7C1EAF017987AB600299DB2 /* CLoopStackInlines.h in Headers */,
 				BC18C4270E16F5CD00B34460 /* JSString.h in Headers */,
 				86E85539111B9968001AF51E /* JSStringBuilder.h in Headers */,
+				0F2017851DCAE14900EA5950 /* DFGNodeFlowProjection.h in Headers */,
 				E3555B8A1DAE03A500F36921 /* DOMJITCallDOMGetterPatchpoint.h in Headers */,
 				70EC0EC31AA0D7DA00B6AAFA /* JSStringIterator.h in Headers */,
 				0F070A471D543A8B006E7232 /* CellContainer.h in Headers */,
@@ -8595,6 +8618,7 @@
 				141448CB13A176EC00F5BA1A /* MarkedBlockSet.h in Headers */,
 				14D2F3DB139F4BE200491031 /* MarkedSpace.h in Headers */,
 				142D6F1213539A4100B02E86 /* MarkStack.h in Headers */,
+				0F2017891DCB942400EA5950 /* DFGNodeAbstractValuePair.h in Headers */,
 				8612E4CD152389EC00C836BE /* MatchResult.h in Headers */,
 				4340A4851A9051AF00D73CCA /* MathCommon.h in Headers */,
 				BC18C43C0E16F5CD00B34460 /* MathObject.h in Headers */,
@@ -8663,6 +8687,7 @@
 				0FB387901BFBC44D00E3AB1E /* AirOptimizeBlockOrder.h in Headers */,
 				DCEE220D1CEBAF75000C2396 /* DFGNullAbstractState.h in Headers */,
 				0FF729BA166AD360000F5BA3 /* ProfilerCompilation.h in Headers */,
+				0F2017801DCADC3500EA5950 /* DFGFlowIndexing.h in Headers */,
 				0FF729BB166AD360000F5BA3 /* ProfilerCompilationKind.h in Headers */,
 				0F4A38FA1C8E13DF00190318 /* SuperSampler.h in Headers */,
 				0FF729BC166AD360000F5BA3 /* ProfilerCompiledBytecode.h in Headers */,
@@ -9858,6 +9883,7 @@
 				A5840E20187B7B8600843B10 /* InjectedScriptModule.cpp in Sources */,
 				0FA762041DB9242600B7A2FD /* CollectionScope.cpp in Sources */,
 				148A7BEF1B82975A002D9157 /* InlineCallFrame.cpp in Sources */,
+				0F20178A1DCB942600EA5950 /* DFGNodeAbstractValuePair.cpp in Sources */,
 				0F24E55517F0B71C00ABB217 /* InlineCallFrameSet.cpp in Sources */,
 				A5CEEE14187F3BAD00E55C99 /* InspectorAgent.cpp in Sources */,
 				A593CF86184038CA00BFCE27 /* InspectorAgentRegistry.cpp in Sources */,
@@ -10087,6 +10113,7 @@
 				0F37308C1C0BD29100052BFA /* B3PhiChildren.cpp in Sources */,
 				14469DDF107EC7E700650446 /* MathObject.cpp in Sources */,
 				90213E3D123A40C200D422F3 /* MemoryStatistics.cpp in Sources */,
+				0F20177F1DCADC3300EA5950 /* DFGFlowIndexing.cpp in Sources */,
 				0FB5467D14F5CFD6002C2989 /* MethodOfGettingAValueProfile.cpp in Sources */,
 				E3794E751B77EB97005543AE /* ModuleAnalyzer.cpp in Sources */,
 				E355F3521B7DC85300C50DC5 /* ModuleLoaderPrototype.cpp in Sources */,
@@ -10184,6 +10211,7 @@
 				A5FD0067189AFE9C00633231 /* ScriptArguments.cpp in Sources */,
 				A5FD006D189B00AA00633231 /* ScriptCallFrame.cpp in Sources */,
 				A5FD006F189B00AA00633231 /* ScriptCallStack.cpp in Sources */,
+				0F2017861DCAE14C00EA5950 /* DFGNodeFlowProjection.cpp in Sources */,
 				A5FD007D189B0B4C00633231 /* ScriptCallStackFactory.cpp in Sources */,
 				A503FA25188EFFFD00110F14 /* ScriptDebugServer.cpp in Sources */,
 				A55D93A5185012A800400DED /* ScriptFunctionCall.cpp in Sources */,

Modified: trunk/Source/_javascript_Core/b3/air/AirLiveness.h (208372 => 208373)


--- trunk/Source/_javascript_Core/b3/air/AirLiveness.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/b3/air/AirLiveness.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -46,7 +46,7 @@
 
     TmpLivenessAdapter(Code&) { }
 
-    static unsigned maxIndex(Code& code)
+    static unsigned numIndices(Code& code)
     {
         unsigned numTmps = code.numTmps(adapterType);
         return AbsoluteTmpMapper<adapterType>::absoluteIndex(numTmps);
@@ -65,9 +65,9 @@
     {
     }
 
-    static unsigned maxIndex(Code& code)
+    static unsigned numIndices(Code& code)
     {
-        return code.stackSlots().size() - 1;
+        return code.stackSlots().size();
     }
     static bool acceptsType(Arg::Type) { return true; }
     static unsigned valueToIndex(StackSlot* stackSlot) { return stackSlot->index(); }
@@ -83,9 +83,9 @@
 
     RegLivenessAdapter(Code&) { }
 
-    static unsigned maxIndex(Code&)
+    static unsigned numIndices(Code&)
     {
-        return Reg::maxIndex();
+        return Reg::maxIndex() + 1;
     }
 
     static bool acceptsType(Arg::Type) { return true; }
@@ -101,7 +101,7 @@
     
     AbstractLiveness(Code& code)
         : Adapter(code)
-        , m_workset(Adapter::maxIndex(code))
+        , m_workset(Adapter::numIndices(code))
         , m_liveAtHead(code.size())
         , m_liveAtTail(code.size())
     {

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreter.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -31,6 +31,7 @@
 #include "DFGBranchDirection.h"
 #include "DFGGraph.h"
 #include "DFGNode.h"
+#include "DFGNodeFlowProjection.h"
 #include "DFGPhiChildren.h"
 
 namespace JSC { namespace DFG {
@@ -41,7 +42,7 @@
     AbstractInterpreter(Graph&, AbstractStateType&);
     ~AbstractInterpreter();
     
-    AbstractValue& forNode(Node* node)
+    AbstractValue& forNode(NodeFlowProjection node)
     {
         return m_state.forNode(node);
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractInterpreterInlines.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -2817,6 +2817,7 @@
             
     case Phi:
         RELEASE_ASSERT(m_graph.m_form == SSA);
+        forNode(node) = forNode(NodeFlowProjection(node, NodeFlowProjection::Shadow));
         // The state of this node would have already been decided, but it may have become a
         // constant, in which case we'd like to know.
         if (forNode(node).m_value)
@@ -2824,8 +2825,11 @@
         break;
         
     case Upsilon: {
-        m_state.createValueForNode(node->phi());
-        forNode(node->phi()) = forNode(node->child1());
+        NodeFlowProjection shadow(node->phi(), NodeFlowProjection::Shadow);
+        if (shadow.isStillValid()) {
+            m_state.createValueForNode(shadow);
+            forNode(shadow) = forNode(node->child1());
+        }
         break;
     }
         
@@ -2977,11 +2981,18 @@
     else
         clobberLimit++;
     ASSERT(clobberLimit <= m_state.block()->size());
-    for (size_t i = clobberLimit; i--;)
-        functor(forNode(m_state.block()->at(i)));
+    for (size_t i = clobberLimit; i--;) {
+        NodeFlowProjection::forEach(
+            m_state.block()->at(i),
+            [&] (NodeFlowProjection nodeProjection) {
+                functor(forNode(nodeProjection));
+            });
+    }
     if (m_graph.m_form == SSA) {
-        for (Node* node : m_state.block()->ssa->liveAtHead)
-            functor(forNode(node));
+        for (NodeFlowProjection node : m_state.block()->ssa->liveAtHead) {
+            if (node.isStillValid())
+                functor(forNode(node));
+        }
     }
     for (size_t i = m_state.variables().numberOfArguments(); i--;)
         functor(m_state.variables().argument(i));
@@ -3037,9 +3048,9 @@
 void AbstractInterpreter<AbstractStateType>::dump(PrintStream& out)
 {
     CommaPrinter comma(" ");
-    HashSet<Node*> seen;
+    HashSet<NodeFlowProjection> seen;
     if (m_graph.m_form == SSA) {
-        for (Node* node : m_state.block()->ssa->liveAtHead) {
+        for (NodeFlowProjection node : m_state.block()->ssa->liveAtHead) {
             seen.add(node);
             AbstractValue& value = forNode(node);
             if (value.isClear())
@@ -3048,15 +3059,17 @@
         }
     }
     for (size_t i = 0; i < m_state.block()->size(); ++i) {
-        Node* node = m_state.block()->at(i);
-        seen.add(node);
-        AbstractValue& value = forNode(node);
-        if (value.isClear())
-            continue;
-        out.print(comma, node, ":", value);
+        NodeFlowProjection::forEach(
+            m_state.block()->at(i), [&] (NodeFlowProjection nodeProjection) {
+                seen.add(nodeProjection);
+                AbstractValue& value = forNode(nodeProjection);
+                if (value.isClear())
+                    return;
+                out.print(comma, nodeProjection, ":", value);
+            });
     }
     if (m_graph.m_form == SSA) {
-        for (Node* node : m_state.block()->ssa->liveAtTail) {
+        for (NodeFlowProjection node : m_state.block()->ssa->liveAtTail) {
             if (seen.contains(node))
                 continue;
             AbstractValue& value = forNode(node);

Modified: trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.cpp (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.cpp	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -47,16 +47,16 @@
 
 AtTailAbstractState::~AtTailAbstractState() { }
 
-void AtTailAbstractState::createValueForNode(Node* node)
+void AtTailAbstractState::createValueForNode(NodeFlowProjection node)
 {
     m_valuesAtTailMap.at(m_block).add(node, AbstractValue());
 }
 
-AbstractValue& AtTailAbstractState::forNode(Node* node)
+AbstractValue& AtTailAbstractState::forNode(NodeFlowProjection node)
 {
     auto& valuesAtTail = m_valuesAtTailMap.at(m_block);
-    HashMap<Node*, AbstractValue>::iterator iter = valuesAtTail.find(node);
-    DFG_ASSERT(m_graph, node, iter != valuesAtTail.end());
+    HashMap<NodeFlowProjection, AbstractValue>::iterator iter = valuesAtTail.find(node);
+    DFG_ASSERT(m_graph, node.node(), iter != valuesAtTail.end());
     return iter->value;
 }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGAtTailAbstractState.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -31,6 +31,7 @@
 #include "DFGBasicBlock.h"
 #include "DFGBlockMap.h"
 #include "DFGGraph.h"
+#include "DFGNodeFlowProjection.h"
 
 namespace JSC { namespace DFG { 
 
@@ -47,8 +48,8 @@
         m_block = block;
     }
     
-    void createValueForNode(Node*);
-    AbstractValue& forNode(Node*);
+    void createValueForNode(NodeFlowProjection);
+    AbstractValue& forNode(NodeFlowProjection);
     AbstractValue& forNode(Edge edge) { return forNode(edge.node()); }
     Operands<AbstractValue>& variables() { return m_block->valuesAtTail; }
     
@@ -66,7 +67,7 @@
 
 private:
     Graph& m_graph;
-    BlockMap<HashMap<Node*, AbstractValue>> m_valuesAtTailMap;
+    BlockMap<HashMap<NodeFlowProjection, AbstractValue>> m_valuesAtTailMap;
     BasicBlock* m_block { nullptr };
 };
 

Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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,6 +33,7 @@
 #include "DFGBranchDirection.h"
 #include "DFGFlushedAt.h"
 #include "DFGNode.h"
+#include "DFGNodeAbstractValuePair.h"
 #include "DFGNodeOrigin.h"
 #include "DFGStructureClobberState.h"
 #include "Operands.h"
@@ -248,12 +249,8 @@
         AvailabilityMap availabilityAtHead;
         AvailabilityMap availabilityAtTail;
 
-        Vector<Node*> liveAtHead;
-        Vector<Node*> liveAtTail;
-        struct NodeAbstractValuePair {
-            Node* node;
-            AbstractValue value;
-        };
+        Vector<NodeFlowProjection> liveAtHead;
+        Vector<NodeFlowProjection> liveAtTail;
         Vector<NodeAbstractValuePair> valuesAtHead;
         Vector<NodeAbstractValuePair> valuesAtTail;
         

Modified: trunk/Source/_javascript_Core/dfg/DFGCombinedLiveness.cpp (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGCombinedLiveness.cpp	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGCombinedLiveness.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -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
@@ -38,8 +38,10 @@
 HashSet<Node*> liveNodesAtHead(Graph& graph, BasicBlock* block)
 {
     HashSet<Node*> seen;
-    for (Node* node : block->ssa->liveAtHead)
-        seen.add(node);
+    for (NodeFlowProjection node : block->ssa->liveAtHead) {
+        if (node.kind() == NodeFlowProjection::Primary)
+            seen.add(node.node());
+    }
     
     AvailabilityMap& availabilityMap = block->ssa->availabilityAtHead;
     graph.forAllLocalsLiveInBytecode(

Modified: trunk/Source/_javascript_Core/dfg/DFGCombinedLiveness.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGCombinedLiveness.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGCombinedLiveness.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -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
@@ -35,6 +35,11 @@
 // Returns the set of nodes live at tail, both due to due DFG and due to bytecode (i.e. OSR exit).
 HashSet<Node*> liveNodesAtHead(Graph&, BasicBlock*);
 
+// WARNING: This currently does not reason about the liveness of shadow values. The execution
+// semantics of DFG SSA are that an Upsilon stores to the shadow value of a Phi, and the Phi loads
+// from that shadow value. Hence, the shadow values are like variables, and have liveness. The normal
+// liveness analysis will tell you about the liveness of shadow values. It's OK to ignore shadow
+// values if you treat Upsilon as an opaque escape, and all of the clients of CombinedLiveness do so.
 struct CombinedLiveness {
     CombinedLiveness() { }
     

Added: trunk/Source/_javascript_Core/dfg/DFGFlowIndexing.cpp (0 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGFlowIndexing.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGFlowIndexing.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "DFGFlowIndexing.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+FlowIndexing::FlowIndexing(Graph& graph)
+    : m_graph(graph)
+    , m_numIndices(0)
+{
+    recompute();
+}
+
+FlowIndexing::~FlowIndexing()
+{
+}
+
+void FlowIndexing::recompute()
+{
+    unsigned numNodeIndices = m_graph.maxNodeCount();
+    
+    m_nodeIndexToShadowIndex.resize(numNodeIndices);
+    m_nodeIndexToShadowIndex.fill(UINT_MAX);
+    
+    m_shadowIndexToNodeIndex.resize(0);
+
+    m_numIndices = numNodeIndices;
+
+    for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+        for (Node* node : *block) {
+            if (node->op() != Phi)
+                continue;
+            
+            unsigned nodeIndex = node->index();
+            unsigned shadowIndex = m_numIndices++;
+            m_nodeIndexToShadowIndex[nodeIndex] = shadowIndex;
+            m_shadowIndexToNodeIndex.append(nodeIndex);
+            DFG_ASSERT(m_graph, nullptr, m_shadowIndexToNodeIndex.size() + numNodeIndices == m_numIndices);
+            DFG_ASSERT(m_graph, nullptr, m_shadowIndexToNodeIndex[shadowIndex - numNodeIndices] == nodeIndex);
+        }
+    }
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+

Added: trunk/Source/_javascript_Core/dfg/DFGFlowIndexing.h (0 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGFlowIndexing.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGFlowIndexing.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGGraph.h"
+#include "DFGNodeFlowProjection.h"
+
+namespace JSC { namespace DFG {
+
+// This is a mapping from nodes to unique, dense indices that can be used for creating fast
+// Node-keyed maps. The special part is that it also allocated indices for the shadow values of Phi
+// nodes, which is needed for any flow-sensitive analysis.
+class FlowIndexing {
+public:
+    FlowIndexing(Graph&);
+    ~FlowIndexing();
+    
+    void recompute();
+    
+    Graph& graph() const { return m_graph; }
+    
+    unsigned numIndices() const { return m_numIndices; }
+    
+    unsigned index(unsigned nodeIndex) const { return nodeIndex; }
+    
+    unsigned index(Node* node) const { return index(node->index()); }
+    
+    unsigned shadowIndex(unsigned nodeIndex) const
+    {
+        return m_nodeIndexToShadowIndex[nodeIndex];
+    }
+    
+    unsigned shadowIndex(Node* node) const
+    {
+        DFG_ASSERT(m_graph, node, node->op() == Phi);
+        return shadowIndex(node->index());
+    }
+    
+    unsigned index(unsigned nodeIndex, NodeFlowProjection::Kind kind) const
+    {
+        switch (kind) {
+        case NodeFlowProjection::Primary:
+            return index(nodeIndex);
+        case NodeFlowProjection::Shadow:
+            return shadowIndex(nodeIndex);
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+    
+    unsigned index(Node *node, NodeFlowProjection::Kind kind) const
+    {
+        switch (kind) {
+        case NodeFlowProjection::Primary:
+            return index(node);
+        case NodeFlowProjection::Shadow:
+            return shadowIndex(node);
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return 0;
+    }
+    
+    unsigned index(NodeFlowProjection projection) const
+    {
+        return index(projection.node(), projection.kind());
+    }
+    
+    NodeFlowProjection nodeProjection(unsigned index) const
+    {
+        if (index < m_nodeIndexToShadowIndex.size())
+            return NodeFlowProjection(m_graph.nodeAt(index));
+        return NodeFlowProjection(
+            m_graph.nodeAt(m_shadowIndexToNodeIndex[index - m_nodeIndexToShadowIndex.size()]),
+            NodeFlowProjection::Shadow);
+    }
+    
+private:
+    Graph& m_graph;
+    unsigned m_numIndices;
+    Vector<unsigned, 0, UnsafeVectorOverflow> m_nodeIndexToShadowIndex;
+    Vector<unsigned, 0, UnsafeVectorOverflow> m_shadowIndexToNodeIndex;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+

Added: trunk/Source/_javascript_Core/dfg/DFGFlowMap.h (0 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGFlowMap.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGFlowMap.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGFlowIndexing.h"
+#include "DFGGraph.h"
+#include "DFGNode.h"
+
+namespace JSC { namespace DFG {
+
+// This is a mapping from nodes to values that is useful for flow-sensitive analysis. In such an
+// analysis, at every point in the program we need to consider the values of nodes plus the shadow
+// values of Phis. This makes it easy to do both of those things.
+template<typename T>
+class FlowMap {
+public:
+    FlowMap(Graph& graph)
+        : m_graph(graph)
+    {
+        resize();
+    }
+    
+    // Call this if the number of nodes in the graph has changed. Note that this does not reset any
+    // entries.
+    void resize()
+    {
+        m_map.resize(m_graph.maxNodeCount());
+        m_shadowMap.resize(m_graph.maxNodeCount());
+    }
+    
+    Graph& graph() const { return m_graph; }
+    
+    T& at(unsigned nodeIndex)
+    {
+        return m_map[nodeIndex];
+    }
+    
+    T& at(Node* node)
+    {
+        return at(node->index());
+    }
+    
+    T& atShadow(unsigned nodeIndex)
+    {
+        return m_shadowMap[nodeIndex];
+    }
+    
+    T& atShadow(Node* node)
+    {
+        return atShadow(node->index());
+    }
+    
+    T& at(unsigned nodeIndex, NodeFlowProjection::Kind kind)
+    {
+        switch (kind) {
+        case NodeFlowProjection::Primary:
+            return at(nodeIndex);
+        case NodeFlowProjection::Shadow:
+            return atShadow(nodeIndex);
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return *bitwise_cast<T*>(nullptr);
+    }
+    
+    T& at(Node* node, NodeFlowProjection::Kind kind)
+    {
+        return at(node->index(), kind);
+    }
+    
+    T& at(NodeFlowProjection projection)
+    {
+        return at(projection.node(), projection.kind());
+    }
+    
+    const T& at(unsigned nodeIndex) const { return const_cast<FlowMap*>(this)->at(nodeIndex); }
+    const T& at(Node* node) const { return const_cast<FlowMap*>(this)->at(node); }
+    const T& atShadow(unsigned nodeIndex) const { return const_cast<FlowMap*>(this)->atShadow(nodeIndex); }
+    const T& atShadow(Node* node) const { return const_cast<FlowMap*>(this)->atShadow(node); }
+    const T& at(unsigned nodeIndex, NodeFlowProjection::Kind kind) const { return const_cast<FlowMap*>(this)->at(nodeIndex, kind); }
+    const T& at(Node* node, NodeFlowProjection::Kind kind) const { return const_cast<FlowMap*>(this)->at(node, kind); }
+    const T& at(NodeFlowProjection projection) const { return const_cast<FlowMap*>(this)->at(projection); }
+    
+private:
+    Graph& m_graph;
+    Vector<T, 0, UnsafeVectorOverflow> m_map;
+    Vector<T, 0, UnsafeVectorOverflow> m_shadowMap;
+};
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+template<typename T>
+void printInternal(PrintStream& out, const JSC::DFG::FlowMap<T>& map)
+{
+    CommaPrinter comma;
+    for (unsigned i = 0; i < map.graph().maxNodeCount(); ++i) {
+        if (JSC::DFG::Node* node = map.graph().nodeAt(i)) {
+            if (const T& value = map.at(node))
+                out.print(comma, node, "=>", value);
+        }
+    }
+    for (unsigned i = 0; i < map.graph().maxNodeCount(); ++i) {
+        if (JSC::DFG::Node* node = map.graph().nodeAt(i)) {
+            if (const T& value = map.atShadow(node))
+                out.print(comma, "shadow(", node, ")=>", value);
+        }
+    }
+}
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)
+

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -40,6 +40,8 @@
 #include "DFGClobbersExitState.h"
 #include "DFGControlEquivalenceAnalysis.h"
 #include "DFGDominators.h"
+#include "DFGFlowIndexing.h"
+#include "DFGFlowMap.h"
 #include "DFGJITCode.h"
 #include "DFGMayExit.h"
 #include "DFGNaturalLoops.h"
@@ -83,6 +85,9 @@
     ASSERT(m_profiledBlock);
     
     m_hasDebuggerEnabled = m_profiledBlock->wasCompiledWithDebuggingOpcodes() || Options::forceDebuggerBytecodeGeneration();
+    
+    m_indexingCache = std::make_unique<FlowIndexing>(*this);
+    m_abstractValuesCache = std::make_unique<FlowMap<AbstractValue>>(*this);
 }
 
 Graph::~Graph()

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -59,9 +59,12 @@
 class CFG;
 class ControlEquivalenceAnalysis;
 class Dominators;
+class FlowIndexing;
 class NaturalLoops;
 class PrePostNumbering;
 
+template<typename> class FlowMap;
+
 #define DFG_NODE_DO_TO_CHILDREN(graph, node, thingToDo) do {            \
         Node* _node = (node);                                           \
         if (_node->flags() & NodeHasVarArgs) {                          \
@@ -201,8 +204,6 @@
     Node* nodeAt(unsigned index) const { return m_nodesByIndex[index]; }
     void packNodeIndices();
 
-    Vector<AbstractValue, 0, UnsafeVectorOverflow>& abstractValuesCache() { return m_abstractValuesCache; }
-
     void dethread();
     
     FrozenValue* freeze(JSValue); // We use weak freezing by default.
@@ -935,6 +936,9 @@
     RefCountState m_refCountState;
     bool m_hasDebuggerEnabled;
     bool m_hasExceptionHandlers { false };
+    std::unique_ptr<FlowIndexing> m_indexingCache;
+    std::unique_ptr<FlowMap<AbstractValue>> m_abstractValuesCache;
+
 private:
     void addNodeToMapByIndex(Node*);
 
@@ -972,7 +976,6 @@
 
     Vector<Node*, 0, UnsafeVectorOverflow> m_nodesByIndex;
     Vector<unsigned, 0, UnsafeVectorOverflow> m_nodeIndexFreeList;
-    Vector<AbstractValue, 0, UnsafeVectorOverflow> m_abstractValuesCache;
 };
 
 } } // namespace JSC::DFG

Modified: trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -41,7 +41,7 @@
 
 InPlaceAbstractState::InPlaceAbstractState(Graph& graph)
     : m_graph(graph)
-    , m_abstractValues(graph.abstractValuesCache())
+    , m_abstractValues(*graph.m_abstractValuesCache)
     , m_variables(m_graph.m_codeBlock->numParameters(), graph.m_localVars)
     , m_block(0)
 {
@@ -57,19 +57,22 @@
     ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals());
     ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals());
 
-    // Certain phases insert nodes in a block after running through it.
-    // We cannot reserve the space for AbstractValues when initializing AbstractState because the number of values
-    // can increase as we execute. Instead, we increase the size as needed before processing each block.
-    m_abstractValues.resize(m_graph.maxNodeCount());
+    m_abstractValues.resize();
     
-    for (size_t i = 0; i < basicBlock->size(); i++)
-        forNode(basicBlock->at(i)).clear();
+    for (size_t i = 0; i < basicBlock->size(); i++) {
+        NodeFlowProjection::forEach(
+            basicBlock->at(i), [&] (NodeFlowProjection nodeProjection) {
+                forNode(nodeProjection).clear();
+            });
+    }
 
     m_variables = basicBlock->valuesAtHead;
     
     if (m_graph.m_form == SSA) {
-        for (auto& entry : basicBlock->ssa->valuesAtHead)
-            forNode(entry.node) = entry.value;
+        for (NodeAbstractValuePair& entry : basicBlock->ssa->valuesAtHead) {
+            if (entry.node.isStillValid())
+                forNode(entry.node) = entry.value;
+        }
     }
     basicBlock->cfaShouldRevisit = false;
     basicBlock->cfaHasVisited = true;
@@ -80,12 +83,12 @@
     m_structureClobberState = basicBlock->cfaStructureClobberStateAtHead;
 }
 
-static void setLiveValues(Vector<BasicBlock::SSAData::NodeAbstractValuePair>& values, const Vector<Node*>& live)
+static void setLiveValues(Vector<NodeAbstractValuePair>& values, const Vector<NodeFlowProjection>& live)
 {
     values.resize(0);
     values.reserveCapacity(live.size());
-    for (Node* node : live)
-        values.uncheckedAppend(BasicBlock::SSAData::NodeAbstractValuePair { node, AbstractValue() });
+    for (NodeFlowProjection node : live)
+        values.uncheckedAppend(NodeAbstractValuePair { node, AbstractValue() });
 }
 
 void InPlaceAbstractState::initialize()
@@ -199,7 +202,7 @@
         for (size_t i = 0; i < block->valuesAtTail.size(); ++i)
             block->valuesAtTail[i].merge(m_variables[i]);
 
-        for (auto& valueAtTail : block->ssa->valuesAtTail) {
+        for (NodeAbstractValuePair& valueAtTail : block->ssa->valuesAtTail) {
             AbstractValue& valueAtNode = forNode(valueAtTail.node);
             valueAtTail.value.merge(valueAtNode);
             valueAtNode = valueAtTail.value;
@@ -291,13 +294,13 @@
         for (size_t i = from->valuesAtTail.size(); i--;)
             changed |= to->valuesAtHead[i].merge(from->valuesAtTail[i]);
 
-        for (auto& entry : to->ssa->valuesAtHead) {
-            Node* node = entry.node;
+        for (NodeAbstractValuePair& entry : to->ssa->valuesAtHead) {
+            NodeFlowProjection node = entry.node;
             if (verbose)
                 dataLog("      Merging for ", node, ": from ", forNode(node), " to ", entry.value, "\n");
 #ifndef NDEBUG
             unsigned valueCountInFromBlock = 0;
-            for (auto& fromBlockValueAtTail : from->ssa->valuesAtTail) {
+            for (NodeAbstractValuePair& fromBlockValueAtTail : from->ssa->valuesAtTail) {
                 if (fromBlockValueAtTail.node == node) {
                     ASSERT(fromBlockValueAtTail.value == forNode(node));
                     ++valueCountInFromBlock;

Modified: trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -29,6 +29,7 @@
 
 #include "DFGAbstractValue.h"
 #include "DFGBranchDirection.h"
+#include "DFGFlowMap.h"
 #include "DFGGraph.h"
 #include "DFGNode.h"
 
@@ -43,11 +44,11 @@
     
     explicit operator bool() const { return true; }
     
-    void createValueForNode(Node*) { }
+    void createValueForNode(NodeFlowProjection) { }
     
-    AbstractValue& forNode(Node* node)
+    AbstractValue& forNode(NodeFlowProjection node)
     {
-        return m_abstractValues[node->index()];
+        return m_abstractValues.at(node);
     }
     
     AbstractValue& forNode(Edge edge)
@@ -132,7 +133,7 @@
     
     Graph& m_graph;
 
-    Vector<AbstractValue, 0, UnsafeVectorOverflow>& m_abstractValues;
+    FlowMap<AbstractValue>& m_abstractValues;
     Operands<AbstractValue> m_variables;
     BasicBlock* m_block;
     

Modified: trunk/Source/_javascript_Core/dfg/DFGIntegerRangeOptimizationPhase.cpp (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGIntegerRangeOptimizationPhase.cpp	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGIntegerRangeOptimizationPhase.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -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,6 +32,7 @@
 #include "DFGBlockSet.h"
 #include "DFGGraph.h"
 #include "DFGInsertionSet.h"
+#include "DFGNodeFlowProjection.h"
 #include "DFGPhase.h"
 #include "DFGPredictionPropagationPhase.h"
 #include "DFGVariableAccessDataDump.h"
@@ -121,7 +122,7 @@
     {
     }
     
-    Relationship(Node* left, Node* right, Kind kind, int offset = 0)
+    Relationship(NodeFlowProjection left, NodeFlowProjection right, Kind kind, int offset = 0)
         : m_left(left)
         , m_right(right)
         , m_kind(kind)
@@ -132,17 +133,17 @@
         RELEASE_ASSERT(m_left != m_right);
     }
     
-    static Relationship safeCreate(Node* left, Node* right, Kind kind, int offset = 0)
+    static Relationship safeCreate(NodeFlowProjection left, NodeFlowProjection right, Kind kind, int offset = 0)
     {
-        if (!left || !right || left == right)
+        if (!left.isStillValid() || !right.isStillValid() || left == right)
             return Relationship();
         return Relationship(left, right, kind, offset);
     }
 
-    explicit operator bool() const { return m_left; }
+    explicit operator bool() const { return !!m_left; }
     
-    Node* left() const { return m_left; }
-    Node* right() const { return m_right; }
+    NodeFlowProjection left() const { return m_left; }
+    NodeFlowProjection right() const { return m_right; }
     Kind kind() const { return m_kind; }
     int offset() const { return m_offset; }
 
@@ -258,7 +259,7 @@
     // If possible, returns a form of this relationship where the given node is the left
     // side. Returns a null relationship if this relationship cannot say anything about this
     // node.
-    Relationship forNode(Node* node) const
+    Relationship forNode(NodeFlowProjection node) const
     {
         if (m_left == node)
             return *this;
@@ -267,7 +268,7 @@
         return Relationship();
     }
     
-    void setLeft(Node* left)
+    void setLeft(NodeFlowProjection left)
     {
         RELEASE_ASSERT(left != m_right);
         m_left = left;
@@ -984,13 +985,13 @@
         RELEASE_ASSERT_NOT_REACHED();
     }
     
-    Node* m_left;
-    Node* m_right;
+    NodeFlowProjection m_left;
+    NodeFlowProjection m_right;
     Kind m_kind;
     int m_offset; // This offset can be arbitrarily large.
 };
 
-typedef HashMap<Node*, Vector<Relationship>> RelationshipMap;
+typedef HashMap<NodeFlowProjection, Vector<Relationship>> RelationshipMap;
 
 class IntegerRangeOptimizationPhase : public Phase {
 public:
@@ -1314,7 +1315,7 @@
                         if (relationship.minValueOfLeft() >= 0)
                             nonNegative = true;
                         
-                        if (relationship.right() == node->child2()) {
+                        if (relationship.right() == node->child2().node()) {
                             if (relationship.kind() == Relationship::Equal
                                 && relationship.offset() < 0)
                                 lessThanLength = true;
@@ -1491,23 +1492,16 @@
         }
             
         case Upsilon: {
-            setRelationship(
-                Relationship::safeCreate(
-                    node->child1().node(), node->phi(), Relationship::Equal, 0));
+            setEquivalence(
+                node->child1().node(),
+                NodeFlowProjection(node->phi(), NodeFlowProjection::Shadow));
+            break;
+        }
             
-            auto iter = m_relationships.find(node->child1().node());
-            if (iter != m_relationships.end()) {
-                Vector<Relationship> toAdd;
-                for (Relationship relationship : iter->value) {
-                    Relationship newRelationship = relationship;
-                    if (node->phi() == newRelationship.right())
-                        continue;
-                    newRelationship.setLeft(node->phi());
-                    toAdd.append(newRelationship);
-                }
-                for (Relationship relationship : toAdd)
-                    setRelationship(relationship);
-            }
+        case Phi: {
+            setEquivalence(
+                NodeFlowProjection(node, NodeFlowProjection::Shadow),
+                node);
             break;
         }
             
@@ -1516,6 +1510,26 @@
         }
     }
     
+    void setEquivalence(NodeFlowProjection oldNode, NodeFlowProjection newNode)
+    {
+        setRelationship(Relationship::safeCreate(oldNode, newNode, Relationship::Equal, 0));
+        
+        auto iter = m_relationships.find(oldNode);
+        if (iter != m_relationships.end()) {
+            Vector<Relationship> toAdd;
+            for (Relationship relationship : iter->value) {
+                Relationship newRelationship = relationship;
+                // Avoid creating any kind of self-relationship.
+                if (newNode.node() == newRelationship.right().node())
+                    continue;
+                newRelationship.setLeft(newNode);
+                toAdd.append(newRelationship);
+            }
+            for (Relationship relationship : toAdd)
+                setRelationship(relationship);
+        }
+    }
+            
     void setRelationship(Relationship relationship, unsigned timeToLive = 1)
     {
         setRelationship(m_relationships, relationship, timeToLive);
@@ -1669,7 +1683,7 @@
         
         if (m_seenBlocks.add(target)) {
             // This is a new block. We copy subject to liveness pruning.
-            auto isLive = [&] (Node* node) {
+            auto isLive = [&] (NodeFlowProjection node) {
                 if (node == m_zero)
                     return true;
                 return target->ssa->liveAtHead.contains(node);
@@ -1701,7 +1715,7 @@
         // assigned would only happen if we have not processed the node's predecessor. We
         // shouldn't process blocks until we have processed the block's predecessor because we
         // are using reverse postorder.
-        Vector<Node*> toRemove;
+        Vector<NodeFlowProjection> toRemove;
         bool changed = false;
         for (auto& entry : m_relationshipsAtHead[target]) {
             auto iter = relationshipMap.find(entry.key);
@@ -1791,7 +1805,7 @@
             entry.value = mergedRelationships;
             changed = true;
         }
-        for (Node* node : toRemove)
+        for (NodeFlowProjection node : toRemove)
             m_relationshipsAtHead[target].remove(node);
         
         return changed;

Modified: trunk/Source/_javascript_Core/dfg/DFGLivenessAnalysisPhase.cpp (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGLivenessAnalysisPhase.cpp	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGLivenessAnalysisPhase.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -30,6 +30,7 @@
 
 #include "DFGBasicBlockInlines.h"
 #include "DFGBlockMapInlines.h"
+#include "DFGFlowIndexing.h"
 #include "DFGGraph.h"
 #include "DFGInsertionSet.h"
 #include "DFGPhase.h"
@@ -44,10 +45,12 @@
     LivenessAnalysisPhase(Graph& graph)
         : Phase(graph, "liveness analysis")
         , m_dirtyBlocks(m_graph.numBlocks())
+        , m_indexing(*m_graph.m_indexingCache)
         , m_liveAtHead(m_graph)
         , m_liveAtTail(m_graph)
-        , m_workset(graph.maxNodeCount() - 1)
     {
+        m_graph.m_indexingCache->recompute();
+        m_workset = std::make_unique<IndexSparseSet<UnsafeVectorOverflow>>(m_graph.m_indexingCache->numIndices());
     }
 
     bool run()
@@ -80,20 +83,20 @@
                 continue;
 
             {
-                const auto& liveAtHeadIndices = m_liveAtHead[blockIndex];
-                Vector<Node*>& liveAtHead = block->ssa->liveAtHead;
+                const Vector<unsigned, 0, UnsafeVectorOverflow, 1>& liveAtHeadIndices = m_liveAtHead[blockIndex];
+                Vector<NodeFlowProjection>& liveAtHead = block->ssa->liveAtHead;
                 liveAtHead.resize(0);
                 liveAtHead.reserveCapacity(liveAtHeadIndices.size());
                 for (unsigned index : liveAtHeadIndices)
-                    liveAtHead.uncheckedAppend(m_graph.nodeAt(index));
+                    liveAtHead.uncheckedAppend(m_indexing.nodeProjection(index));
             }
             {
-                const auto& liveAtTailIndices = m_liveAtTail[blockIndex];
-                Vector<Node*>& liveAtTail = block->ssa->liveAtTail;
+                const HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>>& liveAtTailIndices = m_liveAtTail[blockIndex];
+                Vector<NodeFlowProjection>& liveAtTail = block->ssa->liveAtTail;
                 liveAtTail.resize(0);
                 liveAtTail.reserveCapacity(liveAtTailIndices.size());
                 for (unsigned index : m_liveAtTail[blockIndex])
-                    liveAtTail.uncheckedAppend(m_graph.nodeAt(index));
+                    liveAtTail.uncheckedAppend(m_indexing.nodeProjection(index));
             }
         }
 
@@ -106,67 +109,57 @@
         BasicBlock* block = m_graph.block(blockIndex);
         ASSERT_WITH_MESSAGE(block, "Only dirty blocks needs updates. A null block should never be dirty.");
 
-        m_workset.clear();
+        m_workset->clear();
         for (unsigned index : m_liveAtTail[blockIndex])
-            m_workset.add(index);
+            m_workset->add(index);
 
         for (unsigned nodeIndex = block->size(); nodeIndex--;) {
             Node* node = block->at(nodeIndex);
 
-            // Given an Upsilon:
-            //
-            //    n: Upsilon(@x, ^p)
-            //
-            // We say that it def's @p and @n and uses @x.
-            //
-            // Given a Phi:
-            //
-            //    p: Phi()
-            //
-            // We say nothing. It's neither a use nor a def.
-            //
-            // Given a node:
-            //
-            //    n: Thingy(@a, @b, @c)
-            //
-            // We say that it def's @n and uses @a, @b, @c.
+            auto handleEdge = [&] (Edge& edge) {
+                bool newEntry = m_workset->add(m_indexing.index(edge.node()));
+                edge.setKillStatus(newEntry ? DoesKill : DoesNotKill);
+            };
             
             switch (node->op()) {
             case Upsilon: {
-                ASSERT_WITH_MESSAGE(!m_workset.contains(node->index()), "Upsilon should not be used as defs by other nodes.");
+                ASSERT_WITH_MESSAGE(!m_workset->contains(node->index()), "Upsilon should not be used as defs by other nodes.");
 
                 Node* phi = node->phi();
-                m_workset.remove(phi->index());
-                m_workset.add(node->child1()->index());
+                m_workset->remove(m_indexing.shadowIndex(phi));
+                handleEdge(node->child1());
                 break;
             }
             case Phi: {
+                m_workset->remove(m_indexing.index(node));
+                m_workset->add(m_indexing.shadowIndex(node));
                 break;
             }
             default:
-                m_workset.remove(node->index());
-                DFG_NODE_DO_TO_CHILDREN(m_graph, node, addChildUse);
+                m_workset->remove(m_indexing.index(node));
+                m_graph.doToChildren(node, handleEdge);
                 break;
             }
         }
 
         // Update live at head.
-        auto& liveAtHead = m_liveAtHead[blockIndex];
-        if (m_workset.size() == liveAtHead.size())
+        Vector<unsigned, 0, UnsafeVectorOverflow, 1>& liveAtHead = m_liveAtHead[blockIndex];
+        if (m_workset->size() == liveAtHead.size())
             return false;
 
         for (unsigned liveIndexAtHead : liveAtHead)
-            m_workset.remove(liveIndexAtHead);
-        ASSERT(!m_workset.isEmpty());
+            m_workset->remove(liveIndexAtHead);
+        ASSERT(!m_workset->isEmpty());
 
-        liveAtHead.reserveCapacity(liveAtHead.size() + m_workset.size());
-        for (unsigned newValue : m_workset)
+        liveAtHead.reserveCapacity(liveAtHead.size() + m_workset->size());
+        for (unsigned newValue : *m_workset)
             liveAtHead.uncheckedAppend(newValue);
 
         bool changedPredecessor = false;
         for (BasicBlock* predecessor : block->predecessors) {
-            auto& liveAtTail = m_liveAtTail[predecessor];
-            for (unsigned newValue : m_workset) {
+            HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>>&
+                liveAtTail = m_liveAtTail[predecessor];
+            for (unsigned newValue : *m_workset) {
                 if (liveAtTail.add(newValue)) {
                     if (!m_dirtyBlocks.quickSet(predecessor->index))
                         changedPredecessor = true;
@@ -176,14 +169,10 @@
         return changedPredecessor;
     }
 
-    ALWAYS_INLINE void addChildUse(Node*, Edge& edge)
-    {
-        bool newEntry = m_workset.add(edge->index());
-        edge.setKillStatus(newEntry ? DoesKill : DoesNotKill);
-    }
-
     // Blocks with new live values at tail.
     BitVector m_dirtyBlocks;
+    
+    FlowIndexing& m_indexing;
 
     // Live values per block edge.
     BlockMap<Vector<unsigned, 0, UnsafeVectorOverflow, 1>> m_liveAtHead;
@@ -190,7 +179,7 @@
     BlockMap<HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>>> m_liveAtTail;
 
     // Single sparse set allocated once and used by every basic block.
-    IndexSparseSet<UnsafeVectorOverflow> m_workset;
+    std::unique_ptr<IndexSparseSet<UnsafeVectorOverflow>> m_workset;
 };
 
 bool performLivenessAnalysis(Graph& graph)

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -2560,15 +2560,18 @@
     BasicBlock* owner;
 };
 
-inline bool nodeComparator(Node* a, Node* b)
-{
-    return a->index() < b->index();
-}
+struct NodeComparator {
+    template<typename NodePtrType>
+    bool operator()(NodePtrType a, NodePtrType b) const
+    {
+        return a->index() < b->index();
+    }
+};
 
 template<typename T>
 CString nodeListDump(const T& nodeList)
 {
-    return sortedListDump(nodeList, nodeComparator);
+    return sortedListDump(nodeList, NodeComparator());
 }
 
 template<typename T>
@@ -2579,7 +2582,7 @@
         typename T::const_iterator iter = nodeMap.begin();
         iter != nodeMap.end(); ++iter)
         keys.append(iter->key);
-    std::sort(keys.begin(), keys.end(), nodeComparator);
+    std::sort(keys.begin(), keys.end(), NodeComparator());
     StringPrintStream out;
     CommaPrinter comma;
     for(unsigned i = 0; i < keys.size(); ++i)
@@ -2593,7 +2596,7 @@
     using V = typename T::ValueType;
     T sortedList = nodeValuePairList;
     std::sort(sortedList.begin(), sortedList.end(), [](const V& a, const V& b) {
-        return nodeComparator(a.node, b.node);
+        return NodeComparator()(a.node, b.node);
     });
 
     StringPrintStream out;

Added: trunk/Source/_javascript_Core/dfg/DFGNodeAbstractValuePair.cpp (0 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGNodeAbstractValuePair.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeAbstractValuePair.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,41 @@
+/*
+ * 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. 
+ */
+
+#include "config.h"
+#include "DFGNodeAbstractValuePair.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+void NodeAbstractValuePair::dump(PrintStream& out) const
+{
+    out.print(node, "=>", value);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+

Added: trunk/Source/_javascript_Core/dfg/DFGNodeAbstractValuePair.h (0 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGNodeAbstractValuePair.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeAbstractValuePair.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,53 @@
+/*
+ * 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. 
+ */
+
+#pragma once
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGAbstractValue.h"
+#include "DFGNodeFlowProjection.h"
+
+namespace JSC { namespace DFG {
+
+struct NodeAbstractValuePair {
+    NodeAbstractValuePair() { }
+    
+    NodeAbstractValuePair(NodeFlowProjection node, const AbstractValue& value)
+        : node(node)
+        , value(value)
+    {
+    }
+    
+    void dump(PrintStream& out) const;
+    
+    NodeFlowProjection node;
+    AbstractValue value;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+

Added: trunk/Source/_javascript_Core/dfg/DFGNodeFlowProjection.cpp (0 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGNodeFlowProjection.cpp	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeFlowProjection.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,49 @@
+/*
+ * 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. 
+ */
+
+#include "config.h"
+#include "DFGNodeFlowProjection.h"
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+void NodeFlowProjection::dump(PrintStream& out) const
+{
+    if (!*this) {
+        out.print("-");
+        return;
+    }
+    if (kind() == Primary) {
+        out.print(node());
+        return;
+    }
+    out.print("shadow(", node(), ")");
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+

Added: trunk/Source/_javascript_Core/dfg/DFGNodeFlowProjection.h (0 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGNodeFlowProjection.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeFlowProjection.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -0,0 +1,155 @@
+/*
+ * 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. 
+ */
+
+#pragma once
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGNode.h"
+#include <wtf/HashTable.h>
+
+namespace JSC { namespace DFG {
+
+class NodeFlowProjection {
+public:
+    enum Kind {
+        Primary,
+        Shadow
+    };
+    
+    NodeFlowProjection() { }
+    
+    NodeFlowProjection(Node* node)
+        : m_word(bitwise_cast<uintptr_t>(node))
+    {
+        ASSERT(kind() == Primary);
+    }
+    
+    NodeFlowProjection(Node* node, Kind kind)
+        : m_word(bitwise_cast<uintptr_t>(node) | (kind == Shadow ? shadowBit : 0))
+    {
+        ASSERT(this->kind() == kind);
+    }
+    
+    NodeFlowProjection(WTF::HashTableDeletedValueType)
+        : m_word(shadowBit)
+    {
+    }
+    
+    explicit operator bool() const { return !!m_word; }
+    
+    Kind kind() const { return (m_word & shadowBit) ? Shadow : Primary; }
+    
+    Node* node() const { return bitwise_cast<Node*>(m_word & ~shadowBit); }
+    
+    Node& operator*() const { return *node(); }
+    Node* operator->() const { return node(); }
+    
+    unsigned hash() const
+    {
+        return m_word;
+    }
+    
+    bool operator==(NodeFlowProjection other) const
+    {
+        return m_word == other.m_word;
+    }
+    
+    bool operator!=(NodeFlowProjection other) const
+    {
+        return !(*this == other);
+    }
+    
+    bool operator<(NodeFlowProjection other) const
+    {
+        if (kind() != other.kind())
+            return kind() < other.kind();
+        return node() < other.node();
+    }
+    
+    bool operator>(NodeFlowProjection other) const
+    {
+        return other < *this;
+    }
+    
+    bool operator<=(NodeFlowProjection other) const
+    {
+        return !(*this > other);
+    }
+    
+    bool operator>=(NodeFlowProjection other) const
+    {
+        return !(*this < other);
+    }
+    
+    bool isHashTableDeletedValue() const
+    {
+        return *this == NodeFlowProjection(WTF::HashTableDeletedValue);
+    }
+    
+    // Phi shadow projections can become invalid because the Phi might be folded to something else.
+    bool isStillValid() const
+    {
+        return *this && (kind() == Primary || node()->op() == Phi);
+    }
+    
+    void dump(PrintStream&) const;
+    
+    template<typename Func>
+    static void forEach(Node* node, const Func& func)
+    {
+        func(NodeFlowProjection(node));
+        if (node->op() == Phi)
+            func(NodeFlowProjection(node, Shadow));
+    }
+    
+public:
+    static const uintptr_t shadowBit = 1;
+    
+    uintptr_t m_word { 0 };
+};
+
+struct NodeFlowProjectionHash {
+    static unsigned hash(NodeFlowProjection key) { return key.hash(); }
+    static bool equal(NodeFlowProjection a, NodeFlowProjection b) { return a == b; }
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+} } // namespace JSC::DFG
+
+namespace WTF {
+
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::DFG::NodeFlowProjection> {
+    typedef JSC::DFG::NodeFlowProjectionHash Hash;
+};
+
+template<typename T> struct HashTraits;
+template<> struct HashTraits<JSC::DFG::NodeFlowProjection> : SimpleClassHashTraits<JSC::DFG::NodeFlowProjection> { };
+
+} // namespace WTF
+
+#endif // ENABLE(DFG_JIT)
+

Modified: trunk/Source/_javascript_Core/dfg/DFGStoreBarrierInsertionPhase.cpp (208372 => 208373)


--- trunk/Source/_javascript_Core/dfg/DFGStoreBarrierInsertionPhase.cpp	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/_javascript_Core/dfg/DFGStoreBarrierInsertionPhase.cpp	2016-11-04 05:28:35 UTC (rev 208373)
@@ -126,11 +126,13 @@
                     // Construct the state-at-tail based on the epochs of live nodes and the
                     // current epoch. We grow state-at-tail monotonically to ensure convergence.
                     bool thisBlockChanged = false;
-                    for (Node* node : block->ssa->liveAtTail) {
+                    for (NodeFlowProjection node : block->ssa->liveAtTail) {
+                        if (node.kind() == NodeFlowProjection::Shadow)
+                            continue;
                         if (node->epoch() != m_currentEpoch) {
                             // If the node is older than the current epoch, then we may need to
                             // run a barrier on it in the future. So, add it to the state.
-                            thisBlockChanged |= m_stateAtTail->at(block).add(node).isNewEntry;
+                            thisBlockChanged |= m_stateAtTail->at(block).add(node.node()).isNewEntry;
                         }
                     }
                     
@@ -178,8 +180,10 @@
                 return false;
             m_state->beginBasicBlock(block);
             
-            for (Node* node : block->ssa->liveAtHead) {
-                if (m_stateAtHead->at(block).contains(node)) {
+            for (NodeFlowProjection node : block->ssa->liveAtHead) {
+                if (node.kind() == NodeFlowProjection::Shadow)
+                    continue;
+                if (m_stateAtHead->at(block).contains(node.node())) {
                     // If previous blocks tell us that this node may need a barrier in the
                     // future, then put it in the ancient primordial epoch. This forces us to
                     // emit a barrier on any possibly-cell store, regardless of the epoch of the
@@ -326,7 +330,8 @@
                 break;
                 
             case Upsilon:
-                m_node->phi()->setEpoch(m_node->epoch());
+                // Assume the worst for Phis so that we don't have to worry about Phi shadows.
+                m_node->phi()->setEpoch(Epoch());
                 m_node->setEpoch(Epoch());
                 break;
                 

Modified: trunk/Source/WTF/ChangeLog (208372 => 208373)


--- trunk/Source/WTF/ChangeLog	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/WTF/ChangeLog	2016-11-04 05:28:35 UTC (rev 208373)
@@ -1,3 +1,16 @@
+2016-11-03  Filip Pizlo  <fpi...@apple.com>
+
+        DFG plays fast and loose with the shadow values of a Phi
+        https://bugs.webkit.org/show_bug.cgi?id=164309
+
+        Reviewed by Saam Barati.
+        
+        Made this API use size rather than maxIndex as its initialization parameter, because that's
+        less confusing.
+
+        * wtf/IndexSparseSet.h:
+        (WTF::IndexSparseSet<OverflowHandler>::IndexSparseSet):
+
 2016-11-03  Commit Queue  <commit-qu...@webkit.org>
 
         Unreviewed, rolling out r208364.

Modified: trunk/Source/WTF/wtf/IndexSparseSet.h (208372 => 208373)


--- trunk/Source/WTF/wtf/IndexSparseSet.h	2016-11-04 05:15:11 UTC (rev 208372)
+++ trunk/Source/WTF/wtf/IndexSparseSet.h	2016-11-04 05:28:35 UTC (rev 208373)
@@ -45,7 +45,7 @@
 class IndexSparseSet {
     typedef Vector<unsigned, 0, OverflowHandler> ValueList;
 public:
-    explicit IndexSparseSet(unsigned maxValue);
+    explicit IndexSparseSet(unsigned size);
 
     bool add(unsigned);
     bool remove(unsigned);
@@ -65,9 +65,9 @@
 };
 
 template<typename OverflowHandler>
-inline IndexSparseSet<OverflowHandler>::IndexSparseSet(unsigned maxValue)
+inline IndexSparseSet<OverflowHandler>::IndexSparseSet(unsigned size)
 {
-    m_map.resize(maxValue + 1);
+    m_map.resize(size);
 }
 
 template<typename OverflowHandler>
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to