mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Sol->Yul] Implementing struct copying from storage to memory
This commit is contained in:
parent
b89c863e11
commit
381784dd89
@ -1413,6 +1413,49 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool
|
||||
to_string(_offset) +
|
||||
"_" +
|
||||
_type.identifier();
|
||||
|
||||
if (_type.category() == Type::Category::Struct)
|
||||
{
|
||||
solAssert(_offset == 0, "");
|
||||
auto const& structType = dynamic_cast<StructType const&>(_type);
|
||||
solUnimplementedAssert(structType.location() == DataLocation::Memory, "");
|
||||
MemberList::MemberMap structMembers = structType.nativeMembers(nullptr);
|
||||
vector<map<string, string>> memberSetValues(structMembers.size());
|
||||
for (size_t i = 0; i < structMembers.size(); ++i)
|
||||
{
|
||||
auto const& [memberSlotDiff, memberStorageOffset] = structType.storageOffsetsOfMember(structMembers[i].name);
|
||||
bool isStruct = structMembers[i].type->category() == Type::Category::Struct;
|
||||
|
||||
memberSetValues[i]["setMember"] = Whiskers(R"(
|
||||
mstore(add(value, <memberMemoryOffset>), <readFromStorage>(add(slot, <memberSlotDiff>)<?notStruct>, <memberStorageOffset></notStruct>))
|
||||
)")
|
||||
("memberMemoryOffset", structType.memoryOffsetOfMember(structMembers[i].name).str())
|
||||
("memberSlotDiff", memberSlotDiff.str())
|
||||
("memberStorageOffset", to_string(memberStorageOffset))
|
||||
("readFromStorage",
|
||||
isStruct ?
|
||||
readFromStorage(*structMembers[i].type, memberStorageOffset, true) :
|
||||
readFromStorageDynamic(*structMembers[i].type, true)
|
||||
)
|
||||
("notStruct", !isStruct)
|
||||
.render();
|
||||
}
|
||||
|
||||
return m_functionCollector.createFunction(functionName, [&] {
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot) -> value {
|
||||
value := <allocStruct>()
|
||||
<#member>
|
||||
<setMember>
|
||||
</member>
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("allocStruct", allocateMemoryStructFunction(structType))
|
||||
("member", memberSetValues)
|
||||
.render();
|
||||
});
|
||||
}
|
||||
return m_functionCollector.createFunction(functionName, [&] {
|
||||
solAssert(_type.sizeOnStack() == 1, "");
|
||||
return Whiskers(R"(
|
||||
@ -1430,6 +1473,7 @@ string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFu
|
||||
{
|
||||
if (_type.category() == Type::Category::Function)
|
||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||
|
||||
string functionName =
|
||||
"read_from_storage_dynamic" +
|
||||
string(_splitFunctionTypes ? "split_" : "") +
|
||||
@ -2107,13 +2151,27 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
|
||||
solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), "");
|
||||
solUnimplementedAssert(toStructType.location() == DataLocation::Memory, "");
|
||||
solUnimplementedAssert(fromStructType.location() == DataLocation::CallData, "");
|
||||
solUnimplementedAssert(fromStructType.location() != DataLocation::Memory, "");
|
||||
|
||||
if (fromStructType.location() == DataLocation::CallData)
|
||||
{
|
||||
body = Whiskers(R"(
|
||||
converted := <abiDecode>(value, calldatasize())
|
||||
)")("abiDecode", ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).tupleDecoder(
|
||||
{&toStructType}
|
||||
)).render();
|
||||
}
|
||||
else
|
||||
{
|
||||
solAssert(fromStructType.location() == DataLocation::Storage, "");
|
||||
|
||||
body = Whiskers(R"(
|
||||
converted := <readFromStorage>(value)
|
||||
)")
|
||||
("readFromStorage", readFromStorage(toStructType, 0, true))
|
||||
.render();
|
||||
}
|
||||
|
||||
body = Whiskers(R"(
|
||||
converted := <abiDecode>(value, calldatasize())
|
||||
)")("abiDecode", ABIFunctions(m_evmVersion, m_revertStrings, m_functionCollector).tupleDecoder(
|
||||
{&toStructType}
|
||||
)).render();
|
||||
break;
|
||||
}
|
||||
case Type::Category::FixedBytes:
|
||||
|
@ -222,6 +222,7 @@ public:
|
||||
std::string mappingIndexAccessFunction(MappingType const& _mappingType, Type const& _keyType);
|
||||
|
||||
/// @returns a function that reads a value type from storage.
|
||||
/// Will allocate memory if return type is struct with location set to memory
|
||||
/// Performs bit mask/sign extend cleanup and appropriate left / right shift, but not validation.
|
||||
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||
/// single variable.
|
||||
|
@ -3,6 +3,7 @@ contract c {
|
||||
uint256 a;
|
||||
uint256 b;
|
||||
}
|
||||
uint[75] r;
|
||||
Struct data1;
|
||||
Struct data2;
|
||||
|
||||
@ -15,5 +16,7 @@ contract c {
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// test() -> true
|
||||
|
@ -0,0 +1,26 @@
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract C {
|
||||
struct S {
|
||||
uint32 a;
|
||||
uint128 b;
|
||||
uint256 c;
|
||||
}
|
||||
struct X {
|
||||
uint32 a;
|
||||
S s;
|
||||
}
|
||||
|
||||
uint[79] arr;
|
||||
X x = X(12, S(42, 23, 34));
|
||||
|
||||
function f() external returns (uint32, uint128, uint256) {
|
||||
X memory m = x;
|
||||
return (m.s.a, m.s.b, m.s.c);
|
||||
}
|
||||
}
|
||||
|
||||
// ====
|
||||
// compileViaYul: also
|
||||
// ----
|
||||
// f() -> 42, 23, 34
|
Loading…
Reference in New Issue
Block a user