Move AST annotation of internal function dispatch IDs to ContractDefinition

Co-authored-by: Daniel <daniel@ekpyron.org>
Co-authored-by: Nikola Matić <nikola.matic@ethereum.org>
This commit is contained in:
Rodrigo Q. Saramago 2023-05-02 15:30:59 +02:00
parent 41742c5410
commit a29f77369a
No known key found for this signature in database
GPG Key ID: 9B36B2525704A359
9 changed files with 1110 additions and 17 deletions

View File

@ -25,7 +25,7 @@ Bugfixes:
AST Changes: 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. * 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.

View File

@ -168,6 +168,9 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocu
/// List of contracts whose bytecode is referenced by this contract, e.g. through "new". /// List of contracts whose bytecode is referenced by this contract, e.g. through "new".
/// The Value represents the ast node that referenced the contract. /// The Value represents the ast node that referenced the contract.
std::map<ContractDefinition const*, ASTNode const*, ASTCompareByID<ContractDefinition>> contractDependencies; 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 struct CallableDeclarationAnnotation: DeclarationAnnotation
@ -178,7 +181,6 @@ struct CallableDeclarationAnnotation: DeclarationAnnotation
struct FunctionDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation struct FunctionDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation
{ {
util::SetOnce<uint64_t> internalFunctionID;
}; };
struct EventDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation struct EventDefinitionAnnotation: CallableDeclarationAnnotation, StructurallyDocumentedAnnotation

View File

@ -299,6 +299,14 @@ bool ASTJsonExporter::visit(ContractDefinition const& _node)
if (!_node.annotation().linearizedBaseContracts.empty()) if (!_node.annotation().linearizedBaseContracts.empty())
attributes.emplace_back("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)); 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)); setJsonNode(_node, "ContractDefinition", std::move(attributes));
return false; return false;
} }
@ -473,9 +481,6 @@ bool ASTJsonExporter::visit(FunctionDefinition const& _node)
if (!_node.annotation().baseFunctions.empty()) if (!_node.annotation().baseFunctions.empty())
attributes.emplace_back(make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true))); 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)); setJsonNode(_node, "FunctionDefinition", std::move(attributes));
return false; return false;
} }

View File

@ -313,7 +313,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin
solAssert(m_context.functionCollector().contains(IRNames::function(*function)), ""); solAssert(m_context.functionCollector().contains(IRNames::function(*function)), "");
cases.emplace_back(map<string, string>{ 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)} {"name", IRNames::function(*function)}
}); });
} }

View File

@ -2807,7 +2807,7 @@ void IRGeneratorForStatements::assignInternalFunctionIDIfNotCalledDirectly(
return; return;
define(IRVariable(_expression).part("functionIdentifier")) << define(IRVariable(_expression).part("functionIdentifier")) <<
to_string(*_referencedFunction.annotation().internalFunctionID) << to_string(m_context.mostDerivedContract().annotation().internalFunctionIDs.at(&_referencedFunction)) <<
"\n"; "\n";
m_context.addToInternalDispatch(_referencedFunction); m_context.addToInternalDispatch(_referencedFunction);
} }

View File

