Unpacking of dynamically sized arguments.

This commit is contained in:
Christian 2015-02-15 02:00:33 +01:00
parent d630a67812
commit 971cc9b5b9
3 changed files with 35 additions and 7 deletions

View File

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

View File

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

View File

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