Allow CreateActivation sinking
https://bugs.webkit.org/show_bug.cgi?id=144300
Reviewed by Filip Pizlo.
Source/JavaScriptCore:
This pursues the work started in
https://bugs.webkit.org/show_bug.cgi?id=144016 to expand the set of
allocations we are able to sink by allowing sinking of CreateActivation
node.
This is achieved by following closely the way NewObject is currently
sunk: we add a new PhantomCreateActivation node to record the initial
position of the CreateActivation node, new ClosureVarPLoc promoted heap
locations to keep track of the variables put in the activation, and a
new MaterializeCreateActivation node to allocate and populate the sunk
activation.
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNode.cpp:
(JSC::DFG::Node::convertToPutClosureVarHint):
* dfg/DFGNode.h:
(JSC::DFG::Node::convertToPhantomCreateActivation):
(JSC::DFG::Node::isActivationAllocation):
(JSC::DFG::Node::isPhantomActivationAllocation):
(JSC::DFG::Node::isPhantomAllocation):
* dfg/DFGNodeType.h:
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::lowerNonReadingOperationsOnPhantomAllocations):
(JSC::DFG::ObjectAllocationSinkingPhase::handleNode):
(JSC::DFG::ObjectAllocationSinkingPhase::createMaterialize):
(JSC::DFG::ObjectAllocationSinkingPhase::populateMaterialize):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGPromotedHeapLocation.cpp:
(WTF::printInternal):
* dfg/DFGPromotedHeapLocation.h:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validateCPS):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileMaterializeCreateActivation):
* ftl/FTLOperations.cpp:
(JSC::FTL::operationMaterializeObjectInOSR):
* tests/stress/activation-sink-osrexit.js: Added.
(bar):
(foo.set result):
* tests/stress/activation-sink.js: Added.
(bar):
LayoutTests:
Add a performance test for activation allocation sinking.
* js/regress/script-tests/sink-huge-activation.js: Added.
(bar):
(foo):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@183812 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp b/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
index 339b7df..19aa2bc 100644
--- a/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp
@@ -506,6 +506,15 @@
}
break;
}
+
+ case PutClosureVar: {
+ Node* target = node->child1().node();
+ if (m_sinkCandidates.contains(target)) {
+ ASSERT(target->isPhantomActivationAllocation());
+ node->convertToPutClosureVarHint();
+ }
+ break;
+ }
case PutStructure: {
Node* target = node->child1().node();
@@ -569,11 +578,43 @@
break;
}
+ case CreateActivation: {
+ if (m_sinkCandidates.contains(node)) {
+ m_insertionSet.insert(
+ nodeIndex + 1,
+ PromotedHeapLocation(ActivationScopePLoc, node).createHint(
+ m_graph, node->origin, node->child1().node()));
+ node->convertToPhantomCreateActivation();
+ }
+ break;
+ }
+
+ case MaterializeCreateActivation: {
+ if (m_sinkCandidates.contains(node)) {
+ m_insertionSet.insert(
+ nodeIndex + 1,
+ PromotedHeapLocation(ActivationScopePLoc, node).createHint(
+ m_graph, node->origin, m_graph.varArgChild(node, 0).node()));
+ ObjectMaterializationData& data = node->objectMaterializationData();
+ for (unsigned i = 0; i < data.m_properties.size(); ++i) {
+ unsigned identifierNumber = data.m_properties[i].m_identifierNumber;
+ m_insertionSet.insert(
+ nodeIndex + 1,
+ PromotedHeapLocation(
+ ClosureVarPLoc, node, identifierNumber).createHint(
+ m_graph, node->origin,
+ m_graph.varArgChild(node, i + 1).node()));
+ }
+ node->convertToPhantomCreateActivation();
+ }
+ break;
+ }
+
case StoreBarrier:
case StoreBarrierWithNullCheck: {
Node* target = node->child1().node();
if (m_sinkCandidates.contains(target)) {
- ASSERT(target->isPhantomObjectAllocation());
+ ASSERT(target->isPhantomAllocation());
node->remove();
}
break;
@@ -775,6 +816,7 @@
switch (node->op()) {
case NewObject:
case MaterializeNewObject:
+ case MaterializeCreateActivation:
sinkCandidate();
m_graph.doToChildren(
node,
@@ -793,18 +835,28 @@
});
break;
+ case CreateActivation:
+ if (!m_graph.symbolTableFor(node->origin.semantic)->singletonScope()->isStillValid())
+ sinkCandidate();
+ m_graph.doToChildren(
+ node,
+ [&] (Edge edge) {
+ escape(edge.node());
+ });
+ break;
+
case MovHint:
case Check:
case PutHint:
+ case StoreBarrier:
+ case StoreBarrierWithNullCheck:
break;
case PutStructure:
case CheckStructure:
case GetByOffset:
case MultiGetByOffset:
- case GetGetterSetterByOffset:
- case StoreBarrier:
- case StoreBarrierWithNullCheck: {
+ case GetGetterSetterByOffset: {
Node* target = node->child1().node();
if (!target->isObjectAllocation())
escape(target);
@@ -820,6 +872,14 @@
escape(node->child3().node());
break;
}
+
+ case PutClosureVar: {
+ Node* target = node->child1().node();
+ if (!target->isActivationAllocation())
+ escape(target);
+ escape(node->child2().node());
+ break;
+ }
case MultiPutByOffset:
// FIXME: In the future we should be able to handle this. It's just a matter of
@@ -869,6 +929,19 @@
escapee->child1());
break;
+ case CreateActivation:
+ case MaterializeCreateActivation: {
+ ObjectMaterializationData* data = m_graph.m_objectMaterializationData.add();
+
+ result = m_graph.addNode(
+ escapee->prediction(), Node::VarArg, MaterializeCreateActivation,
+ NodeOrigin(
+ escapee->origin.semantic,
+ where->origin.forExit),
+ OpInfo(data), OpInfo(), 0, 0);
+ break;
+ }
+
default:
DFG_CRASH(m_graph, escapee, "Bad escapee op");
break;
@@ -928,6 +1001,46 @@
break;
}
+ case MaterializeCreateActivation: {
+ ObjectMaterializationData& data = node->objectMaterializationData();
+
+ unsigned firstChild = m_graph.m_varArgChildren.size();
+
+ Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);
+
+ PromotedHeapLocation scope(ActivationScopePLoc, escapee);
+ ASSERT(locations.contains(scope));
+
+ m_graph.m_varArgChildren.append(Edge(resolve(block, scope), KnownCellUse));
+
+ for (unsigned i = 0; i < locations.size(); ++i) {
+ switch (locations[i].kind()) {
+ case ActivationScopePLoc: {
+ ASSERT(locations[i] == scope);
+ break;
+ }
+
+ case ClosureVarPLoc: {
+ Node* value = resolve(block, locations[i]);
+ if (value->op() == BottomValue)
+ break;
+
+ data.m_properties.append(PhantomPropertyValue(locations[i].info()));
+ m_graph.m_varArgChildren.append(value);
+ break;
+ }
+
+ default:
+ DFG_CRASH(m_graph, node, "Bad location kind");
+ }
+ }
+
+ node->children = AdjacencyList(
+ AdjacencyList::Variable,
+ firstChild, m_graph.m_varArgChildren.size() - firstChild);
+ break;
+ }
+
case NewFunction: {
if (!ASSERT_DISABLED) {
Vector<PromotedHeapLocation> locations = m_locationsForAllocation.get(escapee);