Browse Source

Merge branch 'develop' into p2p

cl-refactor
subtly 10 years ago
parent
commit
940e374d9f
  1. 9
      libsolidity/CompilerUtils.cpp
  2. 6
      libsolidity/ExpressionCompiler.cpp
  3. 14
      libsolidity/Types.cpp
  4. 12
      libsolidity/Types.h
  5. 39
      test/SolidityEndToEndTest.cpp

9
libsolidity/CompilerUtils.cpp

@ -184,17 +184,14 @@ void CompilerUtils::copyByteArrayToStorage(ByteArrayType const& _targetType,
<< eth::Instruction::SWAP1;
// stack here: target_ref target_data_end target_data_ref
// store length (in bytes)
if (_sourceType.getOffset() == 0)
m_context << eth::Instruction::CALLDATASIZE;
else
m_context << _sourceType.getOffset() << eth::Instruction::CALLDATASIZE << eth::Instruction::SUB;
m_context << eth::Instruction::CALLDATASIZE;
m_context << eth::Instruction::DUP1 << eth::Instruction::DUP5 << eth::Instruction::SSTORE;
// jump to end if length is zero
m_context << eth::Instruction::ISZERO;
eth::AssemblyItem copyLoopEnd = m_context.newTag();
m_context.appendConditionalJumpTo(copyLoopEnd);
m_context << _sourceType.getOffset();
// store start offset
m_context << u256(0);
// stack now: target_ref target_data_end target_data_ref calldata_offset
eth::AssemblyItem copyLoopStart = m_context.newTag();
m_context << copyLoopStart

6
libsolidity/ExpressionCompiler.cpp

@ -504,6 +504,12 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
}
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid member access to " + type.toString()));
}
case Type::Category::ByteArray:
{
solAssert(member == "length", "Illegal bytearray member.");
m_context << eth::Instruction::SLOAD;
break;
}
default:
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Member access to unknown type."));
}

14
libsolidity/Types.cpp

@ -58,7 +58,7 @@ TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
else if (Token::String0 <= _typeToken && _typeToken <= Token::String32)
return make_shared<StaticStringType>(int(_typeToken) - int(Token::String0));
else if (_typeToken == Token::Bytes)
return make_shared<ByteArrayType>(ByteArrayType::Location::Storage, 0, 0, true);
return make_shared<ByteArrayType>(ByteArrayType::Location::Storage);
else
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
std::string(Token::toString(_typeToken)) + " to type."));
@ -515,12 +515,7 @@ TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
bool ByteArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{
if (*this == _convertTo)
return true;
if (_convertTo.getCategory() != Category::ByteArray)
return false;
auto const& other = dynamic_cast<ByteArrayType const&>(_convertTo);
return (m_dynamicLength == other.m_dynamicLength || m_length == other.m_length);
return _convertTo.getCategory() == getCategory();
}
TypePointer ByteArrayType::unaryOperatorResult(Token::Value _operator) const
@ -535,8 +530,7 @@ bool ByteArrayType::operator==(Type const& _other) const
if (_other.getCategory() != getCategory())
return false;
ByteArrayType const& other = dynamic_cast<ByteArrayType const&>(_other);
return other.m_location == m_location && other.m_dynamicLength == m_dynamicLength
&& other.m_length == m_length && other.m_offset == m_offset;
return other.m_location == m_location;
}
unsigned ByteArrayType::getSizeOnStack() const
@ -547,6 +541,8 @@ unsigned ByteArrayType::getSizeOnStack() const
return 1;
}
const MemberList ByteArrayType::s_byteArrayMemberList = MemberList({{"length", make_shared<IntegerType >(256)}});
bool ContractType::operator==(Type const& _other) const
{
if (_other.getCategory() != getCategory())

12
libsolidity/Types.h

@ -286,25 +286,19 @@ public:
enum class Location { Storage, CallData, Memory };
virtual Category getCategory() const override { return Category::ByteArray; }
explicit ByteArrayType(Location _location, u256 const& _offset = 0, u256 const& _length = 0,
bool _dynamicLength = false):
m_location(_location), m_offset(_offset), m_length(_length), m_dynamicLength(_dynamicLength) {}
explicit ByteArrayType(Location _location): m_location(_location) {}
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 getSizeOnStack() const override;
virtual std::string toString() const override { return "bytes"; }
virtual MemberList const& getMembers() const override { return s_byteArrayMemberList; }
Location getLocation() const { return m_location; }
u256 const& getOffset() const { return m_offset; }
u256 const& getLength() const { return m_length; }
bool hasDynamicLength() const { return m_dynamicLength; }
private:
Location m_location;
u256 m_offset;
u256 m_length;
bool m_dynamicLength;
static const MemberList s_byteArrayMemberList;
};
/**

39
test/SolidityEndToEndTest.cpp

@ -2385,6 +2385,45 @@ BOOST_AUTO_TEST_CASE(copy_removes_bytes_data)
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(bytes_inside_mappings)
{
char const* sourceCode = R"(
contract c {
function set(uint key) returns (bool) { data[key] = msg.data; return true; }
function copy(uint from, uint to) returns (bool) { data[to] = data[from]; return true; }
mapping(uint => bytes) data;
}
)";
compileAndRun(sourceCode);
// store a short byte array at 1 and a longer one at 2
BOOST_CHECK(callContractFunction("set(uint256)", 1, 2) == encodeArgs(true));
BOOST_CHECK(callContractFunction("set(uint256)", 2, 2, 3, 4, 5) == encodeArgs(true));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
// copy shorter to longer
BOOST_CHECK(callContractFunction("copy(uint256,uint256)", 1, 2) == encodeArgs(true));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
// copy empty to both
BOOST_CHECK(callContractFunction("copy(uint256,uint256)", 99, 1) == encodeArgs(true));
BOOST_CHECK(!m_state.storage(m_contractAddress).empty());
BOOST_CHECK(callContractFunction("copy(uint256,uint256)", 99, 2) == encodeArgs(true));
BOOST_CHECK(m_state.storage(m_contractAddress).empty());
}
BOOST_AUTO_TEST_CASE(bytes_length_member)
{
char const* sourceCode = R"(
contract c {
function set() returns (bool) { data = msg.data; return true; }
function getLength() returns (uint) { return data.length; }
bytes data;
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("getLength()") == encodeArgs(0));
BOOST_CHECK(callContractFunction("set()", 1, 2) == encodeArgs(true));
BOOST_CHECK(callContractFunction("getLength()") == encodeArgs(4+32+32));
}
BOOST_AUTO_TEST_SUITE_END()
}

Loading…
Cancel
Save