DFG DCE might eliminate checks unsoundly
https://bugs.webkit.org/show_bug.cgi?id=109389

Source/JavaScriptCore: 

Reviewed by Oliver Hunt.
        
This gets rid of all eager reference counting, and does all dead code elimination
in one phase - the DCEPhase. This phase also sets up the node reference counts,
which are then used not just for DCE but also register allocation and stack slot
allocation.
        
Doing this required a number of surgical changes in places that previously relied
on always having liveness information. For example, the structure check hoisting
phase must now consult whether a VariableAccessData is profitable for unboxing to
make sure that it doesn't try to do hoisting on set SetLocals. The arguments
simplification phase employs its own light-weight liveness analysis. Both phases
previously just used reference counts.
        
The largest change is that now, dead nodes get turned into Phantoms. Those
Phantoms will retain those child edges that are not proven. This ensures that any
type checks performed by a dead node remain even after the node is killed. On the
other hand, this Phantom conversion means that we need special handling for
SetLocal. I decided to make the four forms of SetLocal explicit:
        
MovHint(@a, rK): Just indicates that node @a contains the value that would have
     now been placed into virtual register rK. Does not actually cause @a to be
     stored into rK. This would have previously been a dead SetLocal with @a
     being live. MovHints are always dead.
        
ZombieHint(rK): Indicates that at this point, register rK will contain a dead
     value and OSR should put Undefined into it. This would have previously been
     a dead SetLocal with @a being dead also. ZombieHints are always dead.
        
MovHintAndCheck(@a, rK): Identical to MovHint except @a is also type checked,
     according to whatever UseKind the edge to @a has. The type check is always a
     forward exit. MovHintAndChecks are always live, since they are
     NodeMustGenerate. Previously this would have been a dead SetLocal with a
     live @a, and the check would have disappeared. This is one of the bugs that
     this patch solves.
        
SetLocal(@a, rK): This still does exactly what it does now, if the SetLocal is
     live.
        
Basically this patch makes it so that dead SetLocals eventually decay to MovHint,
ZombieHint, or MovHintAndCheck depending on the situation. If the child @a is
also dead, then you get a ZombieHint. If the child @a is live but the SetLocal
has a type check and @a's type hasn't been proven to have that type then you get
a MovHintAndCheck. Otherwise you get a MovHint.
        
This is performance neutral.

* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::executeEffects):
(JSC::DFG::AbstractState::mergeStateAtTail):
* dfg/DFGArgumentsSimplificationPhase.cpp:
(JSC::DFG::ArgumentsSimplificationPhase::run):
(ArgumentsSimplificationPhase):
(JSC::DFG::ArgumentsSimplificationPhase::removeArgumentsReferencingPhantomChild):
* dfg/DFGBasicBlock.h:
(BasicBlock):
* dfg/DFGBasicBlockInlines.h:
(DFG):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addToGraph):
(JSC::DFG::ByteCodeParser::insertPhiNode):
(JSC::DFG::ByteCodeParser::emitFunctionChecks):
* dfg/DFGCFAPhase.cpp:
(JSC::DFG::CFAPhase::run):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::run):
(JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
* dfg/DFGCPSRethreadingPhase.cpp:
(JSC::DFG::CPSRethreadingPhase::run):
(JSC::DFG::CPSRethreadingPhase::addPhiSilently):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::eliminateIrrelevantPhantomChildren):
(JSC::DFG::CSEPhase::setReplacement):
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGCommon.cpp:
(WTF::printInternal):
(WTF):
* dfg/DFGCommon.h:
(WTF):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
(JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
(JSC::DFG::ConstantFoldingPhase::paintUnreachableCode):
* dfg/DFGDCEPhase.cpp: Added.
(DFG):
(DCEPhase):
(JSC::DFG::DCEPhase::DCEPhase):
(JSC::DFG::DCEPhase::run):
(JSC::DFG::DCEPhase::findTypeCheckRoot):
(JSC::DFG::DCEPhase::countEdge):
(JSC::DFG::DCEPhase::eliminateIrrelevantPhantomChildren):
(JSC::DFG::performDCE):
* dfg/DFGDCEPhase.h: Added.
(DFG):
* dfg/DFGDriver.cpp:
(JSC::DFG::compile):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::checkArray):
(JSC::DFG::FixupPhase::blessArrayOperation):
(JSC::DFG::FixupPhase::fixIntEdge):
(JSC::DFG::FixupPhase::injectInt32ToDoubleNode):
(JSC::DFG::FixupPhase::truncateConstantToInt32):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::Graph):
(JSC::DFG::Graph::dump):
(DFG):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::changeChild):
(JSC::DFG::Graph::changeEdge):
(JSC::DFG::Graph::compareAndSwap):
(JSC::DFG::Graph::clearAndDerefChild):
(JSC::DFG::Graph::performSubstitution):
(JSC::DFG::Graph::performSubstitutionForEdge):
(Graph):
(JSC::DFG::Graph::substitute):
* dfg/DFGInsertionSet.h:
(InsertionSet):
* dfg/DFGNode.h:
(JSC::DFG::Node::Node):
(JSC::DFG::Node::convertToConstant):
(JSC::DFG::Node::convertToGetLocalUnlinked):
(JSC::DFG::Node::containsMovHint):
(Node):
(JSC::DFG::Node::hasVariableAccessData):
(JSC::DFG::Node::willHaveCodeGenOrOSR):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward):
(JSC::DFG::SpeculativeJIT::compileMovHint):
(JSC::DFG::SpeculativeJIT::compileMovHintAndCheck):
(DFG):
(JSC::DFG::SpeculativeJIT::compileInlineStart):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStructureCheckHoistingPhase.cpp:
(JSC::DFG::StructureCheckHoistingPhase::run):
(JSC::DFG::StructureCheckHoistingPhase::shouldConsiderForHoisting):
(StructureCheckHoistingPhase):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):

LayoutTests: 

Reviewed by Oliver Hunt.

* fast/js/dfg-arguments-osr-exit-multiple-blocks-before-exit-expected.txt: Added.
* fast/js/dfg-arguments-osr-exit-multiple-blocks-before-exit.html: Added.
* fast/js/dfg-arguments-osr-exit-multiple-blocks-expected.txt: Added.
* fast/js/dfg-arguments-osr-exit-multiple-blocks.html: Added.
* fast/js/jsc-test-list:
* fast/js/script-tests/dfg-arguments-osr-exit-multiple-blocks-before-exit.js: Added.
(baz):
(foo):
(bar):
* fast/js/script-tests/dfg-arguments-osr-exit-multiple-blocks.js: Added.
(baz):
(foo):
(bar):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@144862 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 3bd6823..4b2d1ba 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -85,6 +85,7 @@
     dfg/DFGCPSRethreadingPhase.cpp
     dfg/DFGConstantFoldingPhase.cpp
     dfg/DFGCSEPhase.cpp
+    dfg/DFGDCEPhase.cpp
     dfg/DFGDisassembler.cpp
     dfg/DFGDominators.cpp
     dfg/DFGDriver.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 2574fc8..9531825 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,162 @@
+2013-03-04  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG DCE might eliminate checks unsoundly
+        https://bugs.webkit.org/show_bug.cgi?id=109389
+
+        Reviewed by Oliver Hunt.
+        
+        This gets rid of all eager reference counting, and does all dead code elimination
+        in one phase - the DCEPhase. This phase also sets up the node reference counts,
+        which are then used not just for DCE but also register allocation and stack slot
+        allocation.
+        
+        Doing this required a number of surgical changes in places that previously relied
+        on always having liveness information. For example, the structure check hoisting
+        phase must now consult whether a VariableAccessData is profitable for unboxing to
+        make sure that it doesn't try to do hoisting on set SetLocals. The arguments
+        simplification phase employs its own light-weight liveness analysis. Both phases
+        previously just used reference counts.
+        
+        The largest change is that now, dead nodes get turned into Phantoms. Those
+        Phantoms will retain those child edges that are not proven. This ensures that any
+        type checks performed by a dead node remain even after the node is killed. On the
+        other hand, this Phantom conversion means that we need special handling for
+        SetLocal. I decided to make the four forms of SetLocal explicit:
+        
+        MovHint(@a, rK): Just indicates that node @a contains the value that would have
+             now been placed into virtual register rK. Does not actually cause @a to be
+             stored into rK. This would have previously been a dead SetLocal with @a
+             being live. MovHints are always dead.
+        
+        ZombieHint(rK): Indicates that at this point, register rK will contain a dead
+             value and OSR should put Undefined into it. This would have previously been
+             a dead SetLocal with @a being dead also. ZombieHints are always dead.
+        
+        MovHintAndCheck(@a, rK): Identical to MovHint except @a is also type checked,
+             according to whatever UseKind the edge to @a has. The type check is always a
+             forward exit. MovHintAndChecks are always live, since they are
+             NodeMustGenerate. Previously this would have been a dead SetLocal with a
+             live @a, and the check would have disappeared. This is one of the bugs that
+             this patch solves.
+        
+        SetLocal(@a, rK): This still does exactly what it does now, if the SetLocal is
+             live.
+        
+        Basically this patch makes it so that dead SetLocals eventually decay to MovHint,
+        ZombieHint, or MovHintAndCheck depending on the situation. If the child @a is
+        also dead, then you get a ZombieHint. If the child @a is live but the SetLocal
+        has a type check and @a's type hasn't been proven to have that type then you get
+        a MovHintAndCheck. Otherwise you get a MovHint.
+        
+        This is performance neutral.
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * Target.pri:
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::executeEffects):
+        (JSC::DFG::AbstractState::mergeStateAtTail):
+        * dfg/DFGArgumentsSimplificationPhase.cpp:
+        (JSC::DFG::ArgumentsSimplificationPhase::run):
+        (ArgumentsSimplificationPhase):
+        (JSC::DFG::ArgumentsSimplificationPhase::removeArgumentsReferencingPhantomChild):
+        * dfg/DFGBasicBlock.h:
+        (BasicBlock):
+        * dfg/DFGBasicBlockInlines.h:
+        (DFG):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addToGraph):
+        (JSC::DFG::ByteCodeParser::insertPhiNode):
+        (JSC::DFG::ByteCodeParser::emitFunctionChecks):
+        * dfg/DFGCFAPhase.cpp:
+        (JSC::DFG::CFAPhase::run):
+        * dfg/DFGCFGSimplificationPhase.cpp:
+        (JSC::DFG::CFGSimplificationPhase::run):
+        (JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
+        * dfg/DFGCPSRethreadingPhase.cpp:
+        (JSC::DFG::CPSRethreadingPhase::run):
+        (JSC::DFG::CPSRethreadingPhase::addPhiSilently):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::eliminateIrrelevantPhantomChildren):
+        (JSC::DFG::CSEPhase::setReplacement):
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGCommon.cpp:
+        (WTF::printInternal):
+        (WTF):
+        * dfg/DFGCommon.h:
+        (WTF):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        (JSC::DFG::ConstantFoldingPhase::addStructureTransitionCheck):
+        (JSC::DFG::ConstantFoldingPhase::paintUnreachableCode):
+        * dfg/DFGDCEPhase.cpp: Added.
+        (DFG):
+        (DCEPhase):
+        (JSC::DFG::DCEPhase::DCEPhase):
+        (JSC::DFG::DCEPhase::run):
+        (JSC::DFG::DCEPhase::findTypeCheckRoot):
+        (JSC::DFG::DCEPhase::countEdge):
+        (JSC::DFG::DCEPhase::eliminateIrrelevantPhantomChildren):
+        (JSC::DFG::performDCE):
+        * dfg/DFGDCEPhase.h: Added.
+        (DFG):
+        * dfg/DFGDriver.cpp:
+        (JSC::DFG::compile):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::checkArray):
+        (JSC::DFG::FixupPhase::blessArrayOperation):
+        (JSC::DFG::FixupPhase::fixIntEdge):
+        (JSC::DFG::FixupPhase::injectInt32ToDoubleNode):
+        (JSC::DFG::FixupPhase::truncateConstantToInt32):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::Graph):
+        (JSC::DFG::Graph::dump):
+        (DFG):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::changeChild):
+        (JSC::DFG::Graph::changeEdge):
+        (JSC::DFG::Graph::compareAndSwap):
+        (JSC::DFG::Graph::clearAndDerefChild):
+        (JSC::DFG::Graph::performSubstitution):
+        (JSC::DFG::Graph::performSubstitutionForEdge):
+        (Graph):
+        (JSC::DFG::Graph::substitute):
+        * dfg/DFGInsertionSet.h:
+        (InsertionSet):
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::Node):
+        (JSC::DFG::Node::convertToConstant):
+        (JSC::DFG::Node::convertToGetLocalUnlinked):
+        (JSC::DFG::Node::containsMovHint):
+        (Node):
+        (JSC::DFG::Node::hasVariableAccessData):
+        (JSC::DFG::Node::willHaveCodeGenOrOSR):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward):
+        (JSC::DFG::SpeculativeJIT::compileMovHint):
+        (JSC::DFG::SpeculativeJIT::compileMovHintAndCheck):
+        (DFG):
+        (JSC::DFG::SpeculativeJIT::compileInlineStart):
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStructureCheckHoistingPhase.cpp:
+        (JSC::DFG::StructureCheckHoistingPhase::run):
+        (JSC::DFG::StructureCheckHoistingPhase::shouldConsiderForHoisting):
+        (StructureCheckHoistingPhase):
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validate):
+
 2013-03-05  Mark Hahnenberg  <mhahnenberg@apple.com>
 
         Objective-C API: JSValue should implement init and return nil in exceptional cases
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index e8a1f2b..e0f7626 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -203,6 +203,8 @@
 	Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.h \
 	Source/JavaScriptCore/dfg/DFGCSEPhase.cpp \
 	Source/JavaScriptCore/dfg/DFGCSEPhase.h \
