version 1.1.1.1, 1999/12/03 07:39:10 |
version 1.7, 2002/07/24 08:00:11 |
|
|
/* |
/* |
* 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 "private/gc_priv.h" |
|
|
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 |
#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) |
|
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) \ |
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 |
|
|
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); |
} |
} |
return(TRUE); |
return(TRUE); |
} |
} |
|
|
# ifdef GATHERSTATS |
/* 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 |
|
#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 |
|
* 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 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 && !USE_MARK_BYTES */ |
|
|
|
/* 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 |
Line 84 register hdr * hhdr; |
|
Line 269 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 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; |
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; |
|
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 107 register word sz; |
|
Line 291 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; |
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, abort_if_found) |
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; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
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))) { \ |
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 170 register ptr_t list; |
|
Line 359 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 181 register ptr_t list; |
|
Line 368 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 COUNT_PARAM) |
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; |
|
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))) { \ |
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 230 register ptr_t list; |
|
Line 413 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, abort_if_found) |
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; |
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; |
|
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)); |
|
|
/* 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 271 register word sz; |
|
Line 448 register word sz; |
|
p += sz; |
p += sz; |
word_no += sz; |
word_no += sz; |
} |
} |
|
COUNT_UPDATE |
|
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 = 0; |
|
register word *p, *plim; |
# ifdef GATHERSTATS |
# ifdef GATHERSTATS |
GC_mem_found += n_words_found; |
register int n_words_found = 0; |
# endif |
# endif |
return(list); |
|
|
p = (word *)(hbp->hb_body); |
|
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 |
#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, abort_if_found) |
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; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
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))) { \ |
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 318 register ptr_t list; |
|
Line 517 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 329 register ptr_t list; |
|
Line 526 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 COUNT_PARAM) |
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; |
|
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))) { \ |
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 375 register ptr_t list; |
|
Line 569 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, abort_if_found) |
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; |
GC_bool abort_if_found; /* Abort if a reclaimable object is found */ |
|
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))) { \ |
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 420 register ptr_t list; |
|
Line 609 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, abort_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 abort_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; |
register word sz; /* size of objects in current block */ |
|
register struct obj_kind * ok; |
|
register ptr_t * flh; |
|
register int kind; |
|
|
|
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]); |
|
GC_write_hint(hbp); |
|
|
|
if (ok -> ok_init) { |
GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr); |
|
GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */); |
|
if (init) { |
switch(sz) { |
switch(sz) { |
# ifndef SMALL_CONFIG |
# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
case 1: |
case 1: |
*flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found); |
/* We now issue the hint even if GC_nearly_full returned */ |
|
/* DONT_KNOW. */ |
|
result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); |
break; |
break; |
case 2: |
case 2: |
*flh = GC_reclaim_clear2(hbp, hhdr, *flh, abort_if_found); |
result = GC_reclaim_clear2(hbp, hhdr, list COUNT_ARG); |
break; |
break; |
case 4: |
case 4: |
*flh = GC_reclaim_clear4(hbp, hhdr, *flh, abort_if_found); |
result = GC_reclaim_clear4(hbp, hhdr, list COUNT_ARG); |
break; |
break; |
# endif |
# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
default: |
default: |
*flh = GC_reclaim_clear(hbp, hhdr, sz, *flh, abort_if_found); |
result = GC_reclaim_clear(hbp, hhdr, sz, list COUNT_ARG); |
break; |
break; |
} |
} |
} else { |
} else { |
|
GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */); |
switch(sz) { |
switch(sz) { |
# ifndef SMALL_CONFIG |
# if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) |
case 1: |
case 1: |
*flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found); |
result = GC_reclaim1(hbp, hhdr, list COUNT_ARG); |
break; |
break; |
case 2: |
case 2: |
*flh = GC_reclaim_uninit2(hbp, hhdr, *flh, abort_if_found); |
result = GC_reclaim_uninit2(hbp, hhdr, list COUNT_ARG); |
break; |
break; |
case 4: |
case 4: |
*flh = GC_reclaim_uninit4(hbp, hhdr, *flh, abort_if_found); |
result = GC_reclaim_uninit4(hbp, hhdr, list COUNT_ARG); |
break; |
break; |
# endif |
# endif /* !SMALL_CONFIG && !USE_MARK_BYTES */ |
default: |
default: |
*flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh, abort_if_found); |
result = GC_reclaim_uninit(hbp, hhdr, sz, list COUNT_ARG); |
break; |
break; |
} |
} |
} |
} |
if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(hhdr); |
if (IS_UNCOLLECTABLE(hhdr -> hb_obj_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 || GC_debugging_started), |
|
*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 |
* 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) |
# 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 abort_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 512 word abort_if_found; /* Abort if a reclaimable object |
|
Line 728 word abort_if_found; /* Abort if a reclaimable object |
|
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) ) { |
FOUND_FREE(hbp, HDR_WORDS); |
if (report_if_found) { |
# ifdef GATHERSTATS |
FOUND_FREE(hbp, 0); |
|
} else { |
|
word blocks = OBJ_SZ_TO_BLOCKS(sz); |
|
if (blocks > 1) { |
|
GC_large_allocd_bytes -= blocks * HBLKSIZE; |
|
} |
|
# 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 |
|
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 541 word abort_if_found; /* Abort if a reclaimable object |
|
Line 769 word abort_if_found; /* Abort if a reclaimable object |
|
/* Routines to gather and print heap block info */ |
/* Routines to gather and print heap block info */ |
/* intended for debugging. Otherwise should be called */ |
/* intended for debugging. Otherwise should be called */ |
/* with lock. */ |
/* with lock. */ |
static size_t number_of_blocks; |
|
static size_t total_bytes; |
|
|
|
|
struct Print_stats |
|
{ |
|
size_t number_of_blocks; |
|
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); |
|
struct Print_stats *ps; |
|
|
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; |
|
number_of_blocks++; |
ps = (struct Print_stats *)dummy; |
|
ps->total_bytes += bytes; |
|
ps->number_of_blocks++; |
} |
} |
|
|
void GC_print_block_list() |
void GC_print_block_list() |
{ |
{ |
|
struct Print_stats pstats; |
|
|
GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n"); |
GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n"); |
number_of_blocks = 0; |
pstats.number_of_blocks = 0; |
total_bytes = 0; |
pstats.total_bytes = 0; |
GC_apply_to_all_blocks(GC_print_block_descr, (word)0); |
GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats); |
GC_printf2("\nblocks = %lu, bytes = %lu\n", |
GC_printf2("\nblocks = %lu, bytes = %lu\n", |
(unsigned long)number_of_blocks, |
(unsigned long)pstats.number_of_blocks, |
(unsigned long)total_bytes); |
(unsigned long)pstats.total_bytes); |
} |
} |
|
|
#endif /* NO_DEBUGGING */ |
#endif /* NO_DEBUGGING */ |
|
|
/* |
/* |
* Do the same thing on the entire heap, after first clearing small object |
* Clear all obj_link pointers in the list of free objects *flp. |
* free lists (if we are not just looking for leaks). |
* Clear *flp. |
|
* This must be done before dropping a list of free gcj-style objects, |
|
* since may otherwise end up with dangling "descriptor" pointers. |
|
* It may help for other pointer-containg objects. |
*/ |
*/ |
void GC_start_reclaim(abort_if_found) |
void GC_clear_fl_links(flp) |
int abort_if_found; /* Abort if a GC_reclaimable object is found */ |
ptr_t *flp; |
{ |
{ |
|
ptr_t next = *flp; |
|
|
|
while (0 != next) { |
|
*flp = 0; |
|
flp = &(obj_link(next)); |
|
next = *flp; |
|
} |
|
} |
|
|
|
/* |
|
* Perform GC_reclaim_block on the entire heap, after first clearing |
|
* small object free lists (if we are not just looking for leaks). |
|
*/ |
|
void GC_start_reclaim(report_if_found) |
|
int report_if_found; /* Abort if a GC_reclaimable object is found */ |
|
{ |
int kind; |
int kind; |
|
|
|
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) |
|
GC_ASSERT(0 == GC_fl_builder_count); |
|
# endif |
/* Clear reclaim- and free-lists */ |
/* Clear reclaim- and free-lists */ |
for (kind = 0; kind < GC_n_kinds; kind++) { |
for (kind = 0; kind < GC_n_kinds; kind++) { |
register ptr_t *fop; |
ptr_t *fop; |
register ptr_t *lim; |
ptr_t *lim; |
register struct hblk ** rlp; |
struct hblk ** rlp; |
register struct hblk ** rlim; |
struct hblk ** rlim; |
register struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list; |
struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list; |
|
GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0); |
|
|
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; |
if (*fop != 0) { |
|
if (should_clobber) { |
|
GC_clear_fl_links(fop); |
|
} else { |
|
*fop = 0; |
|
} |
|
} |
} |
} |
} /* otherwise free list objects are marked, */ |
} /* otherwise free list objects are marked, */ |
/* and its safe to leave them */ |
/* and its safe to leave them */ |
Line 639 int abort_if_found; /* Abort if a GC_reclaimable obje |
|
Line 928 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 defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) |
|
GC_ASSERT(0 == GC_fl_builder_count); |
|
# endif |
|
|
} |
} |
|
|
|
|
|
|
if (rlh == 0) return; /* No blocks of this kind. */ |
if (rlh == 0) return; /* No blocks of this kind. */ |
rlh += sz; |
rlh += sz; |
GC_timerstart(); |
|
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; |
} |
} |
GC_timerstop(); |
|
} |
} |
|
|
/* |
/* |
|
|
* 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 696 GC_bool ignore_old; |
|
Line 992 GC_bool ignore_old; |
|
|
|
GET_TIME(start_time); |
GET_TIME(start_time); |
# endif |
# endif |
|
|
GC_timerstart(); |
|
for (kind = 0; kind < GC_n_kinds; kind++) { |
for (kind = 0; kind < GC_n_kinds; kind++) { |
ok = &(GC_obj_kinds[kind]); |
ok = &(GC_obj_kinds[kind]); |
rlp = ok -> ok_reclaim_list; |
rlp = ok -> ok_reclaim_list; |
Line 714 GC_bool ignore_old; |
|
Line 1009 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); |
} |
} |
} |
} |
} |
} |
} |
} |
GC_timerstop(); |
|
# ifdef PRINTTIMES |
# ifdef PRINTTIMES |
GET_TIME(done_time); |
GET_TIME(done_time); |
GC_printf1("Disposing of reclaim lists took %lu msecs\n", |
GC_printf1("Disposing of reclaim lists took %lu msecs\n", |