Gas estimation taking known state into account.

This commit is contained in:
chriseth 2015-05-20 00:27:07 +02:00
parent 70d9eb3f1d
commit 2be64c7026
5 changed files with 82 additions and 24 deletions

View File

@ -220,6 +220,26 @@ protected:
virtual void endVisitNode(ASTNode const&) { }
};
/**
* 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.

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
};
}