| 2138 | } |
| 2139 | |
| 2140 | std::string YulUtilFunctions::copyValueArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType) |
| 2141 | { |
| 2142 | solAssert(_fromType.baseType()->isValueType(), ""); |
| 2143 | solAssert(_toType.baseType()->isValueType(), ""); |
| 2144 | solAssert(_fromType.baseType()->isImplicitlyConvertibleTo(*_toType.baseType()), ""); |
| 2145 | |
| 2146 | solAssert(!_fromType.isByteArrayOrString(), ""); |
| 2147 | solAssert(!_toType.isByteArrayOrString(), ""); |
| 2148 | solAssert(_toType.dataStoredIn(DataLocation::Storage), ""); |
| 2149 | |
| 2150 | solAssert(_fromType.storageStride() <= _toType.storageStride(), ""); |
| 2151 | solAssert(_toType.storageStride() <= 32, ""); |
| 2152 | |
| 2153 | std::string functionName = "copy_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); |
| 2154 | return m_functionCollector.createFunction(functionName, [&](){ |
| 2155 | Whiskers templ(R"( |
| 2156 | function <functionName>(dst, src<?isFromDynamicCalldata>, len</isFromDynamicCalldata>) { |
| 2157 | <?isFromStorage> |
| 2158 | if eq(dst, src) { leave } |
| 2159 | </isFromStorage> |
| 2160 | let length := <arrayLength>(src<?isFromDynamicCalldata>, len</isFromDynamicCalldata>) |
| 2161 | // Make sure array length is sane |
| 2162 | if gt(length, 0xffffffffffffffff) { <panic>() } |
| 2163 | <resizeArray>(dst, length) |
| 2164 | |
| 2165 | let srcPtr := <srcDataLocation>(src) |
| 2166 | let dstSlot := <dstDataLocation>(dst) |
| 2167 | |
| 2168 | let fullSlots := div(length, <itemsPerSlot>) |
| 2169 | |
| 2170 | <?isFromStorage> |
| 2171 | let srcSlotValue := sload(srcPtr) |
| 2172 | let srcItemIndexInSlot := 0 |
| 2173 | </isFromStorage> |
| 2174 | |
| 2175 | for { let i := 0 } lt(i, fullSlots) { i := add(i, 1) } { |
| 2176 | let dstSlotValue := 0 |
| 2177 | <?sameTypeFromStorage> |
| 2178 | dstSlotValue := <maskFull>(srcSlotValue) |
| 2179 | <updateSrcPtr> |
| 2180 | <!sameTypeFromStorage> |
| 2181 | <?multipleItemsPerSlotDst>for { let j := 0 } lt(j, <itemsPerSlot>) { j := add(j, 1) } </multipleItemsPerSlotDst> |
| 2182 | { |
| 2183 | <?isFromStorage> |
| 2184 | let <stackItems> := <convert>( |
| 2185 | <extractFromSlot>(srcSlotValue, mul(<srcStride>, srcItemIndexInSlot)) |
| 2186 | ) |
| 2187 | <!isFromStorage> |
| 2188 | let <stackItems> := <readFromMemoryOrCalldata>(srcPtr) |
| 2189 | </isFromStorage> |
| 2190 | let itemValue := <prepareStore>(<stackItems>) |
| 2191 | dstSlotValue := |
| 2192 | <?multipleItemsPerSlotDst> |
| 2193 | <updateByteSlice>(dstSlotValue, mul(<dstStride>, j), itemValue) |
| 2194 | <!multipleItemsPerSlotDst> |
| 2195 | itemValue |
| 2196 | </multipleItemsPerSlotDst> |
| 2197 |
nothing calls this directly
no test coverage detected