@ -1246,7 +1246,6 @@ void CompilerStack::storeContractDefinitions()
void CompilerStack::annotateInternalFunctionIDs() void CompilerStack::annotateInternalFunctionIDs()
{ {
uint64_t internalFunctionID = 1;
for (Source const* source: m_sourceOrder) for (Source const* source: m_sourceOrder)
{ {
if (!source->ast) if (!source->ast)
@ -1254,20 +1253,23 @@ void CompilerStack::annotateInternalFunctionIDs()
for (ContractDefinition const* contract: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes())) for (ContractDefinition const* contract: ASTNode::filteredNodes<ContractDefinition>(source->ast->nodes()))
{ {
uint64_t internalFunctionID = 1;
ContractDefinitionAnnotation& annotation = contract->annotation(); ContractDefinitionAnnotation& annotation = contract->annotation();
if (auto const* deployTimeInternalDispatch = util::valueOrNullptr((*annotation.deployedCallGraph)->edges, CallGraph::SpecialNode::InternalDispatch)) if (auto const* deployTimeInternalDispatch = util::valueOrNullptr((*annotation.deployedCallGraph)->edges, CallGraph::SpecialNode::InternalDispatch))
for (auto const& node: *deployTimeInternalDispatch) for (auto const& node: *deployTimeInternalDispatch)
if (auto const* callable = get_if<CallableDeclaration const*>(&node)) if (auto const* callable = get_if<CallableDeclaration const*>(&node))
if (auto const* function = dynamic_cast<FunctionDefinition const*>(*callable)) 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)) if (auto const* creationTimeInternalDispatch = util::valueOrNullptr((*annotation.creationCallGraph)->edges, CallGraph::SpecialNode::InternalDispatch))
for (auto const& node: *creationTimeInternalDispatch) for (auto const& node: *creationTimeInternalDispatch)
if (auto const* callable = get_if<CallableDeclaration const*>(&node)) if (auto const* callable = get_if<CallableDeclaration const*>(&node))
if (auto const* function = dynamic_cast<FunctionDefinition const*>(*callable)) 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. // 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);
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
==== Source: L ====
function free1() {}
function free2() {}
library L {
function g() internal {}
function h() internal {}
}
==== Source: A ====
import "L";
contract A {
function f() public {
(L.g)();
(free2)();
(L.h)();
}
}
contract B {
function f() public {
(L.h)();
(free2)();
}
}
==== Source: C ====
import "L";
contract C {
function f() public {
(L.g)();
(free2)();
(L.h)();
}
}
// ----

View File

@ -41,7 +41,6 @@
}, },
"id": 4, "id": 4,
"implemented": true, "implemented": true,
"internalFunctionID": 1,
"kind": "freeFunction", "kind": "freeFunction",
"modifiers": [], "modifiers": [],
"name": "free1", "name": "free1",
@ -77,7 +76,6 @@
}, },
"id": 8, "id": 8,
"implemented": true, "implemented": true,
"internalFunctionID": 2,
"kind": "freeFunction", "kind": "freeFunction",
"modifiers": [], "modifiers": [],
"name": "free2", "name": "free2",
@ -146,6 +144,13 @@
"contractKind": "library", "contractKind": "library",
"fullyImplemented": true, "fullyImplemented": true,
"id": 53, "id": 53,
"internalFunctionIDs":
{
"20": 3,
"24": 4,
"4": 1,
"8": 2
},
"linearizedBaseContracts": "linearizedBaseContracts":
[ [
53 53
@ -201,7 +206,6 @@
}, },
"id": 20, "id": 20,
"implemented": true, "implemented": true,
"internalFunctionID": 3,
"kind": "function", "kind": "function",
"modifiers": [], "modifiers": [],
"name": "inr1", "name": "inr1",
@ -237,7 +241,6 @@
}, },
"id": 24, "id": 24,
"implemented": true, "implemented": true,
"internalFunctionID": 4,
"kind": "function", "kind": "function",
"modifiers": [], "modifiers": [],
"name": "inr2", "name": "inr2",
@ -579,6 +582,15 @@
"contractKind": "contract", "contractKind": "contract",
"fullyImplemented": true, "fullyImplemented": true,
"id": 128, "id": 128,
"internalFunctionIDs":
{
"20": 3,
"24": 4,
"4": 1,
"69": 5,
"73": 6,
"8": 2
},
"linearizedBaseContracts": "linearizedBaseContracts":
[ [
128 128
@ -706,7 +718,6 @@
}, },
"id": 69, "id": 69,
"implemented": true, "implemented": true,
"internalFunctionID": 5,
"kind": "function", "kind": "function",
"modifiers": [], "modifiers": [],
"name": "inr1", "name": "inr1",
@ -742,7 +753,6 @@
}, },
"id": 73, "id": 73,
"implemented": true, "implemented": true,
"internalFunctionID": 6,
"kind": "function", "kind": "function",
"modifiers": [], "modifiers": [],
"name": "inr2", "name": "inr2",
@ -1405,6 +1415,15 @@
"contractKind": "contract", "contractKind": "contract",
"fullyImplemented": true, "fullyImplemented": true,
"id": 141, "id": 141,
"internalFunctionIDs":
{
"20": 3,
"24": 4,
"4": 1,
"69": 5,
"73": 6,
"8": 2
},
"linearizedBaseContracts": "linearizedBaseContracts":
[ [
141, 141,