| 2061 | |
| 2062 | |
| 2063 | std::string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromType, ArrayType const& _toType) |
| 2064 | { |
| 2065 | solAssert( |
| 2066 | (*_fromType.copyForLocation(_toType.location(), _toType.isPointer())).equals(dynamic_cast<ReferenceType const&>(_toType)), |
| 2067 | "" |
| 2068 | ); |
| 2069 | solAssert(_fromType.isByteArrayOrString(), ""); |
| 2070 | solAssert(_toType.isByteArrayOrString(), ""); |
| 2071 | |
| 2072 | std::string functionName = "copy_byte_array_to_storage_from_" + _fromType.identifier() + "_to_" + _toType.identifier(); |
| 2073 | return m_functionCollector.createFunction(functionName, [&](){ |
| 2074 | Whiskers templ(R"( |
| 2075 | function <functionName>(slot, src<?fromCalldata>, len</fromCalldata>) { |
| 2076 | <?fromStorage> if eq(slot, src) { leave } </fromStorage> |
| 2077 | |
| 2078 | let newLen := <arrayLength>(src<?fromCalldata>, len</fromCalldata>) |
| 2079 | // Make sure array length is sane |
| 2080 | if gt(newLen, 0xffffffffffffffff) { <panic>() } |
| 2081 | |
| 2082 | let oldLen := <byteArrayLength>(sload(slot)) |
| 2083 | |
| 2084 | // potentially truncate data |
| 2085 | <cleanUpEndArray>(slot, oldLen, newLen) |
| 2086 | |
| 2087 | let srcOffset := 0 |
| 2088 | <?fromMemory> |
| 2089 | srcOffset := 0x20 |
| 2090 | </fromMemory> |
| 2091 | |
| 2092 | switch gt(newLen, 31) |
| 2093 | case 1 { |
| 2094 | let loopEnd := and(newLen, not(0x1f)) |
| 2095 | <?fromStorage> src := <srcDataLocation>(src) </fromStorage> |
| 2096 | let dstPtr := <dstDataLocation>(slot) |
| 2097 | let i := 0 |
| 2098 | for { } lt(i, loopEnd) { i := add(i, 0x20) } { |
| 2099 | sstore(dstPtr, <read>(add(src, srcOffset))) |
| 2100 | dstPtr := add(dstPtr, 1) |
| 2101 | srcOffset := add(srcOffset, <srcIncrement>) |
| 2102 | } |
| 2103 | if lt(loopEnd, newLen) { |
| 2104 | let lastValue := <read>(add(src, srcOffset)) |
| 2105 | sstore(dstPtr, <maskBytes>(lastValue, and(newLen, 0x1f))) |
| 2106 | } |
| 2107 | sstore(slot, add(mul(newLen, 2), 1)) |
| 2108 | } |
| 2109 | default { |
| 2110 | let value := 0 |
| 2111 | if newLen { |
| 2112 | value := <read>(add(src, srcOffset)) |
| 2113 | } |
| 2114 | sstore(slot, <byteArrayCombineShort>(value, newLen)) |
| 2115 | } |
| 2116 | } |
| 2117 | )"); |
| 2118 | templ("functionName", functionName); |
| 2119 | bool fromStorage = _fromType.dataStoredIn(DataLocation::Storage); |
| 2120 | templ("fromStorage", fromStorage); |
nothing calls this directly
no test coverage detected