Upgrade Boehm GC to 7.2alpha4.
[cacao.git] / src / mm / boehm-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 #include <stdio.h>
20
21 GC_INNER signed_word GC_bytes_found = 0;
22                         /* Number of bytes of memory reclaimed     */
23                         /* minus the number of bytes originally    */
24                         /* on free lists which we had to drop.     */
25
26 #if defined(PARALLEL_MARK)
27   GC_INNER word GC_fl_builder_count = 0;
28         /* Number of threads currently building free lists without      */
29         /* holding GC lock.  It is not safe to collect if this is       */
30         /* nonzero.                                                     */
31 #endif /* PARALLEL_MARK */
32
33 /* We defer printing of leaked objects until we're done with the GC     */
34 /* cycle, since the routine for printing objects needs to run outside   */
35 /* the collector, e.g. without the allocation lock.                     */
36 #define MAX_LEAKED 40
37 STATIC ptr_t GC_leaked[MAX_LEAKED] = { NULL };
38 STATIC unsigned GC_n_leaked = 0;
39
40 GC_INNER GC_bool GC_have_errors = FALSE;
41
42 STATIC void GC_add_leaked(ptr_t leaked)
43 {
44     if (GC_n_leaked < MAX_LEAKED) {
45       GC_have_errors = TRUE;
46       GC_leaked[GC_n_leaked++] = leaked;
47       /* Make sure it's not reclaimed this cycle */
48         GC_set_mark_bit(leaked);
49     }
50 }
51
52 /* Print all objects on the list after printing any smashed objects.    */
53 /* Clear both lists.                                                    */
54 GC_INNER void GC_print_all_errors(void)
55 {
56     static GC_bool printing_errors = FALSE;
57     unsigned i;
58
59     LOCK();
60     if (printing_errors) {
61         UNLOCK();
62         return;
63     }
64     printing_errors = TRUE;
65     UNLOCK();
66     if (GC_debugging_started) GC_print_all_smashed();
67     for (i = 0; i < GC_n_leaked; ++i) {
68         ptr_t p = GC_leaked[i];
69         if (HDR(p) -> hb_obj_kind == PTRFREE) {
70             GC_err_printf("Leaked atomic object at ");
71         } else {
72             GC_err_printf("Leaked composite object at ");
73         }
74         GC_print_heap_obj(p);
75         GC_err_printf("\n");
76         GC_free(p);
77         GC_leaked[i] = 0;
78     }
79     GC_n_leaked = 0;
80     printing_errors = FALSE;
81 }
82
83
84 /*
85  * reclaim phase
86  *
87  */
88
89 /* Test whether a block is completely empty, i.e. contains no marked    */
90 /* objects.  This does not require the block to be in physical memory.  */
91 GC_INNER GC_bool GC_block_empty(hdr *hhdr)
92 {
93     return (hhdr -> hb_n_marks == 0);
94 }
95
96 STATIC GC_bool GC_block_nearly_full(hdr *hhdr)
97 {
98     return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8);
99 }
100
101 /* FIXME: This should perhaps again be specialized for USE_MARK_BYTES   */
102 /* and USE_MARK_BITS cases.                                             */
103
104 /*
105  * Restore unmarked small objects in h of size sz to the object
106  * free list.  Returns the new list.
107  * Clears unmarked objects.  Sz is in bytes.
108  */
109 STATIC ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, size_t sz,
110                               ptr_t list, signed_word *count)
111 {
112     word bit_no = 0;
113     word *p, *q, *plim;
114     signed_word n_bytes_found = 0;
115
116     GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
117     GC_ASSERT(sz == hhdr -> hb_sz);
118     GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0);
119     p = (word *)(hbp->hb_body);
120     plim = (word *)(hbp->hb_body + HBLKSIZE - sz);
121
122     /* go through all words in block */
123         while (p <= plim) {
124             if( mark_bit_from_hdr(hhdr, bit_no) ) {
125                 p = (word *)((ptr_t)p + sz);
126             } else {
127                 n_bytes_found += sz;
128                 /* object is available - put on list */
129                     obj_link(p) = list;
130                     list = ((ptr_t)p);
131                 /* Clear object, advance p to next object in the process */
132                     q = (word *)((ptr_t)p + sz);
133 #                   ifdef USE_MARK_BYTES
134                       GC_ASSERT(!(sz & 1)
135                                 && !((word)p & (2 * sizeof(word) - 1)));
136                       p[1] = 0;
137                       p += 2;
138                       while (p < q) {
139                         CLEAR_DOUBLE(p);
140                         p += 2;
141                       }
142 #                   else
143                       p++; /* Skip link field */
144                       while (p < q) {
145                         *p++ = 0;
146                       }
147 #                   endif
148             }
149             bit_no += MARK_BIT_OFFSET(sz);
150         }
151     *count += n_bytes_found;
152     return(list);
153 }
154
155 /* The same thing, but don't clear objects: */
156 STATIC ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, size_t sz,
157                                ptr_t list, signed_word *count)
158 {
159     word bit_no = 0;
160     word *p, *plim;
161     signed_word n_bytes_found = 0;
162
163     GC_ASSERT(sz == hhdr -> hb_sz);
164     p = (word *)(hbp->hb_body);
165     plim = (word *)((ptr_t)hbp + HBLKSIZE - sz);
166
167     /* go through all words in block */
168         while (p <= plim) {
169             if( !mark_bit_from_hdr(hhdr, bit_no) ) {
170                 n_bytes_found += sz;
171                 /* object is available - put on list */
172                     obj_link(p) = list;
173                     list = ((ptr_t)p);
174             }
175             p = (word *)((ptr_t)p + sz);
176             bit_no += MARK_BIT_OFFSET(sz);
177         }
178     *count += n_bytes_found;
179     return(list);
180 }
181
182 /* Don't really reclaim objects, just check for unmarked ones: */
183 STATIC void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz)
184 {
185     word bit_no = 0;
186     ptr_t p, plim;
187
188     GC_ASSERT(sz == hhdr -> hb_sz);
189     p = hbp->hb_body;
190     plim = p + HBLKSIZE - sz;
191
192     /* go through all words in block */
193         while (p <= plim) {
194             if( !mark_bit_from_hdr(hhdr, bit_no) ) {
195                 GC_add_leaked(p);
196             }
197             p += sz;
198             bit_no += MARK_BIT_OFFSET(sz);
199         }
200 }
201
202
203 /*
204  * Generic procedure to rebuild a free list in hbp.
205  * Also called directly from GC_malloc_many.
206  * Sz is now in bytes.
207  */
208 GC_INNER ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
209                                   GC_bool init, ptr_t list,
210                                   signed_word *count)
211 {
212     ptr_t result;
213
214     GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr);
215     GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */);
216     if (init || GC_debugging_started) {
217       result = GC_reclaim_clear(hbp, hhdr, sz, list, count);
218     } else {
219       GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */);
220       result = GC_reclaim_uninit(hbp, hhdr, sz, list, count);
221     }
222     if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr);
223     return result;
224 }
225
226 /*
227  * Restore unmarked small objects in the block pointed to by hbp
228  * to the appropriate object free list.
229  * If entirely empty blocks are to be completely deallocated, then
230  * caller should perform that check.
231  */
232 STATIC void GC_reclaim_small_nonempty_block(struct hblk *hbp,
233                                             int report_if_found)
234 {
235     hdr *hhdr = HDR(hbp);
236     size_t sz = hhdr -> hb_sz;
237     int kind = hhdr -> hb_obj_kind;
238     struct obj_kind * ok = &GC_obj_kinds[kind];
239     void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
240
241     hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
242
243     if (report_if_found) {
244         GC_reclaim_check(hbp, hhdr, sz);
245     } else {
246         *flh = GC_reclaim_generic(hbp, hhdr, sz,
247                                   ok -> ok_init,
248                                   *flh, &GC_bytes_found);
249     }
250 }
251
252 /*
253  * Restore an unmarked large object or an entirely empty blocks of small objects
254  * to the heap block free list.
255  * Otherwise enqueue the block for later processing
256  * by GC_reclaim_small_nonempty_block.
257  * If report_if_found is TRUE, then process any block immediately, and
258  * simply report free objects; do not actually reclaim them.
259  */
260 STATIC void GC_reclaim_block(struct hblk *hbp, word report_if_found)
261 {
262     hdr * hhdr = HDR(hbp);
263     size_t sz = hhdr -> hb_sz;  /* size of objects in current block     */
264     struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
265     struct hblk ** rlh;
266
267     if( sz > MAXOBJBYTES ) {  /* 1 big object */
268         if( !mark_bit_from_hdr(hhdr, 0) ) {
269             if (report_if_found) {
270               GC_add_leaked((ptr_t)hbp);
271             } else {
272               size_t blocks = OBJ_SZ_TO_BLOCKS(sz);
273               if (blocks > 1) {
274                 GC_large_allocd_bytes -= blocks * HBLKSIZE;
275               }
276               GC_bytes_found += sz;
277               GC_freehblk(hbp);
278             }
279         } else {
280             if (hhdr -> hb_descr != 0) {
281               GC_composite_in_use += sz;
282             } else {
283               GC_atomic_in_use += sz;
284             }
285         }
286     } else {
287         GC_bool empty = GC_block_empty(hhdr);
288 #       ifdef PARALLEL_MARK
289           /* Count can be low or one too high because we sometimes      */
290           /* have to ignore decrements.  Objects can also potentially   */
291           /* be repeatedly marked by each marker.                       */
292           /* Here we assume two markers, but this is extremely          */
293           /* unlikely to fail spuriously with more.  And if it does, it */
294           /* should be looked at.                                       */
295           GC_ASSERT(hhdr -> hb_n_marks <= 2 * (HBLKSIZE/sz + 1) + 16);
296 #       else
297           GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE);
298 #       endif
299         if (hhdr -> hb_descr != 0) {
300           GC_composite_in_use += sz * hhdr -> hb_n_marks;
301         } else {
302           GC_atomic_in_use += sz * hhdr -> hb_n_marks;
303         }
304         if (report_if_found) {
305           GC_reclaim_small_nonempty_block(hbp, (int)report_if_found);
306         } else if (empty) {
307           GC_bytes_found += HBLKSIZE;
308           GC_freehblk(hbp);
309         } else if (GC_find_leak || !GC_block_nearly_full(hhdr)) {
310           /* group of smaller objects, enqueue the real work */
311           rlh = &(ok -> ok_reclaim_list[BYTES_TO_GRANULES(sz)]);
312           hhdr -> hb_next = *rlh;
313           *rlh = hbp;
314         } /* else not worth salvaging. */
315         /* We used to do the nearly_full check later, but we    */
316         /* already have the right cache context here.  Also     */
317         /* doing it here avoids some silly lock contention in   */
318         /* GC_malloc_many.                                      */
319     }
320 }
321
322 #if !defined(NO_DEBUGGING)
323 /* Routines to gather and print heap block info         */
324 /* intended for debugging.  Otherwise should be called  */
325 /* with lock.                                           */
326
327 struct Print_stats
328 {
329         size_t number_of_blocks;
330         size_t total_bytes;
331 };
332
333 #ifdef USE_MARK_BYTES
334
335 /* Return the number of set mark bits in the given header       */
336 STATIC int GC_n_set_marks(hdr *hhdr)
337 {
338     int result = 0;
339     int i;
340     size_t sz = hhdr -> hb_sz;
341     int offset = (int)MARK_BIT_OFFSET(sz);
342     int limit = (int)FINAL_MARK_BIT(sz);
343
344     for (i = 0; i < limit; i += offset) {
345         result += hhdr -> hb_marks[i];
346     }
347     GC_ASSERT(hhdr -> hb_marks[limit]);
348     return(result);
349 }
350
351 #else
352
353 /* Number of set bits in a word.  Not performance critical.     */
354 static int set_bits(word n)
355 {
356     word m = n;
357     int result = 0;
358
359     while (m > 0) {
360         if (m & 1) result++;
361         m >>= 1;
362     }
363     return(result);
364 }
365
366 /* Return the number of set mark bits in the given header       */
367 STATIC int GC_n_set_marks(hdr *hhdr)
368 {
369     int result = 0;
370     int i;
371     int n_mark_words;
372 #   ifdef MARK_BIT_PER_OBJ
373       int n_objs = (int)HBLK_OBJS(hhdr -> hb_sz);
374
375       if (0 == n_objs) n_objs = 1;
376       n_mark_words = divWORDSZ(n_objs + WORDSZ - 1);
377 #   else /* MARK_BIT_PER_GRANULE */
378       n_mark_words = MARK_BITS_SZ;
379 #   endif
380     for (i = 0; i < n_mark_words - 1; i++) {
381         result += set_bits(hhdr -> hb_marks[i]);
382     }
383 #   ifdef MARK_BIT_PER_OBJ
384       result += set_bits((hhdr -> hb_marks[n_mark_words - 1])
385                          << (n_mark_words * WORDSZ - n_objs));
386 #   else
387       result += set_bits(hhdr -> hb_marks[n_mark_words - 1]);
388 #   endif
389     return(result - 1);
390 }
391
392 #endif /* !USE_MARK_BYTES  */
393
394 STATIC void GC_print_block_descr(struct hblk *h,
395                                  word /* struct PrintStats */ raw_ps)
396 {
397     hdr * hhdr = HDR(h);
398     size_t bytes = hhdr -> hb_sz;
399     struct Print_stats *ps;
400     unsigned n_marks = GC_n_set_marks(hhdr);
401
402     if (hhdr -> hb_n_marks != n_marks) {
403       GC_printf("(%u:%u,%u!=%u)", hhdr -> hb_obj_kind, (unsigned)bytes,
404                                   (unsigned)hhdr -> hb_n_marks, n_marks);
405     } else {
406       GC_printf("(%u:%u,%u)", hhdr -> hb_obj_kind,
407                               (unsigned)bytes, n_marks);
408     }
409     bytes += HBLKSIZE-1;
410     bytes &= ~(HBLKSIZE-1);
411
412     ps = (struct Print_stats *)raw_ps;
413     ps->total_bytes += bytes;
414     ps->number_of_blocks++;
415 }
416
417 void GC_print_block_list(void)
418 {
419     struct Print_stats pstats;
420
421     GC_printf("(kind(0=ptrfree,1=normal,2=unc.):size_in_bytes, #_marks_set)\n");
422     pstats.number_of_blocks = 0;
423     pstats.total_bytes = 0;
424     GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
425     GC_printf("\nblocks = %lu, bytes = %lu\n",
426               (unsigned long)pstats.number_of_blocks,
427               (unsigned long)pstats.total_bytes);
428 }
429
430 /* Currently for debugger use only: */
431 void GC_print_free_list(int kind, size_t sz_in_granules)
432 {
433     struct obj_kind * ok = &GC_obj_kinds[kind];
434     ptr_t flh = ok -> ok_freelist[sz_in_granules];
435     struct hblk *lastBlock = 0;
436     int n = 0;
437
438     while (flh) {
439         struct hblk *block = HBLKPTR(flh);
440         if (block != lastBlock) {
441             GC_printf("\nIn heap block at %p:\n\t", block);
442             lastBlock = block;
443         }
444         GC_printf("%d: %p;", ++n, flh);
445         flh = obj_link(flh);
446     }
447 }
448
449 #endif /* !NO_DEBUGGING */
450
451 /*
452  * Clear all obj_link pointers in the list of free objects *flp.
453  * Clear *flp.
454  * This must be done before dropping a list of free gcj-style objects,
455  * since may otherwise end up with dangling "descriptor" pointers.
456  * It may help for other pointer-containing objects.
457  */
458 STATIC void GC_clear_fl_links(void **flp)
459 {
460     void *next = *flp;
461
462     while (0 != next) {
463        *flp = 0;
464        flp = &(obj_link(next));
465        next = *flp;
466     }
467 }
468
469 /*
470  * Perform GC_reclaim_block on the entire heap, after first clearing
471  * small object free lists (if we are not just looking for leaks).
472  */
473 GC_INNER void GC_start_reclaim(GC_bool report_if_found)
474 {
475     unsigned kind;
476
477 #   if defined(PARALLEL_MARK)
478       GC_ASSERT(0 == GC_fl_builder_count);
479 #   endif
480     /* Reset in use counters.  GC_reclaim_block recomputes them. */
481       GC_composite_in_use = 0;
482       GC_atomic_in_use = 0;
483     /* Clear reclaim- and free-lists */
484       for (kind = 0; kind < GC_n_kinds; kind++) {
485         void **fop;
486         void **lim;
487         struct hblk ** rlp;
488         struct hblk ** rlim;
489         struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
490         GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
491
492         if (rlist == 0) continue;       /* This kind not used.  */
493         if (!report_if_found) {
494             lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJGRANULES+1]);
495             for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
496               if (*fop != 0) {
497                 if (should_clobber) {
498                   GC_clear_fl_links(fop);
499                 } else {
500                   *fop = 0;
501                 }
502               }
503             }
504         } /* otherwise free list objects are marked,    */
505           /* and its safe to leave them                 */
506         rlim = rlist + MAXOBJGRANULES+1;
507         for( rlp = rlist; rlp < rlim; rlp++ ) {
508             *rlp = 0;
509         }
510       }
511
512
513   /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
514   /* or enqueue the block for later processing.                            */
515     GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);
516
517 # ifdef EAGER_SWEEP
518     /* This is a very stupid thing to do.  We make it possible anyway,  */
519     /* so that you can convince yourself that it really is very stupid. */
520     GC_reclaim_all((GC_stop_func)0, FALSE);
521 # endif
522 # if defined(PARALLEL_MARK)
523     GC_ASSERT(0 == GC_fl_builder_count);
524 # endif
525
526 }
527
528 /*
529  * Sweep blocks of the indicated object size and kind until either the
530  * appropriate free list is nonempty, or there are no more blocks to
531  * sweep.
532  */
533 GC_INNER void GC_continue_reclaim(size_t sz /* granules */, int kind)
534 {
535     hdr * hhdr;
536     struct hblk * hbp;
537     struct obj_kind * ok = &(GC_obj_kinds[kind]);
538     struct hblk ** rlh = ok -> ok_reclaim_list;
539     void **flh = &(ok -> ok_freelist[sz]);
540
541     if (rlh == 0) return;       /* No blocks of this kind.      */
542     rlh += sz;
543     while ((hbp = *rlh) != 0) {
544         hhdr = HDR(hbp);
545         *rlh = hhdr -> hb_next;
546         GC_reclaim_small_nonempty_block(hbp, FALSE);
547         if (*flh != 0) break;
548     }
549 }
550
551 /*
552  * Reclaim all small blocks waiting to be reclaimed.
553  * Abort and return FALSE when/if (*stop_func)() returns TRUE.
554  * If this returns TRUE, then it's safe to restart the world
555  * with incorrectly cleared mark bits.
556  * If ignore_old is TRUE, then reclaim only blocks that have been
557  * recently reclaimed, and discard the rest.
558  * Stop_func may be 0.
559  */
560 GC_INNER GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
561 {
562     word sz;
563     unsigned kind;
564     hdr * hhdr;
565     struct hblk * hbp;
566     struct obj_kind * ok;
567     struct hblk ** rlp;
568     struct hblk ** rlh;
569 #   ifndef SMALL_CONFIG
570       CLOCK_TYPE start_time = 0; /* initialized to prevent warning. */
571       CLOCK_TYPE done_time;
572
573       if (GC_print_stats == VERBOSE)
574         GET_TIME(start_time);
575 #   endif
576
577     for (kind = 0; kind < GC_n_kinds; kind++) {
578         ok = &(GC_obj_kinds[kind]);
579         rlp = ok -> ok_reclaim_list;
580         if (rlp == 0) continue;
581         for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
582             rlh = rlp + sz;
583             while ((hbp = *rlh) != 0) {
584                 if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
585                     return(FALSE);
586                 }
587                 hhdr = HDR(hbp);
588                 *rlh = hhdr -> hb_next;
589                 if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
590                     /* It's likely we'll need it this time, too */
591                     /* It's been touched recently, so this      */
592                     /* shouldn't trigger paging.                */
593                     GC_reclaim_small_nonempty_block(hbp, FALSE);
594                 }
595             }
596         }
597     }
598 #   ifndef SMALL_CONFIG
599       if (GC_print_stats == VERBOSE) {
600         GET_TIME(done_time);
601         GC_log_printf("Disposing of reclaim lists took %lu msecs\n",
602                   MS_TIME_DIFF(done_time,start_time));
603       }
604 #   endif
605     return(TRUE);
606 }