+	Source/JavaScriptCore/dfg/DFGDCEPhase.cpp \
+	Source/JavaScriptCore/dfg/DFGDCEPhase.h \
 	Source/JavaScriptCore/dfg/DFGDisassembler.cpp \
 	Source/JavaScriptCore/dfg/DFGDisassembler.h \
 	Source/JavaScriptCore/dfg/DFGDominators.cpp \
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index f50d36c..2940c58b5 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -109,6 +109,8 @@
 		0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */; };
 		0F2E892C16D028AD009E4FD2 /* UnusedPointer.h in Headers */ = {isa = PBXBuildFile; fileRef = 65987F2F16828A7E003C2F8D /* UnusedPointer.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F2E892D16D02BAF009E4FD2 /* DFGMinifiedID.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB4B51016B3A964003F696B /* DFGMinifiedID.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */; };
+		0F2FC77316E12F740038D976 /* DFGDCEPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F34B14916D42010001CDA5A /* DFGUseKind.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */; };
 		0F34B14A16D42013001CDA5A /* DFGUseKind.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F34B14816D4200E001CDA5A /* DFGUseKind.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F34B14C16D43E0D001CDA5A /* PolymorphicAccessStructureList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F34B14B16D43E0C001CDA5A /* PolymorphicAccessStructureList.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1001,6 +1003,8 @@
 		0F2BDC5015228FFA00CD8910 /* DFGVariableEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableEvent.cpp; path = dfg/DFGVariableEvent.cpp; sourceTree = "<group>"; };
 		0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGCodeBlocks.cpp; sourceTree = "<group>"; };
 		0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGCodeBlocks.h; sourceTree = "<group>"; };
+		0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGDCEPhase.cpp; path = dfg/DFGDCEPhase.cpp; sourceTree = "<group>"; };
+		0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGDCEPhase.h; path = dfg/DFGDCEPhase.h; sourceTree = "<group>"; };
 		0F34B14716D4200E001CDA5A /* DFGUseKind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGUseKind.cpp; path = dfg/DFGUseKind.cpp; sourceTree = "<group>"; };
 		0F34B14816D4200E001CDA5A /* DFGUseKind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGUseKind.h; path = dfg/DFGUseKind.h; sourceTree = "<group>"; };
 		0F34B14B16D43E0C001CDA5A /* PolymorphicAccessStructureList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolymorphicAccessStructureList.h; sourceTree = "<group>"; };
@@ -2638,6 +2642,8 @@
 				0FBE0F6C16C1DB010082C5E8 /* DFGCPSRethreadingPhase.h */,
 				0FFFC94D14EF909500C72532 /* DFGCSEPhase.cpp */,
 				0FFFC94E14EF909500C72532 /* DFGCSEPhase.h */,
+				0F2FC77016E12F6F0038D976 /* DFGDCEPhase.cpp */,
+				0F2FC77116E12F6F0038D976 /* DFGDCEPhase.h */,
 				0FF427611591A1C9004CB9FF /* DFGDisassembler.cpp */,
 				0FF427621591A1C9004CB9FF /* DFGDisassembler.h */,
 				0FD81ACF154FB4EB00983E72 /* DFGDominators.cpp */,
@@ -2974,6 +2980,7 @@
 				C2FC9BD316644DFB00810D33 /* CopiedBlockInlines.h in Headers */,
 				C2EAA3FA149A835E00FCE112 /* CopiedSpace.h in Headers */,
 				C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlines.h in Headers */,
+				0F2FC77316E12F740038D976 /* DFGDCEPhase.h in Headers */,
 				C2239D1816262BDD005AC5FD /* CopyVisitor.h in Headers */,
 				C2239D1916262BDD005AC5FD /* CopyVisitorInlines.h in Headers */,
 				C218D1401655CFD50062BB81 /* CopyWorkList.h in Headers */,
@@ -3739,6 +3746,7 @@
 				148F21AA107EC53A0042EC2C /* BytecodeGenerator.cpp in Sources */,
 				1428082D107EC0570013E7B2 /* CallData.cpp in Sources */,
 				1429D8DD0ED2205B00B89619 /* CallFrame.cpp in Sources */,
+				0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */,
 				0F0B83B014BCF71600885B4F /* CallLinkInfo.cpp in Sources */,
 				0F93329D14CA7DC30085F3C6 /* CallLinkStatus.cpp in Sources */,
 				0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */,
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 58140f6..efec453 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -121,6 +121,7 @@
     dfg/DFGCPSRethreadingPhase.cpp \
     dfg/DFGConstantFoldingPhase.cpp \
     dfg/DFGCSEPhase.cpp \
+    dfg/DFGDCEPhase.cpp \
     dfg/DFGDisassembler.cpp \
     dfg/DFGDominators.cpp \
     dfg/DFGDriver.cpp \
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index 370ee26..ec94a7b 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -314,6 +314,18 @@
         m_variables.operand(node->local()) = forNode(node->child1());
         break;
     }
+        
+    case MovHintAndCheck: {
+        // Don't need to do anything. A MovHint is effectively a promise that the SetLocal
+        // was dead.
+        break;
+    }
+        
+    case MovHint:
+    case ZombieHint: {
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
             
     case SetArgument:
         // Assert that the state of arguments has been set.
@@ -1628,18 +1640,6 @@
             break;
             
         case GetLocal:
-            // If the GetLocal is dead, then we transfer from head to tail.
-            // FIXME: We can get rid of this case after https://bugs.webkit.org/show_bug.cgi?id=109389
-            if (!node->shouldGenerate()) {
-                // The block transfers the value from head to tail.
-                source = inVariable;
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-                dataLogF("          Transfering ");
-                source.dump(WTF::dataFile());
-                dataLogF(" from head to tail (dead GetLocal case).\n");
-#endif
-                break;
-            }
             // The block refines the value with additional speculations.
             source = forNode(node);
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
index f23cd6b..071f417 100644
--- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp
@@ -140,6 +140,26 @@
             m_argumentsAliasing.add(variableAccessData, ArgumentsAliasingData());
         }
         
+        // Figure out which variables are live, using a conservative approximation of
+        // liveness.
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            if (!block)
+                continue;
+            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+                Node* node = block->at(indexInBlock);
+                switch (node->op()) {
+                case GetLocal:
+                case Flush:
+                case PhantomLocal:
+                    m_isLive.add(node->variableAccessData());
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+        
         // Figure out which variables alias the arguments and nothing else, and are
         // used only for GetByVal and GetArrayLength accesses. At the same time,
         // identify uses of CreateArguments that are not consistent with the arguments
@@ -198,6 +218,10 @@
                             && !source->valueOfJSConstant(codeBlock()))
                             break;
                         
+                        // If the variable is totally dead, then ignore it.
+                        if (!m_isLive.contains(variableAccessData))
+                            break;
+                        
                         if (argumentsRegister != InvalidVirtualRegister
                             && (variableAccessData->local() == argumentsRegister
                                 || variableAccessData->local() == unmodifiedArgumentsRegister(argumentsRegister))) {
@@ -411,7 +435,7 @@
             BasicBlock* block = m_graph.m_blocks[blockIndex].get();
             if (!block)
                 continue;
-            for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+            for (unsigned indexInBlock = 0; indexInBlock < block->size(); indexInBlock++) {
                 Node* node = block->at(indexInBlock);
                 if (!node->shouldGenerate())
                     continue;
@@ -441,7 +465,46 @@
                     // we replace all uses of this variable with GetMyArgumentsLength and
                     // GetMyArgumentByVal.
                     ASSERT(m_argumentsAliasing.find(variableAccessData)->value.isValid());
-                    changed |= variableAccessData->mergeIsArgumentsAlias(true);
+                    if (variableAccessData->mergeIsArgumentsAlias(true)) {
+                        changed = true;
+                        
+                        // Make sure that the variable knows, that it may now hold non-cell values.
+                        variableAccessData->predict(SpecEmpty);
+                    }
+                    
+                    // Make sure that the SetLocal doesn't check that the input is a Cell.
+                    if (node->child1().useKind() != UntypedUse) {
+                        node->child1().setUseKind(UntypedUse);
+                        changed = true;
+                    }
+                    break;
+                }
+                    
+                case PhantomLocal: {
+                    VariableAccessData* variableAccessData = node->variableAccessData();
+                    
+                    if (variableAccessData->isCaptured()
+                        || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
+                        || m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
+                        break;
+                    
+                    // Turn PhantomLocals into just GetLocals. This will preserve the threading
+                    // of the local through to this point, but will allow it to die, causing
+                    // only OSR to know about it.
+
+                    node->setOpAndDefaultFlags(GetLocal);
+                    break;
+                }
+
+                case Flush: {
+                    VariableAccessData* variableAccessData = node->variableAccessData();
+                    
+                    if (variableAccessData->isCaptured()
+                        || !m_argumentsAliasing.find(variableAccessData)->value.isValid()
+                        || m_createsArguments.contains(node->codeOrigin.inlineCallFrame))
+                        break;
+                    
+                    RELEASE_ASSERT_NOT_REACHED();
                     break;
                 }
                     
@@ -468,7 +531,6 @@
                     // We can just get rid of this node, if it references a phantom argument.
                     if (!isOKToOptimize(node->child1().node()))
                         break;
-                    m_graph.deref(node->child1());
                     node->convertToPhantom();
                     node->children.setChild1(Edge());
                     break;
@@ -488,7 +550,6 @@
                     if (!isOKToOptimize(node->child1().node()))
                         break;
                     
-                    m_graph.deref(node->child1());
                     node->children.child1() = node->children.child2();
                     node->children.child2() = Edge();
                     node->setOpAndDefaultFlags(GetMyArgumentByVal);
@@ -504,10 +565,8 @@
                     if (!isOKToOptimize(node->child1().node()))
                         break;
                     
-                    m_graph.deref(node->child1());
                     node->children.child1() = Edge();
                     node->setOpAndDefaultFlags(GetMyArgumentsLength);
-                    node->ref(); // This is a must-generate node.
                     changed = true;
                     --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
                     break;
@@ -531,8 +590,7 @@
                     // We know exactly what this will return. But only after we have checked
                     // that nobody has escaped our arguments.
                     insertionSet.insertNode(
-                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, 
-                        CheckArgumentsNotCreated, codeOrigin);
+                        indexInBlock, SpecNone, CheckArgumentsNotCreated, codeOrigin);
                     
                     m_graph.convertToConstant(
                         node, jsNumber(codeOrigin.inlineCallFrame->arguments.size() - 1));
@@ -581,10 +639,10 @@
                             m_graph.baselineCodeBlockFor(node->codeOrigin)->argumentIndexAfterCapture(index)));
 
                     insertionSet.insertNode(
-                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, CheckArgumentsNotCreated,
+                        indexInBlock, SpecNone, CheckArgumentsNotCreated,
                         codeOrigin);
                     insertionSet.insertNode(
-                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, Phantom, codeOrigin,
+                        indexInBlock, SpecNone, Phantom, codeOrigin,
                         children);
                     
                     changed = true;
