Browse Source

Fixed arrays in ABI.

cl-refactor
Christian 10 years ago
parent
commit
6d4b77249e
  1. 67
      libsolidity/Compiler.cpp
  2. 13
      libsolidity/Types.cpp
  3. 1
      libsolidity/Types.h
  4. 8
      test/SolidityEndToEndTest.cpp

67
libsolidity/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)

13
libsolidity/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;

1
libsolidity/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;

8
test/SolidityEndToEndTest.cpp

@ -2504,11 +2504,11 @@ BOOST_AUTO_TEST_CASE(struct_containing_bytes_copy_and_delete)
compileAndRun(sourceCode);
string data = "123456789012345678901234567890123";
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true));
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("copy()") == encodeArgs(true));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", u256(data.length()), 12, data, 13) == encodeArgs(true));
BOOST_CHECK(callContractFunction("set(uint256,bytes,uint256)", 12, u256(data.length()), 13, data) == encodeArgs(true));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("del()") == encodeArgs(true));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
@ -2661,8 +2661,8 @@ BOOST_AUTO_TEST_CASE(bytes_in_arguments)
bytes calldata1 = encodeArgs(u256(innercalldata1.length()), 12, innercalldata1, 13);
string innercalldata2 = asString(FixedHash<4>(dev::sha3("g(uint256)")).asBytes() + encodeArgs(3));
bytes calldata = encodeArgs(
u256(innercalldata1.length()), u256(innercalldata2.length()),
12, innercalldata1, innercalldata2, 13);
12, u256(innercalldata1.length()), u256(innercalldata2.length()), 13,
innercalldata1, innercalldata2);
BOOST_CHECK(callContractFunction("test(uint256,bytes,bytes,uint256)", calldata)
== encodeArgs(12, (8 + 9) * 3, 13, u256(innercalldata1.length())));
}

Loading…
Cancel
Save