12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)(* ************************************************************************** *)(* Topological iterators *)(* ************************************************************************** *)moduleMake(G:Graph.Sig.GwithtypeV.t=Kernel_function.t)(N:sigvalname:stringend)=struct(* Topological iterations are memoized in order to improve efficiency when
calling them several times. This has been proved to have a significant
impact in practice. *)moduleS=State_builder.Queue(Kernel_function)(structletname="Callgraph.Uses"^N.nameletdependencies=[Cg.self]end)moduleT=Graph.Topological.Make_stable(G)letitergf=(* Warns if [-cg-no-function-pointers] is in effect, which may lead
to unsound analyses for the users of the callgraph. *)ifnot(Options.Function_pointers.get())thenOptions.warning~once:true"using callgraph while option %s is unset, \
result may be unsound"Options.Function_pointers.name;ifS.is_empty()thenT.iterS.addg;S.iterfendletiter_in_order=letmoduleI=Make(Cg.G)(structletname="iter_in_order"end)infunf->I.iter(Cg.get())fletiter_in_rev_order=letmoduleI=Make(structincludeCg.G(* inverse operations over successors required by
[Graph.Topological.G] *)letiter_succ=iter_predletin_degree=out_degreeend)(structletname="iter_in_rev_order"end)infunf->I.iter(Cg.get())flet_iter_in_rev_order=Dynamic.register~comment:"Iterate over all the functions in the callgraph in reverse order"~plugin:Options.name"iter_in_rev_order"Datatype.(func(funcKernel_function.tyunit)unit)iter_in_rev_orderletiter_on_auxiter_dirfkf=letcg=Cg.get()inifCg.G.mem_vertexcgkfthenletvisited=Kernel_function.Hashtbl.create17inletrecauxkf=iter_dir(funkf'->ifnot(Kernel_function.Hashtbl.memvisitedkf')thenbeginfkf';Kernel_function.Hashtbl.addvisitedkf'();auxkf'end)cgkfinauxkfletiter_on_callers=iter_on_auxCg.G.iter_predletiter_on_callees=iter_on_auxCg.G.iter_succletnb_calls()=letg=Cg.get()in(* [g] contains bidirectional edges (from caller to callee and
conversely). Conseqently each function call is counted twice. *)Cg.G.nb_edgesg/2