diff --git a/Changelog.md b/Changelog.md index 22f845070..e4baf02db 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,7 @@ Language Features: Compiler Features: + * Code Generator: Use SELFBALANCE for ``address(this).balance`` if using Istanbul EVM Bugfixes: diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 2f8bf9455..ae740a6de 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -1229,6 +1229,28 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess) utils().leftShiftNumberOnStack(224); return false; } + // Another special case for `address(this).balance`. Post-Istanbul, we can use the selfbalance + // opcode. + if ( + m_context.evmVersion().hasSelfBalance() && + member == "balance" && + _memberAccess.expression().annotation().type->category() == Type::Category::Address + ) + if (FunctionCall const* funCall = dynamic_cast(&_memberAccess.expression())) + if (auto const* addr = dynamic_cast(&funCall->expression())) + if ( + addr->typeName().token() == Token::Address && + funCall->arguments().size() == 1 + ) + if (auto arg = dynamic_cast( funCall->arguments().front().get())) + if ( + arg->name() == "this" && + dynamic_cast(arg->annotation().referencedDeclaration) + ) + { + m_context << Instruction::SELFBALANCE; + return false; + } _memberAccess.expression().accept(*this); switch (_memberAccess.expression().annotation().type->category()) diff --git a/test/libsolidity/SolidityExpressionCompiler.cpp b/test/libsolidity/SolidityExpressionCompiler.cpp index 607706162..551596456 100644 --- a/test/libsolidity/SolidityExpressionCompiler.cpp +++ b/test/libsolidity/SolidityExpressionCompiler.cpp @@ -617,6 +617,25 @@ BOOST_AUTO_TEST_CASE(gas_left) BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); } +BOOST_AUTO_TEST_CASE(selfbalance) +{ + char const* sourceCode = R"( + contract test { + function f() returns (uint) { + return address(this).balance; + } + } + )"; + + bytes code = compileFirstExpression(sourceCode, {}, {}); + + if (dev::test::Options::get().evmVersion() == EVMVersion::istanbul()) + { + bytes expectation({uint8_t(Instruction::SELFBALANCE)}); + BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); + } +} + BOOST_AUTO_TEST_SUITE_END() }