version 1.2, 2000/04/10 08:31:36 |
version 1.3, 2001/04/20 07:39:26 |
|
|
* 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-1994 by Xerox Corporation. All rights reserved. |
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. |
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. |
* Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. |
* Copyright (c) 1999-2001 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 |
|
|
* 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 16, 1996 2:30 pm PST */ |
|
|
|
|
|
# ifndef GC_PRIVATE_H |
# ifndef GC_PRIVATE_H |
|
|
# include "gc.h" |
# include "gc.h" |
# endif |
# endif |
|
|
typedef GC_word word; |
# ifndef GC_MARK_H |
typedef GC_signed_word signed_word; |
# include "../gc_mark.h" |
|
# endif |
|
|
# ifndef CONFIG_H |
# ifndef GCCONFIG_H |
# include "gcconfig.h" |
# include "gcconfig.h" |
# endif |
# endif |
|
|
# ifndef HEADERS_H |
typedef GC_word word; |
# include "gc_hdrs.h" |
typedef GC_signed_word signed_word; |
# endif |
|
|
|
typedef int GC_bool; |
typedef int GC_bool; |
# define TRUE 1 |
# define TRUE 1 |
Line 61 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 60 typedef char * ptr_t; /* A generic pointer to which we |
|
/* Preferably identical to caddr_t, if it */ |
/* Preferably identical to caddr_t, if it */ |
/* exists. */ |
/* exists. */ |
|
|
|
# ifndef HEADERS_H |
|
# include "gc_hdrs.h" |
|
# endif |
|
|
#if defined(__STDC__) |
#if defined(__STDC__) |
# include <stdlib.h> |
# include <stdlib.h> |
# if !(defined( sony_news ) ) |
# if !(defined( sony_news ) ) |
Line 74 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 77 typedef char * ptr_t; /* A generic pointer to which we |
|
# define VOLATILE |
# define VOLATILE |
#endif |
#endif |
|
|
#define CONST GC_CONST |
#if 0 /* defined(__GNUC__) doesn't work yet */ |
|
# define EXPECT(expr, outcome) __builtin_expect(expr,outcome) |
|
/* Equivalent to (expr), but predict that usually (expr)==outcome. */ |
|
#else |
|
# define EXPECT(expr, outcome) (expr) |
|
#endif /* __GNUC__ */ |
|
|
#if 0 /* was once defined for AMIGA */ |
# ifndef GC_LOCKS_H |
|
# include "gc_locks.h" |
|
# endif |
|
|
|
# ifdef STACK_GROWS_DOWN |
|
# define COOLER_THAN > |
|
# define HOTTER_THAN < |
|
# define MAKE_COOLER(x,y) if ((word)(x)+(y) > (word)(x)) {(x) += (y);} \ |
|
else {(x) = (word)ONES;} |
|
# define MAKE_HOTTER(x,y) (x) -= (y) |
|
# else |
|
# define COOLER_THAN < |
|
# define HOTTER_THAN > |
|
# define MAKE_COOLER(x,y) if ((word)(x)-(y) < (word)(x)) {(x) -= (y);} else {(x) = 0;} |
|
# define MAKE_HOTTER(x,y) (x) += (y) |
|
# endif |
|
|
|
#if defined(AMIGA) && defined(__SASC) |
# define GC_FAR __far |
# define GC_FAR __far |
#else |
#else |
# define GC_FAR |
# define GC_FAR |
#endif |
#endif |
|
|
|
|
/*********************************/ |
/*********************************/ |
/* */ |
/* */ |
/* Definitions for conservative */ |
/* Definitions for conservative */ |
Line 95 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 121 typedef char * ptr_t; /* A generic pointer to which we |
|
/* */ |
/* */ |
/*********************************/ |
/*********************************/ |
|
|
#define STUBBORN_ALLOC /* Define stubborn allocation primitives */ |
/* #define STUBBORN_ALLOC */ |
#if defined(SRC_M3) || defined(SMALL_CONFIG) |
/* Enable stubborm allocation, and thus a limited */ |
# undef STUBBORN_ALLOC |
/* form of incremental collection w/o dirty bits. */ |
#endif |
|
|
|
|
|
/* #define ALL_INTERIOR_POINTERS */ |
/* #define ALL_INTERIOR_POINTERS */ |
/* Forces all pointers into the interior of an */ |
/* Forces all pointers into the interior of an */ |
/* object to be considered valid. Also causes the */ |
/* object to be considered valid. Also causes the */ |
Line 126 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 150 typedef char * ptr_t; /* A generic pointer to which we |
|
/* touched. */ |
/* touched. */ |
/* If you can easily avoid using this option, do. */ |
/* If you can easily avoid using this option, do. */ |
/* If not, try to keep individual objects small. */ |
/* If not, try to keep individual objects small. */ |
|
/* This is now really controlled at startup, */ |
|
/* through GC_all_interior_pointers. */ |
|
|
#define PRINTSTATS /* Print garbage collection statistics */ |
#define PRINTSTATS /* Print garbage collection statistics */ |
/* For less verbose output, undefine in reclaim.c */ |
/* For less verbose output, undefine in reclaim.c */ |
Line 156 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 182 typedef char * ptr_t; /* A generic pointer to which we |
|
# define GATHERSTATS |
# define GATHERSTATS |
#endif |
#endif |
|
|
#ifdef FINALIZE_ON_DEMAND |
#if defined(PRINTSTATS) || !defined(SMALL_CONFIG) |
# define GC_INVOKE_FINALIZERS() |
# define CONDPRINT /* Print some things if GC_print_stats is set */ |
#else |
|
# define GC_INVOKE_FINALIZERS() (void)GC_invoke_finalizers() |
|
#endif |
#endif |
|
|
|
#define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers() |
|
|
#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */ |
#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */ |
/* free lists are actually maintained. This applies */ |
/* free lists are actually maintained. This applies */ |
/* only to the top level routines in misc.c, not to */ |
/* only to the top level routines in misc.c, not to */ |
Line 173 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 199 typedef char * ptr_t; /* A generic pointer to which we |
|
/* May save significant amounts of space for obj_map */ |
/* May save significant amounts of space for obj_map */ |
/* entries. */ |
/* entries. */ |
|
|
#ifndef OLD_BLOCK_ALLOC |
#if defined(USE_MARK_BYTES) && !defined(ALIGN_DOUBLE) |
/* Macros controlling large block allocation strategy. */ |
# define ALIGN_DOUBLE |
# define EXACT_FIRST /* Make a complete pass through the large object */ |
/* We use one byte for every 2 words, which doesn't allow for */ |
/* free list before splitting a block */ |
/* odd numbered words to have mark bits. */ |
# define PRESERVE_LAST /* Do not divide last allocated heap segment */ |
|
/* unless we would otherwise need to expand the */ |
|
/* heap. */ |
|
#endif |
#endif |
|
|
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */ |
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */ |
Line 187 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 210 typedef char * ptr_t; /* A generic pointer to which we |
|
# define MERGE_SIZES |
# define MERGE_SIZES |
# endif |
# endif |
|
|
#if defined(ALL_INTERIOR_POINTERS) && !defined(DONT_ADD_BYTE_AT_END) |
#if !defined(DONT_ADD_BYTE_AT_END) |
# define ADD_BYTE_AT_END |
# define EXTRA_BYTES GC_all_interior_pointers |
|
#else |
|
# define EXTRA_BYTES 0 |
#endif |
#endif |
|
|
|
|
# ifndef LARGE_CONFIG |
# ifndef LARGE_CONFIG |
# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */ |
# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */ |
/* Must be multiple of largest page size. */ |
/* Must be multiple of largest page size. */ |
# define MAXHINCR 512 /* Maximum heap increment, in blocks */ |
# define MAXHINCR 2048 /* Maximum heap increment, in blocks */ |
# else |
# else |
# define MINHINCR 64 |
# define MINHINCR 64 |
# define MAXHINCR 4096 |
# define MAXHINCR 4096 |
Line 228 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 253 typedef char * ptr_t; /* A generic pointer to which we |
|
* Number of frames and arguments to save in objects allocated by |
* Number of frames and arguments to save in objects allocated by |
* debugging allocator. |
* debugging allocator. |
*/ |
*/ |
# define NFRAMES 6 /* Number of frames to save. Even for */ |
# ifndef SAVE_CALL_COUNT |
|
# define NFRAMES 6 /* Number of frames to save. Even for */ |
/* alignment reasons. */ |
/* alignment reasons. */ |
|
# else |
|
# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1) |
|
# endif |
# define NARGS 2 /* Mumber of arguments to save for each call. */ |
# define NARGS 2 /* Mumber of arguments to save for each call. */ |
|
|
# define NEED_CALLINFO |
# define NEED_CALLINFO |
|
|
/* Fill in the pc and argument information for up to NFRAMES of my */ |
/* Fill in the pc and argument information for up to NFRAMES of my */ |
/* callers. Ignore my frame and my callers frame. */ |
/* callers. Ignore my frame and my callers frame. */ |
void GC_save_callers (/* struct callinfo info[NFRAMES] */); |
struct callinfo; |
|
void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES])); |
|
|
|
void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); |
|
|
void GC_print_callers (/* struct callinfo info[NFRAMES] */); |
|
|
|
#else |
#else |
|
|
# ifdef GC_ADD_CALLER |
# ifdef GC_ADD_CALLER |
Line 252 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 282 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
|
|
#ifdef NEED_CALLINFO |
#ifdef NEED_CALLINFO |
struct callinfo { |
struct callinfo { |
word ci_pc; |
word ci_pc; /* Caller, not callee, pc */ |
# if NARGS > 0 |
# if NARGS > 0 |
word ci_arg[NARGS]; /* bit-wise complement to avoid retention */ |
word ci_arg[NARGS]; /* bit-wise complement to avoid retention */ |
# endif |
# endif |
Line 281 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 311 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \ |
# define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \ |
+ (double) (a.tv_usec - b.tv_usec) / 1000.0) |
+ (double) (a.tv_usec - b.tv_usec) / 1000.0) |
#else /* !BSD_TIME */ |
#else /* !BSD_TIME */ |
|
# if defined(MSWIN32) || defined(MSWINCE) |
|
# include <windows.h> |
|
# include <winbase.h> |
|
# define CLOCK_TYPE DWORD |
|
# define GET_TIME(x) x = GetTickCount() |
|
# define MS_TIME_DIFF(a,b) ((long)((a)-(b))) |
|
# else /* !MSWIN32, !MSWINCE, !BSD_TIME */ |
# include <time.h> |
# include <time.h> |
# if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4) |
# if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4) |
clock_t clock(); /* Not in time.h, where it belongs */ |
clock_t clock(); /* Not in time.h, where it belongs */ |
Line 306 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 343 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# define GET_TIME(x) x = clock() |
# define GET_TIME(x) x = clock() |
# define MS_TIME_DIFF(a,b) ((unsigned long) \ |
# define MS_TIME_DIFF(a,b) ((unsigned long) \ |
(1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC)) |
(1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC)) |
|
# endif /* !MSWIN32 */ |
#endif /* !BSD_TIME */ |
#endif /* !BSD_TIME */ |
|
|
/* We use bzero and bcopy internally. They may not be available. */ |
/* We use bzero and bcopy internally. They may not be available. */ |
Line 325 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 363 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# include <string.h> |
# include <string.h> |
# define BCOPY_EXISTS |
# define BCOPY_EXISTS |
# endif |
# endif |
|
# if defined(MACOSX) |
|
# define BCOPY_EXISTS |
|
# endif |
|
|
# ifndef BCOPY_EXISTS |
# ifndef BCOPY_EXISTS |
# include <string.h> |
# include <string.h> |
Line 342 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 383 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
/* GET_MEM is currently not assumed to retrieve 0 filled space, */ |
/* GET_MEM is currently not assumed to retrieve 0 filled space, */ |
/* though we should perhaps take advantage of the case in which */ |
/* though we should perhaps take advantage of the case in which */ |
/* does. */ |
/* does. */ |
|
struct hblk; /* See below. */ |
# ifdef PCR |
# ifdef PCR |
char * real_malloc(); |
char * real_malloc(); |
# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \ |
# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \ |
Line 353 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 395 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
+ GC_page_size) \ |
+ GC_page_size) \ |
+ GC_page_size-1) |
+ GC_page_size-1) |
# else |
# else |
# if defined(AMIGA) || defined(NEXT) || defined(MACOSX) || defined(DOS4GW) |
# if defined(NEXT) || defined(MACOSX) || defined(DOS4GW) || \ |
|
(defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) |
# define GET_MEM(bytes) HBLKPTR((size_t) \ |
# define GET_MEM(bytes) HBLKPTR((size_t) \ |
calloc(1, (size_t)bytes + GC_page_size) \ |
calloc(1, (size_t)bytes + GC_page_size) \ |
+ GC_page_size-1) |
+ GC_page_size-1) |
Line 374 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 417 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
NewPtrClear(bytes + GC_page_size) + GC_page_size-1) |
NewPtrClear(bytes + GC_page_size) + GC_page_size-1) |
# endif |
# endif |
# else |
# else |
extern ptr_t GC_unix_get_mem(); |
# ifdef MSWINCE |
# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes) |
extern ptr_t GC_wince_get_mem(); |
|
# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes) |
|
# else |
|
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC) |
|
extern void *GC_amiga_get_mem(size_t size); |
|
define GET_MEM(bytes) HBLKPTR((size_t) \ |
|
GC_amiga_get_mem((size_t)bytes + GC_page_size) \ |
|
+ GC_page_size-1) |
|
# else |
|
extern ptr_t GC_unix_get_mem(); |
|
# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes) |
|
# endif |
|
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
|
|
/* |
|
* Mutual exclusion between allocator/collector routines. |
|
* Needed if there is more than one allocator thread. |
|
* FASTLOCK() is assumed to try to acquire the lock in a cheap and |
|
* dirty way that is acceptable for a few instructions, e.g. by |
|
* inhibiting preemption. This is assumed to have succeeded only |
|
* if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE. |
|
* FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED(). |
|
* If signals cannot be tolerated with the FASTLOCK held, then |
|
* FASTLOCK should disable signals. The code executed under |
|
* FASTLOCK is otherwise immune to interruption, provided it is |
|
* not restarted. |
|
* DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK |
|
* and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK. |
|
* (There is currently no equivalent for FASTLOCK.) |
|
*/ |
|
# ifdef THREADS |
|
# ifdef PCR_OBSOLETE /* Faster, but broken with multiple lwp's */ |
|
# include "th/PCR_Th.h" |
|
# include "th/PCR_ThCrSec.h" |
|
extern struct PCR_Th_MLRep GC_allocate_ml; |
|
# define DCL_LOCK_STATE PCR_sigset_t GC_old_sig_mask |
|
# define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) |
|
# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) |
|
# define FASTLOCK() PCR_ThCrSec_EnterSys() |
|
/* Here we cheat (a lot): */ |
|
# define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0) |
|
/* TRUE if nobody currently holds the lock */ |
|
# define FASTUNLOCK() PCR_ThCrSec_ExitSys() |
|
# endif |
|
# ifdef PCR |
|
# include <base/PCR_Base.h> |
|
# include <th/PCR_Th.h> |
|
extern PCR_Th_ML GC_allocate_ml; |
|
# define DCL_LOCK_STATE \ |
|
PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask |
|
# define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) |
|
# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) |
|
# define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml)) |
|
# define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay) |
|
# define FASTUNLOCK() {\ |
|
if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); } |
|
# endif |
|
# ifdef SRC_M3 |
|
extern word RT0u__inCritical; |
|
# define LOCK() RT0u__inCritical++ |
|
# define UNLOCK() RT0u__inCritical-- |
|
# endif |
|
# ifdef SOLARIS_THREADS |
|
# include <thread.h> |
|
# include <signal.h> |
|
extern mutex_t GC_allocate_ml; |
|
# define LOCK() mutex_lock(&GC_allocate_ml); |
|
# define UNLOCK() mutex_unlock(&GC_allocate_ml); |
|
# endif |
|
# ifdef LINUX_THREADS |
|
# include <pthread.h> |
|
# if defined(I386) |
|
inline static int GC_test_and_set(volatile unsigned int *addr) { |
|
int oldval; |
|
/* Note: the "xchg" instruction does not need a "lock" prefix */ |
|
__asm__ __volatile__("xchgl %0, %1" |
|
: "=r"(oldval), "=m"(*(addr)) |
|
: "0"(1), "m"(*(addr))); |
|
return oldval; |
|
} |
|
# else |
|
# if defined(POWERPC) |
|
inline static int GC_test_and_set(volatile unsigned int *addr) { |
|
int oldval; |
|
int temp = 1; // locked value |
|
|
|
__asm__ __volatile__( |
|
"1:\tlwarx %0,0,%3\n" // load and reserve |
|
"\tcmpwi %0, 0\n" // if load is |
|
"\tbne 2f\n" // non-zero, return already set |
|
"\tstwcx. %2,0,%1\n" // else store conditional |
|
"\tbne- 1b\n" // retry if lost reservation |
|
"2:\t\n" // oldval is zero if we set |
|
: "=&r"(oldval), "=p"(addr) |
|
: "r"(temp), "1"(addr) |
|
: "memory"); |
|
return (int)oldval; |
|
} |
|
# else |
|
# ifdef ALPHA |
|
inline static int GC_test_and_set(volatile unsigned int * |
|
addr) |
|
{ |
|
unsigned long oldvalue; |
|
unsigned long temp; |
|
|
|
__asm__ __volatile__( |
|
"1: ldl_l %0,%1\n" |
|
" and %0,%3,%2\n" |
|
" bne %2,2f\n" |
|
" xor %0,%3,%0\n" |
|
" stl_c %0,%1\n" |
|
" beq %0,3f\n" |
|
" mb\n" |
|
"2:\n" |
|
".section .text2,\"ax\"\n" |
|
"3: br 1b\n" |
|
".previous" |
|
:"=&r" (temp), "=m" (*addr), "=&r" |
|
(oldvalue) |
|
:"Ir" (1), "m" (*addr)); |
|
|
|
return oldvalue; |
|
} |
|
# else |
|
-- > Need implementation of GC_test_and_set() |
|
# endif |
|
# endif |
|
# endif |
|
inline static void GC_clear(volatile unsigned int *addr) { |
|
*(addr) = 0; |
|
} |
|
|
|
extern volatile unsigned int GC_allocate_lock; |
|
/* This is not a mutex because mutexes that obey the (optional) */ |
|
/* POSIX scheduling rules are subject to convoys in high contention */ |
|
/* applications. This is basically a spin lock. */ |
|
extern pthread_t GC_lock_holder; |
|
extern void GC_lock(void); |
|
/* Allocation lock holder. Only set if acquired by client through */ |
|
/* GC_call_with_alloc_lock. */ |
|
# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self() |
|
# define NO_THREAD (pthread_t)(-1) |
|
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD |
|
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) |
|
# define LOCK() \ |
|
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } |
|
# define UNLOCK() \ |
|
GC_clear(&GC_allocate_lock) |
|
extern GC_bool GC_collecting; |
|
# define ENTER_GC() \ |
|
{ \ |
|
GC_collecting = 1; \ |
|
} |
|
# define EXIT_GC() GC_collecting = 0; |
|
# endif /* LINUX_THREADS */ |
|
# if defined(HPUX_THREADS) |
|
# include <pthread.h> |
|
extern pthread_mutex_t GC_allocate_ml; |
|
# define LOCK() pthread_mutex_lock(&GC_allocate_ml) |
|
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) |
|
# endif |
|
# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) |
|
/* This may also eventually be appropriate for HPUX_THREADS */ |
|
# include <pthread.h> |
|
# ifndef HPUX_THREADS |
|
/* This probably should never be included, but I can't test */ |
|
/* on Irix anymore. */ |
|
# include <mutex.h> |
|
# endif |
|
|
|
# ifndef HPUX_THREADS |
|
# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ |
|
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700 |
|
# define GC_test_and_set(addr, v) test_and_set(addr,v) |
|
# else |
|
# define GC_test_and_set(addr, v) __test_and_set(addr,v) |
|
# endif |
|
# else |
|
/* I couldn't find a way to do this inline on HP/UX */ |
|
# endif |
|
extern unsigned long GC_allocate_lock; |
|
/* This is not a mutex because mutexes that obey the (optional) */ |
|
/* POSIX scheduling rules are subject to convoys in high contention */ |
|
/* applications. This is basically a spin lock. */ |
|
extern pthread_t GC_lock_holder; |
|
extern void GC_lock(void); |
|
/* Allocation lock holder. Only set if acquired by client through */ |
|
/* GC_call_with_alloc_lock. */ |
|
# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self() |
|
# define NO_THREAD (pthread_t)(-1) |
|
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD |
|
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) |
|
# ifdef HPUX_THREADS |
|
# define LOCK() { if (!GC_test_and_clear(&GC_allocate_lock)) GC_lock(); } |
|
/* The following is INCORRECT, since the memory model is too weak. */ |
|
# define UNLOCK() { GC_noop1(&GC_allocate_lock); \ |
|
*(volatile unsigned long *)(&GC_allocate_lock) = 1; } |
|
# else |
|
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); } |
|
# if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64)) \ |
|
&& defined(_COMPILER_VERSION) && _COMPILER_VERSION >= 700 |
|
# define UNLOCK() __lock_release(&GC_allocate_lock) |
|
# else |
|
/* The function call in the following should prevent the */ |
|
/* compiler from moving assignments to below the UNLOCK. */ |
|
/* This is probably not necessary for ucode or gcc 2.8. */ |
|
/* It may be necessary for Ragnarok and future gcc */ |
|
/* versions. */ |
|
# define UNLOCK() { GC_noop1(&GC_allocate_lock); \ |
|
*(volatile unsigned long *)(&GC_allocate_lock) = 0; } |
|
# endif |
|
# endif |
|
extern GC_bool GC_collecting; |
|
# define ENTER_GC() \ |
|
{ \ |
|
GC_collecting = 1; \ |
|
} |
|
# define EXIT_GC() GC_collecting = 0; |
|
# endif /* IRIX_THREADS || IRIX_JDK_THREADS */ |
|
# ifdef WIN32_THREADS |
|
# include <windows.h> |
|
GC_API CRITICAL_SECTION GC_allocate_ml; |
|
# define LOCK() EnterCriticalSection(&GC_allocate_ml); |
|
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml); |
|
# endif |
|
# ifndef SET_LOCK_HOLDER |
|
# define SET_LOCK_HOLDER() |
|
# define UNSET_LOCK_HOLDER() |
|
# define I_HOLD_LOCK() FALSE |
|
/* Used on platforms were locks can be reacquired, */ |
|
/* so it doesn't matter if we lie. */ |
|
# endif |
|
# else |
|
# define LOCK() |
|
# define UNLOCK() |
|
# endif |
|
# ifndef SET_LOCK_HOLDER |
|
# define SET_LOCK_HOLDER() |
|
# define UNSET_LOCK_HOLDER() |
|
# define I_HOLD_LOCK() FALSE |
|
/* Used on platforms were locks can be reacquired, */ |
|
/* so it doesn't matter if we lie. */ |
|
# endif |
|
# ifndef ENTER_GC |
|
# define ENTER_GC() |
|
# define EXIT_GC() |
|
# endif |
|
|
|
# ifndef DCL_LOCK_STATE |
|
# define DCL_LOCK_STATE |
|
# endif |
|
# ifndef FASTLOCK |
|
# define FASTLOCK() LOCK() |
|
# define FASTLOCK_SUCCEEDED() TRUE |
|
# define FASTUNLOCK() UNLOCK() |
|
# endif |
|
|
|
/* Delay any interrupts or signals that may abort this thread. Data */ |
/* Delay any interrupts or signals that may abort this thread. Data */ |
/* structures are in a consistent state outside this pair of calls. */ |
/* structures are in a consistent state outside this pair of calls. */ |
/* ANSI C allows both to be empty (though the standard isn't very */ |
/* ANSI C allows both to be empty (though the standard isn't very */ |
|
|
PCR_Th_SetSigMask(&GC_old_sig_mask, NIL) |
PCR_Th_SetSigMask(&GC_old_sig_mask, NIL) |
# else |
# else |
# if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \ |
# if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \ |
|| defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \ |
|| defined(MSWIN32) || defined(MSWINCE) || defined(MACOS) \ |
|| defined(NO_SIGNALS) || defined(IRIX_THREADS) \ |
|| defined(DJGPP) || defined(NO_SIGNALS) || defined(IRIX_THREADS) \ |
|| defined(IRIX_JDK_THREADS) || defined(LINUX_THREADS) |
|| defined(LINUX_THREADS) |
/* Also useful for debugging. */ |
/* Also useful for debugging. */ |
/* Should probably use thr_sigsetmask for SOLARIS_THREADS. */ |
/* Should probably use thr_sigsetmask for SOLARIS_THREADS. */ |
# define DISABLE_SIGNALS() |
# define DISABLE_SIGNALS() |
|
|
# else |
# else |
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ |
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ |
|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \ |
|| defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) |
|| defined(HPUX_THREADS) |
void GC_stop_world(); |
void GC_stop_world(); |
void GC_start_world(); |
void GC_start_world(); |
# define STOP_WORLD() GC_stop_world() |
# define STOP_WORLD() GC_stop_world() |
|
|
# define WARN(msg,arg) (*GC_current_warn_proc)(msg, (GC_word)(arg)) |
# define WARN(msg,arg) (*GC_current_warn_proc)(msg, (GC_word)(arg)) |
extern GC_warn_proc GC_current_warn_proc; |
extern GC_warn_proc GC_current_warn_proc; |
|
|
|
/* Get environment entry */ |
|
#if !defined(NO_GETENV) |
|
# define GETENV(name) getenv(name) |
|
#else |
|
# define GETENV(name) 0 |
|
#endif |
|
|
/*********************************/ |
/*********************************/ |
/* */ |
/* */ |
/* Word-size-dependent defines */ |
/* Word-size-dependent defines */ |
Line 733 extern GC_warn_proc GC_current_warn_proc; |
|
Line 551 extern GC_warn_proc GC_current_warn_proc; |
|
#define WORDSZ ((word)CPP_WORDSZ) |
#define WORDSZ ((word)CPP_WORDSZ) |
#define SIGNB ((word)1 << (WORDSZ-1)) |
#define SIGNB ((word)1 << (WORDSZ-1)) |
#define BYTES_PER_WORD ((word)(sizeof (word))) |
#define BYTES_PER_WORD ((word)(sizeof (word))) |
#define ONES ((word)(-1)) |
#define ONES ((word)(signed_word)(-1)) |
#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */ |
#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */ |
|
|
/*********************/ |
/*********************/ |
Line 786 extern GC_warn_proc GC_current_warn_proc; |
|
Line 604 extern GC_warn_proc GC_current_warn_proc; |
|
/* max size objects supported by freelist (larger objects may be */ |
/* max size objects supported by freelist (larger objects may be */ |
/* allocated, but less efficiently) */ |
/* allocated, but less efficiently) */ |
|
|
|
#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2) |
|
#define MAXOBJBYTES ((word)CPP_MAXOBJBYTES) |
#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_HBLKSIZE/2) |
#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_HBLKSIZE/2) |
#define MAXOBJSZ ((word)CPP_MAXOBJSZ) |
#define MAXOBJSZ ((word)CPP_MAXOBJSZ) |
|
|
Line 806 extern GC_warn_proc GC_current_warn_proc; |
|
Line 626 extern GC_warn_proc GC_current_warn_proc; |
|
# define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1)) |
# define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1)) |
|
|
/* Round up byte allocation requests to integral number of words, etc. */ |
/* Round up byte allocation requests to integral number of words, etc. */ |
# ifdef ADD_BYTE_AT_END |
# define ROUNDED_UP_WORDS(n) \ |
# define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1)) |
BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1 + EXTRA_BYTES)) |
# ifdef ALIGN_DOUBLE |
# ifdef ALIGN_DOUBLE |
# define ALIGNED_WORDS(n) (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2)) & ~1) |
|
# else |
|
# define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n) |
|
# endif |
|
# define SMALL_OBJ(bytes) ((bytes) < WORDS_TO_BYTES(MAXOBJSZ)) |
|
# define ADD_SLOP(bytes) ((bytes)+1) |
|
# else |
|
# define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1)) |
|
# ifdef ALIGN_DOUBLE |
|
# define ALIGNED_WORDS(n) \ |
# define ALIGNED_WORDS(n) \ |
(BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1) & ~1) |
(BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1 + EXTRA_BYTES) & ~1) |
# else |
# else |
# define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n) |
# define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n) |
|
# endif |
|
# define SMALL_OBJ(bytes) ((bytes) < (MAXOBJBYTES -EXTRA_BYTES)) |
|
# define ADD_SLOP(bytes) ((bytes) + EXTRA_BYTES) |
|
# ifndef MIN_WORDS |
|
/* MIN_WORDS is the size of the smallest allocated object. */ |
|
/* 1 and 2 are the only valid values. */ |
|
/* 2 must be used if: */ |
|
/* - GC_gcj_malloc can be used for objects of requested */ |
|
/* size smaller than 2 words, or */ |
|
/* - USE_MARK_BYTES is defined. */ |
|
# if defined(USE_MARK_BYTES) || defined(GC_GCJ_SUPPORT) |
|
# define MIN_WORDS 2 /* Smallest allocated object. */ |
|
# else |
|
# define MIN_WORDS 1 |
# endif |
# endif |
# define SMALL_OBJ(bytes) ((bytes) <= WORDS_TO_BYTES(MAXOBJSZ)) |
|
# define ADD_SLOP(bytes) (bytes) |
|
# endif |
# endif |
|
|
|
|
Line 835 extern GC_warn_proc GC_current_warn_proc; |
|
Line 658 extern GC_warn_proc GC_current_warn_proc; |
|
*/ |
*/ |
|
|
# ifdef LARGE_CONFIG |
# ifdef LARGE_CONFIG |
# define LOG_PHT_ENTRIES 17 |
# define LOG_PHT_ENTRIES 19 /* Collisions likely at 512K blocks, */ |
|
/* which is >= 2GB. Each table takes */ |
|
/* 64KB. */ |
# else |
# else |
# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */ |
# ifdef SMALL_CONFIG |
/* to more than 16K hblks = 64MB. */ |
# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */ |
/* Each hash table occupies 2K bytes. */ |
/* to more than 16K hblks = 64MB. */ |
|
/* Each hash table occupies 2K bytes. */ |
|
# else /* default "medium" configuration */ |
|
# define LOG_PHT_ENTRIES 16 /* Collisions are likely if heap grows */ |
|
/* to more than 16K hblks >= 256MB. */ |
|
/* Each hash table occupies 8K bytes. */ |
|
# endif |
# endif |
# endif |
# define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES) |
# define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES) |
# define PHT_SIZE (PHT_ENTRIES >> LOGWL) |
# define PHT_SIZE (PHT_ENTRIES >> LOGWL) |
Line 853 typedef word page_hash_table[PHT_SIZE]; |
|
Line 684 typedef word page_hash_table[PHT_SIZE]; |
|
(bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index) |
(bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index) |
# define clear_pht_entry_from_index(bl, index) \ |
# define clear_pht_entry_from_index(bl, index) \ |
(bl)[divWORDSZ(index)] &= ~((word)1 << modWORDSZ(index)) |
(bl)[divWORDSZ(index)] &= ~((word)1 << modWORDSZ(index)) |
|
/* And a dumb but thread-safe version of set_pht_entry_from_index. */ |
|
/* This sets (many) extra bits. */ |
|
# define set_pht_entry_from_index_safe(bl, index) \ |
|
(bl)[divWORDSZ(index)] = ONES |
|
|
|
|
|
|
Line 865 typedef word page_hash_table[PHT_SIZE]; |
|
Line 700 typedef word page_hash_table[PHT_SIZE]; |
|
/* heap block header */ |
/* heap block header */ |
#define HBLKMASK (HBLKSIZE-1) |
#define HBLKMASK (HBLKSIZE-1) |
|
|
#define BITS_PER_HBLK (HBLKSIZE * 8) |
#define BITS_PER_HBLK (CPP_HBLKSIZE * 8) |
|
|
#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/CPP_WORDSZ) |
#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/CPP_WORDSZ) |
/* upper bound */ |
/* upper bound */ |
/* We allocate 1 bit/word. Only the first word */ |
/* We allocate 1 bit/word, unless USE_MARK_BYTES */ |
|
/* is defined. Only the first word */ |
/* in each object is actually marked. */ |
/* in each object is actually marked. */ |
|
|
# ifdef ALIGN_DOUBLE |
# ifdef USE_MARK_BYTES |
# define MARK_BITS_SZ (((MARK_BITS_PER_HBLK + 2*CPP_WORDSZ - 1) \ |
# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/2) |
/ (2*CPP_WORDSZ))*2) |
/* Unlike the other case, this is in units of bytes. */ |
|
/* We actually allocate only every second mark bit, since we */ |
|
/* force all objects to be doubleword aligned. */ |
|
/* However, each mark bit is allocated as a byte. */ |
# else |
# else |
# define MARK_BITS_SZ ((MARK_BITS_PER_HBLK + CPP_WORDSZ - 1)/CPP_WORDSZ) |
# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ) |
# endif |
# endif |
/* Upper bound on number of mark words per heap block */ |
|
|
|
|
/* We maintain layout maps for heap blocks containing objects of a given */ |
|
/* size. Each entry in this map describes a byte offset and has the */ |
|
/* following type. */ |
|
typedef unsigned char map_entry_type; |
|
|
struct hblkhdr { |
struct hblkhdr { |
word hb_sz; /* If in use, size in words, of objects in the block. */ |
word hb_sz; /* If in use, size in words, of objects in the block. */ |
/* if free, the size in bytes of the whole block */ |
/* if free, the size in bytes of the whole block */ |
Line 889 struct hblkhdr { |
|
Line 732 struct hblkhdr { |
|
struct hblk * hb_prev; /* Backwards link for free list. */ |
struct hblk * hb_prev; /* Backwards link for free list. */ |
word hb_descr; /* object descriptor for marking. See */ |
word hb_descr; /* object descriptor for marking. See */ |
/* mark.h. */ |
/* mark.h. */ |
char* hb_map; /* A pointer to a pointer validity map of the block. */ |
map_entry_type * hb_map; |
|
/* A pointer to a pointer validity map of the block. */ |
/* See GC_obj_map. */ |
/* See GC_obj_map. */ |
/* Valid for all blocks with headers. */ |
/* Valid for all blocks with headers. */ |
/* Free blocks point to GC_invalid_map. */ |
/* Free blocks point to GC_invalid_map. */ |
Line 911 struct hblkhdr { |
|
Line 755 struct hblkhdr { |
|
/* Value of GC_gc_no when block was */ |
/* Value of GC_gc_no when block was */ |
/* last allocated or swept. May wrap. */ |
/* last allocated or swept. May wrap. */ |
/* For a free block, this is maintained */ |
/* For a free block, this is maintained */ |
/* unly for USE_MUNMAP, and indicates */ |
/* only for USE_MUNMAP, and indicates */ |
/* when the header was allocated, or */ |
/* when the header was allocated, or */ |
/* when the size of the block last */ |
/* when the size of the block last */ |
/* changed. */ |
/* changed. */ |
word hb_marks[MARK_BITS_SZ]; |
# ifdef USE_MARK_BYTES |
|
union { |
|
char _hb_marks[MARK_BITS_SZ]; |
|
/* The i'th byte is 1 if the object */ |
|
/* starting at word 2i is marked, 0 o.w. */ |
|
word dummy; /* Force word alignment of mark bytes. */ |
|
} _mark_byte_union; |
|
# define hb_marks _mark_byte_union._hb_marks |
|
# else |
|
word hb_marks[MARK_BITS_SZ]; |
/* Bit i in the array refers to the */ |
/* Bit i in the array refers to the */ |
/* object starting at the ith word (header */ |
/* object starting at the ith word (header */ |
/* INCLUDED) in the heap block. */ |
/* INCLUDED) in the heap block. */ |
Line 923 struct hblkhdr { |
|
Line 776 struct hblkhdr { |
|
/* Unused bits are invalid, and are */ |
/* Unused bits are invalid, and are */ |
/* occasionally set, e.g for uncollectable */ |
/* occasionally set, e.g for uncollectable */ |
/* objects. */ |
/* objects. */ |
|
# endif /* !USE_MARK_BYTES */ |
}; |
}; |
|
|
/* heap block body */ |
/* heap block body */ |
|
|
# define DISCARD_WORDS 0 |
# define BODY_SZ (HBLKSIZE/sizeof(word)) |
/* Number of words to be dropped at the beginning of each block */ |
|
/* Must be a multiple of WORDSZ. May reasonably be nonzero */ |
|
/* on machines that don't guarantee longword alignment of */ |
|
/* pointers, so that the number of false hits is minimized. */ |
|
/* 0 and WORDSZ are probably the only reasonable values. */ |
|
|
|
# define BODY_SZ ((HBLKSIZE-WORDS_TO_BYTES(DISCARD_WORDS))/sizeof(word)) |
|
|
|
struct hblk { |
struct hblk { |
# if (DISCARD_WORDS != 0) |
# if 0 /* DISCARDWORDS no longer supported */ |
word garbage[DISCARD_WORDS]; |
word garbage[DISCARD_WORDS]; |
# endif |
# endif |
word hb_body[BODY_SZ]; |
word hb_body[BODY_SZ]; |
}; |
}; |
|
|
# define HDR_WORDS ((word)DISCARD_WORDS) |
|
# define HDR_BYTES ((word)WORDS_TO_BYTES(DISCARD_WORDS)) |
|
|
|
# define OBJ_SZ_TO_BLOCKS(sz) \ |
# define OBJ_SZ_TO_BLOCKS(sz) \ |
divHBLKSZ(HDR_BYTES + WORDS_TO_BYTES(sz) + HBLKSIZE-1) |
divHBLKSZ(WORDS_TO_BYTES(sz) + HBLKSIZE-1) |
/* Size of block (in units of HBLKSIZE) needed to hold objects of */ |
/* Size of block (in units of HBLKSIZE) needed to hold objects of */ |
/* given sz (in words). */ |
/* given sz (in words). */ |
|
|
/* Object free list link */ |
/* Object free list link */ |
# define obj_link(p) (*(ptr_t *)(p)) |
# define obj_link(p) (*(ptr_t *)(p)) |
|
|
/* The type of mark procedures. This really belongs in gc_mark.h. */ |
|
/* But we put it here, so that we can avoid scanning the mark proc */ |
|
/* table. */ |
|
typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr, |
|
mark_stack_limit, env */); |
|
# define LOG_MAX_MARK_PROCS 6 |
# define LOG_MAX_MARK_PROCS 6 |
# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) |
# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) |
|
|
Line 972 typedef struct ms_entry * (*mark_proc)(/* word * addr, |
|
Line 811 typedef struct ms_entry * (*mark_proc)(/* word * addr, |
|
# ifdef PCR |
# ifdef PCR |
# define MAX_ROOT_SETS 1024 |
# define MAX_ROOT_SETS 1024 |
# else |
# else |
# ifdef MSWIN32 |
# if defined(MSWIN32) || defined(MSWINCE) |
# define MAX_ROOT_SETS 512 |
# define MAX_ROOT_SETS 1024 |
/* Under NT, we add only written pages, which can result */ |
/* Under NT, we add only written pages, which can result */ |
/* in many small root sets. */ |
/* in many small root sets. */ |
# else |
# else |
# define MAX_ROOT_SETS 64 |
# define MAX_ROOT_SETS 256 |
# endif |
# endif |
# endif |
# endif |
# endif |
# endif |
Line 1000 struct exclusion { |
|
Line 839 struct exclusion { |
|
struct roots { |
struct roots { |
ptr_t r_start; |
ptr_t r_start; |
ptr_t r_end; |
ptr_t r_end; |
# ifndef MSWIN32 |
# if !defined(MSWIN32) && !defined(MSWINCE) |
struct roots * r_next; |
struct roots * r_next; |
# endif |
# endif |
GC_bool r_tmp; |
GC_bool r_tmp; |
/* Delete before registering new dynamic libraries */ |
/* Delete before registering new dynamic libraries */ |
}; |
}; |
|
|
#ifndef MSWIN32 |
#if !defined(MSWIN32) && !defined(MSWINCE) |
/* Size of hash table index to roots. */ |
/* Size of hash table index to roots. */ |
# define LOG_RT_SIZE 6 |
# define LOG_RT_SIZE 6 |
# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */ |
# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */ |
|
|
struct _GC_arrays { |
struct _GC_arrays { |
word _heapsize; |
word _heapsize; |
word _max_heapsize; |
word _max_heapsize; |
|
word _requested_heapsize; /* Heap size due to explicit expansion */ |
ptr_t _last_heap_addr; |
ptr_t _last_heap_addr; |
ptr_t _prev_heap_addr; |
ptr_t _prev_heap_addr; |
word _large_free_bytes; |
word _large_free_bytes; |
/* Total bytes contained in blocks on large object free */ |
/* Total bytes contained in blocks on large object free */ |
/* list. */ |
/* list. */ |
|
word _large_allocd_bytes; |
|
/* Total number of bytes in allocated large objects blocks. */ |
|
/* For the purposes of this counter and the next one only, a */ |
|
/* large object is one that occupies a block of at least */ |
|
/* 2*HBLKSIZE. */ |
|
word _max_large_allocd_bytes; |
|
/* Maximum number of bytes that were ever allocated in */ |
|
/* large object blocks. This is used to help decide when it */ |
|
/* is safe to split up a large block. */ |
word _words_allocd_before_gc; |
word _words_allocd_before_gc; |
/* Number of words allocated before this */ |
/* Number of words allocated before this */ |
/* collection cycle. */ |
/* collection cycle. */ |
word _words_allocd; |
# ifndef SEPARATE_GLOBALS |
|
word _words_allocd; |
/* Number of words allocated during this collection cycle */ |
/* Number of words allocated during this collection cycle */ |
|
# endif |
word _words_wasted; |
word _words_wasted; |
/* Number of words wasted due to internal fragmentation */ |
/* Number of words wasted due to internal fragmentation */ |
/* in large objects, or due to dropping blacklisted */ |
/* in large objects, or due to dropping blacklisted */ |
Line 1059 struct _GC_arrays { |
|
Line 910 struct _GC_arrays { |
|
word _mem_freed; |
word _mem_freed; |
/* Number of explicitly deallocated words of memory */ |
/* Number of explicitly deallocated words of memory */ |
/* since last collection. */ |
/* since last collection. */ |
mark_proc _mark_procs[MAX_MARK_PROCS]; |
ptr_t _scratch_end_ptr; |
|
ptr_t _scratch_last_end_ptr; |
|
/* Used by headers.c, and can easily appear to point to */ |
|
/* heap. */ |
|
GC_mark_proc _mark_procs[MAX_MARK_PROCS]; |
/* Table of user-defined mark procedures. There is */ |
/* Table of user-defined mark procedures. There is */ |
/* a small number of these, which can be referenced */ |
/* a small number of these, which can be referenced */ |
/* by DS_PROC mark descriptors. See gc_mark.h. */ |
/* by DS_PROC mark descriptors. See gc_mark.h. */ |
ptr_t _objfreelist[MAXOBJSZ+1]; |
|
|
# ifndef SEPARATE_GLOBALS |
|
ptr_t _objfreelist[MAXOBJSZ+1]; |
/* free list for objects */ |
/* free list for objects */ |
ptr_t _aobjfreelist[MAXOBJSZ+1]; |
ptr_t _aobjfreelist[MAXOBJSZ+1]; |
/* free list for atomic objs */ |
/* free list for atomic objs */ |
|
# endif |
|
|
ptr_t _uobjfreelist[MAXOBJSZ+1]; |
ptr_t _uobjfreelist[MAXOBJSZ+1]; |
/* uncollectable but traced objs */ |
/* uncollectable but traced objs */ |
Line 1099 struct _GC_arrays { |
|
Line 957 struct _GC_arrays { |
|
ptr_t _sobjfreelist[MAXOBJSZ+1]; |
ptr_t _sobjfreelist[MAXOBJSZ+1]; |
# endif |
# endif |
/* free list for immutable objects */ |
/* free list for immutable objects */ |
ptr_t _obj_map[MAXOBJSZ+1]; |
map_entry_type * _obj_map[MAXOBJSZ+1]; |
/* If not NIL, then a pointer to a map of valid */ |
/* If not NIL, then a pointer to a map of valid */ |
/* object addresses. _obj_map[sz][i] is j if the */ |
/* object addresses. _obj_map[sz][i] is j if the */ |
/* address block_start+i is a valid pointer */ |
/* address block_start+i is a valid pointer */ |
/* to an object at */ |
/* to an object at block_start + */ |
/* block_start+i&~3 - WORDS_TO_BYTES(j). */ |
/* WORDS_TO_BYTES(BYTES_TO_WORDS(i) - j) */ |
/* (If ALL_INTERIOR_POINTERS is defined, then */ |
/* I.e. j is a word displacement from the */ |
/* instead ((short *)(hb_map[sz])[i] is j if */ |
/* object beginning. */ |
/* block_start+WORDS_TO_BYTES(i) is in the */ |
/* The entry is OBJ_INVALID if the corresponding */ |
/* interior of an object starting at */ |
/* address is not a valid pointer. It is */ |
/* block_start+WORDS_TO_BYTES(i-j)). */ |
/* OFFSET_TOO_BIG if the value j would be too */ |
/* It is OBJ_INVALID if */ |
/* large to fit in the entry. (Note that the */ |
/* block_start+WORDS_TO_BYTES(i) is not */ |
/* size of these entries matters, both for */ |
/* valid as a pointer to an object. */ |
/* space consumption and for cache utilization. */ |
/* We assume all values of j <= OBJ_INVALID. */ |
# define OFFSET_TOO_BIG 0xfe |
/* The zeroth entry corresponds to large objects.*/ |
# define OBJ_INVALID 0xff |
# ifdef ALL_INTERIOR_POINTERS |
# define MAP_ENTRY(map, bytes) (map)[bytes] |
# define map_entry_type short |
# define MAP_ENTRIES HBLKSIZE |
# define OBJ_INVALID 0x7fff |
# define MAP_SIZE MAP_ENTRIES |
# define MAP_ENTRY(map, bytes) \ |
# define CPP_MAX_OFFSET (OFFSET_TOO_BIG - 1) |
(((map_entry_type *)(map))[BYTES_TO_WORDS(bytes)]) |
# define MAX_OFFSET ((word)CPP_MAX_OFFSET) |
# define MAP_ENTRIES BYTES_TO_WORDS(HBLKSIZE) |
/* The following are used only if GC_all_interior_ptrs != 0 */ |
# define MAP_SIZE (MAP_ENTRIES * sizeof(map_entry_type)) |
|
# define OFFSET_VALID(displ) TRUE |
|
# define CPP_MAX_OFFSET (HBLKSIZE - HDR_BYTES - 1) |
|
# define MAX_OFFSET ((word)CPP_MAX_OFFSET) |
|
# else |
|
# define map_entry_type char |
|
# define OBJ_INVALID 0x7f |
|
# define MAP_ENTRY(map, bytes) \ |
|
(map)[bytes] |
|
# define MAP_ENTRIES HBLKSIZE |
|
# define MAP_SIZE MAP_ENTRIES |
|
# define CPP_MAX_OFFSET (WORDS_TO_BYTES(OBJ_INVALID) - 1) |
|
# define MAX_OFFSET ((word)CPP_MAX_OFFSET) |
|
# define VALID_OFFSET_SZ \ |
# define VALID_OFFSET_SZ \ |
(CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \ |
(CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \ |
CPP_MAX_OFFSET+1 \ |
CPP_MAX_OFFSET+1 \ |
Line 1141 struct _GC_arrays { |
|
Line 986 struct _GC_arrays { |
|
char _valid_offsets[VALID_OFFSET_SZ]; |
char _valid_offsets[VALID_OFFSET_SZ]; |
/* GC_valid_offsets[i] == TRUE ==> i */ |
/* GC_valid_offsets[i] == TRUE ==> i */ |
/* is registered as a displacement. */ |
/* is registered as a displacement. */ |
# define OFFSET_VALID(displ) GC_valid_offsets[displ] |
# define OFFSET_VALID(displ) \ |
|
(GC_all_interior_pointers || GC_valid_offsets[displ]) |
char _modws_valid_offsets[sizeof(word)]; |
char _modws_valid_offsets[sizeof(word)]; |
/* GC_valid_offsets[i] ==> */ |
/* GC_valid_offsets[i] ==> */ |
/* GC_modws_valid_offsets[i%sizeof(word)] */ |
/* GC_modws_valid_offsets[i%sizeof(word)] */ |
# endif |
|
# ifdef STUBBORN_ALLOC |
# ifdef STUBBORN_ALLOC |
page_hash_table _changed_pages; |
page_hash_table _changed_pages; |
/* Stubborn object pages that were changes since last call to */ |
/* Stubborn object pages that were changes since last call to */ |
Line 1172 struct _GC_arrays { |
|
Line 1017 struct _GC_arrays { |
|
# define MAX_HEAP_SECTS 768 /* Separately added heap sections. */ |
# define MAX_HEAP_SECTS 768 /* Separately added heap sections. */ |
# endif |
# endif |
# else |
# else |
# define MAX_HEAP_SECTS 256 |
# ifdef SMALL_CONFIG |
|
# define MAX_HEAP_SECTS 128 /* Roughly 1GB */ |
|
# else |
|
# define MAX_HEAP_SECTS 384 /* Roughly 3GB */ |
|
# endif |
# endif |
# endif |
struct HeapSect { |
struct HeapSect { |
ptr_t hs_start; word hs_bytes; |
ptr_t hs_start; word hs_bytes; |
} _heap_sects[MAX_HEAP_SECTS]; |
} _heap_sects[MAX_HEAP_SECTS]; |
# ifdef MSWIN32 |
# if defined(MSWIN32) || defined(MSWINCE) |
ptr_t _heap_bases[MAX_HEAP_SECTS]; |
ptr_t _heap_bases[MAX_HEAP_SECTS]; |
/* Start address of memory regions obtained from kernel. */ |
/* Start address of memory regions obtained from kernel. */ |
# endif |
# endif |
|
# ifdef MSWINCE |
|
word _heap_lengths[MAX_HEAP_SECTS]; |
|
/* Commited lengths of memory regions obtained from kernel. */ |
|
# endif |
struct roots _static_roots[MAX_ROOT_SETS]; |
struct roots _static_roots[MAX_ROOT_SETS]; |
# ifndef MSWIN32 |
# if !defined(MSWIN32) && !defined(MSWINCE) |
struct roots * _root_index[RT_SIZE]; |
struct roots * _root_index[RT_SIZE]; |
# endif |
# endif |
struct exclusion _excl_table[MAX_EXCLUSIONS]; |
struct exclusion _excl_table[MAX_EXCLUSIONS]; |
Line 1201 struct _GC_arrays { |
|
Line 1054 struct _GC_arrays { |
|
|
|
GC_API GC_FAR struct _GC_arrays GC_arrays; |
GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
|
# define GC_objfreelist GC_arrays._objfreelist |
# ifndef SEPARATE_GLOBALS |
# define GC_aobjfreelist GC_arrays._aobjfreelist |
# define GC_objfreelist GC_arrays._objfreelist |
|
# define GC_aobjfreelist GC_arrays._aobjfreelist |
|
# define GC_words_allocd GC_arrays._words_allocd |
|
# endif |
# define GC_uobjfreelist GC_arrays._uobjfreelist |
# define GC_uobjfreelist GC_arrays._uobjfreelist |
# ifdef ATOMIC_UNCOLLECTABLE |
# ifdef ATOMIC_UNCOLLECTABLE |
# define GC_auobjfreelist GC_arrays._auobjfreelist |
# define GC_auobjfreelist GC_arrays._auobjfreelist |
Line 1217 GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
Line 1073 GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
# define GC_obj_map GC_arrays._obj_map |
# define GC_obj_map GC_arrays._obj_map |
# define GC_last_heap_addr GC_arrays._last_heap_addr |
# define GC_last_heap_addr GC_arrays._last_heap_addr |
# define GC_prev_heap_addr GC_arrays._prev_heap_addr |
# define GC_prev_heap_addr GC_arrays._prev_heap_addr |
# define GC_words_allocd GC_arrays._words_allocd |
|
# define GC_words_wasted GC_arrays._words_wasted |
# define GC_words_wasted GC_arrays._words_wasted |
# define GC_large_free_bytes GC_arrays._large_free_bytes |
# define GC_large_free_bytes GC_arrays._large_free_bytes |
|
# define GC_large_allocd_bytes GC_arrays._large_allocd_bytes |
|
# define GC_max_large_allocd_bytes GC_arrays._max_large_allocd_bytes |
# define GC_words_finalized GC_arrays._words_finalized |
# define GC_words_finalized GC_arrays._words_finalized |
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc |
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc |
# define GC_mem_freed GC_arrays._mem_freed |
# define GC_mem_freed GC_arrays._mem_freed |
|
# define GC_scratch_end_ptr GC_arrays._scratch_end_ptr |
|
# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr |
# define GC_mark_procs GC_arrays._mark_procs |
# define GC_mark_procs GC_arrays._mark_procs |
# define GC_heapsize GC_arrays._heapsize |
# define GC_heapsize GC_arrays._heapsize |
# define GC_max_heapsize GC_arrays._max_heapsize |
# define GC_max_heapsize GC_arrays._max_heapsize |
|
# define GC_requested_heapsize GC_arrays._requested_heapsize |
# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc |
# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc |
# define GC_heap_sects GC_arrays._heap_sects |
# define GC_heap_sects GC_arrays._heap_sects |
# define GC_last_stack GC_arrays._last_stack |
# define GC_last_stack GC_arrays._last_stack |
# ifdef USE_MUNMAP |
# ifdef USE_MUNMAP |
# define GC_unmapped_bytes GC_arrays._unmapped_bytes |
# define GC_unmapped_bytes GC_arrays._unmapped_bytes |
# endif |
# endif |
# ifdef MSWIN32 |
# if defined(MSWIN32) || defined(MSWINCE) |
# define GC_heap_bases GC_arrays._heap_bases |
# define GC_heap_bases GC_arrays._heap_bases |
# endif |
# endif |
|
# ifdef MSWINCE |
|
# define GC_heap_lengths GC_arrays._heap_lengths |
|
# endif |
# define GC_static_roots GC_arrays._static_roots |
# define GC_static_roots GC_arrays._static_roots |
# define GC_root_index GC_arrays._root_index |
# define GC_root_index GC_arrays._root_index |
# define GC_excl_table GC_arrays._excl_table |
# define GC_excl_table GC_arrays._excl_table |
Line 1260 GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
Line 1123 GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
# define beginGC_arrays ((ptr_t)(&GC_arrays)) |
# define beginGC_arrays ((ptr_t)(&GC_arrays)) |
# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays)) |
# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays)) |
|
|
|
#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes) |
|
|
/* Object kinds: */ |
/* Object kinds: */ |
# define MAXOBJKINDS 16 |
# define MAXOBJKINDS 16 |
|
|
Line 1279 extern struct obj_kind { |
|
Line 1144 extern struct obj_kind { |
|
GC_bool ok_init; /* Clear objects before putting them on the free list. */ |
GC_bool ok_init; /* Clear objects before putting them on the free list. */ |
} GC_obj_kinds[MAXOBJKINDS]; |
} GC_obj_kinds[MAXOBJKINDS]; |
|
|
# define endGC_obj_kinds (((ptr_t)(&GC_obj_kinds)) + (sizeof GC_obj_kinds)) |
# define beginGC_obj_kinds ((ptr_t)(&GC_obj_kinds)) |
|
# define endGC_obj_kinds (beginGC_obj_kinds + (sizeof GC_obj_kinds)) |
|
|
# define end_gc_area ((ptr_t)endGC_arrays == (ptr_t)(&GC_obj_kinds) ? \ |
/* Variables that used to be in GC_arrays, but need to be accessed by */ |
endGC_obj_kinds : endGC_arrays) |
/* inline allocation code. If they were in GC_arrays, the inlined */ |
|
/* allocation code would include GC_arrays offsets (as it did), which */ |
|
/* introduce maintenance problems. */ |
|
|
|
#ifdef SEPARATE_GLOBALS |
|
word GC_words_allocd; |
|
/* Number of words allocated during this collection cycle */ |
|
ptr_t GC_objfreelist[MAXOBJSZ+1]; |
|
/* free list for NORMAL objects */ |
|
# define beginGC_objfreelist ((ptr_t)(&GC_objfreelist)) |
|
# define endGC_objfreelist (beginGC_objfreelist + sizeof(GC_objfreelist)) |
|
|
|
ptr_t GC_aobjfreelist[MAXOBJSZ+1]; |
|
/* free list for atomic (PTRFREE) objs */ |
|
# define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist)) |
|
# define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist)) |
|
#endif |
|
|
/* Predefined kinds: */ |
/* Predefined kinds: */ |
# define PTRFREE 0 |
# define PTRFREE 0 |
# define NORMAL 1 |
# define NORMAL 1 |
Line 1306 extern word GC_n_heap_sects; /* Number of separately a |
|
Line 1188 extern word GC_n_heap_sects; /* Number of separately a |
|
|
|
extern word GC_page_size; |
extern word GC_page_size; |
|
|
# ifdef MSWIN32 |
# if defined(MSWIN32) || defined(MSWINCE) |
extern word GC_n_heap_bases; /* See GC_heap_bases. */ |
struct _SYSTEM_INFO; |
|
extern struct _SYSTEM_INFO GC_sysinfo; |
|
extern word GC_n_heap_bases; /* See GC_heap_bases. */ |
# endif |
# endif |
|
|
extern word GC_total_stack_black_listed; |
extern word GC_total_stack_black_listed; |
Line 1320 extern word GC_black_list_spacing; |
|
Line 1204 extern word GC_black_list_spacing; |
|
/* "stack-blacklisted", i.e. that are */ |
/* "stack-blacklisted", i.e. that are */ |
/* problematic in the interior of an object. */ |
/* problematic in the interior of an object. */ |
|
|
extern char * GC_invalid_map; |
extern map_entry_type * GC_invalid_map; |
/* Pointer to the nowhere valid hblk map */ |
/* Pointer to the nowhere valid hblk map */ |
/* Blocks pointing to this map are free. */ |
/* Blocks pointing to this map are free. */ |
|
|
Line 1339 extern GC_bool GC_objects_are_marked; /* There are mar |
|
Line 1223 extern GC_bool GC_objects_are_marked; /* There are mar |
|
extern GC_bool GC_incremental; |
extern GC_bool GC_incremental; |
/* Using incremental/generational collection. */ |
/* Using incremental/generational collection. */ |
#else |
#else |
# define GC_incremental TRUE |
# define GC_incremental FALSE |
/* Hopefully allow optimizer to remove some code. */ |
/* Hopefully allow optimizer to remove some code. */ |
#endif |
#endif |
|
|
Line 1352 extern word GC_root_size; /* Total size of registered |
|
Line 1236 extern word GC_root_size; /* Total size of registered |
|
|
|
extern GC_bool GC_debugging_started; /* GC_debug_malloc has been called. */ |
extern GC_bool GC_debugging_started; /* GC_debug_malloc has been called. */ |
|
|
extern ptr_t GC_least_plausible_heap_addr; |
|
extern ptr_t GC_greatest_plausible_heap_addr; |
|
/* Bounds on the heap. Guaranteed valid */ |
|
/* Likely to include future heap expansion. */ |
|
|
|
/* Operations */ |
/* Operations */ |
# ifndef abs |
# ifndef abs |
Line 1368 extern ptr_t GC_greatest_plausible_heap_addr; |
|
Line 1248 extern ptr_t GC_greatest_plausible_heap_addr; |
|
/* with it. Only those corresponding to the beginning of an */ |
/* with it. Only those corresponding to the beginning of an */ |
/* object are used. */ |
/* object are used. */ |
|
|
|
/* Set mark bit correctly, even if mark bits may be concurrently */ |
|
/* accessed. */ |
|
#ifdef PARALLEL_MARK |
|
# define OR_WORD(addr, bits) \ |
|
{ word old; \ |
|
do { \ |
|
old = *((volatile word *)addr); \ |
|
} while (!GC_compare_and_exchange((addr), old, old | (bits))); \ |
|
} |
|
# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \ |
|
{ word old; \ |
|
word my_bits = (bits); \ |
|
do { \ |
|
old = *((volatile word *)addr); \ |
|
if (old & my_bits) goto exit_label; \ |
|
} while (!GC_compare_and_exchange((addr), old, old | my_bits)); \ |
|
} |
|
#else |
|
# define OR_WORD(addr, bits) *(addr) |= (bits) |
|
# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \ |
|
{ \ |
|
word old = *(addr); \ |
|
word my_bits = (bits); \ |
|
if (old & my_bits) goto exit_label; \ |
|
*(addr) = (old | my_bits); \ |
|
} |
|
#endif |
|
|
/* Mark bit operations */ |
/* Mark bit operations */ |
|
|
Line 1379 extern ptr_t GC_greatest_plausible_heap_addr; |
|
Line 1286 extern ptr_t GC_greatest_plausible_heap_addr; |
|
* relative to the beginning of the block, including unused words) |
* relative to the beginning of the block, including unused words) |
*/ |
*/ |
|
|
|
#ifdef USE_MARK_BYTES |
|
# define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n) >> 1]) |
|
# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 1 |
|
# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 0 |
|
#else /* !USE_MARK_BYTES */ |
# define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \ |
# define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \ |
>> (modWORDSZ(n))) & (word)1) |
>> (modWORDSZ(n))) & (word)1) |
# define set_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \ |
# define set_mark_bit_from_hdr(hhdr,n) \ |
|= (word)1 << modWORDSZ(n) |
OR_WORD((hhdr)->hb_marks+divWORDSZ(n), \ |
|
(word)1 << modWORDSZ(n)) |
# define clear_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \ |
# define clear_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \ |
&= ~((word)1 << modWORDSZ(n)) |
&= ~((word)1 << modWORDSZ(n)) |
|
#endif /* !USE_MARK_BYTES */ |
|
|
/* Important internal collector routines */ |
/* Important internal collector routines */ |
|
|
ptr_t GC_approx_sp(); |
ptr_t GC_approx_sp GC_PROTO((void)); |
|
|
GC_bool GC_should_collect(); |
GC_bool GC_should_collect GC_PROTO((void)); |
#ifdef PRESERVE_LAST |
|
GC_bool GC_in_last_heap_sect(/* ptr_t */); |
void GC_apply_to_all_blocks GC_PROTO(( \ |
/* In last added heap section? If so, avoid breaking up. */ |
void (*fn) GC_PROTO((struct hblk *h, word client_data)), \ |
#endif |
word client_data)); |
void GC_apply_to_all_blocks(/*fn, client_data*/); |
/* Invoke fn(hbp, client_data) for each */ |
/* Invoke fn(hbp, client_data) for each */ |
/* allocated heap block. */ |
/* allocated heap block. */ |
struct hblk * GC_next_used_block GC_PROTO((struct hblk * h)); |
struct hblk * GC_next_used_block(/* struct hblk * h */); |
/* Return first in-use block >= h */ |
/* Return first in-use block >= h */ |
struct hblk * GC_prev_block GC_PROTO((struct hblk * h)); |
struct hblk * GC_prev_block(/* struct hblk * h */); |
/* Return last block <= h. Returned block */ |
/* Return last block <= h. Returned block */ |
/* is managed by GC, but may or may not be in */ |
/* is managed by GC, but may or may not be in */ |
|
/* use. */ |
/* use. */ |
void GC_mark_init(); |
void GC_mark_init GC_PROTO((void)); |
void GC_clear_marks(); /* Clear mark bits for all heap objects. */ |
void GC_clear_marks GC_PROTO((void)); /* Clear mark bits for all heap objects. */ |
void GC_invalidate_mark_state(); /* Tell the marker that marked */ |
void GC_invalidate_mark_state GC_PROTO((void)); |
/* objects may point to unmarked */ |
/* Tell the marker that marked */ |
/* ones, and roots may point to */ |
/* objects may point to unmarked */ |
/* unmarked objects. */ |
/* ones, and roots may point to */ |
/* Reset mark stack. */ |
/* unmarked objects. */ |
void GC_mark_from_mark_stack(); /* Mark from everything on the mark stack. */ |
/* Reset mark stack. */ |
/* Return after about one pages worth of */ |
GC_bool GC_mark_stack_empty GC_PROTO((void)); |
/* work. */ |
GC_bool GC_mark_some GC_PROTO((ptr_t cold_gc_frame)); |
GC_bool GC_mark_stack_empty(); |
/* Perform about one pages worth of marking */ |
GC_bool GC_mark_some(/* cold_gc_frame */); |
/* work of whatever kind is needed. Returns */ |
/* Perform about one pages worth of marking */ |
/* quickly if no collection is in progress. */ |
/* work of whatever kind is needed. Returns */ |
/* Return TRUE if mark phase finished. */ |
/* quickly if no collection is in progress. */ |
void GC_initiate_gc GC_PROTO((void)); |
/* Return TRUE if mark phase finished. */ |
/* initiate collection. */ |
void GC_initiate_gc(); /* initiate collection. */ |
/* If the mark state is invalid, this */ |
/* If the mark state is invalid, this */ |
/* becomes full colleection. Otherwise */ |
/* becomes full colleection. Otherwise */ |
/* it's partial. */ |
/* it's partial. */ |
void GC_push_all GC_PROTO((ptr_t bottom, ptr_t top)); |
void GC_push_all(/*b,t*/); /* Push everything in a range */ |
/* Push everything in a range */ |
/* onto mark stack. */ |
/* onto mark stack. */ |
void GC_push_dirty(/*b,t*/); /* Push all possibly changed */ |
void GC_push_selected GC_PROTO(( \ |
/* subintervals of [b,t) onto */ |
ptr_t bottom, \ |
/* mark stack. */ |
ptr_t top, \ |
|
int (*dirty_fn) GC_PROTO((struct hblk *h)), \ |
|
void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top)) )); |
|
/* Push all pages h in [b,t) s.t. */ |
|
/* select_fn(h) != 0 onto mark stack. */ |
#ifndef SMALL_CONFIG |
#ifndef SMALL_CONFIG |
void GC_push_conditional(/* ptr_t b, ptr_t t, GC_bool all*/); |
void GC_push_conditional GC_PROTO((ptr_t b, ptr_t t, GC_bool all)); |
#else |
#else |
# define GC_push_conditional(b, t, all) GC_push_all(b, t) |
# define GC_push_conditional(b, t, all) GC_push_all(b, t) |
#endif |
#endif |
/* Do either of the above, depending */ |
/* Do either of the above, depending */ |
/* on the third arg. */ |
/* on the third arg. */ |
void GC_push_all_stack(/*b,t*/); /* As above, but consider */ |
void GC_push_all_stack GC_PROTO((ptr_t b, ptr_t t)); |
|
/* As above, but consider */ |
/* interior pointers as valid */ |
/* interior pointers as valid */ |
void GC_push_all_eager(/*b,t*/); /* Same as GC_push_all_stack, but */ |
void GC_push_all_eager GC_PROTO((ptr_t b, ptr_t t)); |
|
/* Same as GC_push_all_stack, but */ |
/* ensures that stack is scanned */ |
/* ensures that stack is scanned */ |
/* immediately, not just scheduled */ |
/* immediately, not just scheduled */ |
/* for scanning. */ |
/* for scanning. */ |
#ifndef THREADS |
#ifndef THREADS |
void GC_push_all_stack_partially_eager(/* bottom, top, cold_gc_frame */); |
void GC_push_all_stack_partially_eager GC_PROTO(( \ |
|
ptr_t bottom, ptr_t top, ptr_t cold_gc_frame )); |
/* Similar to GC_push_all_eager, but only the */ |
/* Similar to GC_push_all_eager, but only the */ |
/* part hotter than cold_gc_frame is scanned */ |
/* part hotter than cold_gc_frame is scanned */ |
/* immediately. Needed to endure that callee- */ |
/* immediately. Needed to ensure that callee- */ |
/* save registers are not missed. */ |
/* save registers are not missed. */ |
#else |
#else |
/* In the threads case, we push part of the current thread stack */ |
/* In the threads case, we push part of the current thread stack */ |
Line 1456 void GC_push_all_eager(/*b,t*/); /* Same as GC_push |
|
Line 1375 void GC_push_all_eager(/*b,t*/); /* Same as GC_push |
|
/* stacks are scheduled for scanning in *GC_push_other_roots, which */ |
/* stacks are scheduled for scanning in *GC_push_other_roots, which */ |
/* is thread-package-specific. */ |
/* is thread-package-specific. */ |
#endif |
#endif |
void GC_push_current_stack(/* ptr_t cold_gc_frame */); |
void GC_push_current_stack GC_PROTO((ptr_t cold_gc_frame)); |
/* Push enough of the current stack eagerly to */ |
/* Push enough of the current stack eagerly to */ |
/* ensure that callee-save registers saved in */ |
/* ensure that callee-save registers saved in */ |
/* GC frames are scanned. */ |
/* GC frames are scanned. */ |
/* In the non-threads case, schedule entire */ |
/* In the non-threads case, schedule entire */ |
/* stack for scanning. */ |
/* stack for scanning. */ |
void GC_push_roots(/* GC_bool all, ptr_t cold_gc_frame */); |
void GC_push_roots GC_PROTO((GC_bool all, ptr_t cold_gc_frame)); |
/* Push all or dirty roots. */ |
/* Push all or dirty roots. */ |
extern void (*GC_push_other_roots)(); |
extern void (*GC_push_other_roots) GC_PROTO((void)); |
/* Push system or application specific roots */ |
/* Push system or application specific roots */ |
/* onto the mark stack. In some environments */ |
/* onto the mark stack. In some environments */ |
/* (e.g. threads environments) this is */ |
/* (e.g. threads environments) this is */ |
/* predfined to be non-zero. A client supplied */ |
/* predfined to be non-zero. A client supplied */ |
/* replacement should also call the original */ |
/* replacement should also call the original */ |
/* function. */ |
/* function. */ |
extern void (*GC_start_call_back)(/* void */); |
extern void GC_push_gc_structures GC_PROTO((void)); |
/* Called at start of full collections. */ |
/* Push GC internal roots. These are normally */ |
/* Not called if 0. Called with allocation */ |
/* included in the static data segment, and */ |
/* lock held. */ |
/* Thus implicitly pushed. But we must do this */ |
/* 0 by default. */ |
/* explicitly if normal root processing is */ |
void GC_push_regs(); /* Push register contents onto mark stack. */ |
/* disabled. Calls the following: */ |
/* If NURSERY is defined, the default push */ |
extern void GC_push_finalizer_structures GC_PROTO((void)); |
/* action can be overridden with GC_push_proc */ |
extern void GC_push_stubborn_structures GC_PROTO((void)); |
void GC_remark(); /* Mark from all marked objects. Used */ |
# ifdef THREADS |
/* only if we had to drop something. */ |
extern void GC_push_thread_structures GC_PROTO((void)); |
|
# endif |
|
extern void (*GC_start_call_back) GC_PROTO((void)); |
|
/* Called at start of full collections. */ |
|
/* Not called if 0. Called with allocation */ |
|
/* lock held. */ |
|
/* 0 by default. */ |
|
# if defined(USE_GENERIC_PUSH_REGS) |
|
void GC_generic_push_regs GC_PROTO((ptr_t cold_gc_frame)); |
|
# else |
|
void GC_push_regs GC_PROTO((void)); |
|
# endif |
|
/* Push register contents onto mark stack. */ |
|
/* If NURSERY is defined, the default push */ |
|
/* action can be overridden with GC_push_proc */ |
|
|
# ifdef NURSERY |
# ifdef NURSERY |
extern void (*GC_push_proc)(ptr_t); |
extern void (*GC_push_proc)(ptr_t); |
# endif |
# endif |
# if defined(MSWIN32) |
# if defined(MSWIN32) || defined(MSWINCE) |
void __cdecl GC_push_one(); |
void __cdecl GC_push_one GC_PROTO((word p)); |
# else |
# else |
void GC_push_one(/*p*/); /* If p points to an object, mark it */ |
void GC_push_one GC_PROTO((word p)); |
|
/* If p points to an object, mark it */ |
/* and push contents on the mark stack */ |
/* and push contents on the mark stack */ |
|
/* Pointer recognition test always */ |
|
/* accepts interior pointers, i.e. this */ |
|
/* is appropriate for pointers found on */ |
|
/* stack. */ |
# endif |
# endif |
void GC_push_one_checked(/*p*/); /* Ditto, omits plausibility test */ |
# if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS) |
void GC_push_marked(/* struct hblk h, hdr * hhdr */); |
void GC_mark_and_push_stack GC_PROTO((word p, ptr_t source)); |
|
/* Ditto, omits plausibility test */ |
|
# else |
|
void GC_mark_and_push_stack GC_PROTO((word p)); |
|
# endif |
|
void GC_push_marked GC_PROTO((struct hblk * h, hdr * hhdr)); |
/* Push contents of all marked objects in h onto */ |
/* Push contents of all marked objects in h onto */ |
/* mark stack. */ |
/* mark stack. */ |
#ifdef SMALL_CONFIG |
#ifdef SMALL_CONFIG |
# define GC_push_next_marked_dirty(h) GC_push_next_marked(h) |
# define GC_push_next_marked_dirty(h) GC_push_next_marked(h) |
#else |
#else |
struct hblk * GC_push_next_marked_dirty(/* h */); |
struct hblk * GC_push_next_marked_dirty GC_PROTO((struct hblk * h)); |
/* Invoke GC_push_marked on next dirty block above h. */ |
/* Invoke GC_push_marked on next dirty block above h. */ |
/* Return a pointer just past the end of this block. */ |
/* Return a pointer just past the end of this block. */ |
#endif /* !SMALL_CONFIG */ |
#endif /* !SMALL_CONFIG */ |
struct hblk * GC_push_next_marked(/* h */); |
struct hblk * GC_push_next_marked GC_PROTO((struct hblk * h)); |
/* Ditto, but also mark from clean pages. */ |
/* Ditto, but also mark from clean pages. */ |
struct hblk * GC_push_next_marked_uncollectable(/* h */); |
struct hblk * GC_push_next_marked_uncollectable GC_PROTO((struct hblk * h)); |
/* Ditto, but mark only from uncollectable pages. */ |
/* Ditto, but mark only from uncollectable pages. */ |
GC_bool GC_stopped_mark(); /* Stop world and mark from all roots */ |
GC_bool GC_stopped_mark GC_PROTO((GC_stop_func stop_func)); |
/* and rescuers. */ |
/* Stop world and mark from all roots */ |
void GC_clear_hdr_marks(/* hhdr */); /* Clear the mark bits in a header */ |
/* and rescuers. */ |
void GC_set_hdr_marks(/* hhdr */); /* Set the mark bits in a header */ |
void GC_clear_hdr_marks GC_PROTO((hdr * hhdr)); |
void GC_add_roots_inner(); |
/* Clear the mark bits in a header */ |
GC_bool GC_is_static_root(/* ptr_t p */); |
void GC_set_hdr_marks GC_PROTO((hdr * hhdr)); |
/* Is the address p in one of the registered static */ |
/* Set the mark bits in a header */ |
|
void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp)); |
|
GC_bool GC_is_static_root GC_PROTO((ptr_t p)); |
|
/* Is the address p in one of the registered static */ |
|
/* root sections? */ |
|
# if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION) |
|
GC_bool GC_is_tmp_root GC_PROTO((ptr_t p)); |
|
/* Is the address p in one of the temporary static */ |
/* root sections? */ |
/* root sections? */ |
void GC_register_dynamic_libraries(); |
# endif |
/* Add dynamic library data sections to the root set. */ |
void GC_register_dynamic_libraries GC_PROTO((void)); |
|
/* Add dynamic library data sections to the root set. */ |
|
|
/* Machine dependent startup routines */ |
/* Machine dependent startup routines */ |
ptr_t GC_get_stack_base(); |
ptr_t GC_get_stack_base GC_PROTO((void)); /* Cold end of stack */ |
void GC_register_data_segments(); |
#ifdef IA64 |
|
ptr_t GC_get_register_stack_base GC_PROTO((void)); |
|
/* Cold end of register stack. */ |
|
#endif |
|
void GC_register_data_segments GC_PROTO((void)); |
|
|
/* Black listing: */ |
/* Black listing: */ |
void GC_bl_init(); |
void GC_bl_init GC_PROTO((void)); |
# ifndef ALL_INTERIOR_POINTERS |
# ifdef PRINT_BLACK_LIST |
void GC_add_to_black_list_normal(/* bits, maybe source */); |
void GC_add_to_black_list_normal GC_PROTO((word p, ptr_t source)); |
/* Register bits as a possible future false */ |
/* Register bits as a possible future false */ |
/* reference from the heap or static data */ |
/* reference from the heap or static data */ |
# ifdef PRINT_BLACK_LIST |
|
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ |
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ |
GC_add_to_black_list_normal(bits, source) |
if (GC_all_interior_pointers) { \ |
# else |
GC_add_to_black_list_stack(bits, source); \ |
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ |
} else { \ |
GC_add_to_black_list_normal(bits) |
GC_add_to_black_list_normal(bits, source); \ |
# endif |
} |
# else |
# else |
# ifdef PRINT_BLACK_LIST |
void GC_add_to_black_list_normal GC_PROTO((word p)); |
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ |
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ |
GC_add_to_black_list_stack(bits, source) |
if (GC_all_interior_pointers) { \ |
# else |
GC_add_to_black_list_stack(bits); \ |
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ |
} else { \ |
GC_add_to_black_list_stack(bits) |
GC_add_to_black_list_normal(bits); \ |
# endif |
} |
# endif |
# endif |
|
|
void GC_add_to_black_list_stack(/* bits, maybe source */); |
# ifdef PRINT_BLACK_LIST |
struct hblk * GC_is_black_listed(/* h, len */); |
void GC_add_to_black_list_stack GC_PROTO((word p, ptr_t source)); |
/* If there are likely to be false references */ |
# else |
/* to a block starting at h of the indicated */ |
void GC_add_to_black_list_stack GC_PROTO((word p)); |
/* length, then return the next plausible */ |
# endif |
/* starting location for h that might avoid */ |
struct hblk * GC_is_black_listed GC_PROTO((struct hblk * h, word len)); |
/* these false references. */ |
/* If there are likely to be false references */ |
void GC_promote_black_lists(); |
/* to a block starting at h of the indicated */ |
/* Declare an end to a black listing phase. */ |
/* length, then return the next plausible */ |
void GC_unpromote_black_lists(); |
/* starting location for h that might avoid */ |
/* Approximately undo the effect of the above. */ |
/* these false references. */ |
/* This actually loses some information, but */ |
void GC_promote_black_lists GC_PROTO((void)); |
/* only in a reasonably safe way. */ |
/* Declare an end to a black listing phase. */ |
word GC_number_stack_black_listed(/*struct hblk *start, struct hblk *endp1 */); |
void GC_unpromote_black_lists GC_PROTO((void)); |
/* Return the number of (stack) blacklisted */ |
/* Approximately undo the effect of the above. */ |
/* blocks in the range for statistical */ |
/* This actually loses some information, but */ |
/* purposes. */ |
/* only in a reasonably safe way. */ |
|
word GC_number_stack_black_listed GC_PROTO(( \ |
ptr_t GC_scratch_alloc(/*bytes*/); |
struct hblk *start, struct hblk *endp1)); |
/* GC internal memory allocation for */ |
/* Return the number of (stack) blacklisted */ |
/* small objects. Deallocation is not */ |
/* blocks in the range for statistical */ |
/* possible. */ |
/* purposes. */ |
|
|
|
ptr_t GC_scratch_alloc GC_PROTO((word bytes)); |
|
/* GC internal memory allocation for */ |
|
/* small objects. Deallocation is not */ |
|
/* possible. */ |
|
|
/* Heap block layout maps: */ |
/* Heap block layout maps: */ |
void GC_invalidate_map(/* hdr */); |
void GC_invalidate_map GC_PROTO((hdr * hhdr)); |
/* Remove the object map associated */ |
/* Remove the object map associated */ |
/* with the block. This identifies */ |
/* with the block. This identifies */ |
/* the block as invalid to the mark */ |
/* the block as invalid to the mark */ |
/* routines. */ |
/* routines. */ |
GC_bool GC_add_map_entry(/*sz*/); |
GC_bool GC_add_map_entry GC_PROTO((word sz)); |
/* Add a heap block map for objects of */ |
/* Add a heap block map for objects of */ |
/* size sz to obj_map. */ |
/* size sz to obj_map. */ |
/* Return FALSE on failure. */ |
/* Return FALSE on failure. */ |
void GC_register_displacement_inner(/*offset*/); |
void GC_register_displacement_inner GC_PROTO((word offset)); |
/* Version of GC_register_displacement */ |
/* Version of GC_register_displacement */ |
/* that assumes lock is already held */ |
/* that assumes lock is already held */ |
/* and signals are already disabled. */ |
/* and signals are already disabled. */ |
|
|
/* hblk allocation: */ |
/* hblk allocation: */ |
void GC_new_hblk(/*size_in_words, kind*/); |
void GC_new_hblk GC_PROTO((word size_in_words, int kind)); |
/* Allocate a new heap block, and build */ |
/* Allocate a new heap block, and build */ |
/* a free list in it. */ |
/* a free list in it. */ |
struct hblk * GC_allochblk(/*size_in_words, kind*/); |
|
/* Allocate a heap block, clear it if */ |
ptr_t GC_build_fl GC_PROTO((struct hblk *h, word sz, |
/* for composite objects, inform */ |
GC_bool clear, ptr_t list)); |
|
/* Build a free list for objects of */ |
|
/* size sz in block h. Append list to */ |
|
/* end of the free lists. Possibly */ |
|
/* clear objects on the list. Normally */ |
|
/* called by GC_new_hblk, but also */ |
|
/* called explicitly without GC lock. */ |
|
|
|
struct hblk * GC_allochblk GC_PROTO(( \ |
|
word size_in_words, int kind, unsigned flags)); |
|
/* Allocate a heap block, inform */ |
/* the marker that block is valid */ |
/* the marker that block is valid */ |
/* for objects of indicated size. */ |
/* for objects of indicated size. */ |
/* sz < 0 ==> atomic. */ |
|
void GC_freehblk(); /* Deallocate a heap block and mark it */ |
ptr_t GC_alloc_large GC_PROTO((word lw, int k, unsigned flags)); |
/* as invalid. */ |
/* Allocate a large block of size lw words. */ |
|
/* The block is not cleared. */ |
|
/* Flags is 0 or IGNORE_OFF_PAGE. */ |
|
/* Calls GC_allchblk to do the actual */ |
|
/* allocation, but also triggers GC and/or */ |
|
/* heap expansion as appropriate. */ |
|
/* Does not update GC_words_allocd, but does */ |
|
/* other accounting. */ |
|
|
|
ptr_t GC_alloc_large_and_clear GC_PROTO((word lw, int k, unsigned flags)); |
|
/* As above, but clear block if appropriate */ |
|
/* for kind k. */ |
|
|
|
void GC_freehblk GC_PROTO((struct hblk * p)); |
|
/* Deallocate a heap block and mark it */ |
|
/* as invalid. */ |
|
|
/* Misc GC: */ |
/* Misc GC: */ |
void GC_init_inner(); |
void GC_init_inner GC_PROTO((void)); |
GC_bool GC_expand_hp_inner(); |
GC_bool GC_expand_hp_inner GC_PROTO((word n)); |
void GC_start_reclaim(/*abort_if_found*/); |
void GC_start_reclaim GC_PROTO((int abort_if_found)); |
/* Restore unmarked objects to free */ |
/* Restore unmarked objects to free */ |
/* lists, or (if abort_if_found is */ |
/* lists, or (if abort_if_found is */ |
/* TRUE) report them. */ |
/* TRUE) report them. */ |
/* Sweeping of small object pages is */ |
/* Sweeping of small object pages is */ |
/* largely deferred. */ |
/* largely deferred. */ |
void GC_continue_reclaim(/*size, kind*/); |
void GC_continue_reclaim GC_PROTO((word sz, int kind)); |
/* Sweep pages of the given size and */ |
/* Sweep pages of the given size and */ |
/* kind, as long as possible, and */ |
/* kind, as long as possible, and */ |
/* as long as the corr. free list is */ |
/* as long as the corr. free list is */ |
/* empty. */ |
/* empty. */ |
void GC_reclaim_or_delete_all(); |
void GC_reclaim_or_delete_all GC_PROTO((void)); |
/* Arrange for all reclaim lists to be */ |
/* Arrange for all reclaim lists to be */ |
/* empty. Judiciously choose between */ |
/* empty. Judiciously choose between */ |
/* sweeping and discarding each page. */ |
/* sweeping and discarding each page. */ |
GC_bool GC_reclaim_all(/* GC_stop_func f*/); |
GC_bool GC_reclaim_all GC_PROTO((GC_stop_func stop_func, GC_bool ignore_old)); |
/* Reclaim all blocks. Abort (in a */ |
/* Reclaim all blocks. Abort (in a */ |
/* consistent state) if f returns TRUE. */ |
/* consistent state) if f returns TRUE. */ |
GC_bool GC_block_empty(/* hhdr */); /* Block completely unmarked? */ |
GC_bool GC_block_empty GC_PROTO((hdr * hhdr)); |
GC_bool GC_never_stop_func(); /* Returns FALSE. */ |
/* Block completely unmarked? */ |
GC_bool GC_try_to_collect_inner(/* GC_stop_func f */); |
GC_bool GC_never_stop_func GC_PROTO((void)); |
|
/* Returns FALSE. */ |
|
GC_bool GC_try_to_collect_inner GC_PROTO((GC_stop_func f)); |
|
|
/* Collect; caller must have acquired */ |
/* Collect; caller must have acquired */ |
/* lock and disabled signals. */ |
/* lock and disabled signals. */ |
/* Collection is aborted if f returns */ |
/* Collection is aborted if f returns */ |
Line 1626 GC_bool GC_try_to_collect_inner(/* GC_stop_func f */); |
|
Line 1613 GC_bool GC_try_to_collect_inner(/* GC_stop_func f */); |
|
/* successfully. */ |
/* successfully. */ |
# define GC_gcollect_inner() \ |
# define GC_gcollect_inner() \ |
(void) GC_try_to_collect_inner(GC_never_stop_func) |
(void) GC_try_to_collect_inner(GC_never_stop_func) |
void GC_finish_collection(); /* Finish collection. Mark bits are */ |
void GC_finish_collection GC_PROTO((void)); |
/* consistent and lock is still held. */ |
/* Finish collection. Mark bits are */ |
GC_bool GC_collect_or_expand(/* needed_blocks */); |
/* consistent and lock is still held. */ |
/* Collect or expand heap in an attempt */ |
GC_bool GC_collect_or_expand GC_PROTO(( \ |
/* make the indicated number of free */ |
word needed_blocks, GC_bool ignore_off_page)); |
/* blocks available. Should be called */ |
/* Collect or expand heap in an attempt */ |
/* until the blocks are available or */ |
/* make the indicated number of free */ |
/* until it fails by returning FALSE. */ |
/* blocks available. Should be called */ |
GC_API void GC_init(); /* Initialize collector. */ |
/* until the blocks are available or */ |
void GC_collect_a_little_inner(/* int n */); |
/* until it fails by returning FALSE. */ |
/* Do n units worth of garbage */ |
GC_API void GC_init GC_PROTO((void)); /* Initialize collector. */ |
/* collection work, if appropriate. */ |
|
/* A unit is an amount appropriate for */ |
#if defined(MSWIN32) || defined(MSWINCE) |
/* HBLKSIZE bytes of allocation. */ |
void GC_deinit GC_PROTO((void)); |
ptr_t GC_generic_malloc(/* bytes, kind */); |
/* Free any resources allocated by */ |
/* Allocate an object of the given */ |
/* GC_init */ |
/* kind. By default, there are only */ |
#endif |
/* a few kinds: composite(pointerfree), */ |
|
|
void GC_collect_a_little_inner GC_PROTO((int n)); |
|
/* Do n units worth of garbage */ |
|
/* collection work, if appropriate. */ |
|
/* A unit is an amount appropriate for */ |
|
/* HBLKSIZE bytes of allocation. */ |
|
ptr_t GC_generic_malloc GC_PROTO((word lb, int k)); |
|
/* Allocate an object of the given */ |
|
/* kind. By default, there are only */ |
|
/* a few kinds: composite(pointerfree), */ |
/* atomic, uncollectable, etc. */ |
/* atomic, uncollectable, etc. */ |
/* We claim it's possible for clever */ |
/* We claim it's possible for clever */ |
/* client code that understands GC */ |
/* client code that understands GC */ |
/* internals to add more, e.g. to */ |
/* internals to add more, e.g. to */ |
/* communicate object layout info */ |
/* communicate object layout info */ |
/* to the collector. */ |
/* to the collector. */ |
ptr_t GC_generic_malloc_ignore_off_page(/* bytes, kind */); |
ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k)); |
/* As above, but pointers past the */ |
/* As above, but pointers past the */ |
/* first page of the resulting object */ |
/* first page of the resulting object */ |
/* are ignored. */ |
/* are ignored. */ |
ptr_t GC_generic_malloc_inner(/* bytes, kind */); |
ptr_t GC_generic_malloc_inner GC_PROTO((word lb, int k)); |
/* Ditto, but I already hold lock, etc. */ |
/* Ditto, but I already hold lock, etc. */ |
ptr_t GC_generic_malloc_words_small GC_PROTO((size_t words, int kind)); |
ptr_t GC_generic_malloc_words_small GC_PROTO((size_t lw, int k)); |
/* As above, but size in units of words */ |
/* As above, but size in units of words */ |
/* Bypasses MERGE_SIZES. Assumes */ |
/* Bypasses MERGE_SIZES. Assumes */ |
/* words <= MAXOBJSZ. */ |
/* words <= MAXOBJSZ. */ |
ptr_t GC_generic_malloc_inner_ignore_off_page(/* bytes, kind */); |
ptr_t GC_generic_malloc_inner_ignore_off_page GC_PROTO((size_t lb, int k)); |
/* Allocate an object, where */ |
/* Allocate an object, where */ |
/* the client guarantees that there */ |
/* the client guarantees that there */ |
/* will always be a pointer to the */ |
/* will always be a pointer to the */ |
/* beginning of the object while the */ |
/* beginning of the object while the */ |
/* object is live. */ |
/* object is live. */ |
ptr_t GC_allocobj(/* sz_inn_words, kind */); |
ptr_t GC_allocobj GC_PROTO((word sz, int kind)); |
/* Make the indicated */ |
/* Make the indicated */ |
/* free list nonempty, and return its */ |
/* free list nonempty, and return its */ |
/* head. */ |
/* head. */ |
|
|
|
void GC_init_headers GC_PROTO((void)); |
|
struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h)); |
|
/* Install a header for block h. */ |
|
/* Return 0 on failure, or the header */ |
|
/* otherwise. */ |
|
GC_bool GC_install_counts GC_PROTO((struct hblk * h, word sz)); |
|
/* Set up forwarding counts for block */ |
|
/* h of size sz. */ |
|
/* Return FALSE on failure. */ |
|
void GC_remove_header GC_PROTO((struct hblk * h)); |
|
/* Remove the header for block h. */ |
|
void GC_remove_counts GC_PROTO((struct hblk * h, word sz)); |
|
/* Remove forwarding counts for h. */ |
|
hdr * GC_find_header GC_PROTO((ptr_t h)); /* Debugging only. */ |
|
|
|
void GC_finalize GC_PROTO((void)); |
|
/* Perform all indicated finalization actions */ |
|
/* on unmarked objects. */ |
|
/* Unreachable finalizable objects are enqueued */ |
|
/* for processing by GC_invoke_finalizers. */ |
|
/* Invoked with lock. */ |
|
|
void GC_init_headers(); |
void GC_notify_or_invoke_finalizers GC_PROTO((void)); |
GC_bool GC_install_header(/*h*/); |
/* If GC_finalize_on_demand is not set, invoke */ |
/* Install a header for block h. */ |
/* eligible finalizers. Otherwise: */ |
/* Return FALSE on failure. */ |
/* Call *GC_finalizer_notifier if there are */ |
GC_bool GC_install_counts(/*h, sz*/); |
/* finalizers to be run, and we haven't called */ |
/* Set up forwarding counts for block */ |
/* this procedure yet this GC cycle. */ |
/* h of size sz. */ |
|
/* Return FALSE on failure. */ |
void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes)); |
void GC_remove_header(/*h*/); |
/* Add a HBLKSIZE aligned chunk to the heap. */ |
/* Remove the header for block h. */ |
|
void GC_remove_counts(/*h, sz*/); |
void GC_print_obj GC_PROTO((ptr_t p)); |
/* Remove forwarding counts for h. */ |
/* P points to somewhere inside an object with */ |
hdr * GC_find_header(/*p*/); /* Debugging only. */ |
/* debugging info. Print a human readable */ |
|
/* description of the object to stderr. */ |
|
extern void (*GC_check_heap) GC_PROTO((void)); |
|
/* Check that all objects in the heap with */ |
|
/* debugging info are intact. Print */ |
|
/* descriptions of any that are not. */ |
|
extern void (*GC_print_heap_obj) GC_PROTO((ptr_t p)); |
|
/* If possible print s followed by a more */ |
|
/* detailed description of the object */ |
|
/* referred to by p. */ |
|
|
void GC_finalize(); /* Perform all indicated finalization actions */ |
extern GC_bool GC_print_stats; /* Produce at least some logging output */ |
/* on unmarked objects. */ |
/* Set from environment variable. */ |
/* Unreachable finalizable objects are enqueued */ |
|
/* for processing by GC_invoke_finalizers. */ |
|
/* Invoked with lock. */ |
|
|
|
void GC_add_to_heap(/*p, bytes*/); |
|
/* Add a HBLKSIZE aligned chunk to the heap. */ |
|
|
|
void GC_print_obj(/* ptr_t p */); |
/* Macros used for collector internal allocation. */ |
/* P points to somewhere inside an object with */ |
/* These assume the collector lock is held. */ |
/* debugging info. Print a human readable */ |
#ifdef DBG_HDRS_ALL |
/* description of the object to stderr. */ |
extern GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k); |
extern void (*GC_check_heap)(); |
extern GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, |
/* Check that all objects in the heap with */ |
int k); |
/* debugging info are intact. Print */ |
# define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner |
/* descriptions of any that are not. */ |
# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \ |
extern void (*GC_print_heap_obj)(/* ptr_t p */); |
GC_debug_generic_malloc_inner_ignore_off_page |
/* If possible print s followed by a more */ |
# ifdef THREADS |
/* detailed description of the object */ |
# define GC_INTERNAL_FREE GC_debug_free_inner |
/* referred to by p. */ |
# else |
|
# define GC_INTERNAL_FREE GC_debug_free |
|
# endif |
|
#else |
|
# define GC_INTERNAL_MALLOC GC_generic_malloc_inner |
|
# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \ |
|
GC_generic_malloc_inner_ignore_off_page |
|
# ifdef THREADS |
|
# define GC_INTERNAL_FREE GC_free_inner |
|
# else |
|
# define GC_INTERNAL_FREE GC_free |
|
# endif |
|
#endif |
|
|
/* Memory unmapping: */ |
/* Memory unmapping: */ |
#ifdef USE_MUNMAP |
#ifdef USE_MUNMAP |
void GC_unmap_old(void); |
void GC_unmap_old(void); |
Line 1718 extern void (*GC_print_heap_obj)(/* ptr_t p */); |
|
Line 1751 extern void (*GC_print_heap_obj)(/* ptr_t p */); |
|
|
|
/* Virtual dirty bit implementation: */ |
/* Virtual dirty bit implementation: */ |
/* Each implementation exports the following: */ |
/* Each implementation exports the following: */ |
void GC_read_dirty(); /* Retrieve dirty bits. */ |
void GC_read_dirty GC_PROTO((void)); |
GC_bool GC_page_was_dirty(/* struct hblk * h */); |
/* Retrieve dirty bits. */ |
/* Read retrieved dirty bits. */ |
GC_bool GC_page_was_dirty GC_PROTO((struct hblk *h)); |
GC_bool GC_page_was_ever_dirty(/* struct hblk * h */); |
/* Read retrieved dirty bits. */ |
/* Could the page contain valid heap pointers? */ |
GC_bool GC_page_was_ever_dirty GC_PROTO((struct hblk *h)); |
void GC_is_fresh(/* struct hblk * h, word number_of_blocks */); |
/* Could the page contain valid heap pointers? */ |
/* Assert the region currently contains no */ |
void GC_is_fresh GC_PROTO((struct hblk *h, word n)); |
/* valid pointers. */ |
/* Assert the region currently contains no */ |
void GC_write_hint(/* struct hblk * h */); |
/* valid pointers. */ |
/* h is about to be written. */ |
void GC_write_hint GC_PROTO((struct hblk *h)); |
void GC_dirty_init(); |
/* h is about to be written. */ |
|
void GC_dirty_init GC_PROTO((void)); |
|
|
/* Slow/general mark bit manipulation: */ |
/* Slow/general mark bit manipulation: */ |
GC_API GC_bool GC_is_marked(); |
GC_API GC_bool GC_is_marked GC_PROTO((ptr_t p)); |
void GC_clear_mark_bit(); |
void GC_clear_mark_bit GC_PROTO((ptr_t p)); |
void GC_set_mark_bit(); |
void GC_set_mark_bit GC_PROTO((ptr_t p)); |
|
|
/* Stubborn objects: */ |
/* Stubborn objects: */ |
void GC_read_changed(); /* Analogous to GC_read_dirty */ |
void GC_read_changed GC_PROTO((void)); /* Analogous to GC_read_dirty */ |
GC_bool GC_page_was_changed(/* h */); /* Analogous to GC_page_was_dirty */ |
GC_bool GC_page_was_changed GC_PROTO((struct hblk * h)); |
void GC_clean_changing_list(); /* Collect obsolete changing list entries */ |
/* Analogous to GC_page_was_dirty */ |
void GC_stubborn_init(); |
void GC_clean_changing_list GC_PROTO((void)); |
|
/* Collect obsolete changing list entries */ |
|
void GC_stubborn_init GC_PROTO((void)); |
|
|
/* Debugging print routines: */ |
/* Debugging print routines: */ |
void GC_print_block_list(); |
void GC_print_block_list GC_PROTO((void)); |
void GC_print_hblkfreelist(); |
void GC_print_hblkfreelist GC_PROTO((void)); |
void GC_print_heap_sects(); |
void GC_print_heap_sects GC_PROTO((void)); |
void GC_print_static_roots(); |
void GC_print_static_roots GC_PROTO((void)); |
void GC_dump(); |
void GC_dump GC_PROTO((void)); |
|
|
#ifdef KEEP_BACK_PTRS |
#ifdef KEEP_BACK_PTRS |
void GC_store_back_pointer(ptr_t source, ptr_t dest); |
void GC_store_back_pointer(ptr_t source, ptr_t dest); |
Line 1765 void GC_dump(); |
|
Line 1801 void GC_dump(); |
|
GC_API void GC_noop(); |
GC_API void GC_noop(); |
# endif |
# endif |
|
|
void GC_noop1(/* word arg */); |
void GC_noop1 GC_PROTO((word arg)); |
|
|
/* Logging and diagnostic output: */ |
/* Logging and diagnostic output: */ |
GC_API void GC_printf GC_PROTO((char * format, long, long, long, long, long, long)); |
GC_API void GC_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long)); |
/* A version of printf that doesn't allocate, */ |
/* A version of printf that doesn't allocate, */ |
/* is restricted to long arguments, and */ |
/* is restricted to long arguments, and */ |
/* (unfortunately) doesn't use varargs for */ |
/* (unfortunately) doesn't use varargs for */ |
Line 1787 GC_API void GC_printf GC_PROTO((char * format, long, l |
|
Line 1823 GC_API void GC_printf GC_PROTO((char * format, long, l |
|
# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \ |
# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \ |
(long)d, (long)e, (long)g) |
(long)d, (long)e, (long)g) |
|
|
void GC_err_printf(/* format, a, b, c, d, e, f */); |
GC_API void GC_err_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long)); |
# define GC_err_printf0(f) GC_err_puts(f) |
# define GC_err_printf0(f) GC_err_puts(f) |
# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l) |
# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l) |
# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l) |
# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l) |
Line 1803 void GC_err_printf(/* format, a, b, c, d, e, f */); |
|
Line 1839 void GC_err_printf(/* format, a, b, c, d, e, f */); |
|
(long)e, (long)g) |
(long)e, (long)g) |
/* Ditto, writes to stderr. */ |
/* Ditto, writes to stderr. */ |
|
|
void GC_err_puts(/* char *s */); |
void GC_err_puts GC_PROTO((GC_CONST char *s)); |
/* Write s to stderr, don't buffer, don't add */ |
/* Write s to stderr, don't buffer, don't add */ |
/* newlines, don't ... */ |
/* newlines, don't ... */ |
|
|
|
#if defined(LINUX) && !defined(SMALL_CONFIG) |
|
void GC_err_write GC_PROTO((GC_CONST char *buf, size_t len)); |
|
/* Write buf to stderr, don't buffer, don't add */ |
|
/* newlines, don't ... */ |
|
#endif |
|
|
# ifdef GC_ASSERTIONS |
|
|
# ifdef GC_ASSERTIONS |
# define GC_ASSERT(expr) if(!(expr)) {\ |
# define GC_ASSERT(expr) if(!(expr)) {\ |
GC_err_printf2("Assertion failure: %s:%ld\n", \ |
GC_err_printf2("Assertion failure: %s:%ld\n", \ |
__FILE__, (unsigned long)__LINE__); \ |
__FILE__, (unsigned long)__LINE__); \ |
ABORT("assertion failure"); } |
ABORT("assertion failure"); } |
# else |
# else |
# define GC_ASSERT(expr) |
# define GC_ASSERT(expr) |
# endif |
# endif |
|
|
|
# ifdef PARALLEL_MARK |
|
/* We need additional synchronization facilities from the thread */ |
|
/* support. We believe these are less performance critical */ |
|
/* than the main garbage collector lock; standard pthreads-based */ |
|
/* implementations should be sufficient. */ |
|
|
|
/* The mark lock and condition variable. If the GC lock is also */ |
|
/* acquired, the GC lock must be acquired first. The mark lock is */ |
|
/* used to both protect some variables used by the parallel */ |
|
/* marker, and to protect GC_fl_builder_count, below. */ |
|
/* GC_notify_all_marker() is called when */ |
|
/* the state of the parallel marker changes */ |
|
/* in some significant way (see gc_mark.h for details). The */ |
|
/* latter set of events includes incrementing GC_mark_no. */ |
|
/* GC_notify_all_builder() is called when GC_fl_builder_count */ |
|
/* reaches 0. */ |
|
|
|
extern void GC_acquire_mark_lock(); |
|
extern void GC_release_mark_lock(); |
|
extern void GC_notify_all_marker(); |
|
extern void GC_notify_all_builder(); |
|
extern void GC_wait_marker(); |
|
/* extern void GC_wait_builder(); */ |
|
extern void GC_wait_for_reclaim(); |
|
|
|
extern word GC_fl_builder_count; /* Protected by mark lock. */ |
|
extern word GC_mark_no; /* Protected by mark lock. */ |
|
|
|
extern void GC_help_marker(word my_mark_no); |
|
/* Try to help out parallel marker for mark cycle */ |
|
/* my_mark_no. Returns if the mark cycle finishes or */ |
|
/* was already done, or there was nothing to do for */ |
|
/* some other reason. */ |
|
# endif /* PARALLEL_MARK */ |
|
|
# endif /* GC_PRIVATE_H */ |
# endif /* GC_PRIVATE_H */ |