]> granicus.if.org Git - gc/blob - reclaim.c
Merge (dummy) branch 'fnlz-requires-all-interior'
[gc] / reclaim.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  * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
6  *
7  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
9  *
10  * Permission is hereby granted to use or copy this program
11  * for any purpose,  provided the above notices are retained on all copies.
12  * Permission to modify the code and to distribute modified code is granted,
13  * provided the above notices are retained, and a notice that the code was
14  * modified is included with the above copyright notice.
15  */
16
17 #include "private/gc_priv.h"
18
19 #ifdef ENABLE_DISCLAIM
20 #  include "gc_disclaim.h"
21 #endif
22
23 #include <stdio.h>
24
25 GC_INNER signed_word GC_bytes_found = 0;
26                         /* Number of bytes of memory reclaimed     */
27                         /* minus the number of bytes originally    */
28                         /* on free lists which we had to drop.     */
29
30 #if defined(PARALLEL_MARK)
31   GC_INNER word GC_fl_builder_count = 0;
32         /* Number of threads currently building free lists without      */
33         /* holding GC lock.  It is not safe to collect if this is       */
34         /* nonzero.                                                     */
35 #endif /* PARALLEL_MARK */
36
37 /* We defer printing of leaked objects until we're done with the GC     */
38 /* cycle, since the routine for printing objects needs to run outside   */
39 /* the collector, e.g. without the allocation lock.                     */
40 #ifndef MAX_LEAKED
41 # define MAX_LEAKED 40
42 #endif
43 STATIC ptr_t GC_leaked[MAX_LEAKED] = { NULL };
44 STATIC unsigned GC_n_leaked = 0;
45
46 GC_INNER GC_bool GC_have_errors = FALSE;
47
48 #if !defined(EAGER_SWEEP) && defined(ENABLE_DISCLAIM)
49   STATIC void GC_reclaim_unconditionally_marked(void);
50 #endif
51
52 GC_INLINE void GC_add_leaked(ptr_t leaked)
53 {
54 #  ifndef SHORT_DBG_HDRS
55      if (GC_findleak_delay_free && !GC_check_leaked(leaked))
56        return;
57 #  endif
58
59     GC_have_errors = TRUE;
60     /* FIXME: Prevent adding an object while printing leaked ones.      */
61     if (GC_n_leaked < MAX_LEAKED) {
62       GC_leaked[GC_n_leaked++] = leaked;
63       /* Make sure it's not reclaimed this cycle */
64       GC_set_mark_bit(leaked);
65     }
66 }
67
68 /* Print all objects on the list after printing any smashed objects.    */
69 /* Clear both lists.  Called without the allocation lock held.          */
70 GC_INNER void GC_print_all_errors(void)
71 {
72     static GC_bool printing_errors = FALSE;
73     GC_bool have_errors;
74     unsigned i;
75     DCL_LOCK_STATE;
76
77     LOCK();
78     if (printing_errors) {
79         UNLOCK();
80         return;
81     }
82     have_errors = GC_have_errors;
83     printing_errors = TRUE;
84     UNLOCK();
85
86     if (GC_debugging_started) {
87       GC_print_all_smashed();
88     } else {
89       have_errors = FALSE;
90     }
91
92     if (GC_n_leaked > 0) {
93         GC_err_printf("Found %u leaked objects:\n", GC_n_leaked);
94         have_errors = TRUE;
95     }
96     for (i = 0; i < GC_n_leaked; ++i) {
97         ptr_t p = GC_leaked[i];
98         GC_print_heap_obj(p);
99         GC_free(p);
100         GC_leaked[i] = 0;
101     }
102     GC_n_leaked = 0;
103
104     if (have_errors
105 #       ifndef GC_ABORT_ON_LEAK
106           && GETENV("GC_ABORT_ON_LEAK") != NULL
107 #       endif
108         ) {
109       ABORT("Leaked or smashed objects encountered");
110     }
111
112     printing_errors = FALSE;
113 }
114
115
116 /*
117  * reclaim phase
118  *
119  */
120
121 /* Test whether a block is completely empty, i.e. contains no marked    */
122 /* objects.  This does not require the block to be in physical memory.  */
123 GC_INNER GC_bool GC_block_empty(hdr *hhdr)
124 {
125     return (hhdr -> hb_n_marks == 0);
126 }
127
128 STATIC GC_bool GC_block_nearly_full(hdr *hhdr)
129 {
130     return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8);
131 }
132
133 /* FIXME: This should perhaps again be specialized for USE_MARK_BYTES   */
134 /* and USE_MARK_BITS cases.                                             */
135
136 /*
137  * Restore unmarked small objects in h of size sz to the object
138  * free list.  Returns the new list.
139  * Clears unmarked objects.  Sz is in bytes.
140  */
141 STATIC ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, size_t sz,
142                               ptr_t list, signed_word *count)
143 {
144     word bit_no = 0;
145     word *p, *q, *plim;
146     signed_word n_bytes_found = 0;
147
148     GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
149     GC_ASSERT(sz == hhdr -> hb_sz);
150     GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0);
151     p = (word *)(hbp->hb_body);
152     plim = (word *)(hbp->hb_body + HBLKSIZE - sz);
153
154     /* go through all words in block */
155         while ((word)p <= (word)plim) {
156             if (mark_bit_from_hdr(hhdr, bit_no)) {
157                 p = (word *)((ptr_t)p + sz);
158             } else {
159                 n_bytes_found += sz;
160                 /* object is available - put on list */
161                     obj_link(p) = list;
162                     list = ((ptr_t)p);
163                 /* Clear object, advance p to next object in the process */
164                     q = (word *)((ptr_t)p + sz);
165 #                   ifdef USE_MARK_BYTES
166                       GC_ASSERT(!(sz & 1)
167                                 && !((word)p & (2 * sizeof(word) - 1)));
168                       p[1] = 0;
169                       p += 2;
170                       while ((word)p < (word)q) {
171                         CLEAR_DOUBLE(p);
172                         p += 2;
173                       }
174 #                   else
175                       p++; /* Skip link field */
176                       while ((word)p < (word)q) {
177                         *p++ = 0;
178                       }
179 #                   endif
180             }
181             bit_no += MARK_BIT_OFFSET(sz);
182         }
183     *count += n_bytes_found;
184     return(list);
185 }
186
187 /* The same thing, but don't clear objects: */
188 STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, size_t sz,
189                                ptr_t list, signed_word *count)
190 {
191     word bit_no = 0;
192     word *p, *plim;
193     signed_word n_bytes_found = 0;
194
195     GC_ASSERT(sz == hhdr -> hb_sz);
196     p = (word *)(hbp->hb_body);
197     plim = (word *)((ptr_t)hbp + HBLKSIZE - sz);
198
199     /* go through all words in block */
200         while ((word)p <= (word)plim) {
201             if (!mark_bit_from_hdr(hhdr, bit_no)) {
202                 n_bytes_found += sz;
203                 /* object is available - put on list */
204                     obj_link(p) = list;
205                     list = ((ptr_t)p);
206             }
207             p = (word *)((ptr_t)p + sz);
208             bit_no += MARK_BIT_OFFSET(sz);
209         }
210     *count += n_bytes_found;
211     return(list);
212 }
213
214 #ifdef ENABLE_DISCLAIM
215   /* Call reclaim notifier for block's kind on each unmarked object in  */
216   /* block, all within a pair of corresponding enter/leave callbacks.   */
217   STATIC ptr_t GC_disclaim_and_reclaim(struct hblk *hbp, hdr *hhdr, size_t sz,
218                                        ptr_t list, signed_word *count)
219   {
220     int bit_no = 0;
221     word *p, *q, *plim;
222     signed_word n_bytes_found = 0;
223     struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind];
224     int (GC_CALLBACK *disclaim)(void *) = ok->ok_disclaim_proc;
225
226     GC_ASSERT(sz == hhdr -> hb_sz);
227     p = (word *)(hbp -> hb_body);
228     plim = (word *)((ptr_t)p + HBLKSIZE - sz);
229
230     while ((word)p <= (word)plim) {
231         int marked = mark_bit_from_hdr(hhdr, bit_no);
232         if (!marked && (*disclaim)(p)) {
233             hhdr -> hb_n_marks++;
234             marked = 1;
235         }
236         if (marked)
237             p = (word *)((ptr_t)p + sz);
238         else {
239                 n_bytes_found += sz;
240                 /* object is available - put on list */
241                     obj_link(p) = list;
242                     list = ((ptr_t)p);
243                 /* Clear object, advance p to next object in the process */
244                     q = (word *)((ptr_t)p + sz);
245 #                   ifdef USE_MARK_BYTES
246                       GC_ASSERT((sz & 1) == 0);
247                       GC_ASSERT(((word)p & (2 * sizeof(word) - 1)) == 0);
248                       p[1] = 0;
249                       p += 2;
250                       while ((word)p < (word)q) {
251                         CLEAR_DOUBLE(p);
252                         p += 2;
253                       }
254 #                   else
255                       p++; /* Skip link field */
256                       while ((word)p < (word)q) {
257                         *p++ = 0;
258                       }
259 #                   endif
260         }
261         bit_no += MARK_BIT_OFFSET(sz);
262     }
263     *count += n_bytes_found;
264     return list;
265   }
266 #endif /* ENABLE_DISCLAIM */
267
268 /* Don't really reclaim objects, just check for unmarked ones: */
269 STATIC void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz)
270 {
271     word bit_no;
272     ptr_t p, plim;
273     GC_ASSERT(sz == hhdr -> hb_sz);
274
275     /* go through all words in block */
276     p = hbp->hb_body;
277     plim = p + HBLKSIZE - sz;
278     for (bit_no = 0; (word)p <= (word)plim;
279          p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
280       if (!mark_bit_from_hdr(hhdr, bit_no)) {
281         GC_add_leaked(p);
282       }
283     }
284 }
285
286 /*
287  * Generic procedure to rebuild a free list in hbp.
288  * Also called directly from GC_malloc_many.
289  * Sz is now in bytes.
290  */
291 GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
292                                   GC_bool init, ptr_t list,
293                                   signed_word *count)
294 {
295     ptr_t result;
296
297     GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr);
298 #   ifndef GC_DISABLE_INCREMENTAL
299       GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */);
300 #   endif
301 #   ifdef ENABLE_DISCLAIM
302       if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) {
303         result = GC_disclaim_and_reclaim(hbp, hhdr, sz, list, count);
304       } else
305 #   endif
306     /* else */ if (init || GC_debugging_started) {
307       result = GC_reclaim_clear(hbp, hhdr, sz, list, count);
308     } else {
309       GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */);
310       result = GC_reclaim_uninit(hbp, hhdr, sz, list, count);
311     }
312     if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr);
313     return result;
314 }
315
316 /*
317  * Restore unmarked small objects in the block pointed to by hbp
318  * to the appropriate object free list.
319  * If entirely empty blocks are to be completely deallocated, then
320  * caller should perform that check.
321  */
322 STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp,
323                                             GC_bool report_if_found)
324 {
325     hdr *hhdr = HDR(hbp);
326     size_t sz = hhdr -> hb_sz;
327     struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
328     void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
329
330     hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
331
332     if (report_if_found) {
333         GC_reclaim_check(hbp, hhdr, sz);
334     } else {
335         *flh = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init,
336                                   *flh, &GC_bytes_found);
337     }
338 }
339
340 #ifdef ENABLE_DISCLAIM
341   STATIC void GC_disclaim_and_reclaim_or_free_small_block(struct hblk *hbp)
342   {
343     hdr *hhdr = HDR(hbp);
344     size_t sz = hhdr -> hb_sz;
345     struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
346     void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
347     void *flh_next;
348
349     hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
350     flh_next = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init,
351                                   *flh, &GC_bytes_found);
352     if (hhdr -> hb_n_marks)
353         *flh = flh_next;
354     else {
355         GC_bytes_found += HBLKSIZE;
356         GC_freehblk(hbp);
357     }
358   }
359 #endif /* ENABLE_DISCLAIM */
360
361 /*
362  * Restore an unmarked large object or an entirely empty blocks of small objects
363  * to the heap block free list.
364  * Otherwise enqueue the block for later processing
365  * by GC_reclaim_small_nonempty_block.
366  * If report_if_found is TRUE, then process any block immediately, and
367  * simply report free objects; do not actually reclaim them.
368  */
369 STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found)
370 {
371     hdr * hhdr = HDR(hbp);
372     size_t sz = hhdr -> hb_sz;  /* size of objects in current block     */
373     struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
374     struct hblk ** rlh;
375
376     if( sz > MAXOBJBYTES ) {  /* 1 big object */
377         if( !mark_bit_from_hdr(hhdr, 0) ) {
378             if (report_if_found) {
379               GC_add_leaked((ptr_t)hbp);
380             } else {
381               size_t blocks;
382
383 #             ifdef ENABLE_DISCLAIM
384                 if (EXPECT(hhdr->hb_flags & HAS_DISCLAIM, 0)) {
385                   struct obj_kind *ok = &GC_obj_kinds[hhdr->hb_obj_kind];
386                   if ((*ok->ok_disclaim_proc)(hbp)) {
387                     /* Not disclaimed => resurrect the object. */
388                     set_mark_bit_from_hdr(hhdr, 0);
389                     goto in_use;
390                   }
391                 }
392 #             endif
393               blocks = OBJ_SZ_TO_BLOCKS(sz);
394               if (blocks > 1) {
395                 GC_large_allocd_bytes -= blocks * HBLKSIZE;
396               }
397               GC_bytes_found += sz;
398               GC_freehblk(hbp);
399             }
400         } else {
401 #        ifdef ENABLE_DISCLAIM
402            in_use:
403 #        endif
404             if (hhdr -> hb_descr != 0) {
405               GC_composite_in_use += sz;
406             } else {
407               GC_atomic_in_use += sz;
408             }
409         }
410     } else {
411         GC_bool empty = GC_block_empty(hhdr);
412 #       ifdef PARALLEL_MARK
413           /* Count can be low or one too high because we sometimes      */
414           /* have to ignore decrements.  Objects can also potentially   */
415           /* be repeatedly marked by each marker.                       */
416           /* Here we assume two markers, but this is extremely          */
417           /* unlikely to fail spuriously with more.  And if it does, it */
418           /* should be looked at.                                       */
419           GC_ASSERT(hhdr -> hb_n_marks <= 2 * (HBLKSIZE/sz + 1) + 16);
420 #       else
421           GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE);
422 #       endif
423         if (report_if_found) {
424           GC_reclaim_small_nonempty_block(hbp, TRUE /* report_if_found */);
425         } else if (empty) {
426 #       ifdef ENABLE_DISCLAIM
427           if ((hhdr -> hb_flags & HAS_DISCLAIM) != 0) {
428             GC_disclaim_and_reclaim_or_free_small_block(hbp);
429           } else
430 #       endif
431           /* else */ {
432             GC_bytes_found += HBLKSIZE;
433             GC_freehblk(hbp);
434           }
435         } else if (GC_find_leak || !GC_block_nearly_full(hhdr)) {
436           /* group of smaller objects, enqueue the real work */
437           rlh = &(ok -> ok_reclaim_list[BYTES_TO_GRANULES(sz)]);
438           hhdr -> hb_next = *rlh;
439           *rlh = hbp;
440         } /* else not worth salvaging. */
441         /* We used to do the nearly_full check later, but we    */
442         /* already have the right cache context here.  Also     */
443         /* doing it here avoids some silly lock contention in   */
444         /* GC_malloc_many.                                      */
445
446         if (hhdr -> hb_descr != 0) {
447           GC_composite_in_use += sz * hhdr -> hb_n_marks;
448         } else {
449           GC_atomic_in_use += sz * hhdr -> hb_n_marks;
450         }
451     }
452 }
453
454 #if !defined(NO_DEBUGGING)
455 /* Routines to gather and print heap block info         */
456 /* intended for debugging.  Otherwise should be called  */
457 /* with lock.                                           */
458
459 struct Print_stats
460 {
461         size_t number_of_blocks;
462         size_t total_bytes;
463 };
464
465 #ifdef USE_MARK_BYTES
466
467 /* Return the number of set mark bits in the given header.      */
468 /* Remains externally visible as used by GNU GCJ currently.     */
469 int GC_n_set_marks(hdr *hhdr)
470 {
471     int result = 0;
472     int i;
473     size_t sz = hhdr -> hb_sz;
474     int offset = (int)MARK_BIT_OFFSET(sz);
475     int limit = (int)FINAL_MARK_BIT(sz);
476
477     for (i = 0; i < limit; i += offset) {
478         result += hhdr -> hb_marks[i];
479     }
480     GC_ASSERT(hhdr -> hb_marks[limit]);
481     return(result);
482 }
483
484 #else
485
486 /* Number of set bits in a word.  Not performance critical.     */
487 static int set_bits(word n)
488 {
489     word m = n;
490     int result = 0;
491
492     while (m > 0) {
493         if (m & 1) result++;
494         m >>= 1;
495     }
496     return(result);
497 }
498
499 int GC_n_set_marks(hdr *hhdr)
500 {
501     int result = 0;
502     int i;
503     int n_mark_words;
504 #   ifdef MARK_BIT_PER_OBJ
505       int n_objs = (int)HBLK_OBJS(hhdr -> hb_sz);
506
507       if (0 == n_objs) n_objs = 1;
508       n_mark_words = divWORDSZ(n_objs + WORDSZ - 1);
509 #   else /* MARK_BIT_PER_GRANULE */
510       n_mark_words = MARK_BITS_SZ;
511 #   endif
512     for (i = 0; i < n_mark_words - 1; i++) {
513         result += set_bits(hhdr -> hb_marks[i]);
514     }
515 #   ifdef MARK_BIT_PER_OBJ
516       result += set_bits((hhdr -> hb_marks[n_mark_words - 1])
517                          << (n_mark_words * WORDSZ - n_objs));
518 #   else
519       result += set_bits(hhdr -> hb_marks[n_mark_words - 1]);
520 #   endif
521     return(result - 1);
522 }
523
524 #endif /* !USE_MARK_BYTES  */
525
526 STATIC void GC_print_block_descr(struct hblk *h,
527                                  word /* struct PrintStats */ raw_ps)
528 {
529     hdr * hhdr = HDR(h);
530     size_t bytes = hhdr -> hb_sz;
531     struct Print_stats *ps;
532     unsigned n_marks = GC_n_set_marks(hhdr);
533
534     if (hhdr -> hb_n_marks != n_marks) {
535       GC_printf("(%u:%u,%u!=%u)\n", hhdr->hb_obj_kind, (unsigned)bytes,
536                 (unsigned)hhdr->hb_n_marks, n_marks);
537     } else {
538       GC_printf("(%u:%u,%u)\n", hhdr->hb_obj_kind,
539                 (unsigned)bytes, n_marks);
540     }
541     bytes += HBLKSIZE-1;
542     bytes &= ~(HBLKSIZE-1);
543
544     ps = (struct Print_stats *)raw_ps;
545     ps->total_bytes += bytes;
546     ps->number_of_blocks++;
547 }
548
549 void GC_print_block_list(void)
550 {
551     struct Print_stats pstats;
552
553     GC_printf("(kind(0=ptrfree,1=normal,2=unc.):size_in_bytes, #_marks_set)\n");
554     pstats.number_of_blocks = 0;
555     pstats.total_bytes = 0;
556     GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
557     GC_printf("blocks= %lu, bytes= %lu\n",
558               (unsigned long)pstats.number_of_blocks,
559               (unsigned long)pstats.total_bytes);
560 }
561
562 /* Currently for debugger use only: */
563 void GC_print_free_list(int kind, size_t sz_in_granules)
564 {
565     struct obj_kind * ok = &GC_obj_kinds[kind];
566     ptr_t flh = ok -> ok_freelist[sz_in_granules];
567     int n;
568
569     for (n = 0; flh; n++) {
570         struct hblk *block = HBLKPTR(flh);
571         GC_printf("Free object in heap block %p [%d]: %p\n",
572                   (void *)block, n, flh);
573         flh = obj_link(flh);
574     }
575 }
576
577 #endif /* !NO_DEBUGGING */
578
579 /*
580  * Clear all obj_link pointers in the list of free objects *flp.
581  * Clear *flp.
582  * This must be done before dropping a list of free gcj-style objects,
583  * since may otherwise end up with dangling "descriptor" pointers.
584  * It may help for other pointer-containing objects.
585  */
586 STATIC void GC_clear_fl_links(void **flp)
587 {
588     void *next = *flp;
589
590     while (0 != next) {
591        *flp = 0;
592        flp = &(obj_link(next));
593        next = *flp;
594     }
595 }
596
597 /*
598  * Perform GC_reclaim_block on the entire heap, after first clearing
599  * small object free lists (if we are not just looking for leaks).
600  */
601 GC_INNER void GC_start_reclaim(GC_bool report_if_found)
602 {
603     unsigned kind;
604
605 #   if defined(PARALLEL_MARK)
606       GC_ASSERT(0 == GC_fl_builder_count);
607 #   endif
608     /* Reset in use counters.  GC_reclaim_block recomputes them. */
609       GC_composite_in_use = 0;
610       GC_atomic_in_use = 0;
611     /* Clear reclaim- and free-lists */
612       for (kind = 0; kind < GC_n_kinds; kind++) {
613         void **fop;
614         void **lim;
615         struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
616         GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
617
618         if (rlist == 0) continue;       /* This kind not used.  */
619         if (!report_if_found) {
620             lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJGRANULES+1]);
621             for (fop = GC_obj_kinds[kind].ok_freelist;
622                  (word)fop < (word)lim; fop++) {
623               if (*fop != 0) {
624                 if (should_clobber) {
625                   GC_clear_fl_links(fop);
626                 } else {
627                   *fop = 0;
628                 }
629               }
630             }
631         } /* otherwise free list objects are marked,    */
632           /* and its safe to leave them                 */
633         BZERO(rlist, (MAXOBJGRANULES + 1) * sizeof(void *));
634       }
635
636
637   /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
638   /* or enqueue the block for later processing.                            */
639     GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);
640
641 # ifdef EAGER_SWEEP
642     /* This is a very stupid thing to do.  We make it possible anyway,  */
643     /* so that you can convince yourself that it really is very stupid. */
644     GC_reclaim_all((GC_stop_func)0, FALSE);
645 # elif defined(ENABLE_DISCLAIM)
646     /* However, make sure to clear reclaimable objects of kinds with    */
647     /* unconditional marking enabled before we do any significant       */
648     /* marking work.                                                    */
649     GC_reclaim_unconditionally_marked();
650 # endif
651 # if defined(PARALLEL_MARK)
652     GC_ASSERT(0 == GC_fl_builder_count);
653 # endif
654
655 }
656
657 /*
658  * Sweep blocks of the indicated object size and kind until either the
659  * appropriate free list is nonempty, or there are no more blocks to
660  * sweep.
661  */
662 GC_INNER void GC_continue_reclaim(size_t sz /* granules */, int kind)
663 {
664     hdr * hhdr;
665     struct hblk * hbp;
666     struct obj_kind * ok = &(GC_obj_kinds[kind]);
667     struct hblk ** rlh = ok -> ok_reclaim_list;
668     void **flh = &(ok -> ok_freelist[sz]);
669
670     if (rlh == 0) return;       /* No blocks of this kind.      */
671     rlh += sz;
672     while ((hbp = *rlh) != 0) {
673         hhdr = HDR(hbp);
674         *rlh = hhdr -> hb_next;
675         GC_reclaim_small_nonempty_block(hbp, FALSE);
676         if (*flh != 0) break;
677     }
678 }
679
680 /*
681  * Reclaim all small blocks waiting to be reclaimed.
682  * Abort and return FALSE when/if (*stop_func)() returns TRUE.
683  * If this returns TRUE, then it's safe to restart the world
684  * with incorrectly cleared mark bits.
685  * If ignore_old is TRUE, then reclaim only blocks that have been
686  * recently reclaimed, and discard the rest.
687  * Stop_func may be 0.
688  */
689 GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
690 {
691     word sz;
692     unsigned kind;
693     hdr * hhdr;
694     struct hblk * hbp;
695     struct obj_kind * ok;
696     struct hblk ** rlp;
697     struct hblk ** rlh;
698 #   ifndef SMALL_CONFIG
699       CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
700       CLOCK_TYPE done_time;
701
702       if (GC_print_stats == VERBOSE)
703         GET_TIME(start_time);
704 #   endif
705
706     for (kind = 0; kind < GC_n_kinds; kind++) {
707         ok = &(GC_obj_kinds[kind]);
708         rlp = ok -> ok_reclaim_list;
709         if (rlp == 0) continue;
710         for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
711             rlh = rlp + sz;
712             while ((hbp = *rlh) != 0) {
713                 if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
714                     return(FALSE);
715                 }
716                 hhdr = HDR(hbp);
717                 *rlh = hhdr -> hb_next;
718                 if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
719                     /* It's likely we'll need it this time, too */
720                     /* It's been touched recently, so this      */
721                     /* shouldn't trigger paging.                */
722                     GC_reclaim_small_nonempty_block(hbp, FALSE);
723                 }
724             }
725         }
726     }
727 #   ifndef SMALL_CONFIG
728       if (GC_print_stats == VERBOSE) {
729         GET_TIME(done_time);
730         GC_verbose_log_printf("Disposing of reclaim lists took %lu msecs\n",
731                               MS_TIME_DIFF(done_time,start_time));
732       }
733 #   endif
734     return(TRUE);
735 }
736
737 #if !defined(EAGER_SWEEP) && defined(ENABLE_DISCLAIM)
738 /* We do an eager sweep on heap blocks where unconditional marking has  */
739 /* been enabled, so that any reclaimable objects have been reclaimed    */
740 /* before we start marking.  This is a simplified GC_reclaim_all        */
741 /* restricted to kinds where ok_mark_unconditionally is true.           */
742   STATIC void GC_reclaim_unconditionally_marked(void)
743   {
744     word sz;
745     unsigned kind;
746     hdr * hhdr;
747     struct hblk * hbp;
748     struct obj_kind * ok;
749     struct hblk ** rlp;
750     struct hblk ** rlh;
751
752     for (kind = 0; kind < GC_n_kinds; kind++) {
753         ok = &(GC_obj_kinds[kind]);
754         if (!ok->ok_mark_unconditionally)
755           continue;
756         rlp = ok->ok_reclaim_list;
757         if (rlp == 0)
758           continue;
759         for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
760             rlh = rlp + sz;
761             while ((hbp = *rlh) != 0) {
762                 hhdr = HDR(hbp);
763                 *rlh = hhdr->hb_next;
764                 GC_reclaim_small_nonempty_block(hbp, FALSE);
765             }
766         }
767     }
768   }
769 #endif /* !EAGER_SWEEP && ENABLE_DISCLAIM */