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&) { }
|
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.
|
* 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.
|
* 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):
|
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
|
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 CompilerStack::addSource(string const& _name, string const& _content, bool _isLibrary)
|
||||||
{
|
{
|
||||||
bool existed = m_sources.count(_name) != 0;
|
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);
|
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()
|
void CompilerStack::resolveImports()
|
||||||
{
|
{
|
||||||
// topological sorting (depth first search) of the import graph, cutting potential cycles
|
// 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.
|
/// Creates a new compiler stack. Adds standard sources if @a _addStandardSources.
|
||||||
explicit CompilerStack(bool _addStandardSources = true);
|
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.
|
/// 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.
|
/// @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); }
|
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();
|
Contract();
|
||||||
};
|
};
|
||||||
|
|
||||||
void reset(bool _keepSources = false);
|
|
||||||
void resolveImports();
|
void resolveImports();
|
||||||
|
|
||||||
Contract const& getContract(std::string const& _contractName = "") const;
|
Contract const& getContract(std::string const& _contractName = "") const;
|
||||||
Source const& getSource(std::string const& _sourceName = "") const;
|
Source const& getSource(std::string const& _sourceName = "") const;
|
||||||
|
|
||||||
bool m_addStandardSources; ///< If true, standard sources are added.
|
|
||||||
bool m_parseSuccessful;
|
bool m_parseSuccessful;
|
||||||
std::map<std::string const, Source> m_sources;
|
std::map<std::string const, Source> m_sources;
|
||||||
std::shared_ptr<GlobalContext> m_globalContext;
|
std::shared_ptr<GlobalContext> m_globalContext;
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
#include "StructuralGasEstimator.h"
|
#include "StructuralGasEstimator.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <libevmasm/ControlFlowGraph.h>
|
||||||
|
#include <libevmasm/KnownState.h>
|
||||||
#include <libsolidity/AST.h>
|
#include <libsolidity/AST.h>
|
||||||
#include <libsolidity/ASTVisitor.h>
|
#include <libsolidity/ASTVisitor.h>
|
||||||
|
|
||||||
@ -38,14 +41,23 @@ StructuralGasEstimator::ASTGasConsumptionSelfAccumulated StructuralGasEstimator:
|
|||||||
{
|
{
|
||||||
solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, "");
|
solAssert(std::count(_ast.begin(), _ast.end(), nullptr) == 0, "");
|
||||||
map<SourceLocation, GasMeter::GasConsumption> particularCosts;
|
map<SourceLocation, GasMeter::GasConsumption> particularCosts;
|
||||||
GasMeter meter;
|
|
||||||
|
|
||||||
for (auto const& item: _items)
|
ControlFlowGraph cfg(_items);
|
||||||
particularCosts[item.getLocation()] += meter.estimateMax(item);
|
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;
|
ASTGasConsumptionSelfAccumulated gasCosts;
|
||||||
auto onNode = [&](ASTNode const& _node)
|
auto onNode = [&](ASTNode const& _node)
|
||||||
{
|
{
|
||||||
|
if (!finestNodes.count(&_node))
|
||||||
|
return true;
|
||||||
gasCosts[&_node][0] = gasCosts[&_node][1] = particularCosts[_node.getLocation()];
|
gasCosts[&_node][0] = gasCosts[&_node][1] = particularCosts[_node.getLocation()];
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
@ -108,3 +120,24 @@ map<ASTNode const*, GasMeter::GasConsumption> StructuralGasEstimator::breakToSta
|
|||||||
// gasCosts should only contain non-overlapping locations
|
// gasCosts should only contain non-overlapping locations
|
||||||
return gasCosts;
|
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,
|
ASTGasConsumptionSelfAccumulated const& _gasCosts,
|
||||||
std::vector<ASTNode const*> const& _roots
|
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