DFG should be able to handle variables getting captured
https://bugs.webkit.org/show_bug.cgi?id=79469
Reviewed by Oliver Hunt.
Made captured variables work by placing a Flush on the SetLocal and
forcing the emission of the GetLocal even if copy propagation tells us
who has the value.
Changed the CFA and various prediction codes to understand that we can't
really prove anything about captured variables. Well, we could in the
future by just looking at what side effects are happening, but in this
first cut we just assume that we can't reason about captured variables.
Also added a mode where the DFG pretends that all variables and arguments
got captured. Used this mode to harden the code.
This is performance neutral. Capturing all variables is a slow down, but
not too big of one. This seems to predict that when we add activation
support, the amount of speed benefit we'll get from increased coverage
will far outweigh the pessimism that we'll have to endure for captured
variables.
* bytecode/CodeType.h:
(JSC::codeTypeToString):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::initialize):
(JSC::DFG::AbstractState::endBasicBlock):
(JSC::DFG::AbstractState::execute):
(JSC::DFG::AbstractState::merge):
* dfg/DFGAbstractState.h:
(AbstractState):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getLocal):
(JSC::DFG::ByteCodeParser::setLocal):
(JSC::DFG::ByteCodeParser::getArgument):
(JSC::DFG::ByteCodeParser::setArgument):
(JSC::DFG::ByteCodeParser::flushArgument):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::processPhiStack):
(JSC::DFG::ByteCodeParser::parseCodeBlock):
(JSC::DFG::ByteCodeParser::parse):
* dfg/DFGCapabilities.h:
(JSC::DFG::mightInlineFunctionForCall):
(JSC::DFG::mightInlineFunctionForConstruct):
* dfg/DFGCommon.h:
* dfg/DFGGraph.h:
(JSC::DFG::Graph::needsActivation):
(Graph):
(JSC::DFG::Graph::argumentIsCaptured):
(JSC::DFG::Graph::localIsCaptured):
(JSC::DFG::Graph::isCaptured):
* dfg/DFGNode.h:
(JSC::DFG::Node::shouldGenerate):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
* dfg/DFGSpeculativeJIT.cpp:
(DFG):
(JSC::DFG::ValueSource::dump):
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT.h:
(ValueSource):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGVirtualRegisterAllocationPhase.cpp:
(JSC::DFG::VirtualRegisterAllocationPhase::run):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108842 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index ee0cc9a..bafb4bc 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -113,6 +113,11 @@
continue;
}
+ if (graph.argumentIsCaptured(i)) {
+ root->valuesAtHead.argument(i).makeTop();
+ continue;
+ }
+
PredictedType prediction = node.variableAccessData()->prediction();
if (isInt32Prediction(prediction))
root->valuesAtHead.argument(i).set(PredictInt32);
@@ -143,6 +148,11 @@
else
root->valuesAtHead.argument(i).makeTop();
}
+ for (size_t i = 0; i < root->valuesAtHead.numberOfLocals(); ++i) {
+ if (!graph.localIsCaptured(i))
+ continue;
+ root->valuesAtHead.local(i).makeTop();
+ }
}
bool AbstractState::endBasicBlock(MergeMode mergeMode)
@@ -164,14 +174,28 @@
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Merging state for argument %zu.\n", argument);
#endif
- changed |= mergeStateAtTail(block->valuesAtTail.argument(argument), m_variables.argument(argument), block->variablesAtTail.argument(argument));
+ AbstractValue& destination = block->valuesAtTail.argument(argument);
+ if (m_graph.argumentIsCaptured(argument)) {
+ if (!destination.isTop()) {
+ destination.makeTop();
+ changed = true;
+ }
+ } else
+ changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
}
for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Merging state for local %zu.\n", local);
#endif
- changed |= mergeStateAtTail(block->valuesAtTail.local(local), m_variables.local(local), block->variablesAtTail.local(local));
+ AbstractValue& destination = block->valuesAtTail.local(local);
+ if (m_graph.localIsCaptured(local)) {
+ if (!destination.isTop()) {
+ destination.makeTop();
+ changed = true;
+ }
+ } else
+ changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
}
}
@@ -216,11 +240,17 @@
}
case GetLocal: {
- forNode(nodeIndex) = m_variables.operand(node.local());
+ if (m_graph.isCaptured(node.local()))
+ forNode(nodeIndex).makeTop();
+ else
+ forNode(nodeIndex) = m_variables.operand(node.local());
break;
}
case SetLocal: {
+ if (m_graph.isCaptured(node.local()))
+ break;
+
if (node.variableAccessData()->shouldUseDoubleFormat()) {
forNode(node.child1()).filter(PredictNumber);
m_variables.operand(node.local()).set(PredictDouble);
@@ -1016,11 +1046,29 @@
bool changed = false;
- for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument)
- changed |= mergeVariableBetweenBlocks(to->valuesAtHead.argument(argument), from->valuesAtTail.argument(argument), to->variablesAtHead.argument(argument), from->variablesAtTail.argument(argument));
+ for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
+ AbstractValue& destination = to->valuesAtHead.argument(argument);
+ if (m_graph.argumentIsCaptured(argument)) {
+ if (destination.isTop())
+ continue;
+ destination.makeTop();
+ changed = true;
+ continue;
+ }
+ changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.argument(argument), to->variablesAtHead.argument(argument), from->variablesAtTail.argument(argument));
+ }
- for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local)
- changed |= mergeVariableBetweenBlocks(to->valuesAtHead.local(local), from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
+ for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local) {
+ AbstractValue& destination = to->valuesAtHead.local(local);
+ if (m_graph.localIsCaptured(local)) {
+ if (destination.isTop())
+ continue;
+ destination.makeTop();
+ changed = true;
+ continue;
+ }
+ changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
+ }
if (!to->cfaHasVisited)
changed = true;