diff --git a/libevmjit/BasicBlock.h b/libevmjit/BasicBlock.h index f0643f342..4a789a8ec 100644 --- a/libevmjit/BasicBlock.h +++ b/libevmjit/BasicBlock.h @@ -67,6 +67,9 @@ public: ProgramCounter begin() { return m_beginInstIdx; } ProgramCounter end() { return m_endInstIdx; } + bool isJumpDest() const { return m_isJumpDest; } + void markAsJumpDest() { m_isJumpDest = true; } + LocalStack& localStack() { return m_stack; } /// Optimization: propagates values between local stacks in basic blocks @@ -109,6 +112,10 @@ private: /// How many items higher is the current stack than the initial one. /// May be negative. int m_tosOffset = 0; + + /// Is the basic block a valid jump destination. + /// JUMPDEST is the first instruction of the basic block. + bool m_isJumpDest = false; }; } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 50d131575..d6e61db5e 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -95,10 +95,27 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc); m_badJumpBlock = std::unique_ptr(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); - m_jumpTableBlock = std::unique_ptr(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - m_jumpDests[*it] = basicBlocks.find(*it)->second.llvm(); + basicBlocks.find(*it)->second.markAsJumpDest(); +} + +BasicBlock& Compiler::getJumpTableBlock() +{ + if (!m_jumpTableBlock) + { + m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder)); + InsertPointGuard g{m_builder}; + m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); + auto dest = m_jumpTableBlock->localStack().pop(); + auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm()); + for (auto&& p : basicBlocks) + { + if (p.second.isJumpDest()) + switchInstr->addCase(Constant::get(p.first), p.second.llvm()); + } + } + return *m_jumpTableBlock; } std::unique_ptr Compiler::compile(bytes const& _bytecode, std::string const& _id) @@ -142,22 +159,7 @@ std::unique_ptr Compiler::compile(bytes const& _bytecode, std::str m_builder.CreateRet(Constant::get(ReturnCode::Stop)); m_builder.SetInsertPoint(m_badJumpBlock->llvm()); - m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); - - m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_jumpDests.size() > 0) - { - auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), m_jumpDests.size()); - for (auto it = m_jumpDests.cbegin(); it != m_jumpDests.cend(); ++it) - { - auto& bb = *it; - auto dest = Constant::get(it->first); - switchInstr->addCase(dest, it->second); - } - } - else - m_builder.CreateBr(m_badJumpBlock->llvm()); + m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); removeDeadBlocks(); @@ -552,15 +554,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode if (c.ult(_bytecode.size())) { auto v = c.getZExtValue(); - auto it = m_jumpDests.find(v); - if (it != m_jumpDests.end()) - targetBlock = it->second; + auto it = basicBlocks.find(v); + if (it != basicBlocks.end() && it->second.isJumpDest()) + targetBlock = it->second.llvm(); } if (!targetBlock) - { targetBlock = m_badJumpBlock->llvm(); - } } if (inst == Instruction::JUMP) @@ -574,7 +574,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode else { stack.push(target); - m_builder.CreateBr(m_jumpTableBlock->llvm()); + m_builder.CreateBr(getJumpTableBlock().llvm()); } } else // JUMPI @@ -594,7 +594,6 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); } } - break; } @@ -830,13 +829,6 @@ void Compiler::removeDeadBlocks() } } while (sthErased); - - // Remove jump table block if no predecessors - if (llvm::pred_begin(m_jumpTableBlock->llvm()) == llvm::pred_end(m_jumpTableBlock->llvm())) - { - m_jumpTableBlock->llvm()->eraseFromParent(); - m_jumpTableBlock.reset(); - } } void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 557be1083..74b795318 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -47,6 +47,8 @@ private: void compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock); + BasicBlock& getJumpTableBlock(); + void removeDeadBlocks(); /// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled. @@ -65,10 +67,7 @@ private: llvm::IRBuilder<> m_builder; /// Maps a program counter pc to a basic block that starts at pc (if any). - std::map basicBlocks = {}; - - /// Map of jump destinations - std::map m_jumpDests = {}; + std::map basicBlocks; /// Stop basic block - terminates execution with STOP code (0) llvm::BasicBlock* m_stopBB = nullptr;