Merge remote-tracking branch 'origin/develop' into breaking

This commit is contained in:
chriseth
2020-12-02 12:28:02 +01:00
185 changed files with 541 additions and 272 deletions
+12 -24
View File
@@ -128,7 +128,7 @@ void IRGenerationContext::initializeInternalDispatch(InternalDispatchMap _intern
{
solAssert(internalDispatchClean(), "");
for (set<FunctionDefinition const*> const& functions: _internalDispatch | boost::adaptors::map_values)
for (DispatchSet const& functions: _internalDispatch | boost::adaptors::map_values)
for (auto function: functions)
enqueueFunctionForCodeGeneration(*function);
@@ -137,38 +137,26 @@ void IRGenerationContext::initializeInternalDispatch(InternalDispatchMap _intern
InternalDispatchMap IRGenerationContext::consumeInternalDispatchMap()
{
m_directInternalFunctionCalls.clear();
InternalDispatchMap internalDispatch = move(m_internalDispatchMap);
m_internalDispatchMap.clear();
return internalDispatch;
}
void IRGenerationContext::internalFunctionCalledDirectly(Expression const& _expression)
void IRGenerationContext::addToInternalDispatch(FunctionDefinition const& _function)
{
solAssert(m_directInternalFunctionCalls.count(&_expression) == 0, "");
FunctionType const* functionType = TypeProvider::function(_function, FunctionType::Kind::Internal);
solAssert(functionType, "");
m_directInternalFunctionCalls.insert(&_expression);
YulArity arity = YulArity::fromType(*functionType);
if (m_internalDispatchMap.count(arity) != 0 && m_internalDispatchMap[arity].count(&_function) != 0)
// Note that m_internalDispatchMap[arity] is a set with a custom comparator, which looks at function IDs not definitions
solAssert(*m_internalDispatchMap[arity].find(&_function) == &_function, "Different definitions with the same function ID");
m_internalDispatchMap[arity].insert(&_function);
enqueueFunctionForCodeGeneration(_function);
}
void IRGenerationContext::internalFunctionAccessed(Expression const& _expression, FunctionDefinition const& _function)
{
solAssert(
IRHelpers::referencedFunctionDeclaration(_expression) &&
_function.resolveVirtual(mostDerivedContract()) ==
IRHelpers::referencedFunctionDeclaration(_expression)->resolveVirtual(mostDerivedContract()),
"Function definition does not match the expression"
);
if (m_directInternalFunctionCalls.count(&_expression) == 0)
{
FunctionType const* functionType = TypeProvider::function(_function, FunctionType::Kind::Internal);
solAssert(functionType, "");
m_internalDispatchMap[YulArity::fromType(*functionType)].insert(&_function);
enqueueFunctionForCodeGeneration(_function);
}
}
void IRGenerationContext::internalFunctionCalledThroughDispatch(YulArity const& _arity)
{
+18 -14
View File
@@ -44,7 +44,20 @@ namespace solidity::frontend
class YulUtilFunctions;
class ABIFunctions;
using InternalDispatchMap = std::map<YulArity, std::set<FunctionDefinition const*>>;
struct AscendingFunctionIDCompare
{
bool operator()(FunctionDefinition const* _f1, FunctionDefinition const* _f2) const
{
// NULLs always first.
if (_f1 != nullptr && _f2 != nullptr)
return _f1->id() < _f2->id();
else
return _f1 == nullptr;
}
};
using DispatchSet = std::set<FunctionDefinition const*, AscendingFunctionIDCompare>;
using InternalDispatchMap = std::map<YulArity, DispatchSet>;
/**
* Class that contains contextual information during IR generation.
@@ -108,7 +121,7 @@ public:
void initializeInternalDispatch(InternalDispatchMap _internalDispatchMap);
InternalDispatchMap consumeInternalDispatchMap();
bool internalDispatchClean() const { return m_internalDispatchMap.empty() && m_directInternalFunctionCalls.empty(); }
bool internalDispatchClean() const { return m_internalDispatchMap.empty(); }
/// Notifies the context that a function call that needs to go through internal dispatch was
/// encountered while visiting the AST. This ensures that the corresponding dispatch function
@@ -116,16 +129,8 @@ public:
/// the code contains a call to an uninitialized function variable).
void internalFunctionCalledThroughDispatch(YulArity const& _arity);
/// Notifies the context that a direct function call (i.e. not through internal dispatch) was
/// encountered while visiting the AST. This lets the context know that the function should
/// not be added to the dispatch (unless there are also indirect calls to it elsewhere else).
void internalFunctionCalledDirectly(Expression const& _expression);
/// Notifies the context that a name representing an internal function has been found while
/// visiting the AST. If the name has not been reported as a direct call using
/// @a internalFunctionCalledDirectly(), it's assumed to represent function variable access
/// and the function gets added to internal dispatch.
void internalFunctionAccessed(Expression const& _expression, FunctionDefinition const& _function);
/// Adds a function to the internal dispatch.
void addToInternalDispatch(FunctionDefinition const& _function);
/// @returns a new copy of the utility function generator (but using the same function set).
YulUtilFunctions utils();
@@ -177,14 +182,13 @@ private:
/// The order and duplicates are irrelevant here (hence std::set rather than std::queue) as
/// long as the order of Yul functions in the generated code is deterministic and the same on
/// all platforms - which is a property guaranteed by MultiUseYulFunctionCollector.
std::set<FunctionDefinition const*> m_functionGenerationQueue;
DispatchSet m_functionGenerationQueue;
/// Collection of functions that need to be callable via internal dispatch.
/// Note that having a key with an empty set of functions is a valid situation. It means that
/// the code contains a call via a pointer even though a specific function is never assigned to it.
/// It will fail at runtime but the code must still compile.
InternalDispatchMap m_internalDispatchMap;
std::set<Expression const*> m_directInternalFunctionCalls;
std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
};
@@ -35,7 +35,7 @@
#include <libevmasm/GasMeter.h>
#include <libyul/AsmPrinter.h>
#include <libyul/AsmData.h>
#include <libyul/AST.h>
#include <libyul/Dialect.h>
#include <libyul/optimiser/ASTCopier.h>
@@ -829,20 +829,6 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
return false;
}
bool IRGeneratorForStatements::visit(FunctionCall const& _functionCall)
{
setLocation(_functionCall);
FunctionTypePointer functionType = dynamic_cast<FunctionType const*>(&type(_functionCall.expression()));
if (
functionType &&
functionType->kind() == FunctionType::Kind::Internal &&
IRHelpers::referencedFunctionDeclaration(_functionCall.expression())
)
m_context.internalFunctionCalledDirectly(_functionCall.expression());
return true;
}
void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
{
setLocation(_functionCall);
@@ -1558,6 +1544,7 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options)
void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
{
setLocation(_memberAccess);
ASTString const& member = _memberAccess.memberName();
auto memberFunctionType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type);
Type::Category objectCategory = _memberAccess.expression().annotation().type->category();
@@ -1583,7 +1570,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
if (memberFunctionType->kind() == FunctionType::Kind::Internal)
{
define(IRVariable(_memberAccess).part("functionIdentifier")) << to_string(functionDefinition.id()) << "\n";
m_context.internalFunctionAccessed(_memberAccess, functionDefinition);
if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(functionDefinition);
}
else
{
@@ -1875,7 +1863,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
define(_memberAccess) << to_string(resolvedFunctionDef.id()) << "\n";
solAssert(resolvedFunctionDef.functionType(true), "");
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
m_context.internalFunctionAccessed(_memberAccess, resolvedFunctionDef);
if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(resolvedFunctionDef);
}
else if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
handleVariableReference(*variable, _memberAccess);
@@ -1889,7 +1878,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
{
define(_memberAccess) << to_string(function->id()) << "\n";
m_context.internalFunctionAccessed(_memberAccess, *function);
if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(*function);
}
else
solAssert(false, "Function not found in member access");
@@ -1964,7 +1954,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
define(_memberAccess) << to_string(function->id()) << "\n";
m_context.internalFunctionAccessed(_memberAccess, *function);
if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(*function);
}
break;
}
@@ -2208,7 +2200,8 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
solAssert(resolvedFunctionDef.functionType(true), "");
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
m_context.internalFunctionAccessed(_identifier, resolvedFunctionDef);
if (!_identifier.annotation().calledDirectly)
m_context.addToInternalDispatch(resolvedFunctionDef);
}
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
handleVariableReference(*varDecl, _identifier);
@@ -76,7 +76,6 @@ public:
void endVisit(Return const& _return) override;
void endVisit(UnaryOperation const& _unaryOperation) override;
bool visit(BinaryOperation const& _binOp) override;
bool visit(FunctionCall const& _funCall) override;
void endVisit(FunctionCall const& _funCall) override;
void endVisit(FunctionCallOptions const& _funCallOptions) override;
void endVisit(MemberAccess const& _memberAccess) override;