diff --git a/libsolidity/codegen/YulUtilFunctions.cpp b/libsolidity/codegen/YulUtilFunctions.cpp index 66f052515..198550015 100644 --- a/libsolidity/codegen/YulUtilFunctions.cpp +++ b/libsolidity/codegen/YulUtilFunctions.cpp @@ -1108,7 +1108,7 @@ std::string YulUtilFunctions::resizeArrayFunction(ArrayType const& _type) string functionName = "resize_array_" + _type.identifier(); return m_functionCollector.createFunction(functionName, [&]() { - return Whiskers(R"( + Whiskers templ(R"( function (array, newLen) { if gt(newLen, ) { () @@ -1121,35 +1121,42 @@ std::string YulUtilFunctions::resizeArrayFunction(ArrayType const& _type) sstore(array, newLen) - // Size was reduced, clear end of array - if lt(newLen, oldLen) { - let oldSlotCount := (oldLen) - let newSlotCount := (newLen) - 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) - } - })") - ("functionName", functionName) - ("panic", panicFunction(PanicCode::ResourceError)) - ("fetchLength", arrayLengthFunction(_type)) - ("isDynamic", _type.isDynamicallySized()) - ("convertToSize", arrayConvertLengthToSize(_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(); + + // Size was reduced, clear end of array + if lt(newLen, oldLen) { + let oldSlotCount := (oldLen) + let newSlotCount := (newLen) + 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) + } + + })"); + templ("functionName", functionName); + templ("maxArrayLength", (u256(1) << 64).str()); + templ("panic", panicFunction(util::PanicCode::ResourceError)); + templ("fetchLength", arrayLengthFunction(_type)); + templ("isDynamic", _type.isDynamicallySized()); + bool isMappingBase = _type.baseType()->category() == Type::Category::Mapping; + templ("needsClearing", !isMappingBase); + if (!isMappingBase) + { + templ("convertToSize", arrayConvertLengthToSize(_type)); + templ("dataPosition", arrayDataAreaFunction(_type)); + templ("clearStorageRange", clearStorageRangeFunction(*_type.baseType())); + templ("packed", _type.baseType()->storageBytes() <= 16); + templ("itemsPerSlot", to_string(32 / _type.baseType()->storageBytes())); + templ("storageBytes", to_string(_type.baseType()->storageBytes())); + templ("partialClearStorageSlot", partialClearStorageSlotFunction()); + } + return templ.render(); }); } @@ -1313,14 +1320,17 @@ string YulUtilFunctions::storageArrayPopFunction(ArrayType const& _type) if iszero(oldLen) { () } let newLen := sub(oldLen, 1) let slot, offset := (array, newLen) - (slot, offset) + (slot, offset) sstore(array, newLen) })") ("functionName", functionName) ("panic", panicFunction(PanicCode::EmptyArrayPop)) ("fetchLength", arrayLengthFunction(_type)) ("indexAccess", storageArrayIndexAccessFunction(_type)) - ("setToZero", storageSetToZeroFunction(*_type.baseType())) + ( + "setToZero", + _type.baseType()->category() != Type::Category::Mapping ? storageSetToZeroFunction(*_type.baseType()) : "" + ) .render(); }); } @@ -1527,7 +1537,7 @@ string YulUtilFunctions::clearStorageArrayFunction(ArrayType const& _type) (slot, 0) - (slot, add(slot, ())) + (slot, add(slot, ())) } )") @@ -1536,11 +1546,9 @@ string YulUtilFunctions::clearStorageArrayFunction(ArrayType const& _type) ("resizeArray", _type.isDynamicallySized() ? resizeArrayFunction(_type) : "") ( "clearRange", - clearStorageRangeFunction( - (_type.baseType()->storageBytes() < 32) ? - *TypeProvider::uint256() : - *_type.baseType() - ) + _type.baseType()->category() != Type::Category::Mapping ? + clearStorageRangeFunction((_type.baseType()->storageBytes() < 32) ? *TypeProvider::uint256() : *_type.baseType()) : + "" ) ("lenToSize", arrayConvertLengthToSize(_type)) ("len", _type.length().str()) @@ -1560,6 +1568,9 @@ string YulUtilFunctions::clearStorageStructFunction(StructType const& _type) set slotsCleared; for (auto const& member: structMembers) + { + if (member.type->category() == Type::Category::Mapping) + continue; if (member.type->storageBytes() < 32) { auto const& slotDiff = _type.storageOffsetsOfMember(member.name).first; @@ -1583,6 +1594,7 @@ string YulUtilFunctions::clearStorageStructFunction(StructType const& _type) .render() ); } + } return Whiskers(R"( function (slot) { @@ -1592,7 +1604,6 @@ string YulUtilFunctions::clearStorageStructFunction(StructType const& _type) } )") ("functionName", functionName) - ("allocStruct", allocateMemoryStructFunction(_type)) ("storageSize", _type.storageSize().str()) ("member", memberSetValues) .render(); diff --git a/test/libsolidity/semanticTests/storage/mappings_array2d_pop_delete.sol b/test/libsolidity/semanticTests/storage/mappings_array2d_pop_delete.sol index f4407bb6c..f2def79bc 100644 --- a/test/libsolidity/semanticTests/storage/mappings_array2d_pop_delete.sol +++ b/test/libsolidity/semanticTests/storage/mappings_array2d_pop_delete.sol @@ -28,6 +28,8 @@ contract C { return a.length; } } +// ==== +// compileViaYul: also // ---- // n1(uint256,uint256): 42, 64 -> // map(uint256): 42 -> 64 diff --git a/test/libsolidity/semanticTests/storage/mappings_array_pop_delete.sol b/test/libsolidity/semanticTests/storage/mappings_array_pop_delete.sol index 973900576..5078103b8 100644 --- a/test/libsolidity/semanticTests/storage/mappings_array_pop_delete.sol +++ b/test/libsolidity/semanticTests/storage/mappings_array_pop_delete.sol @@ -23,6 +23,8 @@ contract C { return a.length; } } +// ==== +// compileViaYul: also // ---- // n1(uint256,uint256): 42, 64 -> // map(uint256): 42 -> 64 diff --git a/test/libsolidity/semanticTests/structs/delete_struct.sol b/test/libsolidity/semanticTests/structs/delete_struct.sol index 48de502c7..efc620f15 100644 --- a/test/libsolidity/semanticTests/structs/delete_struct.sol +++ b/test/libsolidity/semanticTests/structs/delete_struct.sol @@ -38,6 +38,8 @@ contract test { return str.nstr.nestedMapping[index]; } } +// ==== +// compileViaYul: also // ---- // getToDelete() -> 0 // getTopValue() -> 0