Refactoring copyLiteralToMemoryFunction and reusing it from other functions.

Co-authored-by: Leonardo <leo@ethereum.org>

Co-authored-by: Alex Beregszaszi <alex@rtfs.hu>
This commit is contained in:
Djordje Mijovic 2020-12-22 15:48:31 +01:00
parent b74c08143f
commit 047d693ac9
4 changed files with 37 additions and 47 deletions

View File

@ -976,30 +976,20 @@ string ABIFunctions::abiEncodingFunctionStringLiteral(
Whiskers templ(R"(
function <functionName>(pos) -> end {
pos := <storeLength>(pos, <length>)
<#word>
mstore(add(pos, <offset>), <wordValue>)
</word>
<storeLiteralInMemory>(pos)
end := add(pos, <overallSize>)
}
)");
templ("functionName", functionName);
// TODO this can make use of CODECOPY for large strings once we have that in Yul
size_t words = (value.size() + 31) / 32;
templ("length", to_string(value.size()));
templ("storeLength", arrayStoreLengthForEncodingFunction(dynamic_cast<ArrayType const&>(_to), _options));
if (_options.padded)
templ("overallSize", to_string(words * 32));
templ("overallSize", to_string(((value.size() + 31) / 32) * 32));
else
templ("overallSize", to_string(value.size()));
vector<map<string, string>> wordParams(words);
for (size_t i = 0; i < words; ++i)
{
wordParams[i]["offset"] = to_string(i * 32);
wordParams[i]["wordValue"] = formatAsStringOrNumber(value.substr(32 * i, 32));
}
templ("word", wordParams);
templ("storeLiteralInMemory", m_utils.storeLiteralInMemoryFunction(value));
return templ.render();
}
else

View File

@ -107,10 +107,28 @@ string YulUtilFunctions::copyToMemoryFunction(bool _fromCalldata)
});
}
string YulUtilFunctions::copyToMemoryLiteralFunction(string const& _literal)
string YulUtilFunctions::copyLiteralToMemoryFunction(string const& _literal)
{
solAssert(!_literal.empty(), "");
string functionName = "copy_literal_to_memory_" + h256(_literal, h256::AlignLeft).hex();
string functionName = "copy_literal_to_memory_" + util::toHex(util::keccak256(_literal).asBytes());
return m_functionCollector.createFunction(functionName, [&]() {
return Whiskers(R"(
function <functionName>() -> memPtr {
memPtr := <arrayAllocationFunction>(<size>)
<storeLiteralInMem>(add(memPtr, 32))
}
)")
("functionName", functionName)
("arrayAllocationFunction", allocateMemoryArrayFunction(*TypeProvider::array(DataLocation::Memory, true)))
("size", to_string(_literal.size()))
("storeLiteralInMem", storeLiteralInMemoryFunction(_literal))
.render();
});
}
string YulUtilFunctions::storeLiteralInMemoryFunction(string const& _literal)
{
string functionName = "store_literal_in_memory_" + util::toHex(util::keccak256(_literal).asBytes());
return m_functionCollector.createFunction(functionName, [&]() {
size_t words = (_literal.length() + 31) / 32;
@ -122,18 +140,13 @@ string YulUtilFunctions::copyToMemoryLiteralFunction(string const& _literal)
}
return Whiskers(R"(
function <functionName>() -> memPtr {
memPtr := <allocationFunction>(add(<size>, 32))
mstore(memPtr, <size>)
let dataPos := add(memPtr, 32)
function <functionName>(memPtr) {
<#word>
mstore(add(dataPos, <offset>), <wordValue>)
mstore(add(memPtr, <offset>), <wordValue>)
</word>
}
)")
("functionName", functionName)
("allocationFunction", allocationFunction())
("size", to_string(_literal.size()))
("word", wordParams)
.render();
});
@ -3933,31 +3946,14 @@ string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const
}
else if (_to.category() == Type::Category::Array)
{
auto const& arrayType = dynamic_cast<ArrayType const&>(_to);
solAssert(arrayType.isByteArray(), "");
size_t words = (data.size() + 31) / 32;
size_t storageSize = 32 + words * 32;
solAssert(dynamic_cast<ArrayType const&>(_to).isByteArray(), "");
Whiskers templ(R"(
function <functionName>() -> converted {
converted := <allocate>(<storageSize>)
mstore(converted, <size>)
<#word>
mstore(add(converted, <offset>), <wordValue>)
</word>
converted := <copyLiteralToMemory>()
}
)");
templ("functionName", functionName);
templ("allocate", allocationFunction());
templ("storageSize", to_string(storageSize));
templ("size", to_string(data.size()));
vector<map<string, string>> wordParams(words);
for (size_t i = 0; i < words; ++i)
{
wordParams[i]["offset"] = to_string(32 + i * 32);
wordParams[i]["wordValue"] = formatAsStringOrNumber(data.substr(32 * i, 32));
}
templ("word", wordParams);
templ("copyLiteralToMemory", copyLiteralToMemoryFunction(data));
return templ.render();
}
else

View File

@ -72,10 +72,14 @@ public:
/// Pads with zeros and might write more than exactly length.
std::string copyToMemoryFunction(bool _fromCalldata);
/// @returns a function name that copies string literal to memory
/// and returns pointer to memory array containing it
/// @returns the name of a function that copies a string literal to memory
/// and returns a pointer to the memory area containing the string literal.
/// signature: () -> memPtr
std::string copyToMemoryLiteralFunction(std::string const& _literal);
std::string copyLiteralToMemoryFunction(std::string const& _literal);
/// @returns the name of a function that stores a string literal at a specific location in memory
/// signature: (memPtr) ->
std::string storeLiteralInMemoryFunction(std::string const& _literal);
// @returns the name of a function that has the equivalent logic of an
// `assert` or `require` call.

View File

@ -1739,7 +1739,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
{
TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition();
define(IRVariable(_memberAccess)) << m_utils.copyToMemoryLiteralFunction(contract.name()) << "()\n";
define(IRVariable(_memberAccess)) << m_utils.copyLiteralToMemoryFunction(contract.name()) << "()\n";
}
else if (member == "interfaceId")
{