version 1.1.1.2, 2000/04/14 11:07:59 |
version 1.1.1.3, 2000/12/01 14:48:26 |
|
|
typedef GC_word word; |
typedef GC_word word; |
typedef GC_signed_word signed_word; |
typedef GC_signed_word signed_word; |
|
|
# ifndef CONFIG_H |
# ifndef GCCONFIG_H |
# include "gcconfig.h" |
# include "gcconfig.h" |
# endif |
# endif |
|
|
Line 82 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 82 typedef char * ptr_t; /* A generic pointer to which we |
|
# define GC_FAR |
# define GC_FAR |
#endif |
#endif |
|
|
|
|
/*********************************/ |
/*********************************/ |
/* */ |
/* */ |
/* Definitions for conservative */ |
/* Definitions for conservative */ |
Line 173 typedef char * ptr_t; /* A generic pointer to which we |
|
Line 174 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 |
|
/* 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. */ |
|
#endif |
|
|
|
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */ |
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */ |
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES) |
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES) |
# define MERGE_SIZES |
# define MERGE_SIZES |
Line 281 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 273 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 */ |
|
# ifdef MSWIN32 |
|
# 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, !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 305 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 437 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 437 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
# define LOCK() mutex_lock(&GC_allocate_ml); |
# define LOCK() mutex_lock(&GC_allocate_ml); |
# define UNLOCK() mutex_unlock(&GC_allocate_ml); |
# define UNLOCK() mutex_unlock(&GC_allocate_ml); |
# endif |
# endif |
# ifdef LINUX_THREADS |
# if defined(LINUX_THREADS) |
|
# if defined(I386)|| defined(POWERPC) || defined(ALPHA) || defined(IA64) \ |
|
|| defined(M68K) |
# include <pthread.h> |
# include <pthread.h> |
|
# define USE_SPIN_LOCK |
# if defined(I386) |
# if defined(I386) |
inline static int GC_test_and_set(volatile unsigned int *addr) { |
inline static int GC_test_and_set(volatile unsigned int *addr) { |
int oldval; |
int oldval; |
Line 448 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 451 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
: "0"(1), "m"(*(addr))); |
: "0"(1), "m"(*(addr))); |
return oldval; |
return oldval; |
} |
} |
# else |
# endif |
# if defined(POWERPC) |
# if defined(IA64) |
inline static int GC_test_and_set(volatile unsigned int *addr) { |
inline static int GC_test_and_set(volatile unsigned int *addr) { |
|
int oldval; |
|
__asm__ __volatile__("xchg4 %0=%1,%2" |
|
: "=r"(oldval), "=m"(*addr) |
|
: "r"(1), "1"(*addr)); |
|
return oldval; |
|
} |
|
inline static void GC_clear(volatile unsigned int *addr) { |
|
__asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr)); |
|
} |
|
# define GC_CLEAR_DEFINED |
|
# endif |
|
# ifdef M68K |
|
/* Contributed by Tony Mantler. I'm not sure how well it was */ |
|
/* tested. */ |
|
inline static int GC_test_and_set(volatile unsigned int *addr) { |
|
char oldval; /* this must be no longer than 8 bits */ |
|
|
|
/* The return value is semi-phony. */ |
|
/* 'tas' sets bit 7 while the return */ |
|
/* value pretends bit 0 was set */ |
|
__asm__ __volatile__( |
|
"tas %1@; sne %0; negb %0" |
|
: "=d" (oldval) |
|
: "a" (addr)); |
|
return oldval; |
|
} |
|
# endif |
|
# if defined(POWERPC) |
|
inline static int GC_test_and_set(volatile unsigned int *addr) { |
int oldval; |
int oldval; |
int temp = 1; // locked value |
int temp = 1; // locked value |
|
|
Line 465 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
Line 497 void GC_print_callers (/* struct callinfo info[NFRAMES |
|
: "r"(temp), "1"(addr) |
: "r"(temp), "1"(addr) |
: "memory"); |
: "memory"); |
return (int)oldval; |
return (int)oldval; |
} |
} |
# else |
inline static void GC_clear(volatile unsigned int *addr) { |
# ifdef ALPHA |
__asm__ __volatile__("eieio"); |
inline static int GC_test_and_set(volatile unsigned int * |
*(addr) = 0; |
addr) |
} |
{ |
# define GC_CLEAR_DEFINED |
unsigned long oldvalue; |
# endif |
unsigned long temp; |
# ifdef ALPHA |
|
inline static int GC_test_and_set(volatile unsigned int * addr) |
|
{ |
|
unsigned long oldvalue; |
|
unsigned long temp; |
|
|
__asm__ __volatile__( |
__asm__ __volatile__( |
"1: ldl_l %0,%1\n" |
"1: ldl_l %0,%1\n" |
" and %0,%3,%2\n" |
" and %0,%3,%2\n" |
" bne %2,2f\n" |
" bne %2,2f\n" |
" xor %0,%3,%0\n" |
" xor %0,%3,%0\n" |
" stl_c %0,%1\n" |
" stl_c %0,%1\n" |
" beq %0,3f\n" |
" beq %0,3f\n" |
" mb\n" |
" mb\n" |
"2:\n" |
"2:\n" |
".section .text2,\"ax\"\n" |
".section .text2,\"ax\"\n" |
"3: br 1b\n" |
"3: br 1b\n" |
".previous" |
".previous" |
:"=&r" (temp), "=m" (*addr), "=&r" |
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue) |
(oldvalue) |
:"Ir" (1), "m" (*addr)); |
:"Ir" (1), "m" (*addr)); |
|
|
|
return oldvalue; |
return oldvalue; |
} |
} |
# else |
/* Should probably also define GC_clear, since it needs */ |
-- > Need implementation of GC_test_and_set() |
/* a memory barrier ?? */ |
# endif |
# endif /* ALPHA */ |
# endif |
# ifdef ARM32 |
|
inline static int GC_test_and_set(volatile unsigned int *addr) { |
|
int oldval; |
|
/* SWP on ARM is very similar to XCHG on x86. Doesn't lock the |
|
* bus because there are no SMP ARM machines. If/when there are, |
|
* this code will likely need to be updated. */ |
|
/* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */ |
|
__asm__ __volatile__("swp %0, %1, [%2]" |
|
: "=r"(oldval) |
|
: "r"(1), "r"(addr)); |
|
return oldval; |
|
} |
# endif |
# endif |
inline static void GC_clear(volatile unsigned int *addr) { |
# ifndef GC_CLEAR_DEFINED |
|
inline static void GC_clear(volatile unsigned int *addr) { |
|
/* Try to discourage gcc from moving anything past this. */ |
|
__asm__ __volatile__(" "); |
*(addr) = 0; |
*(addr) = 0; |
} |
} |
|
# endif |
|
|
extern volatile unsigned int GC_allocate_lock; |
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 pthread_t GC_lock_holder; |
extern void GC_lock(void); |
extern void GC_lock(void); |
/* Allocation lock holder. Only set if acquired by client through */ |
/* Allocation lock holder. Only set if acquired by client through */ |
|
|
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } |
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } |
# define UNLOCK() \ |
# define UNLOCK() \ |
GC_clear(&GC_allocate_lock) |
GC_clear(&GC_allocate_lock) |
extern GC_bool GC_collecting; |
extern VOLATILE GC_bool GC_collecting; |
# define ENTER_GC() \ |
# define ENTER_GC() \ |
{ \ |
{ \ |
GC_collecting = 1; \ |
GC_collecting = 1; \ |
} |
} |
# define EXIT_GC() GC_collecting = 0; |
# define EXIT_GC() GC_collecting = 0; |
|
# else /* LINUX_THREADS on hardware for which we don't know how */ |
|
/* to do test and set. */ |
|
# 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 |
# endif /* LINUX_THREADS */ |
# endif /* LINUX_THREADS */ |
# if defined(HPUX_THREADS) |
# if defined(HPUX_THREADS) |
# include <pthread.h> |
# include <pthread.h> |
|
|
*(volatile unsigned long *)(&GC_allocate_lock) = 0; } |
*(volatile unsigned long *)(&GC_allocate_lock) = 0; } |
# endif |
# endif |
# endif |
# endif |
extern GC_bool GC_collecting; |
extern VOLATILE GC_bool GC_collecting; |
# define ENTER_GC() \ |
# define ENTER_GC() \ |
{ \ |
{ \ |
GC_collecting = 1; \ |
GC_collecting = 1; \ |
|
|
/* The type of mark procedures. This really belongs in gc_mark.h. */ |
/* 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 */ |
/* But we put it here, so that we can avoid scanning the mark proc */ |
/* table. */ |
/* table. */ |
typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr, |
typedef struct ms_entry * (*mark_proc)(/* word * addr, |
mark_stack_limit, env */); |
struct ms_entry *mark_stack_ptr, |
|
struct ms_entry *mark_stack_limit, |
|
word 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) |
|
|
|
|
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; |
Line 1059 struct _GC_arrays { |
|
Line 1116 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. */ |
|
ptr_t _scratch_end_ptr; |
|
ptr_t _scratch_last_end_ptr; |
|
/* Used by headers.c, and can easily appear to point to */ |
|
/* heap. */ |
mark_proc _mark_procs[MAX_MARK_PROCS]; |
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 */ |
Line 1223 GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
Line 1284 GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
# 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 |
Line 1260 GC_API GC_FAR struct _GC_arrays GC_arrays; |
|
Line 1324 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 1339 extern GC_bool GC_objects_are_marked; /* There are mar |
|
Line 1405 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 1392 extern ptr_t GC_greatest_plausible_heap_addr; |
|
Line 1458 extern ptr_t GC_greatest_plausible_heap_addr; |
|
ptr_t GC_approx_sp(); |
ptr_t GC_approx_sp(); |
|
|
GC_bool GC_should_collect(); |
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*/); |
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. */ |
Line 1672 ptr_t GC_allocobj(/* sz_inn_words, kind */); |
|
Line 1735 ptr_t GC_allocobj(/* sz_inn_words, kind */); |
|
/* head. */ |
/* head. */ |
|
|
void GC_init_headers(); |
void GC_init_headers(); |
GC_bool GC_install_header(/*h*/); |
struct hblkhdr * GC_install_header(/*h*/); |
/* Install a header for block h. */ |
/* Install a header for block h. */ |
/* Return FALSE on failure. */ |
/* Return 0 on failure, or the header */ |
|
/* otherwise. */ |
GC_bool GC_install_counts(/*h, sz*/); |
GC_bool GC_install_counts(/*h, sz*/); |
/* Set up forwarding counts for block */ |
/* Set up forwarding counts for block */ |
/* h of size sz. */ |
/* h of size sz. */ |