JUMPI fix: an additional item was left on stack when condition is false

This commit is contained in:
Paweł Bylica 2015-01-16 18:02:36 +01:00
parent 0f53e2153a
commit 5152596cbd
2 changed files with 29 additions and 3 deletions

View file

@ -66,6 +66,9 @@ public:
bool isJumpDest() const { return m_isJumpDest; } bool isJumpDest() const { return m_isJumpDest; }
llvm::Value* getJumpTarget() const { return m_jumpTarget; }
void setJumpTarget(llvm::Value* _jumpTarget) { m_jumpTarget = _jumpTarget; }
LocalStack& localStack() { return m_stack; } LocalStack& localStack() { return m_stack; }
/// Optimization: propagates values between local stacks in basic blocks /// Optimization: propagates values between local stacks in basic blocks
@ -112,6 +115,9 @@ private:
/// Is the basic block a valid jump destination. /// Is the basic block a valid jump destination.
/// JUMPDEST is the first instruction of the basic block. /// JUMPDEST is the first instruction of the basic block.
bool const m_isJumpDest = false; bool const m_isJumpDest = false;
/// If block finishes with dynamic jump target index is stored here
llvm::Value* m_jumpTarget = nullptr;
}; };
} }

View file

@ -100,7 +100,7 @@ llvm::BasicBlock* Compiler::getJumpTableBlock()
m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true)); m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true));
InsertPointGuard g{m_builder}; InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
auto dest = m_jumpTableBlock->localStack().pop(); auto dest = m_builder.CreatePHI(Type::Word, 8, "target");
auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock()); auto switchInstr = m_builder.CreateSwitch(dest, getBadJumpBlock());
for (auto&& p : m_basicBlocks) for (auto&& p : m_basicBlocks)
{ {
@ -165,6 +165,26 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str
removeDeadBlocks(); removeDeadBlocks();
// Link jump table target index
if (m_jumpTableBlock)
{
auto phi = llvm::cast<llvm::PHINode>(&m_jumpTableBlock->llvm()->getInstList().front());
for (auto predIt = llvm::pred_begin(m_jumpTableBlock->llvm()); predIt != llvm::pred_end(m_jumpTableBlock->llvm()); ++predIt)
{
BasicBlock* pred = nullptr;
for (auto&& p : m_basicBlocks)
{
if (p.second.llvm() == *predIt)
{
pred = &p.second;
break;
}
}
phi->addIncoming(pred->getJumpTarget(), pred->llvm());
}
}
dumpCFGifRequired("blocks-init.dot"); dumpCFGifRequired("blocks-init.dot");
if (m_options.optimizeStack) if (m_options.optimizeStack)
@ -565,7 +585,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
} }
else else
{ {
stack.push(target); _basicBlock.setJumpTarget(target);
m_builder.CreateBr(getJumpTableBlock()); m_builder.CreateBr(getJumpTableBlock());
} }
} }
@ -581,7 +601,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode
} }
else else
{ {
stack.push(target); _basicBlock.setJumpTarget(target);
m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock); m_builder.CreateCondBr(cond, getJumpTableBlock(), _nextBasicBlock);
} }
} }