Annotation of OpenXM_contrib2/asir2000/gc/reclaim.c, Revision 1.9
1.1 noro 1: /*
2: * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
1.2 noro 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 by Hewlett-Packard Company. All rights reserved.
1.1 noro 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 <stdio.h>
1.5 noro 18: #include "private/gc_priv.h"
1.1 noro 19:
20: signed_word GC_mem_found = 0;
21: /* Number of words of memory reclaimed */
22:
1.7 noro 23: #if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
1.5 noro 24: word GC_fl_builder_count = 0;
25: /* Number of threads currently building free lists without */
26: /* holding GC lock. It is not safe to collect if this is */
27: /* nonzero. */
28: #endif /* PARALLEL_MARK */
29:
1.9 ! noro 30: /* We defer printing of leaked objects until we're done with the GC */
! 31: /* cycle, since the routine for printing objects needs to run outside */
! 32: /* the collector, e.g. without the allocation lock. */
! 33: #define MAX_LEAKED 40
! 34: ptr_t GC_leaked[MAX_LEAKED];
! 35: unsigned GC_n_leaked = 0;
! 36:
! 37: GC_bool GC_have_errors = FALSE;
! 38:
! 39: void GC_add_leaked(leaked)
! 40: ptr_t leaked;
! 41: {
! 42: if (GC_n_leaked < MAX_LEAKED) {
! 43: GC_have_errors = TRUE;
! 44: GC_leaked[GC_n_leaked++] = leaked;
! 45: /* Make sure it's not reclaimed this cycle */
! 46: GC_set_mark_bit(leaked);
! 47: }
! 48: }
! 49:
! 50: static GC_bool printing_errors = FALSE;
! 51: /* Print all objects on the list after printing any smashed objs. */
! 52: /* Clear both lists. */
! 53: void GC_print_all_errors ()
1.1 noro 54: {
1.9 ! noro 55: unsigned i;
! 56:
! 57: LOCK();
! 58: if (printing_errors) {
! 59: UNLOCK();
! 60: return;
! 61: }
! 62: printing_errors = TRUE;
! 63: UNLOCK();
! 64: if (GC_debugging_started) GC_print_all_smashed();
! 65: for (i = 0; i < GC_n_leaked; ++i) {
! 66: ptr_t p = GC_leaked[i];
! 67: if (HDR(p) -> hb_obj_kind == PTRFREE) {
! 68: GC_err_printf0("Leaked atomic object at ");
! 69: } else {
! 70: GC_err_printf0("Leaked composite object at ");
! 71: }
! 72: GC_print_heap_obj(p);
! 73: GC_err_printf0("\n");
! 74: GC_free(p);
! 75: GC_leaked[i] = 0;
1.1 noro 76: }
1.9 ! noro 77: GC_n_leaked = 0;
! 78: printing_errors = FALSE;
1.1 noro 79: }
80:
1.9 ! noro 81:
1.1 noro 82: # define FOUND_FREE(hblk, word_no) \
1.2 noro 83: { \
1.9 ! noro 84: GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \
1.1 noro 85: }
86:
87: /*
88: * reclaim phase
89: *
90: */
91:
92:
93: /*
94: * Test whether a block is completely empty, i.e. contains no marked
95: * objects. This does not require the block to be in physical
96: * memory.
97: */
98:
99: GC_bool GC_block_empty(hhdr)
100: register hdr * hhdr;
101: {
1.5 noro 102: /* We treat hb_marks as an array of words here, even if it is */
103: /* actually an array of bytes. Since we only check for zero, there */
104: /* are no endian-ness issues. */
1.1 noro 105: register word *p = (word *)(&(hhdr -> hb_marks[0]));
106: register word * plim =
1.5 noro 107: (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
1.1 noro 108: while (p < plim) {
109: if (*p++) return(FALSE);
110: }
111: return(TRUE);
112: }
113:
1.2 noro 114: /* The following functions sometimes return a DONT_KNOW value. */
115: #define DONT_KNOW 2
116:
117: #ifdef SMALL_CONFIG
118: # define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW
119: # define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW
120: # define GC_block_nearly_full(hhdr) DONT_KNOW
1.5 noro 121: #endif
122:
123: #if !defined(SMALL_CONFIG) && defined(USE_MARK_BYTES)
124:
125: # define GC_block_nearly_full1(hhdr, pat1) GC_block_nearly_full(hhdr)
126: # define GC_block_nearly_full3(hhdr, pat1, pat2) GC_block_nearly_full(hhdr)
127:
128:
129: GC_bool GC_block_nearly_full(hhdr)
130: register hdr * hhdr;
131: {
132: /* We again treat hb_marks as an array of words, even though it */
133: /* isn't. We first sum up all the words, resulting in a word */
134: /* containing 4 or 8 separate partial sums. */
135: /* We then sum the bytes in the word of partial sums. */
136: /* This is still endian independant. This fails if the partial */
137: /* sums can overflow. */
138: # if (BYTES_TO_WORDS(MARK_BITS_SZ)) >= 256
139: --> potential overflow; fix the code
140: # endif
141: register word *p = (word *)(&(hhdr -> hb_marks[0]));
142: register word * plim =
143: (word *)(&(hhdr -> hb_marks[MARK_BITS_SZ]));
144: word sum_vector = 0;
145: unsigned sum;
146: while (p < plim) {
147: sum_vector += *p;
148: ++p;
149: }
150: sum = 0;
151: while (sum_vector > 0) {
152: sum += sum_vector & 0xff;
153: sum_vector >>= 8;
154: }
155: return (sum > BYTES_TO_WORDS(7*HBLKSIZE/8)/(hhdr -> hb_sz));
156: }
157: #endif /* USE_MARK_BYTES */
158:
159: #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.2 noro 160:
161: /*
162: * Test whether nearly all of the mark words consist of the same
163: * repeating pattern.
164: */
165: #define FULL_THRESHOLD (MARK_BITS_SZ/16)
166:
167: GC_bool GC_block_nearly_full1(hhdr, pat1)
168: hdr *hhdr;
169: word pat1;
170: {
171: unsigned i;
172: unsigned misses = 0;
173: GC_ASSERT((MARK_BITS_SZ & 1) == 0);
174: for (i = 0; i < MARK_BITS_SZ; ++i) {
175: if ((hhdr -> hb_marks[i] | ~pat1) != ONES) {
176: if (++misses > FULL_THRESHOLD) return FALSE;
177: }
178: }
179: return TRUE;
180: }
181:
182: /*
183: * Test whether the same repeating 3 word pattern occurs in nearly
184: * all the mark bit slots.
185: * This is used as a heuristic, so we're a bit sloppy and ignore
186: * the last one or two words.
187: */
188: GC_bool GC_block_nearly_full3(hhdr, pat1, pat2, pat3)
189: hdr *hhdr;
190: word pat1, pat2, pat3;
191: {
192: unsigned i;
193: unsigned misses = 0;
194:
195: if (MARK_BITS_SZ < 4) {
196: return DONT_KNOW;
197: }
198: for (i = 0; i < MARK_BITS_SZ - 2; i += 3) {
199: if ((hhdr -> hb_marks[i] | ~pat1) != ONES) {
200: if (++misses > FULL_THRESHOLD) return FALSE;
201: }
202: if ((hhdr -> hb_marks[i+1] | ~pat2) != ONES) {
203: if (++misses > FULL_THRESHOLD) return FALSE;
204: }
205: if ((hhdr -> hb_marks[i+2] | ~pat3) != ONES) {
206: if (++misses > FULL_THRESHOLD) return FALSE;
207: }
208: }
209: return TRUE;
210: }
211:
212: /* Check whether a small object block is nearly full by looking at only */
213: /* the mark bits. */
214: /* We manually precomputed the mark bit patterns that need to be */
215: /* checked for, and we give up on the ones that are unlikely to occur, */
216: /* or have period > 3. */
217: /* This would be a lot easier with a mark bit per object instead of per */
218: /* word, but that would rewuire computing object numbers in the mark */
219: /* loop, which would require different data structures ... */
220: GC_bool GC_block_nearly_full(hhdr)
221: hdr *hhdr;
222: {
223: int sz = hhdr -> hb_sz;
224:
225: # if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
226: return DONT_KNOW; /* Shouldn't be used in any standard config. */
227: # endif
228: # if CPP_WORDSZ == 32
229: switch(sz) {
230: case 1:
231: return GC_block_nearly_full1(hhdr, 0xffffffffl);
232: case 2:
233: return GC_block_nearly_full1(hhdr, 0x55555555l);
234: case 4:
235: return GC_block_nearly_full1(hhdr, 0x11111111l);
236: case 6:
237: return GC_block_nearly_full3(hhdr, 0x41041041l,
238: 0x10410410l,
239: 0x04104104l);
240: case 8:
241: return GC_block_nearly_full1(hhdr, 0x01010101l);
242: case 12:
243: return GC_block_nearly_full3(hhdr, 0x01001001l,
244: 0x10010010l,
245: 0x00100100l);
246: case 16:
247: return GC_block_nearly_full1(hhdr, 0x00010001l);
248: case 32:
249: return GC_block_nearly_full1(hhdr, 0x00000001l);
250: default:
251: return DONT_KNOW;
252: }
253: # endif
254: # if CPP_WORDSZ == 64
255: switch(sz) {
256: case 1:
257: return GC_block_nearly_full1(hhdr, 0xffffffffffffffffl);
258: case 2:
259: return GC_block_nearly_full1(hhdr, 0x5555555555555555l);
260: case 4:
261: return GC_block_nearly_full1(hhdr, 0x1111111111111111l);
262: case 6:
263: return GC_block_nearly_full3(hhdr, 0x1041041041041041l,
264: 0x4104104104104104l,
265: 0x0410410410410410l);
266: case 8:
267: return GC_block_nearly_full1(hhdr, 0x0101010101010101l);
268: case 12:
269: return GC_block_nearly_full3(hhdr, 0x1001001001001001l,
270: 0x0100100100100100l,
271: 0x0010010010010010l);
272: case 16:
273: return GC_block_nearly_full1(hhdr, 0x0001000100010001l);
274: case 32:
275: return GC_block_nearly_full1(hhdr, 0x0000000100000001l);
276: default:
277: return DONT_KNOW;
278: }
279: # endif
280: }
1.5 noro 281: #endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
1.2 noro 282:
1.5 noro 283: /* We keep track of reclaimed memory if we are either asked to, or */
284: /* we are using the parallel marker. In the latter case, we assume */
285: /* that most allocation goes through GC_malloc_many for scalability. */
286: /* GC_malloc_many needs the count anyway. */
287: # if defined(GATHERSTATS) || defined(PARALLEL_MARK)
1.1 noro 288: # define INCR_WORDS(sz) n_words_found += (sz)
1.5 noro 289: # define COUNT_PARAM , count
290: # define COUNT_ARG , count
291: # define COUNT_DECL signed_word * count;
292: # define NWORDS_DECL signed_word n_words_found = 0;
293: # define COUNT_UPDATE *count += n_words_found;
294: # define MEM_FOUND_ADDR , &GC_mem_found
1.1 noro 295: # else
296: # define INCR_WORDS(sz)
1.5 noro 297: # define COUNT_PARAM
298: # define COUNT_ARG
299: # define COUNT_DECL
300: # define NWORDS_DECL
301: # define COUNT_UPDATE
302: # define MEM_FOUND_ADDR
1.1 noro 303: # endif
304: /*
305: * Restore unmarked small objects in h of size sz to the object
306: * free list. Returns the new list.
307: * Clears unmarked objects.
308: */
309: /*ARGSUSED*/
1.5 noro 310: ptr_t GC_reclaim_clear(hbp, hhdr, sz, list COUNT_PARAM)
1.1 noro 311: register struct hblk *hbp; /* ptr to current heap block */
312: register hdr * hhdr;
313: register ptr_t list;
314: register word sz;
1.5 noro 315: COUNT_DECL
1.1 noro 316: {
317: register int word_no;
318: register word *p, *q, *plim;
1.5 noro 319: NWORDS_DECL
1.1 noro 320:
1.5 noro 321: GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
1.1 noro 322: p = (word *)(hbp->hb_body);
1.5 noro 323: word_no = 0;
1.1 noro 324: plim = (word *)((((word)hbp) + HBLKSIZE)
325: - WORDS_TO_BYTES(sz));
326:
327: /* go through all words in block */
328: while( p <= plim ) {
329: if( mark_bit_from_hdr(hhdr, word_no) ) {
330: p += sz;
331: } else {
332: INCR_WORDS(sz);
333: /* object is available - put on list */
334: obj_link(p) = list;
335: list = ((ptr_t)p);
336: /* Clear object, advance p to next object in the process */
337: q = p + sz;
1.5 noro 338: # ifdef USE_MARK_BYTES
339: GC_ASSERT(!(sz & 1)
340: && !((word)p & (2 * sizeof(word) - 1)));
341: p[1] = 0;
342: p += 2;
343: while (p < q) {
344: CLEAR_DOUBLE(p);
345: p += 2;
346: }
347: # else
348: p++; /* Skip link field */
349: while (p < q) {
1.1 noro 350: *p++ = 0;
1.5 noro 351: }
352: # endif
1.1 noro 353: }
354: word_no += sz;
355: }
1.5 noro 356: COUNT_UPDATE
1.1 noro 357: return(list);
358: }
359:
1.5 noro 360: #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1 noro 361:
362: /*
363: * A special case for 2 word composite objects (e.g. cons cells):
364: */
365: /*ARGSUSED*/
1.5 noro 366: ptr_t GC_reclaim_clear2(hbp, hhdr, list COUNT_PARAM)
1.1 noro 367: register struct hblk *hbp; /* ptr to current heap block */
368: hdr * hhdr;
369: register ptr_t list;
1.5 noro 370: COUNT_DECL
1.1 noro 371: {
1.5 noro 372: register word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 373: register word *p, *plim;
374: register word mark_word;
375: register int i;
1.5 noro 376: NWORDS_DECL
1.1 noro 377: # define DO_OBJ(start_displ) \
378: if (!(mark_word & ((word)1 << start_displ))) { \
379: p[start_displ] = (word)list; \
380: list = (ptr_t)(p+start_displ); \
381: p[start_displ+1] = 0; \
382: INCR_WORDS(2); \
383: }
384:
385: p = (word *)(hbp->hb_body);
386: plim = (word *)(((word)hbp) + HBLKSIZE);
387:
388: /* go through all words in block */
389: while( p < plim ) {
390: mark_word = *mark_word_addr++;
391: for (i = 0; i < WORDSZ; i += 8) {
392: DO_OBJ(0);
393: DO_OBJ(2);
394: DO_OBJ(4);
395: DO_OBJ(6);
396: p += 8;
397: mark_word >>= 8;
398: }
399: }
1.5 noro 400: COUNT_UPDATE
1.1 noro 401: return(list);
402: # undef DO_OBJ
403: }
404:
405: /*
406: * Another special case for 4 word composite objects:
407: */
408: /*ARGSUSED*/
1.5 noro 409: ptr_t GC_reclaim_clear4(hbp, hhdr, list COUNT_PARAM)
1.1 noro 410: register struct hblk *hbp; /* ptr to current heap block */
411: hdr * hhdr;
412: register ptr_t list;
1.5 noro 413: COUNT_DECL
1.1 noro 414: {
1.5 noro 415: register word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 416: register word *p, *plim;
417: register word mark_word;
1.5 noro 418: NWORDS_DECL
1.1 noro 419: # define DO_OBJ(start_displ) \
420: if (!(mark_word & ((word)1 << start_displ))) { \
421: p[start_displ] = (word)list; \
422: list = (ptr_t)(p+start_displ); \
423: p[start_displ+1] = 0; \
1.4 noro 424: CLEAR_DOUBLE(p + start_displ + 2); \
1.1 noro 425: INCR_WORDS(4); \
426: }
427:
428: p = (word *)(hbp->hb_body);
429: plim = (word *)(((word)hbp) + HBLKSIZE);
430:
431: /* go through all words in block */
432: while( p < plim ) {
433: mark_word = *mark_word_addr++;
434: DO_OBJ(0);
435: DO_OBJ(4);
436: DO_OBJ(8);
437: DO_OBJ(12);
438: DO_OBJ(16);
439: DO_OBJ(20);
440: DO_OBJ(24);
441: DO_OBJ(28);
442: # if CPP_WORDSZ == 64
443: DO_OBJ(32);
444: DO_OBJ(36);
445: DO_OBJ(40);
446: DO_OBJ(44);
447: DO_OBJ(48);
448: DO_OBJ(52);
449: DO_OBJ(56);
450: DO_OBJ(60);
451: # endif
452: p += WORDSZ;
453: }
1.5 noro 454: COUNT_UPDATE
1.1 noro 455: return(list);
456: # undef DO_OBJ
457: }
458:
1.5 noro 459: #endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
1.1 noro 460:
461: /* The same thing, but don't clear objects: */
462: /*ARGSUSED*/
1.5 noro 463: ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_PARAM)
1.1 noro 464: register struct hblk *hbp; /* ptr to current heap block */
465: register hdr * hhdr;
466: register ptr_t list;
467: register word sz;
1.5 noro 468: COUNT_DECL
1.1 noro 469: {
1.5 noro 470: register int word_no = 0;
1.1 noro 471: register word *p, *plim;
1.5 noro 472: NWORDS_DECL
1.1 noro 473:
474: p = (word *)(hbp->hb_body);
475: plim = (word *)((((word)hbp) + HBLKSIZE)
476: - WORDS_TO_BYTES(sz));
477:
478: /* go through all words in block */
479: while( p <= plim ) {
480: if( !mark_bit_from_hdr(hhdr, word_no) ) {
481: INCR_WORDS(sz);
482: /* object is available - put on list */
483: obj_link(p) = list;
484: list = ((ptr_t)p);
485: }
486: p += sz;
487: word_no += sz;
488: }
1.5 noro 489: COUNT_UPDATE
1.1 noro 490: return(list);
491: }
492:
1.2 noro 493: /* Don't really reclaim objects, just check for unmarked ones: */
494: /*ARGSUSED*/
495: void GC_reclaim_check(hbp, hhdr, sz)
496: register struct hblk *hbp; /* ptr to current heap block */
497: register hdr * hhdr;
498: register word sz;
499: {
1.5 noro 500: register int word_no = 0;
1.2 noro 501: register word *p, *plim;
502: # ifdef GATHERSTATS
503: register int n_words_found = 0;
504: # endif
505:
506: p = (word *)(hbp->hb_body);
507: plim = (word *)((((word)hbp) + HBLKSIZE)
508: - WORDS_TO_BYTES(sz));
509:
510: /* go through all words in block */
511: while( p <= plim ) {
512: if( !mark_bit_from_hdr(hhdr, word_no) ) {
513: FOUND_FREE(hbp, word_no);
514: }
515: p += sz;
516: word_no += sz;
517: }
518: }
519:
1.5 noro 520: #if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1 noro 521: /*
522: * Another special case for 2 word atomic objects:
523: */
524: /*ARGSUSED*/
1.5 noro 525: ptr_t GC_reclaim_uninit2(hbp, hhdr, list COUNT_PARAM)
1.1 noro 526: register struct hblk *hbp; /* ptr to current heap block */
527: hdr * hhdr;
528: register ptr_t list;
1.5 noro 529: COUNT_DECL
1.1 noro 530: {
1.5 noro 531: register word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 532: register word *p, *plim;
533: register word mark_word;
534: register int i;
1.5 noro 535: NWORDS_DECL
1.1 noro 536: # define DO_OBJ(start_displ) \
537: if (!(mark_word & ((word)1 << start_displ))) { \
538: p[start_displ] = (word)list; \
539: list = (ptr_t)(p+start_displ); \
540: INCR_WORDS(2); \
541: }
542:
543: p = (word *)(hbp->hb_body);
544: plim = (word *)(((word)hbp) + HBLKSIZE);
545:
546: /* go through all words in block */
547: while( p < plim ) {
548: mark_word = *mark_word_addr++;
549: for (i = 0; i < WORDSZ; i += 8) {
550: DO_OBJ(0);
551: DO_OBJ(2);
552: DO_OBJ(4);
553: DO_OBJ(6);
554: p += 8;
555: mark_word >>= 8;
556: }
557: }
1.5 noro 558: COUNT_UPDATE
1.1 noro 559: return(list);
560: # undef DO_OBJ
561: }
562:
563: /*
564: * Another special case for 4 word atomic objects:
565: */
566: /*ARGSUSED*/
1.5 noro 567: ptr_t GC_reclaim_uninit4(hbp, hhdr, list COUNT_PARAM)
1.1 noro 568: register struct hblk *hbp; /* ptr to current heap block */
569: hdr * hhdr;
570: register ptr_t list;
1.5 noro 571: COUNT_DECL
1.1 noro 572: {
1.5 noro 573: register word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 574: register word *p, *plim;
575: register word mark_word;
1.5 noro 576: NWORDS_DECL
1.1 noro 577: # define DO_OBJ(start_displ) \
578: if (!(mark_word & ((word)1 << start_displ))) { \
579: p[start_displ] = (word)list; \
580: list = (ptr_t)(p+start_displ); \
581: INCR_WORDS(4); \
582: }
583:
584: p = (word *)(hbp->hb_body);
585: plim = (word *)(((word)hbp) + HBLKSIZE);
586:
587: /* go through all words in block */
588: while( p < plim ) {
589: mark_word = *mark_word_addr++;
590: DO_OBJ(0);
591: DO_OBJ(4);
592: DO_OBJ(8);
593: DO_OBJ(12);
594: DO_OBJ(16);
595: DO_OBJ(20);
596: DO_OBJ(24);
597: DO_OBJ(28);
598: # if CPP_WORDSZ == 64
599: DO_OBJ(32);
600: DO_OBJ(36);
601: DO_OBJ(40);
602: DO_OBJ(44);
603: DO_OBJ(48);
604: DO_OBJ(52);
605: DO_OBJ(56);
606: DO_OBJ(60);
607: # endif
608: p += WORDSZ;
609: }
1.5 noro 610: COUNT_UPDATE
1.1 noro 611: return(list);
612: # undef DO_OBJ
613: }
614:
615: /* Finally the one word case, which never requires any clearing: */
616: /*ARGSUSED*/
1.5 noro 617: ptr_t GC_reclaim1(hbp, hhdr, list COUNT_PARAM)
1.1 noro 618: register struct hblk *hbp; /* ptr to current heap block */
619: hdr * hhdr;
620: register ptr_t list;
1.5 noro 621: COUNT_DECL
1.1 noro 622: {
1.5 noro 623: register word * mark_word_addr = &(hhdr->hb_marks[0]);
1.1 noro 624: register word *p, *plim;
625: register word mark_word;
626: register int i;
1.5 noro 627: NWORDS_DECL
1.1 noro 628: # define DO_OBJ(start_displ) \
629: if (!(mark_word & ((word)1 << start_displ))) { \
630: p[start_displ] = (word)list; \
631: list = (ptr_t)(p+start_displ); \
632: INCR_WORDS(1); \
633: }
634:
635: p = (word *)(hbp->hb_body);
636: plim = (word *)(((word)hbp) + HBLKSIZE);
637:
638: /* go through all words in block */
639: while( p < plim ) {
640: mark_word = *mark_word_addr++;
641: for (i = 0; i < WORDSZ; i += 4) {
642: DO_OBJ(0);
643: DO_OBJ(1);
644: DO_OBJ(2);
645: DO_OBJ(3);
646: p += 4;
647: mark_word >>= 4;
648: }
649: }
1.5 noro 650: COUNT_UPDATE
1.1 noro 651: return(list);
652: # undef DO_OBJ
653: }
654:
1.5 noro 655: #endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
1.1 noro 656:
657: /*
1.5 noro 658: * Generic procedure to rebuild a free list in hbp.
659: * Also called directly from GC_malloc_many.
1.1 noro 660: */
1.5 noro 661: ptr_t GC_reclaim_generic(hbp, hhdr, sz, init, list COUNT_PARAM)
662: struct hblk *hbp; /* ptr to current heap block */
663: hdr * hhdr;
664: GC_bool init;
665: ptr_t list;
666: word sz;
667: COUNT_DECL
1.1 noro 668: {
1.5 noro 669: ptr_t result = list;
1.1 noro 670:
1.5 noro 671: GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr);
1.7 noro 672: GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */);
1.5 noro 673: if (init) {
1.1 noro 674: switch(sz) {
1.5 noro 675: # if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1 noro 676: case 1:
1.5 noro 677: /* We now issue the hint even if GC_nearly_full returned */
678: /* DONT_KNOW. */
679: result = GC_reclaim1(hbp, hhdr, list COUNT_ARG);
1.1 noro 680: break;
681: case 2:
1.5 noro 682: result = GC_reclaim_clear2(hbp, hhdr, list COUNT_ARG);
1.1 noro 683: break;
684: case 4:
1.5 noro 685: result = GC_reclaim_clear4(hbp, hhdr, list COUNT_ARG);
1.1 noro 686: break;
1.5 noro 687: # endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
1.1 noro 688: default:
1.5 noro 689: result = GC_reclaim_clear(hbp, hhdr, sz, list COUNT_ARG);
1.1 noro 690: break;
691: }
692: } else {
1.7 noro 693: GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */);
1.1 noro 694: switch(sz) {
1.5 noro 695: # if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
1.1 noro 696: case 1:
1.5 noro 697: result = GC_reclaim1(hbp, hhdr, list COUNT_ARG);
1.1 noro 698: break;
699: case 2:
1.5 noro 700: result = GC_reclaim_uninit2(hbp, hhdr, list COUNT_ARG);
1.1 noro 701: break;
702: case 4:
1.5 noro 703: result = GC_reclaim_uninit4(hbp, hhdr, list COUNT_ARG);
1.1 noro 704: break;
1.5 noro 705: # endif /* !SMALL_CONFIG && !USE_MARK_BYTES */
1.1 noro 706: default:
1.5 noro 707: result = GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_ARG);
1.1 noro 708: break;
709: }
710: }
1.5 noro 711: if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr);
712: return result;
713: }
714:
715: /*
716: * Restore unmarked small objects in the block pointed to by hbp
717: * to the appropriate object free list.
718: * If entirely empty blocks are to be completely deallocated, then
719: * caller should perform that check.
720: */
721: void GC_reclaim_small_nonempty_block(hbp, report_if_found COUNT_PARAM)
722: register struct hblk *hbp; /* ptr to current heap block */
723: int report_if_found; /* Abort if a reclaimable object is found */
724: COUNT_DECL
725: {
726: hdr *hhdr = HDR(hbp);
727: word sz = hhdr -> hb_sz;
728: int kind = hhdr -> hb_obj_kind;
729: struct obj_kind * ok = &GC_obj_kinds[kind];
730: ptr_t * flh = &(ok -> ok_freelist[sz]);
731:
732: hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
733:
734: if (report_if_found) {
735: GC_reclaim_check(hbp, hhdr, sz);
736: } else {
1.7 noro 737: *flh = GC_reclaim_generic(hbp, hhdr, sz,
738: (ok -> ok_init || GC_debugging_started),
1.5 noro 739: *flh MEM_FOUND_ADDR);
740: }
1.1 noro 741: }
742:
743: /*
744: * Restore an unmarked large object or an entirely empty blocks of small objects
745: * to the heap block free list.
746: * Otherwise enqueue the block for later processing
747: * by GC_reclaim_small_nonempty_block.
1.2 noro 748: * If report_if_found is TRUE, then process any block immediately, and
749: * simply report free objects; do not actually reclaim them.
1.1 noro 750: */
1.5 noro 751: # if defined(__STDC__) || defined(__cplusplus)
752: void GC_reclaim_block(register struct hblk *hbp, word report_if_found)
753: # else
754: void GC_reclaim_block(hbp, report_if_found)
755: register struct hblk *hbp; /* ptr to current heap block */
756: word report_if_found; /* Abort if a reclaimable object is found */
757: # endif
1.1 noro 758: {
759: register hdr * hhdr;
760: register word sz; /* size of objects in current block */
761: register struct obj_kind * ok;
762: struct hblk ** rlh;
763:
764: hhdr = HDR(hbp);
765: sz = hhdr -> hb_sz;
766: ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
767:
768: if( sz > MAXOBJSZ ) { /* 1 big object */
1.5 noro 769: if( !mark_bit_from_hdr(hhdr, 0) ) {
1.2 noro 770: if (report_if_found) {
1.5 noro 771: FOUND_FREE(hbp, 0);
1.2 noro 772: } else {
1.5 noro 773: word blocks = OBJ_SZ_TO_BLOCKS(sz);
774: if (blocks > 1) {
775: GC_large_allocd_bytes -= blocks * HBLKSIZE;
776: }
1.2 noro 777: # ifdef GATHERSTATS
1.1 noro 778: GC_mem_found += sz;
1.2 noro 779: # endif
780: GC_freehblk(hbp);
781: }
1.1 noro 782: }
783: } else {
784: GC_bool empty = GC_block_empty(hhdr);
1.2 noro 785: if (report_if_found) {
1.5 noro 786: GC_reclaim_small_nonempty_block(hbp, (int)report_if_found
787: MEM_FOUND_ADDR);
1.1 noro 788: } else if (empty) {
789: # ifdef GATHERSTATS
790: GC_mem_found += BYTES_TO_WORDS(HBLKSIZE);
791: # endif
792: GC_freehblk(hbp);
1.5 noro 793: } else if (TRUE != GC_block_nearly_full(hhdr)){
1.1 noro 794: /* group of smaller objects, enqueue the real work */
795: rlh = &(ok -> ok_reclaim_list[sz]);
796: hhdr -> hb_next = *rlh;
797: *rlh = hbp;
1.5 noro 798: } /* else not worth salvaging. */
799: /* We used to do the nearly_full check later, but we */
800: /* already have the right cache context here. Also */
801: /* doing it here avoids some silly lock contention in */
802: /* GC_malloc_many. */
1.1 noro 803: }
804: }
805:
806: #if !defined(NO_DEBUGGING)
807: /* Routines to gather and print heap block info */
808: /* intended for debugging. Otherwise should be called */
809: /* with lock. */
1.7 noro 810:
811: struct Print_stats
812: {
813: size_t number_of_blocks;
814: size_t total_bytes;
815: };
1.1 noro 816:
1.5 noro 817: #ifdef USE_MARK_BYTES
818:
819: /* Return the number of set mark bits in the given header */
820: int GC_n_set_marks(hhdr)
821: hdr * hhdr;
822: {
823: register int result = 0;
824: register int i;
825:
826: for (i = 0; i < MARK_BITS_SZ; i++) {
827: result += hhdr -> hb_marks[i];
828: }
829: return(result);
830: }
831:
832: #else
833:
1.1 noro 834: /* Number of set bits in a word. Not performance critical. */
835: static int set_bits(n)
836: word n;
837: {
838: register word m = n;
839: register int result = 0;
840:
841: while (m > 0) {
842: if (m & 1) result++;
843: m >>= 1;
844: }
845: return(result);
846: }
847:
848: /* Return the number of set mark bits in the given header */
849: int GC_n_set_marks(hhdr)
850: hdr * hhdr;
851: {
852: register int result = 0;
853: register int i;
854:
855: for (i = 0; i < MARK_BITS_SZ; i++) {
856: result += set_bits(hhdr -> hb_marks[i]);
857: }
858: return(result);
859: }
860:
1.5 noro 861: #endif /* !USE_MARK_BYTES */
862:
1.1 noro 863: /*ARGSUSED*/
1.5 noro 864: # if defined(__STDC__) || defined(__cplusplus)
865: void GC_print_block_descr(struct hblk *h, word dummy)
866: # else
867: void GC_print_block_descr(h, dummy)
868: struct hblk *h;
869: word dummy;
870: # endif
1.1 noro 871: {
872: register hdr * hhdr = HDR(h);
873: register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz);
1.7 noro 874: struct Print_stats *ps;
1.1 noro 875:
876: GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind),
877: (unsigned long)bytes,
878: (unsigned long)(GC_n_set_marks(hhdr)));
1.5 noro 879: bytes += HBLKSIZE-1;
1.1 noro 880: bytes &= ~(HBLKSIZE-1);
1.7 noro 881:
882: ps = (struct Print_stats *)dummy;
883: ps->total_bytes += bytes;
884: ps->number_of_blocks++;
1.1 noro 885: }
886:
887: void GC_print_block_list()
888: {
1.7 noro 889: struct Print_stats pstats;
890:
1.1 noro 891: GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n");
1.7 noro 892: pstats.number_of_blocks = 0;
893: pstats.total_bytes = 0;
894: GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
1.1 noro 895: GC_printf2("\nblocks = %lu, bytes = %lu\n",
1.7 noro 896: (unsigned long)pstats.number_of_blocks,
897: (unsigned long)pstats.total_bytes);
1.1 noro 898: }
899:
900: #endif /* NO_DEBUGGING */
901:
902: /*
1.7 noro 903: * Clear all obj_link pointers in the list of free objects *flp.
904: * Clear *flp.
905: * This must be done before dropping a list of free gcj-style objects,
906: * since may otherwise end up with dangling "descriptor" pointers.
1.9 ! noro 907: * It may help for other pointer-containing objects.
1.7 noro 908: */
909: void GC_clear_fl_links(flp)
910: ptr_t *flp;
911: {
912: ptr_t next = *flp;
913:
914: while (0 != next) {
915: *flp = 0;
916: flp = &(obj_link(next));
917: next = *flp;
918: }
919: }
920:
921: /*
1.2 noro 922: * Perform GC_reclaim_block on the entire heap, after first clearing
923: * small object free lists (if we are not just looking for leaks).
1.1 noro 924: */
1.2 noro 925: void GC_start_reclaim(report_if_found)
926: int report_if_found; /* Abort if a GC_reclaimable object is found */
1.1 noro 927: {
928: int kind;
929:
1.7 noro 930: # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
931: GC_ASSERT(0 == GC_fl_builder_count);
932: # endif
1.1 noro 933: /* Clear reclaim- and free-lists */
934: for (kind = 0; kind < GC_n_kinds; kind++) {
1.7 noro 935: ptr_t *fop;
936: ptr_t *lim;
937: struct hblk ** rlp;
938: struct hblk ** rlim;
939: struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
940: GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
1.1 noro 941:
942: if (rlist == 0) continue; /* This kind not used. */
1.2 noro 943: if (!report_if_found) {
1.1 noro 944: lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]);
945: for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
1.7 noro 946: if (*fop != 0) {
947: if (should_clobber) {
948: GC_clear_fl_links(fop);
949: } else {
950: *fop = 0;
951: }
952: }
1.1 noro 953: }
954: } /* otherwise free list objects are marked, */
955: /* and its safe to leave them */
956: rlim = rlist + MAXOBJSZ+1;
957: for( rlp = rlist; rlp < rlim; rlp++ ) {
958: *rlp = 0;
959: }
960: }
961:
962: # ifdef PRINTBLOCKS
963: GC_printf0("GC_reclaim: current block sizes:\n");
964: GC_print_block_list();
965: # endif
966:
967: /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
968: /* or enqueue the block for later processing. */
1.2 noro 969: GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);
1.4 noro 970:
971: # ifdef EAGER_SWEEP
972: /* This is a very stupid thing to do. We make it possible anyway, */
973: /* so that you can convince yourself that it really is very stupid. */
974: GC_reclaim_all((GC_stop_func)0, FALSE);
975: # endif
1.7 noro 976: # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
977: GC_ASSERT(0 == GC_fl_builder_count);
978: # endif
1.1 noro 979:
980: }
981:
982: /*
983: * Sweep blocks of the indicated object size and kind until either the
984: * appropriate free list is nonempty, or there are no more blocks to
985: * sweep.
986: */
987: void GC_continue_reclaim(sz, kind)
988: word sz; /* words */
989: int kind;
990: {
991: register hdr * hhdr;
992: register struct hblk * hbp;
993: register struct obj_kind * ok = &(GC_obj_kinds[kind]);
994: struct hblk ** rlh = ok -> ok_reclaim_list;
995: ptr_t *flh = &(ok -> ok_freelist[sz]);
996:
997: if (rlh == 0) return; /* No blocks of this kind. */
998: rlh += sz;
999: while ((hbp = *rlh) != 0) {
1000: hhdr = HDR(hbp);
1001: *rlh = hhdr -> hb_next;
1.5 noro 1002: GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR);
1.1 noro 1003: if (*flh != 0) break;
1004: }
1005: }
1006:
1007: /*
1008: * Reclaim all small blocks waiting to be reclaimed.
1009: * Abort and return FALSE when/if (*stop_func)() returns TRUE.
1010: * If this returns TRUE, then it's safe to restart the world
1011: * with incorrectly cleared mark bits.
1.4 noro 1012: * If ignore_old is TRUE, then reclaim only blocks that have been
1.1 noro 1013: * recently reclaimed, and discard the rest.
1014: * Stop_func may be 0.
1015: */
1016: GC_bool GC_reclaim_all(stop_func, ignore_old)
1017: GC_stop_func stop_func;
1018: GC_bool ignore_old;
1019: {
1020: register word sz;
1021: register int kind;
1022: register hdr * hhdr;
1023: register struct hblk * hbp;
1024: register struct obj_kind * ok;
1025: struct hblk ** rlp;
1026: struct hblk ** rlh;
1027: # ifdef PRINTTIMES
1028: CLOCK_TYPE start_time;
1029: CLOCK_TYPE done_time;
1030:
1031: GET_TIME(start_time);
1032: # endif
1.8 noro 1033: GC_timerstart();
1034:
1.1 noro 1035: for (kind = 0; kind < GC_n_kinds; kind++) {
1036: ok = &(GC_obj_kinds[kind]);
1037: rlp = ok -> ok_reclaim_list;
1038: if (rlp == 0) continue;
1039: for (sz = 1; sz <= MAXOBJSZ; sz++) {
1040: rlh = rlp + sz;
1041: while ((hbp = *rlh) != 0) {
1042: if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
1043: return(FALSE);
1044: }
1045: hhdr = HDR(hbp);
1046: *rlh = hhdr -> hb_next;
1047: if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
1048: /* It's likely we'll need it this time, too */
1049: /* It's been touched recently, so this */
1050: /* shouldn't trigger paging. */
1.5 noro 1051: GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR);
1.1 noro 1052: }
1053: }
1054: }
1055: }
1.8 noro 1056: GC_timerstop();
1.1 noro 1057: # ifdef PRINTTIMES
1058: GET_TIME(done_time);
1059: GC_printf1("Disposing of reclaim lists took %lu msecs\n",
1060: MS_TIME_DIFF(done_time,start_time));
1061: # endif
1062: return(TRUE);
1063: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>