mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Implementing struct copying from calldata to storage
This commit is contained in:
parent
762e3f3cee
commit
23f6369a46
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Language Features:
|
Language Features:
|
||||||
* Allow function definitions outside of contracts, behaving much like internal library functions.
|
* Allow function definitions outside of contracts, behaving much like internal library functions.
|
||||||
|
* Code generator: Implementing copying structs from calldata to storage.
|
||||||
|
|
||||||
Compiler Features:
|
Compiler Features:
|
||||||
* SMTChecker: Add underflow and overflow as verification conditions in the CHC engine.
|
* SMTChecker: Add underflow and overflow as verification conditions in the CHC engine.
|
||||||
|
@ -357,7 +357,15 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
|||||||
"Struct assignment with conversion."
|
"Struct assignment with conversion."
|
||||||
);
|
);
|
||||||
solAssert(!structType.containsNestedMapping(), "");
|
solAssert(!structType.containsNestedMapping(), "");
|
||||||
solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
|
if (sourceType.location() == DataLocation::CallData)
|
||||||
|
{
|
||||||
|
solAssert(sourceType.sizeOnStack() == 1, "");
|
||||||
|
solAssert(structType.sizeOnStack() == 1, "");
|
||||||
|
m_context << Instruction::DUP2 << Instruction::DUP2;
|
||||||
|
m_context.callYulFunction(m_context.utilFunctions().updateStorageValueFunction(structType, &sourceType, 0), 2, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
for (auto const& member: structType.members(nullptr))
|
for (auto const& member: structType.members(nullptr))
|
||||||
{
|
{
|
||||||
// assign each member that can live outside of storage
|
// assign each member that can live outside of storage
|
||||||
@ -390,6 +398,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
|||||||
// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
|
// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
|
||||||
StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true);
|
StorageItem(m_context, *memberType).storeValue(*sourceMemberType, _location, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// stack layout: source_ref target_ref
|
// stack layout: source_ref target_ref
|
||||||
solAssert(sourceType.sizeOnStack() == 1, "Unexpected source size.");
|
solAssert(sourceType.sizeOnStack() == 1, "Unexpected source size.");
|
||||||
if (_move)
|
if (_move)
|
||||||
|
@ -1553,11 +1553,6 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|||||||
|
|
||||||
Whiskers templ(R"(
|
Whiskers templ(R"(
|
||||||
function <functionName>(slot, value) {
|
function <functionName>(slot, value) {
|
||||||
<?fromCalldata>
|
|
||||||
let valueMem := <convertToMemory>(value)
|
|
||||||
<!fromCalldata>
|
|
||||||
let valueMem := value
|
|
||||||
</fromCalldata>
|
|
||||||
<#member>
|
<#member>
|
||||||
{
|
{
|
||||||
<updateMemberCall>
|
<updateMemberCall>
|
||||||
@ -1566,12 +1561,6 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|||||||
}
|
}
|
||||||
)");
|
)");
|
||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
templ("fromCalldata", fromStructType.location() == DataLocation::CallData);
|
|
||||||
if (fromStructType.location() == DataLocation::CallData)
|
|
||||||
templ("convertToMemory", conversionFunction(
|
|
||||||
fromStructType,
|
|
||||||
*TypeProvider::structType(toStructType.structDefinition(), DataLocation::Memory)
|
|
||||||
));
|
|
||||||
|
|
||||||
MemberList::MemberMap toStructMembers = toStructType.nativeMembers(nullptr);
|
MemberList::MemberMap toStructMembers = toStructType.nativeMembers(nullptr);
|
||||||
MemberList::MemberMap fromStructMembers = fromStructType.nativeMembers(nullptr);
|
MemberList::MemberMap fromStructMembers = fromStructType.nativeMembers(nullptr);
|
||||||
@ -1581,9 +1570,10 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|||||||
{
|
{
|
||||||
solAssert(toStructMembers[i].type->memoryHeadSize() == 32, "");
|
solAssert(toStructMembers[i].type->memoryHeadSize() == 32, "");
|
||||||
bool isStruct = toStructMembers[i].type->category() == Type::Category::Struct;
|
bool isStruct = toStructMembers[i].type->category() == Type::Category::Struct;
|
||||||
|
bool fromCalldata = fromStructType.location() == DataLocation::CallData;
|
||||||
auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(toStructMembers[i].name);
|
auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(toStructMembers[i].name);
|
||||||
memberParams[i]["updateMemberCall"] = Whiskers(R"(
|
memberParams[i]["updateMemberCall"] = Whiskers(R"(
|
||||||
let memberValue := <loadFromMemory>(add(valueMem, <memberMemoryOffset>))
|
let memberValue := <loadFromMemoryOrCalldata>(add(value, <memberOffset>))
|
||||||
<updateMember>(add(slot, <memberStorageSlotDiff>), <?hasOffset><memberStorageOffset>,</hasOffset> memberValue)
|
<updateMember>(add(slot, <memberStorageSlotDiff>), <?hasOffset><memberStorageOffset>,</hasOffset> memberValue)
|
||||||
)")
|
)")
|
||||||
("hasOffset", !isStruct)
|
("hasOffset", !isStruct)
|
||||||
@ -1595,8 +1585,12 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|||||||
)
|
)
|
||||||
("memberStorageSlotDiff", slotDiff.str())
|
("memberStorageSlotDiff", slotDiff.str())
|
||||||
("memberStorageOffset", to_string(offset))
|
("memberStorageOffset", to_string(offset))
|
||||||
("memberMemoryOffset", fromStructType.memoryOffsetOfMember(fromStructMembers[i].name).str())
|
("memberOffset",
|
||||||
("loadFromMemory", readFromMemory(*fromStructMembers[i].type))
|
fromCalldata ?
|
||||||
|
to_string(fromStructType.calldataOffsetOfMember(fromStructMembers[i].name)) :
|
||||||
|
fromStructType.memoryOffsetOfMember(fromStructMembers[i].name).str()
|
||||||
|
)
|
||||||
|
("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*fromStructMembers[i].type, fromCalldata))
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
templ("member", memberParams);
|
templ("member", memberParams);
|
||||||
|
@ -3,10 +3,11 @@ pragma experimental ABIEncoderV2;
|
|||||||
contract C {
|
contract C {
|
||||||
struct S {
|
struct S {
|
||||||
uint256 a;
|
uint256 a;
|
||||||
uint256 b;
|
uint64 b;
|
||||||
bytes2 c;
|
bytes2 c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint[153] r;
|
||||||
S s;
|
S s;
|
||||||
|
|
||||||
function f(uint32 a, S calldata c, uint256 b) external returns (uint256, uint256, byte) {
|
function f(uint32 a, S calldata c, uint256 b) external returns (uint256, uint256, byte) {
|
||||||
@ -16,6 +17,6 @@ contract C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ====
|
// ====
|
||||||
// compileViaYul: true
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f(uint32, (uint256, uint256, bytes2), uint256): 1, 42, 23, "ab", 1 -> 42, 23, "b"
|
// f(uint32, (uint256, uint64, bytes2), uint256): 1, 42, 23, "ab", 1 -> 42, 23, "b"
|
Loading…
Reference in New Issue
Block a user