Reuse the mechanism for abi functions and move tracking of used functions to CompilerContext

This commit is contained in:
Daniel Kirchner 2020-03-02 17:20:49 +01:00
parent 90fa56c719
commit 24d6e6295e
8 changed files with 28 additions and 62 deletions

View File

@ -55,7 +55,7 @@ string ABIFunctions::tupleEncoder(
functionName += t->identifier() + "_";
functionName += options.toFunctionNameSuffix();
return createExternallyUsedFunction(functionName, [&]() {
return createFunction(functionName, [&]() {
// Note that the values are in reverse due to the difference in calling semantics.
Whiskers templ(R"(
function <functionName>(headStart <valueParams>) -> tail {
@ -121,7 +121,7 @@ string ABIFunctions::tupleEncoderPacked(
functionName += t->identifier() + "_";
functionName += options.toFunctionNameSuffix();
return createExternallyUsedFunction(functionName, [&]() {
return createFunction(functionName, [&]() {
solAssert(!_givenTypes.empty(), "");
// Note that the values are in reverse due to the difference in calling semantics.
@ -173,7 +173,7 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory)
if (_fromMemory)
functionName += "_fromMemory";
return createExternallyUsedFunction(functionName, [&]() {
return createFunction(functionName, [&]() {
TypePointers decodingTypes;
for (auto const& t: _types)
decodingTypes.emplace_back(t->decodingType());
@ -1495,11 +1495,6 @@ string ABIFunctions::createFunction(string const& _name, function<string ()> con
return m_functionCollector->createFunction(_name, _creator);
}
string ABIFunctions::createExternallyUsedFunction(string const& _name, function<string ()> const& _creator)
{
return m_functionCollector->createExternallyUsedFunction(_name, _creator);
}
size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
{
size_t headSize = 0;

View File

@ -31,7 +31,6 @@
#include <functional>
#include <map>
#include <set>
#include <vector>
namespace solidity::frontend
@ -233,11 +232,6 @@ private:
/// cases.
std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator);
/// Helper function that uses @a _creator to create a function and add it to
/// @a m_requestedFunctions if it has not been created yet and returns @a _name in both
/// cases. Also adds it to the list of externally used functions.
std::string createExternallyUsedFunction(std::string const& _name, std::function<std::string()> const& _creator);
/// @returns the size of the static part of the encoding of the given types.
static size_t headSize(TypePointers const& _targetTypes);

View File

@ -100,7 +100,7 @@ void CompilerContext::callYulUtilFunction(
unsigned _outArgs
)
{
m_functionCollector->markAsExternallyUsed(_name);
m_externallyUsedFunctions.insert(_name);
auto retTag = pushNewTag();
CompilerUtils(*this).moveIntoStack(_inArgs);
appendJumpTo(namedTag(_name));
@ -147,6 +147,13 @@ void CompilerContext::appendMissingLowLevelFunctions()
}
}
pair<string, set<string>> CompilerContext::requestedYulFunctions()
{
set<string> empty;
swap(empty, m_externallyUsedFunctions);
return make_pair(m_functionCollector->requestedFunctions(), std::move(empty));
}
void CompilerContext::addVariable(
VariableDeclaration const& _declaration,
unsigned _offsetToCurrent

View File

@ -154,10 +154,11 @@ public:
void appendMissingLowLevelFunctions();
ABIFunctions& abiFunctions() { return m_abiFunctions; }
YulUtilFunctions& utilFunctions() { return m_yulUtilFunctions; }
std::pair<std::string, std::set<std::string>> requestedYulFunctions()
{
return m_functionCollector->requestedFunctions();
}
/// @returns concatenation of all generated functions and a set of the
/// externally used functions.
/// Clears the internal list, i.e. calling it again will result in an
/// empty return value.
std::pair<std::string, std::set<std::string>> requestedYulFunctions();
ModifierDefinition const& resolveVirtualFunctionModifier(ModifierDefinition const& _modifier) const;
/// Returns the distance of the given local variable from the bottom of the stack (of the current function).
@ -371,6 +372,8 @@ private:
std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions;
// Collector for yul functions.
std::shared_ptr<MultiUseYulFunctionCollector> m_functionCollector = std::make_shared<MultiUseYulFunctionCollector>();
/// Set of externally used yul functions.
std::set<std::string> m_externallyUsedFunctions;
/// Container for ABI functions to be generated.
ABIFunctions m_abiFunctions;
/// Container for Yul Util functions to be generated.

View File

@ -595,31 +595,21 @@ void CompilerUtils::abiEncodeV2(
// stack: <$value0> <$value1> ... <$value(n-1)> <$headStart>
auto ret = m_context.pushNewTag();
moveIntoStack(sizeOnStack(_givenTypes) + 1);
string encoderName =
_padToWordBoundaries ?
m_context.abiFunctions().tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes) :
m_context.abiFunctions().tupleEncoderPacked(_givenTypes, _targetTypes);
m_context.appendJumpTo(m_context.namedTag(encoderName));
m_context.adjustStackOffset(-int(sizeOnStack(_givenTypes)) - 1);
m_context << ret.tag();
m_context.callYulUtilFunction(encoderName, sizeOnStack(_givenTypes) + 1, 1);
}
void CompilerUtils::abiDecodeV2(TypePointers const& _parameterTypes, bool _fromMemory)
{
// stack: <source_offset> <length> [stack top]
auto ret = m_context.pushNewTag();
moveIntoStack(2);
// stack: <return tag> <source_offset> <length> [stack top]
m_context << Instruction::DUP2 << Instruction::ADD;
m_context << Instruction::SWAP1;
// stack: <return tag> <end> <start>
// stack: <end> <start>
string decoderName = m_context.abiFunctions().tupleDecoder(_parameterTypes, _fromMemory);
m_context.appendJumpTo(m_context.namedTag(decoderName));
m_context.adjustStackOffset(int(sizeOnStack(_parameterTypes)) - 3);
m_context << ret.tag();
m_context.callYulUtilFunction(decoderName, 2, sizeOnStack(_parameterTypes));
}
void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)

View File

@ -30,15 +30,13 @@ using namespace std;
using namespace solidity;
using namespace solidity::frontend;
pair<string, set<string>> MultiUseYulFunctionCollector::requestedFunctions()
string MultiUseYulFunctionCollector::requestedFunctions()
{
string result;
for (auto const& f: m_requestedFunctions)
result += f.second;
m_requestedFunctions.clear();
std::set<string> empty;
swap(empty, m_externallyUsedFunctions);
return make_pair(result, std::move(empty));
return result;
}
string MultiUseYulFunctionCollector::createFunction(string const& _name, function<string ()> const& _creator)
@ -52,9 +50,3 @@ string MultiUseYulFunctionCollector::createFunction(string const& _name, functio
}
return _name;
}
string MultiUseYulFunctionCollector::createExternallyUsedFunction(string const& _name, function<string ()> const& _creator)
{
m_externallyUsedFunctions.insert(_name);
return createFunction(_name, _creator);
}

View File

@ -23,7 +23,6 @@
#include <functional>
#include <map>
#include <set>
#include <string>
namespace solidity::frontend
@ -41,28 +40,14 @@ public:
/// cases.
std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator);
/// Helper function that uses @a _creator to create a function and add it to
/// @a m_requestedFunctions if it has not been created yet and returns @a _name in both
/// cases.
std::string createExternallyUsedFunction(std::string const& _name, std::function<std::string()> const& _creator);
/// Manually mark a function as externally used.
void markAsExternallyUsed(std::string const& _name)
{
m_externallyUsedFunctions.insert(_name);
}
/// @returns concatenation of all generated functions and a set of the
/// externally used functions.
/// @returns concatenation of all generated functions.
/// Clears the internal list, i.e. calling it again will result in an
/// empty return value.
std::pair<std::string, std::set<std::string>> requestedFunctions();
std::string requestedFunctions();
private:
/// Map from function name to code for a multi-use function.
std::map<std::string, std::string> m_requestedFunctions;
// Set of externally used functions.
std::set<std::string> m_externallyUsedFunctions;
};
}

View File

@ -107,7 +107,7 @@ string IRGenerator::generate(ContractDefinition const& _contract)
for (auto const* contract: _contract.annotation().linearizedBaseContracts)
for (auto const* fun: contract->definedFunctions())
generateFunction(*fun);
t("functions", m_context.functionCollector()->requestedFunctions().first);
t("functions", m_context.functionCollector()->requestedFunctions());
resetContext(_contract);
m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
@ -116,7 +116,7 @@ string IRGenerator::generate(ContractDefinition const& _contract)
for (auto const* contract: _contract.annotation().linearizedBaseContracts)
for (auto const* fun: contract->definedFunctions())
generateFunction(*fun);
t("runtimeFunctions", m_context.functionCollector()->requestedFunctions().first);
t("runtimeFunctions", m_context.functionCollector()->requestedFunctions());
return t.render();
}
@ -383,7 +383,7 @@ string IRGenerator::memoryInit()
void IRGenerator::resetContext(ContractDefinition const& _contract)
{
solAssert(
m_context.functionCollector()->requestedFunctions().first.empty(),
m_context.functionCollector()->requestedFunctions().empty(),
"Reset context while it still had functions."
);
m_context = IRGenerationContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings);