mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11047 from ethereum/bytesToBytesNNConversion
Bytes to bytesNN conversion
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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), "");
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user