mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Replace function selector jump table by more resilient linear time check.
This commit is contained in:
parent
d9822190c6
commit
41b26e491b
37
Compiler.cpp
37
Compiler.cpp
@ -81,35 +81,34 @@ void Compiler::appendFunctionSelector(vector<ASTPointer<FunctionDefinition>> con
|
|||||||
if (publicFunctions.size() > 255)
|
if (publicFunctions.size() > 255)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract."));
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract."));
|
||||||
|
|
||||||
//@todo check for calldatasize?
|
// retrieve the first byte of the call data, which determines the called function
|
||||||
// retrieve the first byte of the call data
|
// @todo This code had a jump table in a previous version which was more efficient but also
|
||||||
m_context << u256(0) << eth::Instruction::CALLDATALOAD << u256(0) << eth::Instruction::BYTE;
|
// error prone (due to the optimizer and variable length tag addresses)
|
||||||
// check that it is not too large
|
m_context << u256(1) << u256(0) // some constants
|
||||||
m_context << eth::Instruction::DUP1 << u256(publicFunctions.size() - 1) << eth::Instruction::LT;
|
<< eth::dupInstruction(1) << eth::Instruction::CALLDATALOAD
|
||||||
eth::AssemblyItem returnTag = m_context.appendConditionalJump();
|
<< eth::dupInstruction(2) << eth::Instruction::BYTE
|
||||||
|
<< eth::dupInstruction(2);
|
||||||
|
|
||||||
// otherwise, jump inside jump table (each entry of the table has size 4)
|
// stack here: 1 0 <funid> 0, stack top will be counted up until it matches funid
|
||||||
m_context << u256(4) << eth::Instruction::MUL;
|
|
||||||
eth::AssemblyItem jumpTableStart = m_context.pushNewTag();
|
|
||||||
m_context << eth::Instruction::ADD << eth::Instruction::JUMP;
|
|
||||||
|
|
||||||
// jump table @todo it could be that the optimizer destroys this
|
|
||||||
m_context << jumpTableStart;
|
|
||||||
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
|
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
|
||||||
m_context.appendJumpTo(f.second.second) << eth::Instruction::JUMPDEST;
|
{
|
||||||
|
eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
|
||||||
m_context << returnTag << eth::Instruction::STOP;
|
m_context << eth::dupInstruction(2) << eth::dupInstruction(2) << eth::Instruction::EQ;
|
||||||
|
m_context.appendConditionalJumpTo(callDataUnpackerEntry);
|
||||||
|
m_context << eth::dupInstruction(4) << eth::Instruction::ADD;
|
||||||
|
//@todo avoid the last ADD (or remove it in the optimizer)
|
||||||
|
}
|
||||||
|
m_context << eth::Instruction::STOP; // function not found
|
||||||
|
|
||||||
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
|
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
|
||||||
{
|
{
|
||||||
FunctionDefinition const& function = *f.second.first;
|
FunctionDefinition const& function = *f.second.first;
|
||||||
m_context << f.second.second;
|
eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
|
||||||
|
m_context << callDataUnpackerEntry;
|
||||||
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
eth::AssemblyItem returnTag = m_context.pushNewTag();
|
||||||
appendCalldataUnpacker(function);
|
appendCalldataUnpacker(function);
|
||||||
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
|
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
|
||||||
m_context << returnTag;
|
m_context << returnTag;
|
||||||
|
|
||||||
appendReturnValuePacker(function);
|
appendReturnValuePacker(function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user