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"( Whiskers templ(R"(
function <functionName>(pos) -> end { function <functionName>(pos) -> end {
pos := <storeLength>(pos, <length>) pos := <storeLength>(pos, <length>)
<#word> <storeLiteralInMemory>(pos)
mstore(add(pos, <offset>), <wordValue>)
</word>
end := add(pos, <overallSize>) end := add(pos, <overallSize>)
} }
)"); )");
templ("functionName", functionName); templ("functionName", functionName);
// TODO this can make use of CODECOPY for large strings once we have that in Yul // 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("length", to_string(value.size()));
templ("storeLength", arrayStoreLengthForEncodingFunction(dynamic_cast<ArrayType const&>(_to), _options)); templ("storeLength", arrayStoreLengthForEncodingFunction(dynamic_cast<ArrayType const&>(_to), _options));
if (_options.padded) if (_options.padded)
templ("overallSize", to_string(words * 32)); templ("overallSize", to_string(((value.size() + 31) / 32) * 32));
else else
templ("overallSize", to_string(value.size())); templ("overallSize", to_string(value.size()));
templ("storeLiteralInMemory", m_utils.storeLiteralInMemoryFunction(value));
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);
return templ.render(); return templ.render();
} }
else 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_" + util::toHex(util::keccak256(_literal).asBytes());
string functionName = "copy_literal_to_memory_" + h256(_literal, h256::AlignLeft).hex();
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, [&]() { return m_functionCollector.createFunction(functionName, [&]() {
size_t words = (_literal.length() + 31) / 32; size_t words = (_literal.length() + 31) / 32;
@ -122,18 +140,13 @@ string YulUtilFunctions::copyToMemoryLiteralFunction(string const& _literal)
} }
return Whiskers(R"( return Whiskers(R"(
function <functionName>() -> memPtr { function <functionName>(memPtr) {
memPtr := <allocationFunction>(add(<size>, 32))
mstore(memPtr, <size>)
let dataPos := add(memPtr, 32)
<#word> <#word>
mstore(add(dataPos, <offset>), <wordValue>) mstore(add(memPtr, <offset>), <wordValue>)
</word> </word>
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("allocationFunction", allocationFunction())
("size", to_string(_literal.size()))
("word", wordParams) ("word", wordParams)
.render(); .render();
}); });
@ -3933,31 +3946,14 @@ string YulUtilFunctions::conversionFunctionSpecial(Type const& _from, Type const
} }
else if (_to.category() == Type::Category::Array) else if (_to.category() == Type::Category::Array)
{ {
auto const& arrayType = dynamic_cast<ArrayType const&>(_to); solAssert(dynamic_cast<ArrayType const&>(_to).isByteArray(), "");
solAssert(arrayType.isByteArray(), "");
size_t words = (data.size() + 31) / 32;
size_t storageSize = 32 + words * 32;
Whiskers templ(R"( Whiskers templ(R"(
function <functionName>() -> converted { function <functionName>() -> converted {
converted := <allocate>(<storageSize>) converted := <copyLiteralToMemory>()
mstore(converted, <size>)
<#word>
mstore(add(converted, <offset>), <wordValue>)
</word>
} }
)"); )");
templ("functionName", functionName); templ("functionName", functionName);
templ("allocate", allocationFunction()); templ("copyLiteralToMemory", copyLiteralToMemoryFunction(data));
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);
return templ.render(); return templ.render();
} }
else else

View File

@ -72,10 +72,14 @@ public:
/// Pads with zeros and might write more than exactly length. /// Pads with zeros and might write more than exactly length.
std::string copyToMemoryFunction(bool _fromCalldata); std::string copyToMemoryFunction(bool _fromCalldata);
/// @returns a function name that copies string literal to memory /// @returns the name of a function that copies a string literal to memory
/// and returns pointer to memory array containing it /// and returns a pointer to the memory area containing the string literal.
/// signature: () -> memPtr /// 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 // @returns the name of a function that has the equivalent logic of an
// `assert` or `require` call. // `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(); TypePointer arg = dynamic_cast<MagicType const&>(*_memberAccess.expression().annotation().type).typeArgument();
ContractDefinition const& contract = dynamic_cast<ContractType const&>(*arg).contractDefinition(); 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") else if (member == "interfaceId")
{ {