mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9843 from ethereum/deleteStructSol2Yul
[Sol->Yul] Implementing delete struct
This commit is contained in:
@@ -33,8 +33,11 @@ string MultiUseYulFunctionCollector::requestedFunctions()
|
||||
{
|
||||
string result;
|
||||
for (auto const& f: m_requestedFunctions)
|
||||
{
|
||||
solAssert(f.second != "<<STUB<<", "");
|
||||
// std::map guarantees ascending order when iterating through its keys.
|
||||
result += f.second;
|
||||
}
|
||||
m_requestedFunctions.clear();
|
||||
return result;
|
||||
}
|
||||
@@ -43,9 +46,10 @@ string MultiUseYulFunctionCollector::createFunction(string const& _name, functio
|
||||
{
|
||||
if (!m_requestedFunctions.count(_name))
|
||||
{
|
||||
m_requestedFunctions[_name] = "<<STUB<<";
|
||||
string fun = _creator();
|
||||
solAssert(!fun.empty(), "");
|
||||
solAssert(fun.find("function " + _name) != string::npos, "Function not properly named.");
|
||||
solAssert(fun.find("function " + _name + "(") != string::npos, "Function not properly named.");
|
||||
m_requestedFunctions[_name] = std::move(fun);
|
||||
}
|
||||
return _name;
|
||||
|
||||
@@ -851,7 +851,6 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
||||
solAssert(_type.isDynamicallySized(), "");
|
||||
solUnimplementedAssert(!_type.isByteArray(), "Byte Arrays not yet implemented!");
|
||||
solUnimplementedAssert(_type.baseType()->storageBytes() <= 32, "...");
|
||||
solUnimplementedAssert(_type.baseType()->storageSize() == 1, "");
|
||||
|
||||
string functionName = "resize_array_" + _type.identifier();
|
||||
return m_functionCollector.createFunction(functionName, [&]() {
|
||||
@@ -1147,6 +1146,45 @@ string YulUtilFunctions::clearStorageArrayFunction(ArrayType const& _type)
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::clearStorageStructFunction(StructType const& _type)
|
||||
{
|
||||
solAssert(_type.location() == DataLocation::Storage, "");
|
||||
|
||||
string functionName = "clear_struct_storage_" + _type.identifier();
|
||||
|
||||
return m_functionCollector.createFunction(functionName, [&] {
|
||||
MemberList::MemberMap structMembers = _type.nativeMembers(nullptr);
|
||||
vector<map<string, string>> memberSetValues;
|
||||
|
||||
for (auto const& member: structMembers)
|
||||
{
|
||||
auto const& [memberSlotDiff, memberStorageOffset] = _type.storageOffsetsOfMember(member.name);
|
||||
|
||||
memberSetValues.emplace_back().emplace("clearMember", Whiskers(R"(
|
||||
<setZero>(add(slot, <memberSlotDiff>), <memberStorageOffset>)
|
||||
)")
|
||||
("setZero", storageSetToZeroFunction(*member.type))
|
||||
("memberSlotDiff", memberSlotDiff.str())
|
||||
("memberStorageOffset", to_string(memberStorageOffset))
|
||||
.render()
|
||||
);
|
||||
}
|
||||
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot) {
|
||||
<#member>
|
||||
<clearMember>
|
||||
</member>
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("allocStruct", allocateMemoryStructFunction(_type))
|
||||
("storageSize", _type.storageSize().str())
|
||||
("member", memberSetValues)
|
||||
.render();
|
||||
});
|
||||
}
|
||||
|
||||
string YulUtilFunctions::arrayConvertLengthToSize(ArrayType const& _type)
|
||||
{
|
||||
string functionName = "array_convert_length_to_size_" + _type.identifier();
|
||||
@@ -2346,27 +2384,32 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
|
||||
auto const& toStructType = dynamic_cast<StructType const &>(_to);
|
||||
solAssert(fromStructType.structDefinition() == toStructType.structDefinition(), "");
|
||||
|
||||
solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), "");
|
||||
solUnimplementedAssert(toStructType.location() == DataLocation::Memory, "");
|
||||
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();
|
||||
}
|
||||
if (fromStructType.location() == toStructType.location() && toStructType.isPointer())
|
||||
body = "converted := value";
|
||||
else
|
||||
{
|
||||
solAssert(fromStructType.location() == DataLocation::Storage, "");
|
||||
solUnimplementedAssert(toStructType.location() == DataLocation::Memory, "");
|
||||
solUnimplementedAssert(fromStructType.location() != DataLocation::Memory, "");
|
||||
|
||||
body = Whiskers(R"(
|
||||
converted := <readFromStorage>(value)
|
||||
)")
|
||||
("readFromStorage", readFromStorage(toStructType, 0, true))
|
||||
.render();
|
||||
if (fromStructType.location() == DataLocation::CallData)
|
||||
{
|
||||
solUnimplementedAssert(!fromStructType.isDynamicallyEncoded(), "");
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -2809,11 +2852,24 @@ string YulUtilFunctions::storageSetToZeroFunction(Type const& _type)
|
||||
else if (_type.category() == Type::Category::Array)
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot, offset) {
|
||||
if iszero(eq(offset, 0)) { <panic>() }
|
||||
<clearArray>(slot)
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("clearArray", clearStorageArrayFunction(dynamic_cast<ArrayType const&>(_type)))
|
||||
("panic", panicFunction())
|
||||
.render();
|
||||
else if (_type.category() == Type::Category::Struct)
|
||||
return Whiskers(R"(
|
||||
function <functionName>(slot, offset) {
|
||||
if iszero(eq(offset, 0)) { <panic>() }
|
||||
<clearStruct>(slot)
|
||||
}
|
||||
)")
|
||||
("functionName", functionName)
|
||||
("clearStruct", clearStorageStructFunction(dynamic_cast<StructType const&>(_type)))
|
||||
("panic", panicFunction())
|
||||
.render();
|
||||
else
|
||||
solUnimplemented("setToZero for type " + _type.identifier() + " not yet implemented!");
|
||||
|
||||
@@ -431,6 +431,10 @@ private:
|
||||
/// signature: (slot, offset)
|
||||
std::string partialClearStorageSlotFunction();
|
||||
|
||||
/// @returns the name of a function that will clear the given storage struct
|
||||
/// signature: (slot) ->
|
||||
std::string clearStorageStructFunction(StructType const& _type);
|
||||
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
RevertStrings m_revertStrings;
|
||||
MultiUseYulFunctionCollector& m_functionCollector;
|
||||
|
||||
Reference in New Issue
Block a user