BytecodeLivenessAnalysis.cpp [plain text]
#include "config.h"
#include "BytecodeLivenessAnalysis.h"
#include "BytecodeLivenessAnalysisInlines.h"
#include "BytecodeUseDef.h"
#include "CodeBlock.h"
#include "FullBytecodeLiveness.h"
#include "JSCJSValueInlines.h"
namespace JSC {
BytecodeLivenessAnalysis::BytecodeLivenessAnalysis(CodeBlock* codeBlock)
: m_graph(codeBlock, codeBlock->instructions())
{
runLivenessFixpoint(codeBlock, codeBlock->instructions(), m_graph);
if (UNLIKELY(Options::dumpBytecodeLivenessResults()))
dumpResults(codeBlock);
}
void BytecodeLivenessAnalysis::computeFullLiveness(CodeBlock* codeBlock, FullBytecodeLiveness& result)
{
FastBitVector out;
size_t size = codeBlock->instructions().size();
result.m_usesBefore.resize(size);
result.m_usesAfter.resize(size);
for (BytecodeBasicBlock& block : m_graph.basicBlocksInReverseOrder()) {
if (block.isEntryBlock() || block.isExitBlock())
continue;
out = block.out();
auto use = [&] (unsigned bitIndex) {
out[bitIndex] = true;
};
auto def = [&] (unsigned bitIndex) {
out[bitIndex] = false;
};
auto& instructions = codeBlock->instructions();
unsigned cursor = block.totalLength();
for (unsigned i = block.delta().size(); i--;) {
cursor -= block.delta()[i];
BytecodeIndex bytecodeIndex = BytecodeIndex(block.leaderOffset() + cursor);
auto instruction = instructions.at(bytecodeIndex);
for (Checkpoint checkpoint = instruction->numberOfCheckpoints(); checkpoint--;) {
ASSERT(checkpoint < instruction->size());
bytecodeIndex = bytecodeIndex.withCheckpoint(checkpoint);
stepOverBytecodeIndexDef(codeBlock, instructions, m_graph, bytecodeIndex, def);
stepOverBytecodeIndexUseInExceptionHandler(codeBlock, instructions, m_graph, bytecodeIndex, use);
result.m_usesAfter[result.toIndex(bytecodeIndex)] = out; stepOverBytecodeIndexUse(codeBlock, instructions, m_graph, bytecodeIndex, use);
result.m_usesBefore[result.toIndex(bytecodeIndex)] = out; }
}
}
}
void BytecodeLivenessAnalysis::dumpResults(CodeBlock* codeBlock)
{
dataLog("\nDumping bytecode liveness for ", *codeBlock, ":\n");
const auto& instructions = codeBlock->instructions();
unsigned i = 0;
unsigned numberOfBlocks = m_graph.size();
Vector<FastBitVector> predecessors(numberOfBlocks);
for (BytecodeBasicBlock& block : m_graph)
predecessors[block.index()].resize(numberOfBlocks);
for (BytecodeBasicBlock& block : m_graph) {
for (unsigned successorIndex : block.successors()) {
unsigned blockIndex = block.index();
predecessors[successorIndex][blockIndex] = true;
}
}
auto dumpBitVector = [] (FastBitVector& bits) {
for (unsigned j = 0; j < bits.numBits(); j++) {
if (bits[j])
dataLogF(" %u", j);
}
};
for (BytecodeBasicBlock& block : m_graph) {
dataLogF("\nBytecode basic block %u: %p (offset: %u, length: %u)\n", i++, &block, block.leaderOffset(), block.totalLength());
dataLogF("Predecessors:");
dumpBitVector(predecessors[block.index()]);
dataLogF("\n");
dataLogF("Successors:");
FastBitVector successors;
successors.resize(numberOfBlocks);
for (unsigned successorIndex : block.successors())
successors[successorIndex] = true;
dumpBitVector(successors); dataLogF("\n");
if (block.isEntryBlock()) {
dataLogF("Entry block %p\n", &block);
continue;
}
if (block.isExitBlock()) {
dataLogF("Exit block: %p\n", &block);
continue;
}
for (unsigned bytecodeOffset = block.leaderOffset(); bytecodeOffset < block.leaderOffset() + block.totalLength();) {
const auto currentInstruction = instructions.at(bytecodeOffset);
dataLogF("Live variables:");
FastBitVector liveBefore = getLivenessInfoAtInstruction(codeBlock, BytecodeIndex(bytecodeOffset));
dumpBitVector(liveBefore);
dataLogF("\n");
codeBlock->dumpBytecode(WTF::dataFile(), currentInstruction);
bytecodeOffset += currentInstruction->size();
}
dataLogF("Live variables:");
FastBitVector liveAfter = block.out();
dumpBitVector(liveAfter);
dataLogF("\n");
}
}
template<typename EnumType1, typename EnumType2>
constexpr bool enumValuesEqualAsIntegral(EnumType1 v1, EnumType2 v2)
{
using IntType1 = typename std::underlying_type<EnumType1>::type;
using IntType2 = typename std::underlying_type<EnumType2>::type;
if constexpr (sizeof(IntType1) > sizeof(IntType2))
return static_cast<IntType1>(v1) == static_cast<IntType1>(v2);
else
return static_cast<IntType2>(v1) == static_cast<IntType2>(v2);
}
Bitmap<maxNumCheckpointTmps> tmpLivenessForCheckpoint(const CodeBlock& codeBlock, BytecodeIndex bytecodeIndex)
{
Bitmap<maxNumCheckpointTmps> result;
Checkpoint checkpoint = bytecodeIndex.checkpoint();
if (!checkpoint)
return result;
switch (codeBlock.instructions().at(bytecodeIndex)->opcodeID()) {
case op_call_varargs:
case op_tail_call_varargs:
case op_construct_varargs: {
static_assert(enumValuesEqualAsIntegral(OpCallVarargs::makeCall, OpTailCallVarargs::makeCall) && enumValuesEqualAsIntegral(OpCallVarargs::argCountIncludingThis, OpTailCallVarargs::argCountIncludingThis));
static_assert(enumValuesEqualAsIntegral(OpCallVarargs::makeCall, OpConstructVarargs::makeCall) && enumValuesEqualAsIntegral(OpCallVarargs::argCountIncludingThis, OpConstructVarargs::argCountIncludingThis));
if (checkpoint == OpCallVarargs::makeCall)
result.set(OpCallVarargs::argCountIncludingThis);
return result;
}
case op_iterator_open: {
return result;
}
case op_iterator_next: {
result.set(OpIteratorNext::nextResult);
return result;
}
default:
break;
}
RELEASE_ASSERT_NOT_REACHED();
}
}