version 1.3, 2000/04/13 06:01:02 |
version 1.5, 2001/04/20 07:39:19 |
|
|
*/ |
*/ |
|
|
#include <stdio.h> |
#include <stdio.h> |
#include "gc_priv.h" |
#include "private/gc_priv.h" |
|
|
void GC_timerstart(), GC_timerstop(); |
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 PARALLEL_MARK |
|
word GC_fl_builder_count = 0; |
|
/* Number of threads currently building free lists without */ |
|
/* holding GC lock. It is not safe to collect if this is */ |
|
/* nonzero. */ |
|
#endif /* PARALLEL_MARK */ |
|
|
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) \ |
|
|
GC_bool GC_block_empty(hhdr) |
GC_bool GC_block_empty(hhdr) |
register hdr * hhdr; |
register hdr * hhdr; |
{ |
{ |
|
/* We treat hb_marks as an array of words here, even if it is */ |
|
/* actually an array of bytes. Since we only check for zero, there */ |
|
/* are no endian-ness issues. */ |
register word *p = (word *)(&(hhdr -> hb_marks[0])); |
register word *p = (word *)(&(hhdr -> hb_marks[0])); |
register word * plim = |
register word * plim = |
(word *)(&(hhdr -> hb_marks[MARK_BITS_SZ])); |
(word *)(&(hhdr -> hb_marks[MARK_BITS_SZ])); |
while (p < plim) { |
while (p < plim) { |
if (*p++) return(FALSE); |
if (*p++) return(FALSE); |
} |
} |
Line 77 register hdr * hhdr; |
|
Line 82 register hdr * hhdr; |
|
# define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW |
# define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW |
# define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW |
# define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW |
# define GC_block_nearly_full(hhdr) DONT_KNOW |
# define GC_block_nearly_full(hhdr) DONT_KNOW |
#else |
#endif |
|
|
|
#if !defined(SMALL_CONFIG) && defined(USE_MARK_BYTES) |
|
|
|
# define GC_block_nearly_full1(hhdr, pat1) GC_block_nearly_full(hhdr) |
|
# define GC_block_nearly_full3(hhdr, pat1, pat2) GC_block_nearly_full(hhdr) |
|
|
|
|
|
GC_bool GC_block_nearly_full(hhdr) |
|
register hdr * hhdr; |
|
{ |
|
/* We again treat hb_marks as an array of words, even though it */ |
|
/* isn't. We first sum up all the words, resulting in a word */ |
|
/* containing 4 or 8 separate partial sums. */ |
|
/* We then sum the bytes in the word of partial sums. */ |
|
/* This is still endian independant. This fails if the partial */ |
|
/* sums can overflow. */ |
|
# if (BYTES_TO_WORDS(MARK_BITS_SZ)) >= 256 |
|
--> potential overflow; fix the code |
|
# endif |
|
register word *p = (word *)(&(hhdr -> hb_marks[0])); |
|
register word * plim = |
|
(word *)(&(hhdr -> hb_marks[MARK_BITS_SZ])); |
|
word sum_vector = 0; |
|
unsigned sum; |
|
while (p < plim) { |
|
sum_vector += *p; |
|
++p; |
|
} |
|
sum = 0; |
|
while (sum_vector > 0) { |
|
sum += sum_vector & 0xff; |
|
sum_vector >>= 8; |
|
} |
|
return (sum > BYTES_TO_WORDS(7*HBLKSIZE/8)/(hhdr -> hb_sz)); |
|
} |
|
#endif /* USE_MARK_BYTES */ |
|
|
|
#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
|
|
/* |
/* |
* Test whether nearly all of the mark words consist of the same |
* Test whether nearly all of the mark words consist of the same |
* repeating pattern. |
* repeating pattern. |
|
|
# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 |
# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 |
return DONT_KNOW; /* Shouldn't be used in any standard config. */ |
return DONT_KNOW; /* Shouldn't be used in any standard config. */ |
# endif |
# endif |
if (0 != HDR_WORDS) return DONT_KNOW; |
|
/* Also shouldn't happen */ |
|
# if CPP_WORDSZ == 32 |
# if CPP_WORDSZ == 32 |
switch(sz) { |
switch(sz) { |
case 1: |
case 1: |
|
|
} |
} |
# endif |
# endif |
} |
} |
#endif /* !SMALL_CONFIG */ |
#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
|
|
# ifdef GATHERSTATS |
/* We keep track of reclaimed memory if we are either asked to, or */ |
|
/* we are using the parallel marker. In the latter case, we assume */ |
|
/* that most allocation goes through GC_malloc_many for scalability. */ |
|
/* GC_malloc_many needs the count anyway. */ |
|
# if defined(GATHERSTATS) || defined(PARALLEL_MARK) |
# define INCR_WORDS(sz) n_words_found += (sz) |
# define INCR_WORDS(sz) n_words_found += (sz) |
|
# define COUNT_PARAM , count |
|
# define COUNT_ARG , count |
|
# define COUNT_DECL signed_word * count; |
|
# define NWORDS_DECL signed_word n_words_found = 0; |
|
# define COUNT_UPDATE *count += n_words_found; |
|
# define MEM_FOUND_ADDR , &GC_mem_found |
# else |
# else |
# define INCR_WORDS(sz) |
# define INCR_WORDS(sz) |
|
# define COUNT_PARAM |
|
# define COUNT_ARG |
|
# define COUNT_DECL |
|
# define NWORDS_DECL |
|
# define COUNT_UPDATE |
|
# define MEM_FOUND_ADDR |
# endif |
# endif |
/* |
/* |
* Restore unmarked small objects in h of size sz to the object |
* Restore unmarked small objects in h of size sz to the object |
|
|
* Clears unmarked objects. |
* Clears unmarked objects. |
*/ |
*/ |
/*ARGSUSED*/ |
/*ARGSUSED*/ |
ptr_t GC_reclaim_clear(hbp, hhdr, sz, list) |
ptr_t GC_reclaim_clear(hbp, hhdr, sz, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
register hdr * hhdr; |
register hdr * hhdr; |
register ptr_t list; |
register ptr_t list; |
register word sz; |
register word sz; |
|
COUNT_DECL |
{ |
{ |
register int word_no; |
register int word_no; |
register word *p, *q, *plim; |
register word *p, *q, *plim; |
# ifdef GATHERSTATS |
NWORDS_DECL |
register int n_words_found = 0; |
|
# endif |
|
|
|
|
GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp)); |
p = (word *)(hbp->hb_body); |
p = (word *)(hbp->hb_body); |
word_no = HDR_WORDS; |
word_no = 0; |
plim = (word *)((((word)hbp) + HBLKSIZE) |
plim = (word *)((((word)hbp) + HBLKSIZE) |
- WORDS_TO_BYTES(sz)); |
- WORDS_TO_BYTES(sz)); |
|
|
Line 242 register word sz; |
|
Line 299 register word sz; |
|
list = ((ptr_t)p); |
list = ((ptr_t)p); |
/* Clear object, advance p to next object in the process */ |
/* Clear object, advance p to next object in the process */ |
q = p + sz; |
q = p + sz; |
p++; /* Skip link field */ |
# ifdef USE_MARK_BYTES |
while (p < q) { |
GC_ASSERT(!(sz & 1) |
|
&& !((word)p & (2 * sizeof(word) - 1))); |
|
p[1] = 0; |
|
p += 2; |
|
while (p < q) { |
|
CLEAR_DOUBLE(p); |
|
p += 2; |
|
} |
|
# else |
|
p++; /* Skip link field */ |
|
while (p < q) { |
*p++ = 0; |
*p++ = 0; |
} |
} |
|
# endif |
} |
} |
word_no += sz; |
word_no += sz; |
} |
} |
# ifdef GATHERSTATS |
COUNT_UPDATE |
GC_mem_found += n_words_found; |
|
# endif |
|
return(list); |
return(list); |
} |
} |
|
|
#ifndef SMALL_CONFIG |
#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
|
|
/* |
/* |
* 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) |
ptr_t GC_reclaim_clear2(hbp, hhdr, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
register ptr_t list; |
register ptr_t list; |
|
COUNT_DECL |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[0]); |
register word *p, *plim; |
register word *p, *plim; |
# ifdef GATHERSTATS |
|
register int n_words_found = 0; |
|
# endif |
|
register word mark_word; |
register word mark_word; |
register int i; |
register int i; |
|
NWORDS_DECL |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
Line 296 register ptr_t list; |
|
Line 361 register ptr_t list; |
|
mark_word >>= 8; |
mark_word >>= 8; |
} |
} |
} |
} |
# ifdef GATHERSTATS |
COUNT_UPDATE |
GC_mem_found += n_words_found; |
|
# endif |
|
return(list); |
return(list); |
# undef DO_OBJ |
# undef DO_OBJ |
} |
} |
Line 307 register ptr_t list; |
|
Line 370 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) |
ptr_t GC_reclaim_clear4(hbp, hhdr, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
register ptr_t list; |
register ptr_t list; |
|
COUNT_DECL |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[0]); |
register word *p, *plim; |
register word *p, *plim; |
# ifdef GATHERSTATS |
|
register int n_words_found = 0; |
|
# endif |
|
register word mark_word; |
register word mark_word; |
|
NWORDS_DECL |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << 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 354 register ptr_t list; |
|
Line 415 register ptr_t list; |
|
# endif |
# endif |
p += WORDSZ; |
p += WORDSZ; |
} |
} |
# ifdef GATHERSTATS |
COUNT_UPDATE |
GC_mem_found += n_words_found; |
|
# endif |
|
return(list); |
return(list); |
# undef DO_OBJ |
# undef DO_OBJ |
} |
} |
|
|
#endif /* !SMALL_CONFIG */ |
#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
|
|
/* 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) |
ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
register hdr * hhdr; |
register hdr * hhdr; |
register ptr_t list; |
register ptr_t list; |
register word sz; |
register word sz; |
|
COUNT_DECL |
{ |
{ |
register int word_no; |
register int word_no = 0; |
register word *p, *plim; |
register word *p, *plim; |
# ifdef GATHERSTATS |
NWORDS_DECL |
register int n_words_found = 0; |
|
# endif |
|
|
|
p = (word *)(hbp->hb_body); |
p = (word *)(hbp->hb_body); |
word_no = HDR_WORDS; |
|
plim = (word *)((((word)hbp) + HBLKSIZE) |
plim = (word *)((((word)hbp) + HBLKSIZE) |
- WORDS_TO_BYTES(sz)); |
- WORDS_TO_BYTES(sz)); |
|
|
Line 393 register word sz; |
|
Line 450 register word sz; |
|
p += sz; |
p += sz; |
word_no += sz; |
word_no += sz; |
} |
} |
# ifdef GATHERSTATS |
COUNT_UPDATE |
GC_mem_found += n_words_found; |
|
# endif |
|
return(list); |
return(list); |
} |
} |
|
|
Line 406 register struct hblk *hbp; /* ptr to current heap bloc |
|
Line 461 register struct hblk *hbp; /* ptr to current heap bloc |
|
register hdr * hhdr; |
register hdr * hhdr; |
register word sz; |
register word sz; |
{ |
{ |
register int word_no; |
register int word_no = 0; |
register word *p, *plim; |
register word *p, *plim; |
# ifdef GATHERSTATS |
# ifdef GATHERSTATS |
register int n_words_found = 0; |
register int n_words_found = 0; |
# endif |
# endif |
|
|
p = (word *)(hbp->hb_body); |
p = (word *)(hbp->hb_body); |
word_no = HDR_WORDS; |
|
plim = (word *)((((word)hbp) + HBLKSIZE) |
plim = (word *)((((word)hbp) + HBLKSIZE) |
- WORDS_TO_BYTES(sz)); |
- WORDS_TO_BYTES(sz)); |
|
|
Line 427 register word sz; |
|
Line 481 register word sz; |
|
} |
} |
} |
} |
|
|
#ifndef SMALL_CONFIG |
#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
/* |
/* |
* 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) |
ptr_t GC_reclaim_uninit2(hbp, hhdr, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
register ptr_t list; |
register ptr_t list; |
|
COUNT_DECL |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[0]); |
register word *p, *plim; |
register word *p, *plim; |
# ifdef GATHERSTATS |
|
register int n_words_found = 0; |
|
# endif |
|
register word mark_word; |
register word mark_word; |
register int i; |
register int i; |
|
NWORDS_DECL |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
Line 466 register ptr_t list; |
|
Line 519 register ptr_t list; |
|
mark_word >>= 8; |
mark_word >>= 8; |
} |
} |
} |
} |
# ifdef GATHERSTATS |
COUNT_UPDATE |
GC_mem_found += n_words_found; |
|
# endif |
|
return(list); |
return(list); |
# undef DO_OBJ |
# undef DO_OBJ |
} |
} |
Line 477 register ptr_t list; |
|
Line 528 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) |
ptr_t GC_reclaim_uninit4(hbp, hhdr, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
register ptr_t list; |
register ptr_t list; |
|
COUNT_DECL |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[0]); |
register word *p, *plim; |
register word *p, *plim; |
# ifdef GATHERSTATS |
|
register int n_words_found = 0; |
|
# endif |
|
register word mark_word; |
register word mark_word; |
|
NWORDS_DECL |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
Line 521 register ptr_t list; |
|
Line 571 register ptr_t list; |
|
# endif |
# endif |
p += WORDSZ; |
p += WORDSZ; |
} |
} |
# ifdef GATHERSTATS |
COUNT_UPDATE |
GC_mem_found += n_words_found; |
|
# endif |
|
return(list); |
return(list); |
# undef DO_OBJ |
# undef DO_OBJ |
} |
} |
|
|
/* 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) |
ptr_t GC_reclaim1(hbp, hhdr, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
register struct hblk *hbp; /* ptr to current heap block */ |
hdr * hhdr; |
hdr * hhdr; |
register ptr_t list; |
register ptr_t list; |
|
COUNT_DECL |
{ |
{ |
register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); |
register word * mark_word_addr = &(hhdr->hb_marks[0]); |
register word *p, *plim; |
register word *p, *plim; |
# ifdef GATHERSTATS |
|
register int n_words_found = 0; |
|
# endif |
|
register word mark_word; |
register word mark_word; |
register int i; |
register int i; |
|
NWORDS_DECL |
# define DO_OBJ(start_displ) \ |
# define DO_OBJ(start_displ) \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
if (!(mark_word & ((word)1 << start_displ))) { \ |
p[start_displ] = (word)list; \ |
p[start_displ] = (word)list; \ |
Line 564 register ptr_t list; |
|
Line 611 register ptr_t list; |
|
mark_word >>= 4; |
mark_word >>= 4; |
} |
} |
} |
} |
# ifdef GATHERSTATS |
COUNT_UPDATE |
GC_mem_found += n_words_found; |
|
# endif |
|
return(list); |
return(list); |
# undef DO_OBJ |
# undef DO_OBJ |
} |
} |
|
|
#endif /* !SMALL_CONFIG */ |
#endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
|
|
/* |
/* |
* Restore unmarked small objects in the block pointed to by hbp |
* Generic procedure to rebuild a free list in hbp. |
* to the appropriate object free list. |
* Also called directly from GC_malloc_many. |
* If entirely empty blocks are to be completely deallocated, then |
|
* caller should perform that check. |
|
*/ |
*/ |
void GC_reclaim_small_nonempty_block(hbp, report_if_found) |
ptr_t GC_reclaim_generic(hbp, hhdr, sz, init, list COUNT_PARAM) |
register struct hblk *hbp; /* ptr to current heap block */ |
struct hblk *hbp; /* ptr to current heap block */ |
int report_if_found; /* Abort if a reclaimable object is found */ |
hdr * hhdr; |
|
GC_bool init; |
|
ptr_t list; |
|
word sz; |
|
COUNT_DECL |
{ |
{ |
hdr * hhdr; |
ptr_t result = list; |
word sz; /* size of objects in current block */ |
|
struct obj_kind * ok; |
|
ptr_t * flh; |
|
int kind; |
|
GC_bool full; |
|
|
|
hhdr = HDR(hbp); |
|
sz = hhdr -> hb_sz; |
|
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no; |
|
kind = hhdr -> hb_obj_kind; |
|
ok = &GC_obj_kinds[kind]; |
|
flh = &(ok -> ok_freelist[sz]); |
|
|
|
if (report_if_found) { |
GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr); |
GC_reclaim_check(hbp, hhdr, sz); |
if (init) { |
} else if (ok -> ok_init) { |
|
switch(sz) { |
switch(sz) { |
# ifndef SMALL_CONFIG |
# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
case 1: |
case 1: |
full = GC_block_nearly_full1(hhdr, 0xffffffffl); |
/* We now issue the hint even if GC_nearly_full returned */ |
if (TRUE == full) goto out; |
/* DONT_KNOW. */ |
if (FALSE == full) GC_write_hint(hbp); |
GC_write_hint(hbp); |
/* In the DONT_KNOW case, we let reclaim fault. */ |
result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); |
*flh = GC_reclaim1(hbp, hhdr, *flh); |
|
break; |
break; |
case 2: |
case 2: |
full = GC_block_nearly_full1(hhdr, 0x55555555l); |
GC_write_hint(hbp); |
if (TRUE == full) goto out; |
result = GC_reclaim_clear2(hbp, hhdr, list COUNT_ARG); |
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_clear2(hbp, hhdr, *flh); |
|
break; |
break; |
case 4: |
case 4: |
full = GC_block_nearly_full1(hhdr, 0x11111111l); |
GC_write_hint(hbp); |
if (TRUE == full) goto out; |
result = GC_reclaim_clear4(hbp, hhdr, list COUNT_ARG); |
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_clear4(hbp, hhdr, *flh); |
|
break; |
break; |
# endif |
# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
default: |
default: |
full = GC_block_nearly_full(hhdr); |
GC_write_hint(hbp); |
if (TRUE == full) goto out; |
result = GC_reclaim_clear(hbp, hhdr, sz, list COUNT_ARG); |
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 |
# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
case 1: |
case 1: |
full = GC_block_nearly_full1(hhdr, 0xffffffffl); |
GC_write_hint(hbp); |
if (TRUE == full) goto out; |
result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); |
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim1(hbp, hhdr, *flh); |
|
break; |
break; |
case 2: |
case 2: |
full = GC_block_nearly_full1(hhdr, 0x55555555l); |
GC_write_hint(hbp); |
if (TRUE == full) goto out; |
result = GC_reclaim_uninit2(hbp, hhdr, list COUNT_ARG); |
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_uninit2(hbp, hhdr, *flh); |
|
break; |
break; |
case 4: |
case 4: |
full = GC_block_nearly_full1(hhdr, 0x11111111l); |
GC_write_hint(hbp); |
if (TRUE == full) goto out; |
result = GC_reclaim_uninit4(hbp, hhdr, list COUNT_ARG); |
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_uninit4(hbp, hhdr, *flh); |
|
break; |
break; |
# endif |
# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
default: |
default: |
full = GC_block_nearly_full(hhdr); |
GC_write_hint(hbp); |
if (TRUE == full) goto out; |
result = GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_ARG); |
if (FALSE == full) GC_write_hint(hbp); |
|
*flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh); |
|
break; |
break; |
} |
} |
} |
} |
out: |
if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr); |
if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(hhdr); |
return result; |
} |
} |
|
|
/* |
/* |
|
* Restore unmarked small objects in the block pointed to by hbp |
|
* to the appropriate object free list. |
|
* If entirely empty blocks are to be completely deallocated, then |
|
* caller should perform that check. |
|
*/ |
|
void GC_reclaim_small_nonempty_block(hbp, report_if_found COUNT_PARAM) |
|
register struct hblk *hbp; /* ptr to current heap block */ |
|
int report_if_found; /* Abort if a reclaimable object is found */ |
|
COUNT_DECL |
|
{ |
|
hdr *hhdr = HDR(hbp); |
|
word sz = hhdr -> hb_sz; |
|
int kind = hhdr -> hb_obj_kind; |
|
struct obj_kind * ok = &GC_obj_kinds[kind]; |
|
ptr_t * flh = &(ok -> ok_freelist[sz]); |
|
|
|
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no; |
|
|
|
if (report_if_found) { |
|
GC_reclaim_check(hbp, hhdr, sz); |
|
} else { |
|
*flh = GC_reclaim_generic(hbp, hhdr, sz, ok -> ok_init, |
|
*flh MEM_FOUND_ADDR); |
|
} |
|
} |
|
|
|
/* |
* Restore an unmarked large object or an entirely empty blocks of small objects |
* Restore an unmarked large object or an entirely empty blocks of small objects |
* 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 |
|
|
* If report_if_found is TRUE, then process any block immediately, and |
* If report_if_found is TRUE, then process any block immediately, and |
* simply report free objects; do not actually reclaim them. |
* simply report free objects; do not actually reclaim them. |
*/ |
*/ |
void GC_reclaim_block(hbp, report_if_found) |
# if defined(__STDC__) || defined(__cplusplus) |
register struct hblk *hbp; /* ptr to current heap block */ |
void GC_reclaim_block(register struct hblk *hbp, word report_if_found) |
word report_if_found; /* Abort if a reclaimable object is found */ |
# else |
|
void GC_reclaim_block(hbp, report_if_found) |
|
register struct hblk *hbp; /* ptr to current heap block */ |
|
word report_if_found; /* Abort if a reclaimable object is found */ |
|
# endif |
{ |
{ |
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 685 word report_if_found; /* Abort if a reclaimable objec |
|
Line 735 word report_if_found; /* Abort if a reclaimable objec |
|
ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; |
ok = &GC_obj_kinds[hhdr -> hb_obj_kind]; |
|
|
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, 0) ) { |
if (report_if_found) { |
if (report_if_found) { |
FOUND_FREE(hbp, HDR_WORDS); |
FOUND_FREE(hbp, 0); |
} else { |
} else { |
|
word blocks = OBJ_SZ_TO_BLOCKS(sz); |
|
if (blocks > 1) { |
|
GC_large_allocd_bytes -= blocks * HBLKSIZE; |
|
} |
# ifdef GATHERSTATS |
# ifdef GATHERSTATS |
GC_mem_found += sz; |
GC_mem_found += sz; |
# endif |
# endif |
Line 698 word report_if_found; /* Abort if a reclaimable objec |
|
Line 752 word report_if_found; /* Abort if a reclaimable objec |
|
} else { |
} else { |
GC_bool empty = GC_block_empty(hhdr); |
GC_bool empty = GC_block_empty(hhdr); |
if (report_if_found) { |
if (report_if_found) { |
GC_reclaim_small_nonempty_block(hbp, (int)report_if_found); |
GC_reclaim_small_nonempty_block(hbp, (int)report_if_found |
|
MEM_FOUND_ADDR); |
} else if (empty) { |
} else if (empty) { |
# ifdef GATHERSTATS |
# ifdef GATHERSTATS |
GC_mem_found += BYTES_TO_WORDS(HBLKSIZE); |
GC_mem_found += BYTES_TO_WORDS(HBLKSIZE); |
# endif |
# endif |
GC_freehblk(hbp); |
GC_freehblk(hbp); |
} else { |
} else if (TRUE != GC_block_nearly_full(hhdr)){ |
/* group of smaller objects, enqueue the real work */ |
/* group of smaller objects, enqueue the real work */ |
rlh = &(ok -> ok_reclaim_list[sz]); |
rlh = &(ok -> ok_reclaim_list[sz]); |
hhdr -> hb_next = *rlh; |
hhdr -> hb_next = *rlh; |
*rlh = hbp; |
*rlh = hbp; |
} |
} /* else not worth salvaging. */ |
|
/* We used to do the nearly_full check later, but we */ |
|
/* already have the right cache context here. Also */ |
|
/* doing it here avoids some silly lock contention in */ |
|
/* GC_malloc_many. */ |
} |
} |
} |
} |
|
|
Line 720 word report_if_found; /* Abort if a reclaimable objec |
|
Line 779 word report_if_found; /* Abort if a reclaimable objec |
|
static size_t number_of_blocks; |
static size_t number_of_blocks; |
static size_t total_bytes; |
static size_t total_bytes; |
|
|
|
#ifdef USE_MARK_BYTES |
|
|
|
/* Return the number of set mark bits in the given header */ |
|
int GC_n_set_marks(hhdr) |
|
hdr * hhdr; |
|
{ |
|
register int result = 0; |
|
register int i; |
|
|
|
for (i = 0; i < MARK_BITS_SZ; i++) { |
|
result += hhdr -> hb_marks[i]; |
|
} |
|
return(result); |
|
} |
|
|
|
#else |
|
|
/* Number of set bits in a word. Not performance critical. */ |
/* Number of set bits in a word. Not performance critical. */ |
static int set_bits(n) |
static int set_bits(n) |
word n; |
word n; |
|
|
return(result); |
return(result); |
} |
} |
|
|
|
#endif /* !USE_MARK_BYTES */ |
|
|
/*ARGSUSED*/ |
/*ARGSUSED*/ |
void GC_print_block_descr(h, dummy) |
# if defined(__STDC__) || defined(__cplusplus) |
struct hblk *h; |
void GC_print_block_descr(struct hblk *h, word dummy) |
word dummy; |
# else |
|
void GC_print_block_descr(h, dummy) |
|
struct hblk *h; |
|
word dummy; |
|
# endif |
{ |
{ |
register hdr * hhdr = HDR(h); |
register hdr * hhdr = HDR(h); |
register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz); |
register size_t bytes = WORDS_TO_BYTES(hhdr -> hb_sz); |
|
|
GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind), |
GC_printf3("(%lu:%lu,%lu)", (unsigned long)(hhdr -> hb_obj_kind), |
(unsigned long)bytes, |
(unsigned long)bytes, |
(unsigned long)(GC_n_set_marks(hhdr))); |
(unsigned long)(GC_n_set_marks(hhdr))); |
bytes += HDR_BYTES + HBLKSIZE-1; |
bytes += HBLKSIZE-1; |
bytes &= ~(HBLKSIZE-1); |
bytes &= ~(HBLKSIZE-1); |
total_bytes += bytes; |
total_bytes += bytes; |
number_of_blocks++; |
number_of_blocks++; |
Line 816 int report_if_found; /* Abort if a GC_reclaimable obj |
|
Line 898 int report_if_found; /* Abort if a GC_reclaimable obj |
|
/* 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)report_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(); |
|
#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 MEM_FOUND_ADDR); |
if (*flh != 0) break; |
if (*flh != 0) break; |
} |
} |
#if 0 |
|
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. |
*/ |
*/ |
Line 894 GC_bool ignore_old; |
|
Line 976 GC_bool ignore_old; |
|
/* It's likely we'll need it this time, too */ |
/* It's likely we'll need it this time, too */ |
/* It's been touched recently, so this */ |
/* It's been touched recently, so this */ |
/* shouldn't trigger paging. */ |
/* shouldn't trigger paging. */ |
GC_reclaim_small_nonempty_block(hbp, FALSE); |
GC_reclaim_small_nonempty_block(hbp, FALSE MEM_FOUND_ADDR); |
} |
} |
} |
} |
} |
} |