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; auto beginInstIdx = *it;
++it; ++it;
@ -151,28 +160,22 @@ void Compiler::createBasicBlocks(const dev::bytes& bytecode)
for (auto it = directJumpTargets.cbegin(); it != directJumpTargets.cend(); ++it) 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 std::cerr << "Bad JUMP at PC " << it->first
<< ": " << it->second << " is not a valid PC\n"; << ": " << it->second << " is not a valid PC\n";
m_directJumpTargets[it->first] = m_badJumpBlock.get(); 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) for (auto it = indirectJumpTargets.cbegin(); it != indirectJumpTargets.cend(); ++it)
{ {
if (*it >= bytecode.size()) m_indirectJumpTargets.push_back(&basicBlocks.find(*it)->second);
m_indirectJumpTargets.push_back(m_finalBlock.get());
else
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); createBasicBlocks(bytecode);
// Init runtime structures. // Init runtime structures.
auto memory = Memory(builder, module.get()); Memory memory(builder, module.get());
auto ext = Ext(builder, module.get()); Ext ext(builder, module.get());
GasMeter gasMeter(builder, module.get()); GasMeter gasMeter(builder, module.get());
// Jump to first instruction // 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 // 1. this is not the first instruction in the block
// 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).
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())
{ {
auto targetBlock = pairIter->second; targetBlock = pairIter->second;
}
}
if (inst == Instruction::JUMP)
{
if (targetBlock)
{
// The target address is computed at compile time, // The target address is computed at compile time,
// just pop it without looking... // just pop it without looking...
stack.pop(); stack.pop();
builder.CreateBr(targetBlock->llvm());
if (inst == Instruction::JUMP) }
{ else
builder.CreateBr(targetBlock->llvm()); {
} // FIXME: this get(0) is a temporary workaround to get some of the jump tests running.
else // JUMPI stack.get(0);
{ builder.CreateBr(m_jumpTableBlock->llvm());
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;
} }
} }
else // JUMPI
if (inst == Instruction::JUMPI)
{ {
std::cerr << "Indirect JUMPI is not supported yet (at PC " stack.swap(1);
<< currentPC << ")\n"; auto val = stack.pop();
std::exit(1); 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; break;
} }
@ -865,7 +866,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
} }
else else
{ {
builder.CreateRet(builder.getInt64(0)); builder.CreateBr(m_badJumpBlock->llvm());
} }
linkBasicBlocks(); linkBasicBlocks();

Loading…
Cancel
Save