DFGPhantomInsertionPhase.cpp [plain text]
#include "config.h"
#include "DFGPhantomInsertionPhase.h"
#if ENABLE(DFG_JIT)
#include "BytecodeLivenessAnalysisInlines.h"
#include "DFGForAllKills.h"
#include "DFGGraph.h"
#include "DFGInsertionSet.h"
#include "DFGMayExit.h"
#include "DFGPhase.h"
#include "DFGPredictionPropagationPhase.h"
#include "DFGVariableAccessDataDump.h"
#include "JSCInlines.h"
#include "OperandsInlines.h"
namespace JSC { namespace DFG {
namespace {
bool verbose = false;
class PhantomInsertionPhase : public Phase {
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->unlinkedLocal()) = node->child1().node();
break;
case ZombieHint:
m_values.operand(node->unlinkedLocal()) = nullptr;
break;
case GetLocal:
case SetArgument:
m_values.operand(node->local()) = nullptr;
break;
default:
break;
}
bool nodeMayExit = mayExit(m_graph, node) != DoesNotExit;
if (nodeMayExit) {
currentEpoch.bump();
lastExitingIndex = nodeIndex;
}
m_graph.doToChildren(
node,
[&] (Edge edge) {
edge->setEpoch(currentEpoch);
});
node->setEpoch(currentEpoch);
VirtualRegister alreadyKilled;
auto processKilledOperand = [&] (VirtualRegister reg) {
if (verbose)
dataLog(" Killed operand: ", reg, "\n");
if (reg == alreadyKilled)
return;
Node* killedNode = m_values.operand(reg);
if (!killedNode)
return;
if (killedNode->epoch() == currentEpoch)
return;
if (verbose) {
dataLog(
" Inserting Phantom on ", killedNode, " after ",
block->at(lastExitingIndex), "\n");
}
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) {
VirtualRegister local = node->local();
if (nodeMayExit) {
processKilledOperand(local);
alreadyKilled = local;
}
m_values.operand(local) = 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)