|
|
@@ -2330,10 +2330,6 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|
|
|
{
|
|
|
|
{
|
|
|
|
solAssert(_toType.category() == Type::Category::Struct, "");
|
|
|
|
solAssert(_toType.category() == Type::Category::Struct, "");
|
|
|
|
|
|
|
|
|
|
|
|
solUnimplementedAssert(
|
|
|
|
|
|
|
|
fromReferenceType->location() != DataLocation::Storage,
|
|
|
|
|
|
|
|
"Copying from storage to storage is not yet implemented."
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
auto const& fromStructType = dynamic_cast<StructType const&>(_fromType);
|
|
|
|
auto const& fromStructType = dynamic_cast<StructType const&>(_fromType);
|
|
|
|
auto const& toStructType = dynamic_cast<StructType const&>(_toType);
|
|
|
|
auto const& toStructType = dynamic_cast<StructType const&>(_toType);
|
|
|
|
solAssert(fromStructType.structDefinition() == toStructType.structDefinition(), "");
|
|
|
|
solAssert(fromStructType.structDefinition() == toStructType.structDefinition(), "");
|
|
|
@@ -2341,6 +2337,7 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|
|
|
|
|
|
|
|
|
|
|
Whiskers templ(R"(
|
|
|
|
Whiskers templ(R"(
|
|
|
|
function <functionName>(slot, value) {
|
|
|
|
function <functionName>(slot, value) {
|
|
|
|
|
|
|
|
<?fromStorage> if eq(slot, value) { leave } </fromStorage>
|
|
|
|
<#member>
|
|
|
|
<#member>
|
|
|
|
{
|
|
|
|
{
|
|
|
|
<updateMemberCall>
|
|
|
|
<updateMemberCall>
|
|
|
@@ -2348,6 +2345,7 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|
|
|
</member>
|
|
|
|
</member>
|
|
|
|
}
|
|
|
|
}
|
|
|
|
)");
|
|
|
|
)");
|
|
|
|
|
|
|
|
templ("fromStorage", fromStructType.dataStoredIn(DataLocation::Storage));
|
|
|
|
templ("functionName", functionName);
|
|
|
|
templ("functionName", functionName);
|
|
|
|
|
|
|
|
|
|
|
|
MemberList::MemberMap structMembers = fromStructType.nativeMembers(nullptr);
|
|
|
|
MemberList::MemberMap structMembers = fromStructType.nativeMembers(nullptr);
|
|
|
@@ -2356,67 +2354,81 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|
|
|
vector<map<string, string>> memberParams(structMembers.size());
|
|
|
|
vector<map<string, string>> memberParams(structMembers.size());
|
|
|
|
for (size_t i = 0; i < structMembers.size(); ++i)
|
|
|
|
for (size_t i = 0; i < structMembers.size(); ++i)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
solAssert(structMembers[i].type->memoryHeadSize() == 32, "");
|
|
|
|
Type const& memberType = *structMembers[i].type;
|
|
|
|
bool fromCalldata = fromStructType.location() == DataLocation::CallData;
|
|
|
|
solAssert(memberType.memoryHeadSize() == 32, "");
|
|
|
|
auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(structMembers[i].name);
|
|
|
|
auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(structMembers[i].name);
|
|
|
|
|
|
|
|
|
|
|
|
Whiskers t(R"(
|
|
|
|
Whiskers t(R"(
|
|
|
|
let memberSlot := add(slot, <memberStorageSlotDiff>)
|
|
|
|
let memberSlot := add(slot, <memberStorageSlotDiff>)
|
|
|
|
|
|
|
|
let memberSrcPtr := add(value, <memberOffset>)
|
|
|
|
|
|
|
|
|
|
|
|
<?fromCalldata>
|
|
|
|
<?fromCalldata>
|
|
|
|
<?dynamicallyEncodedMember>
|
|
|
|
let <memberValues> :=
|
|
|
|
let <memberCalldataOffset> := <accessCalldataTail>(value, add(value, <memberOffset>))
|
|
|
|
<?dynamicallyEncodedMember>
|
|
|
|
<!dynamicallyEncodedMember>
|
|
|
|
<accessCalldataTail>(value, memberSrcPtr)
|
|
|
|
let <memberCalldataOffset> := add(value, <memberOffset>)
|
|
|
|
<!dynamicallyEncodedMember>
|
|
|
|
</dynamicallyEncodedMember>
|
|
|
|
memberSrcPtr
|
|
|
|
|
|
|
|
</dynamicallyEncodedMember>
|
|
|
|
|
|
|
|
|
|
|
|
<?isValueType>
|
|
|
|
<?isValueType>
|
|
|
|
let <memberValues> := <loadFromMemoryOrCalldata>(<memberCalldataOffset>)
|
|
|
|
<memberValues> := <read>(<memberValues>)
|
|
|
|
<updateMember>(memberSlot, <memberStorageOffset>, <memberValues>)
|
|
|
|
|
|
|
|
<!isValueType>
|
|
|
|
|
|
|
|
<updateMember>(memberSlot, <memberCalldataOffset>)
|
|
|
|
|
|
|
|
</isValueType>
|
|
|
|
</isValueType>
|
|
|
|
<!fromCalldata>
|
|
|
|
|
|
|
|
let memberMemoryOffset := add(value, <memberOffset>)
|
|
|
|
|
|
|
|
let <memberValues> := <loadFromMemoryOrCalldata>(memberMemoryOffset)
|
|
|
|
|
|
|
|
<updateMember>(memberSlot, <?hasOffset><memberStorageOffset>,</hasOffset> <memberValues>)
|
|
|
|
|
|
|
|
</fromCalldata>
|
|
|
|
</fromCalldata>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<?fromMemory>
|
|
|
|
|
|
|
|
let <memberValues> := <read>(memberSrcPtr)
|
|
|
|
|
|
|
|
</fromMemory>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<?fromStorage>
|
|
|
|
|
|
|
|
let <memberValues> :=
|
|
|
|
|
|
|
|
<?isValueType>
|
|
|
|
|
|
|
|
<read>(memberSrcPtr)
|
|
|
|
|
|
|
|
<!isValueType>
|
|
|
|
|
|
|
|
memberSrcPtr
|
|
|
|
|
|
|
|
</isValueType>
|
|
|
|
|
|
|
|
</fromStorage>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<updateStorageValue>(memberSlot, <memberValues>)
|
|
|
|
)");
|
|
|
|
)");
|
|
|
|
|
|
|
|
bool fromCalldata = fromStructType.location() == DataLocation::CallData;
|
|
|
|
t("fromCalldata", fromCalldata);
|
|
|
|
t("fromCalldata", fromCalldata);
|
|
|
|
|
|
|
|
bool fromMemory = fromStructType.location() == DataLocation::Memory;
|
|
|
|
|
|
|
|
t("fromMemory", fromMemory);
|
|
|
|
|
|
|
|
bool fromStorage = fromStructType.location() == DataLocation::Storage;
|
|
|
|
|
|
|
|
t("fromStorage", fromStorage);
|
|
|
|
|
|
|
|
t("isValueType", memberType.isValueType());
|
|
|
|
|
|
|
|
t("memberValues", suffixedVariableNameList("memberValue_", 0, memberType.stackItems().size()));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
t("memberStorageSlotDiff", slotDiff.str());
|
|
|
|
if (fromCalldata)
|
|
|
|
if (fromCalldata)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
t("memberCalldataOffset", suffixedVariableNameList(
|
|
|
|
t("memberOffset", to_string(fromStructType.calldataOffsetOfMember(structMembers[i].name)));
|
|
|
|
"memberCalldataOffset_",
|
|
|
|
t("dynamicallyEncodedMember", memberType.isDynamicallyEncoded());
|
|
|
|
0,
|
|
|
|
if (memberType.isDynamicallyEncoded())
|
|
|
|
structMembers[i].type->stackItems().size()
|
|
|
|
t("accessCalldataTail", accessCalldataTailFunction(memberType));
|
|
|
|
));
|
|
|
|
if (memberType.isValueType())
|
|
|
|
t("dynamicallyEncodedMember", structMembers[i].type->isDynamicallyEncoded());
|
|
|
|
t("read", readFromCalldata(memberType));
|
|
|
|
if (structMembers[i].type->isDynamicallyEncoded())
|
|
|
|
|
|
|
|
t("accessCalldataTail", accessCalldataTailFunction(*structMembers[i].type));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
t("isValueType", structMembers[i].type->isValueType());
|
|
|
|
else if (fromMemory)
|
|
|
|
t("memberValues", suffixedVariableNameList(
|
|
|
|
{
|
|
|
|
"memberValue_",
|
|
|
|
t("memberOffset", fromStructType.memoryOffsetOfMember(structMembers[i].name).str());
|
|
|
|
0,
|
|
|
|
t("read", readFromMemory(memberType));
|
|
|
|
structMembers[i].type->stackItems().size()
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (fromStorage)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
auto [srcSlotOffset, srcOffset] = fromStructType.storageOffsetsOfMember(structMembers[i].name);
|
|
|
|
|
|
|
|
t("memberOffset", formatNumber(srcSlotOffset));
|
|
|
|
|
|
|
|
if (memberType.isValueType())
|
|
|
|
|
|
|
|
t("read", readFromStorageValueType(memberType, srcOffset, false));
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
solAssert(srcOffset == 0, "");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
t("updateStorageValue", updateStorageValueFunction(
|
|
|
|
|
|
|
|
memberType,
|
|
|
|
|
|
|
|
*toStructMembers[i].type,
|
|
|
|
|
|
|
|
memberType.isValueType() ? optional<unsigned>{offset} : std::nullopt
|
|
|
|
));
|
|
|
|
));
|
|
|
|
t("hasOffset", structMembers[i].type->isValueType());
|
|
|
|
|
|
|
|
t(
|
|
|
|
|
|
|
|
"updateMember",
|
|
|
|
|
|
|
|
structMembers[i].type->isValueType() ?
|
|
|
|
|
|
|
|
updateStorageValueFunction(*structMembers[i].type, *toStructMembers[i].type) :
|
|
|
|
|
|
|
|
updateStorageValueFunction(*structMembers[i].type, *toStructMembers[i].type, offset)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
t("memberStorageSlotDiff", slotDiff.str());
|
|
|
|
|
|
|
|
t("memberStorageOffset", to_string(offset));
|
|
|
|
|
|
|
|
t(
|
|
|
|
|
|
|
|
"memberOffset",
|
|
|
|
|
|
|
|
fromCalldata ?
|
|
|
|
|
|
|
|
to_string(fromStructType.calldataOffsetOfMember(structMembers[i].name)) :
|
|
|
|
|
|
|
|
fromStructType.memoryOffsetOfMember(structMembers[i].name).str()
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!fromCalldata || structMembers[i].type->isValueType())
|
|
|
|
|
|
|
|
t("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*structMembers[i].type, fromCalldata));
|
|
|
|
|
|
|
|
memberParams[i]["updateMemberCall"] = t.render();
|
|
|
|
memberParams[i]["updateMemberCall"] = t.render();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
templ("member", memberParams);
|
|
|
|
templ("member", memberParams);
|
|
|
|