Skip to content

Commit

Permalink
Merge pull request #11512 from ethereum/issue_10342
Browse files Browse the repository at this point in the history
[yul] Functions: Remove dependency on AST ID.
  • Loading branch information
chriseth committed Jun 23, 2021
2 parents e4cf371 + 8accf42 commit cbf1c3a
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 24 deletions.
14 changes: 14 additions & 0 deletions libsolidity/codegen/ir/IRGenerationContext.cpp
Expand Up @@ -177,3 +177,17 @@ ABIFunctions IRGenerationContext::abiFunctions()
{
return ABIFunctions(m_evmVersion, m_revertStrings, m_functions);
}

uint64_t IRGenerationContext::internalFunctionID(FunctionDefinition const& _function, bool _requirePresent)
{
auto [iterator, inserted] = m_functionIDs.try_emplace(_function.id(), m_functionIDs.size() + 1);
if (_requirePresent)
solAssert(!inserted, "");
return iterator->second;
}

void IRGenerationContext::copyFunctionIDsFrom(IRGenerationContext const& _other)
{
solAssert(m_functionIDs.empty(), "");
m_functionIDs = _other.m_functionIDs;
}
10 changes: 10 additions & 0 deletions libsolidity/codegen/ir/IRGenerationContext.h
Expand Up @@ -152,6 +152,14 @@ class IRGenerationContext
bool inlineAssemblySeen() const { return m_inlineAssemblySeen; }
void setInlineAssemblySeen() { m_inlineAssemblySeen = true; }

/// @returns the runtime ID to be used for the function in the dispatch routine
/// and for internal function pointers.
/// @param _requirePresent if false, generates a new ID if not yet done.
uint64_t internalFunctionID(FunctionDefinition const& _function, bool _requirePresent);
/// Copies the internal function IDs from the @a _other. For use in transferring
/// function IDs from constructor code to deployed code.
void copyFunctionIDsFrom(IRGenerationContext const& _other);

std::map<std::string, unsigned> const& sourceIndices() const { return m_sourceIndices; }

private:
Expand Down Expand Up @@ -191,6 +199,8 @@ class IRGenerationContext
/// 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;
/// Map used by @a internalFunctionID.
std::map<int64_t, uint64_t> m_functionIDs;

std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
};
Expand Down
6 changes: 4 additions & 2 deletions libsolidity/codegen/ir/IRGenerator.cpp
Expand Up @@ -299,7 +299,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin
solAssert(m_context.functionCollector().contains(IRNames::function(*function)), "");

cases.emplace_back(map<string, string>{
{"funID", to_string(function->id())},
{"funID", to_string(m_context.internalFunctionID(*function, true))},
{"name", IRNames::function(*function)}
});
}
Expand Down Expand Up @@ -1013,7 +1013,9 @@ void IRGenerator::resetContext(ContractDefinition const& _contract)
m_context.internalDispatchClean(),
"Reset internal dispatch map without consuming it."
);
m_context = IRGenerationContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings, m_context.sourceIndices());
IRGenerationContext newContext(m_evmVersion, m_context.revertStrings(), m_optimiserSettings, m_context.sourceIndices());
newContext.copyFunctionIDsFrom(m_context);
m_context = move(newContext);

m_context.setMostDerivedContract(_contract);
for (auto const& var: ContractType(_contract).stateVariables())
Expand Down
48 changes: 27 additions & 21 deletions libsolidity/codegen/ir/IRGeneratorForStatements.cpp
Expand Up @@ -1575,12 +1575,10 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
define(IRVariable(_memberAccess).part("self"), _memberAccess.expression());
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");
if (memberFunctionType->kind() == FunctionType::Kind::Internal)
{
auto const& functionDefinition = dynamic_cast<FunctionDefinition const&>(memberFunctionType->declaration());
define(IRVariable(_memberAccess).part("functionIdentifier")) << to_string(functionDefinition.id()) << "\n";
if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(functionDefinition);
}
assignInternalFunctionIDIfNotCalledDirectly(
_memberAccess,
dynamic_cast<FunctionDefinition const&>(memberFunctionType->declaration())
);
else if (
memberFunctionType->kind() == FunctionType::Kind::ArrayPush ||
memberFunctionType->kind() == FunctionType::Kind::ArrayPop
Expand Down Expand Up @@ -1918,11 +1916,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
*_memberAccess.annotation().referencedDeclaration
).resolveVirtual(m_context.mostDerivedContract(), super);

