From 5bebbca27381a59b89496109800000ab209b4478 Mon Sep 17 00:00:00 2001 From: Daniel Kirchner Date: Mon, 12 Apr 2021 12:33:28 +0200 Subject: [PATCH] Extract VariableReferenceCounter and StackTooDeep error from EVMCodeTransform. --- libyul/AsmAnalysis.cpp | 1 + libyul/CMakeLists.txt | 2 + libyul/Exceptions.h | 19 +++++ libyul/Scope.cpp | 2 + libyul/Scope.h | 2 - libyul/backends/evm/EVMCodeTransform.cpp | 62 +------------- libyul/backends/evm/EVMCodeTransform.h | 52 +----------- .../backends/evm/VariableReferenceCounter.cpp | 83 +++++++++++++++++++ .../backends/evm/VariableReferenceCounter.h | 68 +++++++++++++++ 9 files changed, 181 insertions(+), 110 deletions(-) create mode 100644 libyul/backends/evm/VariableReferenceCounter.cpp create mode 100644 libyul/backends/evm/VariableReferenceCounter.h diff --git a/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp index fdd4c19ed..490fee0f1 100644 --- a/libyul/AsmAnalysis.cpp +++ b/libyul/AsmAnalysis.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt index f33067bbb..d8bd02842 100644 --- a/libyul/CMakeLists.txt +++ b/libyul/CMakeLists.txt @@ -65,6 +65,8 @@ add_library(yul backends/evm/EVMMetrics.h backends/evm/NoOutputAssembly.h backends/evm/NoOutputAssembly.cpp + backends/evm/VariableReferenceCounter.h + backends/evm/VariableReferenceCounter.cpp backends/wasm/EVMToEwasmTranslator.cpp backends/wasm/EVMToEwasmTranslator.h backends/wasm/BinaryTransform.cpp diff --git a/libyul/Exceptions.h b/libyul/Exceptions.h index 2fe155030..3be61bd18 100644 --- a/libyul/Exceptions.h +++ b/libyul/Exceptions.h @@ -24,6 +24,8 @@ #include #include +#include + namespace solidity::yul { @@ -32,6 +34,23 @@ struct OptimizerException: virtual YulException {}; struct CodegenException: virtual YulException {}; struct YulAssertion: virtual YulException {}; +struct StackTooDeepError: virtual YulException +{ + StackTooDeepError(YulString _variable, int _depth, std::string const& _message): + variable(_variable), depth(_depth) + { + *this << util::errinfo_comment(_message); + } + StackTooDeepError(YulString _functionName, YulString _variable, int _depth, std::string const& _message): + functionName(_functionName), variable(_variable), depth(_depth) + { + *this << util::errinfo_comment(_message); + } + YulString functionName; + YulString variable; + int depth; +}; + /// Assertion that throws an YulAssertion containing the given description if it is not met. #define yulAssert(CONDITION, DESCRIPTION) \ assertThrow(CONDITION, ::solidity::yul::YulAssertion, DESCRIPTION) diff --git a/libyul/Scope.cpp b/libyul/Scope.cpp index 3425e81ae..affd1853c 100644 --- a/libyul/Scope.cpp +++ b/libyul/Scope.cpp @@ -21,6 +21,8 @@ #include +#include + using namespace std; using namespace solidity; using namespace solidity::yul; diff --git a/libyul/Scope.h b/libyul/Scope.h index 0857b604b..a64906f2d 100644 --- a/libyul/Scope.h +++ b/libyul/Scope.h @@ -25,8 +25,6 @@ #include -#include - #include #include #include diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp index 18d0f438c..e357a071c 100644 --- a/libyul/backends/evm/EVMCodeTransform.cpp +++ b/libyul/backends/evm/EVMCodeTransform.cpp @@ -16,7 +16,7 @@ */ // SPDX-License-Identifier: GPL-3.0 /** - * Common code generator for translating Yul / inline assembly to EVM and EVM1.5. + * Code generator for translating Yul / inline assembly to EVM. */ #include @@ -25,6 +25,8 @@ #include #include +#include + #include #include @@ -42,62 +44,6 @@ using namespace solidity; using namespace solidity::yul; using namespace solidity::util; -void VariableReferenceCounter::operator()(Identifier const& _identifier) -{ - increaseRefIfFound(_identifier.name); -} - -void VariableReferenceCounter::operator()(FunctionDefinition const& _function) -{ - Scope* originalScope = m_scope; - - yulAssert(m_info.virtualBlocks.at(&_function), ""); - m_scope = m_info.scopes.at(m_info.virtualBlocks.at(&_function).get()).get(); - yulAssert(m_scope, "Variable scope does not exist."); - - for (auto const& v: _function.returnVariables) - increaseRefIfFound(v.name); - - VariableReferenceCounter{m_context, m_info}(_function.body); - - m_scope = originalScope; -} - -void VariableReferenceCounter::operator()(ForLoop const& _forLoop) -{ - Scope* originalScope = m_scope; - // Special scoping rules. - m_scope = m_info.scopes.at(&_forLoop.pre).get(); - - walkVector(_forLoop.pre.statements); - visit(*_forLoop.condition); - (*this)(_forLoop.body); - (*this)(_forLoop.post); - - m_scope = originalScope; -} - -void VariableReferenceCounter::operator()(Block const& _block) -{ - Scope* originalScope = m_scope; - m_scope = m_info.scopes.at(&_block).get(); - - ASTWalker::operator()(_block); - - m_scope = originalScope; -} - -void VariableReferenceCounter::increaseRefIfFound(YulString _variableName) -{ - m_scope->lookup(_variableName, GenericVisitor{ - [&](Scope::Variable const& _var) - { - ++m_context.variableReferences[&_var]; - }, - [](Scope::Function const&) { } - }); -} - CodeTransform::CodeTransform( AbstractAssembly& _assembly, AsmAnalysisInfo& _analysisInfo, @@ -127,7 +73,7 @@ CodeTransform::CodeTransform( // initialize m_context = make_shared(); if (m_allowStackOpt) - VariableReferenceCounter{*m_context, m_info}(_block); + m_context->variableReferences = VariableReferenceCounter::run(m_info, _block); } } diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h index 704235e63..be7fef528 100644 --- a/libyul/backends/evm/EVMCodeTransform.h +++ b/libyul/backends/evm/EVMCodeTransform.h @@ -16,7 +16,7 @@ */ // SPDX-License-Identifier: GPL-3.0 /** - * Common code generator for translating Yul / inline assembly to EVM and EVM1.5. + * Code generator for translating Yul / inline assembly to EVM. */ #pragma once @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -41,23 +42,6 @@ namespace solidity::yul struct AsmAnalysisInfo; class EVMAssembly; -struct StackTooDeepError: virtual YulException -{ - StackTooDeepError(YulString _variable, int _depth, std::string const& _message): - variable(_variable), depth(_depth) - { - *this << util::errinfo_comment(_message); - } - StackTooDeepError(YulString _functionName, YulString _variable, int _depth, std::string const& _message): - functionName(_functionName), variable(_variable), depth(_depth) - { - *this << util::errinfo_comment(_message); - } - YulString functionName; - YulString variable; - int depth; -}; - struct CodeTransformContext { std::map functionEntryIDs; @@ -79,38 +63,6 @@ struct CodeTransformContext std::stack forLoopStack; }; -/** - * Counts the number of references to a variable. This includes actual (read) references - * but also assignments to the variable. It does not include the declaration itself or - * function parameters, but it does include function return parameters. - * - * This component can handle multiple variables of the same name. - * - * Can only be applied to strict assembly. - */ -class VariableReferenceCounter: public yul::ASTWalker -{ -public: - explicit VariableReferenceCounter( - CodeTransformContext& _context, - AsmAnalysisInfo const& _assemblyInfo - ): m_context(_context), m_info(_assemblyInfo) - {} - -public: - void operator()(Identifier const& _identifier) override; - void operator()(FunctionDefinition const&) override; - void operator()(ForLoop const&) override; - void operator()(Block const& _block) override; - -private: - void increaseRefIfFound(YulString _variableName); - - CodeTransformContext& m_context; - AsmAnalysisInfo const& m_info; - Scope* m_scope = nullptr; -}; - class CodeTransform { public: diff --git a/libyul/backends/evm/VariableReferenceCounter.cpp b/libyul/backends/evm/VariableReferenceCounter.cpp new file mode 100644 index 000000000..c2afb399d --- /dev/null +++ b/libyul/backends/evm/VariableReferenceCounter.cpp @@ -0,0 +1,83 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Counts the number of references to a variable. + */ +#include +#include +#include + +#include + +using namespace solidity::yul; + +void VariableReferenceCounter::operator()(Identifier const& _identifier) +{ + increaseRefIfFound(_identifier.name); +} + +void VariableReferenceCounter::operator()(FunctionDefinition const& _function) +{ + Scope* originalScope = m_scope; + + yulAssert(m_info.virtualBlocks.at(&_function), ""); + m_scope = m_info.scopes.at(m_info.virtualBlocks.at(&_function).get()).get(); + yulAssert(m_scope, "Variable scope does not exist."); + + for (auto const& v: _function.returnVariables) + increaseRefIfFound(v.name); + + (*this)(_function.body); + + m_scope = originalScope; +} + +void VariableReferenceCounter::operator()(ForLoop const& _forLoop) +{ + Scope* originalScope = m_scope; + // Special scoping rules. + m_scope = m_info.scopes.at(&_forLoop.pre).get(); + + walkVector(_forLoop.pre.statements); + visit(*_forLoop.condition); + (*this)(_forLoop.body); + (*this)(_forLoop.post); + + m_scope = originalScope; +} + +void VariableReferenceCounter::operator()(Block const& _block) +{ + Scope* originalScope = m_scope; + m_scope = m_info.scopes.at(&_block).get(); + + ASTWalker::operator()(_block); + + m_scope = originalScope; +} + +void VariableReferenceCounter::increaseRefIfFound(YulString _variableName) +{ + m_scope->lookup(_variableName, util::GenericVisitor{ + [&](Scope::Variable const& _var) + { + ++m_variableReferences[&_var]; + }, + [](Scope::Function const&) { } + }); +} diff --git a/libyul/backends/evm/VariableReferenceCounter.h b/libyul/backends/evm/VariableReferenceCounter.h new file mode 100644 index 000000000..ba6404b17 --- /dev/null +++ b/libyul/backends/evm/VariableReferenceCounter.h @@ -0,0 +1,68 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +// SPDX-License-Identifier: GPL-3.0 +/** + * Counts the number of references to a variable. + */ +#pragma once + +#include +#include + +namespace solidity::yul +{ +struct AsmAnalysisInfo; + +/** + * Counts the number of references to a variable. This includes actual (read) references + * but also assignments to the variable. It does not include the declaration itself or + * function parameters, but it does include function return parameters. + * + * This component can handle multiple variables of the same name. + * + * Can only be applied to strict assembly. + */ +struct VariableReferenceCounter: public yul::ASTWalker +{ +public: + static std::map run(AsmAnalysisInfo const& _assemblyInfo, Block const& _block) + { + VariableReferenceCounter variableReferenceCounter(_assemblyInfo); + variableReferenceCounter(_block); + return std::move(variableReferenceCounter.m_variableReferences); + } + +protected: + void operator()(Block const& _block) override; + void operator()(Identifier const& _identifier) override; + void operator()(FunctionDefinition const&) override; + void operator()(ForLoop const&) override; + +private: + explicit VariableReferenceCounter( + AsmAnalysisInfo const& _assemblyInfo + ): m_info(_assemblyInfo) + {} + + void increaseRefIfFound(YulString _variableName); + + AsmAnalysisInfo const& m_info; + Scope* m_scope = nullptr; + std::map m_variableReferences; +}; + +}