DFG variable capture analysis should work even if the variables arose through inlining
https://bugs.webkit.org/show_bug.cgi?id=85945

Reviewed by Oliver Hunt.
        
Merged r116555 from dfgopt.
        
This just changes how the DFG queries whether a variable is captured. It does not
change any user-visible behavior.
        
As part of this change, I further solidified the policy that the CFA behaves in an
undefined way for captured locals and queries about their values will not yield
reliable results. This will likely be changed in the future, but for now it makes
sense.
        
One fun part about this change is that it recognizes that the same variable may
be both captured and not, at the same time, because their live interval spans
inlining boundaries. This only happens in the case of arguments to functions that
capture their arguments, and this change treats them with just the right touch of
conservatism: they will be treated as if captured by the caller as well as the 
callee.
        
Finally, this also adds captured variable reasoning to the InlineCallFrame, which
I thought might be useful for later tooling.
        
This is perf-neutral, since it does it does not make the DFG take advantage of this
new functionality in any way. In particular, it is still the case that the DFG will
not inline functions that use arguments reflectively or that create activations.

* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::needsActivation):
(JSC::CodeBlock::argumentIsCaptured):
(JSC::CodeBlock::localIsCaptured):
(JSC::CodeBlock::isCaptured):
* bytecode/CodeOrigin.h:
(InlineCallFrame):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::endBasicBlock):
(JSC::DFG::AbstractState::execute):
(JSC::DFG::AbstractState::merge):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::newVariableAccessData):
(JSC::DFG::ByteCodeParser::getLocal):
(JSC::DFG::ByteCodeParser::setLocal):
(JSC::DFG::ByteCodeParser::getArgument):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::flushArgument):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::processPhiStack):
(JSC::DFG::ByteCodeParser::fixVariableAccessPredictions):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGCFGSimplificationPhase.cpp:
(CFGSimplificationPhase):
(JSC::DFG::CFGSimplificationPhase::keepOperandAlive):
(JSC::DFG::CFGSimplificationPhase::fixPossibleGetLocal):
(JSC::DFG::CFGSimplificationPhase::fixTailOperand):
* dfg/DFGCommon.h:
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::nameOfVariableAccessData):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::needsActivation):
(JSC::DFG::Graph::usesArguments):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGVariableAccessData.h:
(JSC::DFG::VariableAccessData::VariableAccessData):
(JSC::DFG::VariableAccessData::mergeIsCaptured):
(VariableAccessData):
(JSC::DFG::VariableAccessData::isCaptured):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@118136 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index f291b58..0ae5069 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -111,7 +111,7 @@
             continue;
         }
         
-        if (graph.argumentIsCaptured(i)) {
+        if (node.variableAccessData()->isCaptured()) {
             root->valuesAtHead.argument(i).makeTop();
             continue;
         }
@@ -147,7 +147,8 @@
         root->valuesAtTail.argument(i).clear();
     }
     for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
-        if (graph.localIsCaptured(i))
+        NodeIndex nodeIndex = root->variablesAtHead.local(i);
+        if (nodeIndex != NoNode && graph[nodeIndex].variableAccessData()->isCaptured())
             root->valuesAtHead.local(i).makeTop();
         else
             root->valuesAtHead.local(i).clear();
@@ -195,7 +196,8 @@
             dataLog("        Merging state for argument %zu.\n", argument);
 #endif
             AbstractValue& destination = block->valuesAtTail.argument(argument);
-            if (m_graph.argumentIsCaptured(argument)) {
+            NodeIndex nodeIndex = block->variablesAtTail.argument(argument);
+            if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
                 if (!destination.isTop()) {
                     destination.makeTop();
                     changed = true;
@@ -209,7 +211,8 @@
             dataLog("        Merging state for local %zu.\n", local);
 #endif
             AbstractValue& destination = block->valuesAtTail.local(local);
-            if (m_graph.localIsCaptured(local)) {
+            NodeIndex nodeIndex = block->variablesAtTail.local(local);
+            if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
                 if (!destination.isTop()) {
                     destination.makeTop();
                     changed = true;
@@ -255,7 +258,7 @@
     }
             
     case GetLocal: {
-        if (m_graph.isCaptured(node.local()))
+        if (node.variableAccessData()->isCaptured())
             forNode(nodeIndex).makeTop();
         else
             forNode(nodeIndex) = m_variables.operand(node.local());
@@ -263,7 +266,7 @@
     }
         
     case SetLocal: {
-        if (m_graph.isCaptured(node.local()))
+        if (node.variableAccessData()->isCaptured())
             break;
         
         if (node.variableAccessData()->shouldUseDoubleFormat()) {
@@ -1426,7 +1429,8 @@
     
     for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
         AbstractValue& destination = to->valuesAtHead.argument(argument);
-        if (m_graph.argumentIsCaptured(argument)) {
+        NodeIndex nodeIndex = from->variablesAtTail.argument(argument);
+        if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
             if (destination.isTop())
                 continue;
             destination.makeTop();
@@ -1438,7 +1442,8 @@
     
     for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local) {
         AbstractValue& destination = to->valuesAtHead.local(local);
-        if (m_graph.localIsCaptured(local)) {
+        NodeIndex nodeIndex = from->variablesAtTail.local(local);
+        if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
             if (destination.isTop())
                 continue;
             destination.makeTop();