@@ -598,7 +656,6 @@
                     node->setOpAndDefaultFlags(Nop);
                     m_graph.clearAndDerefChild1(node);
                     m_graph.clearAndDerefChild2(node);
-                    node->setRefCount(0);
                     break;
                 }
                     
@@ -626,8 +683,7 @@
                     continue;
                 if (node->shouldGenerate()) {
                     insertionSet.insertNode(
-                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, Phantom,
-                        node->codeOrigin, node->children);
+                        indexInBlock, SpecNone, Phantom, node->codeOrigin, node->children);
                 }
                 node->setOpAndDefaultFlags(PhantomArguments);
                 node->children.reset();
@@ -651,6 +707,7 @@
     HashMap<VariableAccessData*, ArgumentsAliasingData,
             DefaultHash<VariableAccessData*>::Hash,
             NullableHashTraits<VariableAccessData*> > m_argumentsAliasing;
+    HashSet<VariableAccessData*> m_isLive;
 
     void observeBadArgumentsUse(Node* node)
     {
@@ -785,7 +842,6 @@
                 && !m_createsArguments.contains(edge->codeOrigin.inlineCallFrame);
             if (!isDeadArgumentsRegister && !isAliasedArgumentsRegister)
                 break;
-            m_graph.deref(edge);
             node->children.removeEdgeFromBag(edgeIndex);
             break;
         }
@@ -793,7 +849,6 @@
         case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
             if (m_createsArguments.contains(edge->codeOrigin.inlineCallFrame))
                 break;
-            m_graph.deref(edge);
             node->children.removeEdgeFromBag(edgeIndex);
             break;
         }
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlock.h b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
index 1b5c30d..bae9d52 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlock.h
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlock.h
@@ -102,7 +102,7 @@
     }
     
 #define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
-    templatePre typeParams templatePost Node* appendNode(Graph&, RefChildrenMode, RefNodeMode, SpeculatedType valueParamsComma valueParams);
+    templatePre typeParams templatePost Node* appendNode(Graph&, SpeculatedType valueParamsComma valueParams);
     DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_APPEND_NODE)
 #undef DFG_DEFINE_APPEND_NODE
     
diff --git a/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h b/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h
index b14d495..06eb393 100644
--- a/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h
+++ b/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h
@@ -34,9 +34,9 @@
 namespace JSC { namespace DFG {
 
 #define DFG_DEFINE_APPEND_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
-    templatePre typeParams templatePost inline Node* BasicBlock::appendNode(Graph& graph, RefChildrenMode refChildrenMode, RefNodeMode refNodeMode, SpeculatedType type valueParamsComma valueParams) \
+    templatePre typeParams templatePost inline Node* BasicBlock::appendNode(Graph& graph, SpeculatedType type valueParamsComma valueParams) \
     { \
-        Node* result = graph.addNode(refChildrenMode, refNodeMode, type valueParamsComma valueArgs); \
+        Node* result = graph.addNode(type valueParamsComma valueArgs); \
         append(result); \
         return result; \
     }
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 8465a70..30cb53f 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -698,77 +698,56 @@
     Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
     {
         Node* result = m_graph.addNode(
-            DontRefChildren, DontRefNode, SpecNone,
-            op, currentCodeOrigin(), Edge(child1), Edge(child2), Edge(child3));
+            SpecNone, op, currentCodeOrigin(), Edge(child1), Edge(child2), Edge(child3));
         ASSERT(op != Phi);
         m_currentBlock->append(result);
-
-        if (defaultFlags(op) & NodeMustGenerate)
-            m_graph.refChildren(result);
         return result;
     }
     Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
     {
         Node* result = m_graph.addNode(
-            DontRefChildren, DontRefNode, SpecNone,
-            op, currentCodeOrigin(), child1, child2, child3);
+            SpecNone, op, currentCodeOrigin(), child1, child2, child3);
         ASSERT(op != Phi);
         m_currentBlock->append(result);
-
-        if (defaultFlags(op) & NodeMustGenerate)
-            m_graph.refChildren(result);
         return result;
     }
     Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
     {
         Node* result = m_graph.addNode(
-            DontRefChildren, DontRefNode, SpecNone,
-            op, currentCodeOrigin(), info, Edge(child1), Edge(child2), Edge(child3));
+            SpecNone, op, currentCodeOrigin(), info, Edge(child1), Edge(child2), Edge(child3));
         if (op == Phi)
             m_currentBlock->phis.append(result);
         else
             m_currentBlock->append(result);
-
-        if (defaultFlags(op) & NodeMustGenerate)
-            m_graph.refChildren(result);
         return result;
     }
     Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
     {
         Node* result = m_graph.addNode(
-            DontRefChildren, DontRefNode, SpecNone,
-            op, currentCodeOrigin(), info1, info2, Edge(child1), Edge(child2), Edge(child3));
+            SpecNone, op, currentCodeOrigin(), info1, info2,
+            Edge(child1), Edge(child2), Edge(child3));
         ASSERT(op != Phi);
         m_currentBlock->append(result);
-
-        if (defaultFlags(op) & NodeMustGenerate)
-            m_graph.refChildren(result);
         return result;
     }
     
     Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
     {
         Node* result = m_graph.addNode(
-            DontRefChildren, DontRefNode, SpecNone,
-            Node::VarArg, op, currentCodeOrigin(), info1, info2,
+            SpecNone, Node::VarArg, op, currentCodeOrigin(), info1, info2,
             m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs);
         ASSERT(op != Phi);
         m_currentBlock->append(result);
         
         m_numPassedVarArgs = 0;
         
-        if (defaultFlags(op) & NodeMustGenerate)
-            m_graph.refChildren(result);
         return result;
     }
 
     Node* insertPhiNode(OpInfo info, BasicBlock* block)
     {
-        Node* result = m_graph.addNode(
-            DontRefChildren, DontRefNode, SpecNone,
-            Phi, currentCodeOrigin(), info);
+        Node* result = m_graph.addNode(SpecNone, Phi, currentCodeOrigin(), info);
         block->phis.append(result);
-
         return result;
     }
 
@@ -1256,17 +1235,19 @@
 
 void ByteCodeParser::emitFunctionChecks(const CallLinkStatus& callLinkStatus, Node* callTarget, int registerOffset, CodeSpecializationKind kind)
 {
-    if (callLinkStatus.isProved())
-        return;
-    
-    ASSERT(callLinkStatus.canOptimize());
-    
     Node* thisArgument;
     if (kind == CodeForCall)
         thisArgument = get(registerOffset + argumentToOperand(0));
     else
         thisArgument = 0;
 
+    if (callLinkStatus.isProved()) {
+        addToGraph(Phantom, callTarget, thisArgument);
+        return;
+    }
+    
+    ASSERT(callLinkStatus.canOptimize());
+    
     if (JSFunction* function = callLinkStatus.function())
         addToGraph(CheckFunction, OpInfo(function), callTarget, thisArgument);
     else {
diff --git a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
index 4ce2ebf..c427723 100644
--- a/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp
@@ -45,6 +45,10 @@
     
     bool run()
     {
+        ASSERT(m_graph.m_form == ThreadedCPS);
+        ASSERT(m_graph.m_unificationState == GloballyUnified);
+        ASSERT(m_graph.m_refCountState == EverythingIsLive);
+        
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         m_count = 0;
 #endif
diff --git a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
index 93c3095..2386ede 100644
--- a/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp
@@ -140,8 +140,8 @@
                             jettisonBlock(blockIndex, notTakenBlockIndex, boundaryCodeOrigin);
                         
                             block->appendNode(
-                                m_graph, DontRefChildren, DontRefNode, SpecNone, Jump,
-                                boundaryCodeOrigin, OpInfo(takenBlockIndex));
+                                m_graph, SpecNone, Jump, boundaryCodeOrigin,
+                                OpInfo(takenBlockIndex));
                         }
                         innerChanged = outerChanged = true;
                         break;
@@ -171,8 +171,8 @@
                             ASSERT(branch->refCount() == 1);
                             
                             block->appendNode(
-                                m_graph, DontRefChildren, DontRefNode, SpecNone, Jump,
-                                branch->codeOrigin, OpInfo(targetBlockIndex));
+                                m_graph, SpecNone, Jump, branch->codeOrigin,
+                                OpInfo(targetBlockIndex));
                         }
                         innerChanged = outerChanged = true;
                         break;
@@ -272,7 +272,7 @@
         if (!livenessNode->shouldGenerate())
             return;
         block->appendNode(
-            m_graph, DontRefChildren, DontRefNode, SpecNone, PhantomLocal, codeOrigin,
+            m_graph, SpecNone, PhantomLocal, codeOrigin, 
             OpInfo(livenessNode->variableAccessData()));
     }
     
diff --git a/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp b/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
index baa7fc4..96ce188 100644
--- a/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp
@@ -51,7 +51,6 @@
         canonicalizeLocalsInBlocks();
         propagatePhis<LocalOperand>();
         propagatePhis<ArgumentOperand>();
-        m_graph.collectGarbage();
         
         m_graph.m_form = ThreadedCPS;
         return true;
@@ -124,7 +123,7 @@
     
     ALWAYS_INLINE Node* addPhiSilently(BasicBlock* block, const CodeOrigin& codeOrigin, VariableAccessData* variable)
     {
-        Node* result = m_graph.addNode(DontRefChildren, DontRefNode, SpecNone, Phi, codeOrigin, OpInfo(variable));
+        Node* result = m_graph.addNode(SpecNone, Phi, codeOrigin, OpInfo(variable));
         block->phis.append(result);
         return result;
     }
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index d41cd45..f0e5010 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -1008,7 +1008,6 @@
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
             dataLog("   Eliminating edge @", m_currentNode->index(), " -> @", edge->index());
 #endif
-            m_graph.deref(edge);
             node->children.removeEdgeFromBag(i--);
             m_changed = true;
         }
@@ -1024,7 +1023,6 @@
 #endif
         
         m_currentNode->convertToPhantom();
-        m_currentNode->setRefCount(1);
         eliminateIrrelevantPhantomChildren(m_currentNode);
         
         // At this point we will eliminate all references to this node.
@@ -1154,10 +1152,8 @@
             
             // If we replace a GetLocal with a GetLocalUnlinked, then turn the GetLocalUnlinked
             // into a GetLocal.
-            if (relevantLocalOp->op() == GetLocalUnlinked) {
+            if (relevantLocalOp->op() == GetLocalUnlinked)
                 relevantLocalOp->convertToGetLocal(variableAccessData, phi);
-                m_graph.ref(phi);
-            }
 
             m_changed = true;
             break;
@@ -1210,7 +1206,6 @@
             ASSERT(dataNode->hasResult());
             m_graph.clearAndDerefChild1(node);
             node->children.child1() = Edge(dataNode);
