diff --git a/libevmjit/Common.h b/libevmjit/Common.h index d98cc0acb..436931dcd 100644 --- a/libevmjit/Common.h +++ b/libevmjit/Common.h @@ -44,6 +44,8 @@ struct i256 }; static_assert(sizeof(i256) == 32, "Wrong i265 size"); +#define UNTESTED assert(false) + } } } diff --git a/libevmjit/Compiler.cpp b/libevmjit/Compiler.cpp index 48dc50d60..50d131575 100644 --- a/libevmjit/Compiler.cpp +++ b/libevmjit/Compiler.cpp @@ -5,8 +5,6 @@ #include <fstream> #include <chrono> -#include <boost/dynamic_bitset.hpp> - #include <llvm/ADT/PostOrderIterator.h> #include <llvm/IR/CFG.h> #include <llvm/IR/Module.h> @@ -44,17 +42,13 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) { std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end - std::map<ProgramCounter, ProgramCounter> directJumpTargets; std::vector<ProgramCounter> indirectJumpTargets; - boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); splitPoints.insert(0); // First basic block - validJumpTargets[0] = true; for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) { ProgramCounter currentPC = curr - _bytecode.begin(); - validJumpTargets[currentPC] = true; auto inst = Instruction(*curr); switch (inst) @@ -62,21 +56,7 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) case Instruction::ANY_PUSH: { - auto val = readPushData(curr, _bytecode.end()); - auto next = curr + 1; - if (next == _bytecode.end()) - break; - - auto nextInst = Instruction(*next); - if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) - { - // Create a block for the JUMP target. - ProgramCounter targetPC = val.ult(_bytecode.size()) ? val.getZExtValue() : _bytecode.size(); - splitPoints.insert(targetPC); - - ProgramCounter jumpPC = (next - _bytecode.begin()); - directJumpTargets[jumpPC] = targetPC; - } + readPushData(curr, _bytecode.end()); break; } @@ -105,15 +85,6 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) } } - // Remove split points generated from jumps out of code or into data. - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) - { - if (*it > _bytecode.size() || !validJumpTargets[*it]) - it = splitPoints.erase(it); - else - ++it; - } - for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) { auto beginInstIdx = *it; @@ -126,30 +97,8 @@ void Compiler::createBasicBlocks(bytes const& _bytecode) m_badJumpBlock = std::unique_ptr<BasicBlock>(new BasicBlock("BadJumpBlock", m_mainFunc, m_builder)); m_jumpTableBlock = std::unique_ptr<BasicBlock>(new BasicBlock("JumpTableBlock", m_mainFunc, m_builder)); - for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) - { - if (it->second >= _bytecode.size()) - { - // Jumping out of code means STOP - m_directJumpTargets[it->first] = m_stopBB; - continue; - } - - auto blockIter = basicBlocks.find(it->second); - if (blockIter != basicBlocks.end()) - { - m_directJumpTargets[it->first] = blockIter->second.llvm(); - } - else - { - clog(JIT) << "Bad JUMP at PC " << it->first - << ": " << it->second << " is not a valid PC"; - m_directJumpTargets[it->first] = m_badJumpBlock->llvm(); - } - } - for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) - m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); + m_jumpDests[*it] = basicBlocks.find(*it)->second.llvm(); } std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::string const& _id) @@ -196,16 +145,15 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytes const& _bytecode, std::str m_builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination)); m_builder.SetInsertPoint(m_jumpTableBlock->llvm()); - if (m_indirectJumpTargets.size() > 0) + if (m_jumpDests.size() > 0) { auto dest = m_jumpTableBlock->localStack().pop(); - auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(), - m_indirectJumpTargets.size()); - for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it) + 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(bb->begin()); - switchInstr->addCase(dest, bb->llvm()); + auto dest = Constant::get(it->first); + switchInstr->addCase(dest, it->second); } } else @@ -596,16 +544,23 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode case Instruction::JUMP: case Instruction::JUMPI: { - // Generate direct jump iff: - // 1. this is not the first instruction in the block - // 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH) - // Otherwise generate a indirect jump (a switch). llvm::BasicBlock* targetBlock = nullptr; - if (currentPC != _basicBlock.begin()) + auto target = stack.pop(); + if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(target)) { - auto pairIter = m_directJumpTargets.find(currentPC); - if (pairIter != m_directJumpTargets.end()) - targetBlock = pairIter->second; + auto&& c = constant->getValue(); + if (c.ult(_bytecode.size())) + { + auto v = c.getZExtValue(); + auto it = m_jumpDests.find(v); + if (it != m_jumpDests.end()) + targetBlock = it->second; + } + + if (!targetBlock) + { + targetBlock = m_badJumpBlock->llvm(); + } } if (inst == Instruction::JUMP) @@ -614,26 +569,30 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytes const& _bytecode { // The target address is computed at compile time, // just pop it without looking... - stack.pop(); m_builder.CreateBr(targetBlock); } else + { + stack.push(target); m_builder.CreateBr(m_jumpTableBlock->llvm()); + } } else // JUMPI { - stack.swap(1); auto val = stack.pop(); auto zero = Constant::get(0); auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); if (targetBlock) { - stack.pop(); m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); } else + { + UNTESTED; + stack.push(target); m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); + } } break; diff --git a/libevmjit/Compiler.h b/libevmjit/Compiler.h index 8e3bf357c..557be1083 100644 --- a/libevmjit/Compiler.h +++ b/libevmjit/Compiler.h @@ -67,11 +67,8 @@ private: /// Maps a program counter pc to a basic block that starts at pc (if any). std::map<ProgramCounter, BasicBlock> basicBlocks = {}; - /// Maps a pc at which there is a JUMP or JUMPI to the target block of the jump. - std::map<ProgramCounter, llvm::BasicBlock*> m_directJumpTargets = {}; - - /// A list of possible blocks to which there may be indirect jumps. - std::vector<BasicBlock*> m_indirectJumpTargets = {}; + /// Map of jump destinations + std::map<ProgramCounter, llvm::BasicBlock*> m_jumpDests = {}; /// Stop basic block - terminates execution with STOP code (0) llvm::BasicBlock* m_stopBB = nullptr;