diff options
Diffstat (limited to 'src/symbol.c')
-rw-r--r-- | src/symbol.c | 187 |
1 files changed, 64 insertions, 123 deletions
diff --git a/src/symbol.c b/src/symbol.c index 4fe5f85..e3ccd7c 100644 --- a/src/symbol.c +++ b/src/symbol.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* This file is part of GNU cflow | 1 | /* This file is part of GNU cflow |
2 | Copyright (C) 1997, 2005, 2006, 2007 Sergey Poznyakoff | 2 | Copyright (C) 1997, 2005, 2006, 2007, 2009 Sergey Poznyakoff |
3 | 3 | ||
4 | GNU cflow is free software; you can redistribute it and/or modify | 4 | GNU cflow is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by | 5 | it under the terms of the GNU General Public License as published by |
@@ -110,18 +110,19 @@ delete_symbol(struct table_entry *tp) | |||
110 | Symbol *s = unlink_symbol(tp); | 110 | Symbol *s = unlink_symbol(tp); |
111 | /* The symbol could have been referenced even if it is static | 111 | /* The symbol could have been referenced even if it is static |
112 | in -i^s mode. See tests/static.at for details. */ | 112 | in -i^s mode. See tests/static.at for details. */ |
113 | if (s->ref_line == NULL) | 113 | if (s->ref_line == NULL) { |
114 | linked_list_destroy(&s->ref_line); | ||
115 | linked_list_destroy(&s->caller); | ||
116 | linked_list_destroy(&s->callee); | ||
114 | free(s); | 117 | free(s); |
118 | } | ||
115 | } | 119 | } |
116 | 120 | ||
117 | static void cleanup_symbol_refs(Symbol *sym); | ||
118 | |||
119 | /* Delete from the symbol table all static symbols defined in the current | 121 | /* Delete from the symbol table all static symbols defined in the current |
120 | source. | 122 | source. |
121 | If the user requested static symbols in the listing, the symbol is | 123 | If the user requested static symbols in the listing, the symbol is |
122 | not deleted, as it may have been referenced by other symbols. Instead, | 124 | not deleted, as it may have been referenced by other symbols. Instead, |
123 | it is unlinked from its table entry and cleanup_symbol_refs() is | 125 | it is unlinked from its table entry. |
124 | called, so that its reference tables become usable. | ||
125 | NOTE: This takes advantage of the fact that install() uses LIFO strategy, | 126 | NOTE: This takes advantage of the fact that install() uses LIFO strategy, |
126 | so we don't have to check the name of the source where the symbol was | 127 | so we don't have to check the name of the source where the symbol was |
127 | defined. */ | 128 | defined. */ |
@@ -137,7 +138,7 @@ static_processor(void *data, void *proc_data) | |||
137 | if (globals_only()) | 138 | if (globals_only()) |
138 | delete_symbol(t); | 139 | delete_symbol(t); |
139 | else | 140 | else |
140 | cleanup_symbol_refs(unlink_symbol(t)); | 141 | unlink_symbol(t); |
141 | } | 142 | } |
142 | return true; | 143 | return true; |
143 | } | 144 | } |
@@ -174,7 +175,7 @@ auto_processor(void *data, void *proc_data) | |||
174 | break; | 175 | break; |
175 | 176 | ||
176 | case StaticStorage: | 177 | case StaticStorage: |
177 | cleanup_symbol_refs(unlink_symbol(t)); | 178 | unlink_symbol(t); |
178 | break; | 179 | break; |
179 | 180 | ||
180 | default: | 181 | default: |
@@ -193,48 +194,6 @@ delete_autos(int level) | |||
193 | hash_do_for_each (symbol_table, auto_processor, &level); | 194 | hash_do_for_each (symbol_table, auto_processor, &level); |
194 | } | 195 | } |
195 | 196 | ||
196 | |||
197 | /* Make all list pointers of the SYM ready for final processing. | ||
198 | * This means for each list replace its entry point with its CAR | ||
199 | * and throw away the first cons. The first cons holds pointers | ||
200 | * to the head and tail of the list and is used to speed up appends. | ||
201 | * | ||
202 | * TODO: The memory is not reclaimed | ||
203 | */ | ||
204 | static void | ||
205 | cleanup_symbol_refs(Symbol *sym) | ||
206 | { | ||
207 | if (sym && sym->type == SymIdentifier) { | ||
208 | if (sym->ref_line) | ||
209 | sym->ref_line = CAR(sym->ref_line); | ||
210 | if (sym->caller) | ||
211 | sym->caller = CAR(sym->caller); | ||
212 | if (sym->callee) | ||
213 | sym->callee = CAR(sym->callee); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | static bool | ||
218 | cleanup_processor(void *data, void *proc_data) | ||
219 | { | ||
220 | struct table_entry *t = data; | ||
221 | Symbol *sym; | ||
222 | for (sym = t->sym; sym; sym = sym->next) { | ||
223 | cleanup_symbol_refs(sym); | ||
224 | } | ||
225 | return true; | ||
226 | } | ||
227 | |||
228 | |||
229 | /* Clean up all symbols from the auxiliary information. | ||
230 | * See the comment for cleanup_symbol() above | ||
231 | */ | ||
232 | void | ||
233 | cleanup() | ||
234 | { | ||
235 | hash_do_for_each (symbol_table, cleanup_processor, NULL); | ||
236 | } | ||
237 | |||
238 | struct collect_data { | 197 | struct collect_data { |
239 | Symbol **sym; | 198 | Symbol **sym; |
240 | int (*sel)(Symbol *p); | 199 | int (*sel)(Symbol *p); |
@@ -324,97 +283,79 @@ move_parms(int level) | |||
324 | } | 283 | } |
325 | 284 | ||
326 | 285 | ||
327 | typedef struct bucket Bucket; | ||
328 | struct bucket { | ||
329 | Bucket *next; /* Next bucket */ | ||
330 | int free; | ||
331 | Cons cons[1]; | ||
332 | }; | ||
333 | |||
334 | static int bucket_nodes = 512; | ||
335 | static Bucket *root_bucket, *last_bucket; | ||
336 | 286 | ||
337 | void | 287 | static struct linked_list * |
338 | alloc_new_bucket() | 288 | deref_linked_list (struct linked_list **plist) |
339 | { | 289 | { |
340 | Bucket *bp; | 290 | if (!*plist) { |
341 | 291 | struct linked_list *list = xmalloc(sizeof(*list)); | |
342 | bp = malloc(sizeof(*bp) + sizeof(Cons)*(bucket_nodes-1)); | 292 | list->free_data = NULL; |
343 | if (!bp) | 293 | list->head = list->tail = NULL; |
344 | return; | 294 | *plist = list; |
345 | bp->next = NULL; | ||
346 | bp->free = 0; | ||
347 | if (!root_bucket) | ||
348 | root_bucket = last_bucket = bp; | ||
349 | else { | ||
350 | last_bucket->next = bp; | ||
351 | last_bucket = bp; | ||
352 | } | 295 | } |
296 | return *plist; | ||
353 | } | 297 | } |
354 | 298 | ||
355 | Consptr | 299 | |
356 | alloc_cons_from_bucket() | 300 | struct linked_list * |
301 | linked_list_create(linked_list_free_data_fp fun) | ||
357 | { | 302 | { |
358 | if (!last_bucket || last_bucket->free == bucket_nodes) | 303 | struct linked_list *list = xmalloc(sizeof(*list)); |
359 | return NULL; | 304 | list->free_data = fun; |
360 | return &last_bucket->cons[last_bucket->free++]; | 305 | list->head = list->tail = NULL; |
306 | return list; | ||
361 | } | 307 | } |
362 | 308 | ||
363 | Consptr | 309 | void |
364 | alloc_cons() | 310 | linked_list_append(struct linked_list **plist, void *data) |
365 | { | 311 | { |
366 | Consptr cp; | 312 | struct linked_list *list = deref_linked_list (plist); |
367 | 313 | struct linked_list_entry *entry = xmalloc(sizeof(*entry)); | |
368 | cp = alloc_cons_from_bucket(); | 314 | entry->next = NULL; |
369 | if (!cp) { | 315 | entry->data = data; |
370 | alloc_new_bucket(); | 316 | if (list->tail) |
371 | if ((cp = alloc_cons_from_bucket()) == NULL) { | 317 | list->tail->next = entry; |
372 | error(2, 0, _("not enough core")); | 318 | else |
373 | } | 319 | list->head = entry; |
374 | } | 320 | list->tail = entry; |
375 | CAR(cp) = CDR(cp) = NULL; | ||
376 | return cp; | ||
377 | } | 321 | } |
378 | 322 | ||
379 | /* Append a new cons to the tail of the list | 323 | void |
380 | * ROOT_PTR points to a `root cons'. | 324 | linked_list_prepend(struct linked_list **plist, void *data) |
381 | * CAR is the car value of the cons to be created. | ||
382 | * | ||
383 | * Note: Car of the root cons points to the head of the list, | ||
384 | * cdr of root cons points to the tail of the list. | ||
385 | */ | ||
386 | Consptr | ||
387 | append_to_list(Consptr *root_ptr, void *car) | ||
388 | { | 325 | { |
389 | Consptr root, cons; | 326 | struct linked_list *list = deref_linked_list (plist); |
390 | 327 | struct linked_list_entry *entry = xmalloc(sizeof(*entry)); | |
391 | if (!*root_ptr) { | 328 | entry->next = list->head; |
392 | *root_ptr = alloc_cons(); | 329 | entry->data = data; |
393 | /* both car and cdr are guaranteed to be NULL */ | 330 | list->head = entry; |
331 | if (!list->tail) | ||
332 | list->tail = entry; | ||
333 | } | ||
334 | |||
335 | void | ||
336 | linked_list_destroy(struct linked_list **plist) | ||
337 | { | ||
338 | if (plist && *plist) { | ||
339 | struct linked_list *list = *plist; | ||
340 | struct linked_list_entry *p; | ||
341 | |||
342 | for (p = list->head; p; p = p->next) { | ||
343 | if (list->free_data) | ||
344 | list->free_data(p->data); | ||
345 | free(p); | ||
346 | } | ||
347 | free(list); | ||
348 | *plist = NULL; | ||
394 | } | 349 | } |
395 | root = *root_ptr; | ||
396 | |||
397 | cons = alloc_cons(); | ||
398 | if (!CAR(root)) | ||
399 | CAR(root) = cons; | ||
400 | |||
401 | /* Maintain linked list */ | ||
402 | if (CDR(root)) | ||
403 | CDR(CDR(root)) = cons; | ||
404 | CDR(root) = cons; | ||
405 | CAR(cons) = car; | ||
406 | return cons; | ||
407 | } | 350 | } |
408 | 351 | ||
409 | int | 352 | int |
410 | symbol_in_list(Symbol *sym, Consptr list) | 353 | symbol_in_list(Symbol *sym, struct linked_list *list) |