-            m_graph.ref(dataNode);
             m_graph.dethread();
             m_changed = true;
             break;
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.cpp b/Source/JavaScriptCore/dfg/DFGCommon.cpp
index ed6387f..502a95e 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCommon.cpp
@@ -91,6 +91,21 @@
     }
 }
 
+void printInternal(PrintStream& out, RefCountState state)
+{
+    switch (state) {
+    case EverythingIsLive:
+        out.print("EverythingIsLive");
+        break;
+    case ExactRefCount:
+        out.print("ExactRefCount");
+        break;
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+}
+
 void printInternal(PrintStream& out, ProofStatus status)
 {
     switch (status) {
diff --git a/Source/JavaScriptCore/dfg/DFGCommon.h b/Source/JavaScriptCore/dfg/DFGCommon.h
index fede870..b883aee 100644
--- a/Source/JavaScriptCore/dfg/DFGCommon.h
+++ b/Source/JavaScriptCore/dfg/DFGCommon.h
@@ -217,6 +217,15 @@
     GloballyUnified
 };
 
+// Describes how reference counts in the graph behave.
+enum RefCountState {
+    // Everything has refCount() == 1.
+    EverythingIsLive,
+
+    // Set after DCE has run.
+    ExactRefCount
+};
+
 enum OperandSpeculationMode { AutomaticOperandSpeculation, ManualOperandSpeculation };
 
 enum SpeculationDirection { ForwardSpeculation, BackwardSpeculation };
@@ -250,6 +259,7 @@
 void printInternal(PrintStream&, JSC::DFG::OptimizationFixpointState);
 void printInternal(PrintStream&, JSC::DFG::GraphForm);
 void printInternal(PrintStream&, JSC::DFG::UnificationState);
+void printInternal(PrintStream&, JSC::DFG::RefCountState);
 void printInternal(PrintStream&, JSC::DFG::ProofStatus);
 
 } // namespace WTF
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index 199e75b..8376944 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -88,7 +88,6 @@
                         m_state.variables().operand(
                             m_graph.argumentsRegisterFor(node->codeOrigin)).m_type))
                     break;
-                ASSERT(node->refCount() == 1);
                 node->convertToPhantom();
                 eliminated = true;
                 break;
@@ -104,7 +103,6 @@
                 else
                     set = node->structureSet();
                 if (value.m_currentKnownStructure.isSubsetOf(set)) {
-                    ASSERT(node->refCount() == 1);
                     m_state.execute(indexInBlock); // Catch the fact that we may filter on cell.
                     node->convertToPhantom();
                     eliminated = true;
@@ -126,7 +124,6 @@
             case Arrayify: {
                 if (!node->arrayMode().alreadyChecked(m_graph, node, m_state.forNode(node->child1())))
                     break;
-                ASSERT(node->refCount() == 1);
                 node->convertToPhantom();
                 eliminated = true;
                 break;
@@ -186,25 +183,22 @@
                 if (needsWatchpoint) {
                     ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
                     m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, DontRefNode, SpecNone,
-                        StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), childEdge);
+                        indexInBlock, SpecNone, StructureTransitionWatchpoint, codeOrigin,
+                        OpInfo(structure), childEdge);
                 } else if (m_state.forNode(child).m_type & ~SpecCell) {
                     m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, DontRefNode, SpecNone,
-                        Phantom, codeOrigin, childEdge);
+                        indexInBlock, SpecNone, Phantom, codeOrigin, childEdge);
                 }
                 
                 childEdge.setUseKind(KnownCellUse);
                 
                 Edge propertyStorage;
                 
-                child->ref();
                 if (isInlineOffset(status.offset()))
                     propertyStorage = childEdge;
                 else {
                     propertyStorage = Edge(m_insertionSet.insertNode(
-                        indexInBlock, DontRefChildren, RefNode, SpecNone, GetButterfly, codeOrigin,
-                        childEdge));
+                        indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge));
                 }
                 
                 node->convertToGetByOffset(m_graph.m_storageAccessData.size(), propertyStorage);
@@ -252,12 +246,11 @@
                 if (needsWatchpoint) {
                     ASSERT(m_state.forNode(child).m_futurePossibleStructure.isSubsetOf(StructureSet(structure)));
                     m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, DontRefNode, SpecNone,
-                        StructureTransitionWatchpoint, codeOrigin, OpInfo(structure), childEdge);
+                        indexInBlock, SpecNone, StructureTransitionWatchpoint, codeOrigin,
+                        OpInfo(structure), childEdge);
                 } else if (m_state.forNode(child).m_type & ~SpecCell) {
                     m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, DontRefNode, SpecNone,
-                        Phantom, codeOrigin, childEdge);
+                        indexInBlock, SpecNone, Phantom, codeOrigin, childEdge);
                 }
                 
                 childEdge.setUseKind(KnownCellUse);
@@ -287,17 +280,16 @@
 
                 Edge propertyStorage;
                 
-                if (isInlineOffset(status.offset())) {
-                    child->ref(); // The child will be used as the property index, so ref it to reflect the double use.
+                if (isInlineOffset(status.offset()))
                     propertyStorage = childEdge;
-                } else if (status.isSimpleReplace() || structure->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
+                else if (status.isSimpleReplace() || structure->outOfLineCapacity() == status.newStructure()->outOfLineCapacity()) {
                     propertyStorage = Edge(m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, RefNode, SpecNone, GetButterfly, codeOrigin, childEdge));
+                        indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge));
                 } else if (!structure->outOfLineCapacity()) {
                     ASSERT(status.newStructure()->outOfLineCapacity());
                     ASSERT(!isInlineOffset(status.offset()));
                     propertyStorage = Edge(m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, RefNode, SpecNone, AllocatePropertyStorage,
+                        indexInBlock, SpecNone, AllocatePropertyStorage,
                         codeOrigin, OpInfo(transitionData), childEdge));
                 } else {
                     ASSERT(structure->outOfLineCapacity());
@@ -305,17 +297,15 @@
                     ASSERT(!isInlineOffset(status.offset()));
                     
                     propertyStorage = Edge(m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, RefNode, SpecNone, ReallocatePropertyStorage,
-                        codeOrigin, OpInfo(transitionData),
-                        childEdge,
+                        indexInBlock, SpecNone, ReallocatePropertyStorage, codeOrigin,
+                        OpInfo(transitionData), childEdge,
                         Edge(m_insertionSet.insertNode(
-                            indexInBlock, DontRefChildren, DontRefNode, SpecNone, GetButterfly,
-                            codeOrigin, childEdge))));
+                            indexInBlock, SpecNone, GetButterfly, codeOrigin, childEdge))));
                 }
                 
                 if (status.isSimpleTransition()) {
                     m_insertionSet.insertNode(
-                        indexInBlock, RefChildren, DontRefNode, SpecNone, PutStructure, codeOrigin,
+                        indexInBlock, SpecNone, PutStructure, codeOrigin, 
                         OpInfo(transitionData), childEdge);
                 }
                 
@@ -348,6 +338,11 @@
             AdjacencyList children = node->children;
             
             if (node->op() == GetLocal) {
+                // GetLocals without a Phi child are guaranteed dead. We don't have to
+                // do anything about them.
+                if (!node->child1())
+                    continue;
+                
                 if (m_graph.m_form != LoadStore) {
                     VariableAccessData* variable = node->variableAccessData();
                     Node* phi = node->child1().node();
@@ -360,8 +355,8 @@
                         
                         m_graph.convertToConstant(node, value);
                         Node* phantom = m_insertionSet.insertNode(
-                            indexInBlock, DontRefChildren, DontRefNode, SpecNone, PhantomLocal, 
-                            codeOrigin, OpInfo(variable), Edge(phi));
+                            indexInBlock, SpecNone, PhantomLocal,  codeOrigin,
+                            OpInfo(variable), Edge(phi));
                         block->variablesAtHead.operand(variable->local()) = phantom;
                         block->variablesAtTail.operand(variable->local()) = phantom;
                         
@@ -377,7 +372,7 @@
             
             m_graph.convertToConstant(node, value);
             m_insertionSet.insertNode(
-                indexInBlock, DontRefChildren, DontRefNode, SpecNone, Phantom, codeOrigin, children);
+                indexInBlock, SpecNone, Phantom, codeOrigin, children);
             
             changed = true;
         }
@@ -406,18 +401,17 @@
     void addStructureTransitionCheck(CodeOrigin codeOrigin, unsigned indexInBlock, JSCell* cell)
     {
         Node* weakConstant = m_insertionSet.insertNode(
-            indexInBlock, DontRefChildren, DontRefNode, speculationFromValue(cell),
-            WeakJSConstant, codeOrigin, OpInfo(cell));
+            indexInBlock, speculationFromValue(cell), WeakJSConstant, codeOrigin, OpInfo(cell));
         
         if (cell->structure()->transitionWatchpointSetIsStillValid()) {
             m_insertionSet.insertNode(
-                indexInBlock, RefChildren, DontRefNode, SpecNone, StructureTransitionWatchpoint,
-                codeOrigin, OpInfo(cell->structure()), Edge(weakConstant, CellUse));
+                indexInBlock, SpecNone, StructureTransitionWatchpoint, codeOrigin,
+                OpInfo(cell->structure()), Edge(weakConstant, CellUse));
             return;
         }
 
         m_insertionSet.insertNode(
-            indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure, codeOrigin,
+            indexInBlock, SpecNone, CheckStructure, codeOrigin,
             OpInfo(m_graph.addStructureSet(cell->structure())), Edge(weakConstant, CellUse));
     }
     
@@ -454,8 +448,7 @@
                 
             default:
                 m_insertionSet.insertNode(
-                    indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit,
-                    node->codeOrigin);
+                    indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
                 changed = true;
                 break;
             }
