diff options
author | Christian <c@ethdev.com> | 2015-03-03 18:28:56 +0800 |
---|---|---|
committer | Christian <c@ethdev.com> | 2015-03-03 19:58:48 +0800 |
commit | 7112696993c84a889c8d654c03c5285e40e6e637 (patch) | |
tree | d6a3f875be4e31131c73049289581f389f50a1e0 | |
parent | 7f37659a28253f48dc128998017f9ca9a3351506 (diff) | |
download | dexon-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.cpp | 67 | ||||
-rw-r--r-- | Types.cpp | 13 | ||||
-rw-r--r-- | Types.h | 1 |
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) @@ -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; @@ -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; |