version 1.1.1.1, 1999/12/03 07:39:10 |
version 1.4, 2000/12/01 09:26:13 |
|
|
/* |
/* |
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers |
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. |
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. |
|
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. |
|
* Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. |
* |
* |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. |
|
|
* provided the above notices are retained, and a notice that the code was |
* provided the above notices are retained, and a notice that the code was |
* modified is included with the above copyright notice. |
* modified is included with the above copyright notice. |
*/ |
*/ |
/* Boehm, February 15, 1996 2:41 pm PST */ |
|
|
|
#include <stdio.h> |
#include <stdio.h> |
#include "gc_priv.h" |
#include "gc_priv.h" |
Line 21 void GC_timerstart(), GC_timerstop(); |
|
Line 22 void GC_timerstart(), GC_timerstop(); |
|
signed_word GC_mem_found = 0; |
signed_word GC_mem_found = 0; |
/* Number of words of memory reclaimed */ |
/* Number of words of memory reclaimed */ |
|
|
# ifdef FIND_LEAK |
|
static void report_leak(p, sz) |
static void report_leak(p, sz) |
ptr_t p; |
ptr_t p; |
word sz; |
word sz; |
|
|
} else { |
} else { |
GC_err_printf0("Leaked composite object at "); |
GC_err_printf0("Leaked composite object at "); |
} |
} |
if (GC_debugging_started && GC_has_debug_info(p)) { |
GC_print_heap_obj(p); |
GC_print_obj(p); |
GC_err_printf0("\n"); |
} else { |
|
GC_err_printf2("0x%lx (appr. size = %ld)\n", |
|
(unsigned long)p, |
|
(unsigned long)WORDS_TO_BYTES(sz)); |
|
} |
|
} |
} |
|
|
# define FOUND_FREE(hblk, word_no) \ |
# define FOUND_FREE(hblk, word_no) \ |
if (abort_if_found) { \ |
{ \ |
report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \ |
report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \ |
HDR(hblk) -> hb_sz); \ |
HDR(hblk) -> hb_sz); \ |
} |
} |
# else |
|
# define FOUND_FREE(hblk, word_no) |
|
# endif |
|
|
|
/* |
/* |
* reclaim phase |
* reclaim phase |
Line 73 register hdr * hhdr; |
|
Line 65 register hdr * hhdr; |
|
return(TRUE); |
return(TRUE); |
} |
} |
|
|
|
/* The following functions sometimes return a DONT_KNOW value. */ |
|
#define DONT_KNOW 2 |
|
|
|
#ifdef SMALL_CONFIG |
|
# define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW |
|
# define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW |
|
# define GC_block_nearly_full(hhdr) DONT_KNOW |
|
#else |
|
|
|
/* |
|
* Test whether nearly all of the mark words consist of the same |
|
* repeating pattern. |
|
*/ |
|
#define FULL_THRESHOLD (MARK_BITS_SZ/16) |
|
|
|
GC_bool GC_block_nearly_full1(hhdr, pat1) |
|
hdr *hhdr; |
|
word pat1; |
|
{ |
|
unsigned i; |
|
unsigned misses = 0; |
|
GC_ASSERT((MARK_BITS_SZ & 1) == 0); |
|
for (i = 0; i < MARK_BITS_SZ; ++i) { |
|
if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { |
|
if (++misses > FULL_THRESHOLD) return FALSE; |
|
} |
|
} |
|
return TRUE; |
|
} |
|
|
|
/* |
|
* Test whether the same repeating 3 word pattern occurs in nearly |
|
* all the mark bit slots. |
|
* This is used as a heuristic, so we're a bit sloppy and ignore |
|
* the last one or two words. |
|
*/ |
|
GC_bool GC_block_nearly_full3(hhdr, pat1, pat2, pat3) |
|
hdr *hhdr; |
|
word pat1, pat2, pat3; |
|
{ |
|
unsigned i; |
|
unsigned misses = 0; |
|
|
|
if (MARK_BITS_SZ < 4) { |
|
return DONT_KNOW; |
|
} |
|
for (i = 0; i < MARK_BITS_SZ - 2; i += 3) { |
|
if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { |
|
if (++misses > FULL_THRESHOLD) return FALSE; |
|
} |
|
if ((hhdr -> hb_marks[i+1] | ~pat2) != ONES) { |
|
if (++misses > FULL_THRESHOLD) return FALSE; |
|
} |
|
if ((hhdr -> hb_marks[i+2] | ~pat3) != ONES) { |
|
if (++misses > FULL_THRESHOLD) return FALSE; |
|
} |
|
} |
|
return TRUE; |
|
} |
|
|
|
/* Check whether a small object block is nearly full by looking at only */ |
|
/* the mark bits. */ |
|
/* We manually precomputed the mark bit patterns that need to be */ |
|
/* checked for, and we give up on the ones that are unlikely to occur, */ |
|
/* or have period > 3. */ |
|
/* This would be a lot easier with a mark bit per object instead of per */ |
|
/* word, but that would rewuire computing object numbers in the mark */ |
|
/* loop, which would require different data structures ... */ |
|
GC_bool GC_block_nearly_full(hhdr) |
|
hdr *hhdr; |
|
{ |
|
int sz = hhdr -> hb_sz; |
|
|
|
# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 |
|
return DONT_KNOW; /* Shouldn't be used in any standard config. */ |
|
# endif |
|
if (0 != HDR_WORDS) return DONT_KNOW; |
|
/* Also shouldn't happen */ |
|
# if CPP_WORDSZ == 32 |
|
switch(sz) { |
|
case 1: |
|
return GC_block_nearly_full1(hhdr, 0xffffffffl); |
|
case 2: |
|
return GC_block_nearly_full1(hhdr, 0x55555555l); |
|
case 4: |
|
return GC_block_nearly_full1(hhdr, 0x11111111l); |
|
case 6: |
|
return GC_block_nearly_full3(hhdr, 0x41041041l, |
|
0x10410410l, |
|
0x04104104l); |
|
case 8: |
|
return GC_block_nearly_full1(hhdr, 0x01010101l); |
|
case 12: |
|
return GC_block_nearly_full3(hhdr, 0x01001001l, |
|
0x10010010l, |
|
0x00100100l); |
|
case 16: |
|
return GC_block_nearly_full1(hhdr, 0x00010001l); |
|
case 32: |
|
return GC_block_nearly_full1(hhdr, 0x00000001l); |
|
default: |
|
return DONT_KNOW; |
|
} |
|
# endif |
|
# if CPP_WORDSZ == 64 |
|
switch(sz) { |
|
case 1: |
|
return GC_block_nearly_full1(hhdr, 0xffffffffffffffffl); |
|
case 2: |
|
return GC_block_nearly_full1(hhdr, 0x5555555555555555l); |
|
case 4: |
|
return GC_block_nearly_full1(hhdr, 0x1111111111111111l); |
|
case 6: |
|
return GC_block_nearly_full3(hhdr, 0x1041041041041041l, |
|
0x4104104104104104l, |
|
0x0410410410410410l); |
|
case 8: |
|
return GC_block_nearly_full1(hhdr, 0x0101010101010101l); |
|
case 12: |
|
return GC_block_nearly_full3(hhdr, 0x1001001001001001l, |
|
0x0100100100100100l, |
|
0x0010010010010010l); |
|
case 16: |
|
return GC_block_nearly_full1(hhdr, 0x0001000100010001l); |
|
case 32: |
|
return GC_block_nearly_full1(hhdr, 0x0000000100000001l); |
|
default: |
|
return DONT_KNOW; |
|
} |
|
# endif |
|
} |
|
#endif /* !SMALL_CONFIG */ |
|
|
# ifdef GATHERSTATS |
# ifdef GATHERSTATS |
# define INCR_WORDS(sz) n_words_found += (sz) |
# define INCR_WORDS(sz) n_words_found += (sz) |
# else |
# else |
Line 84 register hdr * hhdr; |
|
Line 209 register hdr * hhdr; |
|
* Clears unmarked objects. |
* Clears unmarked objects. |
*/ |
*/ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim_clear(hbp, hhdr, sz, list, abort_if_found) |
ptr_t GC_reclaim_clear(hbp, hhdr, sz, list) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
register hdr * hhdr; |
register hdr * hhdr; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
register ptr_t list; |
register ptr_t list; |
register word sz; |
register word sz; |
{ |
{ |
Line 107 register word sz; |
|
Line 231 register word sz; |
|
if( mark_bit_from_hdr(hhdr, word_no) ) { |
if( mark_bit_from_hdr(hhdr, word_no) ) { |
p += sz; |
p += sz; |
} else { |
} else { |
FOUND_FREE(hbp, word_no); |
|
INCR_WORDS(sz); |
INCR_WORDS(sz); |
/* object is available - put on list */ |
/* object is available - put on list */ |
obj_link(p) = list; |
obj_link(p) = list; |
Line 133 register word sz; |
|
Line 256 register word sz; |
|
* A special case for 2 word composite objects (e.g. cons cells): |
* A special case for 2 word composite objects (e.g. cons cells): |
*/ |
*/ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim_clear2(hbp, hhdr, list, abort_if_found) |
ptr_t GC_reclaim_clear2(hbp, hhdr, list) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
register ptr_t list; |
register ptr_t list; |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
Line 148 register ptr_t list; |
|
Line 270 register ptr_t list; |
|
register int i; |
register int i; |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ |
|
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
list = (ptr_t)(p+start_displ); \ |
list = (ptr_t)(p+start_displ); \ |
p[start_displ+1] = 0; \ |
p[start_displ+1] = 0; \ |
Line 181 register ptr_t list; |
|
Line 302 register ptr_t list; |
|
* Another special case for 4 word composite objects: |
* Another special case for 4 word composite objects: |
*/ |
*/ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim_clear4(hbp, hhdr, list, abort_if_found) |
ptr_t GC_reclaim_clear4(hbp, hhdr, list) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
register ptr_t list; |
register ptr_t list; |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
Line 195 register ptr_t list; |
|
Line 315 register ptr_t list; |
|
register word mark_word; |
register word mark_word; |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ |
|
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
list = (ptr_t)(p+start_displ); \ |
list = (ptr_t)(p+start_displ); \ |
p[start_displ+1] = 0; \ |
p[start_displ+1] = 0; \ |
p[start_displ+2] = 0; \ |
CLEAR_DOUBLE(p + start_displ + 2); \ |
p[start_displ+3] = 0; \ |
|
INCR_WORDS(4); \ |
INCR_WORDS(4); \ |
} |
} |
|
|
Line 241 register ptr_t list; |
|
Line 359 register ptr_t list; |
|
|
|
/* The same thing, but don't clear objects: */ |
/* The same thing, but don't clear objects: */ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list, abort_if_found) |
ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
register hdr * hhdr; |
register hdr * hhdr; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
register ptr_t list; |
register ptr_t list; |
register word sz; |
register word sz; |
{ |
{ |
Line 262 register word sz; |
|
Line 379 register word sz; |
|
/* go through all words in block */ |
/* go through all words in block */ |
while( p <= plim ) { |
while( p <= plim ) { |
if( !mark_bit_from_hdr(hhdr, word_no) ) { |
if( !mark_bit_from_hdr(hhdr, word_no) ) { |
FOUND_FREE(hbp, word_no); |
|
INCR_WORDS(sz); |
INCR_WORDS(sz); |
/* object is available - put on list */ |
/* object is available - put on list */ |
obj_link(p) = list; |
obj_link(p) = list; |
Line 277 register word sz; |
|
Line 393 register word sz; |
|
return(list); |
return(list); |
} |
} |
|
|
|
/* Don't really reclaim objects, just check for unmarked ones: */ |
|
/*ARGSUSED*/ |
|
void GC_reclaim_check(hbp, hhdr, sz) |
|
register struct hblk *hbp; /* ptr to current heap block */ |
|
register hdr * hhdr; |
|
register word sz; |
|
{ |
|
register int word_no; |
|
register word *p, *plim; |
|
# ifdef GATHERSTATS |
|
register int n_words_found = 0; |
|
# endif |
|
|
|
p = (word *)(hbp->hb_body); |
|
word_no = HDR_WORDS; |
|
plim = (word *)((((word)hbp) + HBLKSIZE) |
|
- WORDS_TO_BYTES(sz)); |
|
|
|
/* go through all words in block */ |
|
while( p <= plim ) { |
|
if( !mark_bit_from_hdr(hhdr, word_no) ) { |
|
FOUND_FREE(hbp, word_no); |
|
} |
|
p += sz; |
|
word_no += sz; |
|
} |
|
} |
|
|
#ifndef SMALL_CONFIG |
#ifndef SMALL_CONFIG |
/* |
/* |
* Another special case for 2 word atomic objects: |
* Another special case for 2 word atomic objects: |
*/ |
*/ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim_uninit2(hbp, hhdr, list, abort_if_found) |
ptr_t GC_reclaim_uninit2(hbp, hhdr, list) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
register ptr_t list; |
register ptr_t list; |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
Line 297 register ptr_t list; |
|
Line 440 register ptr_t list; |
|
register int i; |
register int i; |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ |
|
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
list = (ptr_t)(p+start_displ); \ |
list = (ptr_t)(p+start_displ); \ |
INCR_WORDS(2); \ |
INCR_WORDS(2); \ |
Line 329 register ptr_t list; |
|
Line 471 register ptr_t list; |
|
* Another special case for 4 word atomic objects: |
* Another special case for 4 word atomic objects: |
*/ |
*/ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim_uninit4(hbp, hhdr, list, abort_if_found) |
ptr_t GC_reclaim_uninit4(hbp, hhdr, list) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
register ptr_t list; |
register ptr_t list; |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
Line 343 register ptr_t list; |
|
Line 484 register ptr_t list; |
|
register word mark_word; |
register word mark_word; |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ |
|
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
list = (ptr_t)(p+start_displ); \ |
list = (ptr_t)(p+start_displ); \ |
INCR_WORDS(4); \ |
INCR_WORDS(4); \ |
Line 384 register ptr_t list; |
|
Line 524 register ptr_t list; |
|
|
|
/* Finally the one word case, which never requires any clearing: */ |
/* Finally the one word case, which never requires any clearing: */ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim1(hbp, hhdr, list, abort_if_found) |
ptr_t GC_reclaim1(hbp, hhdr, list) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
register ptr_t list; |
register ptr_t list; |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
Line 399 register ptr_t list; |
|
Line 538 register ptr_t list; |
|
register int i; |
register int i; |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ |
|
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
list = (ptr_t)(p+start_displ); \ |
list = (ptr_t)(p+start_displ); \ |
INCR_WORDS(1); \ |
INCR_WORDS(1); \ |
Line 435 register ptr_t list; |
|
Line 573 register ptr_t list; |
|
* If entirely empty blocks are to be completely deallocated, then |
* If entirely empty blocks are to be completely deallocated, then |
* caller should perform that check. |
* caller should perform that check. |
*/ |
*/ |
void GC_reclaim_small_nonempty_block(hbp, abort_if_found) |
void GC_reclaim_small_nonempty_block(hbp, report_if_found) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
int abort_if_found; /* Abort if a reclaimable object is found */ |
int report_if_found; /* Abort if a reclaimable object is found */ |
{ |
{ |
hdr * hhdr; |
hdr * hhdr; |
register word sz; /* size of objects in current block */ |
word sz; /* size of objects in current block */ |
register struct obj_kind * ok; |
struct obj_kind * ok; |
register ptr_t * flh; |
ptr_t * flh; |
register int kind; |
int kind; |
|
GC_bool full; |
|
|
hhdr = HDR(hbp); |
hhdr = HDR(hbp); |
sz = hhdr -> hb_sz; |
sz = hhdr -> hb_sz; |
Line 451 int abort_if_found; /* Abort if a reclaimable object |
|
Line 590 int abort_if_found; /* Abort if a reclaimable object |
|
kind = hhdr -> hb_obj_kind; |
kind = hhdr -> hb_obj_kind; |
ok = &GC_obj_kinds[kind]; |
ok = &GC_obj_kinds[kind]; |
flh = &(ok -> ok_freelist[sz]); |
flh = &(ok -> ok_freelist[sz]); |
GC_write_hint(hbp); |
|
|
|
if (ok -> ok_init) { |
if (report_if_found) { |
|
GC_reclaim_check(hbp, hhdr, sz); |
|
} else if (ok -> ok_init) { |
switch(sz) { |
switch(sz) { |
# ifndef SMALL_CONFIG |
# ifndef SMALL_CONFIG |
case 1: |
case 1: |
*flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found); |
# if CPP_WORDSZ == 64 |
|
full = GC_block_nearly_full1(hhdr, 0xffffffffffffffffl); |
|
# else |
|
full = GC_block_nearly_full1(hhdr, 0xffffffffl); |
|
# endif |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
/* In the DONT_KNOW case, we let reclaim fault. */ |
|
*flh = GC_reclaim1(hbp, hhdr, *flh); |
break; |
break; |
case 2: |
case 2: |
*flh = GC_reclaim_clear2(hbp, hhdr, *flh, abort_if_found); |
# if CPP_WORDSZ == 64 |
|
full = GC_block_nearly_full1(hhdr, 0x5555555555555555l); |
|
# else |
|
full = GC_block_nearly_full1(hhdr, 0x55555555l); |
|
# endif |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_clear2(hbp, hhdr, *flh); |
break; |
break; |
case 4: |
case 4: |
*flh = GC_reclaim_clear4(hbp, hhdr, *flh, abort_if_found); |
# if CPP_WORDSZ == 64 |
|
full = GC_block_nearly_full1(hhdr, 0x1111111111111111l); |
|
# else |
|
full = GC_block_nearly_full1(hhdr, 0x11111111l); |
|
# endif |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_clear4(hbp, hhdr, *flh); |
break; |
break; |
# endif |
# endif |
default: |
default: |
*flh = GC_reclaim_clear(hbp, hhdr, sz, *flh, abort_if_found); |
full = GC_block_nearly_full(hhdr); |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_clear(hbp, hhdr, sz, *flh); |
break; |
break; |
} |
} |
} else { |
} else { |
switch(sz) { |
switch(sz) { |
# ifndef SMALL_CONFIG |
# ifndef SMALL_CONFIG |
case 1: |
case 1: |
*flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found); |
# if CPP_WORDSZ == 64 |
|
full = GC_block_nearly_full1(hhdr, 0xffffffffffffffffl); |
|
# else |
|
full = GC_block_nearly_full1(hhdr, 0xffffffffl); |
|
# endif |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim1(hbp, hhdr, *flh); |
break; |
break; |
case 2: |
case 2: |
*flh = GC_reclaim_uninit2(hbp, hhdr, *flh, abort_if_found); |
# if CPP_WORDSZ == 64 |
|
full = GC_block_nearly_full1(hhdr, 0x5555555555555555l); |
|
# else |
|
full = GC_block_nearly_full1(hhdr, 0x55555555l); |
|
# endif |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_uninit2(hbp, hhdr, *flh); |
break; |
break; |
case 4: |
case 4: |
*flh = GC_reclaim_uninit4(hbp, hhdr, *flh, abort_if_found); |
# if CPP_WORDSZ == 64 |
|
full = GC_block_nearly_full1(hhdr, 0x1111111111111111l); |
|
# else |
|
full = GC_block_nearly_full1(hhdr, 0x11111111l); |
|
# endif |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_uninit4(hbp, hhdr, *flh); |
break; |
break; |
# endif |
# endif |
default: |
default: |
*flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh, abort_if_found); |
full = GC_block_nearly_full(hhdr); |
|
if (TRUE == full) goto out; |
|
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh); |
break; |
break; |
} |
} |
} |
} |
|
out: |
if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(hhdr); |
if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(hhdr); |
} |
} |
|
|
Line 496 int abort_if_found; /* Abort if a reclaimable object |
|
Line 686 int abort_if_found; /* Abort if a reclaimable object |
|
* to the heap block free list. |
* to the heap block free list. |
* Otherwise enqueue the block for later processing |
* Otherwise enqueue the block for later processing |
* by GC_reclaim_small_nonempty_block. |
* by GC_reclaim_small_nonempty_block. |
* If abort_if_found is TRUE, then process any block immediately. |
* If report_if_found is TRUE, then process any block immediately, and |
|
* simply report free objects; do not actually reclaim them. |
*/ |
*/ |
void GC_reclaim_block(hbp, abort_if_found) |
void GC_reclaim_block(hbp, report_if_found) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
word abort_if_found; /* Abort if a reclaimable object is found */ |
word report_if_found; /* Abort if a reclaimable object is found */ |
{ |
{ |
register hdr * hhdr; |
register hdr * hhdr; |
register word sz; /* size of objects in current block */ |
register word sz; /* size of objects in current block */ |
Line 513 word abort_if_found; /* Abort if a reclaimable object |
|
Line 704 word abort_if_found; /* Abort if a reclaimable object |
|
|
|
if( sz > MAXOBJSZ ) { /* 1 big object */ |
if( sz > MAXOBJSZ ) { /* 1 big object */ |
if( !mark_bit_from_hdr(hhdr, HDR_WORDS) ) { |
if( !mark_bit_from_hdr(hhdr, HDR_WORDS) ) { |
FOUND_FREE(hbp, HDR_WORDS); |
if (report_if_found) { |
# ifdef GATHERSTATS |
FOUND_FREE(hbp, HDR_WORDS); |
|
} else { |
|
# ifdef GATHERSTATS |
GC_mem_found += sz; |
GC_mem_found += sz; |
# endif |
# endif |
GC_freehblk(hbp); |
GC_freehblk(hbp); |
|
} |
} |
} |
} else { |
} else { |
GC_bool empty = GC_block_empty(hhdr); |
GC_bool empty = GC_block_empty(hhdr); |
if (abort_if_found) { |
if (report_if_found) { |
GC_reclaim_small_nonempty_block(hbp, (int)abort_if_found); |
GC_reclaim_small_nonempty_block(hbp, (int)report_if_found); |
} else if (empty) { |
} else if (empty) { |
# ifdef GATHERSTATS |
# ifdef GATHERSTATS |
GC_mem_found += BYTES_TO_WORDS(HBLKSIZE); |
GC_mem_found += BYTES_TO_WORDS(HBLKSIZE); |
Line 602 void GC_print_block_list() |
|
Line 796 void GC_print_block_list() |
|
#endif /* NO_DEBUGGING */ |
#endif /* NO_DEBUGGING */ |
|
|
/* |
/* |
* Do the same thing on the entire heap, after first clearing small object |
* Perform GC_reclaim_block on the entire heap, after first clearing |
* free lists (if we are not just looking for leaks). |
* small object free lists (if we are not just looking for leaks). |
*/ |
*/ |
void GC_start_reclaim(abort_if_found) |
void GC_start_reclaim(report_if_found) |
int abort_if_found; /* Abort if a GC_reclaimable object is found */ |
int report_if_found; /* Abort if a GC_reclaimable object is found */ |
{ |
{ |
int kind; |
int kind; |
|
|
Line 619 int abort_if_found; /* Abort if a GC_reclaimable obje |
|
Line 813 int abort_if_found; /* Abort if a GC_reclaimable obje |
|
register struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list; |
register struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list; |
|
|
if (rlist == 0) continue; /* This kind not used. */ |
if (rlist == 0) continue; /* This kind not used. */ |
if (!abort_if_found) { |
if (!report_if_found) { |
lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]); |
lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]); |
for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) { |
for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) { |
*fop = 0; |
*fop = 0; |
Line 639 int abort_if_found; /* Abort if a GC_reclaimable obje |
|
Line 833 int abort_if_found; /* Abort if a GC_reclaimable obje |
|
|
|
/* Go through all heap blocks (in hblklist) and reclaim unmarked objects */ |
/* Go through all heap blocks (in hblklist) and reclaim unmarked objects */ |
/* or enqueue the block for later processing. */ |
/* or enqueue the block for later processing. */ |
GC_apply_to_all_blocks(GC_reclaim_block, (word)abort_if_found); |
GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found); |
|
|
|
# ifdef EAGER_SWEEP |
|
/* This is a very stupid thing to do. We make it possible anyway, */ |
|
/* so that you can convince yourself that it really is very stupid. */ |
|
GC_reclaim_all((GC_stop_func)0, FALSE); |
|
# endif |
|
|
} |
} |
|
|
|
|
|
|
if (rlh == 0) return; /* No blocks of this kind. */ |
if (rlh == 0) return; /* No blocks of this kind. */ |
rlh += sz; |
rlh += sz; |
|
#if 0 |
GC_timerstart(); |
GC_timerstart(); |
|
#endif |
while ((hbp = *rlh) != 0) { |
while ((hbp = *rlh) != 0) { |
hhdr = HDR(hbp); |
hhdr = HDR(hbp); |
*rlh = hhdr -> hb_next; |
*rlh = hhdr -> hb_next; |
GC_reclaim_small_nonempty_block(hbp, FALSE); |
GC_reclaim_small_nonempty_block(hbp, FALSE); |
if (*flh != 0) break; |
if (*flh != 0) break; |
} |
} |
|
#if 0 |
GC_timerstop(); |
GC_timerstop(); |
|
#endif |
} |
} |
|
|
/* |
/* |
|
|
* Abort and return FALSE when/if (*stop_func)() returns TRUE. |
* Abort and return FALSE when/if (*stop_func)() returns TRUE. |
* If this returns TRUE, then it's safe to restart the world |
* If this returns TRUE, then it's safe to restart the world |
* with incorrectly cleared mark bits. |
* with incorrectly cleared mark bits. |
* If ignore_old is TRUE, then reclain only blocks that have been |
* If ignore_old is TRUE, then reclaim only blocks that have been |
* recently reclaimed, and discard the rest. |
* recently reclaimed, and discard the rest. |
* Stop_func may be 0. |
* Stop_func may be 0. |
*/ |
*/ |