diff --git a/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp b/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp
new file mode 100644
index 0000000..f408ef6
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2013 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 "DFGDCEPhase.h"
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGBasicBlockInlines.h"
+#include "DFGGraph.h"
+#include "DFGPhase.h"
+#include "Operations.h"
+
+namespace JSC { namespace DFG {
+
+class DCEPhase : public Phase {
+public:
+    DCEPhase(Graph& graph)
+        : Phase(graph, "dead code elimination")
+    {
+    }
+    
+    bool run()
+    {
+        // First reset the counts to 0 for all nodes.
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            if (!block)
+                continue;
+            for (unsigned indexInBlock = block->size(); indexInBlock--;)
+                block->at(indexInBlock)->setRefCount(0);
+            for (unsigned phiIndex = block->phis.size(); phiIndex--;)
+                block->phis[phiIndex]->setRefCount(0);
+        }
+    
+        // Now find the roots:
+        // - Nodes that are must-generate.
+        // - Nodes that are reachable from type checks.
+        // - Nodes that are reachable from SetLocals.
+        // Set their ref counts to 1 and put them on the worklist.
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            if (!block)
+                continue;
+            for (unsigned indexInBlock = block->size(); indexInBlock--;) {
+                Node* node = block->at(indexInBlock);
+                DFG_NODE_DO_TO_CHILDREN(m_graph, node, findTypeCheckRoot);
+                if (!(node->flags() & NodeMustGenerate))
+                    continue;
+                if (!node->postfixRef())
+                    m_worklist.append(node);
+            }
+        }
+        
+        while (!m_worklist.isEmpty()) {
+            Node* node = m_worklist.last();
+            m_worklist.removeLast();
+            ASSERT(node->shouldGenerate()); // It should not be on the worklist unless it's ref'ed.
+            DFG_NODE_DO_TO_CHILDREN(m_graph, node, countEdge);
+        }
+        
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            if (!block)
+                continue;
+            for (unsigned indexInBlock = block->size(); indexInBlock--;) {
+                Node* node = block->at(indexInBlock);
+                if (node->shouldGenerate())
+                    continue;
+                
+                switch (node->op()) {
+                case SetLocal: {
+                    if (node->child1().isProved() || node->child1().useKind() == UntypedUse) {
+                        // Consider the possibility that UInt32ToNumber is dead but its
+                        // child isn't; if so then we should MovHint the child.
+                        if (!node->child1()->shouldGenerate()
+                            && node->child1()->op() == UInt32ToNumber)
+                            node->child1() = node->child1()->child1();
+
+                        if (!node->child1()->shouldGenerate()) {
+                            node->setOpAndDefaultFlags(ZombieHint);
+                            node->child1() = Edge();
+                            break;
+                        }
+                        node->setOpAndDefaultFlags(MovHint);
+                        break;
+                    }
+                    node->setOpAndDefaultFlags(MovHintAndCheck);
+                    node->setRefCount(1);
+                    break;
+                }
+                    
+                case GetLocal:
+                case SetArgument: {
+                    // Leave them as not shouldGenerate.
+                    break;
+                }
+                    
+                default: {
+                    node->convertToPhantom();
+                    eliminateIrrelevantPhantomChildren(node);
+                    node->setRefCount(1);
+                    break;
+                } }
+            }
+        }
+        
+        m_graph.m_refCountState = ExactRefCount;
+        
+        return true;
+    }
+
+private:
+    void findTypeCheckRoot(Node*, Edge edge)
+    {
+        // We may have an "unproved" untyped use for code that is unreachable. The CFA
+        // will just not have gotten around to it.
+        if (edge.isProved() || edge.useKind() == UntypedUse)
+            return;
+        if (!edge->postfixRef())
+            m_worklist.append(edge.node());
+    }
+    
+    void countEdge(Node*, Edge edge)
+    {
+        // Don't count edges that are already counted for their type checks.
+        if (!(edge.isProved() || edge.useKind() == UntypedUse))
+            return;
+        
+        if (edge->postfixRef())
+            return;
+        m_worklist.append(edge.node());
+    }
+    
+    void eliminateIrrelevantPhantomChildren(Node* node)
+    {
+        for (unsigned i = 0; i < AdjacencyList::Size; ++i) {
+            Edge edge = node->children.child(i);
+            if (!edge)
+                continue;
+            if (edge.needsCheck())
+                continue;
+            node->children.removeEdgeFromBag(i--);
+        }
+    }
+    
+    Vector<Node*, 128> m_worklist;
+};
+
+bool performDCE(Graph& graph)
+{
+    SamplingRegion samplingRegion("DFG DCE Phase");
+    return runPhase<DCEPhase>(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
diff --git a/Source/JavaScriptCore/dfg/DFGDCEPhase.h b/Source/JavaScriptCore/dfg/DFGDCEPhase.h
new file mode 100644
index 0000000..2bb9913
--- /dev/null
+++ b/Source/JavaScriptCore/dfg/DFGDCEPhase.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 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 DFGDCEPhase_h
+#define DFGDCEPhase_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include "DFGCommon.h"
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Global dead code elimination. Eliminates any node that is not NodeMustGenerate,
+// not used by any other live node, and not subject to any type check.
+
+bool performDCE(Graph&);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGDCEPhase_h
+
diff --git a/Source/JavaScriptCore/dfg/DFGDriver.cpp b/Source/JavaScriptCore/dfg/DFGDriver.cpp
index 7e102da..495d852 100644
--- a/Source/JavaScriptCore/dfg/DFGDriver.cpp
+++ b/Source/JavaScriptCore/dfg/DFGDriver.cpp
@@ -39,6 +39,7 @@
 #include "DFGCPSRethreadingPhase.h"
 #include "DFGCSEPhase.h"
 #include "DFGConstantFoldingPhase.h"
+#include "DFGDCEPhase.h"
 #include "DFGFixupPhase.h"
 #include "DFGJITCompiler.h"
 #include "DFGPredictionInjectionPhase.h"
@@ -147,11 +148,13 @@
         performCPSRethreading(dfg);
     }
     
+    if (logCompilationChanges())
+        dataLogF("DFG optimization fixpoint converged in %u iterations.\n", cnt);
+
     dfg.m_fixpointState = FixpointConverged;
     performCSE(dfg);
     performCPSRethreading(dfg); // This should usually be a no-op since CSE rarely dethreads the graph.
-    if (logCompilationChanges())
-        dataLogF("DFG optimization fixpoint converged in %u iterations.\n", cnt);
+    performDCE(dfg);
     performVirtualRegisterAllocation(dfg);
 
     GraphDumpMode modeForFinalValidate = DumpGraph;
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 887dac3..0cc0f77 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -197,7 +197,7 @@
                 // We don't need to do ref'ing on the children because we're stealing them from
                 // the original division.
                 Node* newDivision = m_insertionSet.insertNode(
-                    m_indexInBlock, DontRefChildren, RefNode, SpecDouble, *node);
+                    m_indexInBlock, SpecDouble, *node);
                 
                 node->setOp(DoubleAsInt32);
                 node->children.initialize(Edge(newDivision, KnownNumberUse), Edge(), Edge());
@@ -518,8 +518,6 @@
                 if (ok) {
                     Edge newChildEdge = logicalNot->child1();
                     if (newChildEdge->hasBooleanResult()) {
-                        m_graph.ref(newChildEdge);
-                        m_graph.deref(logicalNot);
                         node->children.setChild1(newChildEdge);
                         
                         BlockIndex toBeTaken = node->notTakenBlockIndex();
@@ -556,8 +554,7 @@
                     // would have already exited by now, but insert a forced exit just to
                     // be safe.
                     m_insertionSet.insertNode(
-                        m_indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit,
-                        node->codeOrigin);
+                        m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
                 }
                 break;
             case ALL_INT32_INDEXING_TYPES:
@@ -638,8 +635,8 @@
                     node->child1()->prediction(), node->prediction());
                 if (arrayMode.supportsLength() && arrayProfile->hasDefiniteStructure()) {
                     m_insertionSet.insertNode(
-                        m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure,
-                        node->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
+                        m_indexInBlock, SpecNone, CheckStructure, node->codeOrigin,
+                        OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())),
                         node->child1());
                 }
             } else
@@ -650,10 +647,9 @@
             ASSERT(node->flags() & NodeMustGenerate);
             node->clearFlags(NodeMustGenerate | NodeClobbersWorld);
             setUseKindAndUnboxIfProfitable<KnownCellUse>(node->child1());
-            m_graph.deref(node);
             node->setArrayMode(arrayMode);
             
-            Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage, node->shouldGenerate());
+            Node* storage = checkArray(arrayMode, node->codeOrigin, node->child1().node(), 0, lengthNeedsStorage);
             if (!storage)
                 break;
             
@@ -730,6 +726,9 @@
         case PhantomPutStructure:
         case GetIndexedPropertyStorage:
         case LastNodeType:
+        case MovHint:
+        case MovHintAndCheck:
+        case ZombieHint:
             RELEASE_ASSERT_NOT_REACHED();
             break;
         
@@ -837,7 +836,7 @@
         m_insertionSet.execute(block);
     }
     
-    Node* checkArray(ArrayMode arrayMode, CodeOrigin codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage, bool shouldGenerate = true)
+    Node* checkArray(ArrayMode arrayMode, CodeOrigin codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage)
     {
         ASSERT(arrayMode.isSpecific());
         
@@ -858,21 +857,21 @@
                 }
                 
                 m_insertionSet.insertNode(
-                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, ArrayifyToStructure, codeOrigin,
+                    m_indexInBlock, SpecNone, ArrayifyToStructure, codeOrigin,
                     OpInfo(structure), OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
             } else {
                 m_insertionSet.insertNode(
-                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, Arrayify, codeOrigin,
+                    m_indexInBlock, SpecNone, Arrayify, codeOrigin,
                     OpInfo(arrayMode.asWord()), Edge(array, CellUse), indexEdge);
             }
         } else {
             if (structure) {
                 m_insertionSet.insertNode(
-                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckStructure, codeOrigin,
+                    m_indexInBlock, SpecNone, CheckStructure, codeOrigin,
                     OpInfo(m_graph.addStructureSet(structure)), Edge(array, CellUse));
             } else {
                 m_insertionSet.insertNode(
-                    m_indexInBlock, RefChildren, DontRefNode, SpecNone, CheckArray, codeOrigin,
+                    m_indexInBlock, SpecNone, CheckArray, codeOrigin,
                     OpInfo(arrayMode.asWord()), Edge(array, CellUse));
             }
         }
@@ -882,17 +881,12 @@
         
         if (arrayMode.usesButterfly()) {
             return m_insertionSet.insertNode(
-                m_indexInBlock,
-                shouldGenerate ? RefChildren : DontRefChildren,
-                shouldGenerate ? RefNode : DontRefNode,
-                SpecNone, GetButterfly, codeOrigin, Edge(array, KnownCellUse));
+                m_indexInBlock, SpecNone, GetButterfly, codeOrigin, Edge(array, KnownCellUse));
         }
         
         return m_insertionSet.insertNode(
-            m_indexInBlock,
-            shouldGenerate ? RefChildren : DontRefChildren,
-            shouldGenerate ? RefNode : DontRefNode,
-            SpecNone, GetIndexedPropertyStorage, codeOrigin, OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
+            m_indexInBlock, SpecNone, GetIndexedPropertyStorage, codeOrigin,
+            OpInfo(arrayMode.asWord()), Edge(array, KnownCellUse));
     }
     
     void blessArrayOperation(Edge base, Edge index, Edge& storageChild)
@@ -902,8 +896,7 @@
         switch (node->arrayMode().type()) {
         case Array::ForceExit: {
             m_insertionSet.insertNode(
-                m_indexInBlock, DontRefChildren, DontRefNode, SpecNone, ForceOSRExit,
-                node->codeOrigin);
+                m_indexInBlock, SpecNone, ForceOSRExit, node->codeOrigin);
             return;
         }
             
@@ -982,7 +975,6 @@
             return;
         }
         
-        Edge oldEdge = edge;
         Edge newEdge = node->child1();
         
         if (newEdge.useKind() != Int32Use) {
@@ -992,8 +984,10 @@
         
         ASSERT(newEdge->shouldSpeculateInteger());
         
-        m_graph.ref(newEdge);
-        m_graph.deref(oldEdge);
+        // Completely kill the ValueToInt32. We wouldn't have to do crazy things like this
+        // if it weren't for https://bugs.webkit.org/show_bug.cgi?id=111238.
+        node->setOpAndDefaultFlags(Nop);
+        node->child1() = Edge();
         
         edge = newEdge;
     }
@@ -1014,7 +1008,7 @@
     void injectInt32ToDoubleNode(Edge& edge, UseKind useKind = NumberUse, SpeculationDirection direction = BackwardSpeculation)
     {
         Node* result = m_insertionSet.insertNode(
-            m_indexInBlock, DontRefChildren, RefNode, SpecDouble,
+            m_indexInBlock, SpecDouble, 
             direction == BackwardSpeculation ? Int32ToDouble : ForwardInt32ToDouble,
             m_currentNode->codeOrigin, Edge(edge.node(), NumberUse));
         
@@ -1039,9 +1033,8 @@
         value = jsNumber(JSC::toInt32(value.asNumber()));
         ASSERT(value.isInt32());
         edge.setNode(m_insertionSet.insertNode(
-            m_indexInBlock, DontRefChildren, RefNode, SpecInt32, JSConstant,
-            m_currentNode->codeOrigin, OpInfo(codeBlock()->addOrFindConstant(value))));
-        m_graph.deref(oldNode);
+            m_indexInBlock, SpecInt32, JSConstant, m_currentNode->codeOrigin,
+            OpInfo(codeBlock()->addOrFindConstant(value))));
     }
     
     void truncateConstantsIfNecessary(Node* node, AddSpeculationMode mode)
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp
index eed8286..7fbb526 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.cpp
+++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp
@@ -56,6 +56,7 @@
     , m_fixpointState(BeforeFixpoint)
     , m_form(LoadStore)
     , m_unificationState(LocallyUnified)
