Do not allocate memory on reverts with small errors.

This commit is contained in:
Daniel Kirchner 2023-05-04 20:40:50 +02:00
parent 21caa43f2c
commit 87ce29542c
3 changed files with 26 additions and 2 deletions

View File

@ -15,6 +15,7 @@ Compiler Features:
* SMTChecker: Properties that are proved safe are now reported explicitly at the end of the analysis. By default, only the number of safe properties is shown. The CLI option ``--model-checker-show-proved-safe`` and the JSON option ``settings.modelChecker.showProvedSafe`` can be enabled to show the full list of safe properties.
* SMTChecker: Group all messages about unsupported language features in a single warning. The CLI option ``--model-checker-show-unsupported`` and the JSON option ``settings.modelChecker.showUnsupported`` can be enabled to show the full list.
* Yul EVM Code Transform: If available, use ``push0`` instead of ``codesize`` to produce an arbitrary value on stack in order to create equal stack heights between branches.
* Yul IR Code Generation: Cheaper code for reverting with errors of a static small encoding size.
Bugfixes:

View File

@ -47,6 +47,7 @@
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/Visitor.h>
#include <range/v3/algorithm/all_of.hpp>
#include <range/v3/view/transform.hpp>
using namespace std;
@ -58,6 +59,18 @@ using namespace std::string_literals;
namespace
{
optional<size_t> staticEncodingSize(vector<Type const*> const& _parameterTypes)
{
size_t encodedSize = 0;
for (auto const* type: _parameterTypes)
{
if (type->isDynamicallyEncoded())
return nullopt;
encodedSize += type->calldataHeadSize();
}
return encodedSize;
}
struct CopyTranslate: public yul::ASTCopier
{
using ExternalRefsMap = std::map<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo>;
@ -3363,8 +3376,16 @@ void IRGeneratorForStatements::revertWithError(
vector<ASTPointer<Expression const>> const& _errorArguments
)
{
bool needsAllocation = true;
if (optional<size_t> size = staticEncodingSize(_parameterTypes))
if (ranges::all_of(_parameterTypes, [](auto const* type) { return type && type->isValueType(); }))
needsAllocation = *size + 4 > CompilerUtils::generalPurposeMemoryStart;
Whiskers templ(R"({
<?needsAllocation>
let <pos> := <allocateUnbounded>()
<!needsAllocation>
let <pos> := 0
</needsAllocation>
mstore(<pos>, <hash>)
let <end> := <encode>(add(<pos>, 4) <argumentVars>)
revert(<pos>, sub(<end>, <pos>))
@ -3372,7 +3393,9 @@ void IRGeneratorForStatements::revertWithError(
templ("pos", m_context.newYulVariable());
templ("end", m_context.newYulVariable());
templ("hash", util::selectorFromSignatureU256(_signature).str());
templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ("needsAllocation", needsAllocation);
if (needsAllocation)
templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
vector<string> errorArgumentVars;
vector<Type const*> errorArgumentTypes;

View File

@ -14,6 +14,6 @@ contract B {
}
// ----
// f() -> FAILURE, hex"92bbf6e8"
// gas irOptimized: 274265
// gas irOptimized: 270934
// gas legacy: 310592
// gas legacyOptimized: 273662