[Sol->Yul] Implementing array resizing for packed array types.

This commit is contained in:
Djordje Mijovic 2020-09-18 15:10:23 +02:00
parent b34465c5ef
commit aa23ebc8e6
2 changed files with 36 additions and 3 deletions

View File

@ -873,6 +873,12 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
let arrayDataStart := <dataPosition>(array)
let deleteStart := add(arrayDataStart, newSlotCount)
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)
}
})")
@ -883,6 +889,10 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
("dataPosition", arrayDataAreaFunction(_type))
("clearStorageRange", clearStorageRangeFunction(*_type.baseType()))
("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();
});
}
@ -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 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 Whiskers(R"(
@ -1076,7 +1104,7 @@ string YulUtilFunctions::clearStorageRangeFunction(Type const& _type)
}
)")
("functionName", functionName)
("setToZero", storageSetToZeroFunction(_type))
("setToZero", storageSetToZeroFunction(_type.storageBytes() < 32 ? *TypeProvider::uint256() : _type))
("increment", _type.storageSize().str())
.render();
});

View File

@ -422,6 +422,11 @@ private:
/// @returns a function that reads a reference type from storage to memory (performing a deep copy).
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;
RevertStrings m_revertStrings;
MultiUseYulFunctionCollector& m_functionCollector;