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) +
|
to_string(_offset) +
|
||||||
"_" +
|
"_" +
|
||||||
_type.identifier();
|
_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, [&] {
|
return m_functionCollector.createFunction(functionName, [&] {
|
||||||
solAssert(_type.sizeOnStack() == 1, "");
|
solAssert(_type.sizeOnStack() == 1, "");
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
@ -1430,6 +1473,7 @@ string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFu
|
|||||||
{
|
{
|
||||||
if (_type.category() == Type::Category::Function)
|
if (_type.category() == Type::Category::Function)
|
||||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||||
|
|
||||||
string functionName =
|
string functionName =
|
||||||
"read_from_storage_dynamic" +
|
"read_from_storage_dynamic" +
|
||||||
string(_splitFunctionTypes ? "split_" : "") +
|
string(_splitFunctionTypes ? "split_" : "") +
|
||||||
@ -2107,13 +2151,27 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
|||||||
|
|
||||||
solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), "");
|
solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), "");
|
||||||
solUnimplementedAssert(toStructType.location() == DataLocation::Memory, "");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::FixedBytes:
|
case Type::Category::FixedBytes:
|
||||||
|
@ -222,6 +222,7 @@ public:
|
|||||||
std::string mappingIndexAccessFunction(MappingType const& _mappingType, Type const& _keyType);
|
std::string mappingIndexAccessFunction(MappingType const& _mappingType, Type const& _keyType);
|
||||||
|
|
||||||
/// @returns a function that reads a value type from storage.
|
/// @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.
|
/// 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
|
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||||
/// single variable.
|
/// single variable.
|
||||||
|
@ -3,6 +3,7 @@ contract c {
|
|||||||
uint256 a;
|
uint256 a;
|
||||||
uint256 b;
|
uint256 b;
|
||||||
}
|
}
|
||||||
|
uint[75] r;
|
||||||
Struct data1;
|
Struct data1;
|
||||||
Struct data2;
|
Struct data2;
|
||||||
|
|
||||||
@ -15,5 +16,7 @@ contract c {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// test() -> true
|
// 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