mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Gas estimation taking known state into account.
This commit is contained in:
parent
70d9eb3f1d
commit
2be64c7026
20
ASTVisitor.h
20
ASTVisitor.h
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user