OSDN Git Service

* include/private/gc_locks.h (GC_test_and_set): Support
[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 = GC_oom_fn(sizeof(struct disappearing_link));
211       if (0 == new_dl) {
212         GC_finalization_failures++;
213         return(0);
214       }
215       /* It's not likely we'll make it here, but ... */
216 #     ifdef THREADS
217         DISABLE_SIGNALS();
218         LOCK();
219 #     endif
220     }
221     new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
222     new_dl -> dl_hidden_link = HIDE_POINTER(link);
223     dl_set_next(new_dl, dl_head[index]);
224     dl_head[index] = new_dl;
225     GC_dl_entries++;
226 #   ifdef THREADS
227         UNLOCK();
228         ENABLE_SIGNALS();
229 #   endif
230     return(0);
231 }
232
233 # if defined(__STDC__) || defined(__cplusplus)
234     int GC_unregister_disappearing_link(GC_PTR * link)
235 # else
236     int GC_unregister_disappearing_link(link)
237     GC_PTR * link;
238 # endif
239 {
240     struct disappearing_link *curr_dl, *prev_dl;
241     int index;
242     DCL_LOCK_STATE;
243     
244     DISABLE_SIGNALS();
245     LOCK();
246     index = HASH2(link, log_dl_table_size);
247     if (((unsigned long)link & (ALIGNMENT-1))) goto out;
248     prev_dl = 0; curr_dl = dl_head[index];
249     while (curr_dl != 0) {
250         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
251             if (prev_dl == 0) {
252                 dl_head[index] = dl_next(curr_dl);
253             } else {
254                 dl_set_next(prev_dl, dl_next(curr_dl));
255             }
256             GC_dl_entries--;
257             UNLOCK();
258             ENABLE_SIGNALS();
259 #           ifdef DBG_HDRS_ALL
260               dl_set_next(curr_dl, 0);
261 #           else
262               GC_free((GC_PTR)curr_dl);
263 #           endif
264             return(1);
265         }
266         prev_dl = curr_dl;
267         curr_dl = dl_next(curr_dl);
268     }
269 out:
270     UNLOCK();
271     ENABLE_SIGNALS();
272     return(0);
273 }
274
275 /* Possible finalization_marker procedures.  Note that mark stack       */
276 /* overflow is handled by the caller, and is not a disaster.            */
277 GC_API void GC_normal_finalize_mark_proc(p)
278 ptr_t p;
279 {
280     hdr * hhdr = HDR(p);
281     
282     PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
283              &(GC_mark_stack[GC_mark_stack_size]));
284 }
285
286 /* This only pays very partial attention to the mark descriptor.        */
287 /* It does the right thing for normal and atomic objects, and treats    */
288 /* most others as normal.                                               */
289 GC_API void GC_ignore_self_finalize_mark_proc(p)
290 ptr_t p;
291 {
292     hdr * hhdr = HDR(p);
293     word descr = hhdr -> hb_descr;
294     ptr_t q, r;
295     ptr_t scan_limit;
296     ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
297     
298     if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
299        scan_limit = p + descr - sizeof(word);
300     } else {
301        scan_limit = target_limit + 1 - sizeof(word);
302     }
303     for (q = p; q <= scan_limit; q += ALIGNMENT) {
304         r = *(ptr_t *)q;
305         if (r < p || r > target_limit) {
306             GC_PUSH_ONE_HEAP((word)r, q);
307         }
308     }
309 }
310
311 /*ARGSUSED*/
312 GC_API void GC_null_finalize_mark_proc(p)
313 ptr_t p;
314 {
315 }
316
317
318
319 /* Register a finalization function.  See gc.h for details.     */
320 /* in the nonthreads case, we try to avoid disabling signals,   */
321 /* since it can be expensive.  Threads packages typically       */
322 /* make it cheaper.                                             */
323 /* The last parameter is a procedure that determines            */
324 /* marking for finalization ordering.  Any objects marked       */
325 /* by that procedure will be guaranteed to not have been        */
326 /* finalized when this finalizer is invoked.                    */
327 GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
328 GC_PTR obj;
329 GC_finalization_proc fn;
330 GC_PTR cd;
331 GC_finalization_proc * ofn;
332 GC_PTR * ocd;
333 finalization_mark_proc * mp;
334 {
335     ptr_t base;
336     struct finalizable_object * curr_fo, * prev_fo;
337     int index;
338     struct finalizable_object *new_fo;
339     hdr *hhdr;
340     DCL_LOCK_STATE;
341
342 #   ifdef THREADS
343         DISABLE_SIGNALS();
344         LOCK();
345 #   endif
346     if (log_fo_table_size == -1
347         || GC_fo_entries > ((word)1 << log_fo_table_size)) {
348 #       ifndef THREADS
349             DISABLE_SIGNALS();
350 #       endif
351         GC_grow_table((struct hash_chain_entry ***)(&fo_head),
352                       &log_fo_table_size);
353 #       ifdef CONDPRINT
354           if (GC_print_stats) {
355             GC_printf1("Grew fo table to %lu entries\n",
356                         (unsigned long)(1 << log_fo_table_size));
357           }
358 #       endif
359 #       ifndef THREADS
360             ENABLE_SIGNALS();
361 #       endif
362     }
363     /* in the THREADS case signals are disabled and we hold allocation  */
364     /* lock; otherwise neither is true.  Proceed carefully.             */
365     base = (ptr_t)obj;
366     index = HASH2(base, log_fo_table_size);
367     prev_fo = 0; curr_fo = fo_head[index];
368     while (curr_fo != 0) {
369         if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
370             /* Interruption by a signal in the middle of this   */
371             /* should be safe.  The client may see only *ocd    */
372             /* updated, but we'll declare that to be his        */
373             /* problem.                                         */
374             if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
375             if (ofn) *ofn = curr_fo -> fo_fn;
376             /* Delete the structure for base. */
377                 if (prev_fo == 0) {
378                   fo_head[index] = fo_next(curr_fo);
379                 } else {
380                   fo_set_next(prev_fo, fo_next(curr_fo));
381                 }
382             if (fn == 0) {
383                 GC_fo_entries--;
384                   /* May not happen if we get a signal.  But a high     */
385                   /* estimate will only make the table larger than      */
386                   /* necessary.                                         */
387 #               if !defined(THREADS) && !defined(DBG_HDRS_ALL)
388                   GC_free((GC_PTR)curr_fo);
389 #               endif
390             } else {
391                 curr_fo -> fo_fn = fn;
392                 curr_fo -> fo_client_data = (ptr_t)cd;
393                 curr_fo -> fo_mark_proc = mp;
394                 /* Reinsert it.  We deleted it first to maintain        */
395                 /* consistency in the event of a signal.                */
396                 if (prev_fo == 0) {
397                   fo_head[index] = curr_fo;
398                 } else {
399                   fo_set_next(prev_fo, curr_fo);
400                 }
401             }
402 #           ifdef THREADS
403                 UNLOCK();
404                 ENABLE_SIGNALS();
405 #           endif
406             return;
407         }
408         prev_fo = curr_fo;
409         curr_fo = fo_next(curr_fo);
410     }
411     if (ofn) *ofn = 0;
412     if (ocd) *ocd = 0;
413     if (fn == 0) {
414 #       ifdef THREADS
415             UNLOCK();
416             ENABLE_SIGNALS();
417 #       endif
418         return;
419     }
420     GET_HDR(base, hhdr);
421     if (0 == hhdr) {
422       /* We won't collect it, hence finalizer wouldn't be run. */
423 #     ifdef THREADS
424           UNLOCK();
425           ENABLE_SIGNALS();
426 #     endif
427       return;
428     }
429     new_fo = (struct finalizable_object *)
430         GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
431     if (0 == new_fo) {
432 #     ifdef THREADS
433         UNLOCK();
434         ENABLE_SIGNALS();
435 #     endif
436       new_fo = GC_oom_fn(sizeof(struct finalizable_object));
437       if (0 == new_fo) {
438         GC_finalization_failures++;
439         return;
440       }
441       /* It's not likely we'll make it here, but ... */
442 #     ifdef THREADS
443         DISABLE_SIGNALS();
444         LOCK();
445 #     endif
446     }
447     new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
448     new_fo -> fo_fn = fn;
449     new_fo -> fo_client_data = (ptr_t)cd;
450     new_fo -> fo_object_size = hhdr -> hb_sz;
451     new_fo -> fo_mark_proc = mp;
452     fo_set_next(new_fo, fo_head[index]);
453     GC_fo_entries++;
454     fo_head[index] = new_fo;
455 #   ifdef THREADS
456         UNLOCK();
457         ENABLE_SIGNALS();
458 #   endif
459 }
460
461 # if defined(__STDC__)
462     void GC_register_finalizer(void * obj,
463                                GC_finalization_proc fn, void * cd,
464                                GC_finalization_proc *ofn, void ** ocd)
465 # else
466     void GC_register_finalizer(obj, fn, cd, ofn, ocd)
467     GC_PTR obj;
468     GC_finalization_proc fn;
469     GC_PTR cd;
470     GC_finalization_proc * ofn;
471     GC_PTR * ocd;
472 # endif
473 {
474     GC_register_finalizer_inner(obj, fn, cd, ofn,
475                                 ocd, GC_normal_finalize_mark_proc);
476 }
477
478 # if defined(__STDC__)
479     void GC_register_finalizer_ignore_self(void * obj,
480                                GC_finalization_proc fn, void * cd,
481                                GC_finalization_proc *ofn, void ** ocd)
482 # else
483     void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
484     GC_PTR obj;
485     GC_finalization_proc fn;
486     GC_PTR cd;
487     GC_finalization_proc * ofn;
488     GC_PTR * ocd;
489 # endif
490 {
491     GC_register_finalizer_inner(obj, fn, cd, ofn,
492                                 ocd, GC_ignore_self_finalize_mark_proc);
493 }
494
495 # if defined(__STDC__)
496     void GC_register_finalizer_no_order(void * obj,
497                                GC_finalization_proc fn, void * cd,
498                                GC_finalization_proc *ofn, void ** ocd)
499 # else
500     void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
501     GC_PTR obj;
502     GC_finalization_proc fn;
503     GC_PTR cd;
504     GC_finalization_proc * ofn;
505     GC_PTR * ocd;
506 # endif
507 {
508     GC_register_finalizer_inner(obj, fn, cd, ofn,
509                                 ocd, GC_null_finalize_mark_proc);
510 }
511
512 #ifndef NO_DEBUGGING
513 void GC_dump_finalization()
514 {
515     struct disappearing_link * curr_dl;
516     struct finalizable_object * curr_fo;
517     ptr_t real_ptr, real_link;
518     int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
519     int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
520     int i;
521
522     GC_printf0("Disappearing links:\n");
523     for (i = 0; i < dl_size; i++) {
524       for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
525         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
526         real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
527         GC_printf2("Object: 0x%lx, Link:0x%lx\n", real_ptr, real_link);
528       }
529     }
530     GC_printf0("Finalizers:\n");
531     for (i = 0; i < fo_size; i++) {
532       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
533         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
534         GC_printf1("Finalizable object: 0x%lx\n", real_ptr);
535       }
536     }
537 }
538 #endif
539
540 /* Called with world stopped.  Cause disappearing links to disappear,   */
541 /* and invoke finalizers.                                               */
542 void GC_finalize()
543 {
544     struct disappearing_link * curr_dl, * prev_dl, * next_dl;
545     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
546     ptr_t real_ptr, real_link;
547     register int i;
548     int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
549     int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
550     
551   /* Make disappearing links disappear */
552     for (i = 0; i < dl_size; i++) {
553       curr_dl = dl_head[i];
554       prev_dl = 0;
555       while (curr_dl != 0) {
556         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
557         real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
558         if (!GC_is_marked(real_ptr)) {
559             *(word *)real_link = 0;
560             next_dl = dl_next(curr_dl);
561             if (prev_dl == 0) {
562                 dl_head[i] = next_dl;
563             } else {
564                 dl_set_next(prev_dl, next_dl);
565             }
566             GC_clear_mark_bit((ptr_t)curr_dl);
567             GC_dl_entries--;
568             curr_dl = next_dl;
569         } else {
570             prev_dl = curr_dl;
571             curr_dl = dl_next(curr_dl);
572         }
573       }
574     }
575   /* Mark all objects reachable via chains of 1 or more pointers        */
576   /* from finalizable objects.                                          */
577     GC_ASSERT(GC_mark_state == MS_NONE);
578     for (i = 0; i < fo_size; i++) {
579       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
580         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
581         if (!GC_is_marked(real_ptr)) {
582             GC_MARKED_FOR_FINALIZATION(real_ptr);
583             GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
584             if (GC_is_marked(real_ptr)) {
585                 WARN("Finalization cycle involving %lx\n", real_ptr);
586             }
587         }
588       }
589     }
590   /* Enqueue for finalization all objects that are still                */
591   /* unreachable.                                                       */
592     GC_words_finalized = 0;
593     for (i = 0; i < fo_size; i++) {
594       curr_fo = fo_head[i];
595       prev_fo = 0;
596       while (curr_fo != 0) {
597         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
598         if (!GC_is_marked(real_ptr)) {
599             if (!GC_java_finalization) {
600               GC_set_mark_bit(real_ptr);
601             }
602             /* Delete from hash table */
603               next_fo = fo_next(curr_fo);
604               if (prev_fo == 0) {
605                 fo_head[i] = next_fo;
606               } else {
607                 fo_set_next(prev_fo, next_fo);
608               }
609               GC_fo_entries--;
610             /* Add to list of objects awaiting finalization.    */
611               fo_set_next(curr_fo, GC_finalize_now);
612               GC_finalize_now = curr_fo;
613               /* unhide object pointer so any future collections will   */
614               /* see it.                                                */
615               curr_fo -> fo_hidden_base = 
616                         (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
617               GC_words_finalized +=
618                         ALIGNED_WORDS(curr_fo -> fo_object_size)
619                         + ALIGNED_WORDS(sizeof(struct finalizable_object));
620             GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
621             curr_fo = next_fo;
622         } else {
623             prev_fo = curr_fo;
624             curr_fo = fo_next(curr_fo);
625         }
626       }
627     }
628
629   if (GC_java_finalization) {
630     /* make sure we mark everything reachable from objects finalized
631        using the no_order mark_proc */
632       for (curr_fo = GC_finalize_now; 
633          curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
634         real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
635         if (!GC_is_marked(real_ptr)) {
636             if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
637                 GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
638             }
639             GC_set_mark_bit(real_ptr);
640         }
641       }
642   }
643
644   /* Remove dangling disappearing links. */
645     for (i = 0; i < dl_size; i++) {
646       curr_dl = dl_head[i];
647       prev_dl = 0;
648       while (curr_dl != 0) {
649         real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
650         if (real_link != 0 && !GC_is_marked(real_link)) {
651             next_dl = dl_next(curr_dl);
652             if (prev_dl == 0) {
653                 dl_head[i] = next_dl;
654             } else {
655                 dl_set_next(prev_dl, next_dl);
656             }
657             GC_clear_mark_bit((ptr_t)curr_dl);
658             GC_dl_entries--;
659             curr_dl = next_dl;
660         } else {
661             prev_dl = curr_dl;
662             curr_dl = dl_next(curr_dl);
663         }
664       }
665     }
666 }
667
668 #ifndef JAVA_FINALIZATION_NOT_NEEDED
669
670 /* Enqueue all remaining finalizers to be run - Assumes lock is
671  * held, and signals are disabled */
672 void GC_enqueue_all_finalizers()
673 {
674     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
675     ptr_t real_ptr;
676     register int i;
677     int fo_size;
678     
679     fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
680     GC_words_finalized = 0;
681     for (i = 0; i < fo_size; i++) {
682         curr_fo = fo_head[i];
683         prev_fo = 0;
684       while (curr_fo != 0) {
685           real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
686           GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
687           GC_set_mark_bit(real_ptr);
688  
689           /* Delete from hash table */
690           next_fo = fo_next(curr_fo);
691           if (prev_fo == 0) {
692               fo_head[i] = next_fo;
693           } else {
694               fo_set_next(prev_fo, next_fo);
695           }
696           GC_fo_entries--;
697
698           /* Add to list of objects awaiting finalization.      */
699           fo_set_next(curr_fo, GC_finalize_now);
700           GC_finalize_now = curr_fo;
701
702           /* unhide object pointer so any future collections will       */
703           /* see it.                                            */
704           curr_fo -> fo_hidden_base = 
705                         (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
706
707           GC_words_finalized +=
708                 ALIGNED_WORDS(curr_fo -> fo_object_size)
709                         + ALIGNED_WORDS(sizeof(struct finalizable_object));
710           curr_fo = next_fo;
711         }
712     }
713
714     return;
715 }
716
717 /* Invoke all remaining finalizers that haven't yet been run. 
718  * This is needed for strict compliance with the Java standard, 
719  * which can make the runtime guarantee that all finalizers are run.
720  * Unfortunately, the Java standard implies we have to keep running
721  * finalizers until there are no more left, a potential infinite loop.
722  * YUCK.
723  * Note that this is even more dangerous than the usual Java
724  * finalizers, in that objects reachable from static variables
725  * may have been finalized when these finalizers are run.
726  * Finalizers run at this point must be prepared to deal with a
727  * mostly broken world.
728  * This routine is externally callable, so is called without 
729  * the allocation lock. 
730  */
731 GC_API void GC_finalize_all()
732 {
733     DCL_LOCK_STATE;
734
735     DISABLE_SIGNALS();
736     LOCK();
737     while (GC_fo_entries > 0) {
738       GC_enqueue_all_finalizers();
739       UNLOCK();
740       ENABLE_SIGNALS();
741       GC_INVOKE_FINALIZERS();
742       DISABLE_SIGNALS();
743       LOCK();
744     }
745     UNLOCK();
746     ENABLE_SIGNALS();
747 }
748 #endif
749
750 /* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
751 /* finalizers can only be called from some kind of `safe state' and     */
752 /* getting into that safe state is expensive.)                          */
753 int GC_should_invoke_finalizers GC_PROTO((void))
754 {
755     return GC_finalize_now != 0;
756 }
757
758 /* Invoke finalizers for all objects that are ready to be finalized.    */
759 /* Should be called without allocation lock.                            */
760 int GC_invoke_finalizers()
761 {
762     register struct finalizable_object * curr_fo;
763     register int count = 0;
764     DCL_LOCK_STATE;
765     
766     while (GC_finalize_now != 0) {
767 #       ifdef THREADS
768             DISABLE_SIGNALS();
769             LOCK();
770 #       endif
771         curr_fo = GC_finalize_now;
772 #       ifdef THREADS
773             if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
774             UNLOCK();
775             ENABLE_SIGNALS();
776             if (curr_fo == 0) break;
777 #       else
778             GC_finalize_now = fo_next(curr_fo);
779 #       endif
780         fo_set_next(curr_fo, 0);
781         (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
782                               curr_fo -> fo_client_data);
783         curr_fo -> fo_client_data = 0;
784         ++count;
785 #       ifdef UNDEFINED
786             /* This is probably a bad idea.  It throws off accounting if */
787             /* nearly all objects are finalizable.  O.w. it shouldn't    */
788             /* matter.                                                   */
789             GC_free((GC_PTR)curr_fo);
790 #       endif
791     }
792     return count;
793 }
794
795 void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
796
797 static GC_word last_finalizer_notification = 0;
798
799 void GC_notify_or_invoke_finalizers GC_PROTO((void))
800 {
801     if (GC_finalize_now == 0) return;
802     if (!GC_finalize_on_demand) {
803         (void) GC_invoke_finalizers();
804         GC_ASSERT(GC_finalize_now == 0);
805         return;
806     }
807     if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
808         && last_finalizer_notification != GC_gc_no) {
809         last_finalizer_notification = GC_gc_no;
810         GC_finalizer_notifier();
811     }
812 }
813
814 # ifdef __STDC__
815     GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
816                                          GC_PTR client_data)
817 # else
818     GC_PTR GC_call_with_alloc_lock(fn, client_data)
819     GC_fn_type fn;
820     GC_PTR client_data;
821 # endif
822 {
823     GC_PTR result;
824     DCL_LOCK_STATE;
825     
826 #   ifdef THREADS
827       DISABLE_SIGNALS();
828       LOCK();
829       SET_LOCK_HOLDER();
830 #   endif
831     result = (*fn)(client_data);
832 #   ifdef THREADS
833 #     ifndef GC_ASSERTIONS
834         UNSET_LOCK_HOLDER();
835 #     endif /* o.w. UNLOCK() does it implicitly */
836       UNLOCK();
837       ENABLE_SIGNALS();
838 #   endif
839     return(result);
840 }
841