Move call graphs from CompilerStack to ContractDefinitionAnnotation

This commit is contained in:
Kamil Śliwak 2021-02-23 10:21:13 +01:00
parent 6c28120f19
commit 54eb34d6fd
4 changed files with 24 additions and 31 deletions

View File

@ -49,6 +49,8 @@ class Type;
using TypePointer = Type const*; using TypePointer = Type const*;
using namespace util; using namespace util;
struct CallGraph;
struct ASTAnnotation struct ASTAnnotation
{ {
ASTAnnotation() = default; ASTAnnotation() = default;
@ -162,6 +164,10 @@ struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocu
/// Mapping containing the nodes that define the arguments for base constructors. /// Mapping containing the nodes that define the arguments for base constructors.
/// These can either be inheritance specifiers or modifier invocations. /// These can either be inheritance specifiers or modifier invocations.
std::map<FunctionDefinition const*, ASTNode const*> baseConstructorArguments; std::map<FunctionDefinition const*, ASTNode const*> baseConstructorArguments;
/// A graph with edges representing calls between functions that may happen during contract construction.
SetOnce<std::shared_ptr<CallGraph const>> creationCallGraph;
/// A graph with edges representing calls between functions that may happen in a deployed contract.
SetOnce<std::shared_ptr<CallGraph const>> deployedCallGraph;
}; };
struct CallableDeclarationAnnotation: DeclarationAnnotation struct CallableDeclarationAnnotation: DeclarationAnnotation

View File

@ -407,8 +407,18 @@ bool CompilerStack::analyze()
if (auto const* contractDefinition = dynamic_cast<ContractDefinition*>(node.get())) if (auto const* contractDefinition = dynamic_cast<ContractDefinition*>(node.get()))
{ {
Contract& contractState = m_contracts.at(contractDefinition->fullyQualifiedName()); Contract& contractState = m_contracts.at(contractDefinition->fullyQualifiedName());
contractState.creationCallGraph.emplace(FunctionCallGraphBuilder::buildCreationGraph(*contractDefinition));
contractState.deployedCallGraph.emplace(FunctionCallGraphBuilder::buildDeployedGraph(*contractDefinition, *contractState.creationCallGraph)); contractState.contract->annotation().creationCallGraph = make_unique<CallGraph>(
FunctionCallGraphBuilder::buildCreationGraph(
*contractDefinition
)
);
contractState.contract->annotation().deployedCallGraph = make_unique<CallGraph>(
FunctionCallGraphBuilder::buildDeployedGraph(
*contractDefinition,
**contractState.contract->annotation().creationCallGraph
)
);
} }
} }
@ -950,24 +960,6 @@ string const& CompilerStack::metadata(Contract const& _contract) const
return _contract.metadata.init([&]{ return createMetadata(_contract); }); return _contract.metadata.init([&]{ return createMetadata(_contract); });
} }
CallGraph const& CompilerStack::creationCallGraph(string const& _contractName) const
{
if (m_stackState < AnalysisPerformed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(contract(_contractName).creationCallGraph.has_value(), "");
return contract(_contractName).creationCallGraph.value();
}
CallGraph const& CompilerStack::deployedCallGraph(string const& _contractName) const
{
if (m_stackState < AnalysisPerformed)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(contract(_contractName).deployedCallGraph.has_value(), "");
return contract(_contractName).deployedCallGraph.value();
}
Scanner const& CompilerStack::scanner(string const& _sourceName) const Scanner const& CompilerStack::scanner(string const& _sourceName) const
{ {
if (m_stackState < SourcesSet) if (m_stackState < SourcesSet)
@ -1307,7 +1299,10 @@ void CompilerStack::generateIR(ContractDefinition const& _contract)
IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings); IRGenerator generator(m_evmVersion, m_revertStrings, m_optimiserSettings);
tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract, otherYulSources); tie(compiledContract.yulIR, compiledContract.yulIROptimized) = generator.run(_contract, otherYulSources);
generator.verifyCallGraphs(compiledContract.creationCallGraph.value(), compiledContract.deployedCallGraph.value()); generator.verifyCallGraphs(
**compiledContract.contract->annotation().creationCallGraph,
**compiledContract.contract->annotation().deployedCallGraph
);
} }
void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract) void CompilerStack::generateEVMFromIR(ContractDefinition const& _contract)

View File

@ -347,12 +347,6 @@ public:
/// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions /// @returns a JSON representing the estimated gas usage for contract creation, internal and external functions
Json::Value gasEstimates(std::string const& _contractName) const; Json::Value gasEstimates(std::string const& _contractName) const;
/// @returns a graph with edges representing calls between functions that may happen during contract construction.
CallGraph const& creationCallGraph(std::string const& _contractName) const;
/// @returns a graph with edges representing calls between functions that may happen in a deployed contract.
CallGraph const& deployedCallGraph(std::string const& _contractName) const;
/// Changes the format of the metadata appended at the end of the bytecode. /// Changes the format of the metadata appended at the end of the bytecode.
/// This is mostly a workaround to avoid bytecode and gas differences between compiler builds /// This is mostly a workaround to avoid bytecode and gas differences between compiler builds
/// caused by differences in metadata. Should only be used for testing. /// caused by differences in metadata. Should only be used for testing.
@ -394,8 +388,6 @@ private:
util::LazyInit<Json::Value const> runtimeGeneratedSources; util::LazyInit<Json::Value const> runtimeGeneratedSources;
mutable std::optional<std::string const> sourceMapping; mutable std::optional<std::string const> sourceMapping;
mutable std::optional<std::string const> runtimeSourceMapping; mutable std::optional<std::string const> runtimeSourceMapping;
std::optional<CallGraph const> creationCallGraph;
std::optional<CallGraph const> deployedCallGraph;
}; };
/// Loads the missing sources from @a _ast (named @a _path) using the callback /// Loads the missing sources from @a _ast (named @a _path) using the callback

View File

@ -116,8 +116,8 @@ tuple<CallGraphMap, CallGraphMap> collectGraphs(CompilerStack const& _compilerSt
soltestAssert(fullyQualifiedContractName.size() > 0 && fullyQualifiedContractName[0] == ':', ""); soltestAssert(fullyQualifiedContractName.size() > 0 && fullyQualifiedContractName[0] == ':', "");
string contractName = fullyQualifiedContractName.substr(1); string contractName = fullyQualifiedContractName.substr(1);
get<0>(graphs).emplace(contractName, &_compilerStack.creationCallGraph(fullyQualifiedContractName)); get<0>(graphs).emplace(contractName, _compilerStack.contractDefinition(fullyQualifiedContractName).annotation().creationCallGraph->get());
get<1>(graphs).emplace(contractName, &_compilerStack.deployedCallGraph(fullyQualifiedContractName)); get<1>(graphs).emplace(contractName, _compilerStack.contractDefinition(fullyQualifiedContractName).annotation().deployedCallGraph->get());
} }
return graphs; return graphs;