diff options
author | Alex Beregszaszi <alex@rtfs.hu> | 2018-01-16 23:12:52 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-16 23:12:52 +0800 |
commit | fc7733c053b6964ded3827e5639de06624b11223 (patch) | |
tree | e4759b98024d673fc7e75496136378087d22b03b | |
parent | 14fcbd659fcdadf6c4314bdfcfbbe65fbc792c4a (diff) | |
parent | 95cf9266abafc07bb4d7b33dff6932c191c36970 (diff) | |
download | dexon-solidity-fc7733c053b6964ded3827e5639de06624b11223.tar.gz dexon-solidity-fc7733c053b6964ded3827e5639de06624b11223.tar.zst dexon-solidity-fc7733c053b6964ded3827e5639de06624b11223.zip |
Merge pull request #3352 from ethereum/movability
Movability check
-rw-r--r-- | libevmasm/SemanticInformation.cpp | 25 | ||||
-rw-r--r-- | libevmasm/SemanticInformation.h | 4 | ||||
-rw-r--r-- | libjulia/optimiser/ASTWalker.cpp | 14 | ||||
-rw-r--r-- | libjulia/optimiser/ASTWalker.h | 26 | ||||
-rw-r--r-- | libjulia/optimiser/Disambiguator.h | 1 | ||||
-rw-r--r-- | libjulia/optimiser/Semantics.cpp | 60 | ||||
-rw-r--r-- | libjulia/optimiser/Semantics.h | 62 |
7 files changed, 176 insertions, 16 deletions
diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp index 61a6ccda..4c2290c4 100644 --- a/libevmasm/SemanticInformation.cpp +++ b/libevmasm/SemanticInformation.cpp @@ -153,6 +153,31 @@ bool SemanticInformation::isDeterministic(AssemblyItem const& _item) } } +bool SemanticInformation::movable(Instruction _instruction) +{ + // These are not really functional. + if (isDupInstruction(_instruction) || isSwapInstruction(_instruction)) + return false; + InstructionInfo info = instructionInfo(_instruction); + if (info.sideEffects) + return false; + switch (_instruction) + { + case Instruction::KECCAK256: + case Instruction::BALANCE: + case Instruction::EXTCODESIZE: + case Instruction::RETURNDATASIZE: + case Instruction::SLOAD: + case Instruction::PC: + case Instruction::MSIZE: + case Instruction::GAS: + return false; + default: + return true; + } + return true; +} + bool SemanticInformation::invalidatesMemory(Instruction _instruction) { switch (_instruction) diff --git a/libevmasm/SemanticInformation.h b/libevmasm/SemanticInformation.h index e5ea7c18..83656252 100644 --- a/libevmasm/SemanticInformation.h +++ b/libevmasm/SemanticInformation.h @@ -49,6 +49,10 @@ struct SemanticInformation /// @returns false if the value put on the stack by _item depends on anything else than /// the information in the current block header, memory, storage or stack. static bool isDeterministic(AssemblyItem const& _item); + /// @returns true if the instruction can be moved or copied (together with its arguments) + /// without altering the semantics. This means it cannot depend on storage or memory, + /// cannot have any side-effects, but it can depend on a call-constant state of the blockchain. + static bool movable(solidity::Instruction _instruction); /// @returns true if the given instruction modifies memory. static bool invalidatesMemory(solidity::Instruction _instruction); /// @returns true if the given instruction modifies storage (even indirectly). diff --git a/libjulia/optimiser/ASTWalker.cpp b/libjulia/optimiser/ASTWalker.cpp index 499b4bf2..6386b29d 100644 --- a/libjulia/optimiser/ASTWalker.cpp +++ b/libjulia/optimiser/ASTWalker.cpp @@ -44,31 +44,31 @@ void ASTWalker::operator()(FunctionCall const& _funCall) void ASTWalker::operator()(ExpressionStatement const& _statement) { - boost::apply_visitor(*this, _statement.expression); + visit(_statement.expression); } void ASTWalker::operator()(Assignment const& _assignment) { for (auto const& name: _assignment.variableNames) (*this)(name); - boost::apply_visitor(*this, *_assignment.value); + visit(*_assignment.value); } void ASTWalker::operator()(VariableDeclaration const& _varDecl) { if (_varDecl.value) - boost::apply_visitor(*this, *_varDecl.value); + visit(*_varDecl.value); } void ASTWalker::operator()(If const& _if) { - boost::apply_visitor(*this, *_if.condition); + visit(*_if.condition); (*this)(_if.body); } void ASTWalker::operator()(Switch const& _switch) { - boost::apply_visitor(*this, *_switch.expression); + visit(*_switch.expression); for (auto const& _case: _switch.cases) { if (_case.value) @@ -85,7 +85,7 @@ void ASTWalker::operator()(FunctionDefinition const& _fun) void ASTWalker::operator()(ForLoop const& _for) { (*this)(_for.pre); - boost::apply_visitor(*this, *_for.condition); + visit(*_for.condition); (*this)(_for.post); (*this)(_for.body); } @@ -107,7 +107,7 @@ void ASTModifier::operator()(FunctionCall& _funCall) void ASTModifier::operator()(ExpressionStatement& _statement) { - boost::apply_visitor(*this, _statement.expression); + visit(_statement.expression); } void ASTModifier::operator()(Assignment& _assignment) diff --git a/libjulia/optimiser/ASTWalker.h b/libjulia/optimiser/ASTWalker.h index 4652a353..dbf8194b 100644 --- a/libjulia/optimiser/ASTWalker.h +++ b/libjulia/optimiser/ASTWalker.h @@ -58,12 +58,21 @@ public: virtual void operator()(ForLoop const&); virtual void operator()(Block const& _block); + virtual void visit(Statement const& _st) + { + boost::apply_visitor(*this, _st); + } + virtual void visit(Expression const& _e) + { + boost::apply_visitor(*this, _e); + } + protected: template <class T> void walkVector(T const& _statements) { for (auto const& st: _statements) - boost::apply_visitor(*this, st); + visit(st); } }; @@ -89,13 +98,6 @@ public: virtual void operator()(ForLoop&); virtual void operator()(Block& _block); -protected: - template <class T> - void walkVector(T&& _statements) - { - for (auto& st: _statements) - visit(st); - } virtual void visit(Statement& _st) { boost::apply_visitor(*this, _st); @@ -104,6 +106,14 @@ protected: { boost::apply_visitor(*this, _e); } + +protected: + template <class T> + void walkVector(T&& _statements) + { + for (auto& st: _statements) + visit(st); + } }; } diff --git a/libjulia/optimiser/Disambiguator.h b/libjulia/optimiser/Disambiguator.h index cc9488d5..18ffd157 100644 --- a/libjulia/optimiser/Disambiguator.h +++ b/libjulia/optimiser/Disambiguator.h @@ -35,7 +35,6 @@ namespace dev { namespace julia { -class EVMAssembly; /** * Creates a copy of a iulia AST replacing all identifiers by unique names. diff --git a/libjulia/optimiser/Semantics.cpp b/libjulia/optimiser/Semantics.cpp new file mode 100644 index 00000000..92728c46 --- /dev/null +++ b/libjulia/optimiser/Semantics.cpp @@ -0,0 +1,60 @@ +/*( + 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 <http://www.gnu.org/licenses/>. +*/ +/** + * Specific AST walkers that collect semantical facts. + */ + +#include <libjulia/optimiser/Semantics.h> + +#include <libsolidity/inlineasm/AsmData.h> + +#include <libevmasm/SemanticInformation.h> + +#include <libdevcore/CommonData.h> + +using namespace std; +using namespace dev; +using namespace dev::julia; + +MovableChecker::MovableChecker(Expression const& _expression) +{ + visit(_expression); +} + +void MovableChecker::operator()(Identifier const& _identifier) +{ + ASTWalker::operator()(_identifier); + m_variableReferences.insert(_identifier.name); +} + +void MovableChecker::operator()(FunctionalInstruction const& _instr) +{ + if (!eth::SemanticInformation::movable(_instr.instruction)) + m_movable = false; + else + ASTWalker::operator()(_instr); +} + +void MovableChecker::operator()(FunctionCall const&) +{ + m_movable = false; +} + +void MovableChecker::visit(Statement const&) +{ + solAssert(false, "Movability for statement requested."); +} diff --git a/libjulia/optimiser/Semantics.h b/libjulia/optimiser/Semantics.h new file mode 100644 index 00000000..6df5f01a --- /dev/null +++ b/libjulia/optimiser/Semantics.h @@ -0,0 +1,62 @@ +/* + 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 <http://www.gnu.org/licenses/>. +*/ +/** + * Specific AST walkers that collect semantical facts. + */ + +#pragma once + +#include <libjulia/optimiser/ASTWalker.h> + +#include <string> +#include <map> +#include <set> + +namespace dev +{ +namespace julia +{ + +/** + * Specific AST walker that determines whether an expression is movable. + */ +class MovableChecker: public ASTWalker +{ +public: + MovableChecker() = default; + explicit MovableChecker(Expression const& _expression); + + virtual void operator()(Identifier const& _identifier) override; + virtual void operator()(FunctionalInstruction const& _functionalInstruction) override; + virtual void operator()(FunctionCall const& _functionCall) override; + + /// Disallow visiting anything apart from Expressions (this throws). + virtual void visit(Statement const&) override; + using ASTWalker::visit; + + bool movable() const { return m_movable; } + std::set<std::string> const& referencedVariables() const { return m_variableReferences; } + +private: + /// Which variables the current expression references. + std::set<std::string> m_variableReferences; + /// Is the current expression movable or not. + bool m_movable = true; +}; + +} +} |