define(_memberAccess) << to_string(resolvedFunctionDef.id()) << "\n";
solAssert(resolvedFunctionDef.functionType(true), "");
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(resolvedFunctionDef);
assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, resolvedFunctionDef);
}
else if (auto const* variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
handleVariableReference(*variable, _memberAccess);
Expand All @@ -1934,11 +1930,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
break;
case FunctionType::Kind::Internal:
if (auto const* function = dynamic_cast<FunctionDefinition const*>(_memberAccess.annotation().referencedDeclaration))
{
define(_memberAccess) << to_string(function->id()) << "\n";
if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(*function);
}
assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, *function);
else
solAssert(false, "Function not found in member access");
break;
Expand Down Expand Up @@ -2021,10 +2013,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
solAssert(funType->kind() == FunctionType::Kind::Internal, "");
solAssert(*_memberAccess.annotation().requiredLookup == VirtualLookup::Static, "");

define(_memberAccess) << to_string(function->id()) << "\n";

if (!_memberAccess.annotation().calledDirectly)
m_context.addToInternalDispatch(*function);
assignInternalFunctionIDIfNotCalledDirectly(_memberAccess, *function);
}
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(_memberAccess.annotation().referencedDeclaration))
{
Expand Down Expand Up @@ -2268,12 +2257,10 @@ void IRGeneratorForStatements::endVisit(Identifier const& _identifier)
{
solAssert(*_identifier.annotation().requiredLookup == VirtualLookup::Virtual, "");
FunctionDefinition const& resolvedFunctionDef = functionDef->resolveVirtual(m_context.mostDerivedContract());
define(_identifier) << to_string(resolvedFunctionDef.id()) << "\n";

solAssert(resolvedFunctionDef.functionType(true), "");
solAssert(resolvedFunctionDef.functionType(true)->kind() == FunctionType::Kind::Internal, "");
if (!_identifier.annotation().calledDirectly)
m_context.addToInternalDispatch(resolvedFunctionDef);
assignInternalFunctionIDIfNotCalledDirectly(_identifier, resolvedFunctionDef);
}
else if (VariableDeclaration const* varDecl = dynamic_cast<VariableDeclaration const*>(declaration))
handleVariableReference(*varDecl, _identifier);
Expand Down Expand Up @@ -2592,6 +2579,25 @@ void IRGeneratorForStatements::appendBareCall(
appendCode() << templ.render();
}

void IRGeneratorForStatements::assignInternalFunctionIDIfNotCalledDirectly(
Expression const& _expression,
FunctionDefinition const& _referencedFunction
)
{
solAssert(
dynamic_cast<MemberAccess const*>(&_expression) ||
dynamic_cast<Identifier const*>(&_expression),
""
);
if (_expression.annotation().calledDirectly)
return;

define(IRVariable(_expression).part("functionIdentifier")) <<
to_string(m_context.internalFunctionID(_referencedFunction, false)) <<
"\n";
m_context.addToInternalDispatch(_referencedFunction);
}

IRVariable IRGeneratorForStatements::convert(IRVariable const& _from, Type const& _to)
{
if (_from.type() == _to)
Expand Down
8 changes: 8 additions & 0 deletions libsolidity/codegen/ir/IRGeneratorForStatements.h
Expand Up @@ -153,6 +153,14 @@ class IRGeneratorForStatements: public IRGeneratorForStatementsBase
std::vector<ASTPointer<Expression const>> const& _arguments
);

/// Requests and assigns the internal ID of the referenced function to the referencing
/// expression and adds the function to the internal dispatch.
/// If the function is called right away, it does nothing.
void assignInternalFunctionIDIfNotCalledDirectly(
Expression const& _expression,
FunctionDefinition const& _referencedFunction
);

/// Generates the required conversion code and @returns an IRVariable referring to the value of @a _variable
/// converted to type @a _to.
IRVariable convert(IRVariable const& _variable, Type const& _to);
Expand Down
Expand Up @@ -32,6 +32,6 @@ contract C {
// compileViaYul: also
// ----
// f() -> 42, 23, 34, 42, 42
// gas irOptimized: 111210
// gas irOptimized: 111180
// gas legacy: 112021
// gas legacyOptimized: 110548

0 comments on commit cbf1c3a

Please sign in to comment.