Browse Source

Type promotion fixes and tests.

cl-refactor
Christian 10 years ago
parent
commit
6ec55d3d5f
  1. 16
      libsolidity/ExpressionCompiler.cpp
  2. 4
      libsolidity/ExpressionCompiler.h
  3. 8
      test/solidityCompiler.cpp
  4. 42
      test/solidityEndToEndTest.cpp
  5. 33
      test/solidityExpressionCompiler.cpp

16
libsolidity/ExpressionCompiler.cpp

@ -136,15 +136,9 @@ bool ExpressionCompiler::visit(BinaryOperation& _binaryOperation)
cleanupNeeded = true;
leftExpression.accept(*this);
if (cleanupNeeded)
appendHighBitsCleanup(dynamic_cast<IntegerType const&>(*leftExpression.getType()));
else
appendTypeConversion(*leftExpression.getType(), commonType);
appendTypeConversion(*leftExpression.getType(), commonType, cleanupNeeded);
rightExpression.accept(*this);
if (cleanupNeeded)
appendHighBitsCleanup(dynamic_cast<IntegerType const&>(*leftExpression.getType()));
else
appendTypeConversion(*rightExpression.getType(), commonType);
appendTypeConversion(*rightExpression.getType(), commonType, cleanupNeeded);
if (Token::isCompareOp(op))
appendCompareOperatorCode(op, commonType);
else
@ -368,20 +362,20 @@ void ExpressionCompiler::appendShiftOperatorCode(Token::Value _operator)
}
}
void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType)
void ExpressionCompiler::appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded)
{
// If the type of one of the operands is extended, we need to remove all
// higher-order bits that we might have ignored in previous operations.
// @todo: store in the AST whether the operand might have "dirty" higher
// order bits
if (_typeOnStack == _targetType)
if (_typeOnStack == _targetType && !_cleanupNeeded)
return;
if (_typeOnStack.getCategory() == Type::Category::INTEGER)
{
appendHighBitsCleanup(dynamic_cast<IntegerType const&>(_typeOnStack));
}
else
else if (_typeOnStack != _targetType)
{
// All other types should not be convertible to non-equal types.
assert(!_typeOnStack.isExplicitlyConvertibleTo(_targetType));

4
libsolidity/ExpressionCompiler.h

@ -66,7 +66,9 @@ private:
/// Appends an implicit or explicit type conversion. For now this comprises only erasing
/// higher-order bits (@see appendHighBitCleanup) when widening integer types.
void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType);
/// If @a _cleanupNeeded, high order bits cleanup is also done if no type conversion would be
/// necessary.
void appendTypeConversion(Type const& _typeOnStack, Type const& _targetType, bool _cleanupNeeded = false);
//// Appends code that cleans higher-order bits for integer types.
void appendHighBitsCleanup(IntegerType const& _typeOnStack);

8
test/solidityCompiler.cpp

@ -119,10 +119,10 @@ BOOST_AUTO_TEST_CASE(different_argument_numbers)
byte(Instruction::JUMPDEST), // beginning of g
byte(Instruction::PUSH1), 0x0,
byte(Instruction::DUP1), // initialized e and h
byte(Instruction::PUSH1), byte(0x20 + shift), // ret address
byte(Instruction::PUSH1), 0x1,
byte(Instruction::PUSH1), 0x2,
byte(Instruction::PUSH1), 0x3,
byte(Instruction::PUSH1), 0x29 + shift, // ret address
byte(Instruction::PUSH1), 0x1, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x2, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), 0x3, byte(Instruction::PUSH1), 0xff, byte(Instruction::AND),
byte(Instruction::PUSH1), byte(0x1 + shift),
// stack here: ret e h 0x20 1 2 3 0x1
byte(Instruction::JUMP),

42
test/solidityEndToEndTest.cpp

@ -192,6 +192,21 @@ BOOST_AUTO_TEST_CASE(many_local_variables)
== toBigEndian(u256(0x121121)));
}
BOOST_AUTO_TEST_CASE(packing_unpacking_types)
{
char const* sourceCode = "contract test {\n"
" function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n"
" if (a) y = 1;\n"
" y = y * 0x100000000 | ~b;\n"
" y = y * 0x10000000000000000 | ~c;\n"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0"))
== fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f"));
}
BOOST_AUTO_TEST_CASE(multiple_return_values)
{
char const* sourceCode = "contract test {\n"
@ -244,7 +259,32 @@ BOOST_AUTO_TEST_CASE(sign_extension)
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, bytes()) == bytes(32, 0xff));
BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xff)));
}
BOOST_AUTO_TEST_CASE(small_unsigned_types)
{
char const* sourceCode = "contract test {\n"
" function run() returns(uint256 y) {\n"
" uint32 x = uint32(0xffffff) * 0xffffff;\n"
" return x / 0x100;"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xfffe0000)));
}
BOOST_AUTO_TEST_CASE(small_signed_types)
{
char const* sourceCode = "contract test {\n"
" function run() returns(int256 y) {\n"
" return -int32(10) * -int64(20);\n"
" }\n"
"}\n";
ExecutionFramework framework;
framework.compileAndRun(sourceCode);
BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(200)));
}
BOOST_AUTO_TEST_SUITE_END()

