aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ASTVisitor.h20
-rw-r--r--CompilerStack.cpp38
-rw-r--r--CompilerStack.h5
-rw-r--r--StructuralGasEstimator.cpp39
-rw-r--r--StructuralGasEstimator.h4
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);
};
}