Browse Source

Implemented indirect JUMPI and fixes for JUMPs to invalid PCs

cl-refactor
artur-zawlocki 10 years ago
parent
commit
6e2bcefaca
  1. 107
      evmcc/Compiler.cpp

107
evmcc/Compiler.cpp

@ -137,7 +137,16 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
}
}
for (auto it = splitPoints.cbegin(); it != splitPoints.cend() && *it < bytecode.size();)
// 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;
++it;
@ -151,28 +160,22 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it)
{
if (it->second >= bytecode.size()) // Jump out of code
auto blockIter = basicBlocks.find(it->second);
if (blockIter != basicBlocks.end())
{
m_directJumpTargets[it->first] = m_finalBlock.get();
m_directJumpTargets[it->first] = &(blockIter->second);
}
else if (!validJumpTargets[it->second]) // Jump into data
else
{
std::cerr << "Bad JUMP at PC " << it->first
<< ": " << it->second << " is not a valid PC\n";
m_directJumpTargets[it->first] = m_badJumpBlock.get();
}
else
{
m_directJumpTargets[it->first] = &basicBlocks.find(it->second)->second;
}
}
for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it)
{
if (*it >= bytecode.size())
m_indirectJumpTargets.push_back(m_finalBlock.get());
else
m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second);
m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second);
}
}
@ -196,8 +199,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
createBasicBlocks(bytecode);
// Init runtime structures.
auto memory = Memory(builder, module.get());
auto ext = Ext(builder, module.get());
Memory memory(builder, module.get());
Ext ext(builder, module.get());
GasMeter gasMeter(builder, module.get());
// Jump to first instruction
@ -587,58 +590,56 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
// 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).
BasicBlock* targetBlock = nullptr;
if (currentPC != basicBlock.begin())
{
auto pairIter = m_directJumpTargets.find(currentPC);
if (pairIter != m_directJumpTargets.end())
{
auto targetBlock = pairIter->second;
targetBlock = pairIter->second;
}
}
if (inst == Instruction::JUMP)
{
if (targetBlock)
{
// The target address is computed at compile time,
// just pop it without looking...
stack.pop();
if (inst == Instruction::JUMP)
{
builder.CreateBr(targetBlock->llvm());
}
else // JUMPI
{
auto top = stack.pop();
auto zero = ConstantInt::get(Type::i256, 0);
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
// Assume the basic blocks are properly ordered:
auto nextBBIter = basicBlockPairIt;
++nextBBIter;
assert (nextBBIter != basicBlocks.end());
auto& followBlock = nextBBIter->second;
builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm());
}
break;
builder.CreateBr(targetBlock->llvm());
}
else
{
// FIXME: this get(0) is a temporary workaround to get some of the jump tests running.
stack.get(0);
builder.CreateBr(m_jumpTableBlock->llvm());
}
}
if (inst == Instruction::JUMPI)
else // JUMPI
{
std::cerr << "Indirect JUMPI is not supported yet (at PC "
<< currentPC << ")\n";
std::exit(1);
stack.swap(1);
auto val = stack.pop();
auto zero = ConstantInt::get(Type::i256, 0);
auto cond = builder.CreateICmpNE(val, zero, "nonzero");
// Assume the basic blocks are properly ordered:
auto nextBBIter = basicBlockPairIt;
++nextBBIter;
assert (nextBBIter != basicBlocks.end());
auto& followBlock = nextBBIter->second;
if (targetBlock)
{
stack.pop();
builder.CreateCondBr(cond, targetBlock->llvm(), followBlock.llvm());
}
else
{
builder.CreateCondBr(cond, m_jumpTableBlock->llvm(), followBlock.llvm());
}
}
builder.CreateBr(m_jumpTableBlock->llvm());
/*
// Generate switch for indirect jump.
auto dest = stack.pop();
auto switchInstr = builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
m_indirectJumpTargets.size());
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
{
auto& bb = *it;
auto dest = ConstantInt::get(Type::i256, bb->begin());
switchInstr->addCase(dest, bb->llvm());
}
*/
break;
}
@ -865,7 +866,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
}
else
{
builder.CreateRet(builder.getInt64(0));
builder.CreateBr(m_badJumpBlock->llvm());
}
linkBasicBlocks();

Loading…
Cancel
Save