308594696e71490506cb35ff169eba4eabb0bd25
[fw/sdcc] / support / gc / reclaim.c
1 /* 
2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
4  *
5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7  *
8  * Permission is hereby granted to use or copy this program
9  * for any purpose,  provided the above notices are retained on all copies.
10  * Permission to modify the code and to distribute modified code is granted,
11  * provided the above notices are retained, and a notice that the code was
12  * modified is included with the above copyright notice.
13  */
14 /* Boehm, February 15, 1996 2:41 pm PST */
15
16 #include <stdio.h>
17 #include "gc_priv.h"
18
19 signed_word GC_mem_found = 0;
20                         /* Number of words of memory reclaimed     */
21
22 static void report_leak(p, sz)
23 ptr_t p;
24 word sz;
25 {
26     if (HDR(p) -> hb_obj_kind == PTRFREE) {
27         GC_err_printf0("Leaked atomic object at ");
28     } else {
29         GC_err_printf0("Leaked composite object at ");
30     }
31     if (GC_debugging_started && GC_has_debug_info(p)) {
32         GC_print_obj(p);
33     } else {
34         GC_err_printf2("0x%lx (appr. size = %ld)\n",
35                       (unsigned long)p,
36                       (unsigned long)WORDS_TO_BYTES(sz));
37     }
38 }
39
40 #   define FOUND_FREE(hblk, word_no) \
41       { \
42          report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \
43                      HDR(hblk) -> hb_sz); \
44       }
45
46 /*
47  * reclaim phase
48  *
49  */
50
51
52 /*
53  * Test whether a block is completely empty, i.e. contains no marked
54  * objects.  This does not require the block to be in physical
55  * memory.
56  */
57  
58 GC_bool GC_block_empty(hhdr)
59 register hdr * hhdr;
60 {
61     register word *p = (word *)(&(hhdr -> hb_marks[0]));
62     register word * plim =
63                         (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
64     while (p < plim) {
65         if (*p++) return(FALSE);
66     }
67     return(TRUE);
68 }
69
70 # ifdef GATHERSTATS
71 #   define INCR_WORDS(sz) n_words_found += (sz)
72 # else
73 #   define INCR_WORDS(sz)
74 # endif
75 /*
76  * Restore unmarked small objects in h of size sz to the object
77  * free list.  Returns the new list.
78  * Clears unmarked objects.
79  */
80 /*ARGSUSED*/
81 ptr_t GC_reclaim_clear(hbp, hhdr, sz, list)
82 register struct hblk *hbp;      /* ptr to current heap block            */
83 register hdr * hhdr;
84 register ptr_t list;
85 register word sz;
86 {
87     register int word_no;
88     register word *p, *q, *plim;
89 #   ifdef GATHERSTATS
90         register int n_words_found = 0;
91 #   endif        
92     
93     p = (word *)(hbp->hb_body);
94     word_no = HDR_WORDS;
95     plim = (word *)((((word)hbp) + HBLKSIZE)
96                    - WORDS_TO_BYTES(sz));
97
98     /* go through all words in block */
99         while( p <= plim )  {
100             if( mark_bit_from_hdr(hhdr, word_no) ) {
101                 p += sz;
102             } else {
103                 INCR_WORDS(sz);
104                 /* object is available - put on list */
105                     obj_link(p) = list;
106                     list = ((ptr_t)p);
107                 /* Clear object, advance p to next object in the process */
108                     q = p + sz;
109                     p++; /* Skip link field */
110                     while (p < q) {
111                         *p++ = 0;
112                     }
113             }
114             word_no += sz;
115         }
116 #   ifdef GATHERSTATS
117         GC_mem_found += n_words_found;
118 #   endif
119     return(list);
120 }
121
122 #ifndef SMALL_CONFIG
123
124 /*
125  * A special case for 2 word composite objects (e.g. cons cells):
126  */
127 /*ARGSUSED*/
128 ptr_t GC_reclaim_clear2(hbp, hhdr, list)
129 register struct hblk *hbp;      /* ptr to current heap block            */
130 hdr * hhdr;
131 register ptr_t list;
132 {
133     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
134     register word *p, *plim;
135 #   ifdef GATHERSTATS
136         register int n_words_found = 0;
137 #   endif
138     register word mark_word;
139     register int i;
140 #   define DO_OBJ(start_displ) \
141         if (!(mark_word & ((word)1 << start_displ))) { \
142             p[start_displ] = (word)list; \
143             list = (ptr_t)(p+start_displ); \
144             p[start_displ+1] = 0; \
145             INCR_WORDS(2); \
146         }
147     
148     p = (word *)(hbp->hb_body);
149     plim = (word *)(((word)hbp) + HBLKSIZE);
150
151     /* go through all words in block */
152         while( p < plim )  {
153             mark_word = *mark_word_addr++;
154             for (i = 0; i < WORDSZ; i += 8) {
155                 DO_OBJ(0);
156                 DO_OBJ(2);
157                 DO_OBJ(4);
158                 DO_OBJ(6);
159                 p += 8;
160                 mark_word >>= 8;
161             }
162         }               
163 #   ifdef GATHERSTATS
164         GC_mem_found += n_words_found;
165 #   endif
166     return(list);
167 #   undef DO_OBJ
168 }
169
170 /*
171  * Another special case for 4 word composite objects:
172  */
173 /*ARGSUSED*/
174 ptr_t GC_reclaim_clear4(hbp, hhdr, list)
175 register struct hblk *hbp;      /* ptr to current heap block            */
176 hdr * hhdr;
177 register ptr_t list;
178 {
179     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
180     register word *p, *plim;
181 #   ifdef GATHERSTATS
182         register int n_words_found = 0;
183 #   endif
184     register word mark_word;
185 #   define DO_OBJ(start_displ) \
186         if (!(mark_word & ((word)1 << start_displ))) { \
187             p[start_displ] = (word)list; \
188             list = (ptr_t)(p+start_displ); \
189             p[start_displ+1] = 0; \
190             p[start_displ+2] = 0; \
191             p[start_displ+3] = 0; \
192             INCR_WORDS(4); \
193         }
194     
195     p = (word *)(hbp->hb_body);
196     plim = (word *)(((word)hbp) + HBLKSIZE);
197
198     /* go through all words in block */
199         while( p < plim )  {
200             mark_word = *mark_word_addr++;
201             DO_OBJ(0);
202             DO_OBJ(4);
203             DO_OBJ(8);
204             DO_OBJ(12);
205             DO_OBJ(16);
206             DO_OBJ(20);
207             DO_OBJ(24);
208             DO_OBJ(28);
209 #           if CPP_WORDSZ == 64
210               DO_OBJ(32);
211               DO_OBJ(36);
212               DO_OBJ(40);
213               DO_OBJ(44);
214               DO_OBJ(48);
215               DO_OBJ(52);
216               DO_OBJ(56);
217               DO_OBJ(60);
218 #           endif
219             p += WORDSZ;
220         }               
221 #   ifdef GATHERSTATS
222         GC_mem_found += n_words_found;
223 #   endif
224     return(list);
225 #   undef DO_OBJ
226 }
227
228 #endif /* !SMALL_CONFIG */
229
230 /* The same thing, but don't clear objects: */
231 /*ARGSUSED*/
232 ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list)
233 register struct hblk *hbp;      /* ptr to current heap block            */
234 register hdr * hhdr;
235 register ptr_t list;
236 register word sz;
237 {
238     register int word_no;
239     register word *p, *plim;
240 #   ifdef GATHERSTATS
241         register int n_words_found = 0;
242 #   endif
243     
244     p = (word *)(hbp->hb_body);
245     word_no = HDR_WORDS;
246     plim = (word *)((((word)hbp) + HBLKSIZE)
247                    - WORDS_TO_BYTES(sz));
248
249     /* go through all words in block */
250         while( p <= plim )  {
251             if( !mark_bit_from_hdr(hhdr, word_no) ) {
252                 INCR_WORDS(sz);
253                 /* object is available - put on list */
254                     obj_link(p) = list;
255                     list = ((ptr_t)p);
256             }
257             p += sz;
258             word_no += sz;
259         }
260 #   ifdef GATHERSTATS
261         GC_mem_found += n_words_found;
262 #   endif
263     return(list);
264 }
265
266 /* Don't really reclaim objects, just check for unmarked ones: */
267 /*ARGSUSED*/
268 void GC_reclaim_check(hbp, hhdr, sz)
269 register struct hblk *hbp;      /* ptr to current heap block            */
270 register hdr * hhdr;
271 register word sz;
272 {
273     register int word_no;
274     register word *p, *plim;
275 #   ifdef GATHERSTATS
276         register int n_words_found = 0;
277 #   endif
278     
279     p = (word *)(hbp->hb_body);
280     word_no = HDR_WORDS;
281     plim = (word *)((((word)hbp) + HBLKSIZE)
282                    - WORDS_TO_BYTES(sz));
283
284     /* go through all words in block */
285         while( p <= plim )  {
286             if( !mark_bit_from_hdr(hhdr, word_no) ) {
287                 FOUND_FREE(hbp, word_no);
288             }
289             p += sz;
290             word_no += sz;
291         }
292 }
293
294 #ifndef SMALL_CONFIG
295 /*
296  * Another special case for 2 word atomic objects:
297  */
298 /*ARGSUSED*/
299 ptr_t GC_reclaim_uninit2(hbp, hhdr, list)
300 register struct hblk *hbp;      /* ptr to current heap block            */
301 hdr * hhdr;
302 register ptr_t list;
303 {
304     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
305     register word *p, *plim;
306 #   ifdef GATHERSTATS
307         register int n_words_found = 0;
308 #   endif
309     register word mark_word;
310     register int i;
311 #   define DO_OBJ(start_displ) \
312         if (!(mark_word & ((word)1 << start_displ))) { \
313             p[start_displ] = (word)list; \
314             list = (ptr_t)(p+start_displ); \
315             INCR_WORDS(2); \
316         }
317     
318     p = (word *)(hbp->hb_body);
319     plim = (word *)(((word)hbp) + HBLKSIZE);
320
321     /* go through all words in block */
322         while( p < plim )  {
323             mark_word = *mark_word_addr++;
324             for (i = 0; i < WORDSZ; i += 8) {
325                 DO_OBJ(0);
326                 DO_OBJ(2);
327                 DO_OBJ(4);
328                 DO_OBJ(6);
329                 p += 8;
330                 mark_word >>= 8;
331             }
332         }               
333 #   ifdef GATHERSTATS
334         GC_mem_found += n_words_found;
335 #   endif
336     return(list);
337 #   undef DO_OBJ
338 }
339
340 /*
341  * Another special case for 4 word atomic objects:
342  */
343 /*ARGSUSED*/
344 ptr_t GC_reclaim_uninit4(hbp, hhdr, list)
345 register struct hblk *hbp;      /* ptr to current heap block            */
346 hdr * hhdr;
347 register ptr_t list;
348 {
349     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
350     register word *p, *plim;
351 #   ifdef GATHERSTATS
352         register int n_words_found = 0;
353 #   endif
354     register word mark_word;
355 #   define DO_OBJ(start_displ) \
356         if (!(mark_word & ((word)1 << start_displ))) { \
357             p[start_displ] = (word)list; \
358             list = (ptr_t)(p+start_displ); \
359             INCR_WORDS(4); \
360         }
361     
362     p = (word *)(hbp->hb_body);
363     plim = (word *)(((word)hbp) + HBLKSIZE);
364
365     /* go through all words in block */
366         while( p < plim )  {
367             mark_word = *mark_word_addr++;
368             DO_OBJ(0);
369             DO_OBJ(4);
370             DO_OBJ(8);
371             DO_OBJ(12);
372             DO_OBJ(16);
373             DO_OBJ(20);
374             DO_OBJ(24);
375             DO_OBJ(28);
376 #           if CPP_WORDSZ == 64
377               DO_OBJ(32);
378               DO_OBJ(36);
379               DO_OBJ(40);
380               DO_OBJ(44);
381               DO_OBJ(48);
382               DO_OBJ(52);
383               DO_OBJ(56);
384               DO_OBJ(60);
385 #           endif
386             p += WORDSZ;
387         }               
388 #   ifdef GATHERSTATS
389         GC_mem_found += n_words_found;
390 #   endif
391     return(list);
392 #   undef DO_OBJ
393 }
394
395 /* Finally the one word case, which never requires any clearing: */
396 /*ARGSUSED*/
397 ptr_t GC_reclaim1(hbp, hhdr, list)
398 register struct hblk *hbp;      /* ptr to current heap block            */
399 hdr * hhdr;
400 register ptr_t list;
401 {
402     register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]);
403     register word *p, *plim;
404 #   ifdef GATHERSTATS
405         register int n_words_found = 0;
406 #   endif
407     register word mark_word;
408     register int i;
409 #   define DO_OBJ(start_displ) \
410         if (!(mark_word & ((word)1 << start_displ))) { \
411             p[start_displ] = (word)list; \
412             list = (ptr_t)(p+start_displ); \
413             INCR_WORDS(1); \
414         }
415     
416     p = (word *)(hbp->hb_body);
417     plim = (word *)(((word)hbp) + HBLKSIZE);
418
419     /* go through all words in block */
420         while( p < plim )  {
421             mark_word = *mark_word_addr++;
422             for (i = 0; i < WORDSZ; i += 4) {
423                 DO_OBJ(0);
424                 DO_OBJ(1);
425                 DO_OBJ(2);
426                 DO_OBJ(3);
427                 p += 4;
428                 mark_word >>= 4;
429             }
430         }               
431 #   ifdef GATHERSTATS
432         GC_mem_found += n_words_found;
433 #   endif
434     return(list);
435 #   undef DO_OBJ
436 }
437
438 #endif /* !SMALL_CONFIG */
439
440 /*
441  * Restore unmarked small objects in the block pointed to by hbp
442  * to the appropriate object free list.
443  * If entirely empty blocks are to be completely deallocated, then
444  * caller should perform that check.
445  */
446 void GC_reclaim_small_nonempty_block(hbp, report_if_found)
447 register struct hblk *hbp;      /* ptr to current heap block            */
448 int report_if_found;            /* Abort if a reclaimable object is found */
449 {
450     hdr * hhdr;
451     register word sz;           /* size of objects in current block     */
452     register struct obj_kind * ok;
453     register ptr_t * flh;
454     register int kind;
455     
456     hhdr = HDR(hbp);
457     sz = hhdr -> hb_sz;
458     hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
459     kind = hhdr -> hb_obj_kind;
460     ok = &GC_obj_kinds[kind];
461     flh = &(ok -> ok_freelist[sz]);
462     GC_write_hint(hbp);
463
464     if (report_if_found) {
465         GC_reclaim_check(hbp, hhdr, sz);
466     } else if (ok -> ok_init) {
467       switch(sz) {
468 #      ifndef SMALL_CONFIG
469         case 1:
470             *flh = GC_reclaim1(hbp, hhdr, *flh);
471             break;
472         case 2:
473             *flh = GC_reclaim_clear2(hbp, hhdr, *flh);
474             break;
475         case 4:
476             *flh = GC_reclaim_clear4(hbp, hhdr, *flh);
477             break;
478 #      endif
479         default:
480             *flh = GC_reclaim_clear(hbp, hhdr, sz, *flh);
481             break;
482       }
483     } else {
484       switch(sz) {
485 #      ifndef SMALL_CONFIG
486         case 1:
487             *flh = GC_reclaim1(hbp, hhdr, *flh);
488             break;
489         case 2:
490             *flh = GC_reclaim_uninit2(hbp, hhdr, *flh);
491             break;
492         case 4:
493             *flh = GC_reclaim_uninit4(hbp, hhdr, *flh);
494             break;
495 #      endif
496         default:
497             *flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh);
498             break;
499       }
500     } 
501     if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(hhdr);
502 }
503
504 /*
505  * Restore an unmarked large object or an entirely empty blocks of small objects
506  * to the heap block free list.
507  * Otherwise enqueue the block for later processing
508  * by GC_reclaim_small_nonempty_block.
509  * If report_if_found is TRUE, then process any block immediately, and
510  * simply report free objects; do not actually reclaim them.
511  */
512 void GC_reclaim_block(hbp, report_if_found)
513 register struct hblk *hbp;      /* ptr to current heap block            */
514 word report_if_found;           /* Abort if a reclaimable object is found */
515 {
516     register hdr * hhdr;
517     register word sz;           /* size of objects in current block     */
518     register struct obj_kind * ok;
519     struct hblk ** rlh;
520
521     hhdr = HDR(hbp);
522     sz = hhdr -> hb_sz;
523     ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
524
525     if( sz > MAXOBJSZ ) {  /* 1 big object */
526         if( !mark_bit_from_hdr(hhdr, HDR_WORDS) ) {
527             if (report_if_found) {
528               FOUND_FREE(hbp, HDR_WORDS);
529             } else {
530 #             ifdef GATHERSTATS
531                 GC_mem_found += sz;
532 #             endif
533               GC_freehblk(hbp);
534             }
535         }
536     } else {
537         GC_bool empty = GC_block_empty(hhdr);
538         if (report_if_found) {
539           GC_reclaim_small_nonempty_block(hbp, (int)report_if_found);
540         } else if (empty) {
541 #         ifdef GATHERSTATS
542             GC_mem_found += BYTES_TO_WORDS(HBLKSIZE);
543 #         endif
544           GC_freehblk(hbp);
545         } else {
546           /* group of smaller objects, enqueue the real work */
547           rlh = &(ok -> ok_reclaim_list[sz]);
548           hhdr -> hb_next = *rlh;
549           *rlh = hbp;
550         }
551     }
552 }
553
554 #if !defined(NO_DEBUGGING)
555 /* Routines to gather and print heap block info         */
556 /* intended for debugging.  Otherwise should be called  */
557 /* with lock.                                           */
558 static size_t number_of_blocks;
559 static size_t total_bytes;
560
561 /* Number of set bits in a word.  Not performance critical.     */
562 static int set_bits(n)
563 word n;
564 {
565     register word m = n;
566     register int result = 0;
567     
568     while (m > 0) {
569         if (m & 1) result++;
570         m >>= 1;
571     }
572     return(result);
573 }
574
575 /* Return the number of set mark bits in the given header       */
576 int GC_n_set_marks(hhdr)
577 hdr * hhdr;
578 {
579     register int result = 0;
580     register int i;
581     
582     for (i = 0; i < MARK_BITS_SZ; i++) {
583         result += set_bits(hhdr -> hb_marks[i]);
584     }
585     return(result);
586 }
587
588 /*ARGSUSED*/
589 void GC_print_block_descr(h, dummy)
590 struct hblk *h;
591 word dummy;
592 {
593     register hdr * hhdr = HDR(h);
594     register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
595     
596     GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind),
597                                 (unsigned long)bytes,
598                                 (unsigned long)(GC_n_set_marks(hhdr)));
599     bytes += HDR_BYTES + HBLKSIZE-1;
600     bytes &= ~(HBLKSIZE-1);
601     total_bytes += bytes;
602     number_of_blocks++;
603 }
604
605 void GC_print_block_list()
606 {
607     GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n");
608     number_of_blocks = 0;
609     total_bytes = 0;
610     GC_apply_to_all_blocks(GC_print_block_descr, (word)0);
611     GC_printf2("\nblocks = %lu, bytes = %lu\n",
612                (unsigned long)number_of_blocks,
613                (unsigned long)total_bytes);
614 }
615
616 #endif /* NO_DEBUGGING */
617
618 /*
619  * Perform GC_reclaim_block on the entire heap, after first clearing
620  * small object free lists (if we are not just looking for leaks).
621  */
622 void GC_start_reclaim(report_if_found)
623 int report_if_found;            /* Abort if a GC_reclaimable object is found */
624 {
625     int kind;
626     
627     /* Clear reclaim- and free-lists */
628       for (kind = 0; kind < GC_n_kinds; kind++) {
629         register ptr_t *fop;
630         register ptr_t *lim;
631         register struct hblk ** rlp;
632         register struct hblk ** rlim;
633         register struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
634         
635         if (rlist == 0) continue;       /* This kind not used.  */
636         if (!report_if_found) {
637             lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]);
638             for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
639               *fop = 0;
640             }
641         } /* otherwise free list objects are marked,    */
642           /* and its safe to leave them                 */
643         rlim = rlist + MAXOBJSZ+1;
644         for( rlp = rlist; rlp < rlim; rlp++ ) {
645             *rlp = 0;
646         }
647       }
648     
649 #   ifdef PRINTBLOCKS
650         GC_printf0("GC_reclaim: current block sizes:\n");
651         GC_print_block_list();
652 #   endif
653
654   /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
655   /* or enqueue the block for later processing.                            */
656     GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);
657     
658 }
659
660 /*
661  * Sweep blocks of the indicated object size and kind until either the
662  * appropriate free list is nonempty, or there are no more blocks to
663  * sweep.
664  */
665 void GC_continue_reclaim(sz, kind)
666 word sz;        /* words */
667 int kind;
668 {
669     register hdr * hhdr;
670     register struct hblk * hbp;
671     register struct obj_kind * ok = &(GC_obj_kinds[kind]);
672     struct hblk ** rlh = ok -> ok_reclaim_list;
673     ptr_t *flh = &(ok -> ok_freelist[sz]);
674     
675     if (rlh == 0) return;       /* No blocks of this kind.      */
676     rlh += sz;
677     while ((hbp = *rlh) != 0) {
678         hhdr = HDR(hbp);
679         *rlh = hhdr -> hb_next;
680         GC_reclaim_small_nonempty_block(hbp, FALSE);
681         if (*flh != 0) break;
682     }
683 }
684
685 /*
686  * Reclaim all small blocks waiting to be reclaimed.
687  * Abort and return FALSE when/if (*stop_func)() returns TRUE.
688  * If this returns TRUE, then it's safe to restart the world
689  * with incorrectly cleared mark bits.
690  * If ignore_old is TRUE, then reclain only blocks that have been 
691  * recently reclaimed, and discard the rest.
692  * Stop_func may be 0.
693  */
694 GC_bool GC_reclaim_all(stop_func, ignore_old)
695 GC_stop_func stop_func;
696 GC_bool ignore_old;
697 {
698     register word sz;
699     register int kind;
700     register hdr * hhdr;
701     register struct hblk * hbp;
702     register struct obj_kind * ok;
703     struct hblk ** rlp;
704     struct hblk ** rlh;
705 #   ifdef PRINTTIMES
706         CLOCK_TYPE start_time;
707         CLOCK_TYPE done_time;
708         
709         GET_TIME(start_time);
710 #   endif
711     
712     for (kind = 0; kind < GC_n_kinds; kind++) {
713         ok = &(GC_obj_kinds[kind]);
714         rlp = ok -> ok_reclaim_list;
715         if (rlp == 0) continue;
716         for (sz = 1; sz <= MAXOBJSZ; sz++) {
717             rlh = rlp + sz;
718             while ((hbp = *rlh) != 0) {
719                 if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
720                     return(FALSE);
721                 }
722                 hhdr = HDR(hbp);
723                 *rlh = hhdr -> hb_next;
724                 if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
725                     /* It's likely we'll need it this time, too */
726                     /* It's been touched recently, so this      */
727                     /* shouldn't trigger paging.                */
728                     GC_reclaim_small_nonempty_block(hbp, FALSE);
729                 }
730             }
731         }
732     }
733 #   ifdef PRINTTIMES
734         GET_TIME(done_time);
735         GC_printf1("Disposing of reclaim lists took %lu msecs\n",
736                    MS_TIME_DIFF(done_time,start_time));
737 #   endif
738     return(TRUE);
739 }