+    , m_refCountState(EverythingIsLive)
 {
     ASSERT(m_profiledBlock);
 }
@@ -312,7 +313,7 @@
 void Graph::dump(PrintStream& out)
 {
     dataLog("DFG for ", CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), ":\n");
-    dataLog("  Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "\n");
+    dataLog("  Fixpoint state: ", m_fixpointState, "; Form: ", m_form, "; Unification state: ", m_unificationState, "; Ref count state: ", m_refCountState, "\n");
     
     Node* lastNode = 0;
     for (size_t b = 0; b < m_blocks.size(); ++b) {
@@ -346,16 +347,6 @@
     }
 }
 
-void Graph::refChildren(Node* op)
-{
-    DFG_NODE_DO_TO_CHILDREN(*this, op, ref);
-}
-
-void Graph::derefChildren(Node* op)
-{
-    DFG_NODE_DO_TO_CHILDREN(*this, op, deref);
-}
-
 void Graph::dethread()
 {
     if (m_form == LoadStore)
@@ -390,67 +381,6 @@
     successor->m_predecessors.append(blockIndex);
 }
 
-void Graph::collectGarbage()
-{
-    SamplingRegion samplingRegion("DFG Garbage Collection");
-    
-    // First reset the counts to 0 for all nodes.
-    for (BlockIndex blockIndex = 0; blockIndex < m_blocks.size(); ++blockIndex) {
-        BasicBlock* block = m_blocks[blockIndex].get();
-        if (!block)
-            continue;
-        for (unsigned indexInBlock = block->size(); indexInBlock--;)
-            block->at(indexInBlock)->setRefCount(0);
-        for (unsigned phiIndex = block->phis.size(); phiIndex--;)
-            block->phis[phiIndex]->setRefCount(0);
-    }
-    
-    // Now find the roots: the nodes that are must-generate. Set their ref counts to
-    // 1 and put them on the worklist.
-    Vector<Node*, 128> worklist;
-    for (BlockIndex blockIndex = 0; blockIndex < m_blocks.size(); ++blockIndex) {
-        BasicBlock* block = m_blocks[blockIndex].get();
-        if (!block)
-            continue;
-        for (unsigned indexInBlock = block->size(); indexInBlock--;) {
-            Node* node = block->at(indexInBlock);
-            if (!(node->flags() & NodeMustGenerate))
-                continue;
-            node->setRefCount(1);
-            worklist.append(node);
-        }
-    }
-    
-    while (!worklist.isEmpty()) {
-        Node* node = worklist.last();
-        worklist.removeLast();
-        ASSERT(node->shouldGenerate()); // It should not be on the worklist unless it's ref'ed.
-        if (node->flags() & NodeHasVarArgs) {
-            for (unsigned childIdx = node->firstChild();
-                childIdx < node->firstChild() + node->numChildren();
-                ++childIdx) {
-                if (!m_varArgChildren[childIdx])
-                    continue;
-                Node* childNode = m_varArgChildren[childIdx].node();
-                if (childNode->postfixRef())
-                    continue;
-                worklist.append(childNode);
-            }
-        } else if (node->child1()) {
-            if (!node->child1()->postfixRef())
-                worklist.append(node->child1().node());
-            if (node->child2()) {
-                if (!node->child2()->postfixRef())
-                    worklist.append(node->child2().node());
-                if (node->child3()) {
-                    if (!node->child3()->postfixRef())
-                        worklist.append(node->child3().node());
-                }
-            }
-        }
-    }
-}
-
 void Graph::determineReachability()
 {
     Vector<BlockIndex, 16> worklist;
diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h
index dfe4937..d9852ac 100644
--- a/Source/JavaScriptCore/dfg/DFGGraph.h
+++ b/Source/JavaScriptCore/dfg/DFGGraph.h
@@ -92,83 +92,34 @@
     Graph(JSGlobalData&, CodeBlock*, unsigned osrEntryBytecodeIndex, const Operands<JSValue>& mustHandleValues);
     ~Graph();
     
-    // Mark a node as being referenced.
-    Node* ref(Node* node)
+    void changeChild(Edge& edge, Node* newNode)
     {
-        // If the value (before incrementing) was at refCount zero then we need to ref its children.
-        if (!node->postfixRef())
-            refChildren(node);
-        return node;
-    }
-    Edge ref(Edge edge)
-    {
-        ref(edge.node());
-        return edge;
-    }
-    Edge ref(Node*, Edge edge)
-    {
-        return ref(edge);
-    }
-    
-    void deref(Node* node)
-    {
-#if !ASSERT_DISABLED
-        if (!node->refCount())
-            dump();
-#endif
-        if (node->postfixDeref() == 1)
-            derefChildren(node);
-    }
-    void deref(Edge edge)
-    {
-        deref(edge.node());
-    }
-    void deref(Node*, Edge edge)
-    {
-        deref(edge);
-    }
-    
-    // When a node's refCount goes from 0 to 1, it must (logically) recursively ref all of its children, and vice versa.
-    void refChildren(Node*);
-    void derefChildren(Node*);
-
-    void changeChild(Edge& edge, Node* newNode, bool changeRef = true)
-    {
-        if (changeRef) {
-            ref(newNode);
-            deref(edge.node());
-        }
         edge.setNode(newNode);
     }
     
-    void changeEdge(Edge& edge, Edge newEdge, bool changeRef = true)
+    void changeEdge(Edge& edge, Edge newEdge)
     {
-        if (changeRef) {
-            ref(newEdge);
-            deref(edge);
-        }
         edge = newEdge;
     }
     
-    void compareAndSwap(Edge& edge, Node* oldNode, Node* newNode, bool changeRef)
+    void compareAndSwap(Edge& edge, Node* oldNode, Node* newNode)
     {
         if (edge.node() != oldNode)
             return;
-        changeChild(edge, newNode, changeRef);
+        changeChild(edge, newNode);
     }
     
-    void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge, bool changeRef)
+    void compareAndSwap(Edge& edge, Edge oldEdge, Edge newEdge)
     {
         if (edge != oldEdge)
             return;
-        changeEdge(edge, newEdge, changeRef);
+        changeEdge(edge, newEdge);
     }
     
     void clearAndDerefChild(Node* node, unsigned index)
     {
         if (!node->children.child(index))
             return;
-        deref(node->children.child(index));
         node->children.setChild(index, Edge());
     }
     void clearAndDerefChild1(Node* node) { clearAndDerefChild(node, 0); }
@@ -177,18 +128,17 @@
     
     void performSubstitution(Node* node)
     {
-        bool shouldGenerate = node->shouldGenerate();
         if (node->flags() & NodeHasVarArgs) {
             for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); childIdx++)
-                performSubstitutionForEdge(m_varArgChildren[childIdx], shouldGenerate);
+                performSubstitutionForEdge(m_varArgChildren[childIdx]);
         } else {
-            performSubstitutionForEdge(node->child1(), shouldGenerate);
-            performSubstitutionForEdge(node->child2(), shouldGenerate);
-            performSubstitutionForEdge(node->child3(), shouldGenerate);
+            performSubstitutionForEdge(node->child1());
+            performSubstitutionForEdge(node->child2());
+            performSubstitutionForEdge(node->child3());
         }
     }
     
-    void performSubstitutionForEdge(Edge& child, bool addRef)
+    void performSubstitutionForEdge(Edge& child)
     {
         // Check if this operand is actually unused.
         if (!child)
@@ -204,22 +154,13 @@
         // There is definitely a replacement. Assert that the replacement does not
         // have a replacement.
         ASSERT(!child->replacement);
-        
-        if (addRef)
-            ref(child);
     }
     
 #define DFG_DEFINE_ADD_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
-    templatePre typeParams templatePost Node* addNode(RefChildrenMode refChildrenMode, RefNodeMode refNodeMode, SpeculatedType type valueParamsComma valueParams) \
+    templatePre typeParams templatePost Node* addNode(SpeculatedType type valueParamsComma valueParams) \
     { \
         Node* node = new (m_allocator) Node(valueArgs); \
         node->predict(type); \
-        if (node->flags() & NodeMustGenerate) \
-            node->ref(); \
-        if (refNodeMode == RefNode) \
-            node->ref(); \
-        if (refChildrenMode == RefChildren) \
-            refChildren(node); \
         return node; \
     }
     DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_ADD_NODE)
@@ -227,12 +168,6 @@
 
     void dethread();
     
-    // Call this if you've modified the reference counts of nodes that deal with
-    // local variables. This is necessary because local variable references can form
-    // cycles, and hence reference counting is not enough. This will reset the
-    // reference counts according to reachability.
-    void collectGarbage();
-    
     void convertToConstant(Node* node, unsigned constantNumber)
     {
         if (node->op() == GetLocal)
@@ -669,19 +604,19 @@
             if (node->flags() & NodeHasVarArgs) {
                 for (unsigned childIdx = node->firstChild(); childIdx < node->firstChild() + node->numChildren(); ++childIdx) {
                     if (!!m_varArgChildren[childIdx])
-                        compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing, node->shouldGenerate());
+                        compareAndSwap(m_varArgChildren[childIdx], oldThing, newThing);
                 }
                 continue;
             }
             if (!node->child1())
                 continue;
-            compareAndSwap(node->children.child1(), oldThing, newThing, node->shouldGenerate());
+            compareAndSwap(node->children.child1(), oldThing, newThing);
             if (!node->child2())
                 continue;
-            compareAndSwap(node->children.child2(), oldThing, newThing, node->shouldGenerate());
+            compareAndSwap(node->children.child2(), oldThing, newThing);
             if (!node->child3())
                 continue;
-            compareAndSwap(node->children.child3(), oldThing, newThing, node->shouldGenerate());
+            compareAndSwap(node->children.child3(), oldThing, newThing);
         }
     }
     
@@ -755,6 +690,7 @@
     OptimizationFixpointState m_fixpointState;
     GraphForm m_form;
     UnificationState m_unificationState;
+    RefCountState m_refCountState;
 private:
     
     void handleSuccessor(Vector<BlockIndex, 16>& worklist, BlockIndex blockIndex, BlockIndex successorIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGInsertionSet.h b/Source/JavaScriptCore/dfg/DFGInsertionSet.h
index 9dccc0f..70d3098 100644
--- a/Source/JavaScriptCore/dfg/DFGInsertionSet.h
+++ b/Source/JavaScriptCore/dfg/DFGInsertionSet.h
@@ -72,9 +72,9 @@
     }
 
 #define DFG_DEFINE_INSERT_NODE(templatePre, templatePost, typeParams, valueParamsComma, valueParams, valueArgs) \
-    templatePre typeParams templatePost Node* insertNode(size_t index, RefChildrenMode refChildrenMode, RefNodeMode refNodeMode, SpeculatedType type valueParamsComma valueParams) \
+    templatePre typeParams templatePost Node* insertNode(size_t index, SpeculatedType type valueParamsComma valueParams) \
     { \
-        return insert(index, m_graph.addNode(refChildrenMode, refNodeMode, type valueParamsComma valueArgs)); \
+        return insert(index, m_graph.addNode(type valueParamsComma valueArgs)); \
     }
     DFG_VARIADIC_TEMPLATE_FUNCTION(DFG_DEFINE_INSERT_NODE)
 #undef DFG_DEFINE_INSERT_NODE
diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h
index ff7be24..c5a40ce 100644
--- a/Source/JavaScriptCore/dfg/DFGNode.h
+++ b/Source/JavaScriptCore/dfg/DFGNode.h
@@ -91,7 +91,7 @@
         : codeOrigin(codeOrigin)
         , children(children)
         , m_virtualRegister(InvalidVirtualRegister)
