Only generate sort/search code when interface functions exist

This commit is contained in:
Mathias Baumann
2018-12-17 21:24:37 +01:00
committed by chriseth
parent 7d3727bbf7
commit 1b8570f829
4 changed files with 90 additions and 15 deletions
+41 -10
View File
@@ -331,6 +331,25 @@ void ContractCompiler::appendInternalSelector(
}
}
namespace
{
// Helper function to check if any function is payable
bool hasPayableFunctions(ContractDefinition const& _contract)
{
FunctionDefinition const* fallback = _contract.fallbackFunction();
if (fallback && fallback->isPayable())
return true;
for (auto const& it: _contract.interfaceFunctions())
if (it.second->isPayable())
return true;
return false;
}
}
void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contract)
{
map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.interfaceFunctions();
@@ -342,6 +361,15 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
}
FunctionDefinition const* fallback = _contract.fallbackFunction();
solAssert(!_contract.isLibrary() || !fallback, "Libraries can't have fallback functions");
bool needToAddCallvalueCheck = true;
if (!hasPayableFunctions(_contract) && !interfaceFunctions.empty() && !_contract.isLibrary())
{
appendCallValueCheck();
needToAddCallvalueCheck = false;
}
eth::AssemblyItem notFound = m_context.newTag();
// directly jump to fallback if the data is too short to contain a function selector
// also guards against short data
@@ -350,23 +378,26 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
// retrieve the function signature hash from the calldata
if (!interfaceFunctions.empty())
{
CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true);
// stack now is: <can-call-non-view-functions>? <funhash>
vector<FixedHash<4>> sortedIDs;
for (auto const& it: interfaceFunctions)
{
callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag()));
sortedIDs.emplace_back(it.first);
// stack now is: <can-call-non-view-functions>? <funhash>
vector<FixedHash<4>> sortedIDs;
for (auto const& it: interfaceFunctions)
{
callDataUnpackerEntryPoints.emplace(it.first, m_context.newTag());
sortedIDs.emplace_back(it.first);
}
std::sort(sortedIDs.begin(), sortedIDs.end());
appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimise_runs);
}
std::sort(sortedIDs.begin(), sortedIDs.end());
appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimise_runs);
m_context << notFound;
if (fallback)
{
solAssert(!_contract.isLibrary(), "");
if (!fallback->isPayable())
if (!fallback->isPayable() && needToAddCallvalueCheck)
appendCallValueCheck();
solAssert(fallback->isFallback(), "");
@@ -396,7 +427,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
m_context.setStackOffset(0);
// We have to allow this for libraries, because value of the previous
// call is still visible in the delegatecall.
if (!functionType->isPayable() && !_contract.isLibrary())
if (!functionType->isPayable() && !_contract.isLibrary() && needToAddCallvalueCheck)
appendCallValueCheck();
// Return tag is used to jump out of the function.