33
test/solidityExpressionCompiler.cpp

@ -154,8 +154,8 @@ BOOST_AUTO_TEST_CASE(comparison)
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa,
byte(eth::Instruction::PUSH2), 0x11, 0xaa,
bytes expectation({byte(eth::Instruction::PUSH2), 0x10, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH2), 0x11, 0xaa, byte(eth::Instruction::PUSH2), 0xff, 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT),
byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::EQ),
@ -172,16 +172,16 @@ BOOST_AUTO_TEST_CASE(short_circuiting)
bytes expectation({byte(eth::Instruction::PUSH1), 0xa,
byte(eth::Instruction::PUSH1), 0x8,
byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::ADD), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::GT),
byte(eth::Instruction::ISZERO), // after this we have 10 + 8 >= 4
byte(eth::Instruction::DUP1),
byte(eth::Instruction::PUSH1), 0x14,
byte(eth::Instruction::PUSH1), 0x20,
byte(eth::Instruction::JUMPI), // short-circuit if it is true
byte(eth::Instruction::POP),
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x9,
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x9, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO), // after this we have 2 != 9
byte(eth::Instruction::JUMPDEST),
@ -197,10 +197,11 @@ BOOST_AUTO_TEST_CASE(arithmetics)
" function f() { var x = (1 * (2 / (3 % (4 + (5 - (6 | (7 & (8 ^ 9)))))))); }"
"}\n";
bytes code = compileFirstExpression(sourceCode);
bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x3,
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x4,
byte(eth::Instruction::PUSH1), 0x5,
byte(eth::Instruction::PUSH1), 0x6,
@ -213,8 +214,10 @@ BOOST_AUTO_TEST_CASE(arithmetics)
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::SUB),
byte(eth::Instruction::ADD),
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::MOD),
byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::SWAP1),
byte(eth::Instruction::DIV),
byte(eth::Instruction::MUL)});
@ -231,8 +234,8 @@ BOOST_AUTO_TEST_CASE(unary_operators)
bytes expectation({byte(eth::Instruction::PUSH1), 0x1,
byte(eth::Instruction::PUSH1), 0x0,
byte(eth::Instruction::SUB),
byte(eth::Instruction::NOT),
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::NOT), byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::EQ),
byte(eth::Instruction::ISZERO)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
@ -305,7 +308,7 @@ BOOST_AUTO_TEST_CASE(assignment)
byte(eth::Instruction::POP),
byte(eth::Instruction::DUP2),
// Stack here: a+b b a+b
byte(eth::Instruction::PUSH1), 0x2,
byte(eth::Instruction::PUSH1), 0x2, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::MUL)});
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
}
@ -320,17 +323,17 @@ BOOST_AUTO_TEST_CASE(function_call)
{{"test", "f", "a"}, {"test", "f", "b"}});
// Stack: a, b
bytes expectation({byte(eth::Instruction::PUSH1), 0x0a,
bytes expectation({byte(eth::Instruction::PUSH1), 0x0d,
byte(eth::Instruction::DUP3),
byte(eth::Instruction::PUSH1), 0x01,
byte(eth::Instruction::PUSH1), 0x01, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::ADD),
// Stack here: a b <ret label> (a+1)
byte(eth::Instruction::DUP3),
byte(eth::Instruction::PUSH1), 0x14,
byte(eth::Instruction::PUSH1), 0x1a,
byte(eth::Instruction::JUMP),
byte(eth::Instruction::JUMPDEST),
// Stack here: a b g(a+1, b)
byte(eth::Instruction::PUSH1), 0x02,
byte(eth::Instruction::PUSH1), 0x02, byte(eth::Instruction::PUSH1), 0xff, byte(eth::Instruction::AND),
byte(eth::Instruction::MUL),
// Stack here: a b g(a+1, b)*2
byte(eth::Instruction::DUP3),

Loading…
Cancel
Save