diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 92a4c2a4d..606714d26 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -55,9 +55,6 @@ void Assembly::append(Assembly const& _a) m_subs += _a.m_subs; for (auto const& lib: _a.m_libraries) m_libraries.insert(lib); - - assert(!_a.m_baseDeposit); - assert(!_a.m_totalDeposit); } void Assembly::append(Assembly const& _a, int _deposit) diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index d1cfc7ef0..0d40abcf4 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -85,12 +85,6 @@ public: AssemblyItem const& back() const { return m_items.back(); } std::string backString() const { return m_items.size() && m_items.back().type() == PushString ? m_strings.at((h256)m_items.back().data()) : std::string(); } - void onePath() { assertThrow(!m_totalDeposit && !m_baseDeposit, InvalidDeposit, ""); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } - void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } - void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } - void ignored() { m_baseDeposit = m_deposit; } - void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } - void injectStart(AssemblyItem const& _i); int deposit() const { return m_deposit; } void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assertThrow(m_deposit >= 0, InvalidDeposit, ""); } @@ -121,7 +115,6 @@ protected: /// returns the replaced tags. std::map optimiseInternal(bool _enable, bool _isCreation, size_t _runs); - void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } unsigned bytesRequired(unsigned subTagSize) const; private: @@ -144,8 +137,6 @@ protected: mutable std::vector m_tagPositionsInBytecode; int m_deposit = 0; - int m_baseDeposit = 0; - int m_totalDeposit = 0; SourceLocation m_currentSourceLocation; }; diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 9f37bc65e..afef63e96 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -439,15 +439,21 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) int minDep = min(code[1].m_asm.deposit(), code[2].m_asm.deposit()); m_asm.append(code[0].m_asm); - auto pos = m_asm.appendJumpI(); - m_asm.onePath(); + auto mainBranch = m_asm.appendJumpI(); + + /// The else branch. + int startDeposit = m_asm.deposit(); m_asm.append(code[2].m_asm, minDep); auto end = m_asm.appendJump(); - m_asm.otherPath(); - m_asm << pos.tag(); + int deposit = m_asm.deposit(); + m_asm.setDeposit(startDeposit); + + /// The main branch. + m_asm << mainBranch.tag(); m_asm.append(code[1].m_asm, minDep); m_asm << end.tag(); - m_asm.donePaths(); + if (m_asm.deposit() != deposit) + error(); } else if (us == "WHEN" || us == "UNLESS") { @@ -458,11 +464,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) if (us == "WHEN") m_asm.append(Instruction::ISZERO); auto end = m_asm.appendJumpI(); - m_asm.onePath(); - m_asm.otherPath(); m_asm.append(code[1].m_asm, 0); m_asm << end.tag(); - m_asm.donePaths(); } else if (us == "WHILE" || us == "UNTIL") { diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp index 3668038de..a01eaca00 100644 --- a/test/liblll/EndToEndTest.cpp +++ b/test/liblll/EndToEndTest.cpp @@ -57,6 +57,68 @@ BOOST_AUTO_TEST_CASE(panic) BOOST_REQUIRE(m_output.empty()); } +BOOST_AUTO_TEST_CASE(when) +{ + char const* sourceCode = R"( + (returnlll + (seq + (when (= (calldatasize) 0) (return 1)) + (when (!= (calldatasize) 0) (return 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(unless) +{ + char const* sourceCode = R"( + (returnlll + (seq + (unless (!= (calldatasize) 0) (return 1)) + (unless (= (calldatasize) 0) (return 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(conditional_literal) +{ + char const* sourceCode = R"( + (returnlll + (seq + (return (if (= (calldatasize) 0) 1 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(conditional) +{ + char const* sourceCode = R"( + (returnlll + (seq + (if (= (calldatasize) 0) (return 1) (return 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(conditional_seq) +{ + char const* sourceCode = R"( + (returnlll + (seq + (return (if (= (calldatasize) 0) { 0 2 1 } { 0 1 2 })))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + BOOST_AUTO_TEST_CASE(exp_operator_const) { char const* sourceCode = R"(