From cad718715bcfbe610be870787e85f5f68917409f Mon Sep 17 00:00:00 2001 From: Christian Date: Sun, 15 Feb 2015 02:00:33 +0100 Subject: [PATCH] Unpacking of dynamically sized arguments. --- libsolidity/Compiler.cpp | 35 ++++++++++++++++++++++++++++++----- libsolidity/Compiler.h | 4 ++-- libsolidity/Types.h | 3 +++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/libsolidity/Compiler.cpp b/libsolidity/Compiler.cpp index e14935873..98c9ffaac 100644 --- a/libsolidity/Compiler.cpp +++ b/libsolidity/Compiler.cpp @@ -178,15 +178,40 @@ void Compiler::appendFunctionSelector(ContractDefinition const& _contract) } } -unsigned Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) +void Compiler::appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory) { // We do not check the calldata size, everything is zero-padded. - unsigned dataOffset = CompilerUtils::dataStartOffset; // the 4 bytes of the function hash signature - + unsigned offset(CompilerUtils::dataStartOffset); bool const c_padToWords = true; + + unsigned dynamicParameterCount = 0; for (TypePointer const& type: _typeParameters) - dataOffset += CompilerUtils(m_context).loadFromMemory(dataOffset, *type, !_fromMemory, c_padToWords); - return dataOffset; + if (type->isDynamicallySized()) + dynamicParameterCount++; + offset += dynamicParameterCount * 32; + unsigned currentDynamicParameter = 0; + for (TypePointer const& type: _typeParameters) + if (type->isDynamicallySized()) + { + // value on stack: [memory_offset] (only if we are already in dynamic mode) + if (currentDynamicParameter == 0) + // switch from static to dynamic + m_context << u256(offset); + CompilerUtils(m_context).loadFromMemory( + CompilerUtils::dataStartOffset + currentDynamicParameter * 32, + IntegerType(256), !_fromMemory, c_padToWords); + // store new memory pointer + m_context << eth::Instruction::DUP2 << eth::Instruction::DUP2 << eth::Instruction::ADD; + currentDynamicParameter++; + // value on stack: offset length next_memory_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) diff --git a/libsolidity/Compiler.h b/libsolidity/Compiler.h index b3eae5b17..5d5b6d47b 100644 --- a/libsolidity/Compiler.h +++ b/libsolidity/Compiler.h @@ -52,8 +52,8 @@ private: void appendConstructorCall(FunctionDefinition const& _constructor); void appendFunctionSelector(ContractDefinition const& _contract); /// Creates code that unpacks the arguments for the given function represented by a vector of TypePointers. - /// From memory if @a _fromMemory is true, otherwise from call data. @returns the size of the data in bytes. - unsigned appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false); + /// From memory if @a _fromMemory is true, otherwise from call data. + void appendCalldataUnpacker(TypePointers const& _typeParameters, bool _fromMemory = false); void appendReturnValuePacker(TypePointers const& _typeParameters); void registerStateVariables(ContractDefinition const& _contract); diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 3b4eee57f..90812f564 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -122,6 +122,8 @@ public: /// is not a simple big-endian encoding or the type cannot be stored in calldata. /// Note that irrespective of this size, each calldata element is padded to a multiple of 32 bytes. virtual unsigned getCalldataEncodedSize() const { return 0; } + /// @returns true if the type is dynamically encoded in calldata + virtual bool isDynamicallySized() const { return false; } /// @returns number of bytes required to hold this value in storage. /// For dynamically "allocated" types, it returns the size of the statically allocated head, virtual u256 getStorageSize() const { return 1; } @@ -289,6 +291,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 bool isDynamicallySized() const { return true; } virtual unsigned getSizeOnStack() const override; virtual std::string toString() const override { return "bytes"; } virtual MemberList const& getMembers() const override { return s_byteArrayMemberList; }