diff options
-rw-r--r-- | ASTVisitor.h | 20 | ||||
-rw-r--r-- | CompilerStack.cpp | 38 | ||||
-rw-r--r-- | CompilerStack.h | 5 | ||||
-rw-r--r-- | StructuralGasEstimator.cpp | 39 | ||||
-rw-r--r-- | StructuralGasEstimator.h | 4 |
5 files changed, 82 insertions, 24 deletions
diff --git a/ASTVisitor.h b/ASTVisitor.h index fbda5079..f7847220 100644 --- a/ASTVisitor.h +++ b/ASTVisitor.h @@ -221,6 +221,26 @@ protected: }; /** + * Utility class that accepts std::functions and calls them for visitNode and endVisitNode. + */ +class SimpleASTVisitor: public ASTConstVisitor +{ +public: + SimpleASTVisitor( + std::function<bool(ASTNode const&)> _onVisit, + std::function<void(ASTNode const&)> _onEndVisit + ): m_onVisit(_onVisit), m_onEndVisit(_onEndVisit) {} + +protected: + virtual bool visitNode(ASTNode const& _n) override { return m_onVisit ? m_onVisit(_n) : true; } + virtual void endVisitNode(ASTNode const& _n) override { m_onEndVisit(_n); } + +private: + std::function<bool(ASTNode const&)> m_onVisit; + std::function<void(ASTNode const&)> m_onEndVisit; +}; + +/** * Utility class that visits the AST in depth-first order and calls a function on each node and each edge. * Child nodes are only visited if the node callback of the parent returns true. * The node callback of a parent is called before any edge or node callback involving the children. diff --git a/CompilerStack.cpp b/CompilerStack.cpp index bffa4158..4f976407 100644 --- a/CompilerStack.cpp +++ b/CompilerStack.cpp @@ -55,12 +55,29 @@ const map<string, string> StandardSources = map<string, string>{ }; CompilerStack::CompilerStack(bool _addStandardSources): - m_addStandardSources(_addStandardSources), m_parseSuccessful(false) + m_parseSuccessful(false) { - if (m_addStandardSources) + if (_addStandardSources) addSources(StandardSources, true); // add them as libraries } +void CompilerStack::reset(bool _keepSources, bool _addStandardSources) +{ + m_parseSuccessful = false; + if (_keepSources) + for (auto sourcePair: m_sources) + sourcePair.second.reset(); + else + { + m_sources.clear(); + if (_addStandardSources) + addSources(StandardSources, true); + } + m_globalContext.reset(); + m_sourceOrder.clear(); + m_contracts.clear(); +} + bool CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary) { bool existed = m_sources.count(_name) != 0; @@ -269,23 +286,6 @@ tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocati return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn); } -void CompilerStack::reset(bool _keepSources) -{ - m_parseSuccessful = false; - if (_keepSources) - for (auto sourcePair: m_sources) - sourcePair.second.reset(); - else - { - m_sources.clear(); - if (m_addStandardSources) - addSources(StandardSources, true); - } - m_globalContext.reset(); - m_sourceOrder.clear(); - m_contracts.clear(); -} - void CompilerStack::resolveImports() { // topological sorting (depth first search) of the import graph, cutting potential cycles diff --git a/CompilerStack.h b/CompilerStack.h index 2ad791f2..0bc109a2 100644 --- a/CompilerStack.h +++ b/CompilerStack.h @@ -72,6 +72,9 @@ public: /// Creates a new compiler stack. Adds standard sources if @a _addStandardSources. explicit CompilerStack(bool _addStandardSources = true); + /// Resets the compiler to a state where the sources are not parsed or even removed. + void reset(bool _keepSources = false, bool _addStandardSources = true); + /// Adds a source object (e.g. file) to the parser. After this, parse has to be called again. /// @returns true if a source object by the name already existed and was replaced. void addSources(StringMap const& _nameContents, bool _isLibrary = false) { for (auto const& i: _nameContents) addSource(i.first, i.second, _isLibrary); } @@ -165,13 +168,11 @@ private: Contract(); }; - void reset(bool _keepSources = false); void resolveImports(); Contract const& getContract(std::string const& _contractName = "") const; Source const& getSource(std::string const& _sourceName = "") const; - bool m_addStandardSources; ///< If true, standard sources are added. bool m_parseSuccessful; std::map<std::string const, Source> m_sources; std::shared_ptr<GlobalContext> m_globalContext; diff --git a/StructuralGasEstimator.cpp b/StructuralGasEstimator.cpp index ececd711..9ce32ca5 100644 --- a/StructuralGasEstimator.cpp +++ b/StructuralGasEstimator.cpp @@ -23,6 +23,9 @@ #include "StructuralGasEstimator.h" #include <map> #include <functional> +#include <memory> +#include <libevmasm/ControlFlowGraph.h> +#include <libevmasm/KnownState.h> #include <libsolidity/AST.h> #include <libsolidity/ASTVisitor.h> @@ -38,14 +41,23 @@ StructuralGasEstimator::ASTGasConsumptionSelfAccumulated StructuralGasEstimator: { solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, ""); map<SourceLocation, GasMeter::GasConsumption> particularCosts; - GasMeter meter; - for (auto const& item: _items) - particularCosts[item.getLocation()] += meter.estimateMax(item); + ControlFlowGraph cfg(_items); + for (BasicBlock const& block: cfg.optimisedBlocks()) + { + assertThrow(!!block.startState, OptimizerException, ""); + GasMeter meter(block.startState->copy()); + auto const end = _items.begin() + block.end; + for (auto iter = _items.begin() + block.begin; iter != end; ++iter) + particularCosts[iter->getLocation()] += meter.estimateMax(*iter); + } + set<ASTNode const*> finestNodes = finestNodesAtLocation(_ast); ASTGasConsumptionSelfAccumulated gasCosts; auto onNode = [&](ASTNode const& _node) { + if (!finestNodes.count(&_node)) + return true; gasCosts[&_node][0] = gasCosts[&_node][1] = particularCosts[_node.getLocation()]; return true; }; @@ -108,3 +120,24 @@ map<ASTNode const*, GasMeter::GasConsumption> StructuralGasEstimator::breakToSta // gasCosts should only contain non-overlapping locations return gasCosts; } + +set<ASTNode const*> StructuralGasEstimator::finestNodesAtLocation( + vector<ASTNode const*> const& _roots +) +{ + map<SourceLocation, ASTNode const*> locations; + set<ASTNode const*> nodes; + SimpleASTVisitor visitor(function<bool(ASTNode const&)>(), [&](ASTNode const& _n) + { + if (!locations.count(_n.getLocation())) + { + locations[_n.getLocation()] = &_n; + nodes.insert(&_n); + } + }); + + for (ASTNode const* root: _roots) + root->accept(visitor); + return nodes; +} + diff --git a/StructuralGasEstimator.h b/StructuralGasEstimator.h index df1ae509..ddc7c186 100644 --- a/StructuralGasEstimator.h +++ b/StructuralGasEstimator.h @@ -56,6 +56,10 @@ public: ASTGasConsumptionSelfAccumulated const& _gasCosts, std::vector<ASTNode const*> const& _roots ); + +private: + /// @returns the set of AST nodes which are the finest nodes at their location. + std::set<ASTNode const*> finestNodesAtLocation(std::vector<ASTNode const*> const& _roots); }; } |