From aa23ebc8e6df52c87060d3c824a549ff67f8efdf Mon Sep 17 00:00:00 2001 From: Djordje Mijovic Date: Fri, 18 Sep 2020 15:10:23 +0200 Subject: [PATCH] [Sol->Yul] Implementing array resizing for packed array types. --- libsolidity/codegen/YulUtilFunctions.cpp | 34 +++++++++++++++++++++--- libsolidity/codegen/YulUtilFunctions.h | 5 ++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 4ac32a1fa..f976f8066 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -873,6 +873,12 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type) let arrayDataStart := (array) let deleteStart := add(arrayDataStart, newSlotCount) let deleteEnd := add(arrayDataStart, oldSlotCount) + + // 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, ), ) + if gt(offset, 0) { (sub(deleteStart, 1), offset) } + (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 (slot, offset) { + let mask := (mul(8, sub(32, offset)), ) + 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(); }); diff --git a/libsolidity/codegen/YulUtilFunctions.h b/libsolidity/codegen/YulUtilFunctions.h index 5437114f7..351c857d4 100644 --- a/libsolidity/codegen/YulUtilFunctions.h +++ b/libsolidity/codegen/YulUtilFunctions.h @@ -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;