mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Refactoring readFromStorage util frunctions
Co-authored-by: Daniel Kirchner <daniel@ekpyron.org>
This commit is contained in:
parent
23f6369a46
commit
15163b2270
@ -1404,6 +1404,25 @@ string YulUtilFunctions::mappingIndexAccessFunction(MappingType const& _mappingT
|
|||||||
|
|
||||||
string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
||||||
{
|
{
|
||||||
|
if (_type.isValueType())
|
||||||
|
return readFromStorageValueType(_type, _offset, _splitFunctionTypes);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(_offset == 0, "");
|
||||||
|
return readFromStorageReferenceType(_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes)
|
||||||
|
{
|
||||||
|
solAssert(_type.isValueType(), "");
|
||||||
|
return readFromStorageValueTypeDynamic(_type, _splitFunctionTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::readFromStorageValueType(Type const& _type, size_t _offset, bool _splitFunctionTypes)
|
||||||
|
{
|
||||||
|
solAssert(_type.isValueType(), "");
|
||||||
|
|
||||||
if (_type.category() == Type::Category::Function)
|
if (_type.category() == Type::Category::Function)
|
||||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||||
string functionName =
|
string functionName =
|
||||||
@ -1414,30 +1433,72 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool
|
|||||||
"_" +
|
"_" +
|
||||||
_type.identifier();
|
_type.identifier();
|
||||||
|
|
||||||
if (_type.category() == Type::Category::Struct)
|
return m_functionCollector.createFunction(functionName, [&] {
|
||||||
{
|
solAssert(_type.sizeOnStack() == 1, "");
|
||||||
solAssert(_offset == 0, "");
|
return Whiskers(R"(
|
||||||
|
function <functionName>(slot) -> value {
|
||||||
|
value := <extract>(sload(slot))
|
||||||
|
}
|
||||||
|
)")
|
||||||
|
("functionName", functionName)
|
||||||
|
("extract", extractFromStorageValue(_type, _offset, false))
|
||||||
|
.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
string YulUtilFunctions::readFromStorageValueTypeDynamic(Type const& _type, bool _splitFunctionTypes)
|
||||||
|
{
|
||||||
|
solAssert(_type.isValueType(), "");
|
||||||
|
if (_type.category() == Type::Category::Function)
|
||||||
|
solUnimplementedAssert(!_splitFunctionTypes, "");
|
||||||
|
|
||||||
|
string functionName =
|
||||||
|
"read_from_storage_value_type_dynamic" +
|
||||||
|
string(_splitFunctionTypes ? "split_" : "") +
|
||||||
|
"_" +
|
||||||
|
_type.identifier();
|
||||||
|
return m_functionCollector.createFunction(functionName, [&] {
|
||||||
|
solAssert(_type.sizeOnStack() == 1, "");
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>(slot, offset) -> value {
|
||||||
|
value := <extract>(sload(slot), offset)
|
||||||
|
}
|
||||||
|
)")
|
||||||
|
("functionName", functionName)
|
||||||
|
("extract", extractFromStorageValueDynamic(_type, _splitFunctionTypes))
|
||||||
|
.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
string YulUtilFunctions::readFromStorageReferenceType(Type const& _type)
|
||||||
|
{
|
||||||
|
solUnimplementedAssert(_type.category() == Type::Category::Struct, "");
|
||||||
|
|
||||||
|
string functionName = "read_from_storage_reference_type_" + _type.identifier();
|
||||||
|
|
||||||
auto const& structType = dynamic_cast<StructType const&>(_type);
|
auto const& structType = dynamic_cast<StructType const&>(_type);
|
||||||
solUnimplementedAssert(structType.location() == DataLocation::Memory, "");
|
solAssert(structType.location() == DataLocation::Memory, "");
|
||||||
MemberList::MemberMap structMembers = structType.nativeMembers(nullptr);
|
MemberList::MemberMap structMembers = structType.nativeMembers(nullptr);
|
||||||
vector<map<string, string>> memberSetValues(structMembers.size());
|
vector<map<string, string>> memberSetValues(structMembers.size());
|
||||||
for (size_t i = 0; i < structMembers.size(); ++i)
|
for (size_t i = 0; i < structMembers.size(); ++i)
|
||||||
{
|
{
|
||||||
auto const& [memberSlotDiff, memberStorageOffset] = structType.storageOffsetsOfMember(structMembers[i].name);
|
auto const& [memberSlotDiff, memberStorageOffset] = structType.storageOffsetsOfMember(structMembers[i].name);
|
||||||
bool isStruct = structMembers[i].type->category() == Type::Category::Struct;
|
|
||||||
|
|
||||||
memberSetValues[i]["setMember"] = Whiskers(R"(
|
memberSetValues[i]["setMember"] = Whiskers(R"(
|
||||||
mstore(add(value, <memberMemoryOffset>), <readFromStorage>(add(slot, <memberSlotDiff>)<?hasOffset>, <memberStorageOffset></hasOffset>))
|
{
|
||||||
|
let <memberValues> := <readFromStorage>(add(slot, <memberSlotDiff>)<?hasOffset>, <memberStorageOffset></hasOffset>)
|
||||||
|
<writeToMemory>(add(value, <memberMemoryOffset>), <memberValues>)
|
||||||
|
}
|
||||||
)")
|
)")
|
||||||
|
("memberValues", suffixedVariableNameList("memberValue_", 0, structMembers[i].type->stackItems().size()))
|
||||||
("memberMemoryOffset", structType.memoryOffsetOfMember(structMembers[i].name).str())
|
("memberMemoryOffset", structType.memoryOffsetOfMember(structMembers[i].name).str())
|
||||||
("memberSlotDiff", memberSlotDiff.str())
|
("memberSlotDiff", memberSlotDiff.str())
|
||||||
("memberStorageOffset", to_string(memberStorageOffset))
|
("memberStorageOffset", to_string(memberStorageOffset))
|
||||||
("readFromStorage",
|
("readFromStorage",
|
||||||
isStruct ?
|
structMembers[i].type->isValueType() ?
|
||||||
readFromStorage(*structMembers[i].type, memberStorageOffset, true) :
|
readFromStorageDynamic(*structMembers[i].type, true) :
|
||||||
readFromStorageDynamic(*structMembers[i].type, true)
|
readFromStorage(*structMembers[i].type, memberStorageOffset, true)
|
||||||
)
|
)
|
||||||
("hasOffset", !isStruct)
|
("writeToMemory", writeToMemoryFunction(*structMembers[i].type))
|
||||||
|
("hasOffset", structMembers[i].type->isValueType())
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1455,41 +1516,6 @@ string YulUtilFunctions::readFromStorage(Type const& _type, size_t _offset, bool
|
|||||||
("member", memberSetValues)
|
("member", memberSetValues)
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
return m_functionCollector.createFunction(functionName, [&] {
|
|
||||||
solAssert(_type.sizeOnStack() == 1, "");
|
|
||||||
return Whiskers(R"(
|
|
||||||
function <functionName>(slot) -> value {
|
|
||||||
value := <extract>(sload(slot))
|
|
||||||
}
|
|
||||||
)")
|
|
||||||
("functionName", functionName)
|
|
||||||
("extract", extractFromStorageValue(_type, _offset, false))
|
|
||||||
.render();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
string YulUtilFunctions::readFromStorageDynamic(Type const& _type, bool _splitFunctionTypes)
|
|
||||||
{
|
|
||||||
if (_type.category() == Type::Category::Function)
|
|
||||||
solUnimplementedAssert(!_splitFunctionTypes, "");
|
|
||||||
|
|
||||||
string functionName =
|
|
||||||
"read_from_storage_dynamic" +
|
|
||||||
string(_splitFunctionTypes ? "split_" : "") +
|
|
||||||
"_" +
|
|
||||||
_type.identifier();
|
|
||||||
return m_functionCollector.createFunction(functionName, [&] {
|
|
||||||
solAssert(_type.sizeOnStack() == 1, "");
|
|
||||||
return Whiskers(R"(
|
|
||||||
function <functionName>(slot, offset) -> value {
|
|
||||||
value := <extract>(sload(slot), offset)
|
|
||||||
}
|
|
||||||
)")
|
|
||||||
("functionName", functionName)
|
|
||||||
("extract", extractFromStorageValueDynamic(_type, _splitFunctionTypes))
|
|
||||||
.render();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::readFromMemory(Type const& _type)
|
string YulUtilFunctions::readFromMemory(Type const& _type)
|
||||||
@ -1562,35 +1588,33 @@ string YulUtilFunctions::updateStorageValueFunction(
|
|||||||
)");
|
)");
|
||||||
templ("functionName", functionName);
|
templ("functionName", functionName);
|
||||||
|
|
||||||
MemberList::MemberMap toStructMembers = toStructType.nativeMembers(nullptr);
|
MemberList::MemberMap structMembers = fromStructType.nativeMembers(nullptr);
|
||||||
MemberList::MemberMap fromStructMembers = fromStructType.nativeMembers(nullptr);
|
|
||||||
|
|
||||||
vector<map<string, string>> memberParams(toStructMembers.size());
|
vector<map<string, string>> memberParams(structMembers.size());
|
||||||
for (size_t i = 0; i < toStructMembers.size(); ++i)
|
for (size_t i = 0; i < structMembers.size(); ++i)
|
||||||
{
|
{
|
||||||
solAssert(toStructMembers[i].type->memoryHeadSize() == 32, "");
|
solAssert(structMembers[i].type->memoryHeadSize() == 32, "");
|
||||||
bool isStruct = toStructMembers[i].type->category() == Type::Category::Struct;
|
|
||||||
bool fromCalldata = fromStructType.location() == DataLocation::CallData;
|
bool fromCalldata = fromStructType.location() == DataLocation::CallData;
|
||||||
auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(toStructMembers[i].name);
|
auto const& [slotDiff, offset] = toStructType.storageOffsetsOfMember(structMembers[i].name);
|
||||||
memberParams[i]["updateMemberCall"] = Whiskers(R"(
|
memberParams[i]["updateMemberCall"] = Whiskers(R"(
|
||||||
let memberValue := <loadFromMemoryOrCalldata>(add(value, <memberOffset>))
|
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", structMembers[i].type->isValueType())
|
||||||
(
|
(
|
||||||
"updateMember",
|
"updateMember",
|
||||||
isStruct ?
|
structMembers[i].type->isValueType() ?
|
||||||
updateStorageValueFunction(*toStructMembers[i].type, fromStructMembers[i].type, offset) :
|
updateStorageValueFunction(*structMembers[i].type, structMembers[i].type) :
|
||||||
updateStorageValueFunction(*toStructMembers[i].type, fromStructMembers[i].type)
|
updateStorageValueFunction(*structMembers[i].type, structMembers[i].type, offset)
|
||||||
)
|
)
|
||||||
("memberStorageSlotDiff", slotDiff.str())
|
("memberStorageSlotDiff", slotDiff.str())
|
||||||
("memberStorageOffset", to_string(offset))
|
("memberStorageOffset", to_string(offset))
|
||||||
("memberOffset",
|
("memberOffset",
|
||||||
fromCalldata ?
|
fromCalldata ?
|
||||||
to_string(fromStructType.calldataOffsetOfMember(fromStructMembers[i].name)) :
|
to_string(fromStructType.calldataOffsetOfMember(structMembers[i].name)) :
|
||||||
fromStructType.memoryOffsetOfMember(fromStructMembers[i].name).str()
|
fromStructType.memoryOffsetOfMember(structMembers[i].name).str()
|
||||||
)
|
)
|
||||||
("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*fromStructMembers[i].type, fromCalldata))
|
("loadFromMemoryOrCalldata", readFromMemoryOrCalldata(*structMembers[i].type, fromCalldata))
|
||||||
.render();
|
.render();
|
||||||
}
|
}
|
||||||
templ("member", memberParams);
|
templ("member", memberParams);
|
||||||
|
@ -221,9 +221,7 @@ public:
|
|||||||
/// @param _keyType the type of the value provided
|
/// @param _keyType the type of the value provided
|
||||||
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 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
|
/// @param _splitFunctionTypes if false, returns the address and function signature in a
|
||||||
/// single variable.
|
/// single variable.
|
||||||
std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes);
|
std::string readFromStorage(Type const& _type, size_t _offset, bool _splitFunctionTypes);
|
||||||
@ -406,6 +404,16 @@ private:
|
|||||||
|
|
||||||
std::string readFromMemoryOrCalldata(Type const& _type, bool _fromCalldata);
|
std::string readFromMemoryOrCalldata(Type const& _type, bool _fromCalldata);
|
||||||
|
|
||||||
|
/// @returns a function that reads a value type from storage.
|
||||||
|
/// 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.
|
||||||
|
std::string readFromStorageValueType(Type const& _type, size_t _offset, bool _splitFunctionTypes);
|
||||||
|
std::string readFromStorageValueTypeDynamic(Type const& _type, bool _splitFunctionTypes);
|
||||||
|
|
||||||
|
/// @returns a function that reads a reference type from storage to memory (performing a deep copy).
|
||||||
|
std::string readFromStorageReferenceType(Type const& _type);
|
||||||
|
|
||||||
langutil::EVMVersion m_evmVersion;
|
langutil::EVMVersion m_evmVersion;
|
||||||
RevertStrings m_revertStrings;
|
RevertStrings m_revertStrings;
|
||||||
MultiUseYulFunctionCollector& m_functionCollector;
|
MultiUseYulFunctionCollector& m_functionCollector;
|
||||||
|
Loading…
Reference in New Issue
Block a user