-        , m_refCount(0)
+        , m_refCount(1)
         , m_prediction(SpecNone)
     {
         setOpAndDefaultFlags(op);
@@ -102,7 +102,7 @@
         : codeOrigin(codeOrigin)
         , children(AdjacencyList::Fixed, child1, child2, child3)
         , m_virtualRegister(InvalidVirtualRegister)
-        , m_refCount(0)
+        , m_refCount(1)
         , m_prediction(SpecNone)
     {
         setOpAndDefaultFlags(op);
@@ -114,7 +114,7 @@
         : codeOrigin(codeOrigin)
         , children(AdjacencyList::Fixed, child1, child2, child3)
         , m_virtualRegister(InvalidVirtualRegister)
-        , m_refCount(0)
+        , m_refCount(1)
         , m_opInfo(imm.m_value)
         , m_prediction(SpecNone)
     {
@@ -127,7 +127,7 @@
         : codeOrigin(codeOrigin)
         , children(AdjacencyList::Fixed, child1, child2, child3)
         , m_virtualRegister(InvalidVirtualRegister)
-        , m_refCount(0)
+        , m_refCount(1)
         , m_opInfo(imm1.m_value)
         , m_opInfo2(safeCast<unsigned>(imm2.m_value))
         , m_prediction(SpecNone)
@@ -141,7 +141,7 @@
         : codeOrigin(codeOrigin)
         , children(AdjacencyList::Variable, firstChild, numChildren)
         , m_virtualRegister(InvalidVirtualRegister)
-        , m_refCount(0)
+        , m_refCount(1)
         , m_opInfo(imm1.m_value)
         , m_opInfo2(safeCast<unsigned>(imm2.m_value))
         , m_prediction(SpecNone)
@@ -272,8 +272,6 @@
     void convertToConstant(unsigned constantNumber)
     {
         m_op = JSConstant;
-        if (m_flags & NodeMustGenerate)
-            m_refCount--;
         m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld);
         m_opInfo = constantNumber;
         children.reset();
@@ -282,8 +280,6 @@
     void convertToGetLocalUnlinked(VirtualRegister local)
     {
         m_op = GetLocalUnlinked;
-        if (m_flags & NodeMustGenerate)
-            m_refCount--;
         m_flags &= ~(NodeMustGenerate | NodeMightClobber | NodeClobbersWorld);
         m_opInfo = local;
         children.reset();
@@ -386,11 +382,27 @@
         return isConstant() && valueOfJSConstant(codeBlock).isBoolean();
     }
     
+    bool containsMovHint()
+    {
+        switch (op()) {
+        case SetLocal:
+        case MovHint:
+        case MovHintAndCheck:
+        case ZombieHint:
+            return true;
+        default:
+            return false;
+        }
+    }
+    
     bool hasVariableAccessData()
     {
         switch (op()) {
         case GetLocal:
         case SetLocal:
+        case MovHint:
+        case MovHintAndCheck:
+        case ZombieHint:
         case Phi:
         case SetArgument:
         case Flush:
@@ -952,6 +964,9 @@
     {
         switch (op()) {
         case SetLocal:
+        case MovHint:
+        case ZombieHint:
+        case MovHintAndCheck:
         case Int32ToDouble:
         case ForwardInt32ToDouble:
         case ValueToInt32:
@@ -973,12 +988,6 @@
         return m_refCount;
     }
 
-    Node* ref()
-    {
-        m_refCount++;
-        return this;
-    }
-
     unsigned postfixRef()
     {
         return m_refCount++;
@@ -994,18 +1003,6 @@
         m_refCount = refCount;
     }
     
-    void deref()
-    {
-        ASSERT(m_refCount);
-        --m_refCount;
-    }
-    
-    unsigned postfixDeref()
-    {
-        ASSERT(m_refCount);
-        return m_refCount--;
-    }
-    
     Edge& child1()
     {
         ASSERT(!(m_flags & NodeHasVarArgs));
diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h
index 985e388..afada5d 100644
--- a/Source/JavaScriptCore/dfg/DFGNodeType.h
+++ b/Source/JavaScriptCore/dfg/DFGNodeType.h
@@ -59,6 +59,9 @@
     /* VariableAccessData, and thus will share predictions. */\
     macro(GetLocal, NodeResultJS) \
     macro(SetLocal, NodeExitsForward) \
+    macro(MovHintAndCheck, NodeMustGenerate | NodeExitsForward) \
+    macro(MovHint, NodeDoesNotExit) \
+    macro(ZombieHint, NodeDoesNotExit) \
     macro(Phantom, NodeMustGenerate) \
     macro(Nop, NodeDoesNotExit) \
     macro(Phi, NodeDoesNotExit | NodeRelevantToOSR) \
@@ -76,7 +79,7 @@
     /* Hint that inlining begins here. No code is generated for this node. It's only */\
     /* used for copying OSR data into inline frame data, to support reification of */\
     /* call frames of inlined functions. */\
-    macro(InlineStart, 0 | NodeDoesNotExit) \
+    macro(InlineStart, NodeMustGenerate | NodeDoesNotExit) \
     \
     /* Nodes for bitwise operations. */\
     macro(BitAnd, NodeResultInt32 | NodeMustGenerate) \
diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
index c7380e4..438d5d6 100644
--- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
@@ -206,7 +206,13 @@
             if (prediction)
                 changed |= mergePrediction(prediction);
             
-            changed |= variableAccessData->mergeFlags(flags & ~NodeUsedAsIntLocally);
+            // Assume conservatively that a SetLocal implies that the value may flow through a loop,
+            // and so we would have overflow leading to the program "observing" numbers even if all
+            // users of the value are doing toInt32. It might be worthwhile to revisit this at some
+            // point and actually check if the data flow involves loops, but right now I don't think
+            // we have evidence that this would be beneficial for benchmarks.
+            
+            changed |= variableAccessData->mergeFlags((flags & ~NodeUsedAsIntLocally) | NodeUsedAsNumber);
             break;
         }
             
@@ -214,12 +220,7 @@
             VariableAccessData* variableAccessData = node->variableAccessData();
             changed |= variableAccessData->predict(node->child1()->prediction());
 
-            // Assume conservatively that a SetLocal implies that the value may flow through a loop,
-            // and so we would have overflow leading to the program "observing" numbers even if all
-            // users of the value are doing toInt32. It might be worthwhile to revisit this at some
-            // point and actually check if the data flow involves loops, but right now I don't think
-            // we have evidence that this would be beneficial for benchmarks.
-            changed |= node->child1()->mergeFlags(variableAccessData->flags() | NodeUsedAsNumber);
+            changed |= node->child1()->mergeFlags(variableAccessData->flags());
             break;
         }
             
@@ -711,8 +712,6 @@
         }
             
         case CreateArguments: {
-            // At this stage we don't try to predict whether the arguments are ours or
-            // someone else's. We could, but we don't, yet.
             changed |= setPrediction(SpecArguments);
             break;
         }
@@ -737,7 +736,10 @@
         case CheckArray:
         case Arrayify:
         case ArrayifyToStructure:
-        case Identity: {
+        case Identity:
+        case MovHint:
+        case MovHintAndCheck:
+        case ZombieHint: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
             CRASH();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index c79ac2e..7fb1f4c 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -227,9 +227,9 @@
     if (!valueRecovery) {
         // Check that either the current node is a SetLocal, or the preceding node was a
         // SetLocal with the same code origin.
-        if (m_currentNode->op() != SetLocal) {
+        if (!m_currentNode->containsMovHint()) {
             Node* setLocal = m_jit.graph().m_blocks[m_block]->at(m_indexInBlock - 1);
-            ASSERT_UNUSED(setLocal, setLocal->op() == SetLocal);
+            ASSERT_UNUSED(setLocal, setLocal->containsMovHint());
             ASSERT_UNUSED(setLocal, setLocal->codeOrigin == m_currentNode->codeOrigin);
         }
         
@@ -272,7 +272,7 @@
         ASSERT(setLocal->child1()->child1() == m_currentNode);
     else
         ASSERT(setLocal->child1() == m_currentNode);
-    ASSERT(setLocal->op() == SetLocal);
+    ASSERT(setLocal->containsMovHint());
     ASSERT(setLocal->codeOrigin == m_currentNode->codeOrigin);
 
     Node* nextNode = m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1);
@@ -1567,7 +1567,7 @@
 
 void SpeculativeJIT::compileMovHint(Node* node)
 {
-    ASSERT(node->op() == SetLocal);
+    ASSERT(node->containsMovHint() && node->op() != ZombieHint);
     
     m_lastSetOperand = node->local();
 
@@ -1580,6 +1580,54 @@
     m_stream->appendAndLog(VariableEvent::movHint(MinifiedID(child), node->local()));
 }
 
+void SpeculativeJIT::compileMovHintAndCheck(Node* node)
+{
+    compileMovHint(node);
+    speculate(node, node->child1());
+    noResult(node);
+}
+
+void SpeculativeJIT::compileInlineStart(Node* node)
+{
+    InlineCallFrame* inlineCallFrame = node->codeOrigin.inlineCallFrame;
+    int argumentCountIncludingThis = inlineCallFrame->arguments.size();
+    unsigned argumentPositionStart = node->argumentPositionStart();
+    CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
+    for (int i = 0; i < argumentCountIncludingThis; ++i) {
+        ValueRecovery recovery;
+        if (codeBlock->isCaptured(argumentToOperand(i)))
+            recovery = ValueRecovery::alreadyInJSStack();
+        else {
+            ArgumentPosition& argumentPosition =
+                m_jit.graph().m_argumentPositions[argumentPositionStart + i];
+            ValueSource valueSource;
+            if (!argumentPosition.shouldUnboxIfPossible())
+                valueSource = ValueSource(ValueInJSStack);
+            else if (argumentPosition.shouldUseDoubleFormat())
+                valueSource = ValueSource(DoubleInJSStack);
+            else if (isInt32Speculation(argumentPosition.prediction()))
+                valueSource = ValueSource(Int32InJSStack);
+            else if (isCellSpeculation(argumentPosition.prediction()))
+                valueSource = ValueSource(CellInJSStack);
+            else if (isBooleanSpeculation(argumentPosition.prediction()))
+                valueSource = ValueSource(BooleanInJSStack);
+            else
+                valueSource = ValueSource(ValueInJSStack);
+            recovery = computeValueRecoveryFor(valueSource);
+        }
+        // The recovery should refer either to something that has already been
+        // stored into the stack at the right place, or to a constant,
+        // since the Arguments code isn't smart enough to handle anything else.
+        // The exception is the this argument, which we don't really need to be
+        // able to recover.
+#if DFG_ENABLE(DEBUG_VERBOSE)
+        dataLogF("\nRecovery for argument %d: ", i);
+        recovery.dump(WTF::dataFile());
+#endif
+        inlineCallFrame->arguments[i] = recovery;
+    }
+}
+
 void SpeculativeJIT::compile(BasicBlock& block)
 {
     ASSERT(m_compileOkay);
@@ -1678,50 +1726,19 @@
                 break;
                 
             case SetLocal:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+                
+            case MovHint:
                 compileMovHint(m_currentNode);
                 break;
-
-            case InlineStart: {
-                InlineCallFrame* inlineCallFrame = m_currentNode->codeOrigin.inlineCallFrame;
-                int argumentCountIncludingThis = inlineCallFrame->arguments.size();
-                unsigned argumentPositionStart = m_currentNode->argumentPositionStart();
-                CodeBlock* codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame);
-                for (int i = 0; i < argumentCountIncludingThis; ++i) {
-                    ValueRecovery recovery;
-                    if (codeBlock->isCaptured(argumentToOperand(i)))
-                        recovery = ValueRecovery::alreadyInJSStack();
-                    else {
-                        ArgumentPosition& argumentPosition =
-                            m_jit.graph().m_argumentPositions[argumentPositionStart + i];
-                        ValueSource valueSource;
-                        if (!argumentPosition.shouldUnboxIfPossible())
-                            valueSource = ValueSource(ValueInJSStack);
-                        else if (argumentPosition.shouldUseDoubleFormat())
-                            valueSource = ValueSource(DoubleInJSStack);
-                        else if (isInt32Speculation(argumentPosition.prediction()))
-                            valueSource = ValueSource(Int32InJSStack);
-                        else if (isCellSpeculation(argumentPosition.prediction()))
-                            valueSource = ValueSource(CellInJSStack);
-                        else if (isBooleanSpeculation(argumentPosition.prediction()))
-                            valueSource = ValueSource(BooleanInJSStack);
-                        else
-                            valueSource = ValueSource(ValueInJSStack);
-                        recovery = computeValueRecoveryFor(valueSource);
-                    }
-                    // The recovery should refer either to something that has already been
-                    // stored into the stack at the right place, or to a constant,
-                    // since the Arguments code isn't smart enough to handle anything else.
-                    // The exception is the this argument, which we don't really need to be
-                    // able to recover.
-#if DFG_ENABLE(DEBUG_VERBOSE)
-                    dataLogF("\nRecovery for argument %d: ", i);
-                    recovery.dump(WTF::dataFile());
-#endif
-                    inlineCallFrame->arguments[i] = recovery;
-                }
+                
+            case ZombieHint: {
+                m_lastSetOperand = m_currentNode->local();
+                m_stream->appendAndLog(VariableEvent::setLocal(m_currentNode->local(), DataFormatDead));
                 break;
             }
-                
+
             default:
                 if (belongsInMinifiedGraph(m_currentNode->op()))
                     m_minifiedGraph->append(MinifiedNode::fromNode(m_currentNode));
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 849d4e9..b20418c 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -307,7 +307,6 @@
     
     void compile(Node*);
     void noticeOSRBirth(Node*);
-    void compileMovHint(Node*);
     void compile(BasicBlock&);
 
     void checkArgumentTypes();
@@ -682,6 +681,10 @@
         return lastNode->op() == Branch && lastNode->child1() == m_currentNode ? block->size() - 1 : UINT_MAX;
     }
     
+    void compileMovHint(Node*);
+    void compileMovHintAndCheck(Node*);
+    void compileInlineStart(Node*);
+
     void nonSpeculativeUInt32ToNumber(Node*);
 
 #if USE(JSVALUE64)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 48e167b..04fe538 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -2022,6 +2022,22 @@
         break;
     }
 
+    case MovHintAndCheck: {
+        compileMovHintAndCheck(node);
+        break;
+    }
+        
+    case InlineStart: {
+        compileInlineStart(node);
+        break;
+    }
+
+    case MovHint:
+    case ZombieHint: {
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
+
     case SetLocal: {
         // SetLocal doubles as a hint as to where a node will be stored and
         // as a speculation point. So before we speculate make sure that we
@@ -4942,7 +4958,6 @@
         noResult(node);
         break;
 
-    case InlineStart:
     case Nop:
     case LastNodeType:
         RELEASE_ASSERT_NOT_REACHED();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index 7336ab5..4044c97 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -1968,6 +1968,22 @@
         jsValueResult(result.gpr(), node);
         break;
     }
+        
+    case MovHintAndCheck: {
+        compileMovHintAndCheck(node);
+        break;
+    }
+        
+    case InlineStart: {
+        compileInlineStart(node);
+        break;
+    }
+
+    case MovHint:
+    case ZombieHint: {
+        RELEASE_ASSERT_NOT_REACHED();
+        break;
+    }
 
     case SetLocal: {
         // SetLocal doubles as a hint as to where a node will be stored and
@@ -4788,7 +4804,6 @@
         noResult(node);
         break;
         
-    case InlineStart:
     case Nop:
         RELEASE_ASSERT_NOT_REACHED();
         break;
diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
index 8a2da48..8c1cb38 100644
--- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp
@@ -77,9 +77,7 @@
                         break;
                     VariableAccessData* variable = child->variableAccessData();
                     variable->vote(VoteStructureCheck);
-                    if (variable->isCaptured() || variable->structureCheckHoistingFailed())
-                        break;
-                    if (!isCellSpeculation(variable->prediction()))
+                    if (!shouldConsiderForHoisting(variable))
                         break;
                     noticeStructureCheck(variable, node->structureSet());
                     break;
@@ -118,9 +116,7 @@
                             break;
                         VariableAccessData* variable = child->variableAccessData();
                         variable->vote(VoteOther);
-                        if (variable->isCaptured() || variable->structureCheckHoistingFailed())
-                            break;
-                        if (!isCellSpeculation(variable->prediction()))
+                        if (!shouldConsiderForHoisting(variable))
                             break;
                         noticeStructureCheck(variable, 0);
                     }
@@ -132,9 +128,7 @@
                     // we're not hoisting a check that would contravene checks that are
                     // already being performed.
                     VariableAccessData* variable = node->variableAccessData();
-                    if (variable->isCaptured() || variable->structureCheckHoistingFailed())
-                        break;
-                    if (!isCellSpeculation(variable->prediction()))
+                    if (!shouldConsiderForHoisting(variable))
                         break;
                     Node* source = node->child1().node();
                     for (unsigned subIndexInBlock = 0; subIndexInBlock < block->size(); ++subIndexInBlock) {
@@ -288,11 +282,11 @@
                     CodeOrigin codeOrigin = node->codeOrigin;
                     
                     Node* getLocal = insertionSet.insertNode(
-                        indexInBlock + 1, DontRefChildren, DontRefNode, variable->prediction(),
-                        GetLocal, codeOrigin, OpInfo(variable), Edge(node));
+                        indexInBlock + 1, variable->prediction(), GetLocal, codeOrigin,
+                        OpInfo(variable), Edge(node));
                     insertionSet.insertNode(
-                        indexInBlock + 1, RefChildren, DontRefNode, SpecNone, CheckStructure,
-                        codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)),
+                        indexInBlock + 1, SpecNone, CheckStructure, codeOrigin,
+                        OpInfo(m_graph.addStructureSet(iter->value.m_structure)),
                         Edge(getLocal, CellUse));
 
                     if (block->variablesAtTail.operand(variable->local()) == node)
@@ -320,14 +314,14 @@
                     Edge child1 = node->child1();
                     
                     insertionSet.insertNode(
-                        indexInBlock, DontRefChildren, DontRefNode, SpecNone, SetLocal, codeOrigin,
-                        OpInfo(variable), child1);
+                        indexInBlock, SpecNone, SetLocal, codeOrigin, OpInfo(variable), child1);
 
                     // Use a ForwardCheckStructure to indicate that we should exit to the
                     // next bytecode instruction rather than reexecuting the current one.
                     insertionSet.insertNode(
-                        indexInBlock, RefChildren, DontRefNode, SpecNone, ForwardCheckStructure,
-                        codeOrigin, OpInfo(m_graph.addStructureSet(iter->value.m_structure)), Edge(child1.node(), CellUse));
+                        indexInBlock, SpecNone, ForwardCheckStructure, codeOrigin,
+                        OpInfo(m_graph.addStructureSet(iter->value.m_structure)),
+                        Edge(child1.node(), CellUse));
                     changed = true;
                     break;
                 }
@@ -343,6 +337,17 @@
     }
 
 private:
