diff options
Diffstat (limited to 'boehm-gc/include/private')
-rw-r--r-- | boehm-gc/include/private/dbg_mlc.h | 10 | ||||
-rw-r--r-- | boehm-gc/include/private/gc_hdrs.h | 2 | ||||
-rw-r--r-- | boehm-gc/include/private/gc_locks.h | 245 | ||||
-rw-r--r-- | boehm-gc/include/private/gc_pmark.h | 39 | ||||
-rw-r--r-- | boehm-gc/include/private/gc_priv.h | 166 | ||||
-rw-r--r-- | boehm-gc/include/private/gcconfig.h | 509 | ||||
-rw-r--r-- | boehm-gc/include/private/solaris_threads.h | 3 | ||||
-rw-r--r-- | boehm-gc/include/private/specific.h | 2 |
8 files changed, 664 insertions, 312 deletions
diff --git a/boehm-gc/include/private/dbg_mlc.h b/boehm-gc/include/private/dbg_mlc.h index 5378835811c..e2003e6c44f 100644 --- a/boehm-gc/include/private/dbg_mlc.h +++ b/boehm-gc/include/private/dbg_mlc.h @@ -115,16 +115,24 @@ typedef struct { #ifdef SHORT_DBG_HDRS # define DEBUG_BYTES (sizeof (oh)) +# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES #else /* Add space for END_FLAG, but use any extra space that was already */ /* added to catch off-the-end pointers. */ -# define DEBUG_BYTES (sizeof (oh) + sizeof (word) - EXTRA_BYTES) + /* For uncollectable objects, the extra byte is not added. */ +# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word)) +# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES) #endif #define USR_PTR_FROM_BASE(p) ((ptr_t)(p) + sizeof(oh)) /* Round bytes to words without adding extra byte at end. */ #define SIMPLE_ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1) +/* ADD_CALL_CHAIN stores a (partial) call chain into an object */ +/* header. It may be called with or without the allocation */ +/* lock. */ +/* PRINT_CALL_CHAIN prints the call chain stored in an object */ +/* to stderr. It requires that we do not hold the lock. */ #ifdef SAVE_CALL_CHAIN # define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci) # define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) diff --git a/boehm-gc/include/private/gc_hdrs.h b/boehm-gc/include/private/gc_hdrs.h index dd615455f3b..96749ab1bf0 100644 --- a/boehm-gc/include/private/gc_hdrs.h +++ b/boehm-gc/include/private/gc_hdrs.h @@ -70,7 +70,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */ #define ADVANCE(p, hhdr, source) \ { \ hdr * new_hdr = GC_invalid_header; \ - p = GC_FIND_START(p, hhdr, &new_hdr, (word)source); \ + p = GC_find_start(p, hhdr, &new_hdr); \ hhdr = new_hdr; \ } diff --git a/boehm-gc/include/private/gc_locks.h b/boehm-gc/include/private/gc_locks.h index 9b91ada917a..775176b3151 100644 --- a/boehm-gc/include/private/gc_locks.h +++ b/boehm-gc/include/private/gc_locks.h @@ -141,23 +141,24 @@ # if defined(POWERPC) inline static int GC_test_and_set(volatile unsigned int *addr) { int oldval; - int temp = 1; // locked value + 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 + "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 */ + "\tsync\n" /* import barrier */ + "2:\t\n" /* oldval is zero if we set */ : "=&r"(oldval), "=p"(addr) : "r"(temp), "1"(addr) - : "memory"); - return (int)oldval; + : "cr0","memory"); + return oldval; } # define GC_TEST_AND_SET_DEFINED inline static void GC_clear(volatile unsigned int *addr) { - __asm__ __volatile__("eieio" ::: "memory"); + __asm__ __volatile__("eieio" : : : "memory"); *(addr) = 0; } # define GC_CLEAR_DEFINED @@ -174,12 +175,18 @@ " bne %2,2f\n" " xor %0,%3,%0\n" " stl_c %0,%1\n" +# ifdef __ELF__ " beq %0,3f\n" +# else + " beq %0,1b\n" +# endif " mb\n" "2:\n" +# ifdef __ELF__ ".section .text2,\"ax\"\n" "3: br 1b\n" ".previous" +# endif :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue) :"Ir" (1), "m" (*addr) :"memory"); @@ -187,8 +194,11 @@ return oldvalue; } # define GC_TEST_AND_SET_DEFINED - /* Should probably also define GC_clear, since it needs */ - /* a memory barrier ?? */ + inline static void GC_clear(volatile unsigned int *addr) { + __asm__ __volatile__("mb" : : : "memory"); + *(addr) = 0; + } +# define GC_CLEAR_DEFINED # endif /* ALPHA */ # ifdef ARM32 inline static int GC_test_and_set(volatile unsigned int *addr) { @@ -206,22 +216,30 @@ # define GC_TEST_AND_SET_DEFINED # endif /* ARM32 */ # ifdef S390 - inline static int GC_test_and_set(volatile unsigned int *addr) { - int ret; - __asm__ __volatile__ ( - " l %0,0(%2)\n" - "0: cs %0,%1,0(%2)\n" - " jl 0b" - : "=&d" (ret) - : "d" (1), "a" (addr) - : "cc", "memory"); - return ret; - } + inline static int GC_test_and_set(volatile unsigned int *addr) { + int ret; + __asm__ __volatile__ ( + " l %0,0(%2)\n" + "0: cs %0,%1,0(%2)\n" + " jl 0b" + : "=&d" (ret) + : "d" (1), "a" (addr) + : "cc", "memory"); + return ret; + } # endif # endif /* __GNUC__ */ # if (defined(ALPHA) && !defined(__GNUC__)) -# define GC_test_and_set(addr) __cxx_test_and_set_atomic(addr, 1) +# ifndef OSF1 + --> We currently assume that if gcc is not used, we are + --> running under Tru64. +# endif +# include <machine/builtins.h> +# include <c_asm.h> +# define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1) # define GC_TEST_AND_SET_DEFINED +# define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; } +# define GC_CLEAR_DEFINED # endif # if defined(MSWIN32) # define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1) @@ -234,14 +252,51 @@ # define GC_TEST_AND_SET_DEFINED # elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ || !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700 -# define GC_test_and_set(addr) test_and_set(addr, 1) +# ifdef __GNUC__ +# define GC_test_and_set(addr) _test_and_set((void *)addr,1) +# else +# define GC_test_and_set(addr) test_and_set((void *)addr,1) +# endif # else -# define GC_test_and_set(addr) __test_and_set(addr,1) +# define GC_test_and_set(addr) __test_and_set32((void *)addr,1) # define GC_clear(addr) __lock_release(addr); # define GC_CLEAR_DEFINED # endif # define GC_TEST_AND_SET_DEFINED # endif /* MIPS */ +# if defined(_AIX) +# include <sys/atomic_op.h> +# if (defined(_POWER) || defined(_POWERPC)) +# if defined(__GNUC__) + inline static void GC_memsync() { + __asm__ __volatile__ ("sync" : : : "memory"); + } +# else +# ifndef inline +# define inline __inline +# endif +# pragma mc_func GC_memsync { \ + "7c0004ac" /* sync (same opcode used for dcs)*/ \ + } +# endif +# else +# error dont know how to memsync +# endif + inline static int GC_test_and_set(volatile unsigned int * addr) { + int oldvalue = 0; + if (compare_and_swap((void *)addr, &oldvalue, 1)) { + GC_memsync(); + return 0; + } else return 1; + } +# define GC_TEST_AND_SET_DEFINED + inline static void GC_clear(volatile unsigned int *addr) { + GC_memsync(); + *(addr) = 0; + } +# define GC_CLEAR_DEFINED + +# endif # if 0 /* defined(HP_PA) */ /* The official recommendation seems to be to not use ldcw from */ /* user mode. Since multithreaded incremental collection doesn't */ @@ -275,7 +330,7 @@ # endif # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ - && !defined(GC_IRIX_THREADS) + && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) # define NO_THREAD (pthread_t)(-1) # include <pthread.h> # if defined(PARALLEL_MARK) @@ -306,12 +361,12 @@ { char result; __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1" - : "=m"(*(addr)), "=r"(result) - : "r" (new_val), "0"(*(addr)), "a"(old) : "memory"); + : "+m"(*(addr)), "=r"(result) + : "r" (new_val), "a"(old) : "memory"); return (GC_bool) result; } # endif /* !GENERIC_COMPARE_AND_SWAP */ - inline static void GC_memory_write_barrier() + inline static void GC_memory_barrier() { /* We believe the processor ensures at least processor */ /* consistent ordering. Thus a compiler barrier */ @@ -319,6 +374,37 @@ __asm__ __volatile__("" : : : "memory"); } # endif /* I386 */ + +# if defined(POWERPC) +# if !defined(GENERIC_COMPARE_AND_SWAP) + /* Returns TRUE if the comparison succeeded. */ + inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, + GC_word old, GC_word new_val) + { + int result, dummy; + __asm__ __volatile__( + "1:\tlwarx %0,0,%5\n" + "\tcmpw %0,%4\n" + "\tbne 2f\n" + "\tstwcx. %3,0,%2\n" + "\tbne- 1b\n" + "\tsync\n" + "\tli %1, 1\n" + "\tb 3f\n" + "2:\tli %1, 0\n" + "3:\t\n" + : "=&r" (dummy), "=r" (result), "=p" (addr) + : "r" (new_val), "r" (old), "2"(addr) + : "cr0","memory"); + return (GC_bool) result; + } +# endif /* !GENERIC_COMPARE_AND_SWAP */ + inline static void GC_memory_barrier() + { + __asm__ __volatile__("sync" : : : "memory"); + } +# endif /* POWERPC */ + # if defined(IA64) # if !defined(GENERIC_COMPARE_AND_SWAP) inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, @@ -330,31 +416,71 @@ # endif /* !GENERIC_COMPARE_AND_SWAP */ # if 0 /* Shouldn't be needed; we use volatile stores instead. */ - inline static void GC_memory_write_barrier() + inline static void GC_memory_barrier() { __sync_synchronize (); } # endif /* 0 */ # endif /* IA64 */ +# if defined(ALPHA) +# if !defined(GENERIC_COMPARE_AND_SWAP) +# if defined(__GNUC__) + inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, + GC_word old, GC_word new_val) + { + unsigned long was_equal; + unsigned long temp; + + __asm__ __volatile__( + "1: ldq_l %0,%1\n" + " cmpeq %0,%4,%2\n" + " mov %3,%0\n" + " beq %2,2f\n" + " stq_c %0,%1\n" + " beq %0,1b\n" + "2:\n" + " mb\n" + :"=&r" (temp), "=m" (*addr), "=&r" (was_equal) + : "r" (new_val), "Ir" (old) + :"memory"); + return was_equal; + } +# else /* !__GNUC__ */ + inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, + GC_word old, GC_word new_val) + { + return __CMP_STORE_QUAD(addr, old, new_val, addr); + } +# endif /* !__GNUC__ */ +# endif /* !GENERIC_COMPARE_AND_SWAP */ +# ifdef __GNUC__ + inline static void GC_memory_barrier() + { + __asm__ __volatile__("mb" : : : "memory"); + } +# else +# define GC_memory_barrier() asm("mb") +# endif /* !__GNUC__ */ +# endif /* ALPHA */ # if defined(S390) # if !defined(GENERIC_COMPARE_AND_SWAP) - inline static GC_bool GC_compare_and_exchange(volatile C_word *addr, - GC_word old, GC_word new_val) - { - int retval; - __asm__ __volatile__ ( -# ifndef __s390x__ - " cs %1,%2,0(%3)\n" -# else - " csg %1,%2,0(%3)\n" -# endif - " ipm %0\n" - " srl %0,28\n" - : "=&d" (retval), "+d" (old) - : "d" (new_val), "a" (addr) - : "cc", "memory"); - return retval == 0; - } + inline static GC_bool GC_compare_and_exchange(volatile C_word *addr, + GC_word old, GC_word new_val) + { + int retval; + __asm__ __volatile__ ( +# ifndef __s390x__ + " cs %1,%2,0(%3)\n" +# else + " csg %1,%2,0(%3)\n" +# endif + " ipm %0\n" + " srl %0,28\n" + : "=&d" (retval), "+d" (old) + : "d" (new_val), "a" (addr) + : "cc", "memory"); + return retval == 0; + } # endif # endif # if !defined(GENERIC_COMPARE_AND_SWAP) @@ -427,8 +553,12 @@ { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \ pthread_mutex_unlock(&GC_allocate_ml); } # else /* !GC_ASSERTIONS */ +# if defined(NO_PTHREAD_TRYLOCK) +# define LOCK() GC_lock(); +# else /* !defined(NO_PTHREAD_TRYLOCK) */ # define LOCK() \ { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); } +# endif # define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) # endif /* !GC_ASSERTIONS */ # endif /* USE_PTHREAD_LOCKS */ @@ -450,7 +580,7 @@ /* on Irix anymore. */ # include <mutex.h> - extern unsigned long 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. */ @@ -471,11 +601,18 @@ } # define EXIT_GC() GC_collecting = 0; # endif /* GC_IRIX_THREADS */ -# ifdef GC_WIN32_THREADS -# include <windows.h> - GC_API CRITICAL_SECTION GC_allocate_ml; -# define LOCK() EnterCriticalSection(&GC_allocate_ml); -# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml); +# if defined(GC_WIN32_THREADS) +# if defined(GC_PTHREADS) +# 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) +# else +# include <windows.h> + GC_API CRITICAL_SECTION GC_allocate_ml; +# define LOCK() EnterCriticalSection(&GC_allocate_ml); +# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml); +# endif # endif # ifndef SET_LOCK_HOLDER # define SET_LOCK_HOLDER() diff --git a/boehm-gc/include/private/gc_pmark.h b/boehm-gc/include/private/gc_pmark.h index 872065702f0..c109738203a 100644 --- a/boehm-gc/include/private/gc_pmark.h +++ b/boehm-gc/include/private/gc_pmark.h @@ -137,7 +137,7 @@ extern mse * GC_mark_stack; #ifdef __STDC__ # ifdef PRINT_BLACK_LIST ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p, - ptr_t source); + word source); # else ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p); # endif @@ -145,7 +145,7 @@ extern mse * GC_mark_stack; ptr_t GC_find_start(); #endif -mse *GC_signal_mark_stack_overflow(mse *msp); +mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp)); # ifdef GATHERSTATS # define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz) @@ -174,14 +174,6 @@ mse *GC_signal_mark_stack_overflow(mse *msp); } \ } -#ifdef PRINT_BLACK_LIST -# define GC_FIND_START(current, hhdr, new_hdr_p, source) \ - GC_find_start(current, hhdr, new_hdr_p, source) -#else -# define GC_FIND_START(current, hhdr, new_hdr_p, source) \ - GC_find_start(current, hhdr, new_hdr_p) -#endif - /* Push the contents of current onto the mark stack if it is a valid */ /* ptr to a currently unmarked object. Mark it. */ /* If we assumed a standard-conforming compiler, we could probably */ @@ -195,8 +187,7 @@ mse *GC_signal_mark_stack_overflow(mse *msp); GET_HDR(my_current, my_hhdr); \ if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \ hdr * new_hdr = GC_invalid_header; \ - my_current = GC_FIND_START(my_current, my_hhdr, \ - &new_hdr, (word)source); \ + my_current = GC_find_start(my_current, my_hhdr, &new_hdr); \ my_hhdr = new_hdr; \ } \ PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \ @@ -290,21 +281,39 @@ exit_label: ; \ /* * Push a single value onto mark stack. Mark from the object pointed to by p. + * Invoke FIXUP_POINTER(p) before any further processing. * P is considered valid even if it is an interior pointer. * Previously marked objects are not pushed. Hence we make progress even * if the mark stack overflows. */ -# define GC_PUSH_ONE_STACK(p, source) \ - if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \ + +# if NEED_FIXUP_POINTER + /* Try both the raw version and the fixed up one. */ +# define GC_PUSH_ONE_STACK(p, source) \ + if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \ PUSH_ONE_CHECKED_STACK(p, source); \ - } + } \ + FIXUP_POINTER(p); \ + if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \ + && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \ + PUSH_ONE_CHECKED_STACK(p, source); \ + } +# else /* !NEED_FIXUP_POINTER */ +# define GC_PUSH_ONE_STACK(p, source) \ + if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \ + && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \ + PUSH_ONE_CHECKED_STACK(p, source); \ + } +# endif + /* * As above, but interior pointer recognition as for * normal for heap pointers. */ # define GC_PUSH_ONE_HEAP(p,source) \ + FIXUP_POINTER(p); \ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \ GC_mark_stack_top = GC_mark_and_push( \ diff --git a/boehm-gc/include/private/gc_priv.h b/boehm-gc/include/private/gc_priv.h index b09c4840945..ffa398b308b 100644 --- a/boehm-gc/include/private/gc_priv.h +++ b/boehm-gc/include/private/gc_priv.h @@ -30,14 +30,20 @@ # define BSD_TIME #endif +#ifdef DGUX +# include <sys/types.h> +# include <sys/time.h> +# include <sys/resource.h> +#endif /* DGUX */ + #ifdef BSD_TIME # include <sys/types.h> # include <sys/time.h> # include <sys/resource.h> #endif /* BSD_TIME */ -# ifndef GC_H -# include "gc.h" +# ifndef _GC_H +# include "../gc.h" # endif # ifndef GC_MARK_H @@ -206,11 +212,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ #endif #if defined(GC_GCJ_SUPPORT) && ALIGNMENT < 8 && !defined(ALIGN_DOUBLE) - /* GCJ's Hashtable synchronization code requires 64-bit alignment. */ + /* GCJ's Hashtable synchronization code requires 64-bit alignment. */ # define ALIGN_DOUBLE #endif - /* ALIGN_DOUBLE requires MERGE_SIZES at present. */ # if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES) # define MERGE_SIZES @@ -347,7 +352,8 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); # include <string.h> # define BCOPY_EXISTS # endif -# if defined(MACOSX) +# if defined(DARWIN) +# include <string.h> # define BCOPY_EXISTS # endif @@ -360,68 +366,6 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); # define BZERO(x,n) bzero((char *)(x),(int)(n)) # endif -/* HBLKSIZE aligned allocation. 0 is taken to mean failure */ -/* space is assumed to be cleared. */ -/* In the case os USE_MMAP, the argument must also be a */ -/* physical page size. */ -/* 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) \ - + GC_page_size-1) -# else -# ifdef OS2 - void * os2_alloc(size_t bytes); -# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \ - + GC_page_size) \ - + GC_page_size-1) -# else -# if defined(NEXT) || defined(MACOSX) || defined(DOS4GW) || \ - (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \ - (defined(SUNOS5) && !defined(USE_MMAP)) -# define GET_MEM(bytes) HBLKPTR((size_t) \ - calloc(1, (size_t)bytes + GC_page_size) \ - + GC_page_size-1) -# else -# ifdef MSWIN32 - extern ptr_t GC_win32_get_mem(); -# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes) -# else -# ifdef MACOS -# if defined(USE_TEMPORARY_MEMORY) - extern Ptr GC_MacTemporaryNewPtr(size_t size, - Boolean clearMemory); -# define GET_MEM(bytes) HBLKPTR( \ - GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \ - + GC_page_size-1) -# else -# define GET_MEM(bytes) HBLKPTR( \ - NewPtrClear(bytes + GC_page_size) + GC_page_size-1) -# endif -# else -# 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 - /* 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 */ @@ -486,7 +430,7 @@ struct hblk; /* See below. */ # ifdef SMALL_CONFIG # define ABORT(msg) abort(); # else - GC_API void GC_abort(); + GC_API void GC_abort GC_PROTO((GC_CONST char * msg)); # define ABORT(msg) GC_abort(msg); # endif # endif @@ -646,9 +590,10 @@ extern GC_warn_proc GC_current_warn_proc; */ # ifdef LARGE_CONFIG -# define LOG_PHT_ENTRIES 19 /* Collisions likely at 512K blocks, */ - /* which is >= 2GB. Each table takes */ - /* 64KB. */ +# define LOG_PHT_ENTRIES 20 /* Collisions likely at 1M blocks, */ + /* which is >= 4GB. Each table takes */ + /* 128KB, some of which may never be */ + /* touched. */ # else # ifdef SMALL_CONFIG # define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */ @@ -656,7 +601,7 @@ extern GC_warn_proc GC_current_warn_proc; /* 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. */ + /* to more than 64K hblks >= 256MB. */ /* Each hash table occupies 8K bytes. */ # endif # endif @@ -897,6 +842,10 @@ struct _GC_arrays { word _mem_freed; /* Number of explicitly deallocated words of memory */ /* since last collection. */ + word _finalizer_mem_freed; + /* Words of memory explicitly deallocated while */ + /* finalizers were running. Used to approximate mem. */ + /* explicitly deallocated by finalizers. */ ptr_t _scratch_end_ptr; ptr_t _scratch_last_end_ptr; /* Used by headers.c, and can easily appear to point to */ @@ -957,7 +906,7 @@ struct _GC_arrays { /* 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. */ + /* space consumption and for cache utilization.) */ # define OFFSET_TOO_BIG 0xfe # define OBJ_INVALID 0xff # define MAP_ENTRY(map, bytes) (map)[bytes] @@ -1067,6 +1016,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays; # 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_finalizer_mem_freed GC_arrays._finalizer_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 @@ -1201,17 +1151,19 @@ extern struct hblk * GC_hblkfreelist[]; /* header structure associated with */ /* block. */ -extern GC_bool GC_is_initialized; /* GC_init() has been run. */ - extern GC_bool GC_objects_are_marked; /* There are marked objects in */ /* the heap. */ #ifndef SMALL_CONFIG extern GC_bool GC_incremental; /* Using incremental/generational collection. */ +# define TRUE_INCREMENTAL \ + (GC_incremental && GC_time_limit != GC_TIME_UNLIMITED) + /* True incremental, not just generational, mode */ #else # define GC_incremental FALSE /* Hopefully allow optimizer to remove some code. */ +# define TRUE_INCREMENTAL FALSE #endif extern GC_bool GC_dirty_maintained; @@ -1229,6 +1181,10 @@ extern long GC_large_alloc_warn_interval; extern long GC_large_alloc_warn_suppressed; /* Number of warnings suppressed so far. */ +#ifdef THREADS + extern GC_bool GC_world_stopped; +#endif + /* Operations */ # ifndef abs # define abs(x) ((x) < 0? (-(x)) : (x)) @@ -1403,6 +1359,11 @@ extern void (*GC_start_call_back) GC_PROTO((void)); # else void GC_push_regs GC_PROTO((void)); # endif +# if defined(SPARC) || defined(IA64) + /* Cause all stacked registers to be saved in memory. Return a */ + /* pointer to the top of the corresponding memory stack. */ + word GC_save_regs_in_stack 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 */ @@ -1452,6 +1413,7 @@ void GC_set_fl_marks GC_PROTO((ptr_t p)); /* Set all mark bits associated with */ /* a free list. */ void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp)); +void GC_remove_roots_inner GC_PROTO((char * b, char * e)); GC_bool GC_is_static_root GC_PROTO((ptr_t p)); /* Is the address p in one of the registered static */ /* root sections? */ @@ -1462,11 +1424,10 @@ GC_bool GC_is_tmp_root GC_PROTO((ptr_t p)); # endif void GC_register_dynamic_libraries GC_PROTO((void)); /* Add dynamic library data sections to the root set. */ - GC_bool GC_register_main_static_data GC_PROTO((void)); - /* We need to register the main data segment. Returns */ - /* TRUE unless this is done implicitly as part of */ - /* dynamic library registration. */ + /* We need to register the main data segment. Returns */ + /* TRUE unless this is done implicitly as part of */ + /* dynamic library registration. */ /* Machine dependent startup routines */ ptr_t GC_get_stack_base GC_PROTO((void)); /* Cold end of stack */ @@ -1624,6 +1585,8 @@ GC_bool GC_collect_or_expand GC_PROTO(( \ /* until the blocks are available or */ /* until it fails by returning FALSE. */ +extern GC_bool GC_is_initialized; /* GC_init() has been run. */ + #if defined(MSWIN32) || defined(MSWINCE) void GC_deinit GC_PROTO((void)); /* Free any resources allocated by */ @@ -1665,6 +1628,8 @@ ptr_t GC_allocobj GC_PROTO((word sz, int kind)); /* Make the indicated */ /* free list nonempty, and return its */ /* head. */ + +void GC_free_inner(GC_PTR p); void GC_init_headers GC_PROTO((void)); struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h)); @@ -1694,6 +1659,12 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void)); /* Call *GC_finalizer_notifier if there are */ /* finalizers to be run, and we haven't called */ /* this procedure yet this GC cycle. */ + +GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data)); +GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data)); + /* Auxiliary fns to make finalization work */ + /* correctly with displaced pointers introduced */ + /* by the debugging allocators. */ void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes)); /* Add a HBLKSIZE aligned chunk to the heap. */ @@ -1704,16 +1675,36 @@ void GC_print_obj GC_PROTO((ptr_t p)); /* 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. */ + /* debugging info are intact. */ + /* Add any that are not to GC_smashed list. */ +extern void (*GC_print_all_smashed) GC_PROTO((void)); + /* Print GC_smashed if it's not empty. */ + /* Clear GC_smashed list. */ +extern void GC_print_all_errors GC_PROTO((void)); + /* Print smashed and leaked objects, if any. */ + /* Clear the lists of such objects. */ 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. */ +#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG) + void GC_print_address_map GC_PROTO((void)); + /* Print an address map of the process. */ +#endif +extern GC_bool GC_have_errors; /* We saw a smashed or leaked object. */ + /* Call error printing routine */ + /* occasionally. */ extern GC_bool GC_print_stats; /* Produce at least some logging output */ /* Set from environment variable. */ +#ifndef NO_DEBUGGING + extern GC_bool GC_dump_regularly; /* Generate regular debugging dumps. */ +# define COND_DUMP if (GC_dump_regularly) GC_dump(); +#else +# define COND_DUMP +#endif + /* Macros used for collector internal allocation. */ /* These assume the collector lock is held. */ #ifdef DBG_HDRS_ALL @@ -1785,6 +1776,7 @@ 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_print_finalization_stats GC_PROTO((void)); void GC_dump GC_PROTO((void)); #ifdef KEEP_BACK_PTRS @@ -1866,6 +1858,16 @@ void GC_err_puts GC_PROTO((GC_CONST char *s)); # define GC_ASSERT(expr) # endif +/* Check a compile time assertion at compile time. The error */ +/* message for failure is a bit baroque, but ... */ +#if defined(mips) && !defined(__GNUC__) +/* DOB: MIPSPro C gets an internal error taking the sizeof an array type. + This code works correctly (ugliness is to avoid "unused var" warnings) */ +# define GC_STATIC_ASSERT(expr) do { if (0) { char j[(expr)? 1 : -1]; j[0]='\0'; j[0]=j[0]; } } while(0) +#else +# define GC_STATIC_ASSERT(expr) sizeof(char[(expr)? 1 : -1]) +#endif + # if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) /* We need additional synchronization facilities from the thread */ /* support. We believe these are less performance critical */ @@ -1911,7 +1913,7 @@ void GC_err_puts GC_PROTO((GC_CONST char *s)); /* in Linux glibc, but it's not exported.) Thus we continue to use */ /* the same hard-coded signals we've always used. */ # if !defined(SIG_SUSPEND) -# if defined(GC_LINUX_THREADS) +# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS) # if defined(SPARC) && !defined(SIGPWR) /* SPARC/Linux doesn't properly define SIGPWR in <signal.h>. * It is aliased to SIGLOST in asm/signal.h, though. */ diff --git a/boehm-gc/include/private/gcconfig.h b/boehm-gc/include/private/gcconfig.h index 809887f8219..29dab213815 100644 --- a/boehm-gc/include/private/gcconfig.h +++ b/boehm-gc/include/private/gcconfig.h @@ -13,11 +13,25 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ + +/* + * This header is private to the gc. It is almost always included from + * gc_priv.h. However it is possible to include it by itself if just the + * configuration macros are needed. In that + * case, a few declarations relying on types declared in gc_priv.h will be + * omitted. + */ #ifndef GCCONFIG_H # define GCCONFIG_H +# ifndef GC_PRIVATE_H + /* Fake ptr_t declaration, just to avoid compilation errors. */ + /* This avoids many instances if "ifndef GC_PRIVATE_H" below. */ + typedef struct GC_undefined_struct * ptr_t; +# endif + /* Machine dependent parameters. Some tuning parameters can be found */ /* near the top of gc_private.h. */ @@ -25,7 +39,9 @@ /* First a unified test for Linux: */ # if defined(linux) || defined(__linux__) +# ifndef LINUX # define LINUX +# endif # endif /* And one for NetBSD: */ @@ -44,9 +60,9 @@ # endif /* Determine the machine type: */ -# if defined(__arm__) || defined(__thumb__) +# if defined(__XSCALE__) # define ARM32 -# if !defined(LINUX) && !defined(NETBSD) +# if !defined(LINUX) # define NOSYS # define mach_type_known # endif @@ -69,7 +85,7 @@ # define SPARC # define mach_type_known # endif -# if defined(NETBSD) && defined(m68k) +# if defined(NETBSD) && (defined(m68k) || defined(__m68k__)) # define M68K # define mach_type_known # endif @@ -77,7 +93,7 @@ # define POWERPC # define mach_type_known # endif -# if defined(NETBSD) && defined(__arm__) +# if defined(NETBSD) && (defined(__arm32__) || defined(__arm__)) # define ARM32 # define mach_type_known # endif @@ -90,6 +106,10 @@ # endif # define mach_type_known # endif +# if defined(__NetBSD__) && defined(__vax__) +# define VAX +# define mach_type_known +# endif # if defined(mips) || defined(__mips) || defined(_mips) # define MIPS # if defined(nec_ews) || defined(_nec_ews) @@ -109,6 +129,13 @@ # endif /* !LINUX */ # define mach_type_known # endif +# if defined(DGUX) && (defined(i386) || defined(__i386__)) +# define I386 +# ifndef _USING_DGUX +# define _USING_DGUX +# endif +# define mach_type_known +# endif # if defined(sequent) && (defined(i386) || defined(__i386__)) # define I386 # define SEQUENT @@ -198,7 +225,11 @@ # define IA64 # define mach_type_known # endif -# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__)) +# if defined(LINUX) && defined(__arm__) +# define ARM32 +# define mach_type_known +# endif +# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__)) # define POWERPC # define mach_type_known # endif @@ -237,19 +268,19 @@ # define MACOS # define mach_type_known # endif -# if defined(__MWERKS__) && defined(__powerc) +# if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__) # define POWERPC # define MACOS # define mach_type_known # endif # if defined(macosx) || \ defined(__APPLE__) && defined(__MACH__) && defined(__ppc__) -# define MACOSX +# define DARWIN # define POWERPC # define mach_type_known # endif # if defined(__APPLE__) && defined(__MACH__) && defined(__i386__) -# define MACOSX +# define DARWIN # define I386 --> Not really supported, but at least we recognize it. # endif @@ -291,7 +322,7 @@ # define CX_UX # define mach_type_known # endif -# if defined(DGUX) +# if defined(DGUX) && defined(m88k) # define M88K /* DGUX defined */ # define mach_type_known @@ -419,17 +450,18 @@ /* (CX_UX and DGUX) */ /* S370 ==> 370-like machine */ /* running Amdahl UTS4 */ - /* S390 ==> 390-like machine */ - /* running LINUX */ + /* S390 ==> 390-like machine */ + /* running LINUX */ /* ARM32 ==> Intel StrongARM */ /* IA64 ==> Intel IPF */ /* (e.g. Itanium) */ /* (LINUX and HPUX) */ - /* IA64_32 ==> IA64 w/32 bit ABI */ - /* (HPUX) */ /* SH ==> Hitachi SuperH */ /* (LINUX & MSWINCE) */ /* X86_64 ==> AMD x86-64 */ + /* POWERPC ==> IBM/Apple PowerPC */ + /* (MACOS(<=9),DARWIN(incl.MACOSX),*/ + /* LINUX, NETBSD, NOSYS variants) */ /* @@ -450,7 +482,12 @@ * defining it to be 1 will always work, but perform poorly. * * DATASTART is the beginning of the data segment. - * On UNIX systems, the collector will scan the area between DATASTART + * On some platforms SEARCH_FOR_DATA_START is defined. + * SEARCH_FOR_DATASTART will cause GC_data_start to + * be set to an address determined by accessing data backwards from _end + * until an unmapped page is found. DATASTART will be defined to be + * GC_data_start. + * On UNIX-like systems, the collector will scan the area between DATASTART * and DATAEND for root pointers. * * DATAEND, if not `end' where `end' is defined as ``extern int end[];''. @@ -470,8 +507,13 @@ * 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and * 2) define exactly one of * STACKBOTTOM (should be defined to be an expression) + * LINUX_STACKBOTTOM * HEURISTIC1 * HEURISTIC2 + * If STACKBOTTOM is defined, then it's value will be used directly as the + * stack base. If LINUX_STACKBOTTOM is defined, then it will be determined + * with a method appropriate for most Linux systems. Currently we look + * first for __libc_stack_end, and if that fails read it from /proc. * If either of the last two macros are defined, then STACKBOTTOM is computed * during collector startup using one of the following two heuristics: * HEURISTIC1: Take an address inside GC_init's frame, and round it up to @@ -536,6 +578,9 @@ * An architecture may also define CLEAR_DOUBLE(x) to be a fast way to * clear the two words at GC_malloc-aligned address x. By default, * word stores of 0 are used instead. + * + * HEAP_START may be defined as the initial address hint for mmap-based + * allocation. */ /* If we are using a recent version of gcc, we can use __builtin_unwind_init() @@ -560,18 +605,25 @@ # ifdef NETBSD # define OS_TYPE "NETBSD" # define HEURISTIC2 - extern char etext[]; -# define DATASTART ((ptr_t)(etext)) +# ifdef __ELF__ +# define DATASTART GC_data_start +# define DYNAMIC_LOADING +# else + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) +# endif # endif # ifdef LINUX # define OS_TYPE "LINUX" # define STACKBOTTOM ((ptr_t)0xf0000000) +# define USE_GENERIC_PUSH_REGS + /* We never got around to the assembly version. */ /* # define MPROTECT_VDB - Reported to not work 9/17/01 */ # ifdef __ELF__ # define DYNAMIC_LOADING # include <features.h> # if defined(__GLIBC__)&& __GLIBC__>=2 -# define LINUX_DATA_START +# define SEARCH_FOR_DATA_START # else /* !GLIBC2 */ extern char **__environ; # define DATASTART ((ptr_t)(&__environ)) @@ -666,26 +718,49 @@ # define DATAEND /* not needed */ # endif # ifdef LINUX -# define ALIGNMENT 4 /* Guess. Can someone verify? */ +# if (defined (powerpc64) || defined(__powerpc64__)) +# define ALIGNMENT 8 +# define CPP_WORDSZ 64 +# else +# define ALIGNMENT 4 /* Guess. Can someone verify? */ /* This was 2, but that didn't sound right. */ +# endif # define OS_TYPE "LINUX" -# define DYNAMIC_LOADING + /* HEURISTIC1 has been reliably reported to fail for a 32-bit */ + /* executable on a 64 bit kernel. */ # define LINUX_STACKBOTTOM - /* Stack usually starts at 0x80000000 */ -# define LINUX_DATA_START +# define DYNAMIC_LOADING +# define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND (_end) # endif -# ifdef MACOSX - /* There are reasons to suspect this may not be reliable. */ +# ifdef DARWIN # define ALIGNMENT 4 -# define OS_TYPE "MACOSX" +# define OS_TYPE "DARWIN" +# define DYNAMIC_LOADING + /* XXX: see get_end(3), get_etext() and get_end() should not be used. + These aren't used when dyld support is enabled (it is by default) */ # define DATASTART ((ptr_t) get_etext()) +# define DATAEND ((ptr_t) get_end()) # define STACKBOTTOM ((ptr_t) 0xc0000000) -# define DATAEND /* not needed */ -# undef MPROTECT_VDB +# define USE_MMAP +# define USE_MMAP_ANON +# define USE_ASM_PUSH_REGS + /* This is potentially buggy. It needs more testing. See the comments in + os_dep.c */ +# define MPROTECT_VDB # include <unistd.h> # define GETPAGESIZE() getpagesize() +# if defined(USE_PPC_PREFETCH) && defined(__GNUC__) + /* The performance impact of prefetches is untested */ +# define PREFETCH(x) \ + __asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x))) +# define PREFETCH_FOR_WRITE(x) \ + __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x))) +# endif + /* There seems to be some issues with trylock hanging on darwin. This + should be looked into some more */ +# define NO_PTHREAD_TRYLOCK # endif # ifdef NETBSD # define ALIGNMENT 4 @@ -746,8 +821,8 @@ # define OS_TYPE "SUNOS5" extern int _etext[]; extern int _end[]; - extern char * GC_SysVGetDataStart(); -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext) + extern ptr_t GC_SysVGetDataStart(); +# define DATASTART GC_SysVGetDataStart(0x10000, _etext) # define DATAEND (_end) # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) # define USE_MMAP @@ -801,9 +876,9 @@ # endif # ifdef DRSNX # define OS_TYPE "DRSNX" - extern char * GC_SysVGetDataStart(); + extern ptr_t GC_SysVGetDataStart(); extern int etext[]; -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext) +# define DATASTART GC_SysVGetDataStart(0x10000, etext) # define MPROTECT_VDB # define STACKBOTTOM ((ptr_t) 0xdfff0000) # define DYNAMIC_LOADING @@ -819,13 +894,14 @@ extern int _etext[]; # define DATAEND (_end) # define SVR4 + extern ptr_t GC_SysVGetDataStart(); # ifdef __arch64__ +# define DATASTART GC_SysVGetDataStart(0x100000, _etext) /* libc_stack_end is not set reliably for sparc64 */ -# define STACKBOTTOM ((ptr_t) 0x80000000000) -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x100000, _etext) +# define STACKBOTTOM ((ptr_t) 0x80000000000ULL) # else -# define LINUX_STACKBOTTOM -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext) +# define DATASTART GC_SysVGetDataStart(0x10000, _etext) +# define LINUX_STACKBOTTOM # endif # endif # ifdef OPENBSD @@ -876,7 +952,7 @@ # ifdef SUNOS5 # define OS_TYPE "SUNOS5" extern int _etext[], _end[]; - extern char * GC_SysVGetDataStart(); + extern ptr_t GC_SysVGetDataStart(); # define DATASTART GC_SysVGetDataStart(0x1000, _etext) # define DATAEND (_end) /* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */ @@ -921,6 +997,28 @@ # define DYNAMIC_LOADING # define ELF_CLASS ELFCLASS32 # endif +# ifdef DGUX +# define OS_TYPE "DGUX" + extern int _etext, _end; + extern ptr_t GC_SysVGetDataStart(); +# define DATASTART GC_SysVGetDataStart(0x1000, &_etext) +# define DATAEND (&_end) +# define STACK_GROWS_DOWN +# define HEURISTIC2 +# include <unistd.h> +# define GETPAGESIZE() sysconf(_SC_PAGESIZE) +# define DYNAMIC_LOADING +# ifndef USE_MMAP +# define USE_MMAP +# endif /* USE_MMAP */ +# define MAP_FAILED (void *) -1 +# ifdef USE_MMAP +# define HEAP_START (ptr_t)0x40000000 +# else /* USE_MMAP */ +# define HEAP_START DATAEND +# endif /* USE_MMAP */ +# endif /* DGUX */ + # ifdef LINUX # ifndef __GNUC__ /* The Intel compiler doesn't like inline assembly */ @@ -944,6 +1042,9 @@ /* possibly because Linux threads is itself a malloc client */ /* and can't deal with the signals. */ # endif +# define HEAP_START 0x1000 + /* This encourages mmap to give us low addresses, */ + /* thus allowing the heap to grow to ~3GB */ # ifdef __ELF__ # define DYNAMIC_LOADING # ifdef UNDEFINED /* includes ro data */ @@ -952,7 +1053,7 @@ # endif # include <features.h> # if defined(__GLIBC__) && __GLIBC__ >= 2 -# define LINUX_DATA_START +# define SEARCH_FOR_DATA_START # else extern char **__environ; # define DATASTART ((ptr_t)(&__environ)) @@ -1006,8 +1107,12 @@ /* DATAEND = _data_end__ */ /* To get it right for both, we take the */ /* minumum/maximum of the two. */ +# ifndef MAX # define MAX(x,y) ((x) > (y) ? (x) : (y)) +# endif +# ifndef MIN # define MIN(x,y) ((x) < (y) ? (x) : (y)) +# endif # define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__)) # define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__)) # undef STACK_GRAN @@ -1061,16 +1166,9 @@ # ifdef __ELF__ # define DYNAMIC_LOADING # endif -/* Handle unmapped hole i386*-*-freebsd[45]* may put between etext and edata. */ extern char etext[]; - extern char edata[]; - extern char end[]; -# define NEED_FIND_LIMIT -# define DATASTART ((ptr_t)(etext)) -# define MIN(x,y) ((x) < (y) ? (x) : (y)) -# define DATAEND (MIN (GC_find_limit (DATASTART, TRUE), DATASTART2)) -# define DATASTART2 ((ptr_t)(edata)) -# define DATAEND2 ((ptr_t)(end)) + extern char * GC_FreeBSDGetDataStart(); +# define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext) # endif # ifdef NETBSD # define OS_TYPE "NETBSD" @@ -1149,7 +1247,11 @@ # define DATASTART ((ptr_t)(__data_start)) # define ALIGNMENT 4 # define USE_GENERIC_PUSH_REGS -# define LINUX_STACKBOTTOM +# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2 +# define LINUX_STACKBOTTOM +# else +# define STACKBOTTOM 0x80000000 +# endif # endif /* Linux */ # ifdef EWS4800 # define HEURISTIC2 @@ -1203,7 +1305,8 @@ /* heap sections so they're not */ /* considered as roots. */ # define OS_TYPE "IRIX5" -# define MPROTECT_VDB +/*# define MPROTECT_VDB DOB: this should work, but there is evidence */ +/* of recent breakage. */ # ifdef _MIPS_SZPTR # define CPP_WORDSZ _MIPS_SZPTR # define ALIGNMENT (_MIPS_SZPTR/8) @@ -1226,28 +1329,46 @@ # define ALIGNMENT 4 # define HEURISTIC2 # define USE_GENERIC_PUSH_REGS - extern int _fdata[]; -# define DATASTART ((ptr_t)(_fdata)) - extern int _end[]; -# define DATAEND ((ptr_t)(_end)) -# define DYNAMIC_LOADING +# ifdef __ELF__ + extern int etext[]; +# define DATASTART GC_data_start +# define NEED_FIND_LIMIT +# define DYNAMIC_LOADING +# else +# define DATASTART ((ptr_t) 0x10000000) +# define STACKBOTTOM ((ptr_t) 0x7ffff000) +# endif /* _ELF_ */ # endif # endif # ifdef RS6000 # define MACH_TYPE "RS6000" +# ifdef ALIGNMENT +# undef ALIGNMENT +# endif +# ifdef IA64 +# undef IA64 /* DOB: some AIX installs stupidly define IA64 in /usr/include/sys/systemcfg.h */ +# endif # ifdef __64BIT__ # define ALIGNMENT 8 # define CPP_WORDSZ 64 +# define STACKBOTTOM ((ptr_t)0x1000000000000000) # else # define ALIGNMENT 4 # define CPP_WORDSZ 32 -# endif +# define STACKBOTTOM ((ptr_t)((ulong)&errno)) +# endif + /* From AIX linker man page: + _text Specifies the first location of the program. + _etext Specifies the first location after the program. + _data Specifies the first location of the data. + _edata Specifies the first location after the initialized data + _end or end Specifies the first location after all data. + */ extern int _data[], _end[]; # define DATASTART ((ptr_t)((ulong)_data)) # define DATAEND ((ptr_t)((ulong)_end)) extern int errno; -# define STACKBOTTOM ((ptr_t)((ulong)&errno)) # define USE_GENERIC_PUSH_REGS # define DYNAMIC_LOADING /* For really old versions of AIX, this may have to be removed. */ @@ -1311,15 +1432,23 @@ # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM # define DYNAMIC_LOADING -# define LINUX_DATA_START +# define SEARCH_FOR_DATA_START extern int _end[]; -# define DATAEND (_end) +# define DATAEND (&_end) # endif /* LINUX */ # endif /* HP_PA */ # ifdef ALPHA # define MACH_TYPE "ALPHA" # define ALIGNMENT 8 +# define CPP_WORDSZ 64 +# ifndef LINUX +# define USE_GENERIC_PUSH_REGS + /* Gcc and probably the DEC/Compaq compiler spill pointers to preserved */ + /* fp registers in some cases when the target is a 21264. The assembly */ + /* code doesn't handle that yet, and version dependencies make that a */ + /* bit tricky. Do the easy thing for now. */ +# endif # ifdef NETBSD # define OS_TYPE "NETBSD" # define HEURISTIC2 @@ -1327,13 +1456,11 @@ # define ELFCLASS32 32 # define ELFCLASS64 64 # define ELF_CLASS ELFCLASS64 -# define CPP_WORDSZ 64 # define DYNAMIC_LOADING # endif # ifdef OPENBSD # define OS_TYPE "OPENBSD" # define HEURISTIC2 -# define CPP_WORDSZ 64 # ifdef __ELF__ /* since OpenBSD/Alpha 2.9 */ # define DATASTART GC_data_start # define ELFCLASS32 32 @@ -1357,17 +1484,16 @@ extern char edata[]; extern char end[]; # define NEED_FIND_LIMIT -# define DATASTART ((ptr_t)(etext)) +# define DATASTART ((ptr_t)(&etext)) # define DATAEND (GC_find_limit (DATASTART, TRUE)) -# define DATASTART2 ((ptr_t)(edata)) -# define DATAEND2 ((ptr_t)(end)) -# define CPP_WORDSZ 64 +# define DATASTART2 ((ptr_t)(&edata)) +# define DATAEND2 ((ptr_t)(&end)) # endif # ifdef OSF1 # define OS_TYPE "OSF1" # define DATASTART ((ptr_t) 0x140000000) extern int _end[]; -# define DATAEND ((ptr_t) _end) +# define DATAEND ((ptr_t) &_end) extern char ** environ; /* round up from the value of environ to the nearest page boundary */ /* Probably breaks if putenv is called before collector */ @@ -1378,19 +1504,19 @@ /* the text segment immediately follows the stack. */ /* Hence we give an upper pound. */ /* This is currently unused, since we disabled HEURISTIC2 */ - extern int __start[]; + extern int __start[]; # define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1))) -# define CPP_WORDSZ 64 -# define MPROTECT_VDB +# ifndef GC_OSF1_THREADS + /* Unresolved signal issues with threads. */ +# define MPROTECT_VDB +# endif # define DYNAMIC_LOADING # endif # ifdef LINUX # define OS_TYPE "LINUX" -# define CPP_WORDSZ 64 # define STACKBOTTOM ((ptr_t) 0x120000000) # ifdef __ELF__ # define SEARCH_FOR_DATA_START -# define DATASTART GC_data_start # define DYNAMIC_LOADING # else # define DATASTART ((ptr_t) 0x140000000) @@ -1468,7 +1594,6 @@ extern char * GC_register_stackbottom; # define BACKING_STORE_BASE ((ptr_t)GC_register_stackbottom) # define SEARCH_FOR_DATA_START -# define DATASTART GC_data_start # ifdef __GNUC__ # define DYNAMIC_LOADING # else @@ -1502,23 +1627,25 @@ # endif # ifdef DGUX # define OS_TYPE "DGUX" - extern char * GC_SysVGetDataStart(); -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext) + extern ptr_t GC_SysVGetDataStart(); +# define DATASTART GC_SysVGetDataStart(0x10000, etext) # endif # define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */ # endif # ifdef S370 + /* If this still works, and if anyone cares, this should probably */ + /* be moved to the S390 category. */ # define MACH_TYPE "S370" # define ALIGNMENT 4 /* Required by hardware */ # define USE_GENERIC_PUSH_REGS # ifdef UTS4 # define OS_TYPE "UTS4" - extern int etext[]; + extern int etext[]; extern int _etext[]; extern int _end[]; - extern char * GC_SysVGetDataStart(); -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext) + extern ptr_t GC_SysVGetDataStart(); +# define DATASTART GC_SysVGetDataStart(0x10000, _etext) # define DATAEND (_end) # define HEURISTIC2 # endif @@ -1528,23 +1655,23 @@ # define MACH_TYPE "S390" # define USE_GENERIC_PUSH_REGS # ifndef __s390x__ -# define ALIGNMENT 4 -# define CPP_WORDSZ 32 +# define ALIGNMENT 4 +# define CPP_WORDSZ 32 # else -# define ALIGNMENT 8 -# define CPP_WORDSZ 64 -# define HBLKSIZE 4096 +# define ALIGNMENT 8 +# define CPP_WORDSZ 64 +# define HBLKSIZE 4096 # endif # ifdef LINUX # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM # define DYNAMIC_LOADING - extern int __data_start[]; + extern int __data_start[]; # define DATASTART ((ptr_t)(__data_start)) - extern int _end[]; -# define DATAEND (_end) -# define CACHE_LINE_SIZE 256 -# define GETPAGESIZE() 4096 + extern int _end[]; +# define DATAEND (_end) +# define CACHE_LINE_SIZE 256 +# define GETPAGESIZE() 4096 # endif # endif @@ -1562,13 +1689,8 @@ # ifdef NETBSD # define OS_TYPE "NETBSD" # define HEURISTIC2 -# ifdef __ELF__ -# define DATASTART GC_data_start -# define DYNAMIC_LOADING -# else - extern char etext[]; -# define DATASTART ((ptr_t)(etext)) -# endif + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # define USE_GENERIC_PUSH_REGS # endif # ifdef LINUX @@ -1581,7 +1703,7 @@ # define DYNAMIC_LOADING # include <features.h> # if defined(__GLIBC__) && __GLIBC__ >= 2 -# define LINUX_DATA_START +# define SEARCH_FOR_DATA_START # else extern char **__environ; # define DATASTART ((ptr_t)(&__environ)) @@ -1628,7 +1750,7 @@ # define STACKBOTTOM ((ptr_t) 0x7c000000) # define USE_GENERIC_PUSH_REGS # define DYNAMIC_LOADING -# define LINUX_DATA_START +# define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND (_end) # endif @@ -1645,7 +1767,9 @@ # define MACH_TYPE "X86_64" # define ALIGNMENT 8 # define CPP_WORDSZ 64 -# define HBLKSIZE 4096 +# ifndef HBLKSIZE +# define HBLKSIZE 4096 +# endif # define CACHE_LINE_SIZE 64 # define USE_GENERIC_PUSH_REGS # ifdef LINUX @@ -1665,7 +1789,7 @@ # define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff)) # endif # include <features.h> -# define LINUX_DATA_START +# define SEARCH_FOR_DATA_START extern int _end[]; # define DATAEND (_end) # else @@ -1679,19 +1803,6 @@ # endif # endif -#ifdef LINUX_DATA_START - /* Some Linux distributions arrange to define __data_start. Some */ - /* define data_start as a weak symbol. The latter is technically */ - /* broken, since the user program may define data_start, in which */ - /* case we lose. Nonetheless, we try both, prefering __data_start. */ - /* We assume gcc. */ -# pragma weak __data_start - extern int __data_start[]; -# pragma weak data_start - extern int data_start[]; -# define DATASTART ((ptr_t)(__data_start != 0? __data_start : data_start)) -#endif - #if defined(LINUX) && defined(REDIRECT_MALLOC) /* Rld appears to allocate some memory with its own allocator, and */ /* some through malloc, which might be redirected. To make this */ @@ -1730,15 +1841,15 @@ # endif # if defined(SUNOS5) || defined(DRSNX) || defined(UTS4) - /* OS has SVR4 generic features. Probably others also qualify. */ + /* OS has SVR4 generic features. Probably others also qualify. */ # define SVR4 # endif # if defined(SUNOS5) || defined(DRSNX) - /* OS has SUNOS5 style semi-undocumented interface to dynamic */ - /* loader. */ + /* OS has SUNOS5 style semi-undocumented interface to dynamic */ + /* loader. */ # define SUNOS5DL - /* OS has SUNOS5 style signal handlers. */ + /* OS has SUNOS5 style signal handlers. */ # define SUNOS5SIGS # endif @@ -1747,13 +1858,14 @@ # endif # if defined(SVR4) || defined(LINUX) || defined(IRIX) || defined(HPUX) \ - || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \ - || defined(BSD) || defined(_AIX) || defined(MACOSX) || defined(OSF1) + || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \ + || defined(DGUX) || defined(BSD) \ + || defined(_AIX) || defined(DARWIN) || defined(OSF1) # define UNIX_LIKE /* Basic Unix-like system calls work. */ # endif # if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 - -> bad word size + -> bad word size # endif # ifdef PCR @@ -1767,13 +1879,13 @@ # endif # ifdef SRC_M3 -/* Postponed for now. */ + /* Postponed for now. */ # undef PROC_VDB # undef MPROTECT_VDB # endif # ifdef SMALL_CONFIG -/* Presumably not worth the space it takes. */ + /* Presumably not worth the space it takes. */ # undef PROC_VDB # undef MPROTECT_VDB # endif @@ -1813,49 +1925,50 @@ /* platforms as well, though it should be avoided in win32. */ # endif /* LINUX */ -# if defined(SEARCH_FOR_DATA_START) && defined(GC_PRIVATE_H) +# if defined(SEARCH_FOR_DATA_START) extern ptr_t GC_data_start; +# define DATASTART GC_data_start # endif # ifndef CLEAR_DOUBLE # define CLEAR_DOUBLE(x) \ - ((word*)x)[0] = 0; \ - ((word*)x)[1] = 0; + ((word*)x)[0] = 0; \ + ((word*)x)[1] = 0; # endif /* CLEAR_DOUBLE */ -/* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */ + /* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */ # if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS) # define GC_SOLARIS_THREADS # endif # if defined(GC_IRIX_THREADS) && !defined(IRIX5) ---> inconsistent configuration + --> inconsistent configuration # endif # if defined(GC_LINUX_THREADS) && !defined(LINUX) ---> inconsistent configuration + --> inconsistent configuration # endif # if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5) ---> inconsistent configuration + --> inconsistent configuration # endif # if defined(GC_HPUX_THREADS) && !defined(HPUX) ---> inconsistent configuration + --> inconsistent configuration +# endif +# if defined(GC_AIX_THREADS) && !defined(_AIX) + --> inconsistent configuration # endif -# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) - /* Ideally CYGWIN32 should work, in addition to MSWIN32. I suspect */ - /* the necessary code is mostly there, but nobody has actually made */ - /* sure the right combination of pieces is compiled in, etc. */ ---> inconsistent configuration +# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32) + --> inconsistent configuration # endif # if defined(PCR) || defined(SRC_M3) || \ - defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \ - defined(GC_PTHREADS) + defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \ + defined(GC_PTHREADS) # define THREADS # endif -# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(MACOSX) \ - || defined(LINT) || defined(MSWINCE) \ - || (defined(I386) && defined(__LCC__)) +# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \ + || defined(LINT) || defined(MSWINCE) || defined(ARM32) \ + || (defined(I386) && defined(__LCC__)) /* Use setjmp based hack to mark from callee-save registers. */ /* The define should move to the individual platform */ /* descriptions. */ @@ -1867,36 +1980,26 @@ /* include assembly code to do it well. */ # endif -/* Can we save call chain in objects for debugging? */ -/* SET NFRAMES (# of saved frames) and NARGS (#of args for each frame) */ -/* to reasonable values for the platform. */ -/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified at */ -/* build time, though we feel free to adjust it slightly. */ -/* Define NEED_CALLINFO if we either save the call stack or */ -/* GC_ADD_CALLER is defined. */ -#ifdef LINUX -# include <features.h> -# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2 -# define HAVE_BUILTIN_BACKTRACE -# endif -#endif + /* Can we save call chain in objects for debugging? */ + /* SET NFRAMES (# of saved frames) and NARGS (#of args for each */ + /* frame) to reasonable values for the platform. */ + /* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */ + /* at build time, though we feel free to adjust it slightly. */ + /* Define NEED_CALLINFO if we either save the call stack or */ + /* GC_ADD_CALLER is defined. */ + /* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */ #if defined(SPARC) -# define CAN_SAVE_CALL_STACKS # define CAN_SAVE_CALL_ARGS #endif #if (defined(I386) || defined(X86_64)) && defined(LINUX) - /* SAVE_CALL_CHAIN is supported if the code is compiled to save */ - /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */ -# define CAN_SAVE_CALL_STACKS + /* SAVE_CALL_CHAIN is supported if the code is compiled to save */ + /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */ # define CAN_SAVE_CALL_ARGS #endif -#if defined(HAVE_BUILTIN_BACKTRACE) && !defined(CAN_SAVE_CALL_STACKS) -# define CAN_SAVE_CALL_STACKS -#endif # if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \ - && defined(CAN_SAVE_CALL_STACKS) + && defined(GC_CAN_SAVE_CALL_STACKS) # define SAVE_CALL_CHAIN # endif # ifdef SAVE_CALL_CHAIN @@ -1909,7 +2012,7 @@ # ifdef SAVE_CALL_CHAIN # ifndef SAVE_CALL_COUNT # define NFRAMES 6 /* Number of frames to save. Even for */ - /* alignment reasons. */ + /* alignment reasons. */ # else # define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1) # endif @@ -1925,4 +2028,96 @@ # define DBG_HDRS_ALL # endif +# if defined(POINTER_MASK) && !defined(POINTER_SHIFT) +# define POINTER_SHIFT 0 +# endif + +# if defined(POINTER_SHIFT) && !defined(POINTER_MASK) +# define POINTER_MASK ((GC_word)(-1)) +# endif + +# if !defined(FIXUP_POINTER) && defined(POINTER_MASK) +# define FIXUP_POINTER(p) (p) = ((p) & (POINTER_MASK) << POINTER_SHIFT) +# endif + +# if defined(FIXUP_POINTER) +# define NEED_FIXUP_POINTER 1 +# else +# define NEED_FIXUP_POINTER 0 +# define FIXUP_POINTER(p) +# endif + +#ifdef GC_PRIVATE_H + /* This relies on some type definitions from gc_priv.h, from */ + /* where it's normally included. */ + /* */ + /* How to get heap memory from the OS: */ + /* Note that sbrk()-like allocation is preferred, since it */ + /* usually makes it possible to merge consecutively allocated */ + /* chunks. It also avoids unintented recursion with */ + /* -DREDIRECT_MALLOC. */ + /* GET_MEM() returns a HLKSIZE aligned chunk. */ + /* 0 is taken to mean failure. */ + /* In the case os USE_MMAP, the argument must also be a */ + /* physical page size. */ + /* 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 gc_priv.h. */ +# ifdef PCR + char * real_malloc(); +# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \ + + GC_page_size-1) +# else +# ifdef OS2 + void * os2_alloc(size_t bytes); +# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \ + + GC_page_size) \ + + GC_page_size-1) +# else +# if defined(NEXT) || defined(DOS4GW) || \ + (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \ + (defined(SUNOS5) && !defined(USE_MMAP)) +# define GET_MEM(bytes) HBLKPTR((size_t) \ + calloc(1, (size_t)bytes + GC_page_size) \ + + GC_page_size-1) +# else +# ifdef MSWIN32 + extern ptr_t GC_win32_get_mem(); +# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes) +# else +# ifdef MACOS +# if defined(USE_TEMPORARY_MEMORY) + extern Ptr GC_MacTemporaryNewPtr(size_t size, + Boolean clearMemory); +# define GET_MEM(bytes) HBLKPTR( \ + GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \ + + GC_page_size-1) +# else +# define GET_MEM(bytes) HBLKPTR( \ + NewPtrClear(bytes + GC_page_size) + GC_page_size-1) +# endif +# else +# 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 + +#endif /* GC_PRIVATE_H */ + # endif /* GCCONFIG_H */ diff --git a/boehm-gc/include/private/solaris_threads.h b/boehm-gc/include/private/solaris_threads.h index 1464bc14fd7..7d49c2987e0 100644 --- a/boehm-gc/include/private/solaris_threads.h +++ b/boehm-gc/include/private/solaris_threads.h @@ -16,7 +16,8 @@ # define DETACHED 2 /* Thread is intended to be detached. */ # define CLIENT_OWNS_STACK 4 /* Stack was supplied by client. */ -# define SUSPENDED 8 /* Currently suspended. */ +# define SUSPNDED 8 /* Currently suspended. */ + /* SUSPENDED is used insystem header. */ ptr_t stack; size_t stack_size; cond_t join_cv; diff --git a/boehm-gc/include/private/specific.h b/boehm-gc/include/private/specific.h index 399f84f58d6..a0e6ae0ebc1 100644 --- a/boehm-gc/include/private/specific.h +++ b/boehm-gc/include/private/specific.h @@ -85,7 +85,7 @@ static __inline__ void * PREFIXED(getspecific) (tsd * key) { unsigned hash_val = CACHE_HASH(qtid); tse * volatile * entry_ptr = key -> cache + hash_val; tse * entry = *entry_ptr; /* Must be loaded only once. */ - if (entry -> qtid == qtid) { + if (EXPECT(entry -> qtid == qtid, 1)) { GC_ASSERT(entry -> thread == pthread_self()); return entry -> value; } |