DFGPhantomInsertionPhase.cpp [plain text]
#include "config.h"
#include "DFGPhantomInsertionPhase.h"
#if ENABLE(DFG_JIT)
#include "DFGForAllKills.h"
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGMayExit.h"
#include "DFGPhase.h"
#include "JSCJSValueInlines.h"
#include "OperandsInlines.h"
namespace JSC { namespace DFG {
namespace {
class PhantomInsertionPhase : public Phase {
static constexpr bool verbose = false;
public:
PhantomInsertionPhase(Graph& graph)
: Phase(graph, "phantom insertion")
, m_insertionSet(graph)
, m_values(OperandsLike, graph.block(0)->variablesAtHead)
{
}
bool run()
{
DFG_ASSERT(m_graph, nullptr, m_graph.m_refCountState == ExactRefCount);
if (verbose) {
dataLog("Graph before Phantom insertion:\n");
m_graph.dump();
}
m_graph.clearEpochs();
for (BasicBlock* block : m_graph.blocksInNaturalOrder())
handleBlock(block);
if (verbose) {
dataLog("Graph after Phantom insertion:\n");
m_graph.dump();
}
return true;
}
private:
void handleBlock(BasicBlock* block)
{
m_values.fill(nullptr);
Epoch currentEpoch = Epoch::first();
unsigned lastExitingIndex = 0;
for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
Node* node = block->at(nodeIndex);
if (verbose)
dataLog("Considering ", node, "\n");
switch (node->op()) {
case MovHint:
m_values.operand(node->unlinkedOperand()) = node->child1().node();
break;
case GetLocal:
case SetArgumentDefinitely:
case SetArgumentMaybe:
m_values.operand(node->operand()) = nullptr;
break;
default:
break;
}
bool nodeMayExit = mayExit(m_graph, node) != DoesNotExit;
if (nodeMayExit) {
currentEpoch.bump();
lastExitingIndex = nodeIndex;
}
m_graph.doToChildren(
node,
[&] (Edge edge) {
dataLogLnIf(verbose, "Updating epoch for ", edge, " to ", currentEpoch);
edge->setEpoch(currentEpoch);
});
node->setEpoch(currentEpoch);
Operand alreadyKilled;
auto processKilledOperand = [&] (Operand operand) {
dataLogLnIf(verbose, " Killed operand: ", operand);
if (operand == alreadyKilled) {
dataLogLnIf(verbose, " Operand ", operand, " already killed by set local");
return;
}
Node* killedNode = m_values.operand(operand);
if (!killedNode) {
dataLogLnIf(verbose, " Operand ", operand, " was not defined in this block.");
return;
}
m_values.operand(operand) = nullptr;
if (killedNode->epoch() == currentEpoch) {
dataLogLnIf(verbose, " Operand ", operand, " has current epoch ", currentEpoch);
return;
}
dataLogLnIf(verbose,
" Inserting Phantom on ", killedNode, " after ",
block->at(lastExitingIndex));
killedNode->postfixRef();
Node* lastExitingNode = block->at(lastExitingIndex);
m_insertionSet.insertNode(
lastExitingIndex + 1, SpecNone, Phantom,
lastExitingNode->origin.forInsertingAfter(m_graph, lastExitingNode),
killedNode->defaultEdge());
};
if (node->op() == SetLocal) {
Operand operand = node->operand();
if (nodeMayExit) {
processKilledOperand(operand);
alreadyKilled = operand;
}
m_values.operand(operand) = nullptr;
}
forAllKilledOperands(m_graph, node, block->tryAt(nodeIndex + 1), processKilledOperand);
}
m_insertionSet.execute(block);
}
InsertionSet m_insertionSet;
Operands<Node*> m_values;
};
}
bool performPhantomInsertion(Graph& graph)
{
return runPhase<PhantomInsertionPhase>(graph);
}
} }
#endif // ENABLE(DFG_JIT)