Fixed arrays in ABI.

This commit is contained in:
Christian 2015-03-03 11:28:56 +01:00
parent 7f37659a28
commit 7112696993
3 changed files with 49 additions and 32 deletions

View File

@ -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)
{
switch (type->getCategory())
{
case Type::Category::Array:
if (type->isDynamicallySized()) if (type->isDynamicallySized())
{ {
// value on stack: [calldata_offset] (only if we are already in dynamic mode) // put on stack: data_offset length
if (currentDynamicParameter == 0) unsigned newStackHeight = m_context.getStackHeight();
// switch from static to dynamic if (previousDynamicType)
m_context << u256(offset); {
// retrieve length // Retrieve data start offset by adding length to start offset of previous dynamic type
CompilerUtils(m_context).loadFromMemory( unsigned stackDepth = m_context.getStackHeight() - stackHeightOfPreviousDynamicArgument;
CompilerUtils::dataStartOffset + currentDynamicParameter * 32, m_context << eth::dupInstruction(stackDepth) << eth::dupInstruction(stackDepth);
IntegerType(256), !_fromMemory, c_padToWords); ArrayUtils(m_context).convertLengthToSize(*previousDynamicType);
// stack: offset length m_context << u256(32) << eth::Instruction::MUL << eth::Instruction::ADD;
// add 32-byte padding to copy of length
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 else
CompilerUtils(m_context).loadFromMemoryDynamic(*type, !_fromMemory, c_padToWords); m_context << u256(parameterHeadEnd);
if (dynamicParameterCount > 0) stackHeightOfPreviousDynamicArgument = newStackHeight;
m_context << eth::Instruction::POP; previousDynamicType = &dynamic_cast<ArrayType const&>(*type);
offset += CompilerUtils(m_context).loadFromMemory(offset, IntegerType(256), !_fromMemory);
}
else
{
m_context << u256(offset);
offset += CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
}
break;
default:
solAssert(!type->isDynamicallySized(), "Unknown dynamically sized type: " + type->toString());
offset += CompilerUtils(m_context).loadFromMemory(offset, *type, !_fromMemory, true);
}
}
} }
void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters) void Compiler::appendReturnValuePacker(TypePointers const& _typeParameters)

View File

@ -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;

View File

@ -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;