14
15:- module(pdt_call_graph, [ensure_call_graph_generated/0, calls/7, call_type/7, calls_multifile/8, pdt_walk_code/1]). 16
17:- use_module(pdt_prolog_codewalk). 18:- use_module(library(lists)). 19:- use_module(pdt_prolog_library(compatibility), [
20 pdt_source_file/2
21]). 22
23pdt_walk_code(Options) :-
24 ensure_call_graph_generated,
25 pdt_prolog_walk_code(Options).
26
27:- dynamic(first_run/0). 28first_run.
29
30reset :-
31 with_mutex(pdt_call_graph, (
32 ( first_run
33 -> true
34 ; assertz(first_run),
35 retractall(calls_(_, _, _, _, _, _, _, _, _)),
36 retractall(calls_multifile_(_, _, _, _, _, _, _, _))
37 )
38 )).
39
40ensure_call_graph_generated :-
41 with_mutex(pdt_call_graph, (
42 first_run,
43 !,
44 generate_call_graph,
45 retractall(first_run)
46 )),
47 !.
48ensure_call_graph_generated.
51calls(CalleeModule, CalleeName, CalleeArity, CallerModule, CallerName, CallerArity, NumberOfCalls) :-
52 calls_(CalleeModule, CalleeName, CalleeArity, CallerModule, CallerName, CallerArity, NumberOfCalls, _TermPosition, _Info).
53
54call_type(CalleeModule, CalleeName, CalleeArity, CallerModule, CallerName, CallerArity, Info) :-
55 calls_(CalleeModule, CalleeName, CalleeArity, CallerModule, CallerName, CallerArity, _NumberOfCalls, _TermPosition, [Info|_]).
58calls_multifile(CalleeModule, CalleeName, CalleeArity, CallerModule, CallerName, CallerArity, File, NumberOfCalls) :-
59 calls_multifile_(CalleeModule, CalleeName, CalleeArity, CallerModule, CallerName, CallerArity, File, NumberOfCalls).
60
61:- dynamic(calls_/9). 62:- dynamic(calls_multifile_/8). 63
64
65clear([]).
66clear([Module:Name/Arity|Predicates]) :-
67 retractall(calls_(_,_,_,Module,Name,Arity,_, _, _)),
68 retractall(calls_multifile_(_,_,_,Module,Name,Arity,_,_)),
69 clear(Predicates).
70
71:- dynamic(predicates_to_walk/1). 72
73generate_call_graph :-
74 with_mutex(pdt_call_graph, generate_call_graph__).
75
76generate_call_graph__ :-
77 pdt_prolog_walk_code([ trace_reference(_),
78 on_trace(pdt_call_graph:assert_edge),
79 new_meta_specs(pdt_call_graph:generate_call_graph_new_meta_specs),
80 reiterate(false),
81 source(false)
82 ]),
83 ( predicates_to_walk(NewPredicates)
84 -> retractall(predicates_to_walk(_)),
85 clear(NewPredicates),
86 generate_call_graph__(NewPredicates)
87 ; true
88 ).
89
90generate_call_graph(Predicates) :-
91 with_mutex(pdt_call_graph, generate_call_graph__(Predicates)).
92
93generate_call_graph__(Predicates) :-
94 pdt_prolog_walk_code([ trace_reference(_),
95 on_trace(pdt_call_graph:assert_edge),
96 new_meta_specs(pdt_call_graph:generate_call_graph_new_meta_specs),
97 reiterate(false),
98 source(false),
99 predicates(Predicates)
100 ]),
101 ( predicates_to_walk(NewPredicates)
102 -> retractall(predicates_to_walk(_)),
103 clear(NewPredicates),
104 generate_call_graph__(NewPredicates)
105 ; true
106 ).
107
108generate_call_graph_new_meta_specs(MetaSpecs) :-
109 retractall(predicates_to_walk(_)),
110 findall(Module:Name/Arity, (
111 member(MetaSpec, MetaSpecs),
112 pi_of_head(MetaSpec, M, N, A),
113 calls_(M, N, A, Module, Name, Arity, _, _, _)
114 ), Predicates),
115 ( Predicates \== []
116 -> sort(Predicates, PredicatesUnique),
117 assertz(predicates_to_walk(PredicatesUnique))
118 ; true
119 ).
120
121assert_edge(M1:Callee, M2:Caller, clause(Ref), Info) :-
122 assert_edge(M1:Callee, M2:Caller, clause_term_position(Ref, undefined), Info).
123
124assert_edge(M1:Callee, M2:Caller, clause_term_position(Ref, TermPosition), Info) :-
125 functor(Callee,F1,N1),
126 ( predicate_property(M1:Callee, imported_from(M0))
127 -> M = M0
128 ; M = M1
129 ),
130 functor(Caller,F2,N2),
131 assert_edge_(M,F1,N1, M2,F2,N2,TermPosition,Info),
132 ( predicate_property(M2:Caller, multifile),
133 clause_property(Ref, file(File))
134 -> assert_multifile_edge(M,F1,N1, M2,F2,N2, File)
135 ; true
136 ).
137assert_edge(_, '<initialization>', _, _) :- !.
138
139assert_edge_(M1,F1,N1, M2,F2,N2,TermPos,Info) :-
140 retract( calls_(M1,F1,N1, M2,F2,N2, Counter, TermPosTail, InfoTail) ),
141 !,
142 Cnt_plus_1 is Counter + 1,
143 assertz(calls_(M1,F1,N1, M2,F2,N2, Cnt_plus_1, [TermPos|TermPosTail], [Info|InfoTail])).
144assert_edge_(M1,F1,N1, M2,F2,N2, TermPos, Info) :-
145 assertz(calls_(M1,F1,N1, M2,F2,N2, 1, [TermPos], [Info])).
146
147assert_multifile_edge(M1,F1,N1, M2,F2,N2, File) :-
148 retract( calls_multifile_(M1,F1,N1, M2,F2,N2, File, Counter) ),
149 !,
150 Cnt_plus_1 is Counter + 1,
151 assertz(calls_multifile_(M1,F1,N1, M2,F2,N2, File, Cnt_plus_1)).
152assert_multifile_edge(M1,F1,N1, M2,F2,N2, File) :-
153 assertz(calls_multifile_(M1,F1,N1, M2,F2,N2, File, 1)).
154
155:- multifile(pdt_reload:pdt_reload_listener/1). 156pdt_reload:pdt_reload_listener(_Files) :-
157 ( first_run
158 -> true
159 ; setof(Module:Name/Arity, Head^File^FileModule^(
160 ( pdt_reload:reloaded_file(File),
161 ( pdt_source_file(Module:Head, File)
162 ; module_property(FileModule, file(File)),
163 predicate_property(FileModule:Head, imported_from(Module)),
164 predicate_property(Module:Head, transparent),
165 \+ predicate_property(Module:Head, meta_predicate(_))
166 ),
167 functor(Head, Name, Arity)
168 ; retract(predicate_to_clear(Module, Name, Arity))
169 )
170 ), Predicates),
171 !,
172 clear(Predicates),
173 generate_call_graph(Predicates)
174 ).
175
176:- multifile(user:message_hook/3). 177:- dynamic(user:message_hook/3). 178user:message_hook(load_file(start(_, file(_, File))),_,_) :-
179 \+ first_run,
180 ( pdt_source_file(Module:Head, File)
181 ; module_property(FileModule, file(File)),
182 predicate_property(FileModule:Head, imported_from(Module)),
183 predicate_property(Module:Head, transparent),
184 \+ predicate_property(Module:Head, meta_predicate(_))
185 ),
186 functor(Head, Name, Arity),
187 \+ predicate_to_clear(Module, Name, Arity),
188 assertz(predicate_to_clear(Module, Name, Arity)),
189 fail.
190
191pi_of_head(Module:Head, Module, Name, Arity) :-
192 functor(Head, Name, Arity).
193
194:- dynamic(predicate_to_clear/3).