BytecodeBasicBlock.cpp [plain text]
#include "config.h"
#include "BytecodeBasicBlock.h"
#include "CodeBlock.h"
#include "JSCInlines.h"
#include "PreciseJumpTargets.h"
namespace JSC {
static bool isBranch(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_jmp:
case op_jtrue:
case op_jfalse:
case op_jeq_null:
case op_jneq_null:
case op_jneq_ptr:
case op_jless:
case op_jlesseq:
case op_jgreater:
case op_jgreatereq:
case op_jnless:
case op_jnlesseq:
case op_jngreater:
case op_jngreatereq:
case op_switch_imm:
case op_switch_char:
case op_switch_string:
case op_check_has_instance:
return true;
default:
return false;
}
}
static bool isUnconditionalBranch(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_jmp:
return true;
default:
return false;
}
}
static bool isTerminal(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_ret:
case op_end:
return true;
default:
return false;
}
}
static bool isThrow(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_throw:
case op_throw_static_error:
return true;
default:
return false;
}
}
static bool isJumpTarget(OpcodeID opcodeID, Vector<unsigned, 32>& jumpTargets, unsigned bytecodeOffset)
{
if (opcodeID == op_catch)
return true;
for (unsigned i = 0; i < jumpTargets.size(); i++) {
if (bytecodeOffset == jumpTargets[i])
return true;
}
return false;
}
static void linkBlocks(BytecodeBasicBlock* predecessor, BytecodeBasicBlock* successor)
{
predecessor->addSuccessor(successor);
successor->addPredecessor(predecessor);
}
void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasicBlock> >& basicBlocks)
{
Vector<unsigned, 32> jumpTargets;
computePreciseJumpTargets(codeBlock, jumpTargets);
BytecodeBasicBlock* entry = new BytecodeBasicBlock(BytecodeBasicBlock::EntryBlock);
basicBlocks.append(adoptRef(entry));
BytecodeBasicBlock* exit = new BytecodeBasicBlock(BytecodeBasicBlock::ExitBlock);
BytecodeBasicBlock* current = new BytecodeBasicBlock(0, 0);
linkBlocks(entry, current);
basicBlocks.append(adoptRef(current));
bool nextInstructionIsLeader = false;
Interpreter* interpreter = codeBlock->vm()->interpreter;
Instruction* instructionsBegin = codeBlock->instructions().begin();
unsigned instructionCount = codeBlock->instructions().size();
for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount;) {
OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode);
unsigned opcodeLength = opcodeLengths[opcodeID];
bool createdBlock = false;
if (isJumpTarget(opcodeID, jumpTargets, bytecodeOffset) || nextInstructionIsLeader) {
BytecodeBasicBlock* block = new BytecodeBasicBlock(bytecodeOffset, opcodeLength);
basicBlocks.append(adoptRef(block));
current = block;
createdBlock = true;
nextInstructionIsLeader = false;
bytecodeOffset += opcodeLength;
}
if (isBranch(opcodeID) || isTerminal(opcodeID) || isThrow(opcodeID))
nextInstructionIsLeader = true;
if (createdBlock)
continue;
current->addBytecodeLength(opcodeLength);
bytecodeOffset += opcodeLength;
}
for (unsigned i = 0; i < basicBlocks.size(); i++) {
BytecodeBasicBlock* block = basicBlocks[i].get();
if (block->isEntryBlock() || block->isExitBlock())
continue;
bool fallsThrough = true;
for (unsigned bytecodeOffset = block->leaderBytecodeOffset(); bytecodeOffset < block->leaderBytecodeOffset() + block->totalBytecodeLength();) {
const Instruction& currentInstruction = instructionsBegin[bytecodeOffset];
OpcodeID opcodeID = interpreter->getOpcodeID(currentInstruction.u.opcode);
unsigned opcodeLength = opcodeLengths[opcodeID];
if (isTerminal(opcodeID)) {
ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength());
linkBlocks(block, exit);
fallsThrough = false;
break;
}
if (isThrow(opcodeID)) {
ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength());
HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
fallsThrough = false;
if (!handler) {
linkBlocks(block, exit);
break;
}
for (unsigned i = 0; i < basicBlocks.size(); i++) {
BytecodeBasicBlock* otherBlock = basicBlocks[i].get();
if (handler->target == otherBlock->leaderBytecodeOffset()) {
linkBlocks(block, otherBlock);
break;
}
}
break;
}
if (isBranch(opcodeID)) {
ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength());
Vector<unsigned, 1> bytecodeOffsetsJumpedTo;
findJumpTargetsForBytecodeOffset(codeBlock, bytecodeOffset, bytecodeOffsetsJumpedTo);
for (unsigned i = 0; i < basicBlocks.size(); i++) {
BytecodeBasicBlock* otherBlock = basicBlocks[i].get();
if (bytecodeOffsetsJumpedTo.contains(otherBlock->leaderBytecodeOffset()))
linkBlocks(block, otherBlock);
}
if (isUnconditionalBranch(opcodeID))
fallsThrough = false;
break;
}
bytecodeOffset += opcodeLength;
}
if (fallsThrough) {
ASSERT(i + 1 < basicBlocks.size());
BytecodeBasicBlock* nextBlock = basicBlocks[i + 1].get();
linkBlocks(block, nextBlock);
}
}
basicBlocks.append(adoptRef(exit));
}
}