Skip to content

Commit

Permalink
Merge pull request #14050 from ethereum/contract-ast-internal-functio…
Browse files Browse the repository at this point in the history
…n-ids

Annotate internal function IDs
  • Loading branch information
ekpyron committed Apr 12, 2023
2 parents 46457cf + a0e62bb commit 6bc6ae9
Show file tree
Hide file tree
Showing 11 changed files with 1,631 additions and 27 deletions.
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Bugfixes:
* Antlr Grammar: Stricter rules for function definitions. The grammar will no longer accept as valid free functions having specifiers which are exclusive to contract functions.


AST Changes:
* AST: add the ``internalFunctionID`` field to the AST nodes of functions that may be called via the internal dispatch. These IDs are always generated, but they are only used in via-IR code generation.


### 0.8.19 (2023-02-22)

Language Features:
Expand Down
1 change: 1 addition & 0 deletions libsolidity/ast/ASTAnnotations.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ struct CallableDeclarationAnnotation: DeclarationAnnotation

struct FunctionDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation
{
util::SetOnce<uint64_t> internalFunctionID;
};

struct EventDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation
Expand Down
4 changes: 4 additions & 0 deletions libsolidity/ast/ASTJsonExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,10 @@ bool ASTJsonExporter::visit(FunctionDefinition const& _node)
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
if (!_node.annotation().baseFunctions.empty())
attributes.emplace_back(make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true)));

if (_node.annotation().internalFunctionID.set())
attributes.emplace_back("internalFunctionID", *_node.annotation().internalFunctionID);

setJsonNode(_node, "FunctionDefinition", std::move(attributes));
return false;
}
Expand Down
14 changes: 0 additions & 14 deletions libsolidity/codegen/ir/IRGenerationContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,17 +177,3 @@ 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: 0 additions & 10 deletions libsolidity/codegen/ir/IRGenerationContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,6 @@ class IRGenerationContext
bool memoryUnsafeInlineAssemblySeen() const { return m_memoryUnsafeInlineAssemblySeen; }
void setMemoryUnsafeInlineAssemblySeen() { m_memoryUnsafeInlineAssemblySeen = 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; }
void markSourceUsed(std::string const& _name) { m_usedSourceNames.insert(_name); }
std::set<std::string> const& usedSourceNames() const { return m_usedSourceNames; }
Expand Down Expand Up @@ -219,8 +211,6 @@ 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
3 changes: 1 addition & 2 deletions libsolidity/codegen/ir/IRGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin
solAssert(m_context.functionCollector().contains(IRNames::function(*function)), "");

cases.emplace_back(map<string, string>{
{"funID", to_string(m_context.internalFunctionID(*function, true))},
{"funID", to_string(*function->annotation().internalFunctionID)},
{"name", IRNames::function(*function)}
});
}
Expand Down Expand Up @@ -1117,7 +1117,6 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon
m_context.debugInfoSelection(),
m_context.soliditySourceProvider()
);
newContext.copyFunctionIDsFrom(m_context);
m_context = std::move(newContext);

m_context.setMostDerivedContract(_contract);
Expand Down
2 changes: 1 addition & 1 deletion libsolidity/codegen/ir/IRGeneratorForStatements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2807,7 +2807,7 @@ void IRGeneratorForStatements::assignInternalFunctionIDIfNotCalledDirectly(
return;

define(IRVariable(_expression).part("functionIdentifier")) <<
to_string(m_context.internalFunctionID(_referencedFunction, false)) <<
to_string(*_referencedFunction.annotation().internalFunctionID) <<
"\n";
m_context.addToInternalDispatch(_referencedFunction);
}
Expand Down
29 changes: 29 additions & 0 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ bool CompilerStack::analyze()
if (noErrors)
{
createAndAssignCallGraphs();
annotateInternalFunctionIDs();
findAndReportCyclicContractDependencies();
}

Expand Down Expand Up @@ -1245,6 +1246,34 @@ void CompilerStack::storeContractDefinitions()
}
}

void CompilerStack::annotateInternalFunctionIDs()
{
uint64_t internalFunctionID = 1;
for (Source const* source: m_sourceOrder)
{
if (!source->ast)
continue;

for (ContractDefinition const* contract: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes()))
{
ContractDefinitionAnnotation& annotation = contract->annotation();

if (auto const* deployTimeInternalDispatch = util::valueOrNullptr((*annotation.deployedCallGraph)->edges, CallGraph::SpecialNode::InternalDispatch))
for (auto const& node: *deployTimeInternalDispatch)
if (auto const* callable = get_if<CallableDeclaration const*>(&node))
if (auto const* function = dynamic_cast<FunctionDefinition const*>(*callable))
if (!function->annotation().internalFunctionID.set())
function->annotation().internalFunctionID = internalFunctionID++;
if (auto const* creationTimeInternalDispatch = util::valueOrNullptr((*annotation.creationCallGraph)->edges, CallGraph::SpecialNode::InternalDispatch))
for (auto const& node: *creationTimeInternalDispatch)
if (auto const* callable = get_if<CallableDeclaration const*>(&node))
if (auto const* function = dynamic_cast<FunctionDefinition const*>(*callable))
// Make sure the function already got an ID since it also occurs in the deploy-time internal dispatch.
solAssert(function->annotation().internalFunctionID.set());
}
}
}

namespace
{
bool onlySafeExperimentalFeaturesActivated(set<ExperimentalFeature> const& features)
Expand Down
3 changes: 3 additions & 0 deletions libsolidity/interface/CompilerStack.h
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ class CompilerStack: public langutil::CharStreamProvider
/// Store the contract definitions in m_contracts.
void storeContractDefinitions();

/// Annotate internal dispatch function Ids
void annotateInternalFunctionIDs();

/// @returns true if the source is requested to be compiled.
bool isRequestedSource(std::string const& _sourceName) const;

Expand Down

0 comments on commit 6bc6ae9

Please sign in to comment.