Allow ABI encoding for array slices without explicit casts.

This commit is contained in:
Daniel Kirchner
2020-05-13 18:20:07 +02:00
parent e9446475bb
commit 97296d8622
9 changed files with 214 additions and 24 deletions
+31 -15
View File
@@ -279,31 +279,47 @@ string ABIFunctions::abiEncodingFunction(
return abiEncodingFunctionStringLiteral(_from, to, _options);
else if (auto toArray = dynamic_cast<ArrayType const*>(&to))
{
solAssert(_from.category() == Type::Category::Array, "");
solAssert(to.dataStoredIn(DataLocation::Memory), "");
ArrayType const& fromArray = dynamic_cast<ArrayType const&>(_from);
ArrayType const* fromArray = nullptr;
switch (_from.category())
{
case Type::Category::Array:
fromArray = dynamic_cast<ArrayType const*>(&_from);
break;
case Type::Category::ArraySlice:
fromArray = &dynamic_cast<ArraySliceType const*>(&_from)->arrayType();
solAssert(
fromArray->dataStoredIn(DataLocation::CallData) &&
fromArray->isDynamicallySized() &&
!fromArray->baseType()->isDynamicallyEncoded(),
""
);
break;
default:
solAssert(false, "");
break;
}
switch (fromArray.location())
switch (fromArray->location())
{
case DataLocation::CallData:
if (
fromArray.isByteArray() ||
*fromArray.baseType() == *TypeProvider::uint256() ||
*fromArray.baseType() == FixedBytesType(32)
fromArray->isByteArray() ||
*fromArray->baseType() == *TypeProvider::uint256() ||
*fromArray->baseType() == FixedBytesType(32)
)
return abiEncodingFunctionCalldataArrayWithoutCleanup(fromArray, *toArray, _options);
return abiEncodingFunctionCalldataArrayWithoutCleanup(*fromArray, *toArray, _options);
else
return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options);
case DataLocation::Memory:
if (fromArray.isByteArray())
return abiEncodingFunctionMemoryByteArray(fromArray, *toArray, _options);
if (fromArray->isByteArray())
return abiEncodingFunctionMemoryByteArray(*fromArray, *toArray, _options);
else
return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options);
case DataLocation::Storage:
if (fromArray.baseType()->storageBytes() <= 16)
return abiEncodingFunctionCompactStorageArray(fromArray, *toArray, _options);
if (fromArray->baseType()->storageBytes() <= 16)
return abiEncodingFunctionCompactStorageArray(*fromArray, *toArray, _options);
else
return abiEncodingFunctionSimpleArray(fromArray, *toArray, _options);
return abiEncodingFunctionSimpleArray(*fromArray, *toArray, _options);
default:
solAssert(false, "");
}
+34 -7
View File
@@ -480,6 +480,16 @@ void CompilerUtils::encodeToMemory(
convertType(*_givenTypes[i], *targetType, true);
if (auto arrayType = dynamic_cast<ArrayType const*>(type))
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
else if (auto arraySliceType = dynamic_cast<ArraySliceType const*>(type))
{
solAssert(
arraySliceType->dataStoredIn(DataLocation::CallData) &&
arraySliceType->isDynamicallySized() &&
!arraySliceType->arrayType().baseType()->isDynamicallyEncoded(),
""
);
ArrayUtils(m_context).copyArrayToMemory(arraySliceType->arrayType(), _padToWordBoundaries);
}
else
storeInMemoryDynamic(*type, _padToWordBoundaries);
}
@@ -516,22 +526,39 @@ void CompilerUtils::encodeToMemory(
}
else
{
solAssert(_givenTypes[i]->category() == Type::Category::Array, "Unknown dynamic type.");
auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
ArrayType const* arrayType = nullptr;
switch (_givenTypes[i]->category())
{
case Type::Category::Array:
arrayType = dynamic_cast<ArrayType const*>(_givenTypes[i]);
break;
case Type::Category::ArraySlice:
arrayType = &dynamic_cast<ArraySliceType const*>(_givenTypes[i])->arrayType();
solAssert(
arrayType->isDynamicallySized() &&
arrayType->dataStoredIn(DataLocation::CallData) &&
!arrayType->baseType()->isDynamicallyEncoded(),
""
);
break;
default:
solAssert(false, "Unknown dynamic type.");
break;
}
// now copy the array
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.sizeOnStack());
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType->sizeOnStack());
// stack: ... <end_of_mem> <value...>
// copy length to memory
m_context << dupInstruction(1 + arrayType.sizeOnStack());
ArrayUtils(m_context).retrieveLength(arrayType, 1);
m_context << dupInstruction(1 + arrayType->sizeOnStack());
ArrayUtils(m_context).retrieveLength(*arrayType, 1);
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
storeInMemoryDynamic(*TypeProvider::uint256(), true);
// stack: ... <end_of_mem> <value...> <end_of_mem''>
// copy the new memory pointer
m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
m_context << swapInstruction(arrayType->sizeOnStack() + 1) << Instruction::POP;
// stack: ... <end_of_mem''> <value...>
// copy data part
ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
ArrayUtils(m_context).copyArrayToMemory(*arrayType, _padToWordBoundaries);
// stack: ... <end_of_mem'''>
}