=================================================================== RCS file: /home/cvs/OpenXM_contrib2/asir2000/gc/include/private/gc_priv.h,v retrieving revision 1.2 retrieving revision 1.3 diff -u -p -r1.2 -r1.3 --- OpenXM_contrib2/asir2000/gc/include/private/gc_priv.h 2000/04/10 08:31:36 1.2 +++ OpenXM_contrib2/asir2000/gc/include/private/gc_priv.h 2001/04/20 07:39:26 1.3 @@ -2,7 +2,7 @@ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. - * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. + * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved. * * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED @@ -14,7 +14,6 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, February 16, 1996 2:30 pm PST */ # ifndef GC_PRIVATE_H @@ -41,16 +40,16 @@ # include "gc.h" # endif -typedef GC_word word; -typedef GC_signed_word signed_word; +# ifndef GC_MARK_H +# include "../gc_mark.h" +# endif -# ifndef CONFIG_H +# ifndef GCCONFIG_H # include "gcconfig.h" # endif -# ifndef HEADERS_H -# include "gc_hdrs.h" -# endif +typedef GC_word word; +typedef GC_signed_word signed_word; typedef int GC_bool; # define TRUE 1 @@ -61,6 +60,10 @@ typedef char * ptr_t; /* A generic pointer to which we /* Preferably identical to caddr_t, if it */ /* exists. */ +# ifndef HEADERS_H +# include "gc_hdrs.h" +# endif + #if defined(__STDC__) # include # if !(defined( sony_news ) ) @@ -74,14 +77,37 @@ typedef char * ptr_t; /* A generic pointer to which we # define VOLATILE #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 #else # define GC_FAR #endif + /*********************************/ /* */ /* Definitions for conservative */ @@ -95,12 +121,10 @@ typedef char * ptr_t; /* A generic pointer to which we /* */ /*********************************/ -#define STUBBORN_ALLOC /* Define stubborn allocation primitives */ -#if defined(SRC_M3) || defined(SMALL_CONFIG) -# undef STUBBORN_ALLOC -#endif +/* #define STUBBORN_ALLOC */ + /* Enable stubborm allocation, and thus a limited */ + /* form of incremental collection w/o dirty bits. */ - /* #define ALL_INTERIOR_POINTERS */ /* Forces all pointers into the interior of an */ /* object to be considered valid. Also causes the */ @@ -126,6 +150,8 @@ typedef char * ptr_t; /* A generic pointer to which we /* touched. */ /* If you can easily avoid using this option, do. */ /* 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 */ /* For less verbose output, undefine in reclaim.c */ @@ -156,12 +182,12 @@ typedef char * ptr_t; /* A generic pointer to which we # define GATHERSTATS #endif -#ifdef FINALIZE_ON_DEMAND -# define GC_INVOKE_FINALIZERS() -#else -# define GC_INVOKE_FINALIZERS() (void)GC_invoke_finalizers() +#if defined(PRINTSTATS) || !defined(SMALL_CONFIG) +# define CONDPRINT /* Print some things if GC_print_stats is set */ #endif +#define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers() + #define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */ /* free lists are actually maintained. This applies */ /* only to the top level routines in misc.c, not to */ @@ -173,13 +199,10 @@ typedef char * ptr_t; /* A generic pointer to which we /* May save significant amounts of space for obj_map */ /* entries. */ -#ifndef OLD_BLOCK_ALLOC - /* Macros controlling large block allocation strategy. */ -# define EXACT_FIRST /* Make a complete pass through the large object */ - /* free list before splitting a block */ -# define PRESERVE_LAST /* Do not divide last allocated heap segment */ - /* unless we would otherwise need to expand the */ - /* heap. */ +#if defined(USE_MARK_BYTES) && !defined(ALIGN_DOUBLE) +# define ALIGN_DOUBLE + /* We use one byte for every 2 words, which doesn't allow for */ + /* odd numbered words to have mark bits. */ #endif /* ALIGN_DOUBLE requires MERGE_SIZES at present. */ @@ -187,15 +210,17 @@ typedef char * ptr_t; /* A generic pointer to which we # define MERGE_SIZES # endif -#if defined(ALL_INTERIOR_POINTERS) && !defined(DONT_ADD_BYTE_AT_END) -# define ADD_BYTE_AT_END +#if !defined(DONT_ADD_BYTE_AT_END) +# define EXTRA_BYTES GC_all_interior_pointers +#else +# define EXTRA_BYTES 0 #endif # ifndef LARGE_CONFIG -# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */ - /* Must be multiple of largest page size. */ -# define MAXHINCR 512 /* Maximum heap increment, in blocks */ +# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */ + /* Must be multiple of largest page size. */ +# define MAXHINCR 2048 /* Maximum heap increment, in blocks */ # else # define MINHINCR 64 # define MAXHINCR 4096 @@ -228,18 +253,23 @@ typedef char * ptr_t; /* A generic pointer to which we * Number of frames and arguments to save in objects allocated by * 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. */ +# else +# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1) +# endif # define NARGS 2 /* Mumber of arguments to save for each call. */ # define NEED_CALLINFO /* Fill in the pc and argument information for up to NFRAMES of my */ /* 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 # ifdef GC_ADD_CALLER @@ -252,7 +282,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES #ifdef NEED_CALLINFO struct callinfo { - word ci_pc; + word ci_pc; /* Caller, not callee, pc */ # if NARGS > 0 word ci_arg[NARGS]; /* bit-wise complement to avoid retention */ # endif @@ -281,6 +311,13 @@ void GC_print_callers (/* struct callinfo info[NFRAMES # define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \ + (double) (a.tv_usec - b.tv_usec) / 1000.0) #else /* !BSD_TIME */ +# if defined(MSWIN32) || defined(MSWINCE) +# include +# include +# 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 # if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4) clock_t clock(); /* Not in time.h, where it belongs */ @@ -306,6 +343,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES # define GET_TIME(x) x = clock() # define MS_TIME_DIFF(a,b) ((unsigned long) \ (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC)) +# endif /* !MSWIN32 */ #endif /* !BSD_TIME */ /* We use bzero and bcopy internally. They may not be available. */ @@ -325,6 +363,9 @@ void GC_print_callers (/* struct callinfo info[NFRAMES # include # define BCOPY_EXISTS # endif +# if defined(MACOSX) +# define BCOPY_EXISTS +# endif # ifndef BCOPY_EXISTS # include @@ -342,6 +383,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES /* GET_MEM is currently not assumed to retrieve 0 filled space, */ /* though we should perhaps take advantage of the case in which */ /* does. */ +struct hblk; /* See below. */ # ifdef PCR char * real_malloc(); # define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \ @@ -353,7 +395,8 @@ void GC_print_callers (/* struct callinfo info[NFRAMES + GC_page_size) \ + GC_page_size-1) # 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) \ calloc(1, (size_t)bytes + GC_page_size) \ + GC_page_size-1) @@ -374,258 +417,26 @@ void GC_print_callers (/* struct callinfo info[NFRAMES NewPtrClear(bytes + GC_page_size) + GC_page_size-1) # endif # else - extern ptr_t GC_unix_get_mem(); -# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes) +# ifdef MSWINCE + 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 -/* - * 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 -# include - 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 -# include - 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 -# 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 - 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 -# ifndef HPUX_THREADS - /* This probably should never be included, but I can't test */ - /* on Irix anymore. */ -# include -# 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 - 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 */ /* structures are in a consistent state outside this pair of calls. */ /* ANSI C allows both to be empty (though the standard isn't very */ @@ -639,9 +450,9 @@ addr) PCR_Th_SetSigMask(&GC_old_sig_mask, NIL) # else # if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \ - || defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \ - || defined(NO_SIGNALS) || defined(IRIX_THREADS) \ - || defined(IRIX_JDK_THREADS) || defined(LINUX_THREADS) + || defined(MSWIN32) || defined(MSWINCE) || defined(MACOS) \ + || defined(DJGPP) || defined(NO_SIGNALS) || defined(IRIX_THREADS) \ + || defined(LINUX_THREADS) /* Also useful for debugging. */ /* Should probably use thr_sigsetmask for SOLARIS_THREADS. */ # define DISABLE_SIGNALS() @@ -670,7 +481,7 @@ addr) # else # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \ - || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) + || defined(HPUX_THREADS) void GC_stop_world(); void GC_start_world(); # define STOP_WORLD() GC_stop_world() @@ -704,6 +515,13 @@ addr) # define WARN(msg,arg) (*GC_current_warn_proc)(msg, (GC_word)(arg)) 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 */ @@ -733,7 +551,7 @@ extern GC_warn_proc GC_current_warn_proc; #define WORDSZ ((word)CPP_WORDSZ) #define SIGNB ((word)1 << (WORDSZ-1)) #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 */ /*********************/ @@ -786,6 +604,8 @@ extern GC_warn_proc GC_current_warn_proc; /* max size objects supported by freelist (larger objects may be */ /* 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 MAXOBJSZ ((word)CPP_MAXOBJSZ) @@ -806,25 +626,28 @@ extern GC_warn_proc GC_current_warn_proc; # define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1)) /* Round up byte allocation requests to integral number of words, etc. */ -# ifdef ADD_BYTE_AT_END -# define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1)) -# 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 ROUNDED_UP_WORDS(n) \ + BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1 + EXTRA_BYTES)) +# ifdef ALIGN_DOUBLE # define ALIGNED_WORDS(n) \ - (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1) & ~1) -# else + (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1 + EXTRA_BYTES) & ~1) +# else # 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 -# define SMALL_OBJ(bytes) ((bytes) <= WORDS_TO_BYTES(MAXOBJSZ)) -# define ADD_SLOP(bytes) (bytes) # endif @@ -835,11 +658,19 @@ extern GC_warn_proc GC_current_warn_proc; */ # 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 -# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */ - /* to more than 16K hblks = 64MB. */ - /* Each hash table occupies 2K bytes. */ +# ifdef SMALL_CONFIG +# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */ + /* 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 # define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES) # define PHT_SIZE (PHT_ENTRIES >> LOGWL) @@ -853,6 +684,10 @@ typedef word page_hash_table[PHT_SIZE]; (bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index) # define clear_pht_entry_from_index(bl, 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 @@ -865,21 +700,29 @@ typedef word page_hash_table[PHT_SIZE]; /* heap block header */ #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) /* 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. */ -# ifdef ALIGN_DOUBLE -# define MARK_BITS_SZ (((MARK_BITS_PER_HBLK + 2*CPP_WORDSZ - 1) \ - / (2*CPP_WORDSZ))*2) +# ifdef USE_MARK_BYTES +# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/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 -# define MARK_BITS_SZ ((MARK_BITS_PER_HBLK + CPP_WORDSZ - 1)/CPP_WORDSZ) +# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ) # 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 { word hb_sz; /* If in use, size in words, of objects in the block. */ /* if free, the size in bytes of the whole block */ @@ -889,7 +732,8 @@ struct hblkhdr { struct hblk * hb_prev; /* Backwards link for free list. */ word hb_descr; /* object descriptor for marking. See */ /* 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. */ /* Valid for all blocks with headers. */ /* Free blocks point to GC_invalid_map. */ @@ -911,11 +755,20 @@ struct hblkhdr { /* Value of GC_gc_no when block was */ /* last allocated or swept. May wrap. */ /* 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 size of the block last */ /* 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 */ /* object starting at the ith word (header */ /* INCLUDED) in the heap block. */ @@ -923,42 +776,28 @@ struct hblkhdr { /* Unused bits are invalid, and are */ /* occasionally set, e.g for uncollectable */ /* objects. */ +# endif /* !USE_MARK_BYTES */ }; /* heap block body */ -# define DISCARD_WORDS 0 - /* 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/sizeof(word)) -# define BODY_SZ ((HBLKSIZE-WORDS_TO_BYTES(DISCARD_WORDS))/sizeof(word)) - struct hblk { -# if (DISCARD_WORDS != 0) +# if 0 /* DISCARDWORDS no longer supported */ word garbage[DISCARD_WORDS]; # endif 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) \ - 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 */ /* given sz (in words). */ /* Object free list link */ # 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 MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) @@ -972,12 +811,12 @@ typedef struct ms_entry * (*mark_proc)(/* word * addr, # ifdef PCR # define MAX_ROOT_SETS 1024 # else -# ifdef MSWIN32 -# define MAX_ROOT_SETS 512 +# if defined(MSWIN32) || defined(MSWINCE) +# define MAX_ROOT_SETS 1024 /* Under NT, we add only written pages, which can result */ /* in many small root sets. */ # else -# define MAX_ROOT_SETS 64 +# define MAX_ROOT_SETS 256 # endif # endif # endif @@ -1000,14 +839,14 @@ struct exclusion { struct roots { ptr_t r_start; ptr_t r_end; -# ifndef MSWIN32 +# if !defined(MSWIN32) && !defined(MSWINCE) struct roots * r_next; # endif GC_bool r_tmp; /* Delete before registering new dynamic libraries */ }; -#ifndef MSWIN32 +#if !defined(MSWIN32) && !defined(MSWINCE) /* Size of hash table index to roots. */ # define LOG_RT_SIZE 6 # define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */ @@ -1035,16 +874,28 @@ struct roots { struct _GC_arrays { word _heapsize; word _max_heapsize; + word _requested_heapsize; /* Heap size due to explicit expansion */ ptr_t _last_heap_addr; ptr_t _prev_heap_addr; word _large_free_bytes; /* Total bytes contained in blocks on large object free */ /* 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; /* Number of words allocated before this */ /* collection cycle. */ - word _words_allocd; +# ifndef SEPARATE_GLOBALS + word _words_allocd; /* Number of words allocated during this collection cycle */ +# endif word _words_wasted; /* Number of words wasted due to internal fragmentation */ /* in large objects, or due to dropping blacklisted */ @@ -1059,14 +910,21 @@ struct _GC_arrays { word _mem_freed; /* Number of explicitly deallocated words of memory */ /* 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 */ /* a small number of these, which can be referenced */ /* 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 */ - ptr_t _aobjfreelist[MAXOBJSZ+1]; + ptr_t _aobjfreelist[MAXOBJSZ+1]; /* free list for atomic objs */ +# endif ptr_t _uobjfreelist[MAXOBJSZ+1]; /* uncollectable but traced objs */ @@ -1099,41 +957,28 @@ struct _GC_arrays { ptr_t _sobjfreelist[MAXOBJSZ+1]; # endif /* 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 */ /* object addresses. _obj_map[sz][i] is j if the */ /* address block_start+i is a valid pointer */ - /* to an object at */ - /* block_start+i&~3 - WORDS_TO_BYTES(j). */ - /* (If ALL_INTERIOR_POINTERS is defined, then */ - /* instead ((short *)(hb_map[sz])[i] is j if */ - /* block_start+WORDS_TO_BYTES(i) is in the */ - /* interior of an object starting at */ - /* block_start+WORDS_TO_BYTES(i-j)). */ - /* It is OBJ_INVALID if */ - /* block_start+WORDS_TO_BYTES(i) is not */ - /* valid as a pointer to an object. */ - /* We assume all values of j <= OBJ_INVALID. */ - /* The zeroth entry corresponds to large objects.*/ -# ifdef ALL_INTERIOR_POINTERS -# define map_entry_type short -# define OBJ_INVALID 0x7fff -# define MAP_ENTRY(map, bytes) \ - (((map_entry_type *)(map))[BYTES_TO_WORDS(bytes)]) -# define MAP_ENTRIES BYTES_TO_WORDS(HBLKSIZE) -# 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) + /* to an object at block_start + */ + /* WORDS_TO_BYTES(BYTES_TO_WORDS(i) - j) */ + /* I.e. j is a word displacement from the */ + /* object beginning. */ + /* The entry is OBJ_INVALID if the corresponding */ + /* address is not a valid pointer. It is */ + /* OFFSET_TOO_BIG if the value j would be too */ + /* large to fit in the entry. (Note that the */ + /* size of these entries matters, both for */ + /* space consumption and for cache utilization. */ +# define OFFSET_TOO_BIG 0xfe +# define OBJ_INVALID 0xff +# define MAP_ENTRY(map, bytes) (map)[bytes] +# define MAP_ENTRIES HBLKSIZE +# define MAP_SIZE MAP_ENTRIES +# define CPP_MAX_OFFSET (OFFSET_TOO_BIG - 1) +# define MAX_OFFSET ((word)CPP_MAX_OFFSET) + /* The following are used only if GC_all_interior_ptrs != 0 */ # define VALID_OFFSET_SZ \ (CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \ CPP_MAX_OFFSET+1 \ @@ -1141,11 +986,11 @@ struct _GC_arrays { char _valid_offsets[VALID_OFFSET_SZ]; /* GC_valid_offsets[i] == TRUE ==> i */ /* 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)]; /* GC_valid_offsets[i] ==> */ /* GC_modws_valid_offsets[i%sizeof(word)] */ -# endif # ifdef STUBBORN_ALLOC page_hash_table _changed_pages; /* Stubborn object pages that were changes since last call to */ @@ -1172,17 +1017,25 @@ struct _GC_arrays { # define MAX_HEAP_SECTS 768 /* Separately added heap sections. */ # endif # 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 struct HeapSect { ptr_t hs_start; word hs_bytes; } _heap_sects[MAX_HEAP_SECTS]; -# ifdef MSWIN32 +# if defined(MSWIN32) || defined(MSWINCE) ptr_t _heap_bases[MAX_HEAP_SECTS]; /* Start address of memory regions obtained from kernel. */ # 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]; -# ifndef MSWIN32 +# if !defined(MSWIN32) && !defined(MSWINCE) struct roots * _root_index[RT_SIZE]; # endif struct exclusion _excl_table[MAX_EXCLUSIONS]; @@ -1201,8 +1054,11 @@ struct _GC_arrays { GC_API GC_FAR struct _GC_arrays GC_arrays; -# define GC_objfreelist GC_arrays._objfreelist -# define GC_aobjfreelist GC_arrays._aobjfreelist +# ifndef SEPARATE_GLOBALS +# 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 # ifdef ATOMIC_UNCOLLECTABLE # define GC_auobjfreelist GC_arrays._auobjfreelist @@ -1217,24 +1073,31 @@ GC_API GC_FAR struct _GC_arrays GC_arrays; # define GC_obj_map GC_arrays._obj_map # define GC_last_heap_addr GC_arrays._last_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_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_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc # 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_heapsize GC_arrays._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_heap_sects GC_arrays._heap_sects # define GC_last_stack GC_arrays._last_stack # ifdef USE_MUNMAP # define GC_unmapped_bytes GC_arrays._unmapped_bytes # endif -# ifdef MSWIN32 +# if defined(MSWIN32) || defined(MSWINCE) # define GC_heap_bases GC_arrays._heap_bases # endif +# ifdef MSWINCE +# define GC_heap_lengths GC_arrays._heap_lengths +# endif # define GC_static_roots GC_arrays._static_roots # define GC_root_index GC_arrays._root_index # define GC_excl_table GC_arrays._excl_table @@ -1260,6 +1123,8 @@ GC_API GC_FAR struct _GC_arrays GC_arrays; # define beginGC_arrays ((ptr_t)(&GC_arrays)) # define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays)) +#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes) + /* Object kinds: */ # define MAXOBJKINDS 16 @@ -1279,11 +1144,28 @@ extern struct obj_kind { GC_bool ok_init; /* Clear objects before putting them on the free list. */ } 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) ? \ - endGC_obj_kinds : endGC_arrays) +/* Variables that used to be in GC_arrays, but need to be accessed by */ +/* 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: */ # define PTRFREE 0 # define NORMAL 1 @@ -1306,8 +1188,10 @@ extern word GC_n_heap_sects; /* Number of separately a extern word GC_page_size; -# ifdef MSWIN32 -extern word GC_n_heap_bases; /* See GC_heap_bases. */ +# if defined(MSWIN32) || defined(MSWINCE) + struct _SYSTEM_INFO; + extern struct _SYSTEM_INFO GC_sysinfo; + extern word GC_n_heap_bases; /* See GC_heap_bases. */ # endif extern word GC_total_stack_black_listed; @@ -1320,7 +1204,7 @@ extern word GC_black_list_spacing; /* "stack-blacklisted", i.e. that are */ /* 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 */ /* Blocks pointing to this map are free. */ @@ -1339,7 +1223,7 @@ extern GC_bool GC_objects_are_marked; /* There are mar extern GC_bool GC_incremental; /* Using incremental/generational collection. */ #else -# define GC_incremental TRUE +# define GC_incremental FALSE /* Hopefully allow optimizer to remove some code. */ #endif @@ -1352,10 +1236,6 @@ extern word GC_root_size; /* Total size of registered 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 */ # ifndef abs @@ -1368,6 +1248,33 @@ extern ptr_t GC_greatest_plausible_heap_addr; /* with it. Only those corresponding to the beginning of an */ /* 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 */ @@ -1379,75 +1286,87 @@ extern ptr_t GC_greatest_plausible_heap_addr; * 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)] \ >> (modWORDSZ(n))) & (word)1) -# define set_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \ - |= (word)1 << modWORDSZ(n) - +# define set_mark_bit_from_hdr(hhdr,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)] \ &= ~((word)1 << modWORDSZ(n)) +#endif /* !USE_MARK_BYTES */ /* Important internal collector routines */ -ptr_t GC_approx_sp(); - -GC_bool GC_should_collect(); -#ifdef PRESERVE_LAST - GC_bool GC_in_last_heap_sect(/* ptr_t */); - /* In last added heap section? If so, avoid breaking up. */ -#endif -void GC_apply_to_all_blocks(/*fn, client_data*/); - /* Invoke fn(hbp, client_data) for each */ - /* allocated heap block. */ -struct hblk * GC_next_used_block(/* struct hblk * h */); - /* Return first in-use block >= h */ -struct hblk * GC_prev_block(/* struct hblk * h */); - /* Return last block <= h. Returned block */ - /* is managed by GC, but may or may not be in */ +ptr_t GC_approx_sp GC_PROTO((void)); + +GC_bool GC_should_collect GC_PROTO((void)); + +void GC_apply_to_all_blocks GC_PROTO(( \ + void (*fn) GC_PROTO((struct hblk *h, word client_data)), \ + word client_data)); + /* Invoke fn(hbp, client_data) for each */ + /* allocated heap block. */ +struct hblk * GC_next_used_block GC_PROTO((struct hblk * h)); + /* Return first in-use block >= h */ +struct hblk * GC_prev_block GC_PROTO((struct hblk * h)); + /* Return last block <= h. Returned block */ + /* is managed by GC, but may or may not be in */ /* use. */ -void GC_mark_init(); -void GC_clear_marks(); /* Clear mark bits for all heap objects. */ -void GC_invalidate_mark_state(); /* Tell the marker that marked */ - /* objects may point to unmarked */ - /* ones, and roots may point to */ - /* unmarked objects. */ - /* Reset mark stack. */ -void GC_mark_from_mark_stack(); /* Mark from everything on the mark stack. */ - /* Return after about one pages worth of */ - /* work. */ -GC_bool GC_mark_stack_empty(); -GC_bool GC_mark_some(/* cold_gc_frame */); - /* Perform about one pages worth of marking */ - /* work of whatever kind is needed. Returns */ - /* quickly if no collection is in progress. */ - /* Return TRUE if mark phase finished. */ -void GC_initiate_gc(); /* initiate collection. */ - /* If the mark state is invalid, this */ - /* becomes full colleection. Otherwise */ - /* it's partial. */ -void GC_push_all(/*b,t*/); /* Push everything in a range */ - /* onto mark stack. */ -void GC_push_dirty(/*b,t*/); /* Push all possibly changed */ - /* subintervals of [b,t) onto */ - /* mark stack. */ +void GC_mark_init GC_PROTO((void)); +void GC_clear_marks GC_PROTO((void)); /* Clear mark bits for all heap objects. */ +void GC_invalidate_mark_state GC_PROTO((void)); + /* Tell the marker that marked */ + /* objects may point to unmarked */ + /* ones, and roots may point to */ + /* unmarked objects. */ + /* Reset mark stack. */ +GC_bool GC_mark_stack_empty GC_PROTO((void)); +GC_bool GC_mark_some GC_PROTO((ptr_t cold_gc_frame)); + /* Perform about one pages worth of marking */ + /* work of whatever kind is needed. Returns */ + /* quickly if no collection is in progress. */ + /* Return TRUE if mark phase finished. */ +void GC_initiate_gc GC_PROTO((void)); + /* initiate collection. */ + /* If the mark state is invalid, this */ + /* becomes full colleection. Otherwise */ + /* it's partial. */ +void GC_push_all GC_PROTO((ptr_t bottom, ptr_t top)); + /* Push everything in a range */ + /* onto mark stack. */ +void GC_push_selected GC_PROTO(( \ + ptr_t bottom, \ + 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 - 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 # define GC_push_conditional(b, t, all) GC_push_all(b, t) #endif /* Do either of the above, depending */ /* 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 */ -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 */ /* immediately, not just scheduled */ /* for scanning. */ #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 */ /* 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. */ #else /* In the threads case, we push part of the current thread stack */ @@ -1456,169 +1375,237 @@ void GC_push_all_eager(/*b,t*/); /* Same as GC_push /* stacks are scheduled for scanning in *GC_push_other_roots, which */ /* is thread-package-specific. */ #endif -void GC_push_current_stack(/* ptr_t cold_gc_frame */); - /* Push enough of the current stack eagerly to */ - /* ensure that callee-save registers saved in */ - /* GC frames are scanned. */ - /* In the non-threads case, schedule entire */ - /* stack for scanning. */ -void GC_push_roots(/* GC_bool all, ptr_t cold_gc_frame */); - /* Push all or dirty roots. */ -extern void (*GC_push_other_roots)(); - /* Push system or application specific roots */ - /* onto the mark stack. In some environments */ - /* (e.g. threads environments) this is */ - /* predfined to be non-zero. A client supplied */ - /* replacement should also call the original */ - /* function. */ -extern void (*GC_start_call_back)(/* void */); - /* Called at start of full collections. */ - /* Not called if 0. Called with allocation */ - /* lock held. */ - /* 0 by default. */ -void GC_push_regs(); /* Push register contents onto mark stack. */ - /* If NURSERY is defined, the default push */ - /* action can be overridden with GC_push_proc */ -void GC_remark(); /* Mark from all marked objects. Used */ - /* only if we had to drop something. */ +void GC_push_current_stack GC_PROTO((ptr_t cold_gc_frame)); + /* Push enough of the current stack eagerly to */ + /* ensure that callee-save registers saved in */ + /* GC frames are scanned. */ + /* In the non-threads case, schedule entire */ + /* stack for scanning. */ +void GC_push_roots GC_PROTO((GC_bool all, ptr_t cold_gc_frame)); + /* Push all or dirty roots. */ +extern void (*GC_push_other_roots) GC_PROTO((void)); + /* Push system or application specific roots */ + /* onto the mark stack. In some environments */ + /* (e.g. threads environments) this is */ + /* predfined to be non-zero. A client supplied */ + /* replacement should also call the original */ + /* function. */ +extern void GC_push_gc_structures GC_PROTO((void)); + /* Push GC internal roots. These are normally */ + /* included in the static data segment, and */ + /* Thus implicitly pushed. But we must do this */ + /* explicitly if normal root processing is */ + /* disabled. Calls the following: */ + extern void GC_push_finalizer_structures GC_PROTO((void)); + extern void GC_push_stubborn_structures GC_PROTO((void)); +# ifdef THREADS + 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 extern void (*GC_push_proc)(ptr_t); # endif -# if defined(MSWIN32) - void __cdecl GC_push_one(); +# if defined(MSWIN32) || defined(MSWINCE) + void __cdecl GC_push_one GC_PROTO((word p)); # 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 */ + /* Pointer recognition test always */ + /* accepts interior pointers, i.e. this */ + /* is appropriate for pointers found on */ + /* stack. */ # endif -void GC_push_one_checked(/*p*/); /* Ditto, omits plausibility test */ -void GC_push_marked(/* struct hblk h, hdr * hhdr */); +# if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS) + 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 */ /* mark stack. */ #ifdef SMALL_CONFIG # define GC_push_next_marked_dirty(h) GC_push_next_marked(h) #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. */ /* Return a pointer just past the end of this block. */ #endif /* !SMALL_CONFIG */ -struct hblk * GC_push_next_marked(/* h */); - /* Ditto, but also mark from clean pages. */ -struct hblk * GC_push_next_marked_uncollectable(/* h */); - /* Ditto, but mark only from uncollectable pages. */ -GC_bool GC_stopped_mark(); /* Stop world and mark from all roots */ - /* and rescuers. */ -void GC_clear_hdr_marks(/* hhdr */); /* Clear the mark bits in a header */ -void GC_set_hdr_marks(/* hhdr */); /* Set the mark bits in a header */ -void GC_add_roots_inner(); -GC_bool GC_is_static_root(/* ptr_t p */); - /* Is the address p in one of the registered static */ +struct hblk * GC_push_next_marked GC_PROTO((struct hblk * h)); + /* Ditto, but also mark from clean pages. */ +struct hblk * GC_push_next_marked_uncollectable GC_PROTO((struct hblk * h)); + /* Ditto, but mark only from uncollectable pages. */ +GC_bool GC_stopped_mark GC_PROTO((GC_stop_func stop_func)); + /* Stop world and mark from all roots */ + /* and rescuers. */ +void GC_clear_hdr_marks GC_PROTO((hdr * hhdr)); + /* Clear the mark bits in a header */ +void GC_set_hdr_marks GC_PROTO((hdr * hhdr)); + /* 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? */ -void GC_register_dynamic_libraries(); - /* Add dynamic library data sections to the root set. */ - +# endif +void GC_register_dynamic_libraries GC_PROTO((void)); + /* Add dynamic library data sections to the root set. */ + /* Machine dependent startup routines */ -ptr_t GC_get_stack_base(); -void GC_register_data_segments(); - +ptr_t GC_get_stack_base GC_PROTO((void)); /* Cold end of stack */ +#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: */ -void GC_bl_init(); -# ifndef ALL_INTERIOR_POINTERS - void GC_add_to_black_list_normal(/* bits, maybe source */); +void GC_bl_init GC_PROTO((void)); +# ifdef PRINT_BLACK_LIST + void GC_add_to_black_list_normal GC_PROTO((word p, ptr_t source)); /* Register bits as a possible future false */ /* reference from the heap or static data */ -# ifdef PRINT_BLACK_LIST # define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ - GC_add_to_black_list_normal(bits, source) -# else -# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ - GC_add_to_black_list_normal(bits) -# endif + if (GC_all_interior_pointers) { \ + GC_add_to_black_list_stack(bits, source); \ + } else { \ + GC_add_to_black_list_normal(bits, source); \ + } # 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) \ - GC_add_to_black_list_stack(bits, source) -# else -# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ - GC_add_to_black_list_stack(bits) -# endif + if (GC_all_interior_pointers) { \ + GC_add_to_black_list_stack(bits); \ + } else { \ + GC_add_to_black_list_normal(bits); \ + } # endif -void GC_add_to_black_list_stack(/* bits, maybe source */); -struct hblk * GC_is_black_listed(/* h, len */); - /* If there are likely to be false references */ - /* to a block starting at h of the indicated */ - /* length, then return the next plausible */ - /* starting location for h that might avoid */ - /* these false references. */ -void GC_promote_black_lists(); - /* Declare an end to a black listing phase. */ -void GC_unpromote_black_lists(); - /* Approximately undo the effect of the above. */ - /* This actually loses some information, but */ - /* only in a reasonably safe way. */ -word GC_number_stack_black_listed(/*struct hblk *start, struct hblk *endp1 */); - /* Return the number of (stack) blacklisted */ - /* blocks in the range for statistical */ - /* purposes. */ - -ptr_t GC_scratch_alloc(/*bytes*/); - /* GC internal memory allocation for */ - /* small objects. Deallocation is not */ - /* possible. */ - +# ifdef PRINT_BLACK_LIST + void GC_add_to_black_list_stack GC_PROTO((word p, ptr_t source)); +# else + void GC_add_to_black_list_stack GC_PROTO((word p)); +# endif +struct hblk * GC_is_black_listed GC_PROTO((struct hblk * h, word len)); + /* If there are likely to be false references */ + /* to a block starting at h of the indicated */ + /* length, then return the next plausible */ + /* starting location for h that might avoid */ + /* these false references. */ +void GC_promote_black_lists GC_PROTO((void)); + /* Declare an end to a black listing phase. */ +void GC_unpromote_black_lists GC_PROTO((void)); + /* Approximately undo the effect of the above. */ + /* This actually loses some information, but */ + /* only in a reasonably safe way. */ +word GC_number_stack_black_listed GC_PROTO(( \ + struct hblk *start, struct hblk *endp1)); + /* Return the number of (stack) blacklisted */ + /* blocks in the range for statistical */ + /* 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: */ -void GC_invalidate_map(/* hdr */); - /* Remove the object map associated */ - /* with the block. This identifies */ - /* the block as invalid to the mark */ - /* routines. */ -GC_bool GC_add_map_entry(/*sz*/); - /* Add a heap block map for objects of */ - /* size sz to obj_map. */ - /* Return FALSE on failure. */ -void GC_register_displacement_inner(/*offset*/); - /* Version of GC_register_displacement */ - /* that assumes lock is already held */ - /* and signals are already disabled. */ - +void GC_invalidate_map GC_PROTO((hdr * hhdr)); + /* Remove the object map associated */ + /* with the block. This identifies */ + /* the block as invalid to the mark */ + /* routines. */ +GC_bool GC_add_map_entry GC_PROTO((word sz)); + /* Add a heap block map for objects of */ + /* size sz to obj_map. */ + /* Return FALSE on failure. */ +void GC_register_displacement_inner GC_PROTO((word offset)); + /* Version of GC_register_displacement */ + /* that assumes lock is already held */ + /* and signals are already disabled. */ + /* hblk allocation: */ -void GC_new_hblk(/*size_in_words, kind*/); - /* Allocate a new heap block, and build */ - /* a free list in it. */ -struct hblk * GC_allochblk(/*size_in_words, kind*/); - /* Allocate a heap block, clear it if */ - /* for composite objects, inform */ +void GC_new_hblk GC_PROTO((word size_in_words, int kind)); + /* Allocate a new heap block, and build */ + /* a free list in it. */ + +ptr_t GC_build_fl GC_PROTO((struct hblk *h, word sz, + 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 */ /* for objects of indicated size. */ - /* sz < 0 ==> atomic. */ -void GC_freehblk(); /* Deallocate a heap block and mark it */ - /* as invalid. */ - + +ptr_t GC_alloc_large GC_PROTO((word lw, int k, unsigned flags)); + /* 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: */ -void GC_init_inner(); -GC_bool GC_expand_hp_inner(); -void GC_start_reclaim(/*abort_if_found*/); - /* Restore unmarked objects to free */ - /* lists, or (if abort_if_found is */ - /* TRUE) report them. */ - /* Sweeping of small object pages is */ - /* largely deferred. */ -void GC_continue_reclaim(/*size, kind*/); - /* Sweep pages of the given size and */ - /* kind, as long as possible, and */ - /* as long as the corr. free list is */ - /* empty. */ -void GC_reclaim_or_delete_all(); - /* Arrange for all reclaim lists to be */ - /* empty. Judiciously choose between */ - /* sweeping and discarding each page. */ -GC_bool GC_reclaim_all(/* GC_stop_func f*/); - /* Reclaim all blocks. Abort (in a */ - /* consistent state) if f returns TRUE. */ -GC_bool GC_block_empty(/* hhdr */); /* Block completely unmarked? */ -GC_bool GC_never_stop_func(); /* Returns FALSE. */ -GC_bool GC_try_to_collect_inner(/* GC_stop_func f */); +void GC_init_inner GC_PROTO((void)); +GC_bool GC_expand_hp_inner GC_PROTO((word n)); +void GC_start_reclaim GC_PROTO((int abort_if_found)); + /* Restore unmarked objects to free */ + /* lists, or (if abort_if_found is */ + /* TRUE) report them. */ + /* Sweeping of small object pages is */ + /* largely deferred. */ +void GC_continue_reclaim GC_PROTO((word sz, int kind)); + /* Sweep pages of the given size and */ + /* kind, as long as possible, and */ + /* as long as the corr. free list is */ + /* empty. */ +void GC_reclaim_or_delete_all GC_PROTO((void)); + /* Arrange for all reclaim lists to be */ + /* empty. Judiciously choose between */ + /* sweeping and discarding each page. */ +GC_bool GC_reclaim_all GC_PROTO((GC_stop_func stop_func, GC_bool ignore_old)); + /* Reclaim all blocks. Abort (in a */ + /* consistent state) if f returns TRUE. */ +GC_bool GC_block_empty GC_PROTO((hdr * hhdr)); + /* Block completely unmarked? */ +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 */ /* lock and disabled signals. */ /* Collection is aborted if f returns */ @@ -1626,87 +1613,133 @@ GC_bool GC_try_to_collect_inner(/* GC_stop_func f */); /* successfully. */ # define GC_gcollect_inner() \ (void) GC_try_to_collect_inner(GC_never_stop_func) -void GC_finish_collection(); /* Finish collection. Mark bits are */ - /* consistent and lock is still held. */ -GC_bool GC_collect_or_expand(/* needed_blocks */); - /* Collect or expand heap in an attempt */ - /* make the indicated number of free */ - /* blocks available. Should be called */ - /* until the blocks are available or */ - /* until it fails by returning FALSE. */ -GC_API void GC_init(); /* Initialize collector. */ -void GC_collect_a_little_inner(/* 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(/* bytes, kind */); - /* Allocate an object of the given */ - /* kind. By default, there are only */ - /* a few kinds: composite(pointerfree), */ +void GC_finish_collection GC_PROTO((void)); + /* Finish collection. Mark bits are */ + /* consistent and lock is still held. */ +GC_bool GC_collect_or_expand GC_PROTO(( \ + word needed_blocks, GC_bool ignore_off_page)); + /* Collect or expand heap in an attempt */ + /* make the indicated number of free */ + /* blocks available. Should be called */ + /* until the blocks are available or */ + /* until it fails by returning FALSE. */ +GC_API void GC_init GC_PROTO((void)); /* Initialize collector. */ + +#if defined(MSWIN32) || defined(MSWINCE) + void GC_deinit GC_PROTO((void)); + /* Free any resources allocated by */ + /* GC_init */ +#endif + +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. */ /* We claim it's possible for clever */ /* client code that understands GC */ /* internals to add more, e.g. to */ /* communicate object layout info */ /* to the collector. */ -ptr_t GC_generic_malloc_ignore_off_page(/* bytes, kind */); - /* As above, but pointers past the */ - /* first page of the resulting object */ - /* are ignored. */ -ptr_t GC_generic_malloc_inner(/* bytes, kind */); - /* Ditto, but I already hold lock, etc. */ -ptr_t GC_generic_malloc_words_small GC_PROTO((size_t words, int kind)); - /* As above, but size in units of words */ - /* Bypasses MERGE_SIZES. Assumes */ - /* words <= MAXOBJSZ. */ -ptr_t GC_generic_malloc_inner_ignore_off_page(/* bytes, kind */); - /* Allocate an object, where */ - /* the client guarantees that there */ - /* will always be a pointer to the */ - /* beginning of the object while the */ - /* object is live. */ -ptr_t GC_allocobj(/* sz_inn_words, kind */); - /* Make the indicated */ - /* free list nonempty, and return its */ - /* head. */ +ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k)); + /* As above, but pointers past the */ + /* first page of the resulting object */ + /* are ignored. */ +ptr_t GC_generic_malloc_inner GC_PROTO((word lb, int k)); + /* Ditto, but I already hold lock, etc. */ +ptr_t GC_generic_malloc_words_small GC_PROTO((size_t lw, int k)); + /* As above, but size in units of words */ + /* Bypasses MERGE_SIZES. Assumes */ + /* words <= MAXOBJSZ. */ +ptr_t GC_generic_malloc_inner_ignore_off_page GC_PROTO((size_t lb, int k)); + /* Allocate an object, where */ + /* the client guarantees that there */ + /* will always be a pointer to the */ + /* beginning of the object while the */ + /* object is live. */ +ptr_t GC_allocobj GC_PROTO((word sz, int kind)); + /* Make the indicated */ + /* free list nonempty, and return its */ + /* 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(); -GC_bool GC_install_header(/*h*/); - /* Install a header for block h. */ - /* Return FALSE on failure. */ -GC_bool GC_install_counts(/*h, sz*/); - /* Set up forwarding counts for block */ - /* h of size sz. */ - /* Return FALSE on failure. */ -void GC_remove_header(/*h*/); - /* Remove the header for block h. */ -void GC_remove_counts(/*h, sz*/); - /* Remove forwarding counts for h. */ -hdr * GC_find_header(/*p*/); /* Debugging only. */ +void GC_notify_or_invoke_finalizers GC_PROTO((void)); + /* If GC_finalize_on_demand is not set, invoke */ + /* eligible finalizers. Otherwise: */ + /* Call *GC_finalizer_notifier if there are */ + /* finalizers to be run, and we haven't called */ + /* this procedure yet this GC cycle. */ + +void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes)); + /* Add a HBLKSIZE aligned chunk to the heap. */ + +void GC_print_obj GC_PROTO((ptr_t p)); + /* P points to somewhere inside an object with */ + /* 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 */ - /* on unmarked objects. */ - /* 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. */ +extern GC_bool GC_print_stats; /* Produce at least some logging output */ + /* Set from environment variable. */ -void GC_print_obj(/* ptr_t p */); - /* P points to somewhere inside an object with */ - /* debugging info. Print a human readable */ - /* description of the object to stderr. */ -extern void (*GC_check_heap)(); - /* 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)(/* ptr_t p */); - /* If possible print s followed by a more */ - /* detailed description of the object */ - /* referred to by p. */ - +/* Macros used for collector internal allocation. */ +/* These assume the collector lock is held. */ +#ifdef DBG_HDRS_ALL + extern GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k); + extern GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, + int k); +# define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner +# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \ + GC_debug_generic_malloc_inner_ignore_off_page +# ifdef THREADS +# define GC_INTERNAL_FREE GC_debug_free_inner +# 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: */ #ifdef USE_MUNMAP void GC_unmap_old(void); @@ -1718,35 +1751,38 @@ extern void (*GC_print_heap_obj)(/* ptr_t p */); /* Virtual dirty bit implementation: */ /* Each implementation exports the following: */ -void GC_read_dirty(); /* Retrieve dirty bits. */ -GC_bool GC_page_was_dirty(/* struct hblk * h */); - /* Read retrieved dirty bits. */ -GC_bool GC_page_was_ever_dirty(/* struct hblk * h */); - /* Could the page contain valid heap pointers? */ -void GC_is_fresh(/* struct hblk * h, word number_of_blocks */); - /* Assert the region currently contains no */ - /* valid pointers. */ -void GC_write_hint(/* struct hblk * h */); - /* h is about to be written. */ -void GC_dirty_init(); - +void GC_read_dirty GC_PROTO((void)); + /* Retrieve dirty bits. */ +GC_bool GC_page_was_dirty GC_PROTO((struct hblk *h)); + /* Read retrieved dirty bits. */ +GC_bool GC_page_was_ever_dirty GC_PROTO((struct hblk *h)); + /* Could the page contain valid heap pointers? */ +void GC_is_fresh GC_PROTO((struct hblk *h, word n)); + /* Assert the region currently contains no */ + /* valid pointers. */ +void GC_write_hint GC_PROTO((struct hblk *h)); + /* h is about to be written. */ +void GC_dirty_init GC_PROTO((void)); + /* Slow/general mark bit manipulation: */ -GC_API GC_bool GC_is_marked(); -void GC_clear_mark_bit(); -void GC_set_mark_bit(); - +GC_API GC_bool GC_is_marked GC_PROTO((ptr_t p)); +void GC_clear_mark_bit GC_PROTO((ptr_t p)); +void GC_set_mark_bit GC_PROTO((ptr_t p)); + /* Stubborn objects: */ -void GC_read_changed(); /* Analogous to GC_read_dirty */ -GC_bool GC_page_was_changed(/* h */); /* Analogous to GC_page_was_dirty */ -void GC_clean_changing_list(); /* Collect obsolete changing list entries */ -void GC_stubborn_init(); - +void GC_read_changed GC_PROTO((void)); /* Analogous to GC_read_dirty */ +GC_bool GC_page_was_changed GC_PROTO((struct hblk * h)); + /* Analogous to GC_page_was_dirty */ +void GC_clean_changing_list GC_PROTO((void)); + /* Collect obsolete changing list entries */ +void GC_stubborn_init GC_PROTO((void)); + /* Debugging print routines: */ -void GC_print_block_list(); -void GC_print_hblkfreelist(); -void GC_print_heap_sects(); -void GC_print_static_roots(); -void GC_dump(); +void GC_print_block_list GC_PROTO((void)); +void GC_print_hblkfreelist GC_PROTO((void)); +void GC_print_heap_sects GC_PROTO((void)); +void GC_print_static_roots GC_PROTO((void)); +void GC_dump GC_PROTO((void)); #ifdef KEEP_BACK_PTRS void GC_store_back_pointer(ptr_t source, ptr_t dest); @@ -1765,10 +1801,10 @@ void GC_dump(); GC_API void GC_noop(); # endif -void GC_noop1(/* word arg */); +void GC_noop1 GC_PROTO((word arg)); /* 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, */ /* is restricted to long arguments, and */ /* (unfortunately) doesn't use varargs for */ @@ -1787,7 +1823,7 @@ 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, \ (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_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) @@ -1803,18 +1839,59 @@ void GC_err_printf(/* format, a, b, c, d, e, f */); (long)e, (long)g) /* 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 */ /* 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)) {\ GC_err_printf2("Assertion failure: %s:%ld\n", \ __FILE__, (unsigned long)__LINE__); \ ABORT("assertion failure"); } -# else +# else # 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 */