mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Fixed arrays in ABI.
This commit is contained in:
parent
7f37659a28
commit
7112696993
67
Compiler.cpp
67
Compiler.cpp
@ -205,42 +205,49 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
|
|||||||
{
|
{
|
||||||
// We do not check the calldata size, everything is zero-padded.
|
// We do not check the calldata size, everything is zero-padded.
|
||||||
unsigned offset(CompilerUtils::dataStartOffset);
|
unsigned offset(CompilerUtils::dataStartOffset);
|
||||||
bool const c_padToWords = true;
|
|
||||||
|
|
||||||
unsigned dynamicParameterCount = 0;
|
bigint parameterHeadEnd = offset;
|
||||||
for (TypePointer const& type: _typeParameters)
|
for (TypePointer const& type: _typeParameters)
|
||||||
if (type->isDynamicallySized())
|
parameterHeadEnd += type->isDynamicallySized() ? 32 :
|
||||||
dynamicParameterCount++;
|
CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
|
||||||
offset += dynamicParameterCount * 32;
|
solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large.");
|
||||||
unsigned currentDynamicParameter = 0;
|
|
||||||
|
unsigned stackHeightOfPreviousDynamicArgument = 0;
|
||||||
|
ArrayType const* previousDynamicType = nullptr;
|
||||||
for (TypePointer const& type: _typeParameters)
|
for (TypePointer const& type: _typeParameters)
|
||||||
if (type->isDynamicallySized())
|
{
|
||||||
|
switch (type->getCategory())
|
||||||
{
|
{
|
||||||
// value on stack: [calldata_offset] (only if we are already in dynamic mode)
|
case Type::Category::Array:
|
||||||
if (currentDynamicParameter == 0)
|
if (type->isDynamicallySized())
|
||||||
// switch from static to dynamic
|
{
|
||||||
|
// put on stack: data_offset length
|
||||||
|
unsigned newStackHeight = m_context.getStackHeight();
|
||||||
|
if (previousDynamicType)
|
||||||
|
{
|
||||||
|
// Retrieve data start offset by adding length to start offset of previous dynamic type
|
||||||
|
unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument;
|
||||||
|
m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth);
|
||||||
|
ArrayUtils(m_context).convertLengthToSize(*previousDynamicType);
|
||||||
|
m_context << u256(32) << eth::Instruction::MUL << eth::Instruction::ADD;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_context << u256(parameterHeadEnd);
|
||||||
|
stackHeightOfPreviousDynamicArgument = newStackHeight;
|
||||||
|
previousDynamicType = &dynamic_cast<ArrayType const&>(*type);
|
||||||
|
offset += CompilerUtils(m_context).loadFromMemory(offset, IntegerType(256), !_fromMemory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_context << u256(offset);
|
m_context << u256(offset);
|
||||||
// retrieve length
|
offset += CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
|
||||||
CompilerUtils(m_context).loadFromMemory(
|
}
|
||||||
CompilerUtils::dataStartOffset + currentDynamicParameter * 32,
|
break;
|
||||||
IntegerType(256), !_fromMemory, c_padToWords);
|
default:
|
||||||
// stack: offset length
|
solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
|
||||||
// add 32-byte padding to copy of length
|
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, true);
|
||||||
m_context << u256(32) << eth::Instruction::DUP1 << u256(31)
|
|
||||||
<< eth::Instruction::DUP4 << eth::Instruction::ADD
|
|
||||||
<< eth::Instruction::DIV << eth::Instruction::MUL;
|
|
||||||
// stack: offset length padded_length
|
|
||||||
m_context << eth::Instruction::DUP3 << eth::Instruction::ADD;
|
|
||||||
currentDynamicParameter++;
|
|
||||||
// stack: offset length next_calldata_offset
|
|
||||||
}
|
}
|
||||||
else if (currentDynamicParameter == 0)
|
}
|
||||||
// we can still use static load
|
|
||||||
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, c_padToWords);
|
|
||||||
else
|
|
||||||
CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, c_padToWords);
|
|
||||||
if (dynamicParameterCount > 0)
|
|
||||||
m_context << eth::Instruction::POP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
|
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)
|
||||||
|
13
Types.cpp
13
Types.cpp
@ -570,6 +570,15 @@ bool ArrayType::operator==(Type const& _other) const
|
|||||||
return isDynamicallySized() || getLength() == other.getLength();
|
return isDynamicallySized() || getLength() == other.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned ArrayType::getCalldataEncodedSize() const
|
||||||
|
{
|
||||||
|
if (isDynamicallySized())
|
||||||
|
return 0;
|
||||||
|
bigint size = bigint(getLength()) * (isByteArray() ? 1 : getBaseType()->getCalldataEncodedSize());
|
||||||
|
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
|
||||||
|
return unsigned(size);
|
||||||
|
}
|
||||||
|
|
||||||
u256 ArrayType::getStorageSize() const
|
u256 ArrayType::getStorageSize() const
|
||||||
{
|
{
|
||||||
if (isDynamicallySized())
|
if (isDynamicallySized())
|
||||||
@ -586,8 +595,8 @@ u256 ArrayType::getStorageSize() const
|
|||||||
unsigned ArrayType::getSizeOnStack() const
|
unsigned ArrayType::getSizeOnStack() const
|
||||||
{
|
{
|
||||||
if (m_location == Location::CallData)
|
if (m_location == Location::CallData)
|
||||||
// offset, length (stack top)
|
// offset [length] (stack top)
|
||||||
return 2;
|
return 1 + (isDynamicallySized() ? 1 : 0);
|
||||||
else
|
else
|
||||||
// offset
|
// offset
|
||||||
return 1;
|
return 1;
|
||||||
|
1
Types.h
1
Types.h
@ -302,6 +302,7 @@ public:
|
|||||||
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
||||||
virtual bool operator==(const Type& _other) const override;
|
virtual bool operator==(const Type& _other) const override;
|
||||||
|
virtual unsigned getCalldataEncodedSize() const override;
|
||||||
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
|
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
|
||||||
virtual u256 getStorageSize() const override;
|
virtual u256 getStorageSize() const override;
|
||||||
virtual unsigned getSizeOnStack() const override;
|
virtual unsigned getSizeOnStack() const override;
|
||||||
|
Loading…
Reference in New Issue
Block a user