|
@ -32,28 +32,27 @@ namespace eth |
|
|
namespace jit |
|
|
namespace jit |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
Compiler::Compiler(): |
|
|
Compiler::Compiler(Options const& _options): |
|
|
m_builder(llvm::getGlobalContext()), |
|
|
m_options(_options), |
|
|
m_jumpTableBlock(), |
|
|
m_builder(llvm::getGlobalContext()) |
|
|
m_badJumpBlock() |
|
|
|
|
|
{ |
|
|
{ |
|
|
Type::init(m_builder.getContext()); |
|
|
Type::init(m_builder.getContext()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
void Compiler::createBasicBlocks(bytesConstRef _bytecode) |
|
|
{ |
|
|
{ |
|
|
std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end
|
|
|
std::set<ProgramCounter> splitPoints; // Sorted collections of instruction indices where basic blocks start/end
|
|
|
|
|
|
|
|
|
std::map<ProgramCounter, ProgramCounter> directJumpTargets; |
|
|
std::map<ProgramCounter, ProgramCounter> directJumpTargets; |
|
|
std::vector<ProgramCounter> indirectJumpTargets; |
|
|
std::vector<ProgramCounter> indirectJumpTargets; |
|
|
boost::dynamic_bitset<> validJumpTargets(std::max(bytecode.size(), size_t(1))); |
|
|
boost::dynamic_bitset<> validJumpTargets(std::max(_bytecode.size(), size_t(1))); |
|
|
|
|
|
|
|
|
splitPoints.insert(0); // First basic block
|
|
|
splitPoints.insert(0); // First basic block
|
|
|
validJumpTargets[0] = true; |
|
|
validJumpTargets[0] = true; |
|
|
|
|
|
|
|
|
for (auto curr = bytecode.begin(); curr != bytecode.end(); ++curr) |
|
|
for (auto curr = _bytecode.begin(); curr != _bytecode.end(); ++curr) |
|
|
{ |
|
|
{ |
|
|
ProgramCounter currentPC = curr - bytecode.begin(); |
|
|
ProgramCounter currentPC = curr - _bytecode.begin(); |
|
|
validJumpTargets[currentPC] = true; |
|
|
validJumpTargets[currentPC] = true; |
|
|
|
|
|
|
|
|
auto inst = Instruction(*curr); |
|
|
auto inst = Instruction(*curr); |
|
@ -62,19 +61,19 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
|
|
|
|
|
|
case Instruction::ANY_PUSH: |
|
|
case Instruction::ANY_PUSH: |
|
|
{ |
|
|
{ |
|
|
auto val = readPushData(curr, bytecode.end()); |
|
|
auto val = readPushData(curr, _bytecode.end()); |
|
|
auto next = curr + 1; |
|
|
auto next = curr + 1; |
|
|
if (next == bytecode.end()) |
|
|
if (next == _bytecode.end()) |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
auto nextInst = Instruction(*next); |
|
|
auto nextInst = Instruction(*next); |
|
|
if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) |
|
|
if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI) |
|
|
{ |
|
|
{ |
|
|
// Create a block for the JUMP target.
|
|
|
// Create a block for the JUMP target.
|
|
|
ProgramCounter targetPC = val < bytecode.size() ? val.convert_to<ProgramCounter>() : bytecode.size(); |
|
|
ProgramCounter targetPC = val < _bytecode.size() ? val.convert_to<ProgramCounter>() : _bytecode.size(); |
|
|
splitPoints.insert(targetPC); |
|
|
splitPoints.insert(targetPC); |
|
|
|
|
|
|
|
|
ProgramCounter jumpPC = (next - bytecode.begin()); |
|
|
ProgramCounter jumpPC = (next - _bytecode.begin()); |
|
|
directJumpTargets[jumpPC] = targetPC; |
|
|
directJumpTargets[jumpPC] = targetPC; |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
@ -83,7 +82,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
case Instruction::JUMPDEST: |
|
|
case Instruction::JUMPDEST: |
|
|
{ |
|
|
{ |
|
|
// A basic block starts at the next instruction.
|
|
|
// A basic block starts at the next instruction.
|
|
|
if (currentPC + 1 < bytecode.size()) |
|
|
if (currentPC + 1 < _bytecode.size()) |
|
|
{ |
|
|
{ |
|
|
splitPoints.insert(currentPC + 1); |
|
|
splitPoints.insert(currentPC + 1); |
|
|
indirectJumpTargets.push_back(currentPC + 1); |
|
|
indirectJumpTargets.push_back(currentPC + 1); |
|
@ -98,7 +97,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
case Instruction::SUICIDE: |
|
|
case Instruction::SUICIDE: |
|
|
{ |
|
|
{ |
|
|
// Create a basic block starting at the following instruction.
|
|
|
// Create a basic block starting at the following instruction.
|
|
|
if (curr + 1 < bytecode.end()) |
|
|
if (curr + 1 < _bytecode.end()) |
|
|
{ |
|
|
{ |
|
|
splitPoints.insert(currentPC + 1); |
|
|
splitPoints.insert(currentPC + 1); |
|
|
} |
|
|
} |
|
@ -113,7 +112,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
// Remove split points generated from jumps out of code or into data.
|
|
|
// Remove split points generated from jumps out of code or into data.
|
|
|
for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) |
|
|
for (auto it = splitPoints.cbegin(); it != splitPoints.cend();) |
|
|
{ |
|
|
{ |
|
|
if (*it > bytecode.size() || !validJumpTargets[*it]) |
|
|
if (*it > _bytecode.size() || !validJumpTargets[*it]) |
|
|
it = splitPoints.erase(it); |
|
|
it = splitPoints.erase(it); |
|
|
else |
|
|
else |
|
|
++it; |
|
|
++it; |
|
@ -123,7 +122,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
{ |
|
|
{ |
|
|
auto beginInstIdx = *it; |
|
|
auto beginInstIdx = *it; |
|
|
++it; |
|
|
++it; |
|
|
auto endInstIdx = it != splitPoints.cend() ? *it : bytecode.size(); |
|
|
auto endInstIdx = it != splitPoints.cend() ? *it : _bytecode.size(); |
|
|
basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); |
|
|
basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginInstIdx), std::forward_as_tuple(beginInstIdx, endInstIdx, m_mainFunc, m_builder)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -133,7 +132,7 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
|
|
|
|
|
|
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) |
|
|
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) |
|
|
{ |
|
|
{ |
|
|
if (it->second >= bytecode.size()) |
|
|
if (it->second >= _bytecode.size()) |
|
|
{ |
|
|
{ |
|
|
// Jumping out of code means STOP
|
|
|
// Jumping out of code means STOP
|
|
|
m_directJumpTargets[it->first] = m_stopBB; |
|
|
m_directJumpTargets[it->first] = m_stopBB; |
|
@ -154,12 +153,10 @@ void Compiler::createBasicBlocks(bytesConstRef bytecode) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) |
|
|
for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it) |
|
|
{ |
|
|
|
|
|
m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); |
|
|
m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode) |
|
|
std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef _bytecode) |
|
|
{ |
|
|
{ |
|
|
auto module = std::unique_ptr<llvm::Module>(new llvm::Module("main", m_builder.getContext())); |
|
|
auto module = std::unique_ptr<llvm::Module>(new llvm::Module("main", m_builder.getContext())); |
|
|
|
|
|
|
|
@ -173,7 +170,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode) |
|
|
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); |
|
|
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), "entry", m_mainFunc); |
|
|
m_builder.SetInsertPoint(entryBlock); |
|
|
m_builder.SetInsertPoint(entryBlock); |
|
|
|
|
|
|
|
|
createBasicBlocks(bytecode); |
|
|
createBasicBlocks(_bytecode); |
|
|
|
|
|
|
|
|
// Init runtime structures.
|
|
|
// Init runtime structures.
|
|
|
RuntimeManager runtimeManager(m_builder); |
|
|
RuntimeManager runtimeManager(m_builder); |
|
@ -191,13 +188,11 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode) |
|
|
auto iterCopy = basicBlockPairIt; |
|
|
auto iterCopy = basicBlockPairIt; |
|
|
++iterCopy; |
|
|
++iterCopy; |
|
|
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; |
|
|
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; |
|
|
compileBasicBlock(basicBlock, bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); |
|
|
compileBasicBlock(basicBlock, _bytecode, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Code for special blocks:
|
|
|
// Code for special blocks:
|
|
|
// TODO: move to separate function.
|
|
|
// TODO: move to separate function.
|
|
|
// Note: Right now the codegen for special blocks depends only on createBasicBlock(),
|
|
|
|
|
|
// not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks().
|
|
|
|
|
|
m_builder.SetInsertPoint(m_stopBB); |
|
|
m_builder.SetInsertPoint(m_stopBB); |
|
|
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); |
|
|
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); |
|
|
|
|
|
|
|
@ -218,75 +213,59 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
|
|
|
m_builder.CreateBr(m_badJumpBlock->llvm()); |
|
|
m_builder.CreateBr(m_badJumpBlock->llvm()); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
removeDeadBlocks(); |
|
|
removeDeadBlocks(); |
|
|
|
|
|
|
|
|
if (getenv("EVMCC_DEBUG_BLOCKS")) |
|
|
dumpCFGifRequired("blocks-init.dot"); |
|
|
{ |
|
|
|
|
|
std::ofstream ofs("blocks-init.dot"); |
|
|
|
|
|
dumpBasicBlockGraph(ofs); |
|
|
|
|
|
ofs.close(); |
|
|
|
|
|
std::cerr << "\n\nAfter dead block elimination \n\n"; |
|
|
|
|
|
dump(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//if (getenv("EVMCC_OPTIMIZE_STACK"))
|
|
|
if (m_options.optimizeStack) |
|
|
//{
|
|
|
{ |
|
|
std::vector<BasicBlock*> blockList; |
|
|
std::vector<BasicBlock*> blockList; |
|
|
for (auto& entry : basicBlocks) |
|
|
for (auto& entry : basicBlocks) |
|
|
blockList.push_back(&entry.second); |
|
|
blockList.push_back(&entry.second); |
|
|
|
|
|
|
|
|
if (m_jumpTableBlock != nullptr) |
|
|
if (m_jumpTableBlock) |
|
|
blockList.push_back(m_jumpTableBlock.get()); |
|
|
blockList.push_back(m_jumpTableBlock.get()); |
|
|
|
|
|
|
|
|
BasicBlock::linkLocalStacks(blockList, m_builder); |
|
|
BasicBlock::linkLocalStacks(blockList, m_builder); |
|
|
|
|
|
|
|
|
if (getenv("EVMCC_DEBUG_BLOCKS")) |
|
|
dumpCFGifRequired("blocks-opt.dot"); |
|
|
{ |
|
|
|
|
|
std::ofstream ofs("blocks-opt.dot"); |
|
|
|
|
|
dumpBasicBlockGraph(ofs); |
|
|
|
|
|
ofs.close(); |
|
|
|
|
|
std::cerr << "\n\nAfter stack optimization \n\n"; |
|
|
|
|
|
dump(); |
|
|
|
|
|
} |
|
|
} |
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& entry : basicBlocks) |
|
|
for (auto& entry : basicBlocks) |
|
|
entry.second.localStack().synchronize(stack); |
|
|
entry.second.localStack().synchronize(stack); |
|
|
if (m_jumpTableBlock != nullptr) |
|
|
if (m_jumpTableBlock) |
|
|
m_jumpTableBlock->localStack().synchronize(stack); |
|
|
m_jumpTableBlock->localStack().synchronize(stack); |
|
|
|
|
|
|
|
|
if (getenv("EVMCC_DEBUG_BLOCKS")) |
|
|
dumpCFGifRequired("blocks-sync.dot"); |
|
|
{ |
|
|
|
|
|
std::ofstream ofs("blocks-sync.dot"); |
|
|
|
|
|
dumpBasicBlockGraph(ofs); |
|
|
|
|
|
ofs.close(); |
|
|
|
|
|
std::cerr << "\n\nAfter stack synchronization \n\n"; |
|
|
|
|
|
dump(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_jumpTableBlock && m_options.rewriteSwitchToBranches) |
|
|
|
|
|
{ |
|
|
llvm::FunctionPassManager fpManager(module.get()); |
|
|
llvm::FunctionPassManager fpManager(module.get()); |
|
|
fpManager.add(llvm::createLowerSwitchPass()); |
|
|
fpManager.add(llvm::createLowerSwitchPass()); |
|
|
fpManager.doInitialization(); |
|
|
fpManager.doInitialization(); |
|
|
fpManager.run(*m_mainFunc); |
|
|
fpManager.run(*m_mainFunc); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return module; |
|
|
return module; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, RuntimeManager& _runtimeManager, Arith256& arith, Memory& memory, Ext& ext, GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock) |
|
|
void Compiler::compileBasicBlock(BasicBlock& _basicBlock, bytesConstRef _bytecode, RuntimeManager& _runtimeManager, |
|
|
|
|
|
Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock) |
|
|
{ |
|
|
{ |
|
|
m_builder.SetInsertPoint(basicBlock.llvm()); |
|
|
if (!_nextBasicBlock) // this is the last block in the code
|
|
|
auto& stack = basicBlock.localStack(); |
|
|
_nextBasicBlock = m_stopBB; |
|
|
|
|
|
|
|
|
|
|
|
m_builder.SetInsertPoint(_basicBlock.llvm()); |
|
|
|
|
|
auto& stack = _basicBlock.localStack(); |
|
|
|
|
|
|
|
|
for (auto currentPC = basicBlock.begin(); currentPC != basicBlock.end(); ++currentPC) |
|
|
for (auto currentPC = _basicBlock.begin(); currentPC != _basicBlock.end(); ++currentPC) |
|
|
{ |
|
|
{ |
|
|
auto inst = static_cast<Instruction>(bytecode[currentPC]); |
|
|
auto inst = static_cast<Instruction>(_bytecode[currentPC]); |
|
|
|
|
|
|
|
|
gasMeter.count(inst); |
|
|
_gasMeter.count(inst); |
|
|
|
|
|
|
|
|
switch (inst) |
|
|
switch (inst) |
|
|
{ |
|
|
{ |
|
@ -313,7 +292,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto lhs = stack.pop(); |
|
|
auto lhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto res = arith.mul(lhs, rhs); |
|
|
auto res = _arith.mul(lhs, rhs); |
|
|
stack.push(res); |
|
|
stack.push(res); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -322,7 +301,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto lhs = stack.pop(); |
|
|
auto lhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto res = arith.div(lhs, rhs); |
|
|
auto res = _arith.div(lhs, rhs); |
|
|
stack.push(res); |
|
|
stack.push(res); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -331,7 +310,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto lhs = stack.pop(); |
|
|
auto lhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto res = arith.sdiv(lhs, rhs); |
|
|
auto res = _arith.sdiv(lhs, rhs); |
|
|
stack.push(res); |
|
|
stack.push(res); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -340,7 +319,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto lhs = stack.pop(); |
|
|
auto lhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto res = arith.mod(lhs, rhs); |
|
|
auto res = _arith.mod(lhs, rhs); |
|
|
stack.push(res); |
|
|
stack.push(res); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -349,7 +328,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto lhs = stack.pop(); |
|
|
auto lhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto res = arith.smod(lhs, rhs); |
|
|
auto res = _arith.smod(lhs, rhs); |
|
|
stack.push(res); |
|
|
stack.push(res); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -358,7 +337,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto left = stack.pop(); |
|
|
auto left = stack.pop(); |
|
|
auto right = stack.pop(); |
|
|
auto right = stack.pop(); |
|
|
auto ret = ext.exp(left, right); |
|
|
auto ret = _ext.exp(left, right); |
|
|
stack.push(ret); |
|
|
stack.push(ret); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -478,7 +457,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto lhs = stack.pop(); |
|
|
auto lhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto mod = stack.pop(); |
|
|
auto mod = stack.pop(); |
|
|
auto res = arith.addmod(lhs, rhs, mod); |
|
|
auto res = _arith.addmod(lhs, rhs, mod); |
|
|
stack.push(res); |
|
|
stack.push(res); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -488,7 +467,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto lhs = stack.pop(); |
|
|
auto lhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto rhs = stack.pop(); |
|
|
auto mod = stack.pop(); |
|
|
auto mod = stack.pop(); |
|
|
auto res = arith.mulmod(lhs, rhs, mod); |
|
|
auto res = _arith.mulmod(lhs, rhs, mod); |
|
|
stack.push(res); |
|
|
stack.push(res); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -526,8 +505,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto inOff = stack.pop(); |
|
|
auto inOff = stack.pop(); |
|
|
auto inSize = stack.pop(); |
|
|
auto inSize = stack.pop(); |
|
|
memory.require(inOff, inSize); |
|
|
_memory.require(inOff, inSize); |
|
|
auto hash = ext.sha3(inOff, inSize); |
|
|
auto hash = _ext.sha3(inOff, inSize); |
|
|
stack.push(hash); |
|
|
stack.push(hash); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -540,9 +519,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
|
|
|
|
|
|
case Instruction::ANY_PUSH: |
|
|
case Instruction::ANY_PUSH: |
|
|
{ |
|
|
{ |
|
|
auto curr = bytecode.begin() + currentPC; // TODO: replace currentPC with iterator
|
|
|
auto curr = _bytecode.begin() + currentPC; // TODO: replace currentPC with iterator
|
|
|
auto value = readPushData(curr, bytecode.end()); |
|
|
auto value = readPushData(curr, _bytecode.end()); |
|
|
currentPC = curr - bytecode.begin(); |
|
|
currentPC = curr - _bytecode.begin(); |
|
|
|
|
|
|
|
|
stack.push(Constant::get(value)); |
|
|
stack.push(Constant::get(value)); |
|
|
break; |
|
|
break; |
|
@ -565,7 +544,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
case Instruction::MLOAD: |
|
|
case Instruction::MLOAD: |
|
|
{ |
|
|
{ |
|
|
auto addr = stack.pop(); |
|
|
auto addr = stack.pop(); |
|
|
auto word = memory.loadWord(addr); |
|
|
auto word = _memory.loadWord(addr); |
|
|
stack.push(word); |
|
|
stack.push(word); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -574,7 +553,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto addr = stack.pop(); |
|
|
auto addr = stack.pop(); |
|
|
auto word = stack.pop(); |
|
|
auto word = stack.pop(); |
|
|
memory.storeWord(addr, word); |
|
|
_memory.storeWord(addr, word); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -582,13 +561,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto addr = stack.pop(); |
|
|
auto addr = stack.pop(); |
|
|
auto word = stack.pop(); |
|
|
auto word = stack.pop(); |
|
|
memory.storeByte(addr, word); |
|
|
_memory.storeByte(addr, word); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
case Instruction::MSIZE: |
|
|
case Instruction::MSIZE: |
|
|
{ |
|
|
{ |
|
|
auto word = memory.getSize(); |
|
|
auto word = _memory.getSize(); |
|
|
stack.push(word); |
|
|
stack.push(word); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -596,7 +575,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
case Instruction::SLOAD: |
|
|
case Instruction::SLOAD: |
|
|
{ |
|
|
{ |
|
|
auto index = stack.pop(); |
|
|
auto index = stack.pop(); |
|
|
auto value = ext.store(index); |
|
|
auto value = _ext.store(index); |
|
|
stack.push(value); |
|
|
stack.push(value); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -605,8 +584,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
{ |
|
|
{ |
|
|
auto index = stack.pop(); |
|
|
auto index = stack.pop(); |
|
|
auto value = stack.pop(); |
|
|
auto value = stack.pop(); |
|
|
gasMeter.countSStore(ext, index, value); |
|
|
_gasMeter.countSStore(_ext, index, value); |
|
|
ext.setStore(index, value); |
|
|
_ext.setStore(index, value); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -618,7 +597,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
// 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH)
|
|
|
// 2. m_directJumpTargets[currentPC] is defined (meaning that the previous instruction is a PUSH)
|
|
|
// Otherwise generate a indirect jump (a switch).
|
|
|
// Otherwise generate a indirect jump (a switch).
|
|
|
llvm::BasicBlock* targetBlock = nullptr; |
|
|
llvm::BasicBlock* targetBlock = nullptr; |
|
|
if (currentPC != basicBlock.begin()) |
|
|
if (currentPC != _basicBlock.begin()) |
|
|
{ |
|
|
{ |
|
|
auto pairIter = m_directJumpTargets.find(currentPC); |
|
|
auto pairIter = m_directJumpTargets.find(currentPC); |
|
|
if (pairIter != m_directJumpTargets.end()) |
|
|
if (pairIter != m_directJumpTargets.end()) |
|
@ -644,17 +623,13 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto zero = Constant::get(0); |
|
|
auto zero = Constant::get(0); |
|
|
auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); |
|
|
auto cond = m_builder.CreateICmpNE(val, zero, "nonzero"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!nextBasicBlock) // In case JUMPI is the last instruction
|
|
|
|
|
|
nextBasicBlock = m_stopBB; |
|
|
|
|
|
|
|
|
|
|
|
if (targetBlock) |
|
|
if (targetBlock) |
|
|
{ |
|
|
{ |
|
|
stack.pop(); |
|
|
stack.pop(); |
|
|
m_builder.CreateCondBr(cond, targetBlock, nextBasicBlock); |
|
|
m_builder.CreateCondBr(cond, targetBlock, _nextBasicBlock); |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), nextBasicBlock); |
|
|
m_builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), _nextBasicBlock); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
break; |
|
|
break; |
|
@ -696,7 +671,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
case Instruction::BALANCE: |
|
|
case Instruction::BALANCE: |
|
|
{ |
|
|
{ |
|
|
auto address = stack.pop(); |
|
|
auto address = stack.pop(); |
|
|
auto value = ext.balance(address); |
|
|
auto value = _ext.balance(address); |
|
|
stack.push(value); |
|
|
stack.push(value); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -704,7 +679,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
case Instruction::EXTCODESIZE: |
|
|
case Instruction::EXTCODESIZE: |
|
|
{ |
|
|
{ |
|
|
auto addr = stack.pop(); |
|
|
auto addr = stack.pop(); |
|
|
auto value = ext.codesizeAt(addr); |
|
|
auto value = _ext.codesizeAt(addr); |
|
|
stack.push(value); |
|
|
stack.push(value); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -718,7 +693,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto srcPtr = _runtimeManager.getCallData(); |
|
|
auto srcPtr = _runtimeManager.getCallData(); |
|
|
auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); |
|
|
auto srcSize = _runtimeManager.get(RuntimeData::CallDataSize); |
|
|
|
|
|
|
|
|
memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); |
|
|
_memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -731,7 +706,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234
|
|
|
auto srcPtr = _runtimeManager.getCode(); // TODO: Code & its size are constants, feature #80814234
|
|
|
auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); |
|
|
auto srcSize = _runtimeManager.get(RuntimeData::CodeSize); |
|
|
|
|
|
|
|
|
memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); |
|
|
_memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -742,17 +717,17 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto srcIdx = stack.pop(); |
|
|
auto srcIdx = stack.pop(); |
|
|
auto reqBytes = stack.pop(); |
|
|
auto reqBytes = stack.pop(); |
|
|
|
|
|
|
|
|
auto srcPtr = ext.codeAt(extAddr); |
|
|
auto srcPtr = _ext.codeAt(extAddr); |
|
|
auto srcSize = ext.codesizeAt(extAddr); |
|
|
auto srcSize = _ext.codesizeAt(extAddr); |
|
|
|
|
|
|
|
|
memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); |
|
|
_memory.copyBytes(srcPtr, srcSize, srcIdx, destMemIdx, reqBytes); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
case Instruction::CALLDATALOAD: |
|
|
case Instruction::CALLDATALOAD: |
|
|
{ |
|
|
{ |
|
|
auto index = stack.pop(); |
|
|
auto index = stack.pop(); |
|
|
auto value = ext.calldataload(index); |
|
|
auto value = _ext.calldataload(index); |
|
|
stack.push(value); |
|
|
stack.push(value); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -762,9 +737,9 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto endowment = stack.pop(); |
|
|
auto endowment = stack.pop(); |
|
|
auto initOff = stack.pop(); |
|
|
auto initOff = stack.pop(); |
|
|
auto initSize = stack.pop(); |
|
|
auto initSize = stack.pop(); |
|
|
memory.require(initOff, initSize); |
|
|
_memory.require(initOff, initSize); |
|
|
|
|
|
|
|
|
auto address = ext.create(endowment, initOff, initSize); |
|
|
auto address = _ext.create(endowment, initOff, initSize); |
|
|
stack.push(address); |
|
|
stack.push(address); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -780,7 +755,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto outOff = stack.pop(); |
|
|
auto outOff = stack.pop(); |
|
|
auto outSize = stack.pop(); |
|
|
auto outSize = stack.pop(); |
|
|
|
|
|
|
|
|
gasMeter.commitCostBlock(gas); |
|
|
_gasMeter.commitCostBlock(gas); |
|
|
|
|
|
|
|
|
// Require memory for in and out buffers
|
|
|
// Require memory for in and out buffers
|
|
|
memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one
|
|
|
memory.require(outOff, outSize); // Out buffer first as we guess it will be after the in one
|
|
@ -790,8 +765,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
if (inst == Instruction::CALLCODE) |
|
|
if (inst == Instruction::CALLCODE) |
|
|
receiveAddress = _runtimeManager.get(RuntimeData::Address); |
|
|
receiveAddress = _runtimeManager.get(RuntimeData::Address); |
|
|
|
|
|
|
|
|
auto ret = ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); |
|
|
auto ret = _ext.call(gas, receiveAddress, value, inOff, inSize, outOff, outSize, codeAddress); |
|
|
gasMeter.giveBack(gas); |
|
|
_gasMeter.giveBack(gas); |
|
|
stack.push(ret); |
|
|
stack.push(ret); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -801,7 +776,7 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
auto index = stack.pop(); |
|
|
auto index = stack.pop(); |
|
|
auto size = stack.pop(); |
|
|
auto size = stack.pop(); |
|
|
|
|
|
|
|
|
memory.require(index, size); |
|
|
_memory.require(index, size); |
|
|
_runtimeManager.registerReturnData(index, size); |
|
|
_runtimeManager.registerReturnData(index, size); |
|
|
|
|
|
|
|
|
m_builder.CreateRet(Constant::get(ReturnCode::Return)); |
|
|
m_builder.CreateRet(Constant::get(ReturnCode::Return)); |
|
@ -809,13 +784,14 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
case Instruction::SUICIDE: |
|
|
case Instruction::SUICIDE: |
|
|
|
|
|
case Instruction::STOP: |
|
|
|
|
|
{ |
|
|
|
|
|
if (inst == Instruction::SUICIDE) |
|
|
{ |
|
|
{ |
|
|
auto address = stack.pop(); |
|
|
auto address = stack.pop(); |
|
|
ext.suicide(address); |
|
|
_ext.suicide(address); |
|
|
// Fall through
|
|
|
|
|
|
} |
|
|
} |
|
|
case Instruction::STOP: |
|
|
|
|
|
{ |
|
|
|
|
|
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); |
|
|
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
@ -828,15 +804,11 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
gasMeter.commitCostBlock(); |
|
|
_gasMeter.commitCostBlock(); |
|
|
|
|
|
|
|
|
if (!basicBlock.llvm()->getTerminator()) // If block not terminated
|
|
|
// Block may have no terminator if the next instruction is a jump destination.
|
|
|
{ |
|
|
if (!_basicBlock.llvm()->getTerminator()) |
|
|
if (nextBasicBlock) |
|
|
m_builder.CreateBr(_nextBasicBlock); |
|
|
m_builder.CreateBr(nextBasicBlock); // Branch to the next block
|
|
|
|
|
|
else |
|
|
|
|
|
m_builder.CreateRet(Constant::get(ReturnCode::Stop)); // Return STOP code
|
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -871,9 +843,20 @@ void Compiler::removeDeadBlocks() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Compiler::dumpBasicBlockGraph(std::ostream& out) |
|
|
void Compiler::dumpCFGifRequired(std::string const& _dotfilePath) |
|
|
|
|
|
{ |
|
|
|
|
|
if (! m_options.dumpCFG) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
// TODO: handle i/o failures
|
|
|
|
|
|
std::ofstream ofs(_dotfilePath); |
|
|
|
|
|
dumpCFGtoStream(ofs); |
|
|
|
|
|
ofs.close(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Compiler::dumpCFGtoStream(std::ostream& _out) |
|
|
{ |
|
|
{ |
|
|
out << "digraph BB {\n" |
|
|
_out << "digraph BB {\n" |
|
|
<< " node [shape=record, fontname=Courier, fontsize=10];\n" |
|
|
<< " node [shape=record, fontname=Courier, fontsize=10];\n" |
|
|
<< " entry [share=record, label=\"entry block\"];\n"; |
|
|
<< " entry [share=record, label=\"entry block\"];\n"; |
|
|
|
|
|
|
|
@ -895,7 +878,7 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) |
|
|
std::ostringstream oss; |
|
|
std::ostringstream oss; |
|
|
bb->dump(oss, true); |
|
|
bb->dump(oss, true); |
|
|
|
|
|
|
|
|
out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; |
|
|
_out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Output edges
|
|
|
// Output edges
|
|
@ -906,15 +889,13 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out) |
|
|
auto end = llvm::pred_end(bb->llvm()); |
|
|
auto end = llvm::pred_end(bb->llvm()); |
|
|
for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) |
|
|
for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it) |
|
|
{ |
|
|
{ |
|
|
out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" |
|
|
_out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" [" |
|
|
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") |
|
|
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "") |
|
|
//<< "label = \""
|
|
|
|
|
|
//<< phiNodesPerBlock[bb]
|
|
|
|
|
|
<< "];\n"; |
|
|
<< "];\n"; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
out << "}\n"; |
|
|
_out << "}\n"; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Compiler::dump() |
|
|
void Compiler::dump() |
|
|