aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2015-03-03 18:28:56 +0800
committerChristian <c@ethdev.com>2015-03-03 19:58:48 +0800
commit7112696993c84a889c8d654c03c5285e40e6e637 (patch)
treed6a3f875be4e31131c73049289581f389f50a1e0
parent7f37659a28253f48dc128998017f9ca9a3351506 (diff)
downloaddexon-solidity-7112696993c84a889c8d654c03c5285e40e6e637.tar
dexon-solidity-7112696993c84a889c8d654c03c5285e40e6e637.tar.gz
dexon-solidity-7112696993c84a889c8d654c03c5285e40e6e637.tar.bz2
dexon-solidity-7112696993c84a889c8d654c03c5285e40e6e637.tar.lz
dexon-solidity-7112696993c84a889c8d654c03c5285e40e6e637.tar.xz
dexon-solidity-7112696993c84a889c8d654c03c5285e40e6e637.tar.zst
dexon-solidity-7112696993c84a889c8d654c03c5285e40e6e637.zip
Fixed arrays in ABI.
-rw-r--r--Compiler.cpp67
-rw-r--r--Types.cpp13
-rw-r--r--Types.h1
3 files changed, 49 insertions, 32 deletions
diff --git a/Compiler.cpp b/Compiler.cpp
index 580fd5b6..acc30cf3 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -205,42 +205,49 @@ void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool
{
// We do not check the calldata size, everything is zero-padded.
unsigned offset(CompilerUtils::dataStartOffset);
- bool const c_padToWords = true;
- unsigned dynamicParameterCount = 0;
+ bigint parameterHeadEnd = offset;
for (TypePointer const& type: _typeParameters)
- if (type->isDynamicallySized())
- dynamicParameterCount++;
- offset += dynamicParameterCount * 32;
- unsigned currentDynamicParameter = 0;
+ parameterHeadEnd += type->isDynamicallySized() ? 32 :
+ CompilerUtils::getPaddedSize(type->getCalldataEncodedSize());
+ solAssert(parameterHeadEnd <= numeric_limits<unsigned>::max(), "Arguments too large.");
+
+ unsigned stackHeightOfPreviousDynamicArgument = 0;
+ ArrayType const* previousDynamicType = nullptr;
for (TypePointer const& type: _typeParameters)
- if (type->isDynamicallySized())
+ {
+ switch (type->getCategory())
{
- // value on stack: [calldata_offset] (only if we are already in dynamic mode)
- if (currentDynamicParameter == 0)
- // switch from static to dynamic
+ case Type::Category::Array:
+ if (type->isDynamicallySized())
+ {
+ // 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);
- // retrieve length
- CompilerUtils(m_context).loadFromMemory(
- CompilerUtils::dataStartOffset + currentDynamicParameter * 32,
- IntegerType(256), !_fromMemory, c_padToWords);
- // stack: offset length
- // 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
+ 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);
}
- 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)
diff --git a/Types.cpp b/Types.cpp
index 22d612cd..96feefff 100644
--- a/Types.cpp
+++ b/Types.cpp
@@ -570,6 +570,15 @@ bool ArrayType::operator==(Type const& _other) const
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
{
if (isDynamicallySized())
@@ -586,8 +595,8 @@ u256 ArrayType::getStorageSize() const
unsigned ArrayType::getSizeOnStack() const
{
if (m_location == Location::CallData)
- // offset, length (stack top)
- return 2;
+ // offset [length] (stack top)
+ return 1 + (isDynamicallySized() ? 1 : 0);
else
// offset
return 1;
diff --git a/Types.h b/Types.h
index 9961f03a..8474c6c0 100644
--- a/Types.h
+++ b/Types.h
@@ -302,6 +302,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual bool operator==(const Type& _other) const override;
+ virtual unsigned getCalldataEncodedSize() const override;
virtual bool isDynamicallySized() const { return m_hasDynamicLength; }
virtual u256 getStorageSize() const override;
virtual unsigned getSizeOnStack() const override;