#ifndef DFGForAllKills_h
#define DFGForAllKills_h
#include "DFGCombinedLiveness.h"
#include "DFGGraph.h"
#include "DFGOSRAvailabilityAnalysisPhase.h"
#include "FullBytecodeLiveness.h"
namespace JSC { namespace DFG {
template<typename Functor>
void forAllKilledOperands(Graph& graph, Node* nodeBefore, Node* nodeAfter, const Functor& functor)
{
CodeOrigin before = nodeBefore->origin.forExit;
if (!nodeAfter) {
graph.forAllLiveInBytecode(before, functor);
return;
}
CodeOrigin after = nodeAfter->origin.forExit;
VirtualRegister alreadyNoted;
if (!!after) {
if (nodeAfter->containsMovHint()) {
VirtualRegister reg = nodeAfter->unlinkedLocal();
if (graph.isLiveInBytecode(reg, after)) {
functor(reg);
alreadyNoted = reg;
}
}
}
if (!before) {
if (!after)
return;
graph.forAllLocalsLiveInBytecode(after, functor);
return;
}
if (before == after)
return;
ASSERT(!!after);
if (before.inlineCallFrame == after.inlineCallFrame) {
int stackOffset = before.inlineCallFrame ? before.inlineCallFrame->stackOffset : 0;
CodeBlock* codeBlock = graph.baselineCodeBlockFor(before.inlineCallFrame);
FullBytecodeLiveness& fullLiveness = graph.livenessFor(codeBlock);
const FastBitVector& liveBefore = fullLiveness.getLiveness(before.bytecodeIndex);
const FastBitVector& liveAfter = fullLiveness.getLiveness(after.bytecodeIndex);
for (unsigned relativeLocal = codeBlock->m_numCalleeRegisters; relativeLocal--;) {
if (liveBefore.get(relativeLocal) && !liveAfter.get(relativeLocal))
functor(virtualRegisterForLocal(relativeLocal) + stackOffset);
}
return;
}
BitVector liveAfter = graph.localsLiveInBytecode(after);
graph.forAllLocalsLiveInBytecode(
before,
[&] (VirtualRegister reg) {
if (reg == alreadyNoted)
return;
if (liveAfter.get(reg.toLocal()))
return;
functor(reg);
});
}
template<typename Functor>
void forAllKilledNodesAtNodeIndex(
Graph& graph, AvailabilityMap& availabilityMap, BasicBlock* block, unsigned nodeIndex,
const Functor& functor)
{
static const unsigned seenInClosureFlag = 1;
static const unsigned calledFunctorFlag = 2;
HashMap<Node*, unsigned> flags;
Node* node = block->at(nodeIndex);
graph.doToChildren(
node,
[&] (Edge edge) {
if (edge.doesKill()) {
auto& result = flags.add(edge.node(), 0).iterator->value;
if (!(result & calledFunctorFlag)) {
functor(edge.node());
result |= calledFunctorFlag;
}
}
});
Node* before = nullptr;
if (nodeIndex)
before = block->at(nodeIndex - 1);
forAllKilledOperands(
graph, before, node,
[&] (VirtualRegister reg) {
availabilityMap.closeStartingWithLocal(
reg,
[&] (Node* node) -> bool {
return flags.get(node) & seenInClosureFlag;
},
[&] (Node* node) -> bool {
auto& resultFlags = flags.add(node, 0).iterator->value;
bool result = resultFlags & seenInClosureFlag;
if (!(resultFlags & calledFunctorFlag))
functor(node);
resultFlags |= seenInClosureFlag | calledFunctorFlag;
return result;
});
});
}
template<typename Functor>
void forAllKillsInBlock(
Graph& graph, const CombinedLiveness& combinedLiveness, BasicBlock* block,
const Functor& functor)
{
for (Node* node : combinedLiveness.liveAtTail[block])
functor(block->size(), node);
LocalOSRAvailabilityCalculator localAvailability;
localAvailability.beginBlock(block);
for (unsigned nodeIndex = 1; nodeIndex < block->size(); ++nodeIndex) {
forAllKilledNodesAtNodeIndex(
graph, localAvailability.m_availability, block, nodeIndex,
[&] (Node* node) {
functor(nodeIndex, node);
});
localAvailability.executeNode(block->at(nodeIndex));
}
}
} }
#endif // DFGForAllKills_h