typedef GC_word word;
typedef GC_signed_word signed_word;
-# ifndef CONFIG_H
+# ifndef GCCONFIG_H
# include "gcconfig.h"
# endif
# define GC_FAR
#endif
+
/*********************************/
/* */
/* Definitions for conservative */
/* 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. */
-#endif
-
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
# define MERGE_SIZES
# 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 */
+# 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>
# if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
clock_t clock(); /* Not in time.h, where it belongs */
# 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. */
# define LOCK() mutex_lock(&GC_allocate_ml);
# define UNLOCK() mutex_unlock(&GC_allocate_ml);
# endif
-# ifdef LINUX_THREADS
+# if defined(LINUX_THREADS)
+# if defined(I386)|| defined(POWERPC) || defined(ALPHA) || defined(IA64) \
+ || defined(M68K) || defined(SPARC)
# include <pthread.h>
+# define USE_SPIN_LOCK
# if defined(I386)
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
: "0"(1), "m"(*(addr)));
return oldval;
}
-# else
-# if defined(POWERPC)
+# endif
+# if defined(IA64)
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 SPARC
+ inline static int GC_test_and_set(volatile unsigned int *addr) {
+ int oldval;
+
+ __asm__ __volatile__("ldstub %1,%0"
+ : "=r"(oldval), "=m"(*addr)
+ : "m"(*addr));
+ return oldval;
+ }
+# 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 temp = 1; // locked value
: "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
+ }
+ inline static void GC_clear(volatile unsigned int *addr) {
+ __asm__ __volatile__("eieio");
+ *(addr) = 0;
+ }
+# define GC_CLEAR_DEFINED
+# endif
+# 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;
+ }
+ /* Should probably also define GC_clear, since it needs */
+ /* a memory barrier ?? */
+# endif /* ALPHA */
+# 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
- 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;
- }
+ }
+# endif
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 */
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
# define UNLOCK() \
GC_clear(&GC_allocate_lock)
- extern GC_bool GC_collecting;
+ extern VOLATILE GC_bool GC_collecting;
# define ENTER_GC() \
{ \
GC_collecting = 1; \
}
# 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 */
# if defined(HPUX_THREADS)
# include <pthread.h>
*(volatile unsigned long *)(&GC_allocate_lock) = 0; }
# endif
# endif
- extern GC_bool GC_collecting;
+ extern VOLATILE GC_bool GC_collecting;
# define ENTER_GC() \
{ \
GC_collecting = 1; \
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
# endif
-# ifdef QUICK_THREADS
-# define LOCK()
-# define UNLOCK()
-# endif
# ifndef SET_LOCK_HOLDER
# define SET_LOCK_HOLDER()
# define UNSET_LOCK_HOLDER()
/* 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 */);
+typedef struct ms_entry * (*mark_proc)(/* word * addr,
+ struct ms_entry *mark_stack_ptr,
+ struct ms_entry *mark_stack_limit,
+ word env */);
# define LOG_MAX_MARK_PROCS 6
# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
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;
word _mem_freed;
/* Number of explicitly deallocated words of memory */
/* 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];
/* Table of user-defined mark procedures. There is */
/* a small number of these, which can be referenced */
# 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
# 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
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
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. */
/* Black listing: */
void GC_bl_init();
# ifndef ALL_INTERIOR_POINTERS
- void GC_add_to_black_list_normal(/* bits, maybe source */);
+ void GC_add_to_black_list_normal(word /* bits, maybe 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)
+ GC_add_to_black_list_normal((word) bits, source)
# else
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
- GC_add_to_black_list_normal(bits)
+ GC_add_to_black_list_normal((word) bits)
# endif
# else
# ifdef PRINT_BLACK_LIST
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
- GC_add_to_black_list_stack(bits, source)
+ GC_add_to_black_list_stack((word) bits, source)
# else
# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \
- GC_add_to_black_list_stack(bits)
+ GC_add_to_black_list_stack((word) bits)
# endif
# endif
/* collection work, if appropriate. */
/* A unit is an amount appropriate for */
/* HBLKSIZE bytes of allocation. */
-ptr_t GC_generic_malloc(/* bytes, kind */);
+ptr_t GC_generic_malloc(word bytes, int kind);
/* Allocate an object of the given */
/* kind. By default, there are only */
/* a few kinds: composite(pointerfree), */
/* As above, but pointers past the */
/* first page of the resulting object */
/* are ignored. */
-ptr_t GC_generic_malloc_inner(/* bytes, kind */);
+ptr_t GC_generic_malloc_inner(word bytes, int 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 */
/* head. */
void GC_init_headers();
-GC_bool GC_install_header(/*h*/);
+struct hblkhdr * GC_install_header(/*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*/);
/* Set up forwarding counts for block */
/* h of size sz. */
/* Remove the header for block h. */
void GC_remove_counts(/*h, sz*/);
/* Remove forwarding counts for h. */
-hdr * GC_find_header(/*p*/); /* Debugging only. */
+hdr * GC_find_header(ptr_t /*p*/); /* Debugging only. */
void GC_finalize(); /* Perform all indicated finalization actions */
/* on unmarked objects. */
/* P points to somewhere inside an object with */
/* debugging info. Print a human readable */
/* description of the object to stderr. */
-ptr_t GC_debug_object_start(/* ptr_t p */);
- /* P points to the start of an object that may */
- /* have debug info at its head. Return the */
- /* start of the real data. */
extern void (*GC_check_heap)();
/* Check that all objects in the heap with */
/* debugging info are intact. Print */