mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9905 from ethereum/deleteArrayPackedSol2Yul
[Sol->Yul] Implementing deleting of storage array of types that are packed in storage
This commit is contained in:
commit
e5771efdf8
@ -873,6 +873,12 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
|||||||
let arrayDataStart := <dataPosition>(array)
|
let arrayDataStart := <dataPosition>(array)
|
||||||
let deleteStart := add(arrayDataStart, newSlotCount)
|
let deleteStart := add(arrayDataStart, newSlotCount)
|
||||||
let deleteEnd := add(arrayDataStart, oldSlotCount)
|
let deleteEnd := add(arrayDataStart, oldSlotCount)
|
||||||
|
<?packed>
|
||||||
|
// if we are dealing with packed array and offset is greater than zero
|
||||||
|
// we have to partially clear last slot that is still used, so decreasing start by one
|
||||||
|
let offset := mul(mod(newLen, <itemsPerSlot>), <storageBytes>)
|
||||||
|
if gt(offset, 0) { <partialClearStorageSlot>(sub(deleteStart, 1), offset) }
|
||||||
|
</packed>
|
||||||
<clearStorageRange>(deleteStart, deleteEnd)
|
<clearStorageRange>(deleteStart, deleteEnd)
|
||||||
}
|
}
|
||||||
})")
|
})")
|
||||||
@ -883,6 +889,10 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
|
|||||||
("dataPosition", arrayDataAreaFunction(_type))
|
("dataPosition", arrayDataAreaFunction(_type))
|
||||||
("clearStorageRange", clearStorageRangeFunction(*_type.baseType()))
|
("clearStorageRange", clearStorageRangeFunction(*_type.baseType()))
|
||||||
("maxArrayLength", (u256(1) << 64).str())
|
("maxArrayLength", (u256(1) << 64).str())
|
||||||
|
("packed", _type.baseType()->storageBytes() <= 16)
|
||||||
|
("itemsPerSlot", to_string(32 / _type.baseType()->storageBytes()))
|
||||||
|
("storageBytes", to_string(_type.baseType()->storageBytes()))
|
||||||
|
("partialClearStorageSlot", partialClearStorageSlotFunction())
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1060,11 +1070,29 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string YulUtilFunctions::partialClearStorageSlotFunction()
|
||||||
|
{
|
||||||
|
string functionName = "partial_clear_storage_slot";
|
||||||
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
|
return Whiskers(R"(
|
||||||
|
function <functionName>(slot, offset) {
|
||||||
|
let mask := <shr>(mul(8, sub(32, offset)), <ones>)
|
||||||
|
sstore(slot, and(mask, sload(slot)))
|
||||||
|
}
|
||||||
|
)")
|
||||||
|
("functionName", functionName)
|
||||||
|
("ones", formatNumber((bigint(1) << 256) - 1))
|
||||||
|
("shr", shiftRightFunctionDynamic())
|
||||||
|
.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
string YulUtilFunctions::clearStorageRangeFunction(Type const& _type)
|
string YulUtilFunctions::clearStorageRangeFunction(Type const& _type)
|
||||||
{
|
{
|
||||||
string functionName = "clear_storage_range_" + _type.identifier();
|
if (_type.storageBytes() < 32)
|
||||||
|
solAssert(_type.isValueType(), "");
|
||||||
|
|
||||||
solAssert(_type.storageBytes() >= 32, "Expected smaller value for storage bytes");
|
string functionName = "clear_storage_range_" + _type.identifier();
|
||||||
|
|
||||||
return m_functionCollector.createFunction(functionName, [&]() {
|
return m_functionCollector.createFunction(functionName, [&]() {
|
||||||
return Whiskers(R"(
|
return Whiskers(R"(
|
||||||
@ -1076,7 +1104,7 @@ string YulUtilFunctions::clearStorageRangeFunction(Type const& _type)
|
|||||||
}
|
}
|
||||||
)")
|
)")
|
||||||
("functionName", functionName)
|
("functionName", functionName)
|
||||||
("setToZero", storageSetToZeroFunction(_type))
|
("setToZero", storageSetToZeroFunction(_type.storageBytes() < 32 ? *TypeProvider::uint256() : _type))
|
||||||
("increment", _type.storageSize().str())
|
("increment", _type.storageSize().str())
|
||||||
.render();
|
.render();
|
||||||
});
|
});
|
||||||
|
@ -422,6 +422,11 @@ private:
|
|||||||
/// @returns a function that reads a reference type from storage to memory (performing a deep copy).
|
/// @returns a function that reads a reference type from storage to memory (performing a deep copy).
|
||||||
std::string readFromStorageReferenceType(Type const& _type);
|
std::string readFromStorageReferenceType(Type const& _type);
|
||||||
|
|
||||||
|
/// @returns the name of a function that will clear given storage slot
|
||||||
|
/// starting with given offset until the end of the slot
|
||||||
|
/// signature: (slot, offset)
|
||||||
|
std::string partialClearStorageSlotFunction();
|
||||||
|
|
||||||
langutil::EVMVersion m_evmVersion;
|
langutil::EVMVersion m_evmVersion;
|
||||||
RevertStrings m_revertStrings;
|
RevertStrings m_revertStrings;
|
||||||
MultiUseYulFunctionCollector& m_functionCollector;
|
MultiUseYulFunctionCollector& m_functionCollector;
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
contract C {
|
||||||
|
uint120[] data;
|
||||||
|
|
||||||
|
function f() public returns (uint120, uint120, uint120) {
|
||||||
|
data.push(123);
|
||||||
|
data.push(234);
|
||||||
|
data.push(345);
|
||||||
|
delete data;
|
||||||
|
assembly {
|
||||||
|
sstore(data.slot, 3)
|
||||||
|
}
|
||||||
|
return (data[0], data[1], data[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// compileViaYul: also
|
||||||
|
// ----
|
||||||
|
// f() -> 0, 0, 0
|
Loading…
Reference in New Issue
Block a user