Merge pull request #11047 from ethereum/bytesToBytesNNConversion

Bytes to bytesNN conversion
This commit is contained in:
chriseth
2021-04-26 11:51:41 +02:00
committed by GitHub
14 changed files with 271 additions and 29 deletions
+47 -2
View File
@@ -961,8 +961,31 @@ void CompilerUtils::convertType(
}
case Type::Category::Array:
{
solAssert(targetTypeCategory == stackTypeCategory, "");
auto const& typeOnStack = dynamic_cast<ArrayType const&>(_typeOnStack);
if (_targetType.category() == Type::Category::FixedBytes)
{
solAssert(
typeOnStack.isByteArray() && !typeOnStack.isString(),
"Array types other than bytes not convertible to bytesNN."
);
solAssert(typeOnStack.isDynamicallySized(), "");
bool fromCalldata = typeOnStack.dataStoredIn(DataLocation::CallData);
solAssert(typeOnStack.sizeOnStack() == (fromCalldata ? 2 : 1), "");
if (fromCalldata)
m_context << Instruction::SWAP1;
m_context.callYulFunction(
m_context.utilFunctions().bytesToFixedBytesConversionFunction(
typeOnStack,
dynamic_cast<FixedBytesType const &>(_targetType)
),
typeOnStack.sizeOnStack(),
1
);
break;
}
solAssert(targetTypeCategory == stackTypeCategory, "");
auto const& targetType = dynamic_cast<ArrayType const&>(_targetType);
switch (targetType.location())
{
@@ -1066,8 +1089,30 @@ void CompilerUtils::convertType(
}
case Type::Category::ArraySlice:
{
solAssert(_targetType.category() == Type::Category::Array, "");
auto& typeOnStack = dynamic_cast<ArraySliceType const&>(_typeOnStack);
if (_targetType.category() == Type::Category::FixedBytes)
{
solAssert(
typeOnStack.arrayType().isByteArray() && !typeOnStack.arrayType().isString(),
"Array types other than bytes not convertible to bytesNN."
);
solAssert(typeOnStack.isDynamicallySized(), "");
solAssert(typeOnStack.dataStoredIn(DataLocation::CallData), "");
solAssert(typeOnStack.sizeOnStack() == 2, "");
m_context << Instruction::SWAP1;
m_context.callYulFunction(
m_context.utilFunctions().bytesToFixedBytesConversionFunction(
typeOnStack.arrayType(),
dynamic_cast<FixedBytesType const &>(_targetType)
),
2,
1
);
break;
}
solAssert(_targetType.category() == Type::Category::Array, "");
auto const& targetArrayType = dynamic_cast<ArrayType const&>(_targetType);
solAssert(typeOnStack.arrayType().isImplicitlyConvertibleTo(targetArrayType), "");
solAssert(
+71 -5
View File
@@ -3084,8 +3084,13 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
}
else if (_from.category() == Type::Category::ArraySlice)
{
solAssert(_to.category() == Type::Category::Array, "");
auto const& fromType = dynamic_cast<ArraySliceType const&>(_from);
if (_to.category() == Type::Category::FixedBytes)
{
solAssert(fromType.arrayType().isByteArray(), "Array types other than bytes not convertible to bytesNN.");
return bytesToFixedBytesConversionFunction(fromType.arrayType(), dynamic_cast<FixedBytesType const &>(_to));
}
solAssert(_to.category() == Type::Category::Array, "");
auto const& targetType = dynamic_cast<ArrayType const&>(_to);
solAssert(fromType.arrayType().isImplicitlyConvertibleTo(targetType), "");
@@ -3117,11 +3122,14 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
}
else if (_from.category() == Type::Category::Array)
{
auto const& fromArrayType = dynamic_cast<ArrayType const&>(_from);
if (_to.category() == Type::Category::FixedBytes)
{
solAssert(fromArrayType.isByteArray(), "Array types other than bytes not convertible to bytesNN.");
return bytesToFixedBytesConversionFunction(fromArrayType, dynamic_cast<FixedBytesType const &>(_to));
}
solAssert(_to.category() == Type::Category::Array, "");
return arrayConversionFunction(
dynamic_cast<ArrayType const&>(_from),
dynamic_cast<ArrayType const&>(_to)
);
return arrayConversionFunction(fromArrayType, dynamic_cast<ArrayType const&>(_to));
}
if (_from.sizeOnStack() != 1 || _to.sizeOnStack() != 1)
@@ -3342,6 +3350,64 @@ string YulUtilFunctions::conversionFunction(Type const& _from, Type const& _to)
});
}
string YulUtilFunctions::bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to)
{
solAssert(_from.isByteArray() && !_from.isString(), "");
solAssert(_from.isDynamicallySized(), "");
string functionName = "convert_bytes_to_fixedbytes_from_" + _from.identifier() + "_to_" + _to.identifier();
return m_functionCollector.createFunction(functionName, [&](auto& _args, auto& _returnParams) {
_args = { "array" };
bool fromCalldata = _from.dataStoredIn(DataLocation::CallData);
if (fromCalldata)
_args.emplace_back("len");
_returnParams = {"value"};
Whiskers templ(R"(
let length := <arrayLen>(array<?fromCalldata>, len</fromCalldata>)
let dataArea := array
<?fromMemory>
dataArea := <dataArea>(array)
</fromMemory>
<?fromStorage>
if gt(length, 31) { dataArea := <dataArea>(array) }
</fromStorage>
<?fromCalldata>
value := <cleanup>(calldataload(dataArea))
<!fromCalldata>
value := <extractValue>(dataArea)
</fromCalldata>
if lt(length, <fixedBytesLen>) {
value := and(
value,
<shl>(
mul(8, sub(<fixedBytesLen>, length)),
<mask>
)
)
}
)");
templ("fromCalldata", fromCalldata);
templ("arrayLen", arrayLengthFunction(_from));
templ("fixedBytesLen", to_string(_to.numBytes()));
templ("fromMemory", _from.dataStoredIn(DataLocation::Memory));
templ("fromStorage", _from.dataStoredIn(DataLocation::Storage));
templ("dataArea", arrayDataAreaFunction(_from));
if (fromCalldata)
templ("cleanup", cleanupFunction(_to));
else
templ(
"extractValue",
_from.dataStoredIn(DataLocation::Storage) ?
readFromStorage(_to, 32 - _to.numBytes(), false) :
readFromMemory(_to)
);
templ("shl", shiftLeftFunctionDynamic());
templ("mask", formatNumber(~((u256(1) << (256 - _to.numBytes() * 8)) - 1)));
return templ.render();
});
}
string YulUtilFunctions::copyStructToStorageFunction(StructType const& _from, StructType const& _to)
{
solAssert(_to.dataStoredIn(DataLocation::Storage), "");
+4
View File
@@ -411,6 +411,10 @@ public:
/// This is used for data being encoded or general type conversions in the code.
std::string conversionFunction(Type const& _from, Type const& _to);
/// @returns the name of a function that converts bytes array to fixed bytes type
/// signature: (array) -> value
std::string bytesToFixedBytesConversionFunction(ArrayType const& _from, FixedBytesType const& _to);
/// @returns the name of the cleanup function for the given type and
/// adds its implementation to the requested functions.
/// The cleanup function defers to the validator function with "assert"