Skip to content

Commit

Permalink
Move AST annotation of internal function dispatch IDs to ContractDefi…
Browse files Browse the repository at this point in the history
…nition

Co-authored-by: Daniel <[email protected]>
Co-authored-by: Nikola Matić <[email protected]>
  • Loading branch information
3 people committed May 6, 2023
1 parent 41742c5 commit a29f773
Show file tree
Hide file tree
Showing 9 changed files with 1,110 additions and 17 deletions.
2 changes: 1 addition & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Bugfixes:


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.
* AST: Add the ``internalFunctionIDs`` field to the AST nodes of contracts containing IDs of functions that may be called via the internal dispatch. The field is a map from function AST IDs to internal dispatch function IDs. These IDs are always generated, but they are only used in via-IR code generation.
* AST: Add the ``usedEvents`` field to ``ContractDefinition`` which contains the AST IDs of all events emitted by the contract as well as all events defined and inherited by the contract.


Expand Down
4 changes: 3 additions & 1 deletion libsolidity/ast/ASTAnnotations.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocu
/// List of contracts whose bytecode is referenced by this contract, e.g. through "new".
/// The Value represents the ast node that referenced the contract.
std::map<ContractDefinition const*, ASTNode const*, ASTCompareByID<ContractDefinition>> contractDependencies;

// Per-contract map from function AST IDs to internal dispatch function IDs.
std::map<FunctionDefinition const*, uint64_t> internalFunctionIDs;
};

struct CallableDeclarationAnnotation: DeclarationAnnotation
Expand All @@ -178,7 +181,6 @@ struct CallableDeclarationAnnotation: DeclarationAnnotation

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

struct EventDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation
Expand Down
11 changes: 8 additions & 3 deletions libsolidity/ast/ASTJsonExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,14 @@ bool ASTJsonExporter::visit(ContractDefinition const& _node)
if (!_node.annotation().linearizedBaseContracts.empty())
attributes.emplace_back("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts));

if (!_node.annotation().internalFunctionIDs.empty())
{
Json::Value internalFunctionIDs(Json::objectValue);
for (auto const& [functionDefinition, internalFunctionID]: _node.annotation().internalFunctionIDs)
internalFunctionIDs[to_string(functionDefinition->id())] = internalFunctionID;
attributes.emplace_back("internalFunctionIDs", std::move(internalFunctionIDs));
}

setJsonNode(_node, "ContractDefinition", std::move(attributes));
return false;
}
Expand Down Expand Up @@ -473,9 +481,6 @@ bool ASTJsonExporter::visit(FunctionDefinition const& _node)
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
2 changes: 1 addition & 1 deletion 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(*function->annotation().internalFunctionID)},
{"funID", to_string(m_context.mostDerivedContract().annotation().internalFunctionIDs.at(function))},
{"name", IRNames::function(*function)}
});
}
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(*_referencedFunction.annotation().internalFunctionID) <<
to_string(m_context.mostDerivedContract().annotation().internalFunctionIDs.at(&_referencedFunction)) <<
"\n";
m_context.addToInternalDispatch(_referencedFunction);
}
Expand Down
10 changes: 6 additions & 4 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1246,28 +1246,30 @@ 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()))
{
uint64_t internalFunctionID = 1;
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++;
{
solAssert(contract->annotation().internalFunctionIDs.count(function) == 0);
contract->annotation().internalFunctionIDs[function] = 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());
solAssert(contract->annotation().internalFunctionIDs.count(function) != 0);
}
}
}
Expand Down
Loading

0 comments on commit a29f773

Please sign in to comment.