@@ -1797,8 +1797,11 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
1797
1797
1798
1798
if (_fromType.isByteArrayOrString ())
1799
1799
return copyByteArrayToStorageFunction (_fromType, _toType);
1800
- if (_fromType.dataStoredIn (DataLocation::Storage) && _toType.baseType ()->isValueType ())
1801
- return copyValueArrayStorageToStorageFunction (_fromType, _toType);
1800
+ if (_toType.baseType ()->isValueType ())
1801
+ return copyValueArrayToStorageFunction (_fromType, _toType);
1802
+
1803
+ solAssert (_toType.storageStride () == 32 );
1804
+ solAssert (!_fromType.baseType ()->isValueType ());
1802
1805
1803
1806
string functionName = " copy_array_to_storage_from_" + _fromType.identifier () + " _to_" + _toType.identifier ();
1804
1807
return m_functionCollector.createFunction (functionName, [&](){
@@ -1812,43 +1815,30 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
1812
1815
let srcPtr := <srcDataLocation>(value)
1813
1816
1814
1817
let elementSlot := <dstDataLocation>(slot)
1815
- let elementOffset := 0
1816
1818
1817
1819
for { let i := 0 } lt(i, length) {i := add(i, 1)} {
1818
1820
<?fromCalldata>
1819
- let <elementValues > :=
1821
+ let <stackItems > :=
1820
1822
<?dynamicallyEncodedBase>
1821
1823
<accessCalldataTail>(value, srcPtr)
1822
1824
<!dynamicallyEncodedBase>
1823
1825
srcPtr
1824
1826
</dynamicallyEncodedBase>
1825
-
1826
- <?isValueType>
1827
- <elementValues> := <readFromCalldataOrMemory>(<elementValues>)
1828
- </isValueType>
1829
1827
</fromCalldata>
1830
1828
1831
1829
<?fromMemory>
1832
- let <elementValues > := <readFromCalldataOrMemory >(srcPtr)
1830
+ let <stackItems > := <readFromMemoryOrCalldata >(srcPtr)
1833
1831
</fromMemory>
1834
1832
1835
1833
<?fromStorage>
1836
- let <elementValues > := srcPtr
1834
+ let <stackItems > := srcPtr
1837
1835
</fromStorage>
1838
1836
1839
- <updateStorageValue>(elementSlot, elementOffset, <elementValues >)
1837
+ <updateStorageValue>(elementSlot, <stackItems >)
1840
1838
1841
1839
srcPtr := add(srcPtr, <srcStride>)
1842
1840
1843
- <?multipleItemsPerSlot>
1844
- elementOffset := add(elementOffset, <storageStride>)
1845
- if gt(elementOffset, sub(32, <storageStride>)) {
1846
- elementOffset := 0
1847
- elementSlot := add(elementSlot, 1)
1848
- }
1849
- <!multipleItemsPerSlot>
1850
- elementSlot := add(elementSlot, <storageSize>)
1851
- </multipleItemsPerSlot>
1841
+ elementSlot := add(elementSlot, <storageSize>)
1852
1842
}
1853
1843
}
1854
1844
)" );
@@ -1870,25 +1860,22 @@ string YulUtilFunctions::copyArrayToStorageFunction(ArrayType const& _fromType,
1870
1860
}
1871
1861
templ (" resizeArray" , resizeArrayFunction (_toType));
1872
1862
templ (" arrayLength" ,arrayLengthFunction (_fromType));
1873
- templ (" isValueType" , _fromType.baseType ()->isValueType ());
1874
1863
templ (" dstDataLocation" , arrayDataAreaFunction (_toType));
1875
1864
if (fromMemory || (fromCalldata && _fromType.baseType ()->isValueType ()))
1876
- templ (" readFromCalldataOrMemory " , readFromMemoryOrCalldata (*_fromType.baseType (), fromCalldata));
1877
- templ (" elementValues " , suffixedVariableNameList (
1878
- " elementValue_ " ,
1865
+ templ (" readFromMemoryOrCalldata " , readFromMemoryOrCalldata (*_fromType.baseType (), fromCalldata));
1866
+ templ (" stackItems " , suffixedVariableNameList (
1867
+ " stackItem_ " ,
1879
1868
0 ,
1880
1869
_fromType.baseType ()->stackItems ().size ()
1881
1870
));
1882
- templ (" updateStorageValue" , updateStorageValueFunction (*_fromType.baseType (), *_toType.baseType ()));
1871
+ templ (" updateStorageValue" , updateStorageValueFunction (*_fromType.baseType (), *_toType.baseType (), 0 ));
1883
1872
templ (" srcStride" ,
1884
1873
fromCalldata ?
1885
1874
to_string (_fromType.calldataStride ()) :
1886
1875
fromMemory ?
1887
1876
to_string (_fromType.memoryStride ()) :
1888
1877
formatNumber (_fromType.baseType ()->storageSize ())
1889
1878
);
1890
- templ (" multipleItemsPerSlot" , _toType.storageStride () <= 16 );
1891
- templ (" storageStride" , to_string (_toType.storageStride ()));
1892
1879
templ (" storageSize" , _toType.baseType ()->storageSize ().str ());
1893
1880
1894
1881
return templ.render ();
@@ -1973,16 +1960,14 @@ string YulUtilFunctions::copyByteArrayToStorageFunction(ArrayType const& _fromTy
1973
1960
});
1974
1961
}
1975
1962
1976
-
1977
- string YulUtilFunctions::copyValueArrayStorageToStorageFunction (ArrayType const & _fromType, ArrayType const & _toType)
1963
+ string YulUtilFunctions::copyValueArrayToStorageFunction (ArrayType const & _fromType, ArrayType const & _toType)
1978
1964
{
1979
1965
solAssert (_fromType.baseType ()->isValueType (), " " );
1980
1966
solAssert (_toType.baseType ()->isValueType (), " " );
1981
1967
solAssert (_fromType.baseType ()->isImplicitlyConvertibleTo (*_toType.baseType ()), " " );
1982
1968
1983
1969
solAssert (!_fromType.isByteArrayOrString (), " " );
1984
1970
solAssert (!_toType.isByteArrayOrString (), " " );
1985
- solAssert (_fromType.dataStoredIn (DataLocation::Storage), " " );
1986
1971
solAssert (_toType.dataStoredIn (DataLocation::Storage), " " );
1987
1972
1988
1973
solAssert (_fromType.storageStride () <= _toType.storageStride (), " " );
@@ -1991,42 +1976,51 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const&
1991
1976
string functionName = " copy_array_to_storage_from_" + _fromType.identifier () + " _to_" + _toType.identifier ();
1992
1977
return m_functionCollector.createFunction (functionName, [&](){
1993
1978
Whiskers templ (R"(
1994
- function <functionName>(dst, src) {
1979
+ function <functionName>(dst, src<?isFromDynamicCalldata>, len</isFromDynamicCalldata>) {
1980
+ <?isFromStorage>
1995
1981
if eq(dst, src) { leave }
1996
- let length := <arrayLength>(src)
1982
+ </isFromStorage>
1983
+ let length := <arrayLength>(src<?isFromDynamicCalldata>, len</isFromDynamicCalldata>)
1997
1984
// Make sure array length is sane
1998
1985
if gt(length, 0xffffffffffffffff) { <panic>() }
1999
1986
<resizeArray>(dst, length)
2000
1987
2001
- let srcSlot := <srcDataLocation>(src)
1988
+ let srcPtr := <srcDataLocation>(src)
2002
1989
let dstSlot := <dstDataLocation>(dst)
2003
1990
2004
1991
let fullSlots := div(length, <itemsPerSlot>)
2005
1992
2006
- let srcSlotValue := sload(srcSlot)
1993
+ <?isFromStorage>
1994
+ let srcSlotValue := sload(srcPtr)
2007
1995
let srcItemIndexInSlot := 0
1996
+ </isFromStorage>
1997
+
2008
1998
for { let i := 0 } lt(i, fullSlots) { i := add(i, 1) } {
2009
1999
let dstSlotValue := 0
2010
- <?sameType >
2000
+ <?sameTypeFromStorage >
2011
2001
dstSlotValue := <maskFull>(srcSlotValue)
2012
- <updateSrcSlotValue >
2013
- <!sameType >
2002
+ <updateSrcPtr >
2003
+ <!sameTypeFromStorage >
2014
2004
<?multipleItemsPerSlotDst>for { let j := 0 } lt(j, <itemsPerSlot>) { j := add(j, 1) } </multipleItemsPerSlotDst>
2015
2005
{
2016
- let itemValue := <convert>(
2006
+ <?isFromStorage>
2007
+ let <stackItems> := <convert>(
2017
2008
<extractFromSlot>(srcSlotValue, mul(<srcStride>, srcItemIndexInSlot))
2018
2009
)
2019
- itemValue := <prepareStore>(itemValue)
2010
+ <!isFromStorage>
2011
+ let <stackItems> := <readFromMemoryOrCalldata>(srcPtr)
2012
+ </isFromStorage>
2013
+ let itemValue := <prepareStore>(<stackItems>)
2020
2014
dstSlotValue :=
2021
2015
<?multipleItemsPerSlotDst>
2022
2016
<updateByteSlice>(dstSlotValue, mul(<dstStride>, j), itemValue)
2023
2017
<!multipleItemsPerSlotDst>
2024
2018
itemValue
2025
2019
</multipleItemsPerSlotDst>
2026
2020
2027
- <updateSrcSlotValue >
2021
+ <updateSrcPtr >
2028
2022
}
2029
- </sameType >
2023
+ </sameTypeFromStorage >
2030
2024
2031
2025
sstore(add(dstSlot, i), dstSlotValue)
2032
2026
}
@@ -2035,47 +2029,62 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const&
2035
2029
let spill := sub(length, mul(fullSlots, <itemsPerSlot>))
2036
2030
if gt(spill, 0) {
2037
2031
let dstSlotValue := 0
2038
- <?sameType >
2032
+ <?sameTypeFromStorage >
2039
2033
dstSlotValue := <maskBytes>(srcSlotValue, mul(spill, <srcStride>))
2040
- <updateSrcSlotValue >
2041
- <!sameType >
2034
+ <updateSrcPtr >
2035
+ <!sameTypeFromStorage >
2042
2036
for { let j := 0 } lt(j, spill) { j := add(j, 1) } {
2043
- let itemValue := <convert>(
2037
+ <?isFromStorage>
2038
+ let <stackItems> := <convert>(
2044
2039
<extractFromSlot>(srcSlotValue, mul(<srcStride>, srcItemIndexInSlot))
2045
2040
)
2046
- itemValue := <prepareStore>(itemValue)
2041
+ <!isFromStorage>
2042
+ let <stackItems> := <readFromMemoryOrCalldata>(srcPtr)
2043
+ </isFromStorage>
2044
+ let itemValue := <prepareStore>(<stackItems>)
2047
2045
dstSlotValue := <updateByteSlice>(dstSlotValue, mul(<dstStride>, j), itemValue)
2048
2046
2049
- <updateSrcSlotValue >
2047
+ <updateSrcPtr >
2050
2048
}
2051
- </sameType >
2049
+ </sameTypeFromStorage >
2052
2050
sstore(add(dstSlot, fullSlots), dstSlotValue)
2053
2051
}
2054
2052
</multipleItemsPerSlotDst>
2055
2053
}
2056
2054
)" );
2057
2055
if (_fromType.dataStoredIn (DataLocation::Storage))
2058
2056
solAssert (!_fromType.isValueType (), " " );
2057
+
2058
+ bool fromCalldata = _fromType.dataStoredIn (DataLocation::CallData);
2059
+ bool fromStorage = _fromType.dataStoredIn (DataLocation::Storage);
2059
2060
templ (" functionName" , functionName);
2060
2061
templ (" resizeArray" , resizeArrayFunction (_toType));
2061
2062
templ (" arrayLength" , arrayLengthFunction (_fromType));
2062
2063
templ (" panic" , panicFunction (PanicCode::ResourceError));
2064
+ templ (" isFromDynamicCalldata" , _fromType.isDynamicallySized () && fromCalldata);
2065
+ templ (" isFromStorage" , fromStorage);
2066
+ templ (" readFromMemoryOrCalldata" , readFromMemoryOrCalldata (*_fromType.baseType (), fromCalldata));
2063
2067
templ (" srcDataLocation" , arrayDataAreaFunction (_fromType));
2064
2068
templ (" dstDataLocation" , arrayDataAreaFunction (_toType));
2065
2069
templ (" srcStride" , to_string (_fromType.storageStride ()));
2070
+ templ (" stackItems" , suffixedVariableNameList (
2071
+ " stackItem_" ,
2072
+ 0 ,
2073
+ _fromType.baseType ()->stackItems ().size ()
2074
+ ));
2066
2075
unsigned itemsPerSlot = 32 / _toType.storageStride ();
2067
2076
templ (" itemsPerSlot" , to_string (itemsPerSlot));
2068
2077
templ (" multipleItemsPerSlotDst" , itemsPerSlot > 1 );
2069
- bool sameType = *_fromType.baseType () == *_toType.baseType ();
2078
+ bool sameTypeFromStorage = fromStorage && ( *_fromType.baseType () == *_toType.baseType () );
2070
2079
if (auto functionType = dynamic_cast <FunctionType const *>(_fromType.baseType ()))
2071
2080
{
2072
2081
solAssert (functionType->equalExcludingStateMutability (
2073
2082
dynamic_cast <FunctionType const &>(*_toType.baseType ())
2074
2083
));
2075
- sameType = true ;
2084
+ sameTypeFromStorage = fromStorage ;
2076
2085
}
2077
- templ (" sameType " , sameType );
2078
- if (sameType )
2086
+ templ (" sameTypeFromStorage " , sameTypeFromStorage );
2087
+ if (sameTypeFromStorage )
2079
2088
{
2080
2089
templ (" maskFull" , maskLowerOrderBytesFunction (itemsPerSlot * _toType.storageStride ()));
2081
2090
templ (" maskBytes" , maskLowerOrderBytesFunctionDynamic ());
@@ -2088,24 +2097,32 @@ string YulUtilFunctions::copyValueArrayStorageToStorageFunction(ArrayType const&
2088
2097
templ (" convert" , conversionFunction (*_fromType.baseType (), *_toType.baseType ()));
2089
2098
templ (" prepareStore" , prepareStoreFunction (*_toType.baseType ()));
2090
2099
}
2091
- templ (" updateSrcSlotValue" , Whiskers (R"(
2092
- <?srcReadMultiPerSlot>
2093
- srcItemIndexInSlot := add(srcItemIndexInSlot, 1)
2094
- if eq(srcItemIndexInSlot, <srcItemsPerSlot>) {
2095
- // here we are done with this slot, we need to read next one
2096
- srcSlot := add(srcSlot, 1)
2097
- srcSlotValue := sload(srcSlot)
2098
- srcItemIndexInSlot := 0
2099
- }
2100
- <!srcReadMultiPerSlot>
2101
- srcSlot := add(srcSlot, 1)
2102
- srcSlotValue := sload(srcSlot)
2103
- </srcReadMultiPerSlot>
2104
- )" )
2105
- (" srcReadMultiPerSlot" , !sameType && _fromType.storageStride () <= 16 )
2106
- (" srcItemsPerSlot" , to_string (32 / _fromType.storageStride ()))
2107
- .render ()
2108
- );
2100
+ if (fromStorage)
2101
+ templ (" updateSrcPtr" , Whiskers (R"(
2102
+ <?srcReadMultiPerSlot>
2103
+ srcItemIndexInSlot := add(srcItemIndexInSlot, 1)
2104
+ if eq(srcItemIndexInSlot, <srcItemsPerSlot>) {
2105
+ // here we are done with this slot, we need to read next one
2106
+ srcPtr := add(srcPtr, 1)
2107
+ srcSlotValue := sload(srcPtr)
2108
+ srcItemIndexInSlot := 0
2109
+ }
2110
+ <!srcReadMultiPerSlot>
2111
+ srcPtr := add(srcPtr, 1)
2112
+ srcSlotValue := sload(srcPtr)
2113
+ </srcReadMultiPerSlot>
2114
+ )" )
2115
+ (" srcReadMultiPerSlot" , !sameTypeFromStorage && _fromType.storageStride () <= 16 )
2116
+ (" srcItemsPerSlot" , to_string (32 / _fromType.storageStride ()))
2117
+ .render ()
2118
+ );
2119
+ else
2120
+ templ (" updateSrcPtr" , Whiskers (R"(
2121
+ srcPtr := add(srcPtr, <srcStride>)
2122
+ )" )
2123
+ (" srcStride" , fromCalldata ? to_string (_fromType.calldataStride ()) : to_string (_fromType.memoryStride ()))
2124
+ .render ()
2125
+ );
2109
2126
2110
2127
return templ.render ();
2111
2128
});
0 commit comments