diff options
Diffstat (limited to '')
-rw-r--r-- | gc/include/gc.h | 96 | ||||
-rw-r--r-- | gc/include/gc_allocator.h | 232 | ||||
-rw-r--r-- | gc/include/gc_cpp.h | 56 | ||||
-rw-r--r-- | gc/include/gc_local_alloc.h | 3 | ||||
-rw-r--r-- | gc/include/private/dbg_mlc.h | 10 | ||||
-rw-r--r-- | gc/include/private/gc_hdrs.h | 2 | ||||
-rw-r--r-- | gc/include/private/gc_locks.h | 51 | ||||
-rw-r--r-- | gc/include/private/gc_pmark.h | 16 | ||||
-rw-r--r-- | gc/include/private/gc_priv.h | 156 | ||||
-rw-r--r-- | gc/include/private/gcconfig.h | 610 | ||||
-rw-r--r-- | gc/include/private/solaris_threads.h | 3 | ||||
-rw-r--r-- | gc/include/private/specific.h | 24 |
12 files changed, 877 insertions, 382 deletions
diff --git a/gc/include/gc.h b/gc/include/gc.h index 8ac709b..6ea7165 100644 --- a/gc/include/gc.h +++ b/gc/include/gc.h @@ -43,6 +43,11 @@ #if defined(IRIX_THREADS) # define GC_IRIX_THREADS #endif +#if defined(DGUX_THREADS) +# if !defined(GC_DGUX386_THREADS) +# define GC_DGUX386_THREADS +# endif +#endif #if defined(HPUX_THREADS) # define GC_HPUX_THREADS #endif @@ -68,13 +73,19 @@ /* depend on this were previously included. */ #endif +#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE) +# define _POSIX4A_DRAFT10_SOURCE 1 +#endif + #if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS) # define GC_SOLARIS_THREADS #endif # if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \ defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \ - defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) + defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \ + defined(GC_DGUX386_THREADS) || \ + (defined(GC_WIN32_THREADS) && defined(__CYGWIN32__)) # define GC_PTHREADS # endif @@ -86,7 +97,7 @@ typedef long ptrdiff_t; /* ptrdiff_t is not defined */ # endif -#if defined(__MINGW32__) && defined(GC_WIN32_THREADS) +#if defined(__MINGW32__) && defined(_DLL) && !defined(GC_NOT_DLL) # ifdef GC_BUILD # define GC_API __declspec(dllexport) # else @@ -154,7 +165,7 @@ GC_API int GC_parallel; /* GC is parallelized for performance on */ /* Env variable GC_NPROC is set to > 1, or */ /* GC_NPROC is not set and this is an MP. */ /* If GC_parallel is set, incremental */ - /* collection is aonly partially functional, */ + /* collection is only partially functional, */ /* and may not be desirable. */ @@ -296,7 +307,29 @@ GC_API int GC_dont_precollect; /* Don't collect as part of */ /* Interferes with blacklisting. */ /* Wizards only. */ +GC_API unsigned long GC_time_limit; + /* If incremental collection is enabled, */ + /* We try to terminate collections */ + /* after this many milliseconds. Not a */ + /* hard time bound. Setting this to */ + /* GC_TIME_UNLIMITED will essentially */ + /* disable incremental collection while */ + /* leaving generational collection */ + /* enabled. */ +# define GC_TIME_UNLIMITED 999999 + /* Setting GC_time_limit to this value */ + /* will disable the "pause time exceeded"*/ + /* tests. */ + /* Public procedures */ + +/* Initialize the collector. This is only required when using thread-local + * allocation, since unlike the regular allocation routines, GC_local_malloc + * is not self-initializing. If you use GC_local_malloc you should arrange + * to call this somehow (e.g. from a constructor) before doing any allocation. + */ +GC_API void GC_init GC_PROTO((void)); + /* * general purpose allocation routines, with roughly malloc calling conv. * The atomic versions promise that no relevant pointers are contained @@ -452,9 +485,23 @@ GC_API size_t GC_get_total_bytes GC_PROTO((void)); /* Don't use in leak finding mode. */ /* Ignored if GC_dont_gc is true. */ /* Only the generational piece of this is */ -/* functional if GC_parallel is TRUE. */ +/* functional if GC_parallel is TRUE */ +/* or if GC_time_limit is GC_TIME_UNLIMITED. */ +/* Causes GC_local_gcj_malloc() to revert to */ +/* locked allocation. Must be called */ +/* before any GC_local_gcj_malloc() calls. */ GC_API void GC_enable_incremental GC_PROTO((void)); +/* Does incremental mode write-protect pages? Returns zero or */ +/* more of the following, or'ed together: */ +#define GC_PROTECTS_POINTER_HEAP 1 /* May protect non-atomic objs. */ +#define GC_PROTECTS_PTRFREE_HEAP 2 +#define GC_PROTECTS_STATIC_DATA 4 /* Curently never. */ +#define GC_PROTECTS_STACK 8 /* Probably impractical. */ + +#define GC_PROTECTS_NONE 0 +GC_API int GC_incremental_protection_needs GC_PROTO((void)); + /* Perform some garbage collection work, if appropriate. */ /* Return 0 if there is no more work to be done. */ /* Typically performs an amount of work corresponding roughly */ @@ -841,10 +888,24 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */ #endif /* THREADS && !SRC_M3 */ -#if defined(GC_WIN32_THREADS) && defined(_WIN32_WCE) +#if defined(GC_WIN32_THREADS) # include <windows.h> +# include <winbase.h> /* + * All threads must be created using GC_CreateThread, so that they will be + * recorded in the thread table. For backwards compatibility, this is not + * technically true if the GC is built as a dynamic library, since it can + * and does then use DllMain to keep track of thread creations. But new code + * should be built to call GC_CreateThread. + */ + HANDLE WINAPI GC_CreateThread( + LPSECURITY_ATTRIBUTES lpThreadAttributes, + DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); + +# if defined(_WIN32_WCE) + /* * win32_threads.c implements the real WinMain, which will start a new thread * to call GC_WinMain after initializing the garbage collector. */ @@ -854,21 +915,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */ LPWSTR lpCmdLine, int nCmdShow ); - /* - * All threads must be created using GC_CreateThread, so that they will be - * recorded in the thread table. - */ - HANDLE WINAPI GC_CreateThread( - LPSECURITY_ATTRIBUTES lpThreadAttributes, - DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); - -# ifndef GC_BUILD -# define WinMain GC_WinMain -# define CreateThread GC_CreateThread -# endif +# ifndef GC_BUILD +# define WinMain GC_WinMain +# define CreateThread GC_CreateThread +# endif +# endif /* defined(_WIN32_WCE) */ -#endif +#endif /* defined(GC_WIN32_THREADS) */ /* * If you are planning on putting @@ -880,9 +933,10 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */ # define GC_INIT() { extern end, etext; \ GC_noop(&end, &etext); } #else -# if defined(__CYGWIN32__) && defined(GC_USE_DLL) +# if defined(__CYGWIN32__) && defined(GC_USE_DLL) || defined (_AIX) /* - * Similarly gnu-win32 DLLs need explicit initialization + * Similarly gnu-win32 DLLs need explicit initialization from + * the main program, as does AIX. */ # define GC_INIT() { GC_add_roots(DATASTART, DATAEND); } # else diff --git a/gc/include/gc_allocator.h b/gc/include/gc_allocator.h new file mode 100644 index 0000000..87c8509 --- /dev/null +++ b/gc/include/gc_allocator.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 1996-1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Copyright (c) 2002 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/* + * This implements standard-conforming allocators that interact with + * the garbage collector. Gc_alloctor<T> allocates garbage-collectable + * objects of type T. Traceable_allocator<T> allocates objects that + * are not temselves garbage collected, but are scanned by the + * collector for pointers to collectable objects. Traceable_alloc + * should be used for explicitly managed STL containers that may + * point to collectable objects. + * + * This code was derived from an earlier version of the GNU C++ standard + * library, which itself was derived from the SGI STL implementation. + */ + +#include "gc.h" // For size_t + +/* First some helpers to allow us to dispatch on whether or not a type + * is known to be pointerfree. + * These are private, except that the client may invoke the + * GC_DECLARE_PTRFREE macro. + */ + +struct GC_true_type {}; +struct GC_false_type {}; + +template <class GC_tp> +struct GC_type_traits { + GC_false_type GC_is_ptr_free; +}; + +# define GC_DECLARE_PTRFREE(T) \ +template<> struct GC_type_traits<T> { GC_true_type GC_is_ptr_free; } + +GC_DECLARE_PTRFREE(signed char); +GC_DECLARE_PTRFREE(unsigned char); +GC_DECLARE_PTRFREE(signed short); +GC_DECLARE_PTRFREE(unsigned short); +GC_DECLARE_PTRFREE(signed int); +GC_DECLARE_PTRFREE(unsigned int); +GC_DECLARE_PTRFREE(signed long); +GC_DECLARE_PTRFREE(unsigned long); +GC_DECLARE_PTRFREE(float); +GC_DECLARE_PTRFREE(double); +/* The client may want to add others. */ + +// In the following GC_Tp is GC_true_type iff we are allocating a +// pointerfree object. +template <class GC_Tp> +inline void * GC_selective_alloc(size_t n, GC_Tp) { + return GC_MALLOC(n); +} + +template <> +inline void * GC_selective_alloc<GC_true_type>(size_t n, GC_true_type) { + return GC_MALLOC_ATOMIC(n); +} + +/* Now the public gc_allocator<T> class: + */ +template <class GC_Tp> +class gc_allocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef GC_Tp* pointer; + typedef const GC_Tp* const_pointer; + typedef GC_Tp& reference; + typedef const GC_Tp& const_reference; + typedef GC_Tp value_type; + + template <class GC_Tp1> struct rebind { + typedef gc_allocator<GC_Tp1> other; + }; + + gc_allocator() {} +# ifndef _MSC_VER + // I'm not sure why this is needed here in addition to the following. + // The standard specifies it for the standard allocator, but VC++ rejects + // it. -HB + gc_allocator(const gc_allocator&) throw() {} +# endif + template <class GC_Tp1> gc_allocator(const gc_allocator<GC_Tp1>&) throw() {} + ~gc_allocator() throw() {} + + pointer address(reference GC_x) const { return &GC_x; } + const_pointer address(const_reference GC_x) const { return &GC_x; } + + // GC_n is permitted to be 0. The C++ standard says nothing about what + // the return value is when GC_n == 0. + GC_Tp* allocate(size_type GC_n, const void* = 0) { + GC_type_traits<GC_Tp> traits; + return static_cast<GC_Tp *> + (GC_selective_alloc(GC_n * sizeof(GC_Tp), + traits.GC_is_ptr_free)); + } + + // __p is not permitted to be a null pointer. + void deallocate(pointer __p, size_type GC_n) + { GC_FREE(__p); } + + size_type max_size() const throw() + { return size_t(-1) / sizeof(GC_Tp); } + + void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); } + void destroy(pointer __p) { __p->~GC_Tp(); } +}; + +template<> +class gc_allocator<void> { + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef void* pointer; + typedef const void* const_pointer; + typedef void value_type; + + template <class GC_Tp1> struct rebind { + typedef gc_allocator<GC_Tp1> other; + }; +}; + + +template <class GC_T1, class GC_T2> +inline bool operator==(const gc_allocator<GC_T1>&, const gc_allocator<GC_T2>&) +{ + return true; +} + +template <class GC_T1, class GC_T2> +inline bool operator!=(const gc_allocator<GC_T1>&, const gc_allocator<GC_T2>&) +{ + return false; +} + +/* + * And the public traceable_allocator class. + */ + +// Note that we currently don't specialize the pointer-free case, since a +// pointer-free traceable container doesn't make that much sense, +// though it could become an issue due to abstraction boundaries. +template <class GC_Tp> +class traceable_allocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef GC_Tp* pointer; + typedef const GC_Tp* const_pointer; + typedef GC_Tp& reference; + typedef const GC_Tp& const_reference; + typedef GC_Tp value_type; + + template <class GC_Tp1> struct rebind { + typedef traceable_allocator<GC_Tp1> other; + }; + + traceable_allocator() throw() {} +# ifndef _MSC_VER + traceable_allocator(const traceable_allocator&) throw() {} +# endif + template <class GC_Tp1> traceable_allocator + (const traceable_allocator<GC_Tp1>&) throw() {} + ~traceable_allocator() throw() {} + + pointer address(reference GC_x) const { return &GC_x; } + const_pointer address(const_reference GC_x) const { return &GC_x; } + + // GC_n is permitted to be 0. The C++ standard says nothing about what + // the return value is when GC_n == 0. + GC_Tp* allocate(size_type GC_n, const void* = 0) { + return static_cast<GC_Tp*>(GC_MALLOC_UNCOLLECTABLE(GC_n * sizeof(GC_Tp))); + } + + // __p is not permitted to be a null pointer. + void deallocate(pointer __p, size_type GC_n) + { GC_FREE(__p); } + + size_type max_size() const throw() + { return size_t(-1) / sizeof(GC_Tp); } + + void construct(pointer __p, const GC_Tp& __val) { new(__p) GC_Tp(__val); } + void destroy(pointer __p) { __p->~GC_Tp(); } +}; + +template<> +class traceable_allocator<void> { + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef void* pointer; + typedef const void* const_pointer; + typedef void value_type; + + template <class GC_Tp1> struct rebind { + typedef traceable_allocator<GC_Tp1> other; + }; +}; + + +template <class GC_T1, class GC_T2> +inline bool operator==(const traceable_allocator<GC_T1>&, const traceable_allocator<GC_T2>&) +{ + return true; +} + +template <class GC_T1, class GC_T2> +inline bool operator!=(const traceable_allocator<GC_T1>&, const traceable_allocator<GC_T2>&) +{ + return false; +} + diff --git a/gc/include/gc_cpp.h b/gc/include/gc_cpp.h index ceb73f5..2b3a138 100644 --- a/gc/include/gc_cpp.h +++ b/gc/include/gc_cpp.h @@ -159,12 +159,18 @@ enum GCPlacement {UseGC, class gc {public: inline void* operator new( size_t size ); inline void* operator new( size_t size, GCPlacement gcp ); + inline void* operator new( size_t size, void *p ); + /* Must be redefined here, since the other overloadings */ + /* hide the global definition. */ inline void operator delete( void* obj ); + inline void operator delete( void*, void* ); #ifdef GC_OPERATOR_NEW_ARRAY inline void* operator new[]( size_t size ); inline void* operator new[]( size_t size, GCPlacement gcp ); + inline void* operator new[]( size_t size, void *p ); inline void operator delete[]( void* obj ); + inline void gc::operator delete[]( void*, void* ); #endif /* GC_OPERATOR_NEW_ARRAY */ }; /* @@ -211,7 +217,6 @@ inline void* operator new( classes derived from "gc_cleanup" or containing members derived from "gc_cleanup". */ -#ifdef GC_OPERATOR_NEW_ARRAY #ifdef _MSC_VER /** This ensures that the system default operator new[] doesn't get @@ -220,42 +225,24 @@ inline void* operator new( * There seems to be really redirect new in this environment without * including this everywhere. */ - inline void *operator new[]( size_t size ) - { - return GC_MALLOC_UNCOLLECTABLE( size ); - } - - inline void operator delete[](void* obj) - { - GC_FREE(obj); - }; - - inline void* operator new( size_t size) - { - return GC_MALLOC_UNCOLLECTABLE( size); - }; + void *operator new[]( size_t size ); + + void operator delete[](void* obj); - inline void operator delete(void* obj) - { - GC_FREE(obj); - }; + void* operator new( size_t size); + void operator delete(void* obj); -// This new operator is used by VC++ in case of Debug builds ! - inline void* operator new( size_t size, + // This new operator is used by VC++ in case of Debug builds ! + void* operator new( size_t size, int ,//nBlockUse, const char * szFileName, - int nLine - ) { -# ifndef GC_DEBUG - return GC_malloc_uncollectable( size ); -# else - return GC_debug_malloc_uncollectable(size, szFileName, nLine); -# endif - } - + int nLine ); #endif /* _MSC_VER */ + +#ifdef GC_OPERATOR_NEW_ARRAY + inline void* operator new[]( size_t size, GCPlacement gcp, @@ -283,9 +270,13 @@ inline void* gc::operator new( size_t size, GCPlacement gcp ) { else return GC_MALLOC_UNCOLLECTABLE( size );} +inline void* gc::operator new( size_t size, void *p ) { + return p;} + inline void gc::operator delete( void* obj ) { GC_FREE( obj );} +inline void gc::operator delete( void*, void* ) {} #ifdef GC_OPERATOR_NEW_ARRAY @@ -295,8 +286,13 @@ inline void* gc::operator new[]( size_t size ) { inline void* gc::operator new[]( size_t size, GCPlacement gcp ) { return gc::operator new( size, gcp );} +inline void* gc::operator new[]( size_t size, void *p ) { + return p;} + inline void gc::operator delete[]( void* obj ) { gc::operator delete( obj );} + +inline void gc::operator delete[]( void*, void* ) {} #endif /* GC_OPERATOR_NEW_ARRAY */ diff --git a/gc/include/gc_local_alloc.h b/gc/include/gc_local_alloc.h index 1e58730..88e29e9 100644 --- a/gc/include/gc_local_alloc.h +++ b/gc/include/gc_local_alloc.h @@ -33,6 +33,9 @@ * -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux. * * The debugging allocators use standard, not thread-local allocation. + * + * These routines normally require an explicit call to GC_init(), though + * that may be done from a constructor function. */ #ifndef GC_LOCAL_ALLOC_H diff --git a/gc/include/private/dbg_mlc.h b/gc/include/private/dbg_mlc.h index 5378835..e2003e6 100644 --- a/gc/include/private/dbg_mlc.h +++ b/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/gc/include/private/gc_hdrs.h b/gc/include/private/gc_hdrs.h index dd61545..96749ab 100644 --- a/gc/include/private/gc_hdrs.h +++ b/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/gc/include/private/gc_locks.h b/gc/include/private/gc_locks.h index 5ea1e54..2dbc6ca 100644 --- a/gc/include/private/gc_locks.h +++ b/gc/include/private/gc_locks.h @@ -145,15 +145,15 @@ # 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 */ + "2:\t\n" /* oldval is zero if we set */ : "=&r"(oldval), "=p"(addr) : "r"(temp), "1"(addr) : "memory"); @@ -161,7 +161,7 @@ } # 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 @@ -219,11 +219,19 @@ # define GC_TEST_AND_SET_DEFINED # endif # ifdef MIPS -# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ +# ifdef LINUX +# include <sys/tas.h> +# define GC_test_and_set(addr) _test_and_set((int *) addr,1) +# 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, v) test_and_set(addr,v) +# ifdef __GNUC__ +# define GC_test_and_set(addr) _test_and_set(addr,1) +# else +# define GC_test_and_set(addr) test_and_set(addr,1) +# endif # else -# define GC_test_and_set(addr, v) __test_and_set(addr,v) +# define GC_test_and_set(addr) __test_and_set(addr,1) # define GC_clear(addr) __lock_release(addr); # define GC_CLEAR_DEFINED # endif @@ -262,7 +270,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) @@ -431,7 +439,7 @@ # 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, 1)) GC_lock(); } +# define LOCK() { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } # define UNLOCK() GC_clear(&GC_allocate_lock); extern VOLATILE GC_bool GC_collecting; # define ENTER_GC() \ @@ -440,11 +448,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/gc/include/private/gc_pmark.h b/gc/include/private/gc_pmark.h index 5936f2e..cf85d4d 100644 --- a/gc/include/private/gc_pmark.h +++ b/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 * 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(); } \ } -#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(); 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, \ @@ -236,7 +227,6 @@ exit_label: ; \ # define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \ { \ register word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(displ); \ - register word mark_word = *mark_word_addr; \ \ OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(displ), \ exit_label); \ diff --git a/gc/include/private/gc_priv.h b/gc/include/private/gc_priv.h index 5ca02a6..2cf07d1 100644 --- a/gc/include/private/gc_priv.h +++ b/gc/include/private/gc_priv.h @@ -30,6 +30,12 @@ # 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> @@ -44,10 +50,6 @@ # include "../gc_mark.h" # endif -# ifndef GCCONFIG_H -# include "gcconfig.h" -# endif - typedef GC_word word; typedef GC_signed_word signed_word; @@ -60,6 +62,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ /* Preferably identical to caddr_t, if it */ /* exists. */ +# ifndef GCCONFIG_H +# include "gcconfig.h" +# endif + # ifndef HEADERS_H # include "gc_hdrs.h" # endif @@ -205,6 +211,11 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ /* odd numbered words to have mark bits. */ #endif +#if defined(GC_GCJ_SUPPORT) && ALIGNMENT < 8 && !defined(ALIGN_DOUBLE) + /* 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 @@ -249,20 +260,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ #ifdef SAVE_CALL_CHAIN -/* - * Number of frames and arguments to save in objects allocated by - * debugging allocator. - */ -# 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. */ struct callinfo; @@ -270,14 +267,6 @@ void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES])); void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); -#else - -# ifdef GC_ADD_CALLER -# define NFRAMES 1 -# define NARGS 0 -# define NEED_CALLINFO -# endif - #endif #ifdef NEED_CALLINFO @@ -376,68 +365,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 */ @@ -502,7 +429,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 @@ -515,7 +442,7 @@ struct hblk; /* See below. */ # endif /* Print warning message, e.g. almost out of memory. */ -# define WARN(msg,arg) (*GC_current_warn_proc)(msg, (GC_word)(arg)) +# define WARN(msg,arg) (*GC_current_warn_proc)("GC Warning: " msg, (GC_word)(arg)) extern GC_warn_proc GC_current_warn_proc; /* Get environment entry */ @@ -788,12 +715,11 @@ struct hblkhdr { # define BODY_SZ (HBLKSIZE/sizeof(word)) struct hblk { -# if 0 /* DISCARDWORDS no longer supported */ - word garbage[DISCARD_WORDS]; -# endif word hb_body[BODY_SZ]; }; +# define HBLK_IS_FREE(hdr) ((hdr) -> hb_map == GC_invalid_map) + # define OBJ_SZ_TO_BLOCKS(sz) \ divHBLKSZ(WORDS_TO_BYTES(sz) + HBLKSIZE-1) /* Size of block (in units of HBLKSIZE) needed to hold objects of */ @@ -914,6 +840,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 */ @@ -1084,6 +1014,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 @@ -1218,17 +1149,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; @@ -1240,7 +1173,12 @@ extern word GC_root_size; /* Total size of registered root sections */ extern GC_bool GC_debugging_started; /* GC_debug_malloc has been called. */ - +extern long GC_large_alloc_warn_interval; + /* Interval between unsuppressed warnings. */ + +extern long GC_large_alloc_warn_suppressed; + /* Number of warnings suppressed so far. */ + /* Operations */ # ifndef abs # define abs(x) ((x) < 0? (-(x)) : (x)) @@ -1630,7 +1568,8 @@ GC_bool GC_collect_or_expand GC_PROTO(( \ /* 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. */ + +extern GC_bool GC_is_initialized; /* GC_init() has been run. */ #if defined(MSWIN32) || defined(MSWINCE) void GC_deinit GC_PROTO((void)); @@ -1712,8 +1651,11 @@ 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_heap_obj) GC_PROTO((ptr_t p)); /* If possible print s followed by a more */ /* detailed description of the object */ @@ -1767,8 +1709,12 @@ GC_bool GC_page_was_ever_dirty GC_PROTO((struct hblk *h)); 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_remove_protection GC_PROTO((struct hblk *h, word nblocks, + GC_bool pointerfree)); + /* h is about to be writteni or allocated. Ensure */ + /* that it's not write protected by the virtual */ + /* dirty bit implementation. */ + void GC_dirty_init GC_PROTO((void)); /* Slow/general mark bit manipulation: */ @@ -1915,7 +1861,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. */ @@ -1925,7 +1871,11 @@ void GC_err_puts GC_PROTO((GC_CONST char *s)); # define SIG_SUSPEND SIGPWR # endif # else /* !GC_LINUX_THREADS */ -# define SIG_SUSPEND _SIGRTMIN + 6 +# if defined(_SIGRTMIN) +# define SIG_SUSPEND _SIGRTMIN + 6 +# else +# define SIG_SUSPEND SIGRTMIN + 6 +# endif # endif # endif /* !SIG_SUSPEND */ diff --git a/gc/include/private/gcconfig.h b/gc/include/private/gcconfig.h index 86020fc..b995074 100644 --- a/gc/include/private/gcconfig.h +++ b/gc/include/private/gcconfig.h @@ -38,7 +38,19 @@ # define OPENBSD # endif +/* And one for FreeBSD: */ +# if defined(__FreeBSD__) +# define FREEBSD +# endif + /* Determine the machine type: */ +# if defined(__XSCALE__) +# define ARM32 +# if !defined(LINUX) +# define NOSYS +# define mach_type_known +# endif +# endif # if defined(sun) && defined(mc68000) # define M68K # define SUNOS4 @@ -100,6 +112,13 @@ # endif # 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 @@ -185,6 +204,10 @@ # define IA64 # define mach_type_known # endif +# if defined(LINUX) && defined(__arm__) +# define ARM32 +# define mach_type_known +# endif # if defined(LINUX) && (defined(powerpc) || defined(__powerpc__)) # define POWERPC # define mach_type_known @@ -207,7 +230,7 @@ # endif # if defined(__alpha) || defined(__alpha__) # define ALPHA -# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) +# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) && !defined(FREEBSD) # define OSF1 /* a.k.a Digital Unix */ # endif # define mach_type_known @@ -224,7 +247,7 @@ # 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 @@ -255,9 +278,8 @@ # define OPENBSD # define mach_type_known # endif -# if defined(__FreeBSD__) && (defined(i386) || defined(__i386__)) +# if defined(FREEBSD) && (defined(i386) || defined(__i386__)) # define I386 -# define FREEBSD # define mach_type_known # endif # if defined(__NetBSD__) && (defined(i386) || defined(__i386__)) @@ -279,7 +301,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 @@ -436,10 +458,17 @@ * 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. + * DATAEND, if not `end' where `end' is defined as ``extern int end[];''. + * RTH suggests gaining access to linker script synth'd values with + * this idiom instead of `&end' where `end' is defined as ``extern int end;'' . * * ALIGN_DOUBLE of GC_malloc should return blocks aligned to twice * the pointer size. @@ -451,8 +480,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 @@ -517,6 +551,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() @@ -535,14 +572,14 @@ # ifdef OPENBSD # define OS_TYPE "OPENBSD" # define HEURISTIC2 - extern char etext; -# define DATASTART ((ptr_t)(&etext)) + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # endif # ifdef NETBSD # define OS_TYPE "NETBSD" # define HEURISTIC2 - extern char etext; -# define DATASTART ((ptr_t)(&etext)) + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # endif # ifdef LINUX # define OS_TYPE "LINUX" @@ -565,24 +602,24 @@ /* contain large read-only data tables */ /* that we'd rather not scan. */ # endif /* !GLIBC2 */ - extern int _end; -# define DATAEND (&_end) + extern int _end[]; +# define DATAEND (_end) # else - extern int etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # endif # endif # ifdef SUNOS4 # define OS_TYPE "SUNOS4" - extern char etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ffff) & ~0x1ffff)) + extern char etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0x1ffff) & ~0x1ffff)) # define HEURISTIC1 /* differs */ # define DYNAMIC_LOADING # endif # ifdef HP # define OS_TYPE "HP" - extern char etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) + extern char etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # define STACKBOTTOM ((ptr_t) 0xffeffffc) /* empirically determined. seems to work. */ # include <unistd.h> @@ -590,13 +627,13 @@ # endif # ifdef SYSV # define OS_TYPE "SYSV" - extern etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ + extern etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \ & ~0x3fffff) \ - +((word)&etext & 0x1fff)) + +((word)etext & 0x1fff)) /* This only works for shared-text binaries with magic number 0413. The other sorts of SysV binaries put the data at the end of the text, - in which case the default of &etext would work. Unfortunately, + in which case the default of etext would work. Unfortunately, handling both would require having the magic-number available. -- Parag */ @@ -656,8 +693,8 @@ # define STACK_GRAN 0x10000000 /* Stack usually starts at 0x80000000 */ # define LINUX_DATA_START - extern int _end; -# define DATAEND (&_end) + extern int _end[]; +# define DATAEND (_end) # endif # ifdef MACOSX /* There are reasons to suspect this may not be reliable. */ @@ -674,16 +711,16 @@ # define ALIGNMENT 4 # define OS_TYPE "NETBSD" # define HEURISTIC2 - extern char etext; + extern char etext[]; # define DATASTART GC_data_start # define DYNAMIC_LOADING # endif # ifdef NOSYS # define ALIGNMENT 4 # define OS_TYPE "NOSYS" - extern void __end, __dso_handle; -# define DATASTART (&__dso_handle) /* OK, that's ugly. */ -# define DATAEND (&__end) + extern void __end[], __dso_handle[]; +# define DATASTART (__dso_handle) /* OK, that's ugly. */ +# define DATAEND (__end) /* Stack starts at 0xE0000000 for the simulator. */ # undef STACK_GRAN # define STACK_GRAN 0x10000000 @@ -694,8 +731,8 @@ # ifdef VAX # define MACH_TYPE "VAX" # define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */ - extern char etext; -# define DATASTART ((ptr_t)(&etext)) + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # ifdef BSD # define OS_TYPE "BSD" # define HEURISTIC1 @@ -718,17 +755,20 @@ # define MACH_TYPE "SPARC" # if defined(__arch64__) || defined(__sparcv9) # define ALIGNMENT 8 +# define CPP_WORDSZ 64 +# define ELF_CLASS ELFCLASS64 # else # define ALIGNMENT 4 /* Required by hardware */ +# define CPP_WORDSZ 32 # endif # define ALIGN_DOUBLE # ifdef SUNOS5 # define OS_TYPE "SUNOS5" - extern int _etext; - extern int _end; + extern int _etext[]; + extern int _end[]; extern char * GC_SysVGetDataStart(); -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &_etext) -# define DATAEND (&_end) +# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext) +# define DATAEND (_end) # if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) # define USE_MMAP /* Otherwise we now use calloc. Mmap may result in the */ @@ -764,9 +804,9 @@ # define OS_TYPE "SUNOS4" /* [If you have a weak stomach, don't read this.] */ /* We would like to use: */ -/* # define DATASTART ((ptr_t)((((word) (&etext)) + 0x1fff) & ~0x1fff)) */ +/* # define DATASTART ((ptr_t)((((word) (etext)) + 0x1fff) & ~0x1fff)) */ /* This fails occasionally, due to an ancient, but very */ - /* persistent ld bug. &etext is set 32 bytes too high. */ + /* persistent ld bug. etext is set 32 bytes too high. */ /* We instead read the text segment size from the a.out */ /* header, which happens to be mapped into our address space */ /* at the start of the text segment. The detective work here */ @@ -780,11 +820,10 @@ # define DYNAMIC_LOADING # endif # ifdef DRSNX -# define CPP_WORDSZ 32 # define OS_TYPE "DRSNX" extern char * GC_SysVGetDataStart(); - extern int etext; -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext) + extern int etext[]; +# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext) # define MPROTECT_VDB # define STACKBOTTOM ((ptr_t) 0xdfff0000) # define DYNAMIC_LOADING @@ -796,24 +835,24 @@ # else Linux Sparc/a.out not supported # endif - extern int _end; - extern int _etext; -# define DATAEND (&_end) + extern int _end[]; + extern int _etext[]; +# define DATAEND (_end) # define SVR4 # ifdef __arch64__ +# define DATASTART (ptr_t)GC_SysVGetDataStart(0x100000, _etext) + /* libc_stack_end is not set reliably for sparc64 */ # define STACKBOTTOM ((ptr_t) 0x80000000000ULL) -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x100000, &_etext) -# define CPP_WORDSZ 64 # else -# define STACKBOTTOM ((ptr_t) 0xf0000000) -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &_etext) +# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext) +# define LINUX_STACKBOTTOM # endif # endif # ifdef OPENBSD # define OS_TYPE "OPENBSD" # define STACKBOTTOM ((ptr_t) 0xf8000000) - extern int etext; -# define DATASTART ((ptr_t)(&etext)) + extern int etext[]; +# define DATASTART ((ptr_t)(etext)) # endif # ifdef NETBSD # define OS_TYPE "NETBSD" @@ -822,8 +861,8 @@ # define DATASTART GC_data_start # define DYNAMIC_LOADING # else - extern char etext; -# define DATASTART ((ptr_t)(&etext)) + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # endif # endif # endif @@ -843,24 +882,24 @@ # endif # ifdef SEQUENT # define OS_TYPE "SEQUENT" - extern int etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # define STACKBOTTOM ((ptr_t) 0x3ffff000) # endif # ifdef BEOS # define OS_TYPE "BEOS" # include <OS.h> # define GETPAGESIZE() B_PAGE_SIZE - extern int etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # endif # ifdef SUNOS5 # define OS_TYPE "SUNOS5" - extern int _etext, _end; + extern int _etext[], _end[]; extern char * GC_SysVGetDataStart(); -# define DATASTART GC_SysVGetDataStart(0x1000, &_etext) -# define DATAEND (&_end) -/* # define STACKBOTTOM ((ptr_t)(&_start)) worked through 2.7, */ +# define DATASTART GC_SysVGetDataStart(0x1000, _etext) +# define DATAEND (_end) +/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */ /* but reportedly breaks under 2.8. It appears that the stack */ /* base is a property of the executable, so this should not break */ /* old executables. */ @@ -888,21 +927,47 @@ # endif # ifdef SCO # define OS_TYPE "SCO" - extern int etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \ + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \ & ~0x3fffff) \ - +((word)&etext & 0xfff)) + +((word)etext & 0xfff)) # define STACKBOTTOM ((ptr_t) 0x7ffffffc) # endif # ifdef SCO_ELF # define OS_TYPE "SCO_ELF" - extern int etext; -# define DATASTART ((ptr_t)(&etext)) + extern int etext[]; +# define DATASTART ((ptr_t)(etext)) # define STACKBOTTOM ((ptr_t) 0x08048000) # define DYNAMIC_LOADING # define ELF_CLASS ELFCLASS32 # endif +# ifdef DGUX +# define OS_TYPE "DGUX" + extern int _etext, _end; + extern char * 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 */ +# define USE_GENERIC_PUSH_REGS +# endif # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM # if 0 @@ -921,11 +986,14 @@ /* 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 */ - extern int _etext; -# define DATASTART ((ptr_t)((((word) (&_etext)) + 0xfff) & ~0xfff)) + extern int _etext[]; +# define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff)) # endif # include <features.h> # if defined(__GLIBC__) && __GLIBC__ >= 2 @@ -942,11 +1010,11 @@ /* contain large read-only data tables */ /* that we'd rather not scan. */ # endif - extern int _end; -# define DATAEND (&_end) + extern int _end[]; +# define DATAEND (_end) # else - extern int etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # endif # ifdef USE_I686_PREFETCH # define PREFETCH(x) \ @@ -971,10 +1039,10 @@ # endif # ifdef CYGWIN32 # define OS_TYPE "CYGWIN32" - extern int _data_start__; - extern int _data_end__; - extern int _bss_start__; - extern int _bss_end__; + extern int _data_start__[]; + extern int _data_end__[]; + extern int _bss_start__[]; + extern int _bss_end__[]; /* For binutils 2.9.1, we have */ /* DATASTART = _data_start__ */ /* DATAEND = _bss_end__ */ @@ -985,8 +1053,8 @@ /* minumum/maximum of the two. */ # define MAX(x,y) ((x) > (y) ? (x) : (y)) # define MIN(x,y) ((x) < (y) ? (x) : (y)) -# define DATASTART ((ptr_t) MIN(&_data_start__, &_bss_start__)) -# define DATAEND ((ptr_t) MAX(&_data_end__, &_bss_end__)) +# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__)) +# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__)) # undef STACK_GRAN # define STACK_GRAN 0x10000 # define HEURISTIC1 @@ -1015,10 +1083,10 @@ # ifdef DJGPP # define OS_TYPE "DJGPP" # include "stubinfo.h" - extern int etext; + extern int etext[]; extern int _stklen; extern int __djgpp_stack_limit; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ff) & ~0x1ff)) +# define DATASTART ((ptr_t)((((word) (etext)) + 0x1ff) & ~0x1ff)) /* # define STACKBOTTOM ((ptr_t)((word) _stubinfo + _stubinfo->size \ + _stklen)) */ # define STACKBOTTOM ((ptr_t)((word) __djgpp_stack_limit + _stklen)) @@ -1038,11 +1106,14 @@ # ifdef __ELF__ # define DYNAMIC_LOADING # endif - extern char etext; -# define DATASTART ((ptr_t)(&etext)) + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # endif # ifdef NETBSD # define OS_TYPE "NETBSD" +# ifdef __ELF__ +# define DYNAMIC_LOADING +# endif # endif # ifdef THREE86BSD # define OS_TYPE "THREE86BSD" @@ -1053,8 +1124,8 @@ # if defined(OPENBSD) || defined(NETBSD) \ || defined(THREE86BSD) || defined(BSDI) # define HEURISTIC2 - extern char etext; -# define DATASTART ((ptr_t)(&etext)) + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # endif # ifdef NEXT # define OS_TYPE "NEXT" @@ -1081,10 +1152,10 @@ # define OS_TYPE "HURD" # define STACK_GROWS_DOWN # define HEURISTIC2 - extern int __data_start; -# define DATASTART ( (ptr_t) (&__data_start)) - extern int _end; -# define DATAEND ( (ptr_t) (&_end)) + extern int __data_start[]; +# define DATASTART ( (ptr_t) (__data_start)) + extern int _end[]; +# define DATAEND ( (ptr_t) (_end)) /* # define MPROTECT_VDB Not quite working yet? */ # define DYNAMIC_LOADING # endif @@ -1108,15 +1179,14 @@ /* This was developed for a linuxce style platform. Probably */ /* needs to be tweaked for workstation class machines. */ # define OS_TYPE "LINUX" - extern int __data_start; -# define DATASTART ((ptr_t)(&__data_start)) +# define DYNAMIC_LOADING + extern int _end[]; +# define DATAEND (_end) + extern int __data_start[]; +# define DATASTART ((ptr_t)(__data_start)) # define ALIGNMENT 4 # define USE_GENERIC_PUSH_REGS -# define STACKBOTTOM ((ptr_t)0x7fff8000) - /* Older toolchains may need 0x80000000. */ - /* In many cases, this should probably use LINUX_STACKBOTTOM */ - /* instead. But some kernel versions seem to give the wrong */ - /* value from /proc. */ +# define LINUX_STACKBOTTOM # endif /* Linux */ # ifdef EWS4800 # define HEURISTIC2 @@ -1127,15 +1197,15 @@ # define CPP_WORDSZ _MIPS_SZPTR # define ALIGNMENT (_MIPS_SZPTR/8) # else - extern int etext, edata, end; - extern int _DYNAMIC_LINKING, _gp; -# define DATASTART ((ptr_t)((((word)&etext + 0x3ffff) & ~0x3ffff) \ - + ((word)&etext & 0xffff))) -# define DATAEND (&edata) -# define DATASTART2 (&_DYNAMIC_LINKING \ - ? (ptr_t)(((word)&_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \ - : (ptr_t)&edata) -# define DATAEND2 (&end) + extern int etext[], edata[], end[]; + extern int _DYNAMIC_LINKING[], _gp[]; +# define DATASTART ((ptr_t)((((word)etext + 0x3ffff) & ~0x3ffff) \ + + ((word)etext & 0xffff))) +# define DATAEND (edata) +# define DATASTART2 (_DYNAMIC_LINKING \ + ? (ptr_t)(((word)_gp + 0x8000 + 0x3ffff) & ~0x3ffff) \ + : (ptr_t)edata) +# define DATAEND2 (end) # define ALIGNMENT 4 # endif # define OS_TYPE "EWS4800" @@ -1157,8 +1227,8 @@ # endif # ifdef IRIX5 # define HEURISTIC2 - extern int _fdata; -# define DATASTART ((ptr_t)(&_fdata)) + extern int _fdata[]; +# define DATASTART ((ptr_t)(_fdata)) # ifdef USE_MMAP # define HEAP_START (ptr_t)0x30000000 # else @@ -1196,7 +1266,7 @@ # define HEURISTIC2 # define USE_GENERIC_PUSH_REGS # ifdef __ELF__ - extern int etext; + extern int etext[]; # define DATASTART GC_data_start # define NEED_FIND_LIMIT # define DYNAMIC_LOADING @@ -1209,10 +1279,20 @@ # ifdef RS6000 # define MACH_TYPE "RS6000" -# define ALIGNMENT 4 -# define DATASTART ((ptr_t)0x20000000) +# ifdef __64BIT__ +# define ALIGNMENT 8 +# define CPP_WORDSZ 64 +# define STACKBOTTOM 0x1000000000000000 +# else +# define ALIGNMENT 4 +# define CPP_WORDSZ 32 +# define STACKBOTTOM ((ptr_t)((ulong)&errno)) +# endif + 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. */ # endif @@ -1243,8 +1323,8 @@ # define STACK_GROWS_UP # ifdef HPUX # define OS_TYPE "HPUX" - extern int __data_start; -# define DATASTART ((ptr_t)(&__data_start)) + extern int __data_start[]; +# define DATASTART ((ptr_t)(__data_start)) # if 0 /* The following appears to work for 7xx systems running HP/UX */ /* 9.xx Furthermore, it might result in much faster */ @@ -1275,8 +1355,8 @@ # define OS_TYPE "LINUX" # define LINUX_STACKBOTTOM # define DYNAMIC_LOADING -# define LINUX_DATA_START - extern int _end; +# define SEARCH_FOR_DATA_START + extern int _end[]; # define DATAEND (&_end) # endif /* LINUX */ # endif /* HP_PA */ @@ -1284,11 +1364,13 @@ # ifdef ALPHA # define MACH_TYPE "ALPHA" # define ALIGNMENT 8 -# 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. */ +# 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 @@ -1312,10 +1394,30 @@ # define DATASTART ((ptr_t) 0x140000000) # endif # endif +# ifdef FREEBSD +# define OS_TYPE "FREEBSD" +/* MPROTECT_VDB is not yet supported at all on FreeBSD/alpha. */ +# define SIG_SUSPEND SIGUSR1 +# define SIG_THR_RESTART SIGUSR2 +# define FREEBSD_STACKBOTTOM +# ifdef __ELF__ +# define DYNAMIC_LOADING +# endif +/* Handle unmapped hole alpha*-*-freebsd[45]* puts between etext and edata. */ + extern char etext[]; + extern char edata[]; + extern char end[]; +# define NEED_FIND_LIMIT +# 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 +# endif # ifdef OSF1 # define OS_TYPE "OSF1" # define DATASTART ((ptr_t) 0x140000000) - extern int _end; + extern int _end[]; # define DATAEND ((ptr_t) &_end) extern char ** environ; /* round up from the value of environ to the nearest page boundary */ @@ -1327,8 +1429,8 @@ /* the text segment immediately follows the stack. */ /* Hence we give an upper pound. */ /* This is currently unused, since we disabled HEURISTIC2 */ - extern int __start; -# define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1))) + extern int __start[]; +# define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1))) # define CPP_WORDSZ 64 # define MPROTECT_VDB # define DYNAMIC_LOADING @@ -1339,13 +1441,12 @@ # 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) # endif - extern int _end; -# define DATAEND (&_end) + extern int _end[]; +# define DATAEND (_end) # define MPROTECT_VDB /* Has only been superficially tested. May not */ /* work on all versions. */ @@ -1378,8 +1479,8 @@ # define ALIGNMENT 8 # endif # define OS_TYPE "HPUX" - extern int __data_start; -# define DATASTART ((ptr_t)(&__data_start)) + extern int __data_start[]; +# define DATASTART ((ptr_t)(__data_start)) /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */ /* to this. Note that the GC must be initialized before the */ /* first putenv call. */ @@ -1417,7 +1518,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 @@ -1427,8 +1527,8 @@ # endif # define MPROTECT_VDB /* Requires Linux 2.3.47 or later. */ - extern int _end; -# define DATAEND (&_end) + extern int _end[]; +# define DATAEND (_end) # ifdef __GNUC__ # define PREFETCH(x) \ __asm__ (" lfetch [%0]": : "r"((void *)(x))) @@ -1444,15 +1544,15 @@ # define MACH_TYPE "M88K" # define ALIGNMENT 4 # define ALIGN_DOUBLE - extern int etext; + extern int etext[]; # ifdef CX_UX # define OS_TYPE "CX_UX" -# define DATASTART ((((word)&etext + 0x3fffff) & ~0x3fffff) + 0x10000) +# define DATASTART ((((word)etext + 0x3fffff) & ~0x3fffff) + 0x10000) # endif # ifdef DGUX # define OS_TYPE "DGUX" extern char * GC_SysVGetDataStart(); -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext) +# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext) # endif # define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */ # endif @@ -1463,27 +1563,27 @@ # define USE_GENERIC_PUSH_REGS # ifdef UTS4 # define OS_TYPE "UTS4" - extern int etext; - extern int _etext; - extern int _end; + extern int etext[]; + extern int _etext[]; + extern int _end[]; extern char * GC_SysVGetDataStart(); -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &_etext) -# define DATAEND (&_end) +# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext) +# define DATAEND (_end) # define HEURISTIC2 # endif # ifdef LINUX # define OS_TYPE "LINUX" # define HEURISTIC1 # define DYNAMIC_LOADING - extern int __data_start; -# define DATASTART ((ptr_t)(&__data_start)) + extern int __data_start[]; +# define DATASTART ((ptr_t)(__data_start)) # endif # endif # if defined(PJ) # define ALIGNMENT 4 - extern int _etext; -# define DATASTART ((ptr_t)(&_etext)) + extern int _etext[]; +# define DATASTART ((ptr_t)(_etext)) # define HEURISTIC1 # endif @@ -1494,8 +1594,8 @@ # ifdef NETBSD # define OS_TYPE "NETBSD" # define HEURISTIC2 - extern char etext; -# define DATASTART ((ptr_t)(&etext)) + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) # define USE_GENERIC_PUSH_REGS # endif # ifdef LINUX @@ -1521,17 +1621,26 @@ /* contain large read-only data tables */ /* that we'd rather not scan. */ # endif - extern int _end; -# define DATAEND (&_end) + extern int _end[]; +# define DATAEND (_end) # else - extern int etext; -# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff)) + extern int etext[]; +# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # endif # endif # ifdef MSWINCE # define OS_TYPE "MSWINCE" # define DATAEND /* not needed */ # endif +# ifdef NOSYS + /* __data_start is usually defined in the target linker script. */ + extern int __data_start[]; +# define DATASTART (ptr_t)(__data_start) +# define USE_GENERIC_PUSH_REGS + /* __stack_base__ is set in newlib/libc/sys/arm/crt0.S */ + extern void *__stack_base__; +# define STACKBOTTOM ((ptr_t) (__stack_base__)) +# endif #endif # ifdef SH @@ -1547,8 +1656,8 @@ # define USE_GENERIC_PUSH_REGS # define DYNAMIC_LOADING # define LINUX_DATA_START - extern int _end; -# define DATAEND (&_end) + extern int _end[]; +# define DATAEND (_end) # endif # endif @@ -1566,10 +1675,10 @@ /* case we lose. Nonetheless, we try both, prefering __data_start. */ /* We assume gcc. */ # pragma weak __data_start - extern int __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)) + extern int data_start[]; +# define DATASTART ((ptr_t)(__data_start != 0? __data_start : data_start)) #endif #if defined(LINUX) && defined(REDIRECT_MALLOC) @@ -1593,8 +1702,8 @@ # endif # ifndef DATAEND - extern int end; -# define DATAEND (&end) + extern int end[]; +# define DATAEND (end) # endif # if defined(SVR4) && !defined(GETPAGESIZE) @@ -1610,15 +1719,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 @@ -1627,13 +1736,13 @@ # 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(MACOSX) || 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 @@ -1647,13 +1756,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 @@ -1684,65 +1793,190 @@ # define CACHE_LINE_SIZE 32 /* Wild guess */ # endif +# 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_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 + /* 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 # 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__)) - /* Use setjmp based hack to mark from callee-save registers. */ - /* The define should move to the individual platform */ - /* descriptions. */ + || 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. */ # define USE_GENERIC_PUSH_REGS # endif -# if defined(I386) && 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. */ -# ifdef SAVE_CALL_COUNT + +# if defined(SPARC) +# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */ + /* 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 + +#if defined(SPARC) +# define CAN_SAVE_CALL_STACKS +# define CAN_SAVE_CALL_ARGS +#endif +#if defined(I386) && 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 +# 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) # define SAVE_CALL_CHAIN # endif +# ifdef SAVE_CALL_CHAIN +# if defined(SAVE_CALL_NARGS) && defined(CAN_SAVE_CALL_ARGS) +# define NARGS SAVE_CALL_NARGS +# else +# define NARGS 0 /* Number of arguments to save for each call. */ +# endif # endif -# if defined(SPARC) -# define SAVE_CALL_CHAIN -# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */ - /* include assembly code to do it well. */ +# ifdef SAVE_CALL_CHAIN +# 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 NEED_CALLINFO +# endif /* SAVE_CALL_CHAIN */ +# ifdef GC_ADD_CALLER +# define NFRAMES 1 +# define NARGS 0 +# define NEED_CALLINFO # endif # if defined(MAKE_BACK_GRAPH) && !defined(DBG_HDRS_ALL) # define DBG_HDRS_ALL # 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(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 + +#endif /* GC_PRIVATE_H */ + # endif /* GCCONFIG_H */ diff --git a/gc/include/private/solaris_threads.h b/gc/include/private/solaris_threads.h index 1464bc1..7d49c29 100644 --- a/gc/include/private/solaris_threads.h +++ b/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/gc/include/private/specific.h b/gc/include/private/specific.h index 60c152c..399f84f 100644 --- a/gc/include/private/specific.h +++ b/gc/include/private/specific.h @@ -27,16 +27,22 @@ #define TS_HASH_SIZE 1024 #define HASH(n) (((((long)n) >> 8) ^ (long)n) & (TS_HASH_SIZE - 1)) +/* An entry describing a thread-specific value for a given thread. */ +/* All such accessible structures preserve the invariant that if either */ +/* thread is a valid pthread id or qtid is a valid "quick tread id" */ +/* for a thread, then value holds the corresponding thread specific */ +/* value. This invariant must be preserved at ALL times, since */ +/* asynchronous reads are allowed. */ typedef struct thread_specific_entry { unsigned long qtid; /* quick thread id, only for cache */ void * value; - pthread_t thread; struct thread_specific_entry *next; + pthread_t thread; } tse; /* We represent each thread-specific datum as two tables. The first is */ -/* a cache, index by a "quick thread identifier". The "quick" thread */ +/* a cache, indexed by a "quick thread identifier". The "quick" thread */ /* identifier is an easy to compute value, which is guaranteed to */ /* determine the thread, though a thread may correspond to more than */ /* one value. We typically use the address of a page in the stack. */ @@ -45,12 +51,15 @@ typedef struct thread_specific_entry { /* Return the "quick thread id". Default version. Assumes page size, */ /* or at least thread stack separation, is at least 4K. */ -static __inline__ long quick_thread_id() { +/* Must be defined so that it never returns 0. (Page 0 can't really */ +/* be part of any stack, since that would make 0 a valid stack pointer.)*/ +static __inline__ unsigned long quick_thread_id() { int dummy; - return (long)(&dummy) >> 12; + return (unsigned long)(&dummy) >> 12; } -#define INVALID_QTID ((unsigned long)(-1)) +#define INVALID_QTID ((unsigned long)0) +#define INVALID_THREADID ((pthread_t)0) typedef struct thread_specific_data { tse * volatile cache[TS_CACHE_SIZE]; @@ -76,7 +85,10 @@ 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) return entry -> value; + if (entry -> qtid == qtid) { + GC_ASSERT(entry -> thread == pthread_self()); + return entry -> value; + } return PREFIXED(slow_getspecific) (key, qtid, entry_ptr); } |