#pragma once
#include "DFGCombinedLiveness.h"
#include "DFGGraph.h"
#include "DFGOSRAvailabilityAnalysisPhase.h"
#include "FullBytecodeLiveness.h"
namespace JSC { namespace DFG {
namespace ForAllKillsInternal {
constexpr bool verbose = false;
}
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;
Operand alreadyNoted;
if (nodeAfter->containsMovHint()) {
Operand operand = nodeAfter->unlinkedOperand();
if (graph.isLiveInBytecode(operand, after)) {
functor(operand);
alreadyNoted = operand;
}
}
if (before == after)
return;
auto* beforeInlineCallFrame = before.inlineCallFrame();
if (beforeInlineCallFrame == after.inlineCallFrame()) {
CodeBlock* codeBlock = graph.baselineCodeBlockFor(beforeInlineCallFrame);
if (after.bytecodeIndex().checkpoint()) {
ASSERT(before.bytecodeIndex().checkpoint() != after.bytecodeIndex().checkpoint());
ASSERT_WITH_MESSAGE(before.bytecodeIndex().offset() == after.bytecodeIndex().offset() || nodeAfter->op() == ExitOK || nodeAfter->op() == InvalidationPoint, "When the DFG does code motion it should change the forExit origin to match the surrounding bytecodes.");
auto liveBefore = tmpLivenessForCheckpoint(*codeBlock, before.bytecodeIndex());
auto liveAfter = tmpLivenessForCheckpoint(*codeBlock, after.bytecodeIndex());
liveAfter.invert();
liveBefore.filter(liveAfter);
liveBefore.forEachSetBit([&] (size_t tmp) {
functor(remapOperand(beforeInlineCallFrame, Operand::tmp(tmp)));
});
} else if (before.bytecodeIndex().checkpoint()) {
auto liveBefore = tmpLivenessForCheckpoint(*codeBlock, before.bytecodeIndex());
liveBefore.forEachSetBit([&] (size_t tmp) {
functor(remapOperand(beforeInlineCallFrame, Operand::tmp(tmp)));
});
}
FullBytecodeLiveness& fullLiveness = graph.livenessFor(codeBlock);
const FastBitVector& liveBefore = fullLiveness.getLiveness(before.bytecodeIndex(), LivenessCalculationPoint::BeforeUse);
const FastBitVector& liveAfter = fullLiveness.getLiveness(after.bytecodeIndex(), LivenessCalculationPoint::BeforeUse);
(liveBefore & ~liveAfter).forEachSetBit(
[&] (size_t relativeLocal) {
functor(remapOperand(beforeInlineCallFrame, virtualRegisterForLocal(relativeLocal)));
});
return;
}
BitVector liveAfter = graph.localsAndTmpsLiveInBytecode(after);
unsigned numLocals = graph.block(0)->variablesAtHead.numberOfLocals();
graph.forAllLocalsAndTmpsLiveInBytecode(
before,
[&] (Operand operand) {
if (operand == alreadyNoted)
return;
unsigned offset = operand.isTmp() ? numLocals + operand.value() : operand.toLocal();
if (liveAfter.get(offset))
return;
functor(operand);
});
}
template<typename Functor>
void forAllKilledNodesAtNodeIndex(
Graph& graph, AvailabilityMap& availabilityMap, BasicBlock* block, unsigned nodeIndex,
const Functor& functor)
{
static constexpr unsigned seenInClosureFlag = 1;
static constexpr unsigned calledFunctorFlag = 2;
HashMap<Node*, unsigned> flags;
ASSERT(nodeIndex);
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 = block->at(nodeIndex - 1);
forAllKilledOperands(
graph, before, node,
[&] (Operand operand) {
availabilityMap.closeStartingWithLocal(
operand,
[&] (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(graph);
localAvailability.beginBlock(block);
for (unsigned nodeIndex = 1; nodeIndex < block->size(); ++nodeIndex) {
dataLogLnIf(ForAllKillsInternal::verbose, "local availability at index: ", nodeIndex, " ", localAvailability.m_availability);
forAllKilledNodesAtNodeIndex(
graph, localAvailability.m_availability, block, nodeIndex,
[&] (Node* node) {
functor(nodeIndex, node);
});
localAvailability.executeNode(block->at(nodeIndex));
}
}
} }