mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Reuse the mechanism for abi functions and move tracking of used functions to CompilerContext
This commit is contained in:
parent
90fa56c719
commit
24d6e6295e
@ -55,7 +55,7 @@ string ABIFunctions::tupleEncoder(
|
|||||||
functionName += t->identifier() + "_";
|
functionName += t->identifier() + "_";
|
||||||
functionName += options.toFunctionNameSuffix();
|
functionName += options.toFunctionNameSuffix();
|
||||||
|
|
||||||
return createExternallyUsedFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
// Note that the values are in reverse due to the difference in calling semantics.
|
// Note that the values are in reverse due to the difference in calling semantics.
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
function <functionName>(headStart <valueParams>) -> tail {
|
function <functionName>(headStart <valueParams>) -> tail {
|
||||||
@ -121,7 +121,7 @@ string ABIFunctions::tupleEncoderPacked(
|
|||||||
functionName += t->identifier() + "_";
|
functionName += t->identifier() + "_";
|
||||||
functionName += options.toFunctionNameSuffix();
|
functionName += options.toFunctionNameSuffix();
|
||||||
|
|
||||||
return createExternallyUsedFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
solAssert(!_givenTypes.empty(), "");
|
solAssert(!_givenTypes.empty(), "");
|
||||||
|
|
||||||
// Note that the values are in reverse due to the difference in calling semantics.
|
// 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)
|
if (_fromMemory)
|
||||||
functionName += "_fromMemory";
|
functionName += "_fromMemory";
|
||||||
|
|
||||||
return createExternallyUsedFunction(functionName, [&]() {
|
return createFunction(functionName, [&]() {
|
||||||
TypePointers decodingTypes;
|
TypePointers decodingTypes;
|
||||||
for (auto const& t: _types)
|
for (auto const& t: _types)
|
||||||
decodingTypes.emplace_back(t->decodingType());
|
decodingTypes.emplace_back(t->decodingType());
|
||||||
@ -1495,11 +1495,6 @@ string ABIFunctions::createFunction(string const& _name, function<string ()> con
|
|||||||
return m_functionCollector->createFunction(_name, _creator);
|
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 ABIFunctions::headSize(TypePointers const& _targetTypes)
|
||||||
{
|
{
|
||||||
size_t headSize = 0;
|
size_t headSize = 0;
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
@ -233,11 +232,6 @@ private:
|
|||||||
/// cases.
|
/// cases.
|
||||||
std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator);
|
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.
|
/// @returns the size of the static part of the encoding of the given types.
|
||||||
static size_t headSize(TypePointers const& _targetTypes);
|
static size_t headSize(TypePointers const& _targetTypes);
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ void CompilerContext::callYulUtilFunction(
|
|||||||
unsigned _outArgs
|
unsigned _outArgs
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_functionCollector->markAsExternallyUsed(_name);
|
m_externallyUsedFunctions.insert(_name);
|
||||||
auto retTag = pushNewTag();
|
auto retTag = pushNewTag();
|
||||||
CompilerUtils(*this).moveIntoStack(_inArgs);
|
CompilerUtils(*this).moveIntoStack(_inArgs);
|
||||||
appendJumpTo(namedTag(_name));
|
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(
|
void CompilerContext::addVariable(
|
||||||
VariableDeclaration const& _declaration,
|
VariableDeclaration const& _declaration,
|
||||||
unsigned _offsetToCurrent
|
unsigned _offsetToCurrent
|
||||||
|
@ -154,10 +154,11 @@ public:
|
|||||||
void appendMissingLowLevelFunctions();
|
void appendMissingLowLevelFunctions();
|
||||||
ABIFunctions& abiFunctions() { return m_abiFunctions; }
|
ABIFunctions& abiFunctions() { return m_abiFunctions; }
|
||||||
YulUtilFunctions& utilFunctions() { return m_yulUtilFunctions; }
|
YulUtilFunctions& utilFunctions() { return m_yulUtilFunctions; }
|
||||||
std::pair<std::string, std::set<std::string>> requestedYulFunctions()
|
/// @returns concatenation of all generated functions and a set of the
|
||||||
{
|
/// externally used functions.
|
||||||
return m_functionCollector->requestedFunctions();
|
/// 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;
|
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).
|
/// 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;
|
std::map<std::string, evmasm::AssemblyItem> m_lowLevelFunctions;
|
||||||
// Collector for yul functions.
|
// Collector for yul functions.
|
||||||
std::shared_ptr<MultiUseYulFunctionCollector> m_functionCollector = std::make_shared<MultiUseYulFunctionCollector>();
|
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.
|
/// Container for ABI functions to be generated.
|
||||||
ABIFunctions m_abiFunctions;
|
ABIFunctions m_abiFunctions;
|
||||||
/// Container for Yul Util functions to be generated.
|
/// Container for Yul Util functions to be generated.
|
||||||
|
@ -595,31 +595,21 @@ void CompilerUtils::abiEncodeV2(
|
|||||||
|
|
||||||
// stack: <$value0> <$value1> ... <$value(n-1)> <$headStart>
|
// stack: <$value0> <$value1> ... <$value(n-1)> <$headStart>
|
||||||
|
|
||||||
auto ret = m_context.pushNewTag();
|
|
||||||
moveIntoStack(sizeOnStack(_givenTypes) + 1);
|
|
||||||
|
|
||||||
string encoderName =
|
string encoderName =
|
||||||
_padToWordBoundaries ?
|
_padToWordBoundaries ?
|
||||||
m_context.abiFunctions().tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes) :
|
m_context.abiFunctions().tupleEncoder(_givenTypes, _targetTypes, _encodeAsLibraryTypes) :
|
||||||
m_context.abiFunctions().tupleEncoderPacked(_givenTypes, _targetTypes);
|
m_context.abiFunctions().tupleEncoderPacked(_givenTypes, _targetTypes);
|
||||||
m_context.appendJumpTo(m_context.namedTag(encoderName));
|
m_context.callYulUtilFunction(encoderName, sizeOnStack(_givenTypes) + 1, 1);
|
||||||
m_context.adjustStackOffset(-int(sizeOnStack(_givenTypes)) - 1);
|
|
||||||
m_context << ret.tag();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::abiDecodeV2(TypePointers const& _parameterTypes, bool _fromMemory)
|
void CompilerUtils::abiDecodeV2(TypePointers const& _parameterTypes, bool _fromMemory)
|
||||||
{
|
{
|
||||||
// stack: <source_offset> <length> [stack top]
|
// 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::DUP2 << Instruction::ADD;
|
||||||
m_context << Instruction::SWAP1;
|
m_context << Instruction::SWAP1;
|
||||||
// stack: <return tag> <end> <start>
|
// stack: <end> <start>
|
||||||
string decoderName = m_context.abiFunctions().tupleDecoder(_parameterTypes, _fromMemory);
|
string decoderName = m_context.abiFunctions().tupleDecoder(_parameterTypes, _fromMemory);
|
||||||
m_context.appendJumpTo(m_context.namedTag(decoderName));
|
m_context.callYulUtilFunction(decoderName, 2, sizeOnStack(_parameterTypes));
|
||||||
m_context.adjustStackOffset(int(sizeOnStack(_parameterTypes)) - 3);
|
|
||||||
m_context << ret.tag();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
|
void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
|
||||||
|
@ -30,15 +30,13 @@ using namespace std;
|
|||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::frontend;
|
using namespace solidity::frontend;
|
||||||
|
|
||||||
pair<string, set<string>> MultiUseYulFunctionCollector::requestedFunctions()
|
string MultiUseYulFunctionCollector::requestedFunctions()
|
||||||
{
|
{
|
||||||
string result;
|
string result;
|
||||||
for (auto const& f: m_requestedFunctions)
|
for (auto const& f: m_requestedFunctions)
|
||||||
result += f.second;
|
result += f.second;
|
||||||
m_requestedFunctions.clear();
|
m_requestedFunctions.clear();
|
||||||
std::set<string> empty;
|
return result;
|
||||||
swap(empty, m_externallyUsedFunctions);
|
|
||||||
return make_pair(result, std::move(empty));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string MultiUseYulFunctionCollector::createFunction(string const& _name, function<string ()> const& _creator)
|
string MultiUseYulFunctionCollector::createFunction(string const& _name, function<string ()> const& _creator)
|
||||||
@ -52,9 +50,3 @@ string MultiUseYulFunctionCollector::createFunction(string const& _name, functio
|
|||||||
}
|
}
|
||||||
return _name;
|
return _name;
|
||||||
}
|
}
|
||||||
|
|
||||||
string MultiUseYulFunctionCollector::createExternallyUsedFunction(string const& _name, function<string ()> const& _creator)
|
|
||||||
{
|
|
||||||
m_externallyUsedFunctions.insert(_name);
|
|
||||||
return createFunction(_name, _creator);
|
|
||||||
}
|
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace solidity::frontend
|
namespace solidity::frontend
|
||||||
@ -41,28 +40,14 @@ public:
|
|||||||
/// cases.
|
/// cases.
|
||||||
std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator);
|
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
|
/// @returns concatenation of all generated functions.
|
||||||
/// @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.
|
|
||||||
/// Clears the internal list, i.e. calling it again will result in an
|
/// Clears the internal list, i.e. calling it again will result in an
|
||||||
/// empty return value.
|
/// empty return value.
|
||||||
std::pair<std::string, std::set<std::string>> requestedFunctions();
|
std::string requestedFunctions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Map from function name to code for a multi-use function.
|
/// Map from function name to code for a multi-use function.
|
||||||
std::map<std::string, std::string> m_requestedFunctions;
|
std::map<std::string, std::string> m_requestedFunctions;
|
||||||
// Set of externally used functions.
|
|
||||||
std::set<std::string> m_externallyUsedFunctions;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ string IRGenerator::generate(ContractDefinition const& _contract)
|
|||||||
for (auto const* contract: _contract.annotation().linearizedBaseContracts)
|
for (auto const* contract: _contract.annotation().linearizedBaseContracts)
|
||||||
for (auto const* fun: contract->definedFunctions())
|
for (auto const* fun: contract->definedFunctions())
|
||||||
generateFunction(*fun);
|
generateFunction(*fun);
|
||||||
t("functions", m_context.functionCollector()->requestedFunctions().first);
|
t("functions", m_context.functionCollector()->requestedFunctions());
|
||||||
|
|
||||||
resetContext(_contract);
|
resetContext(_contract);
|
||||||
m_context.setInheritanceHierarchy(_contract.annotation().linearizedBaseContracts);
|
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* contract: _contract.annotation().linearizedBaseContracts)
|
||||||
for (auto const* fun: contract->definedFunctions())
|
for (auto const* fun: contract->definedFunctions())
|
||||||
generateFunction(*fun);
|
generateFunction(*fun);
|
||||||
t("runtimeFunctions", m_context.functionCollector()->requestedFunctions().first);
|
t("runtimeFunctions", m_context.functionCollector()->requestedFunctions());
|
||||||
return t.render();
|
return t.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ string IRGenerator::memoryInit()
|
|||||||
void IRGenerator::resetContext(ContractDefinition const& _contract)
|
void IRGenerator::resetContext(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
solAssert(
|
solAssert(
|
||||||
m_context.functionCollector()->requestedFunctions().first.empty(),
|
m_context.functionCollector()->requestedFunctions().empty(),
|
||||||
"Reset context while it still had functions."
|
"Reset context while it still had functions."
|
||||||
);
|
);
|
||||||
m_context = IRGenerationContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings);
|
m_context = IRGenerationContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings);
|
||||||
|
Loading…
Reference in New Issue
Block a user