1 |
|
|
/* $OpenBSD: dfn.c,v 1.8 2014/03/16 18:38:30 guenther Exp $ */ |
2 |
|
|
/* $NetBSD: dfn.c,v 1.5 1995/04/19 07:15:56 cgd Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1983, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <stdio.h> |
34 |
|
|
#include "gprof.h" |
35 |
|
|
|
36 |
|
|
#define DFN_DEPTH 100 |
37 |
|
|
struct dfnstruct { |
38 |
|
|
nltype *nlentryp; |
39 |
|
|
int cycletop; |
40 |
|
|
}; |
41 |
|
|
typedef struct dfnstruct dfntype; |
42 |
|
|
|
43 |
|
|
dfntype dfn_stack[ DFN_DEPTH ]; |
44 |
|
|
int dfn_depth; |
45 |
|
|
|
46 |
|
|
int dfn_counter; |
47 |
|
|
|
48 |
|
|
void |
49 |
|
|
dfn_init() |
50 |
|
|
{ |
51 |
|
|
|
52 |
|
|
dfn_depth = 0; |
53 |
|
|
dfn_counter = DFN_NAN; |
54 |
|
|
} |
55 |
|
|
|
56 |
|
|
/* |
57 |
|
|
* given this parent, depth first number its children. |
58 |
|
|
*/ |
59 |
|
|
void |
60 |
|
|
dfn(nltype *parentp) |
61 |
|
|
{ |
62 |
|
|
arctype *arcp; |
63 |
|
|
|
64 |
|
|
# ifdef DEBUG |
65 |
|
|
if ( debug & DFNDEBUG ) { |
66 |
|
|
printf( "[dfn] dfn(" ); |
67 |
|
|
printname( parentp ); |
68 |
|
|
printf( ")\n" ); |
69 |
|
|
} |
70 |
|
|
# endif /* DEBUG */ |
71 |
|
|
/* |
72 |
|
|
* if we're already numbered, no need to look any furthur. |
73 |
|
|
*/ |
74 |
|
|
if ( dfn_numbered( parentp ) ) { |
75 |
|
|
return; |
76 |
|
|
} |
77 |
|
|
/* |
78 |
|
|
* if we're already busy, must be a cycle |
79 |
|
|
*/ |
80 |
|
|
if ( dfn_busy( parentp ) ) { |
81 |
|
|
dfn_findcycle( parentp ); |
82 |
|
|
return; |
83 |
|
|
} |
84 |
|
|
/* |
85 |
|
|
* visit yourself before your children |
86 |
|
|
*/ |
87 |
|
|
dfn_pre_visit( parentp ); |
88 |
|
|
/* |
89 |
|
|
* visit children |
90 |
|
|
*/ |
91 |
|
|
for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) { |
92 |
|
|
if ( arcp -> arc_flags & DEADARC ) |
93 |
|
|
continue; |
94 |
|
|
dfn( arcp -> arc_childp ); |
95 |
|
|
} |
96 |
|
|
/* |
97 |
|
|
* visit yourself after your children |
98 |
|
|
*/ |
99 |
|
|
dfn_post_visit( parentp ); |
100 |
|
|
} |
101 |
|
|
|
102 |
|
|
/* |
103 |
|
|
* push a parent onto the stack and mark it busy |
104 |
|
|
*/ |
105 |
|
|
void |
106 |
|
|
dfn_pre_visit(nltype *parentp) |
107 |
|
|
{ |
108 |
|
|
|
109 |
|
|
dfn_depth += 1; |
110 |
|
|
if ( dfn_depth >= DFN_DEPTH ) |
111 |
|
|
errx(1, "[dfn] out of my depth (dfn_stack overflow)" ); |
112 |
|
|
dfn_stack[ dfn_depth ].nlentryp = parentp; |
113 |
|
|
dfn_stack[ dfn_depth ].cycletop = dfn_depth; |
114 |
|
|
parentp -> toporder = DFN_BUSY; |
115 |
|
|
# ifdef DEBUG |
116 |
|
|
if ( debug & DFNDEBUG ) { |
117 |
|
|
printf( "[dfn_pre_visit]\t\t%d:" , dfn_depth ); |
118 |
|
|
printname( parentp ); |
119 |
|
|
printf( "\n" ); |
120 |
|
|
} |
121 |
|
|
# endif /* DEBUG */ |
122 |
|
|
} |
123 |
|
|
|
124 |
|
|
/* |
125 |
|
|
* are we already numbered? |
126 |
|
|
*/ |
127 |
|
|
bool |
128 |
|
|
dfn_numbered(nltype *childp) |
129 |
|
|
{ |
130 |
|
|
|
131 |
|
|
return ( childp -> toporder != DFN_NAN && childp -> toporder != DFN_BUSY ); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
/* |
135 |
|
|
* are we already busy? |
136 |
|
|
*/ |
137 |
|
|
bool |
138 |
|
|
dfn_busy(nltype *childp) |
139 |
|
|
{ |
140 |
|
|
|
141 |
|
|
if ( childp -> toporder == DFN_NAN ) { |
142 |
|
|
return FALSE; |
143 |
|
|
} |
144 |
|
|
return TRUE; |
145 |
|
|
} |
146 |
|
|
|
147 |
|
|
/* |
148 |
|
|
* MISSING: an explanation |
149 |
|
|
*/ |
150 |
|
|
void |
151 |
|
|
dfn_findcycle(nltype *childp) |
152 |
|
|
{ |
153 |
|
|
int cycletop; |
154 |
|
|
nltype *cycleheadp; |
155 |
|
|
nltype *tailp; |
156 |
|
|
int index; |
157 |
|
|
|
158 |
|
|
for ( cycletop = dfn_depth ; cycletop > 0 ; cycletop -= 1 ) { |
159 |
|
|
cycleheadp = dfn_stack[ cycletop ].nlentryp; |
160 |
|
|
if ( childp == cycleheadp ) { |
161 |
|
|
break; |
162 |
|
|
} |
163 |
|
|
if ( childp -> cyclehead != childp && |
164 |
|
|
childp -> cyclehead == cycleheadp ) { |
165 |
|
|
break; |
166 |
|
|
} |
167 |
|
|
} |
168 |
|
|
if ( cycletop <= 0 ) |
169 |
|
|
errx( 1, "[dfn_findcycle] couldn't find head of cycle"); |
170 |
|
|
# ifdef DEBUG |
171 |
|
|
if ( debug & DFNDEBUG ) { |
172 |
|
|
printf( "[dfn_findcycle] dfn_depth %d cycletop %d " , |
173 |
|
|
dfn_depth , cycletop ); |
174 |
|
|
printname( cycleheadp ); |
175 |
|
|
printf( "\n" ); |
176 |
|
|
} |
177 |
|
|
# endif /* DEBUG */ |
178 |
|
|
if ( cycletop == dfn_depth ) { |
179 |
|
|
/* |
180 |
|
|
* this is previous function, e.g. this calls itself |
181 |
|
|
* sort of boring |
182 |
|
|
*/ |
183 |
|
|
dfn_self_cycle( childp ); |
184 |
|
|
} else { |
185 |
|
|
/* |
186 |
|
|
* glom intervening functions that aren't already |
187 |
|
|
* glommed into this cycle. |
188 |
|
|
* things have been glommed when their cyclehead field |
189 |
|
|
* points to the head of the cycle they are glommed into. |
190 |
|
|
*/ |
191 |
|
|
for ( tailp = cycleheadp ; tailp -> cnext ; tailp = tailp -> cnext ) { |
192 |
|
|
/* void: chase down to tail of things already glommed */ |
193 |
|
|
# ifdef DEBUG |
194 |
|
|
if ( debug & DFNDEBUG ) { |
195 |
|
|
printf( "[dfn_findcycle] tail " ); |
196 |
|
|
printname( tailp ); |
197 |
|
|
printf( "\n" ); |
198 |
|
|
} |
199 |
|
|
# endif /* DEBUG */ |
200 |
|
|
} |
201 |
|
|
/* |
202 |
|
|
* if what we think is the top of the cycle |
203 |
|
|
* has a cyclehead field, then it's not really the |
204 |
|
|
* head of the cycle, which is really what we want |
205 |
|
|
*/ |
206 |
|
|
if ( cycleheadp -> cyclehead != cycleheadp ) { |
207 |
|
|
cycleheadp = cycleheadp -> cyclehead; |
208 |
|
|
# ifdef DEBUG |
209 |
|
|
if ( debug & DFNDEBUG ) { |
210 |
|
|
printf( "[dfn_findcycle] new cyclehead " ); |
211 |
|
|
printname( cycleheadp ); |
212 |
|
|
printf( "\n" ); |
213 |
|
|
} |
214 |
|
|
# endif /* DEBUG */ |
215 |
|
|
} |
216 |
|
|
for ( index = cycletop + 1 ; index <= dfn_depth ; index += 1 ) { |
217 |
|
|
childp = dfn_stack[ index ].nlentryp; |
218 |
|
|
if ( childp -> cyclehead == childp ) { |
219 |
|
|
/* |
220 |
|
|
* not yet glommed anywhere, glom it |
221 |
|
|
* and fix any children it has glommed |
222 |
|
|
*/ |
223 |
|
|
tailp -> cnext = childp; |
224 |
|
|
childp -> cyclehead = cycleheadp; |
225 |
|
|
# ifdef DEBUG |
226 |
|
|
if ( debug & DFNDEBUG ) { |
227 |
|
|
printf( "[dfn_findcycle] glomming " ); |
228 |
|
|
printname( childp ); |
229 |
|
|
printf( " onto " ); |
230 |
|
|
printname( cycleheadp ); |
231 |
|
|
printf( "\n" ); |
232 |
|
|
} |
233 |
|
|
# endif /* DEBUG */ |
234 |
|
|
for ( tailp = childp ; tailp->cnext ; tailp = tailp->cnext ) { |
235 |
|
|
tailp -> cnext -> cyclehead = cycleheadp; |
236 |
|
|
# ifdef DEBUG |
237 |
|
|
if ( debug & DFNDEBUG ) { |
238 |
|
|
printf( "[dfn_findcycle] and its tail " ); |
239 |
|
|
printname( tailp -> cnext ); |
240 |
|
|
printf( " onto " ); |
241 |
|
|
printname( cycleheadp ); |
242 |
|
|
printf( "\n" ); |
243 |
|
|
} |
244 |
|
|
# endif /* DEBUG */ |
245 |
|
|
} |
246 |
|
|
} else if ( childp -> cyclehead != cycleheadp /* firewall */ ) |
247 |
|
|
warnx("[dfn_busy] glommed, but not to cyclehead"); |
248 |
|
|
} |
249 |
|
|
} |
250 |
|
|
} |
251 |
|
|
|
252 |
|
|
/* |
253 |
|
|
* deal with self-cycles |
254 |
|
|
*/ |
255 |
|
|
void |
256 |
|
|
dfn_self_cycle(nltype *parentp __unused) |
257 |
|
|
{ |
258 |
|
|
/* |
259 |
|
|
* since we are taking out self-cycles elsewhere |
260 |
|
|
* no need for the special case, here. |
261 |
|
|
*/ |
262 |
|
|
# ifdef DEBUG |
263 |
|
|
if ( debug & DFNDEBUG ) { |
264 |
|
|
printf( "[dfn_self_cycle] " ); |
265 |
|
|
printname( parentp ); |
266 |
|
|
printf( "\n" ); |
267 |
|
|
} |
268 |
|
|
# endif /* DEBUG */ |
269 |
|
|
} |
270 |
|
|
|
271 |
|
|
/* |
272 |
|
|
* visit a node after all its children |
273 |
|
|
* [MISSING: an explanation] |
274 |
|
|
* and pop it off the stack |
275 |
|
|
*/ |
276 |
|
|
void |
277 |
|
|
dfn_post_visit(nltype *parentp) |
278 |
|
|
{ |
279 |
|
|
nltype *memberp; |
280 |
|
|
|
281 |
|
|
# ifdef DEBUG |
282 |
|
|
if ( debug & DFNDEBUG ) { |
283 |
|
|
printf( "[dfn_post_visit]\t%d: " , dfn_depth ); |
284 |
|
|
printname( parentp ); |
285 |
|
|
printf( "\n" ); |
286 |
|
|
} |
287 |
|
|
# endif /* DEBUG */ |
288 |
|
|
/* |
289 |
|
|
* number functions and things in their cycles |
290 |
|
|
* unless the function is itself part of a cycle |
291 |
|
|
*/ |
292 |
|
|
if ( parentp -> cyclehead == parentp ) { |
293 |
|
|
dfn_counter += 1; |
294 |
|
|
for ( memberp = parentp ; memberp ; memberp = memberp -> cnext ) { |
295 |
|
|
memberp -> toporder = dfn_counter; |
296 |
|
|
# ifdef DEBUG |
297 |
|
|
if ( debug & DFNDEBUG ) { |
298 |
|
|
printf( "[dfn_post_visit]\t\tmember " ); |
299 |
|
|
printname( memberp ); |
300 |
|
|
printf( " -> toporder = %d\n" , dfn_counter ); |
301 |
|
|
} |
302 |
|
|
# endif /* DEBUG */ |
303 |
|
|
} |
304 |
|
|
} else { |
305 |
|
|
# ifdef DEBUG |
306 |
|
|
if ( debug & DFNDEBUG ) { |
307 |
|
|
printf( "[dfn_post_visit]\t\tis part of a cycle\n" ); |
308 |
|
|
} |
309 |
|
|
# endif /* DEBUG */ |
310 |
|
|
} |
311 |
|
|
dfn_depth -= 1; |
312 |
|
|
} |