+    bool shouldConsiderForHoisting(VariableAccessData* variable)
+    {
+        if (!variable->shouldUnboxIfPossible())
+            return false;
+        if (variable->structureCheckHoistingFailed())
+            return false;
+        if (!isCellSpeculation(variable->prediction()))
+            return false;
+        return true;
+    }
+    
     void noticeStructureCheck(VariableAccessData* variable, Structure* structure)
     {
         HashMap<VariableAccessData*, CheckData>::AddResult result =
diff --git a/Source/JavaScriptCore/dfg/DFGValidate.cpp b/Source/JavaScriptCore/dfg/DFGValidate.cpp
index a85c4e3..6720451 100644
--- a/Source/JavaScriptCore/dfg/DFGValidate.cpp
+++ b/Source/JavaScriptCore/dfg/DFGValidate.cpp
@@ -114,9 +114,13 @@
                     switch (node->op()) {
                     case Flush:
                     case GetLocal:
+                        VALIDATE((node, edge), edge->hasVariableAccessData());
+                        VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
+                        break;
                     case PhantomLocal:
                         VALIDATE((node, edge), edge->hasVariableAccessData());
                         VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
+                        VALIDATE((node, edge), edge->op() != SetLocal);
                         break;
                     case Phi:
                         VALIDATE((node, edge), edge->hasVariableAccessData());
@@ -125,8 +129,27 @@
                         VALIDATE((node, edge), edge->variableAccessData() == node->variableAccessData());
                         break;
                     case Phantom:
-                        if (m_graph.m_form == LoadStore && !j)
+                        switch (m_graph.m_form) {
+                        case LoadStore:
+                            if (j) {
+                                VALIDATE((node, edge), edge->hasResult());
+                                break;
+                            }
+                            switch (edge->op()) {
+                            case Phi:
+                            case SetArgument:
+                            case SetLocal:
+                                break;
+                            default:
+                                VALIDATE((node, edge), edge->hasResult());
+                                break;
+                            }
                             break;
+                        case ThreadedCPS:
+                            VALIDATE((node, edge), edge->hasResult());
+                            break;
+                        }
+                        break;
                     default:
                         VALIDATE((node, edge), edge->hasResult());
                         break;
@@ -147,10 +170,10 @@
                 nodesInThisBlock.add(node);
                 if (block->isPhiIndex(i))
                     phisInThisBlock.add(node);
-                if (m_graph.m_form == ThreadedCPS || !node->hasVariableAccessData())
+                if (m_graph.m_refCountState == ExactRefCount)
                     V_EQUAL((node), myRefCounts.get(node), node->adjustedRefCount());
                 else
-                    VALIDATE((node), myRefCounts.get(node) ? node->adjustedRefCount() : true);
+                    V_EQUAL((node), node->refCount(), 1);
                 for (unsigned j = 0; j < m_graph.numChildren(node); ++j) {
                     Edge edge = m_graph.child(node, j);
                     if (!edge)
@@ -178,7 +201,10 @@
                         edge->op() == SetLocal
                         || edge->op() == SetArgument
                         || edge->op() == Flush
-                        || edge->op() == Phi);
+                        || edge->op() == Phi
+                        || edge->op() == ZombieHint
+                        || edge->op() == MovHint
+                        || edge->op() == MovHintAndCheck);
                     
                     if (phisInThisBlock.contains(edge.node()))
                         continue;
@@ -187,6 +213,9 @@
                         VALIDATE(
                             (node, edge),
                             edge->op() == SetLocal
+                            || edge->op() == ZombieHint
+                            || edge->op() == MovHint
+                            || edge->op() == MovHintAndCheck
                             || edge->op() == SetArgument
                             || edge->op() == Flush);
                         
@@ -220,6 +249,9 @@
                         VALIDATE(
                             (local, block->m_predecessors[k], prevNode),
                             prevNode->op() == SetLocal
+                            || prevNode->op() == MovHint
+                            || prevNode->op() == MovHintAndCheck
+                            || prevNode->op() == ZombieHint
                             || prevNode->op() == SetArgument
                             || prevNode->op() == Phi);
                         if (prevNode == edge.node()) {
@@ -287,6 +319,10 @@
                 case GetLocal:
                     if (node->variableAccessData()->isCaptured())
                         break;
+                    // Ignore GetLocal's that we know to be dead, but that the graph
+                    // doesn't yet know to be dead.
+                    if (!myRefCounts.get(node))
+                        break;
                     if (m_graph.m_form == ThreadedCPS)
                         VALIDATE((node, blockIndex), getLocalPositions.operand(node->local()) == notSet);
                     getLocalPositions.operand(node->local()) = i;