OSDN Git Service

2007-01-15 Andreas Tobler <a.tobler@schweiz.org>
[pf3gnuchains/gcc-fork.git] / boehm-gc / finalize.c
1 /*
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
4  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
5
6  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
8  *
9  * Permission is hereby granted to use or copy this program
10  * for any purpose,  provided the above notices are retained on all copies.
11  * Permission to modify the code and to distribute modified code is granted,
12  * provided the above notices are retained, and a notice that the code was
13  * modified is included with the above copyright notice.
14  */
15 /* Boehm, February 1, 1996 1:19 pm PST */
16 # define I_HIDE_POINTERS
17 # include "private/gc_pmark.h"
18
19 # ifdef FINALIZE_ON_DEMAND
20     int GC_finalize_on_demand = 1;
21 # else
22     int GC_finalize_on_demand = 0;
23 # endif
24
25 # ifdef JAVA_FINALIZATION
26     int GC_java_finalization = 1;
27 # else
28     int GC_java_finalization = 0;
29 # endif
30
31 /* Type of mark procedure used for marking from finalizable object.     */
32 /* This procedure normally does not mark the object, only its           */
33 /* descendents.                                                         */
34 typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */); 
35
36 # define HASH3(addr,size,log_size) \
37     ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
38     & ((size) - 1))
39 #define HASH2(addr,log_size) HASH3(addr, 1 << log_size, log_size)
40
41 struct hash_chain_entry {
42     word hidden_key;
43     struct hash_chain_entry * next;
44 };
45
46 unsigned GC_finalization_failures = 0;
47         /* Number of finalization requests that failed for lack of memory. */
48
49 static struct disappearing_link {
50     struct hash_chain_entry prolog;
51 #   define dl_hidden_link prolog.hidden_key
52                                 /* Field to be cleared.         */
53 #   define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
54 #   define dl_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
55
56     word dl_hidden_obj;         /* Pointer to object base       */
57 } **dl_head = 0;
58
59 static signed_word log_dl_table_size = -1;
60                         /* Binary log of                                */
61                         /* current size of array pointed to by dl_head. */
62                         /* -1 ==> size is 0.                            */
63
64 word GC_dl_entries = 0; /* Number of entries currently in disappearing  */
65                         /* link table.                                  */
66
67 static struct finalizable_object {
68     struct hash_chain_entry prolog;
69 #   define fo_hidden_base prolog.hidden_key
70                                 /* Pointer to object base.      */
71                                 /* No longer hidden once object */
72                                 /* is on finalize_now queue.    */
73 #   define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
74 #   define fo_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
75     GC_finalization_proc fo_fn; /* Finalizer.                   */
76     ptr_t fo_client_data;
77     word fo_object_size;        /* In bytes.                    */
78     finalization_mark_proc * fo_mark_proc;      /* Mark-through procedure */
79 } **fo_head = 0;
80
81 struct finalizable_object * GC_finalize_now = 0;
82         /* LIst of objects that should be finalized now.        */
83
84 static signed_word log_fo_table_size = -1;
85
86 word GC_fo_entries = 0;
87
88 void GC_push_finalizer_structures GC_PROTO((void))
89 {
90     GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
91     GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
92     GC_push_all((ptr_t)(&GC_finalize_now),
93                 (ptr_t)(&GC_finalize_now) + sizeof(word));
94 }
95
96 /* Double the size of a hash table. *size_ptr is the log of its current */
97 /* size.  May be a noop.                                                */
98 /* *table is a pointer to an array of hash headers.  If we succeed, we  */
99 /* update both *table and *log_size_ptr.                                */
100 /* Lock is held.  Signals are disabled.                                 */
101 void GC_grow_table(table, log_size_ptr)
102 struct hash_chain_entry ***table;
103 signed_word * log_size_ptr;
104 {
105     register word i;
106     register struct hash_chain_entry *p;
107     int log_old_size = *log_size_ptr;
108     register int log_new_size = log_old_size + 1;
109     word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
110     register word new_size = 1 << log_new_size;
111     struct hash_chain_entry **new_table = (struct hash_chain_entry **)
112         GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
113                 (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
114     
115     if (new_table == 0) {
116         if (table == 0) {
117             ABORT("Insufficient space for initial table allocation");
118         } else {
119             return;
120         }
121     }
122     for (i = 0; i < old_size; i++) {
123       p = (*table)[i];
124       while (p != 0) {
125         register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
126         register struct hash_chain_entry *next = p -> next;
127         register int new_hash = HASH3(real_key, new_size, log_new_size);
128         
129         p -> next = new_table[new_hash];
130         new_table[new_hash] = p;
131         p = next;
132       }
133     }
134     *log_size_ptr = log_new_size;
135     *table = new_table;
136 }
137
138 # if defined(__STDC__) || defined(__cplusplus)
139     int GC_register_disappearing_link(GC_PTR * link)
140 # else
141     int GC_register_disappearing_link(link)
142     GC_PTR * link;
143 # endif
144 {
145     ptr_t base;
146     
147     base = (ptr_t)GC_base((GC_PTR)link);
148     if (base == 0)
149         ABORT("Bad arg to GC_register_disappearing_link");
150     return(GC_general_register_disappearing_link(link, base));
151 }
152
153 # if defined(__STDC__) || defined(__cplusplus)
154     int GC_general_register_disappearing_link(GC_PTR * link,
155                                               GC_PTR obj)
156 # else
157     int GC_general_register_disappearing_link(link, obj)
158     GC_PTR * link;
159     GC_PTR obj;
160 # endif
161
162 {
163     struct disappearing_link *curr_dl;
164     int index;
165     struct disappearing_link * new_dl;
166     DCL_LOCK_STATE;
167     
168     if ((word)link & (ALIGNMENT-1))
169         ABORT("Bad arg to GC_general_register_disappearing_link");
170 #   ifdef THREADS
171         DISABLE_SIGNALS();
172         LOCK();
173 #   endif
174     if (log_dl_table_size == -1
175         || GC_dl_entries > ((word)1 << log_dl_table_size)) {
176 #       ifndef THREADS
177             DISABLE_SIGNALS();
178 #       endif
179         GC_grow_table((struct hash_chain_entry ***)(&dl_head),
180                       &log_dl_table_size);
181 #       ifdef CONDPRINT
182           if (GC_print_stats) {
183             GC_printf1("Grew dl table to %lu entries\n",
184                         (unsigned long)(1 << log_dl_table_size));
185           }
186 #       endif
187 #       ifndef THREADS
188             ENABLE_SIGNALS();
189 #       endif
190     }
191     index = HASH2(link, log_dl_table_size);
192     curr_dl = dl_head[index];
193     for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
194         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
195             curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
196 #           ifdef THREADS
197                 UNLOCK();
198                 ENABLE_SIGNALS();
199 #           endif
200             return(1);
201         }
202     }
203     new_dl = (struct disappearing_link *)
204         GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
205     if (0 == new_dl) {
206 #     ifdef THREADS
207         UNLOCK();
208         ENABLE_SIGNALS();
209 #     endif
210       new_dl = (struct disappearing_link *)
211               GC_oom_fn(sizeof(struct disappearing_link));
212       if (0 == new_dl) {
213         GC_finalization_failures++;
214         return(0);
215       }
216       /* It's not likely we'll make it here, but ... */
217 #     ifdef THREADS
218         DISABLE_SIGNALS();
219         LOCK();
220 #     endif
221     }
222     new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
223     new_dl -> dl_hidden_link = HIDE_POINTER(link);
224     dl_set_next(new_dl, dl_head[index]);
225     dl_head[index] = new_dl;
226     GC_dl_entries++;
227 #   ifdef THREADS
228         UNLOCK();
229         ENABLE_SIGNALS();
230 #   endif
231     return(0);
232 }
233
234 # if defined(__STDC__) || defined(__cplusplus)
235     int GC_unregister_disappearing_link(GC_PTR * link)
236 # else
237     int GC_unregister_disappearing_link(link)
238     GC_PTR * link;
239 # endif
240 {
241     struct disappearing_link *curr_dl, *prev_dl;
242     int index;
243     DCL_LOCK_STATE;
244     
245     DISABLE_SIGNALS();
246     LOCK();
247     index = HASH2(link, log_dl_table_size);
248     if (((unsigned long)link & (ALIGNMENT-1))) goto out;
249     prev_dl = 0; curr_dl = dl_head[index];
250     while (curr_dl != 0) {
251         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
252             if (prev_dl == 0) {
253                 dl_head[index] = dl_next(curr_dl);
254             } else {
255                 dl_set_next(prev_dl, dl_next(curr_dl));
256             }
257             GC_dl_entries--;
258             UNLOCK();
259             ENABLE_SIGNALS();
260 #           ifdef DBG_HDRS_ALL
261               dl_set_next(curr_dl, 0);
262 #           else
263               GC_free((GC_PTR)curr_dl);
264 #           endif
265             return(1);
266         }
267         prev_dl = curr_dl;
268         curr_dl = dl_next(curr_dl);
269     }
270 out:
271     UNLOCK();
272     ENABLE_SIGNALS();
273     return(0);
274 }
275
276 /* Possible finalization_marker procedures.  Note that mark stack       */
277 /* overflow is handled by the caller, and is not a disaster.            */
278 GC_API void GC_normal_finalize_mark_proc(p)
279 ptr_t p;
280 {
281     hdr * hhdr = HDR(p);
282     
283     PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
284              &(GC_mark_stack[GC_mark_stack_size]));
285 }
286
287 /* This only pays very partial attention to the mark descriptor.        */
288 /* It does the right thing for normal and atomic objects, and treats    */
289 /* most others as normal.                                               */
290 GC_API void GC_ignore_self_finalize_mark_proc(p)
291 ptr_t p;
292 {
293     hdr * hhdr = HDR(p);
294     word descr = hhdr -> hb_descr;
295     ptr_t q, r;
296     ptr_t scan_limit;
297     ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
298     
299     if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
300        scan_limit = p + descr - sizeof(word);
301     } else {
302        scan_limit = target_limit + 1 - sizeof(word);
303     }
304     for (q = p; q <= scan_limit; q += ALIGNMENT) {
305         r = *(ptr_t *)q;
306         if (r < p || r > target_limit) {
307             GC_PUSH_ONE_HEAP((word)r, q);
308         }
309     }
310 }
311
312 /*ARGSUSED*/
313 GC_API void GC_null_finalize_mark_proc(p)
314 ptr_t p;
315 {
316 }
317
318
319
320 /* Register a finalization function.  See gc.h for details.     */
321 /* in the nonthreads case, we try to avoid disabling signals,   */
322 /* since it can be expensive.  Threads packages typically       */
323 /* make it cheaper.                                             */
324 /* The last parameter is a procedure that determines            */
325 /* marking for finalization ordering.  Any objects marked       */
326 /* by that procedure will be guaranteed to not have been        */
327 /* finalized when this finalizer is invoked.                    */
328 GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
329 GC_PTR obj;
330 GC_finalization_proc fn;
331 GC_PTR cd;
332 GC_finalization_proc * ofn;
333 GC_PTR * ocd;
334 finalization_mark_proc * mp;
335 {
336     ptr_t base;
337     struct finalizable_object * curr_fo, * prev_fo;
338     int index;
339     struct finalizable_object *new_fo;
340     hdr *hhdr;
341     DCL_LOCK_STATE;
342
343 #   ifdef THREADS
344         DISABLE_SIGNALS();
345         LOCK();
346 #   endif
347     if (log_fo_table_size == -1
348         || GC_fo_entries > ((word)1 << log_fo_table_size)) {
349 #       ifndef THREADS
350             DISABLE_SIGNALS();
351 #       endif
352         GC_grow_table((struct hash_chain_entry ***)(&fo_head),
353                       &log_fo_table_size);
354 #       ifdef CONDPRINT
355           if (GC_print_stats) {
356             GC_printf1("Grew fo table to %lu entries\n",
357                         (unsigned long)(1 << log_fo_table_size));
358           }
359 #       endif
360 #       ifndef THREADS
361             ENABLE_SIGNALS();
362 #       endif
363     }
364     /* in the THREADS case signals are disabled and we hold allocation  */
365     /* lock; otherwise neither is true.  Proceed carefully.             */
366     base = (ptr_t)obj;
367     index = HASH2(base, log_fo_table_size);
368     prev_fo = 0; curr_fo = fo_head[index];
369     while (curr_fo != 0) {
370         if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
371             /* Interruption by a signal in the middle of this   */
372             /* should be safe.  The client may see only *ocd    */
373             /* updated, but we'll declare that to be his        */
374             /* problem.                                         */
375             if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
376             if (ofn) *ofn = curr_fo -> fo_fn;
377             /* Delete the structure for base. */
378                 if (prev_fo == 0) {
379                   fo_head[index] = fo_next(curr_fo);
380                 } else {
381                   fo_set_next(prev_fo, fo_next(curr_fo));
382                 }
383             if (fn == 0) {
384                 GC_fo_entries--;
385                   /* May not happen if we get a signal.  But a high     */
386                   /* estimate will only make the table larger than      */
387                   /* necessary.                                         */
388 #               if !defined(THREADS) && !defined(DBG_HDRS_ALL)
389                   GC_free((GC_PTR)curr_fo);
390 #               endif
391             } else {
392                 curr_fo -> fo_fn = fn;
393                 curr_fo -> fo_client_data = (ptr_t)cd;
394                 curr_fo -> fo_mark_proc = mp;
395                 /* Reinsert it.  We deleted it first to maintain        */
396                 /* consistency in the event of a signal.                */
397                 if (prev_fo == 0) {
398                   fo_head[index] = curr_fo;
399                 } else {
400                   fo_set_next(prev_fo, curr_fo);
401                 }
402             }
403 #           ifdef THREADS
404                 UNLOCK();
405                 ENABLE_SIGNALS();
406 #           endif
407             return;
408         }
409         prev_fo = curr_fo;
410         curr_fo = fo_next(curr_fo);
411     }
412     if (ofn) *ofn = 0;
413     if (ocd) *ocd = 0;
414     if (fn == 0) {
415 #       ifdef THREADS
416             UNLOCK();
417             ENABLE_SIGNALS();
418 #       endif
419         return;
420     }
421     GET_HDR(base, hhdr);
422     if (0 == hhdr) {
423       /* We won't collect it, hence finalizer wouldn't be run. */
424 #     ifdef THREADS
425           UNLOCK();
426           ENABLE_SIGNALS();
427 #     endif
428       return;
429     }
430     new_fo = (struct finalizable_object *)
431         GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
432     if (0 == new_fo) {
433 #     ifdef THREADS
434         UNLOCK();
435         ENABLE_SIGNALS();
436 #     endif
437       new_fo = (struct finalizable_object *)
438               GC_oom_fn(sizeof(struct finalizable_object));
439       if (0 == new_fo) {
440         GC_finalization_failures++;
441         return;
442       }
443       /* It's not likely we'll make it here, but ... */
444 #     ifdef THREADS
445         DISABLE_SIGNALS();
446         LOCK();
447 #     endif
448     }
449     new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
450     new_fo -> fo_fn = fn;
451     new_fo -> fo_client_data = (ptr_t)cd;
452     new_fo -> fo_object_size = hhdr -> hb_sz;
453     new_fo -> fo_mark_proc = mp;
454     fo_set_next(new_fo, fo_head[index]);
455     GC_fo_entries++;
456     fo_head[index] = new_fo;
457 #   ifdef THREADS
458         UNLOCK();
459         ENABLE_SIGNALS();
460 #   endif
461 }
462
463 # if defined(__STDC__)
464     void GC_register_finalizer(void * obj,
465                                GC_finalization_proc fn, void * cd,
466                                GC_finalization_proc *ofn, void ** ocd)
467 # else
468     void GC_register_finalizer(obj, fn, cd, ofn, ocd)
469     GC_PTR obj;
470     GC_finalization_proc fn;
471     GC_PTR cd;
472     GC_finalization_proc * ofn;
473     GC_PTR * ocd;
474 # endif
475 {
476     GC_register_finalizer_inner(obj, fn, cd, ofn,
477                                 ocd, GC_normal_finalize_mark_proc);
478 }
479
480 # if defined(__STDC__)
481     void GC_register_finalizer_ignore_self(void * obj,
482                                GC_finalization_proc fn, void * cd,
483                                GC_finalization_proc *ofn, void ** ocd)
484 # else
485     void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
486     GC_PTR obj;
487     GC_finalization_proc fn;
488     GC_PTR cd;
489     GC_finalization_proc * ofn;
490     GC_PTR * ocd;
491 # endif
492 {
493     GC_register_finalizer_inner(obj, fn, cd, ofn,
494                                 ocd, GC_ignore_self_finalize_mark_proc);
495 }
496
497 # if defined(__STDC__)
498     void GC_register_finalizer_no_order(void * obj,
499                                GC_finalization_proc fn, void * cd,
500                                GC_finalization_proc *ofn, void ** ocd)
501 # else
502     void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
503     GC_PTR obj;
504     GC_finalization_proc fn;
505     GC_PTR cd;
506     GC_finalization_proc * ofn;
507     GC_PTR * ocd;
508 # endif
509 {
510     GC_register_finalizer_inner(obj, fn, cd, ofn,
511                                 ocd, GC_null_finalize_mark_proc);
512 }
513
514 #ifndef NO_DEBUGGING
515 void GC_dump_finalization()
516 {
517     struct disappearing_link * curr_dl;
518     struct finalizable_object * curr_fo;
519     ptr_t real_ptr, real_link;
520     int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
521     int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
522     int i;
523
524     GC_printf0("Disappearing links:\n");
525     for (i = 0; i < dl_size; i++) {
526       for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
527         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
528         real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
529         GC_printf2("Object: 0x%lx, Link:0x%lx\n", real_ptr, real_link);
530       }
531     }
532     GC_printf0("Finalizers:\n");
533     for (i = 0; i < fo_size; i++) {
534       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
535         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
536         GC_printf1("Finalizable object: 0x%lx\n", real_ptr);
537       }
538     }
539 }
540 #endif
541
542 /* Called with world stopped.  Cause disappearing links to disappear,   */
543 /* and invoke finalizers.                                               */
544 void GC_finalize()
545 {
546     struct disappearing_link * curr_dl, * prev_dl, * next_dl;
547     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
548     ptr_t real_ptr, real_link;
549     register int i;
550     int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
551     int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
552     
553   /* Make disappearing links disappear */
554     for (i = 0; i < dl_size; i++) {
555       curr_dl = dl_head[i];
556       prev_dl = 0;
557       while (curr_dl != 0) {
558         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
559         real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
560         if (!GC_is_marked(real_ptr)) {
561             *(word *)real_link = 0;
562             next_dl = dl_next(curr_dl);
563             if (prev_dl == 0) {
564                 dl_head[i] = next_dl;
565             } else {
566                 dl_set_next(prev_dl, next_dl);
567             }
568             GC_clear_mark_bit((ptr_t)curr_dl);
569             GC_dl_entries--;
570             curr_dl = next_dl;
571         } else {
572             prev_dl = curr_dl;
573             curr_dl = dl_next(curr_dl);
574         }
575       }
576     }
577   /* Mark all objects reachable via chains of 1 or more pointers        */
578   /* from finalizable objects.                                          */
579     GC_ASSERT(GC_mark_state == MS_NONE);
580     for (i = 0; i < fo_size; i++) {
581       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
582         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
583         if (!GC_is_marked(real_ptr)) {
584             GC_MARKED_FOR_FINALIZATION(real_ptr);
585             GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
586             if (GC_is_marked(real_ptr)) {
587                 WARN("Finalization cycle involving %lx\n", real_ptr);
588             }
589         }
590       }
591     }
592   /* Enqueue for finalization all objects that are still                */
593   /* unreachable.                                                       */
594     GC_words_finalized = 0;
595     for (i = 0; i < fo_size; i++) {
596       curr_fo = fo_head[i];
597       prev_fo = 0;
598       while (curr_fo != 0) {
599         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
600         if (!GC_is_marked(real_ptr)) {
601             if (!GC_java_finalization) {
602               GC_set_mark_bit(real_ptr);
603             }
604             /* Delete from hash table */
605               next_fo = fo_next(curr_fo);
606               if (prev_fo == 0) {
607                 fo_head[i] = next_fo;
608               } else {
609                 fo_set_next(prev_fo, next_fo);
610               }
611               GC_fo_entries--;
612             /* Add to list of objects awaiting finalization.    */
613               fo_set_next(curr_fo, GC_finalize_now);
614               GC_finalize_now = curr_fo;
615               /* unhide object pointer so any future collections will   */
616               /* see it.                                                */
617               curr_fo -> fo_hidden_base = 
618                         (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
619               GC_words_finalized +=
620                         ALIGNED_WORDS(curr_fo -> fo_object_size)
621                         + ALIGNED_WORDS(sizeof(struct finalizable_object));
622             GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
623             curr_fo = next_fo;
624         } else {
625             prev_fo = curr_fo;
626             curr_fo = fo_next(curr_fo);
627         }
628       }
629     }
630
631   if (GC_java_finalization) {
632     /* make sure we mark everything reachable from objects finalized
633        using the no_order mark_proc */
634       for (curr_fo = GC_finalize_now; 
635          curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
636         real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
637         if (!GC_is_marked(real_ptr)) {
638             if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
639                 GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
640             }
641             GC_set_mark_bit(real_ptr);
642         }
643       }
644   }
645
646   /* Remove dangling disappearing links. */
647     for (i = 0; i < dl_size; i++) {
648       curr_dl = dl_head[i];
649       prev_dl = 0;
650       while (curr_dl != 0) {
651         real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
652         if (real_link != 0 && !GC_is_marked(real_link)) {
653             next_dl = dl_next(curr_dl);
654             if (prev_dl == 0) {
655                 dl_head[i] = next_dl;
656             } else {
657                 dl_set_next(prev_dl, next_dl);
658             }
659             GC_clear_mark_bit((ptr_t)curr_dl);
660             GC_dl_entries--;
661             curr_dl = next_dl;
662         } else {
663             prev_dl = curr_dl;
664             curr_dl = dl_next(curr_dl);
665         }
666       }
667     }
668 }
669
670 #ifndef JAVA_FINALIZATION_NOT_NEEDED
671
672 /* Enqueue all remaining finalizers to be run - Assumes lock is
673  * held, and signals are disabled */
674 void GC_enqueue_all_finalizers()
675 {
676     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
677     ptr_t real_ptr;
678     register int i;
679     int fo_size;
680     
681     fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
682     GC_words_finalized = 0;
683     for (i = 0; i < fo_size; i++) {
684         curr_fo = fo_head[i];
685         prev_fo = 0;
686       while (curr_fo != 0) {
687           real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
688           GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
689           GC_set_mark_bit(real_ptr);
690  
691           /* Delete from hash table */
692           next_fo = fo_next(curr_fo);
693           if (prev_fo == 0) {
694               fo_head[i] = next_fo;
695           } else {
696               fo_set_next(prev_fo, next_fo);
697           }
698           GC_fo_entries--;
699
700           /* Add to list of objects awaiting finalization.      */
701           fo_set_next(curr_fo, GC_finalize_now);
702           GC_finalize_now = curr_fo;
703
704           /* unhide object pointer so any future collections will       */
705           /* see it.                                            */
706           curr_fo -> fo_hidden_base = 
707                         (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
708
709           GC_words_finalized +=
710                 ALIGNED_WORDS(curr_fo -> fo_object_size)
711                         + ALIGNED_WORDS(sizeof(struct finalizable_object));
712           curr_fo = next_fo;
713         }
714     }
715
716     return;
717 }
718
719 /* Invoke all remaining finalizers that haven't yet been run. 
720  * This is needed for strict compliance with the Java standard, 
721  * which can make the runtime guarantee that all finalizers are run.
722  * Unfortunately, the Java standard implies we have to keep running
723  * finalizers until there are no more left, a potential infinite loop.
724  * YUCK.
725  * Note that this is even more dangerous than the usual Java
726  * finalizers, in that objects reachable from static variables
727  * may have been finalized when these finalizers are run.
728  * Finalizers run at this point must be prepared to deal with a
729  * mostly broken world.
730  * This routine is externally callable, so is called without 
731  * the allocation lock. 
732  */
733 GC_API void GC_finalize_all()
734 {
735     DCL_LOCK_STATE;
736
737     DISABLE_SIGNALS();
738     LOCK();
739     while (GC_fo_entries > 0) {
740       GC_enqueue_all_finalizers();
741       UNLOCK();
742       ENABLE_SIGNALS();
743       GC_INVOKE_FINALIZERS();
744       DISABLE_SIGNALS();
745       LOCK();
746     }
747     UNLOCK();
748     ENABLE_SIGNALS();
749 }
750 #endif
751
752 /* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
753 /* finalizers can only be called from some kind of `safe state' and     */
754 /* getting into that safe state is expensive.)                          */
755 int GC_should_invoke_finalizers GC_PROTO((void))
756 {
757     return GC_finalize_now != 0;
758 }
759
760 /* Invoke finalizers for all objects that are ready to be finalized.    */
761 /* Should be called without allocation lock.                            */
762 int GC_invoke_finalizers()
763 {
764     struct finalizable_object * curr_fo;
765     int count = 0;
766     word mem_freed_before;
767     DCL_LOCK_STATE;
768     
769     while (GC_finalize_now != 0) {
770 #       ifdef THREADS
771             DISABLE_SIGNALS();
772             LOCK();
773 #       endif
774         if (count == 0) {
775             mem_freed_before = GC_mem_freed;
776         }
777         curr_fo = GC_finalize_now;
778 #       ifdef THREADS
779             if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
780             UNLOCK();
781             ENABLE_SIGNALS();
782             if (curr_fo == 0) break;
783 #       else
784             GC_finalize_now = fo_next(curr_fo);
785 #       endif
786         fo_set_next(curr_fo, 0);
787         (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
788                               curr_fo -> fo_client_data);
789         curr_fo -> fo_client_data = 0;
790         ++count;
791 #       ifdef UNDEFINED
792             /* This is probably a bad idea.  It throws off accounting if */
793             /* nearly all objects are finalizable.  O.w. it shouldn't    */
794             /* matter.                                                   */
795             GC_free((GC_PTR)curr_fo);
796 #       endif
797     }
798     if (count != 0 && mem_freed_before != GC_mem_freed) {
799         LOCK();
800         GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
801         UNLOCK();
802     }
803     return count;
804 }
805
806 void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
807
808 static GC_word last_finalizer_notification = 0;
809
810 void GC_notify_or_invoke_finalizers GC_PROTO((void))
811 {
812     /* This is a convenient place to generate backtraces if appropriate, */
813     /* since that code is not callable with the allocation lock.         */
814 #   if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
815       static word last_back_trace_gc_no = 1;    /* Skip first one. */
816
817       if (GC_gc_no > last_back_trace_gc_no) {
818         word i;
819
820 #       ifdef KEEP_BACK_PTRS
821           LOCK();
822           /* Stops when GC_gc_no wraps; that's OK.      */
823           last_back_trace_gc_no = (word)(-1);  /* disable others. */
824           for (i = 0; i < GC_backtraces; ++i) {
825               /* FIXME: This tolerates concurrent heap mutation,        */
826               /* which may cause occasional mysterious results.         */
827               /* We need to release the GC lock, since GC_print_callers */
828               /* acquires it.  It probably shouldn't.                   */
829               UNLOCK();
830               GC_generate_random_backtrace_no_gc();
831               LOCK();
832           }
833           last_back_trace_gc_no = GC_gc_no;
834           UNLOCK();
835 #       endif
836 #       ifdef MAKE_BACK_GRAPH
837           if (GC_print_back_height)
838             GC_print_back_graph_stats();
839 #       endif
840       }
841 #   endif
842     if (GC_finalize_now == 0) return;
843     if (!GC_finalize_on_demand) {
844         (void) GC_invoke_finalizers();
845 #       ifndef THREADS
846           GC_ASSERT(GC_finalize_now == 0);
847 #       endif   /* Otherwise GC can run concurrently and add more */
848         return;
849     }
850     if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
851         && last_finalizer_notification != GC_gc_no) {
852         last_finalizer_notification = GC_gc_no;
853         GC_finalizer_notifier();
854     }
855 }
856
857 # ifdef __STDC__
858     GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
859                                          GC_PTR client_data)
860 # else
861     GC_PTR GC_call_with_alloc_lock(fn, client_data)
862     GC_fn_type fn;
863     GC_PTR client_data;
864 # endif
865 {
866     GC_PTR result;
867     DCL_LOCK_STATE;
868     
869 #   ifdef THREADS
870       DISABLE_SIGNALS();
871       LOCK();
872       SET_LOCK_HOLDER();
873 #   endif
874     result = (*fn)(client_data);
875 #   ifdef THREADS
876 #     ifndef GC_ASSERTIONS
877         UNSET_LOCK_HOLDER();
878 #     endif /* o.w. UNLOCK() does it implicitly */
879       UNLOCK();
880       ENABLE_SIGNALS();
881 #   endif
882     return(result);
883 }
884
885 #if !defined(NO_DEBUGGING)
886
887 void GC_print_finalization_stats()
888 {
889     struct finalizable_object *fo = GC_finalize_now;
890     size_t ready = 0;
891
892     GC_printf2("%lu finalization table entries; %lu disappearing links\n",
893                GC_fo_entries, GC_dl_entries);
894     for (; 0 != fo; fo = fo_next(fo)) ++ready;
895     GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
896 }
897
898 #endif /* NO_DEBUGGING */