diff options
author | Fumitoshi UKAI <ukai@debian.or.jp> | 2003-03-09 19:43:05 +0000 |
---|---|---|
committer | Fumitoshi UKAI <ukai@debian.or.jp> | 2003-03-09 19:43:05 +0000 |
commit | 1dff73dfd6accb9bae971dd0f1ce15a182b0f75b (patch) | |
tree | 90442e8c55bb3e5d8aade44a20152d2d8e297608 /gc/include/private | |
parent | autoconficate (diff) | |
download | w3m-1dff73dfd6accb9bae971dd0f1ce15a182b0f75b.tar.gz w3m-1dff73dfd6accb9bae971dd0f1ce15a182b0f75b.zip |
remove gc
Diffstat (limited to 'gc/include/private')
-rw-r--r-- | gc/include/private/cord_pos.h | 118 | ||||
-rw-r--r-- | gc/include/private/dbg_mlc.h | 176 | ||||
-rw-r--r-- | gc/include/private/gc_hdrs.h | 233 | ||||
-rw-r--r-- | gc/include/private/gc_locks.h | 496 | ||||
-rw-r--r-- | gc/include/private/gc_pmark.h | 379 | ||||
-rw-r--r-- | gc/include/private/gc_priv.h | 1884 | ||||
-rw-r--r-- | gc/include/private/gcconfig.h | 1986 | ||||
-rw-r--r-- | gc/include/private/solaris_threads.h | 35 | ||||
-rw-r--r-- | gc/include/private/specific.h | 95 |
9 files changed, 0 insertions, 5402 deletions
diff --git a/gc/include/private/cord_pos.h b/gc/include/private/cord_pos.h deleted file mode 100644 index d2b24bb..0000000 --- a/gc/include/private/cord_pos.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved. - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - */ -/* Boehm, May 19, 1994 2:23 pm PDT */ -# ifndef CORD_POSITION_H - -/* The representation of CORD_position. This is private to the */ -/* implementation, but the size is known to clients. Also */ -/* the implementation of some exported macros relies on it. */ -/* Don't use anything defined here and not in cord.h. */ - -# define MAX_DEPTH 48 - /* The maximum depth of a balanced cord + 1. */ - /* We don't let cords get deeper than MAX_DEPTH. */ - -struct CORD_pe { - CORD pe_cord; - size_t pe_start_pos; -}; - -/* A structure describing an entry on the path from the root */ -/* to current position. */ -typedef struct CORD_Pos { - size_t cur_pos; - int path_len; -# define CORD_POS_INVALID (0x55555555) - /* path_len == INVALID <==> position invalid */ - const char *cur_leaf; /* Current leaf, if it is a string. */ - /* If the current leaf is a function, */ - /* then this may point to function_buf */ - /* containing the next few characters. */ - /* Always points to a valid string */ - /* containing the current character */ - /* unless cur_end is 0. */ - size_t cur_start; /* Start position of cur_leaf */ - size_t cur_end; /* Ending position of cur_leaf */ - /* 0 if cur_leaf is invalid. */ - struct CORD_pe path[MAX_DEPTH + 1]; - /* path[path_len] is the leaf corresponding to cur_pos */ - /* path[0].pe_cord is the cord we point to. */ -# define FUNCTION_BUF_SZ 8 - char function_buf[FUNCTION_BUF_SZ]; /* Space for next few chars */ - /* from function node. */ -} CORD_pos[1]; - -/* Extract the cord from a position: */ -CORD CORD_pos_to_cord(CORD_pos p); - -/* Extract the current index from a position: */ -size_t CORD_pos_to_index(CORD_pos p); - -/* Fetch the character located at the given position: */ -char CORD_pos_fetch(CORD_pos p); - -/* Initialize the position to refer to the give cord and index. */ -/* Note that this is the most expensive function on positions: */ -void CORD_set_pos(CORD_pos p, CORD x, size_t i); - -/* Advance the position to the next character. */ -/* P must be initialized and valid. */ -/* Invalidates p if past end: */ -void CORD_next(CORD_pos p); - -/* Move the position to the preceding character. */ -/* P must be initialized and valid. */ -/* Invalidates p if past beginning: */ -void CORD_prev(CORD_pos p); - -/* Is the position valid, i.e. inside the cord? */ -int CORD_pos_valid(CORD_pos p); - -char CORD__pos_fetch(CORD_pos); -void CORD__next(CORD_pos); -void CORD__prev(CORD_pos); - -#define CORD_pos_fetch(p) \ - (((p)[0].cur_end != 0)? \ - (p)[0].cur_leaf[(p)[0].cur_pos - (p)[0].cur_start] \ - : CORD__pos_fetch(p)) - -#define CORD_next(p) \ - (((p)[0].cur_pos + 1 < (p)[0].cur_end)? \ - (p)[0].cur_pos++ \ - : (CORD__next(p), 0)) - -#define CORD_prev(p) \ - (((p)[0].cur_end != 0 && (p)[0].cur_pos > (p)[0].cur_start)? \ - (p)[0].cur_pos-- \ - : (CORD__prev(p), 0)) - -#define CORD_pos_to_index(p) ((p)[0].cur_pos) - -#define CORD_pos_to_cord(p) ((p)[0].path[0].pe_cord) - -#define CORD_pos_valid(p) ((p)[0].path_len != CORD_POS_INVALID) - -/* Some grubby stuff for performance-critical friends: */ -#define CORD_pos_chars_left(p) ((long)((p)[0].cur_end) - (long)((p)[0].cur_pos)) - /* Number of characters in cache. <= 0 ==> none */ - -#define CORD_pos_advance(p,n) ((p)[0].cur_pos += (n) - 1, CORD_next(p)) - /* Advance position by n characters */ - /* 0 < n < CORD_pos_chars_left(p) */ - -#define CORD_pos_cur_char_addr(p) \ - (p)[0].cur_leaf + ((p)[0].cur_pos - (p)[0].cur_start) - /* address of current character in cache. */ - -#endif diff --git a/gc/include/private/dbg_mlc.h b/gc/include/private/dbg_mlc.h deleted file mode 100644 index e2003e6..0000000 --- a/gc/include/private/dbg_mlc.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. - * Copyright (c) 1997 by Silicon Graphics. All rights reserved. - * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - */ - -/* - * This is mostly an internal header file. Typical clients should - * not use it. Clients that define their own object kinds with - * debugging allocators will probably want to include this, however. - * No attempt is made to keep the namespace clean. This should not be - * included from header files that are frequently included by clients. - */ - -#ifndef _DBG_MLC_H - -#define _DBG_MLC_H - -# define I_HIDE_POINTERS -# include "gc_priv.h" -# ifdef KEEP_BACK_PTRS -# include "gc_backptr.h" -# endif - -#ifndef HIDE_POINTER - /* Gc.h was previously included, and hence the I_HIDE_POINTERS */ - /* definition had no effect. Repeat the gc.h definitions here to */ - /* get them anyway. */ - typedef GC_word GC_hidden_pointer; -# define HIDE_POINTER(p) (~(GC_hidden_pointer)(p)) -# define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p))) -#endif /* HIDE_POINTER */ - -# define START_FLAG ((word)0xfedcedcb) -# define END_FLAG ((word)0xbcdecdef) - /* Stored both one past the end of user object, and one before */ - /* the end of the object as seen by the allocator. */ - -# if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) \ - || defined(MAKE_BACK_GRAPH) - /* Pointer "source"s that aren't real locations. */ - /* Used in oh_back_ptr fields and as "source" */ - /* argument to some marking functions. */ -# define NOT_MARKED (ptr_t)(0) -# define MARKED_FOR_FINALIZATION (ptr_t)(2) - /* Object was marked because it is finalizable. */ -# define MARKED_FROM_REGISTER (ptr_t)(4) - /* Object was marked from a rgister. Hence the */ - /* source of the reference doesn't have an address. */ -# endif /* KEEP_BACK_PTRS || PRINT_BLACK_LIST */ - -/* Object header */ -typedef struct { -# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) - /* We potentially keep two different kinds of back */ - /* pointers. KEEP_BACK_PTRS stores a single back */ - /* pointer in each reachable object to allow reporting */ - /* of why an object was retained. MAKE_BACK_GRAPH */ - /* builds a graph containing the inverse of all */ - /* "points-to" edges including those involving */ - /* objects that have just become unreachable. This */ - /* allows detection of growing chains of unreachable */ - /* objects. It may be possible to eventually combine */ - /* both, but for now we keep them separate. Both */ - /* kinds of back pointers are hidden using the */ - /* following macros. In both cases, the plain version */ - /* is constrained to have an least significant bit of 1,*/ - /* to allow it to be distinguished from a free list */ - /* link. This means the plain version must have an */ - /* lsb of 0. */ - /* Note that blocks dropped by black-listing will */ - /* also have the lsb clear once debugging has */ - /* started. */ - /* We're careful never to overwrite a value with lsb 0. */ -# if ALIGNMENT == 1 - /* Fudge back pointer to be even. */ -# define HIDE_BACK_PTR(p) HIDE_POINTER(~1 & (GC_word)(p)) -# else -# define HIDE_BACK_PTR(p) HIDE_POINTER(p) -# endif - -# ifdef KEEP_BACK_PTRS - GC_hidden_pointer oh_back_ptr; -# endif -# ifdef MAKE_BACK_GRAPH - GC_hidden_pointer oh_bg_ptr; -# endif -# if defined(ALIGN_DOUBLE) && \ - (defined(KEEP_BACK_PTRS) != defined(MAKE_BACK_GRAPH)) - word oh_dummy; -# endif -# endif - GC_CONST char * oh_string; /* object descriptor string */ - word oh_int; /* object descriptor integers */ -# ifdef NEED_CALLINFO - struct callinfo oh_ci[NFRAMES]; -# endif -# ifndef SHORT_DBG_HDRS - word oh_sz; /* Original malloc arg. */ - word oh_sf; /* start flag */ -# endif /* SHORT_DBG_HDRS */ -} oh; -/* The size of the above structure is assumed not to dealign things, */ -/* and to be a multiple of the word length. */ - -#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. */ - /* 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) -#else -# ifdef GC_ADD_CALLER -# define ADD_CALL_CHAIN(base, ra) ((oh *)(base)) -> oh_ci[0].ci_pc = (ra) -# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci) -# else -# define ADD_CALL_CHAIN(base, ra) -# define PRINT_CALL_CHAIN(base) -# endif -#endif - -# ifdef GC_ADD_CALLER -# define OPT_RA ra, -# else -# define OPT_RA -# endif - - -/* Check whether object with base pointer p has debugging info */ -/* p is assumed to point to a legitimate object in our part */ -/* of the heap. */ -#ifdef SHORT_DBG_HDRS -# define GC_has_other_debug_info(p) TRUE -#else - GC_bool GC_has_other_debug_info(/* p */); -#endif - -#if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH) -# define GC_HAS_DEBUG_INFO(p) \ - ((*((word *)p) & 1) && GC_has_other_debug_info(p)) -#else -# define GC_HAS_DEBUG_INFO(p) GC_has_other_debug_info(p) -#endif - -/* Store debugging info into p. Return displaced pointer. */ -/* Assumes we don't hold allocation lock. */ -ptr_t GC_store_debug_info(/* p, sz, string, integer */); - -#endif /* _DBG_MLC_H */ diff --git a/gc/include/private/gc_hdrs.h b/gc/include/private/gc_hdrs.h deleted file mode 100644 index 96749ab..0000000 --- a/gc/include/private/gc_hdrs.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - */ -/* Boehm, July 11, 1995 11:54 am PDT */ -# ifndef GC_HEADERS_H -# define GC_HEADERS_H -typedef struct hblkhdr hdr; - -# if CPP_WORDSZ != 32 && CPP_WORDSZ < 36 - --> Get a real machine. -# endif - -/* - * The 2 level tree data structure that is used to find block headers. - * If there are more than 32 bits in a pointer, the top level is a hash - * table. - * - * This defines HDR, GET_HDR, and SET_HDR, the main macros used to - * retrieve and set object headers. - * - * Since 5.0 alpha 5, we can also take advantage of a header lookup - * cache. This is a locally declared direct mapped cache, used inside - * the marker. The HC_GET_HDR macro uses and maintains this - * cache. Assuming we get reasonable hit rates, this shaves a few - * memory references from each pointer validation. - */ - -# if CPP_WORDSZ > 32 -# define HASH_TL -# endif - -/* Define appropriate out-degrees for each of the two tree levels */ -# ifdef SMALL_CONFIG -# define LOG_BOTTOM_SZ 11 - /* Keep top index size reasonable with smaller blocks. */ -# else -# define LOG_BOTTOM_SZ 10 -# endif -# ifndef HASH_TL -# define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE) -# else -# define LOG_TOP_SZ 11 -# endif -# define TOP_SZ (1 << LOG_TOP_SZ) -# define BOTTOM_SZ (1 << LOG_BOTTOM_SZ) - -#ifndef SMALL_CONFIG -# define USE_HDR_CACHE -#endif - -/* #define COUNT_HDR_CACHE_HITS */ - -extern hdr * GC_invalid_header; /* header for an imaginary block */ - /* containing no objects. */ - - -/* Check whether p and corresponding hhdr point to long or invalid */ -/* object. If so, advance hhdr to */ -/* beginning of block, or set hhdr to GC_invalid_header. */ -#define ADVANCE(p, hhdr, source) \ - { \ - hdr * new_hdr = GC_invalid_header; \ - p = GC_find_start(p, hhdr, &new_hdr); \ - hhdr = new_hdr; \ - } - -#ifdef USE_HDR_CACHE - -# ifdef COUNT_HDR_CACHE_HITS - extern word GC_hdr_cache_hits; - extern word GC_hdr_cache_misses; -# define HC_HIT() ++GC_hdr_cache_hits -# define HC_MISS() ++GC_hdr_cache_misses -# else -# define HC_HIT() -# define HC_MISS() -# endif - - typedef struct hce { - word block_addr; /* right shifted by LOG_HBLKSIZE */ - hdr * hce_hdr; - } hdr_cache_entry; - -# define HDR_CACHE_SIZE 8 /* power of 2 */ - -# define DECLARE_HDR_CACHE \ - hdr_cache_entry hdr_cache[HDR_CACHE_SIZE] - -# define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache)); - -# define HCE(h) hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1)) - -# define HCE_VALID_FOR(hce,h) ((hce) -> block_addr == \ - ((word)(h) >> LOG_HBLKSIZE)) - -# define HCE_HDR(h) ((hce) -> hce_hdr) - - -/* Analogous to GET_HDR, except that in the case of large objects, it */ -/* Returns the header for the object beginning, and updates p. */ -/* Returns &GC_bad_header instead of 0. All of this saves a branch */ -/* in the fast path. */ -# define HC_GET_HDR(p, hhdr, source) \ - { \ - hdr_cache_entry * hce = HCE(p); \ - if (HCE_VALID_FOR(hce, p)) { \ - HC_HIT(); \ - hhdr = hce -> hce_hdr; \ - } else { \ - HC_MISS(); \ - GET_HDR(p, hhdr); \ - if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \ - ADVANCE(p, hhdr, source); \ - } else { \ - hce -> block_addr = (word)(p) >> LOG_HBLKSIZE; \ - hce -> hce_hdr = hhdr; \ - } \ - } \ - } - -#else /* !USE_HDR_CACHE */ - -# define DECLARE_HDR_CACHE - -# define INIT_HDR_CACHE - -# define HC_GET_HDR(p, hhdr, source) \ - { \ - GET_HDR(p, hhdr); \ - if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \ - ADVANCE(p, hhdr, source); \ - } \ - } -#endif - -typedef struct bi { - hdr * index[BOTTOM_SZ]; - /* - * The bottom level index contains one of three kinds of values: - * 0 means we're not responsible for this block, - * or this is a block other than the first one in a free block. - * 1 < (long)X <= MAX_JUMP means the block starts at least - * X * HBLKSIZE bytes before the current address. - * A valid pointer points to a hdr structure. (The above can't be - * valid pointers due to the GET_MEM return convention.) - */ - struct bi * asc_link; /* All indices are linked in */ - /* ascending order... */ - struct bi * desc_link; /* ... and in descending order. */ - word key; /* high order address bits. */ -# ifdef HASH_TL - struct bi * hash_link; /* Hash chain link. */ -# endif -} bottom_index; - -/* extern bottom_index GC_all_nils; - really part of GC_arrays */ - -/* extern bottom_index * GC_top_index []; - really part of GC_arrays */ - /* Each entry points to a bottom_index. */ - /* On a 32 bit machine, it points to */ - /* the index for a set of high order */ - /* bits equal to the index. For longer */ - /* addresses, we hash the high order */ - /* bits to compute the index in */ - /* GC_top_index, and each entry points */ - /* to a hash chain. */ - /* The last entry in each chain is */ - /* GC_all_nils. */ - - -# define MAX_JUMP (HBLKSIZE - 1) - -# define HDR_FROM_BI(bi, p) \ - ((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)]) -# ifndef HASH_TL -# define BI(p) (GC_top_index \ - [(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)]) -# define HDR_INNER(p) HDR_FROM_BI(BI(p),p) -# ifdef SMALL_CONFIG -# define HDR(p) GC_find_header((ptr_t)(p)) -# else -# define HDR(p) HDR_INNER(p) -# endif -# define GET_BI(p, bottom_indx) (bottom_indx) = BI(p) -# define GET_HDR(p, hhdr) (hhdr) = HDR(p) -# define SET_HDR(p, hhdr) HDR_INNER(p) = (hhdr) -# define GET_HDR_ADDR(p, ha) (ha) = &(HDR_INNER(p)) -# else /* hash */ -/* Hash function for tree top level */ -# define TL_HASH(hi) ((hi) & (TOP_SZ - 1)) -/* Set bottom_indx to point to the bottom index for address p */ -# define GET_BI(p, bottom_indx) \ - { \ - register word hi = \ - (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \ - register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \ - \ - while (_bi -> key != hi && _bi != GC_all_nils) \ - _bi = _bi -> hash_link; \ - (bottom_indx) = _bi; \ - } -# define GET_HDR_ADDR(p, ha) \ - { \ - register bottom_index * bi; \ - \ - GET_BI(p, bi); \ - (ha) = &(HDR_FROM_BI(bi, p)); \ - } -# define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \ - (hhdr) = *_ha; } -# define SET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \ - *_ha = (hhdr); } -# define HDR(p) GC_find_header((ptr_t)(p)) -# endif - -/* Is the result a forwarding address to someplace closer to the */ -/* beginning of the block or NIL? */ -# define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((unsigned long) (hhdr) <= MAX_JUMP) - -/* Get an HBLKSIZE aligned address closer to the beginning of the block */ -/* h. Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr). */ -# define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (unsigned long)(hhdr)) -# endif /* GC_HEADERS_H */ diff --git a/gc/include/private/gc_locks.h b/gc/include/private/gc_locks.h deleted file mode 100644 index 2dbc6ca..0000000 --- a/gc/include/private/gc_locks.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. - * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. - * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. - * - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - */ - -#ifndef GC_LOCKS_H -#define GC_LOCKS_H - -/* - * Mutual exclusion between allocator/collector routines. - * Needed if there is more than one allocator thread. - * FASTLOCK() is assumed to try to acquire the lock in a cheap and - * dirty way that is acceptable for a few instructions, e.g. by - * inhibiting preemption. This is assumed to have succeeded only - * if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE. - * FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED(). - * If signals cannot be tolerated with the FASTLOCK held, then - * FASTLOCK should disable signals. The code executed under - * FASTLOCK is otherwise immune to interruption, provided it is - * not restarted. - * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK - * and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK. - * (There is currently no equivalent for FASTLOCK.) - * - * In the PARALLEL_MARK case, we also need to define a number of - * other inline finctions here: - * GC_bool GC_compare_and_exchange( volatile GC_word *addr, - * GC_word old, GC_word new ) - * GC_word GC_atomic_add( volatile GC_word *addr, GC_word how_much ) - * void GC_memory_barrier( ) - * - */ -# ifdef THREADS - void GC_noop1 GC_PROTO((word)); -# ifdef PCR_OBSOLETE /* Faster, but broken with multiple lwp's */ -# include "th/PCR_Th.h" -# include "th/PCR_ThCrSec.h" - extern struct PCR_Th_MLRep GC_allocate_ml; -# define DCL_LOCK_STATE PCR_sigset_t GC_old_sig_mask -# define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) -# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) -# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) -# define FASTLOCK() PCR_ThCrSec_EnterSys() - /* Here we cheat (a lot): */ -# define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0) - /* TRUE if nobody currently holds the lock */ -# define FASTUNLOCK() PCR_ThCrSec_ExitSys() -# endif -# ifdef PCR -# include <base/PCR_Base.h> -# include <th/PCR_Th.h> - extern PCR_Th_ML GC_allocate_ml; -# define DCL_LOCK_STATE \ - PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask -# define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) -# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) -# define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml)) -# define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay) -# define FASTUNLOCK() {\ - if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); } -# endif -# ifdef SRC_M3 - extern GC_word RT0u__inCritical; -# define LOCK() RT0u__inCritical++ -# define UNLOCK() RT0u__inCritical-- -# endif -# ifdef GC_SOLARIS_THREADS -# include <thread.h> -# include <signal.h> - extern mutex_t GC_allocate_ml; -# define LOCK() mutex_lock(&GC_allocate_ml); -# define UNLOCK() mutex_unlock(&GC_allocate_ml); -# endif - -/* Try to define GC_TEST_AND_SET and a matching GC_CLEAR for spin lock */ -/* acquisition and release. We need this for correct operation of the */ -/* incremental GC. */ -# ifdef __GNUC__ -# if defined(I386) - inline static int GC_test_and_set(volatile unsigned int *addr) { - int oldval; - /* Note: the "xchg" instruction does not need a "lock" prefix */ - __asm__ __volatile__("xchgl %0, %1" - : "=r"(oldval), "=m"(*(addr)) - : "0"(1), "m"(*(addr)) : "memory"); - return oldval; - } -# define GC_TEST_AND_SET_DEFINED -# endif -# if defined(IA64) - inline static int GC_test_and_set(volatile unsigned int *addr) { - long oldval, n = 1; - __asm__ __volatile__("xchg4 %0=%1,%2" - : "=r"(oldval), "=m"(*addr) - : "r"(n), "1"(*addr) : "memory"); - return oldval; - } -# define GC_TEST_AND_SET_DEFINED - /* Should this handle post-increment addressing?? */ - inline static void GC_clear(volatile unsigned int *addr) { - __asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr) : : "memory"); - } -# define GC_CLEAR_DEFINED -# endif -# ifdef SPARC - inline static int GC_test_and_set(volatile unsigned int *addr) { - int oldval; - - __asm__ __volatile__("ldstub %1,%0" - : "=r"(oldval), "=m"(*addr) - : "m"(*addr) : "memory"); - return oldval; - } -# define GC_TEST_AND_SET_DEFINED -# endif -# ifdef M68K - /* Contributed by Tony Mantler. I'm not sure how well it was */ - /* tested. */ - inline static int GC_test_and_set(volatile unsigned int *addr) { - char oldval; /* this must be no longer than 8 bits */ - - /* The return value is semi-phony. */ - /* 'tas' sets bit 7 while the return */ - /* value pretends bit 0 was set */ - __asm__ __volatile__( - "tas %1@; sne %0; negb %0" - : "=d" (oldval) - : "a" (addr) : "memory"); - return oldval; - } -# define GC_TEST_AND_SET_DEFINED -# endif -# if defined(POWERPC) - inline static int GC_test_and_set(volatile unsigned int *addr) { - int oldval; - int temp = 1; /* locked value */ - - __asm__ __volatile__( - "1:\tlwarx %0,0,%3\n" /* load and reserve */ - "\tcmpwi %0, 0\n" /* if load is */ - "\tbne 2f\n" /* non-zero, return already set */ - "\tstwcx. %2,0,%1\n" /* else store conditional */ - "\tbne- 1b\n" /* retry if lost reservation */ - "2:\t\n" /* oldval is zero if we set */ - : "=&r"(oldval), "=p"(addr) - : "r"(temp), "1"(addr) - : "memory"); - return (int)oldval; - } -# define GC_TEST_AND_SET_DEFINED - inline static void GC_clear(volatile unsigned int *addr) { - __asm__ __volatile__("eieio" : : : "memory"); - *(addr) = 0; - } -# define GC_CLEAR_DEFINED -# endif -# if defined(ALPHA) - inline static int GC_test_and_set(volatile unsigned int * addr) - { - unsigned long oldvalue; - unsigned long temp; - - __asm__ __volatile__( - "1: ldl_l %0,%1\n" - " and %0,%3,%2\n" - " bne %2,2f\n" - " xor %0,%3,%0\n" - " stl_c %0,%1\n" - " beq %0,3f\n" - " mb\n" - "2:\n" - ".section .text2,\"ax\"\n" - "3: br 1b\n" - ".previous" - :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue) - :"Ir" (1), "m" (*addr) - :"memory"); - - return oldvalue; - } -# define GC_TEST_AND_SET_DEFINED - /* Should probably also define GC_clear, since it needs */ - /* a memory barrier ?? */ -# endif /* ALPHA */ -# ifdef ARM32 - inline static int GC_test_and_set(volatile unsigned int *addr) { - int oldval; - /* SWP on ARM is very similar to XCHG on x86. Doesn't lock the - * bus because there are no SMP ARM machines. If/when there are, - * this code will likely need to be updated. */ - /* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */ - __asm__ __volatile__("swp %0, %1, [%2]" - : "=r"(oldval) - : "r"(1), "r"(addr) - : "memory"); - return oldval; - } -# define GC_TEST_AND_SET_DEFINED -# endif /* ARM32 */ -# endif /* __GNUC__ */ -# if (defined(ALPHA) && !defined(__GNUC__)) -# define GC_test_and_set(addr) __cxx_test_and_set_atomic(addr, 1) -# define GC_TEST_AND_SET_DEFINED -# endif -# if defined(MSWIN32) -# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1) -# define GC_TEST_AND_SET_DEFINED -# endif -# ifdef MIPS -# 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 -# 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) __test_and_set(addr,1) -# define GC_clear(addr) __lock_release(addr); -# define GC_CLEAR_DEFINED -# endif -# define GC_TEST_AND_SET_DEFINED -# endif /* MIPS */ -# if 0 /* defined(HP_PA) */ - /* The official recommendation seems to be to not use ldcw from */ - /* user mode. Since multithreaded incremental collection doesn't */ - /* work anyway on HP_PA, this shouldn't be a major loss. */ - - /* "set" means 0 and "clear" means 1 here. */ -# define GC_test_and_set(addr) !GC_test_and_clear(addr); -# define GC_TEST_AND_SET_DEFINED -# define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1; - /* The above needs a memory barrier! */ -# define GC_CLEAR_DEFINED -# endif -# if defined(GC_TEST_AND_SET_DEFINED) && !defined(GC_CLEAR_DEFINED) -# ifdef __GNUC__ - inline static void GC_clear(volatile unsigned int *addr) { - /* Try to discourage gcc from moving anything past this. */ - __asm__ __volatile__(" " : : : "memory"); - *(addr) = 0; - } -# else - /* The function call in the following should prevent the */ - /* compiler from moving assignments to below the UNLOCK. */ -# define GC_clear(addr) GC_noop1((word)(addr)); \ - *((volatile unsigned int *)(addr)) = 0; -# endif -# define GC_CLEAR_DEFINED -# endif /* !GC_CLEAR_DEFINED */ - -# if !defined(GC_TEST_AND_SET_DEFINED) -# define USE_PTHREAD_LOCKS -# endif - -# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ - && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) -# define NO_THREAD (pthread_t)(-1) -# include <pthread.h> -# if defined(PARALLEL_MARK) - /* We need compare-and-swap to update mark bits, where it's */ - /* performance critical. If USE_MARK_BYTES is defined, it is */ - /* no longer needed for this purpose. However we use it in */ - /* either case to implement atomic fetch-and-add, though that's */ - /* less performance critical, and could perhaps be done with */ - /* a lock. */ -# if defined(GENERIC_COMPARE_AND_SWAP) - /* Probably not useful, except for debugging. */ - /* We do use GENERIC_COMPARE_AND_SWAP on PA_RISC, but we */ - /* minimize its use. */ - extern pthread_mutex_t GC_compare_and_swap_lock; - - /* Note that if GC_word updates are not atomic, a concurrent */ - /* reader should acquire GC_compare_and_swap_lock. On */ - /* currently supported platforms, such updates are atomic. */ - extern GC_bool GC_compare_and_exchange(volatile GC_word *addr, - GC_word old, GC_word new_val); -# endif /* GENERIC_COMPARE_AND_SWAP */ -# if defined(I386) -# 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) - { - char result; - __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1" - : "=m"(*(addr)), "=r"(result) - : "r" (new_val), "0"(*(addr)), "a"(old) : "memory"); - return (GC_bool) result; - } -# endif /* !GENERIC_COMPARE_AND_SWAP */ - inline static void GC_memory_write_barrier() - { - /* We believe the processor ensures at least processor */ - /* consistent ordering. Thus a compiler barrier */ - /* should suffice. */ - __asm__ __volatile__("" : : : "memory"); - } -# endif /* I386 */ -# if defined(IA64) -# if !defined(GENERIC_COMPARE_AND_SWAP) - inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, - GC_word old, GC_word new_val) - { - unsigned long oldval; - __asm__ __volatile__("mov ar.ccv=%4 ;; cmpxchg8.rel %0=%1,%2,ar.ccv" - : "=r"(oldval), "=m"(*addr) - : "r"(new_val), "1"(*addr), "r"(old) : "memory"); - return (oldval == old); - } -# endif /* !GENERIC_COMPARE_AND_SWAP */ -# if 0 - /* Shouldn't be needed; we use volatile stores instead. */ - inline static void GC_memory_write_barrier() - { - __asm__ __volatile__("mf" : : : "memory"); - } -# endif /* 0 */ -# endif /* IA64 */ -# if !defined(GENERIC_COMPARE_AND_SWAP) - /* Returns the original value of *addr. */ - inline static GC_word GC_atomic_add(volatile GC_word *addr, - GC_word how_much) - { - GC_word old; - do { - old = *addr; - } while (!GC_compare_and_exchange(addr, old, old+how_much)); - return old; - } -# else /* GENERIC_COMPARE_AND_SWAP */ - /* So long as a GC_word can be atomically updated, it should */ - /* be OK to read *addr without a lock. */ - extern GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much); -# endif /* GENERIC_COMPARE_AND_SWAP */ - -# endif /* PARALLEL_MARK */ - -# if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS) - /* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to */ - /* be held for long periods, if it is held at all. Thus spinning */ - /* and sleeping for fixed periods are likely to result in */ - /* significant wasted time. We thus rely mostly on queued locks. */ -# define USE_SPIN_LOCK - extern volatile unsigned int GC_allocate_lock; - extern void GC_lock(void); - /* Allocation lock holder. Only set if acquired by client through */ - /* GC_call_with_alloc_lock. */ -# ifdef GC_ASSERTIONS -# define LOCK() \ - { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); \ - SET_LOCK_HOLDER(); } -# define UNLOCK() \ - { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \ - GC_clear(&GC_allocate_lock); } -# else -# define LOCK() \ - { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } -# define UNLOCK() \ - GC_clear(&GC_allocate_lock) -# endif /* !GC_ASSERTIONS */ -# if 0 - /* Another alternative for OSF1 might be: */ -# include <sys/mman.h> - extern msemaphore GC_allocate_semaphore; -# define LOCK() { if (msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) \ - != 0) GC_lock(); else GC_allocate_lock = 1; } - /* The following is INCORRECT, since the memory model is too weak. */ - /* Is this true? Presumably msem_unlock has the right semantics? */ - /* - HB */ -# define UNLOCK() { GC_allocate_lock = 0; \ - msem_unlock(&GC_allocate_semaphore, 0); } -# endif /* 0 */ -# else /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */ -# ifndef USE_PTHREAD_LOCKS -# define USE_PTHREAD_LOCKS -# endif -# endif /* THREAD_LOCAL_ALLOC */ -# ifdef USE_PTHREAD_LOCKS -# include <pthread.h> - extern pthread_mutex_t GC_allocate_ml; -# ifdef GC_ASSERTIONS -# define LOCK() \ - { GC_lock(); \ - SET_LOCK_HOLDER(); } -# define UNLOCK() \ - { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \ - pthread_mutex_unlock(&GC_allocate_ml); } -# else /* !GC_ASSERTIONS */ -# define LOCK() \ - { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); } -# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) -# endif /* !GC_ASSERTIONS */ -# endif /* USE_PTHREAD_LOCKS */ -# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self() -# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD -# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) - extern VOLATILE GC_bool GC_collecting; -# define ENTER_GC() GC_collecting = 1; -# define EXIT_GC() GC_collecting = 0; - extern void GC_lock(void); - extern pthread_t GC_lock_holder; -# ifdef GC_ASSERTIONS - extern pthread_t GC_mark_lock_holder; -# endif -# endif /* GC_PTHREADS with linux_threads.c implementation */ -# if defined(GC_IRIX_THREADS) -# include <pthread.h> - /* This probably should never be included, but I can't test */ - /* on Irix anymore. */ -# include <mutex.h> - - extern unsigned long GC_allocate_lock; - /* This is not a mutex because mutexes that obey the (optional) */ - /* POSIX scheduling rules are subject to convoys in high contention */ - /* applications. This is basically a spin lock. */ - extern pthread_t GC_lock_holder; - extern void GC_lock(void); - /* Allocation lock holder. Only set if acquired by client through */ - /* GC_call_with_alloc_lock. */ -# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self() -# define NO_THREAD (pthread_t)(-1) -# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD -# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) -# 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() \ - { \ - GC_collecting = 1; \ - } -# define EXIT_GC() GC_collecting = 0; -# endif /* GC_IRIX_THREADS */ -# 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() -# define UNSET_LOCK_HOLDER() -# define I_HOLD_LOCK() FALSE - /* Used on platforms were locks can be reacquired, */ - /* so it doesn't matter if we lie. */ -# endif -# else /* !THREADS */ -# define LOCK() -# define UNLOCK() -# endif /* !THREADS */ -# ifndef SET_LOCK_HOLDER -# define SET_LOCK_HOLDER() -# define UNSET_LOCK_HOLDER() -# define I_HOLD_LOCK() FALSE - /* Used on platforms were locks can be reacquired, */ - /* so it doesn't matter if we lie. */ -# endif -# ifndef ENTER_GC -# define ENTER_GC() -# define EXIT_GC() -# endif - -# ifndef DCL_LOCK_STATE -# define DCL_LOCK_STATE -# endif -# ifndef FASTLOCK -# define FASTLOCK() LOCK() -# define FASTLOCK_SUCCEEDED() TRUE -# define FASTUNLOCK() UNLOCK() -# endif - -#endif /* GC_LOCKS_H */ diff --git a/gc/include/private/gc_pmark.h b/gc/include/private/gc_pmark.h deleted file mode 100644 index cf85d4d..0000000 --- a/gc/include/private/gc_pmark.h +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. - * Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved. - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - * - */ - -/* Private declarations of GC marker data structures and macros */ - -/* - * Declarations of mark stack. Needed by marker and client supplied mark - * routines. Transitively include gc_priv.h. - * (Note that gc_priv.h should not be included before this, since this - * includes dbg_mlc.h, which wants to include gc_priv.h AFTER defining - * I_HIDE_POINTERS.) - */ -#ifndef GC_PMARK_H -# define GC_PMARK_H - -# if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) -# include "dbg_mlc.h" -# endif -# ifndef GC_MARK_H -# include "../gc_mark.h" -# endif -# ifndef GC_PRIVATE_H -# include "gc_priv.h" -# endif - -/* The real declarations of the following is in gc_priv.h, so that */ -/* we can avoid scanning the following table. */ -/* -extern mark_proc GC_mark_procs[MAX_MARK_PROCS]; -*/ - -/* - * Mark descriptor stuff that should remain private for now, mostly - * because it's hard to export WORDSZ without including gcconfig.h. - */ -# define BITMAP_BITS (WORDSZ - GC_DS_TAG_BITS) -# define PROC(descr) \ - (GC_mark_procs[((descr) >> GC_DS_TAG_BITS) & (GC_MAX_MARK_PROCS-1)]) -# define ENV(descr) \ - ((descr) >> (GC_DS_TAG_BITS + GC_LOG_MAX_MARK_PROCS)) -# define MAX_ENV \ - (((word)1 << (WORDSZ - GC_DS_TAG_BITS - GC_LOG_MAX_MARK_PROCS)) - 1) - - -extern word GC_n_mark_procs; - -/* Number of mark stack entries to discard on overflow. */ -#define GC_MARK_STACK_DISCARDS (INITIAL_MARK_STACK_SIZE/8) - -typedef struct GC_ms_entry { - GC_word * mse_start; /* First word of object */ - GC_word mse_descr; /* Descriptor; low order two bits are tags, */ - /* identifying the upper 30 bits as one of the */ - /* following: */ -} mse; - -extern word GC_mark_stack_size; - -extern mse * GC_mark_stack_limit; - -#ifdef PARALLEL_MARK - extern mse * VOLATILE GC_mark_stack_top; -#else - extern mse * GC_mark_stack_top; -#endif - -extern mse * GC_mark_stack; - -#ifdef PARALLEL_MARK - /* - * Allow multiple threads to participate in the marking process. - * This works roughly as follows: - * The main mark stack never shrinks, but it can grow. - * - * The initiating threads holds the GC lock, and sets GC_help_wanted. - * - * Other threads: - * 1) update helper_count (while holding mark_lock.) - * 2) allocate a local mark stack - * repeatedly: - * 3) Steal a global mark stack entry by atomically replacing - * its descriptor with 0. - * 4) Copy it to the local stack. - * 5) Mark on the local stack until it is empty, or - * it may be profitable to copy it back. - * 6) If necessary, copy local stack to global one, - * holding mark lock. - * 7) Stop when the global mark stack is empty. - * 8) decrement helper_count (holding mark_lock). - * - * This is an experiment to see if we can do something along the lines - * of the University of Tokyo SGC in a less intrusive, though probably - * also less performant, way. - */ - void GC_do_parallel_mark(); - /* inititate parallel marking. */ - - extern GC_bool GC_help_wanted; /* Protected by mark lock */ - extern unsigned GC_helper_count; /* Number of running helpers. */ - /* Protected by mark lock */ - extern unsigned GC_active_count; /* Number of active helpers. */ - /* Protected by mark lock */ - /* May increase and decrease */ - /* within each mark cycle. But */ - /* once it returns to 0, it */ - /* stays zero for the cycle. */ - /* GC_mark_stack_top is also protected by mark lock. */ - extern mse * VOLATILE GC_first_nonempty; - /* Lowest entry on mark stack */ - /* that may be nonempty. */ - /* Updated only by initiating */ - /* thread. */ - /* - * GC_notify_all_marker() is used when GC_help_wanted is first set, - * when the last helper becomes inactive, - * when something is added to the global mark stack, and just after - * GC_mark_no is incremented. - * This could be split into multiple CVs (and probably should be to - * scale to really large numbers of processors.) - */ -#endif /* PARALLEL_MARK */ - -/* Return a pointer to within 1st page of object. */ -/* Set *new_hdr_p to corr. hdr. */ -#ifdef __STDC__ -# ifdef PRINT_BLACK_LIST - ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p, - word source); -# else - ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p); -# endif -#else - ptr_t GC_find_start(); -#endif - -mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp)); - -# ifdef GATHERSTATS -# define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz) -# define ADD_TO_COMPOSITE(sz) GC_composite_in_use += (sz) -# else -# define ADD_TO_ATOMIC(sz) -# define ADD_TO_COMPOSITE(sz) -# endif - -/* Push the object obj with corresponding heap block header hhdr onto */ -/* the mark stack. */ -# define PUSH_OBJ(obj, hhdr, mark_stack_top, mark_stack_limit) \ -{ \ - register word _descr = (hhdr) -> hb_descr; \ - \ - if (_descr == 0) { \ - ADD_TO_ATOMIC((hhdr) -> hb_sz); \ - } else { \ - ADD_TO_COMPOSITE((hhdr) -> hb_sz); \ - mark_stack_top++; \ - if (mark_stack_top >= mark_stack_limit) { \ - mark_stack_top = GC_signal_mark_stack_overflow(mark_stack_top); \ - } \ - mark_stack_top -> mse_start = (obj); \ - mark_stack_top -> mse_descr = _descr; \ - } \ -} - -/* 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 */ -/* generate the exit_label transparently. */ -# define PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \ - source, exit_label) \ -{ \ - hdr * my_hhdr; \ - ptr_t my_current = current; \ - \ - 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); \ - my_hhdr = new_hdr; \ - } \ - PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \ - source, exit_label, my_hhdr); \ -exit_label: ; \ -} - -/* As above, but use header cache for header lookup. */ -# define HC_PUSH_CONTENTS(current, mark_stack_top, mark_stack_limit, \ - source, exit_label) \ -{ \ - hdr * my_hhdr; \ - ptr_t my_current = current; \ - \ - HC_GET_HDR(my_current, my_hhdr, source); \ - PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \ - source, exit_label, my_hhdr); \ -exit_label: ; \ -} - -/* Set mark bit, exit if it was already set. */ - -# ifdef USE_MARK_BYTES - /* Unlike the mark bit case, there is a race here, and we may set */ - /* the bit twice in the concurrent case. This can result in the */ - /* object being pushed twice. But that's only a performance issue. */ -# define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \ - { \ - register VOLATILE char * mark_byte_addr = \ - hhdr -> hb_marks + ((displ) >> 1); \ - register char mark_byte = *mark_byte_addr; \ - \ - if (mark_byte) goto exit_label; \ - *mark_byte_addr = 1; \ - } -# else -# define SET_MARK_BIT_EXIT_IF_SET(hhdr,displ,exit_label) \ - { \ - register word * mark_word_addr = hhdr -> hb_marks + divWORDSZ(displ); \ - \ - OR_WORD_EXIT_IF_SET(mark_word_addr, (word)1 << modWORDSZ(displ), \ - exit_label); \ - } -# endif /* USE_MARK_BYTES */ - -/* If the mark bit corresponding to current is not set, set it, and */ -/* push the contents of the object on the mark stack. For a small */ -/* object we assume that current is the (possibly interior) pointer */ -/* to the object. For large objects we assume that current points */ -/* to somewhere inside the first page of the object. If */ -/* GC_all_interior_pointers is set, it may have been previously */ -/* adjusted to make that true. */ -# define PUSH_CONTENTS_HDR(current, mark_stack_top, mark_stack_limit, \ - source, exit_label, hhdr) \ -{ \ - int displ; /* Displacement in block; first bytes, then words */ \ - int map_entry; \ - \ - displ = HBLKDISPL(current); \ - map_entry = MAP_ENTRY((hhdr -> hb_map), displ); \ - displ = BYTES_TO_WORDS(displ); \ - if (map_entry > CPP_MAX_OFFSET) { \ - if (map_entry == OFFSET_TOO_BIG) { \ - map_entry = displ % (hhdr -> hb_sz); \ - displ -= map_entry; \ - if (displ + (hhdr -> hb_sz) > BYTES_TO_WORDS(HBLKSIZE)) { \ - GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); \ - goto exit_label; \ - } \ - } else { \ - GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); goto exit_label; \ - } \ - } else { \ - displ -= map_entry; \ - } \ - GC_ASSERT(displ >= 0 && displ < MARK_BITS_PER_HBLK); \ - SET_MARK_BIT_EXIT_IF_SET(hhdr, displ, exit_label); \ - GC_STORE_BACK_PTR((ptr_t)source, (ptr_t)HBLKPTR(current) \ - + WORDS_TO_BYTES(displ)); \ - PUSH_OBJ(((word *)(HBLKPTR(current)) + displ), hhdr, \ - mark_stack_top, mark_stack_limit) \ -} - -#if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS) -# define PUSH_ONE_CHECKED_STACK(p, source) \ - GC_mark_and_push_stack(p, (ptr_t)(source)) -#else -# define PUSH_ONE_CHECKED_STACK(p, source) \ - GC_mark_and_push_stack(p) -#endif - -/* - * Push a single value onto mark stack. Mark from the object pointed to by p. - * 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 \ - && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \ - PUSH_ONE_CHECKED_STACK(p, source); \ - } - -/* - * As above, but interior pointer recognition as for - * normal for heap pointers. - */ -# define GC_PUSH_ONE_HEAP(p,source) \ - 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( \ - (GC_PTR)(p), GC_mark_stack_top, \ - GC_mark_stack_limit, (GC_PTR *)(source)); \ - } - -/* Mark starting at mark stack entry top (incl.) down to */ -/* mark stack entry bottom (incl.). Stop after performing */ -/* about one page worth of work. Return the new mark stack */ -/* top entry. */ -mse * GC_mark_from GC_PROTO((mse * top, mse * bottom, mse *limit)); - -#define MARK_FROM_MARK_STACK() \ - GC_mark_stack_top = GC_mark_from(GC_mark_stack_top, \ - GC_mark_stack, \ - GC_mark_stack + GC_mark_stack_size); - -/* - * Mark from one finalizable object using the specified - * mark proc. May not mark the object pointed to by - * real_ptr. That is the job of the caller, if appropriate - */ -# define GC_MARK_FO(real_ptr, mark_proc) \ -{ \ - (*(mark_proc))(real_ptr); \ - while (!GC_mark_stack_empty()) MARK_FROM_MARK_STACK(); \ - if (GC_mark_state != MS_NONE) { \ - GC_set_mark_bit(real_ptr); \ - while (!GC_mark_some((ptr_t)0)) {} \ - } \ -} - -extern GC_bool GC_mark_stack_too_small; - /* We need a larger mark stack. May be */ - /* set by client supplied mark routines.*/ - -typedef int mark_state_t; /* Current state of marking, as follows:*/ - /* Used to remember where we are during */ - /* concurrent marking. */ - - /* We say something is dirty if it was */ - /* written since the last time we */ - /* retrieved dirty bits. We say it's */ - /* grungy if it was marked dirty in the */ - /* last set of bits we retrieved. */ - - /* Invariant I: all roots and marked */ - /* objects p are either dirty, or point */ - /* to objects q that are either marked */ - /* or a pointer to q appears in a range */ - /* on the mark stack. */ - -# define MS_NONE 0 /* No marking in progress. I holds. */ - /* Mark stack is empty. */ - -# define MS_PUSH_RESCUERS 1 /* Rescuing objects are currently */ - /* being pushed. I holds, except */ - /* that grungy roots may point to */ - /* unmarked objects, as may marked */ - /* grungy objects above scan_ptr. */ - -# define MS_PUSH_UNCOLLECTABLE 2 - /* I holds, except that marked */ - /* uncollectable objects above scan_ptr */ - /* may point to unmarked objects. */ - /* Roots may point to unmarked objects */ - -# define MS_ROOTS_PUSHED 3 /* I holds, mark stack may be nonempty */ - -# define MS_PARTIALLY_INVALID 4 /* I may not hold, e.g. because of M.S. */ - /* overflow. However marked heap */ - /* objects below scan_ptr point to */ - /* marked or stacked objects. */ - -# define MS_INVALID 5 /* I may not hold. */ - -extern mark_state_t GC_mark_state; - -#endif /* GC_PMARK_H */ - diff --git a/gc/include/private/gc_priv.h b/gc/include/private/gc_priv.h deleted file mode 100644 index 2cf07d1..0000000 --- a/gc/include/private/gc_priv.h +++ /dev/null @@ -1,1884 +0,0 @@ -/* - * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. - * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. - * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved. - * - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - */ - - -# ifndef GC_PRIVATE_H -# define GC_PRIVATE_H - -#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news) - /* sony RISC NEWS, NEWSOS 4 */ -# define BSD_TIME -/* typedef long ptrdiff_t; -- necessary on some really old systems */ -#endif - -#if defined(mips) && defined(SYSTYPE_BSD43) - /* MIPS RISCOS 4 */ -# 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" -# endif - -# ifndef GC_MARK_H -# include "../gc_mark.h" -# endif - -typedef GC_word word; -typedef GC_signed_word signed_word; - -typedef int GC_bool; -# define TRUE 1 -# define FALSE 0 - -typedef char * ptr_t; /* A generic pointer to which we can add */ - /* byte displacements. */ - /* Preferably identical to caddr_t, if it */ - /* exists. */ - -# ifndef GCCONFIG_H -# include "gcconfig.h" -# endif - -# ifndef HEADERS_H -# include "gc_hdrs.h" -# endif - -#if defined(__STDC__) -# include <stdlib.h> -# if !(defined( sony_news ) ) -# include <stddef.h> -# endif -# define VOLATILE volatile -#else -# ifdef MSWIN32 -# include <stdlib.h> -# endif -# define VOLATILE -#endif - -#if 0 /* defined(__GNUC__) doesn't work yet */ -# define EXPECT(expr, outcome) __builtin_expect(expr,outcome) - /* Equivalent to (expr), but predict that usually (expr)==outcome. */ -#else -# define EXPECT(expr, outcome) (expr) -#endif /* __GNUC__ */ - -# ifndef GC_LOCKS_H -# include "gc_locks.h" -# endif - -# ifdef STACK_GROWS_DOWN -# define COOLER_THAN > -# define HOTTER_THAN < -# define MAKE_COOLER(x,y) if ((word)(x)+(y) > (word)(x)) {(x) += (y);} \ - else {(x) = (word)ONES;} -# define MAKE_HOTTER(x,y) (x) -= (y) -# else -# define COOLER_THAN < -# define HOTTER_THAN > -# define MAKE_COOLER(x,y) if ((word)(x)-(y) < (word)(x)) {(x) -= (y);} else {(x) = 0;} -# define MAKE_HOTTER(x,y) (x) += (y) -# endif - -#if defined(AMIGA) && defined(__SASC) -# define GC_FAR __far -#else -# define GC_FAR -#endif - - -/*********************************/ -/* */ -/* Definitions for conservative */ -/* collector */ -/* */ -/*********************************/ - -/*********************************/ -/* */ -/* Easily changeable parameters */ -/* */ -/*********************************/ - -/* #define STUBBORN_ALLOC */ - /* Enable stubborm allocation, and thus a limited */ - /* form of incremental collection w/o dirty bits. */ - -/* #define ALL_INTERIOR_POINTERS */ - /* Forces all pointers into the interior of an */ - /* object to be considered valid. Also causes the */ - /* sizes of all objects to be inflated by at least */ - /* one byte. This should suffice to guarantee */ - /* that in the presence of a compiler that does */ - /* not perform garbage-collector-unsafe */ - /* optimizations, all portable, strictly ANSI */ - /* conforming C programs should be safely usable */ - /* with malloc replaced by GC_malloc and free */ - /* calls removed. There are several disadvantages: */ - /* 1. There are probably no interesting, portable, */ - /* strictly ANSI conforming C programs. */ - /* 2. This option makes it hard for the collector */ - /* to allocate space that is not ``pointed to'' */ - /* by integers, etc. Under SunOS 4.X with a */ - /* statically linked libc, we empiricaly */ - /* observed that it would be difficult to */ - /* allocate individual objects larger than 100K. */ - /* Even if only smaller objects are allocated, */ - /* more swap space is likely to be needed. */ - /* Fortunately, much of this will never be */ - /* touched. */ - /* If you can easily avoid using this option, do. */ - /* If not, try to keep individual objects small. */ - /* This is now really controlled at startup, */ - /* through GC_all_interior_pointers. */ - -#define PRINTSTATS /* Print garbage collection statistics */ - /* For less verbose output, undefine in reclaim.c */ - -#define PRINTTIMES /* Print the amount of time consumed by each garbage */ - /* collection. */ - -#define PRINTBLOCKS /* Print object sizes associated with heap blocks, */ - /* whether the objects are atomic or composite, and */ - /* whether or not the block was found to be empty */ - /* during the reclaim phase. Typically generates */ - /* about one screenful per garbage collection. */ -#undef PRINTBLOCKS - -#ifdef SILENT -# ifdef PRINTSTATS -# undef PRINTSTATS -# endif -# ifdef PRINTTIMES -# undef PRINTTIMES -# endif -# ifdef PRINTNBLOCKS -# undef PRINTNBLOCKS -# endif -#endif - -#if defined(PRINTSTATS) && !defined(GATHERSTATS) -# define GATHERSTATS -#endif - -#if defined(PRINTSTATS) || !defined(SMALL_CONFIG) -# define CONDPRINT /* Print some things if GC_print_stats is set */ -#endif - -#define GC_INVOKE_FINALIZERS() GC_notify_or_invoke_finalizers() - -#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */ - /* free lists are actually maintained. This applies */ - /* only to the top level routines in misc.c, not to */ - /* user generated code that calls GC_allocobj and */ - /* GC_allocaobj directly. */ - /* Slows down average programs slightly. May however */ - /* substantially reduce fragmentation if allocation */ - /* request sizes are widely scattered. */ - /* May save significant amounts of space for obj_map */ - /* entries. */ - -#if defined(USE_MARK_BYTES) && !defined(ALIGN_DOUBLE) -# define ALIGN_DOUBLE - /* We use one byte for every 2 words, which doesn't allow for */ - /* odd numbered words to have mark bits. */ -#endif - -#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 -# endif - -#if !defined(DONT_ADD_BYTE_AT_END) -# define EXTRA_BYTES GC_all_interior_pointers -#else -# define EXTRA_BYTES 0 -#endif - - -# ifndef LARGE_CONFIG -# define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE */ - /* Must be multiple of largest page size. */ -# define MAXHINCR 2048 /* Maximum heap increment, in blocks */ -# else -# define MINHINCR 64 -# define MAXHINCR 4096 -# endif - -# define TIME_LIMIT 50 /* We try to keep pause times from exceeding */ - /* this by much. In milliseconds. */ - -# define BL_LIMIT GC_black_list_spacing - /* If we need a block of N bytes, and we have */ - /* a block of N + BL_LIMIT bytes available, */ - /* and N > BL_LIMIT, */ - /* but all possible positions in it are */ - /* blacklisted, we just use it anyway (and */ - /* print a warning, if warnings are enabled). */ - /* This risks subsequently leaking the block */ - /* due to a false reference. But not using */ - /* the block risks unreasonable immediate */ - /* heap growth. */ - -/*********************************/ -/* */ -/* Stack saving for debugging */ -/* */ -/*********************************/ - -#ifdef SAVE_CALL_CHAIN - -/* Fill in the pc and argument information for up to NFRAMES of my */ -/* callers. Ignore my frame and my callers frame. */ -struct callinfo; -void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES])); - -void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES])); - -#endif - -#ifdef NEED_CALLINFO - struct callinfo { - word ci_pc; /* Caller, not callee, pc */ -# if NARGS > 0 - word ci_arg[NARGS]; /* bit-wise complement to avoid retention */ -# endif -# if defined(ALIGN_DOUBLE) && (NFRAMES * (NARGS + 1)) % 2 == 1 - /* Likely alignment problem. */ - word ci_dummy; -# endif - }; -#endif - - -/*********************************/ -/* */ -/* OS interface routines */ -/* */ -/*********************************/ - -#ifdef BSD_TIME -# undef CLOCK_TYPE -# undef GET_TIME -# undef MS_TIME_DIFF -# define CLOCK_TYPE struct timeval -# define GET_TIME(x) { struct rusage rusage; \ - getrusage (RUSAGE_SELF, &rusage); \ - x = rusage.ru_utime; } -# define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \ - + (double) (a.tv_usec - b.tv_usec) / 1000.0) -#else /* !BSD_TIME */ -# if defined(MSWIN32) || defined(MSWINCE) -# include <windows.h> -# include <winbase.h> -# define CLOCK_TYPE DWORD -# define GET_TIME(x) x = GetTickCount() -# define MS_TIME_DIFF(a,b) ((long)((a)-(b))) -# else /* !MSWIN32, !MSWINCE, !BSD_TIME */ -# include <time.h> -# if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4) - clock_t clock(); /* Not in time.h, where it belongs */ -# endif -# if defined(FREEBSD) && !defined(CLOCKS_PER_SEC) -# include <machine/limits.h> -# define CLOCKS_PER_SEC CLK_TCK -# endif -# if !defined(CLOCKS_PER_SEC) -# define CLOCKS_PER_SEC 1000000 -/* - * This is technically a bug in the implementation. ANSI requires that - * CLOCKS_PER_SEC be defined. But at least under SunOS4.1.1, it isn't. - * Also note that the combination of ANSI C and POSIX is incredibly gross - * here. The type clock_t is used by both clock() and times(). But on - * some machines these use different notions of a clock tick, CLOCKS_PER_SEC - * seems to apply only to clock. Hence we use it here. On many machines, - * including SunOS, clock actually uses units of microseconds (which are - * not really clock ticks). - */ -# endif -# define CLOCK_TYPE clock_t -# define GET_TIME(x) x = clock() -# define MS_TIME_DIFF(a,b) ((unsigned long) \ - (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC)) -# endif /* !MSWIN32 */ -#endif /* !BSD_TIME */ - -/* We use bzero and bcopy internally. They may not be available. */ -# if defined(SPARC) && defined(SUNOS4) -# define BCOPY_EXISTS -# endif -# if defined(M68K) && defined(AMIGA) -# define BCOPY_EXISTS -# endif -# if defined(M68K) && defined(NEXT) -# define BCOPY_EXISTS -# endif -# if defined(VAX) -# define BCOPY_EXISTS -# endif -# if defined(AMIGA) -# include <string.h> -# define BCOPY_EXISTS -# endif -# if defined(MACOSX) -# define BCOPY_EXISTS -# endif - -# ifndef BCOPY_EXISTS -# include <string.h> -# define BCOPY(x,y,n) memcpy(y, x, (size_t)(n)) -# define BZERO(x,n) memset(x, 0, (size_t)(n)) -# else -# define BCOPY(x,y,n) bcopy((char *)(x),(char *)(y),(int)(n)) -# define BZERO(x,n) bzero((char *)(x),(int)(n)) -# 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 */ -/* clear on that point). Standard malloc implementations are usually */ -/* neither interruptable nor thread-safe, and thus correspond to */ -/* empty definitions. */ -/* It probably doesn't make any sense to declare these to be nonempty */ -/* if the code is being optimized, since signal safety relies on some */ -/* ordering constraints that are typically not obeyed by optimizing */ -/* compilers. */ -# ifdef PCR -# define DISABLE_SIGNALS() \ - PCR_Th_SetSigMask(PCR_allSigsBlocked,&GC_old_sig_mask) -# define ENABLE_SIGNALS() \ - PCR_Th_SetSigMask(&GC_old_sig_mask, NIL) -# else -# if defined(THREADS) || defined(AMIGA) \ - || defined(MSWIN32) || defined(MSWINCE) || defined(MACOS) \ - || defined(DJGPP) || defined(NO_SIGNALS) - /* Also useful for debugging. */ - /* Should probably use thr_sigsetmask for GC_SOLARIS_THREADS. */ -# define DISABLE_SIGNALS() -# define ENABLE_SIGNALS() -# else -# define DISABLE_SIGNALS() GC_disable_signals() - void GC_disable_signals(); -# define ENABLE_SIGNALS() GC_enable_signals() - void GC_enable_signals(); -# endif -# endif - -/* - * Stop and restart mutator threads. - */ -# ifdef PCR -# include "th/PCR_ThCtl.h" -# define STOP_WORLD() \ - PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal, \ - PCR_allSigsBlocked, \ - PCR_waitForever) -# define START_WORLD() \ - PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null, \ - PCR_allSigsBlocked, \ - PCR_waitForever); -# else -# if defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) \ - || defined(GC_PTHREADS) - void GC_stop_world(); - void GC_start_world(); -# define STOP_WORLD() GC_stop_world() -# define START_WORLD() GC_start_world() -# else -# define STOP_WORLD() -# define START_WORLD() -# endif -# endif - -/* Abandon ship */ -# ifdef PCR -# define ABORT(s) PCR_Base_Panic(s) -# else -# ifdef SMALL_CONFIG -# define ABORT(msg) abort(); -# else - GC_API void GC_abort GC_PROTO((GC_CONST char * msg)); -# define ABORT(msg) GC_abort(msg); -# endif -# endif - -/* Exit abnormally, but without making a mess (e.g. out of memory) */ -# ifdef PCR -# define EXIT() PCR_Base_Exit(1,PCR_waitForever) -# else -# define EXIT() (void)exit(1) -# endif - -/* Print warning message, e.g. almost out of memory. */ -# 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 */ -#if !defined(NO_GETENV) -# define GETENV(name) getenv(name) -#else -# define GETENV(name) 0 -#endif - -/*********************************/ -/* */ -/* Word-size-dependent defines */ -/* */ -/*********************************/ - -#if CPP_WORDSZ == 32 -# define WORDS_TO_BYTES(x) ((x)<<2) -# define BYTES_TO_WORDS(x) ((x)>>2) -# define LOGWL ((word)5) /* log[2] of CPP_WORDSZ */ -# define modWORDSZ(n) ((n) & 0x1f) /* n mod size of word */ -# if ALIGNMENT != 4 -# define UNALIGNED -# endif -#endif - -#if CPP_WORDSZ == 64 -# define WORDS_TO_BYTES(x) ((x)<<3) -# define BYTES_TO_WORDS(x) ((x)>>3) -# define LOGWL ((word)6) /* log[2] of CPP_WORDSZ */ -# define modWORDSZ(n) ((n) & 0x3f) /* n mod size of word */ -# if ALIGNMENT != 8 -# define UNALIGNED -# endif -#endif - -#define WORDSZ ((word)CPP_WORDSZ) -#define SIGNB ((word)1 << (WORDSZ-1)) -#define BYTES_PER_WORD ((word)(sizeof (word))) -#define ONES ((word)(signed_word)(-1)) -#define divWORDSZ(n) ((n) >> LOGWL) /* divide n by size of word */ - -/*********************/ -/* */ -/* Size Parameters */ -/* */ -/*********************/ - -/* heap block size, bytes. Should be power of 2 */ - -#ifndef HBLKSIZE -# ifdef SMALL_CONFIG -# define CPP_LOG_HBLKSIZE 10 -# else -# if (CPP_WORDSZ == 32) || (defined(HPUX) && defined(HP_PA)) - /* HPUX/PA seems to use 4K pages with the 64 bit ABI */ -# define CPP_LOG_HBLKSIZE 12 -# else -# define CPP_LOG_HBLKSIZE 13 -# endif -# endif -#else -# if HBLKSIZE == 512 -# define CPP_LOG_HBLKSIZE 9 -# endif -# if HBLKSIZE == 1024 -# define CPP_LOG_HBLKSIZE 10 -# endif -# if HBLKSIZE == 2048 -# define CPP_LOG_HBLKSIZE 11 -# endif -# if HBLKSIZE == 4096 -# define CPP_LOG_HBLKSIZE 12 -# endif -# if HBLKSIZE == 8192 -# define CPP_LOG_HBLKSIZE 13 -# endif -# if HBLKSIZE == 16384 -# define CPP_LOG_HBLKSIZE 14 -# endif -# ifndef CPP_LOG_HBLKSIZE - --> fix HBLKSIZE -# endif -# undef HBLKSIZE -#endif -# define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE) -# define LOG_HBLKSIZE ((word)CPP_LOG_HBLKSIZE) -# define HBLKSIZE ((word)CPP_HBLKSIZE) - - -/* max size objects supported by freelist (larger objects may be */ -/* allocated, but less efficiently) */ - -#define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2) -#define MAXOBJBYTES ((word)CPP_MAXOBJBYTES) -#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_HBLKSIZE/2) -#define MAXOBJSZ ((word)CPP_MAXOBJSZ) - -# define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE) - -# define HBLK_PTR_DIFF(p,q) divHBLKSZ((ptr_t)p - (ptr_t)q) - /* Equivalent to subtracting 2 hblk pointers. */ - /* We do it this way because a compiler should */ - /* find it hard to use an integer division */ - /* instead of a shift. The bundled SunOS 4.1 */ - /* o.w. sometimes pessimizes the subtraction to */ - /* involve a call to .div. */ - -# define modHBLKSZ(n) ((n) & (HBLKSIZE-1)) - -# define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1))) - -# define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1)) - -/* Round up byte allocation requests to integral number of words, etc. */ -# define ROUNDED_UP_WORDS(n) \ - BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1 + EXTRA_BYTES)) -# ifdef ALIGN_DOUBLE -# define ALIGNED_WORDS(n) \ - (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1 + EXTRA_BYTES) & ~1) -# else -# define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n) -# endif -# define SMALL_OBJ(bytes) ((bytes) < (MAXOBJBYTES - EXTRA_BYTES)) -# define ADD_SLOP(bytes) ((bytes) + EXTRA_BYTES) -# ifndef MIN_WORDS - /* MIN_WORDS is the size of the smallest allocated object. */ - /* 1 and 2 are the only valid values. */ - /* 2 must be used if: */ - /* - GC_gcj_malloc can be used for objects of requested */ - /* size smaller than 2 words, or */ - /* - USE_MARK_BYTES is defined. */ -# if defined(USE_MARK_BYTES) || defined(GC_GCJ_SUPPORT) -# define MIN_WORDS 2 /* Smallest allocated object. */ -# else -# define MIN_WORDS 1 -# endif -# endif - - -/* - * Hash table representation of sets of pages. This assumes it is - * OK to add spurious entries to sets. - * Used by black-listing code, and perhaps by dirty bit maintenance code. - */ - -# ifdef LARGE_CONFIG -# define LOG_PHT_ENTRIES 19 /* Collisions likely at 512K blocks, */ - /* which is >= 2GB. Each table takes */ - /* 64KB. */ -# else -# ifdef SMALL_CONFIG -# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */ - /* to more than 16K hblks = 64MB. */ - /* Each hash table occupies 2K bytes. */ -# else /* default "medium" configuration */ -# define LOG_PHT_ENTRIES 16 /* Collisions are likely if heap grows */ - /* to more than 16K hblks >= 256MB. */ - /* Each hash table occupies 8K bytes. */ -# endif -# endif -# define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES) -# define PHT_SIZE (PHT_ENTRIES >> LOGWL) -typedef word page_hash_table[PHT_SIZE]; - -# define PHT_HASH(addr) ((((word)(addr)) >> LOG_HBLKSIZE) & (PHT_ENTRIES - 1)) - -# define get_pht_entry_from_index(bl, index) \ - (((bl)[divWORDSZ(index)] >> modWORDSZ(index)) & 1) -# define set_pht_entry_from_index(bl, index) \ - (bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index) -# define clear_pht_entry_from_index(bl, index) \ - (bl)[divWORDSZ(index)] &= ~((word)1 << modWORDSZ(index)) -/* And a dumb but thread-safe version of set_pht_entry_from_index. */ -/* This sets (many) extra bits. */ -# define set_pht_entry_from_index_safe(bl, index) \ - (bl)[divWORDSZ(index)] = ONES - - - -/********************************************/ -/* */ -/* H e a p B l o c k s */ -/* */ -/********************************************/ - -/* heap block header */ -#define HBLKMASK (HBLKSIZE-1) - -#define BITS_PER_HBLK (CPP_HBLKSIZE * 8) - -#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/CPP_WORDSZ) - /* upper bound */ - /* We allocate 1 bit/word, unless USE_MARK_BYTES */ - /* is defined. Only the first word */ - /* in each object is actually marked. */ - -# ifdef USE_MARK_BYTES -# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/2) - /* Unlike the other case, this is in units of bytes. */ - /* We actually allocate only every second mark bit, since we */ - /* force all objects to be doubleword aligned. */ - /* However, each mark bit is allocated as a byte. */ -# else -# define MARK_BITS_SZ (MARK_BITS_PER_HBLK/CPP_WORDSZ) -# endif - -/* We maintain layout maps for heap blocks containing objects of a given */ -/* size. Each entry in this map describes a byte offset and has the */ -/* following type. */ -typedef unsigned char map_entry_type; - -struct hblkhdr { - word hb_sz; /* If in use, size in words, of objects in the block. */ - /* if free, the size in bytes of the whole block */ - struct hblk * hb_next; /* Link field for hblk free list */ - /* and for lists of chunks waiting to be */ - /* reclaimed. */ - struct hblk * hb_prev; /* Backwards link for free list. */ - word hb_descr; /* object descriptor for marking. See */ - /* mark.h. */ - map_entry_type * hb_map; - /* A pointer to a pointer validity map of the block. */ - /* See GC_obj_map. */ - /* Valid for all blocks with headers. */ - /* Free blocks point to GC_invalid_map. */ - unsigned char hb_obj_kind; - /* Kind of objects in the block. Each kind */ - /* identifies a mark procedure and a set of */ - /* list headers. Sometimes called regions. */ - unsigned char hb_flags; -# define IGNORE_OFF_PAGE 1 /* Ignore pointers that do not */ - /* point to the first page of */ - /* this object. */ -# define WAS_UNMAPPED 2 /* This is a free block, which has */ - /* been unmapped from the address */ - /* space. */ - /* GC_remap must be invoked on it */ - /* before it can be reallocated. */ - /* Only set with USE_MUNMAP. */ - unsigned short hb_last_reclaimed; - /* Value of GC_gc_no when block was */ - /* last allocated or swept. May wrap. */ - /* For a free block, this is maintained */ - /* only for USE_MUNMAP, and indicates */ - /* when the header was allocated, or */ - /* when the size of the block last */ - /* changed. */ -# ifdef USE_MARK_BYTES - union { - char _hb_marks[MARK_BITS_SZ]; - /* The i'th byte is 1 if the object */ - /* starting at word 2i is marked, 0 o.w. */ - word dummy; /* Force word alignment of mark bytes. */ - } _mark_byte_union; -# define hb_marks _mark_byte_union._hb_marks -# else - word hb_marks[MARK_BITS_SZ]; - /* Bit i in the array refers to the */ - /* object starting at the ith word (header */ - /* INCLUDED) in the heap block. */ - /* The lsb of word 0 is numbered 0. */ - /* Unused bits are invalid, and are */ - /* occasionally set, e.g for uncollectable */ - /* objects. */ -# endif /* !USE_MARK_BYTES */ -}; - -/* heap block body */ - -# define BODY_SZ (HBLKSIZE/sizeof(word)) - -struct hblk { - 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 */ - /* given sz (in words). */ - -/* Object free list link */ -# define obj_link(p) (*(ptr_t *)(p)) - -# define LOG_MAX_MARK_PROCS 6 -# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) - -/* Root sets. Logically private to mark_rts.c. But we don't want the */ -/* tables scanned, so we put them here. */ -/* MAX_ROOT_SETS is the maximum number of ranges that can be */ -/* registered as static roots. */ -# ifdef LARGE_CONFIG -# define MAX_ROOT_SETS 4096 -# else -# ifdef PCR -# define MAX_ROOT_SETS 1024 -# else -# if defined(MSWIN32) || defined(MSWINCE) -# define MAX_ROOT_SETS 1024 - /* Under NT, we add only written pages, which can result */ - /* in many small root sets. */ -# else -# define MAX_ROOT_SETS 256 -# endif -# endif -# endif - -# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4) -/* Maximum number of segments that can be excluded from root sets. */ - -/* - * Data structure for excluded static roots. - */ -struct exclusion { - ptr_t e_start; - ptr_t e_end; -}; - -/* Data structure for list of root sets. */ -/* We keep a hash table, so that we can filter out duplicate additions. */ -/* Under Win32, we need to do a better job of filtering overlaps, so */ -/* we resort to sequential search, and pay the price. */ -struct roots { - ptr_t r_start; - ptr_t r_end; -# if !defined(MSWIN32) && !defined(MSWINCE) - struct roots * r_next; -# endif - GC_bool r_tmp; - /* Delete before registering new dynamic libraries */ -}; - -#if !defined(MSWIN32) && !defined(MSWINCE) - /* Size of hash table index to roots. */ -# define LOG_RT_SIZE 6 -# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */ -#endif - -/* Lists of all heap blocks and free lists */ -/* as well as other random data structures */ -/* that should not be scanned by the */ -/* collector. */ -/* These are grouped together in a struct */ -/* so that they can be easily skipped by the */ -/* GC_mark routine. */ -/* The ordering is weird to make GC_malloc */ -/* faster by keeping the important fields */ -/* sufficiently close together that a */ -/* single load of a base register will do. */ -/* Scalars that could easily appear to */ -/* be pointers are also put here. */ -/* The main fields should precede any */ -/* conditionally included fields, so that */ -/* gc_inl.h will work even if a different set */ -/* of macros is defined when the client is */ -/* compiled. */ - -struct _GC_arrays { - word _heapsize; - word _max_heapsize; - word _requested_heapsize; /* Heap size due to explicit expansion */ - ptr_t _last_heap_addr; - ptr_t _prev_heap_addr; - word _large_free_bytes; - /* Total bytes contained in blocks on large object free */ - /* list. */ - word _large_allocd_bytes; - /* Total number of bytes in allocated large objects blocks. */ - /* For the purposes of this counter and the next one only, a */ - /* large object is one that occupies a block of at least */ - /* 2*HBLKSIZE. */ - word _max_large_allocd_bytes; - /* Maximum number of bytes that were ever allocated in */ - /* large object blocks. This is used to help decide when it */ - /* is safe to split up a large block. */ - word _words_allocd_before_gc; - /* Number of words allocated before this */ - /* collection cycle. */ -# ifndef SEPARATE_GLOBALS - word _words_allocd; - /* Number of words allocated during this collection cycle */ -# endif - word _words_wasted; - /* Number of words wasted due to internal fragmentation */ - /* in large objects, or due to dropping blacklisted */ - /* blocks, since last gc. Approximate. */ - word _words_finalized; - /* Approximate number of words in objects (and headers) */ - /* That became ready for finalization in the last */ - /* collection. */ - word _non_gc_bytes_at_gc; - /* Number of explicitly managed bytes of storage */ - /* at last collection. */ - 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 */ - /* heap. */ - GC_mark_proc _mark_procs[MAX_MARK_PROCS]; - /* Table of user-defined mark procedures. There is */ - /* a small number of these, which can be referenced */ - /* by DS_PROC mark descriptors. See gc_mark.h. */ - -# ifndef SEPARATE_GLOBALS - ptr_t _objfreelist[MAXOBJSZ+1]; - /* free list for objects */ - ptr_t _aobjfreelist[MAXOBJSZ+1]; - /* free list for atomic objs */ -# endif - - ptr_t _uobjfreelist[MAXOBJSZ+1]; - /* uncollectable but traced objs */ - /* objects on this and auobjfreelist */ - /* are always marked, except during */ - /* garbage collections. */ -# ifdef ATOMIC_UNCOLLECTABLE - ptr_t _auobjfreelist[MAXOBJSZ+1]; -# endif - /* uncollectable but traced objs */ - -# ifdef GATHERSTATS - word _composite_in_use; - /* Number of words in accessible composite */ - /* objects. */ - word _atomic_in_use; - /* Number of words in accessible atomic */ - /* objects. */ -# endif -# ifdef USE_MUNMAP - word _unmapped_bytes; -# endif -# ifdef MERGE_SIZES - unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)]; - /* Number of words to allocate for a given allocation request in */ - /* bytes. */ -# endif - -# ifdef STUBBORN_ALLOC - ptr_t _sobjfreelist[MAXOBJSZ+1]; -# endif - /* free list for immutable objects */ - map_entry_type * _obj_map[MAXOBJSZ+1]; - /* If not NIL, then a pointer to a map of valid */ - /* object addresses. _obj_map[sz][i] is j if the */ - /* address block_start+i is a valid pointer */ - /* to an object at block_start + */ - /* WORDS_TO_BYTES(BYTES_TO_WORDS(i) - j) */ - /* I.e. j is a word displacement from the */ - /* object beginning. */ - /* The entry is OBJ_INVALID if the corresponding */ - /* address is not a valid pointer. It is */ - /* OFFSET_TOO_BIG if the value j would be too */ - /* large to fit in the entry. (Note that the */ - /* size of these entries matters, both for */ - /* space consumption and for cache utilization. */ -# define OFFSET_TOO_BIG 0xfe -# define OBJ_INVALID 0xff -# define MAP_ENTRY(map, bytes) (map)[bytes] -# define MAP_ENTRIES HBLKSIZE -# define MAP_SIZE MAP_ENTRIES -# define CPP_MAX_OFFSET (OFFSET_TOO_BIG - 1) -# define MAX_OFFSET ((word)CPP_MAX_OFFSET) - /* The following are used only if GC_all_interior_ptrs != 0 */ -# define VALID_OFFSET_SZ \ - (CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \ - CPP_MAX_OFFSET+1 \ - : WORDS_TO_BYTES(CPP_MAXOBJSZ)+1) - char _valid_offsets[VALID_OFFSET_SZ]; - /* GC_valid_offsets[i] == TRUE ==> i */ - /* is registered as a displacement. */ -# define OFFSET_VALID(displ) \ - (GC_all_interior_pointers || GC_valid_offsets[displ]) - char _modws_valid_offsets[sizeof(word)]; - /* GC_valid_offsets[i] ==> */ - /* GC_modws_valid_offsets[i%sizeof(word)] */ -# ifdef STUBBORN_ALLOC - page_hash_table _changed_pages; - /* Stubborn object pages that were changes since last call to */ - /* GC_read_changed. */ - page_hash_table _prev_changed_pages; - /* Stubborn object pages that were changes before last call to */ - /* GC_read_changed. */ -# endif -# if defined(PROC_VDB) || defined(MPROTECT_VDB) - page_hash_table _grungy_pages; /* Pages that were dirty at last */ - /* GC_read_dirty. */ -# endif -# ifdef MPROTECT_VDB - VOLATILE page_hash_table _dirty_pages; - /* Pages dirtied since last GC_read_dirty. */ -# endif -# ifdef PROC_VDB - page_hash_table _written_pages; /* Pages ever dirtied */ -# endif -# ifdef LARGE_CONFIG -# if CPP_WORDSZ > 32 -# define MAX_HEAP_SECTS 4096 /* overflows at roughly 64 GB */ -# else -# define MAX_HEAP_SECTS 768 /* Separately added heap sections. */ -# endif -# else -# ifdef SMALL_CONFIG -# define MAX_HEAP_SECTS 128 /* Roughly 1GB */ -# else -# define MAX_HEAP_SECTS 384 /* Roughly 3GB */ -# endif -# endif - struct HeapSect { - ptr_t hs_start; word hs_bytes; - } _heap_sects[MAX_HEAP_SECTS]; -# if defined(MSWIN32) || defined(MSWINCE) - ptr_t _heap_bases[MAX_HEAP_SECTS]; - /* Start address of memory regions obtained from kernel. */ -# endif -# ifdef MSWINCE - word _heap_lengths[MAX_HEAP_SECTS]; - /* Commited lengths of memory regions obtained from kernel. */ -# endif - struct roots _static_roots[MAX_ROOT_SETS]; -# if !defined(MSWIN32) && !defined(MSWINCE) - struct roots * _root_index[RT_SIZE]; -# endif - struct exclusion _excl_table[MAX_EXCLUSIONS]; - /* Block header index; see gc_headers.h */ - bottom_index * _all_nils; - bottom_index * _top_index [TOP_SZ]; -#ifdef SAVE_CALL_CHAIN - struct callinfo _last_stack[NFRAMES]; /* Stack at last garbage collection.*/ - /* Useful for debugging mysterious */ - /* object disappearances. */ - /* In the multithreaded case, we */ - /* currently only save the calling */ - /* stack. */ -#endif -}; - -GC_API GC_FAR struct _GC_arrays GC_arrays; - -# ifndef SEPARATE_GLOBALS -# define GC_objfreelist GC_arrays._objfreelist -# define GC_aobjfreelist GC_arrays._aobjfreelist -# define GC_words_allocd GC_arrays._words_allocd -# endif -# define GC_uobjfreelist GC_arrays._uobjfreelist -# ifdef ATOMIC_UNCOLLECTABLE -# define GC_auobjfreelist GC_arrays._auobjfreelist -# endif -# define GC_sobjfreelist GC_arrays._sobjfreelist -# define GC_valid_offsets GC_arrays._valid_offsets -# define GC_modws_valid_offsets GC_arrays._modws_valid_offsets -# ifdef STUBBORN_ALLOC -# define GC_changed_pages GC_arrays._changed_pages -# define GC_prev_changed_pages GC_arrays._prev_changed_pages -# endif -# define GC_obj_map GC_arrays._obj_map -# define GC_last_heap_addr GC_arrays._last_heap_addr -# define GC_prev_heap_addr GC_arrays._prev_heap_addr -# define GC_words_wasted GC_arrays._words_wasted -# define GC_large_free_bytes GC_arrays._large_free_bytes -# define GC_large_allocd_bytes GC_arrays._large_allocd_bytes -# define GC_max_large_allocd_bytes GC_arrays._max_large_allocd_bytes -# define GC_words_finalized GC_arrays._words_finalized -# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc -# define GC_mem_freed GC_arrays._mem_freed -# define GC_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 -# define GC_heapsize GC_arrays._heapsize -# define GC_max_heapsize GC_arrays._max_heapsize -# define GC_requested_heapsize GC_arrays._requested_heapsize -# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc -# define GC_heap_sects GC_arrays._heap_sects -# define GC_last_stack GC_arrays._last_stack -# ifdef USE_MUNMAP -# define GC_unmapped_bytes GC_arrays._unmapped_bytes -# endif -# if defined(MSWIN32) || defined(MSWINCE) -# define GC_heap_bases GC_arrays._heap_bases -# endif -# ifdef MSWINCE -# define GC_heap_lengths GC_arrays._heap_lengths -# endif -# define GC_static_roots GC_arrays._static_roots -# define GC_root_index GC_arrays._root_index -# define GC_excl_table GC_arrays._excl_table -# define GC_all_nils GC_arrays._all_nils -# define GC_top_index GC_arrays._top_index -# if defined(PROC_VDB) || defined(MPROTECT_VDB) -# define GC_grungy_pages GC_arrays._grungy_pages -# endif -# ifdef MPROTECT_VDB -# define GC_dirty_pages GC_arrays._dirty_pages -# endif -# ifdef PROC_VDB -# define GC_written_pages GC_arrays._written_pages -# endif -# ifdef GATHERSTATS -# define GC_composite_in_use GC_arrays._composite_in_use -# define GC_atomic_in_use GC_arrays._atomic_in_use -# endif -# ifdef MERGE_SIZES -# define GC_size_map GC_arrays._size_map -# endif - -# define beginGC_arrays ((ptr_t)(&GC_arrays)) -# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays)) - -#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes) - -/* Object kinds: */ -# define MAXOBJKINDS 16 - -extern struct obj_kind { - ptr_t *ok_freelist; /* Array of free listheaders for this kind of object */ - /* Point either to GC_arrays or to storage allocated */ - /* with GC_scratch_alloc. */ - struct hblk **ok_reclaim_list; - /* List headers for lists of blocks waiting to be */ - /* swept. */ - word ok_descriptor; /* Descriptor template for objects in this */ - /* block. */ - GC_bool ok_relocate_descr; - /* Add object size in bytes to descriptor */ - /* template to obtain descriptor. Otherwise */ - /* template is used as is. */ - GC_bool ok_init; /* Clear objects before putting them on the free list. */ -} GC_obj_kinds[MAXOBJKINDS]; - -# define beginGC_obj_kinds ((ptr_t)(&GC_obj_kinds)) -# define endGC_obj_kinds (beginGC_obj_kinds + (sizeof GC_obj_kinds)) - -/* Variables that used to be in GC_arrays, but need to be accessed by */ -/* inline allocation code. If they were in GC_arrays, the inlined */ -/* allocation code would include GC_arrays offsets (as it did), which */ -/* introduce maintenance problems. */ - -#ifdef SEPARATE_GLOBALS - word GC_words_allocd; - /* Number of words allocated during this collection cycle */ - ptr_t GC_objfreelist[MAXOBJSZ+1]; - /* free list for NORMAL objects */ -# define beginGC_objfreelist ((ptr_t)(&GC_objfreelist)) -# define endGC_objfreelist (beginGC_objfreelist + sizeof(GC_objfreelist)) - - ptr_t GC_aobjfreelist[MAXOBJSZ+1]; - /* free list for atomic (PTRFREE) objs */ -# define beginGC_aobjfreelist ((ptr_t)(&GC_aobjfreelist)) -# define endGC_aobjfreelist (beginGC_aobjfreelist + sizeof(GC_aobjfreelist)) -#endif - -/* Predefined kinds: */ -# define PTRFREE 0 -# define NORMAL 1 -# define UNCOLLECTABLE 2 -# ifdef ATOMIC_UNCOLLECTABLE -# define AUNCOLLECTABLE 3 -# define STUBBORN 4 -# define IS_UNCOLLECTABLE(k) (((k) & ~1) == UNCOLLECTABLE) -# else -# define STUBBORN 3 -# define IS_UNCOLLECTABLE(k) ((k) == UNCOLLECTABLE) -# endif - -extern int GC_n_kinds; - -GC_API word GC_fo_entries; - -extern word GC_n_heap_sects; /* Number of separately added heap */ - /* sections. */ - -extern word GC_page_size; - -# if defined(MSWIN32) || defined(MSWINCE) - struct _SYSTEM_INFO; - extern struct _SYSTEM_INFO GC_sysinfo; - extern word GC_n_heap_bases; /* See GC_heap_bases. */ -# endif - -extern word GC_total_stack_black_listed; - /* Number of bytes on stack blacklist. */ - -extern word GC_black_list_spacing; - /* Average number of bytes between blacklisted */ - /* blocks. Approximate. */ - /* Counts only blocks that are */ - /* "stack-blacklisted", i.e. that are */ - /* problematic in the interior of an object. */ - -extern map_entry_type * GC_invalid_map; - /* Pointer to the nowhere valid hblk map */ - /* Blocks pointing to this map are free. */ - -extern struct hblk * GC_hblkfreelist[]; - /* List of completely empty heap blocks */ - /* Linked through hb_next field of */ - /* header structure associated with */ - /* block. */ - -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; - /* Dirty bits are being maintained, */ - /* either for incremental collection, */ - /* or to limit the root set. */ - -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)) -# endif - - -/* Marks are in a reserved area in */ -/* each heap block. Each word has one mark bit associated */ -/* with it. Only those corresponding to the beginning of an */ -/* object are used. */ - -/* Set mark bit correctly, even if mark bits may be concurrently */ -/* accessed. */ -#ifdef PARALLEL_MARK -# define OR_WORD(addr, bits) \ - { word old; \ - do { \ - old = *((volatile word *)addr); \ - } while (!GC_compare_and_exchange((addr), old, old | (bits))); \ - } -# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \ - { word old; \ - word my_bits = (bits); \ - do { \ - old = *((volatile word *)addr); \ - if (old & my_bits) goto exit_label; \ - } while (!GC_compare_and_exchange((addr), old, old | my_bits)); \ - } -#else -# define OR_WORD(addr, bits) *(addr) |= (bits) -# define OR_WORD_EXIT_IF_SET(addr, bits, exit_label) \ - { \ - word old = *(addr); \ - word my_bits = (bits); \ - if (old & my_bits) goto exit_label; \ - *(addr) = (old | my_bits); \ - } -#endif - -/* Mark bit operations */ - -/* - * Retrieve, set, clear the mark bit corresponding - * to the nth word in a given heap block. - * - * (Recall that bit n corresponds to object beginning at word n - * relative to the beginning of the block, including unused words) - */ - -#ifdef USE_MARK_BYTES -# define mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n) >> 1]) -# define set_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 1 -# define clear_mark_bit_from_hdr(hhdr,n) ((hhdr)->hb_marks[(n)>>1]) = 0 -#else /* !USE_MARK_BYTES */ -# define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \ - >> (modWORDSZ(n))) & (word)1) -# define set_mark_bit_from_hdr(hhdr,n) \ - OR_WORD((hhdr)->hb_marks+divWORDSZ(n), \ - (word)1 << modWORDSZ(n)) -# define clear_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \ - &= ~((word)1 << modWORDSZ(n)) -#endif /* !USE_MARK_BYTES */ - -/* Important internal collector routines */ - -ptr_t GC_approx_sp GC_PROTO((void)); - -GC_bool GC_should_collect GC_PROTO((void)); - -void GC_apply_to_all_blocks GC_PROTO(( \ - void (*fn) GC_PROTO((struct hblk *h, word client_data)), \ - word client_data)); - /* Invoke fn(hbp, client_data) for each */ - /* allocated heap block. */ -struct hblk * GC_next_used_block GC_PROTO((struct hblk * h)); - /* Return first in-use block >= h */ -struct hblk * GC_prev_block GC_PROTO((struct hblk * h)); - /* Return last block <= h. Returned block */ - /* is managed by GC, but may or may not be in */ - /* use. */ -void GC_mark_init GC_PROTO((void)); -void GC_clear_marks GC_PROTO((void)); /* Clear mark bits for all heap objects. */ -void GC_invalidate_mark_state GC_PROTO((void)); - /* Tell the marker that marked */ - /* objects may point to unmarked */ - /* ones, and roots may point to */ - /* unmarked objects. */ - /* Reset mark stack. */ -GC_bool GC_mark_stack_empty GC_PROTO((void)); -GC_bool GC_mark_some GC_PROTO((ptr_t cold_gc_frame)); - /* Perform about one pages worth of marking */ - /* work of whatever kind is needed. Returns */ - /* quickly if no collection is in progress. */ - /* Return TRUE if mark phase finished. */ -void GC_initiate_gc GC_PROTO((void)); - /* initiate collection. */ - /* If the mark state is invalid, this */ - /* becomes full colleection. Otherwise */ - /* it's partial. */ -void GC_push_all GC_PROTO((ptr_t bottom, ptr_t top)); - /* Push everything in a range */ - /* onto mark stack. */ -void GC_push_selected GC_PROTO(( \ - ptr_t bottom, \ - ptr_t top, \ - int (*dirty_fn) GC_PROTO((struct hblk *h)), \ - void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top)) )); - /* Push all pages h in [b,t) s.t. */ - /* select_fn(h) != 0 onto mark stack. */ -#ifndef SMALL_CONFIG - void GC_push_conditional GC_PROTO((ptr_t b, ptr_t t, GC_bool all)); -#else -# define GC_push_conditional(b, t, all) GC_push_all(b, t) -#endif - /* Do either of the above, depending */ - /* on the third arg. */ -void GC_push_all_stack GC_PROTO((ptr_t b, ptr_t t)); - /* As above, but consider */ - /* interior pointers as valid */ -void GC_push_all_eager GC_PROTO((ptr_t b, ptr_t t)); - /* Same as GC_push_all_stack, but */ - /* ensures that stack is scanned */ - /* immediately, not just scheduled */ - /* for scanning. */ -#ifndef THREADS - void GC_push_all_stack_partially_eager GC_PROTO(( \ - ptr_t bottom, ptr_t top, ptr_t cold_gc_frame )); - /* Similar to GC_push_all_eager, but only the */ - /* part hotter than cold_gc_frame is scanned */ - /* immediately. Needed to ensure that callee- */ - /* save registers are not missed. */ -#else - /* In the threads case, we push part of the current thread stack */ - /* with GC_push_all_eager when we push the registers. This gets the */ - /* callee-save registers that may disappear. The remainder of the */ - /* stacks are scheduled for scanning in *GC_push_other_roots, which */ - /* is thread-package-specific. */ -#endif -void GC_push_current_stack GC_PROTO((ptr_t cold_gc_frame)); - /* Push enough of the current stack eagerly to */ - /* ensure that callee-save registers saved in */ - /* GC frames are scanned. */ - /* In the non-threads case, schedule entire */ - /* stack for scanning. */ -void GC_push_roots GC_PROTO((GC_bool all, ptr_t cold_gc_frame)); - /* Push all or dirty roots. */ -extern void (*GC_push_other_roots) GC_PROTO((void)); - /* Push system or application specific roots */ - /* onto the mark stack. In some environments */ - /* (e.g. threads environments) this is */ - /* predfined to be non-zero. A client supplied */ - /* replacement should also call the original */ - /* function. */ -extern void GC_push_gc_structures GC_PROTO((void)); - /* Push GC internal roots. These are normally */ - /* included in the static data segment, and */ - /* Thus implicitly pushed. But we must do this */ - /* explicitly if normal root processing is */ - /* disabled. Calls the following: */ - extern void GC_push_finalizer_structures GC_PROTO((void)); - extern void GC_push_stubborn_structures GC_PROTO((void)); -# ifdef THREADS - extern void GC_push_thread_structures GC_PROTO((void)); -# endif -extern void (*GC_start_call_back) GC_PROTO((void)); - /* Called at start of full collections. */ - /* Not called if 0. Called with allocation */ - /* lock held. */ - /* 0 by default. */ -# if defined(USE_GENERIC_PUSH_REGS) - void GC_generic_push_regs GC_PROTO((ptr_t cold_gc_frame)); -# else - void GC_push_regs GC_PROTO((void)); -# endif - /* Push register contents onto mark stack. */ - /* If NURSERY is defined, the default push */ - /* action can be overridden with GC_push_proc */ - -# ifdef NURSERY - extern void (*GC_push_proc)(ptr_t); -# endif -# if defined(MSWIN32) || defined(MSWINCE) - void __cdecl GC_push_one GC_PROTO((word p)); -# else - void GC_push_one GC_PROTO((word p)); - /* If p points to an object, mark it */ - /* and push contents on the mark stack */ - /* Pointer recognition test always */ - /* accepts interior pointers, i.e. this */ - /* is appropriate for pointers found on */ - /* stack. */ -# endif -# if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS) - void GC_mark_and_push_stack GC_PROTO((word p, ptr_t source)); - /* Ditto, omits plausibility test */ -# else - void GC_mark_and_push_stack GC_PROTO((word p)); -# endif -void GC_push_marked GC_PROTO((struct hblk * h, hdr * hhdr)); - /* Push contents of all marked objects in h onto */ - /* mark stack. */ -#ifdef SMALL_CONFIG -# define GC_push_next_marked_dirty(h) GC_push_next_marked(h) -#else - struct hblk * GC_push_next_marked_dirty GC_PROTO((struct hblk * h)); - /* Invoke GC_push_marked on next dirty block above h. */ - /* Return a pointer just past the end of this block. */ -#endif /* !SMALL_CONFIG */ -struct hblk * GC_push_next_marked GC_PROTO((struct hblk * h)); - /* Ditto, but also mark from clean pages. */ -struct hblk * GC_push_next_marked_uncollectable GC_PROTO((struct hblk * h)); - /* Ditto, but mark only from uncollectable pages. */ -GC_bool GC_stopped_mark GC_PROTO((GC_stop_func stop_func)); - /* Stop world and mark from all roots */ - /* and rescuers. */ -void GC_clear_hdr_marks GC_PROTO((hdr * hhdr)); - /* Clear the mark bits in a header */ -void GC_set_hdr_marks GC_PROTO((hdr * hhdr)); - /* Set the mark bits in a header */ -void GC_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)); -GC_bool GC_is_static_root GC_PROTO((ptr_t p)); - /* Is the address p in one of the registered static */ - /* root sections? */ -# if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION) -GC_bool GC_is_tmp_root GC_PROTO((ptr_t p)); - /* Is the address p in one of the temporary static */ - /* root sections? */ -# endif -void GC_register_dynamic_libraries GC_PROTO((void)); - /* Add dynamic library data sections to the root set. */ - -/* Machine dependent startup routines */ -ptr_t GC_get_stack_base GC_PROTO((void)); /* Cold end of stack */ -#ifdef IA64 - ptr_t GC_get_register_stack_base GC_PROTO((void)); - /* Cold end of register stack. */ -#endif -void GC_register_data_segments GC_PROTO((void)); - -/* Black listing: */ -void GC_bl_init GC_PROTO((void)); -# ifdef PRINT_BLACK_LIST - void GC_add_to_black_list_normal GC_PROTO((word p, ptr_t source)); - /* Register bits as a possible future false */ - /* reference from the heap or static data */ -# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ - if (GC_all_interior_pointers) { \ - GC_add_to_black_list_stack(bits, (ptr_t)(source)); \ - } else { \ - GC_add_to_black_list_normal(bits, (ptr_t)(source)); \ - } -# else - void GC_add_to_black_list_normal GC_PROTO((word p)); -# define GC_ADD_TO_BLACK_LIST_NORMAL(bits, source) \ - if (GC_all_interior_pointers) { \ - GC_add_to_black_list_stack(bits); \ - } else { \ - GC_add_to_black_list_normal(bits); \ - } -# endif - -# ifdef PRINT_BLACK_LIST - void GC_add_to_black_list_stack GC_PROTO((word p, ptr_t source)); -# else - void GC_add_to_black_list_stack GC_PROTO((word p)); -# endif -struct hblk * GC_is_black_listed GC_PROTO((struct hblk * h, word len)); - /* If there are likely to be false references */ - /* to a block starting at h of the indicated */ - /* length, then return the next plausible */ - /* starting location for h that might avoid */ - /* these false references. */ -void GC_promote_black_lists GC_PROTO((void)); - /* Declare an end to a black listing phase. */ -void GC_unpromote_black_lists GC_PROTO((void)); - /* Approximately undo the effect of the above. */ - /* This actually loses some information, but */ - /* only in a reasonably safe way. */ -word GC_number_stack_black_listed GC_PROTO(( \ - struct hblk *start, struct hblk *endp1)); - /* Return the number of (stack) blacklisted */ - /* blocks in the range for statistical */ - /* purposes. */ - -ptr_t GC_scratch_alloc GC_PROTO((word bytes)); - /* GC internal memory allocation for */ - /* small objects. Deallocation is not */ - /* possible. */ - -/* Heap block layout maps: */ -void GC_invalidate_map GC_PROTO((hdr * hhdr)); - /* Remove the object map associated */ - /* with the block. This identifies */ - /* the block as invalid to the mark */ - /* routines. */ -GC_bool GC_add_map_entry GC_PROTO((word sz)); - /* Add a heap block map for objects of */ - /* size sz to obj_map. */ - /* Return FALSE on failure. */ -void GC_register_displacement_inner GC_PROTO((word offset)); - /* Version of GC_register_displacement */ - /* that assumes lock is already held */ - /* and signals are already disabled. */ - -/* hblk allocation: */ -void GC_new_hblk GC_PROTO((word size_in_words, int kind)); - /* Allocate a new heap block, and build */ - /* a free list in it. */ - -ptr_t GC_build_fl GC_PROTO((struct hblk *h, word sz, - GC_bool clear, ptr_t list)); - /* Build a free list for objects of */ - /* size sz in block h. Append list to */ - /* end of the free lists. Possibly */ - /* clear objects on the list. Normally */ - /* called by GC_new_hblk, but also */ - /* called explicitly without GC lock. */ - -struct hblk * GC_allochblk GC_PROTO(( \ - word size_in_words, int kind, unsigned flags)); - /* Allocate a heap block, inform */ - /* the marker that block is valid */ - /* for objects of indicated size. */ - -ptr_t GC_alloc_large GC_PROTO((word lw, int k, unsigned flags)); - /* Allocate a large block of size lw words. */ - /* The block is not cleared. */ - /* Flags is 0 or IGNORE_OFF_PAGE. */ - /* Calls GC_allchblk to do the actual */ - /* allocation, but also triggers GC and/or */ - /* heap expansion as appropriate. */ - /* Does not update GC_words_allocd, but does */ - /* other accounting. */ - -ptr_t GC_alloc_large_and_clear GC_PROTO((word lw, int k, unsigned flags)); - /* As above, but clear block if appropriate */ - /* for kind k. */ - -void GC_freehblk GC_PROTO((struct hblk * p)); - /* Deallocate a heap block and mark it */ - /* as invalid. */ - -/* Misc GC: */ -void GC_init_inner GC_PROTO((void)); -GC_bool GC_expand_hp_inner GC_PROTO((word n)); -void GC_start_reclaim GC_PROTO((int abort_if_found)); - /* Restore unmarked objects to free */ - /* lists, or (if abort_if_found is */ - /* TRUE) report them. */ - /* Sweeping of small object pages is */ - /* largely deferred. */ -void GC_continue_reclaim GC_PROTO((word sz, int kind)); - /* Sweep pages of the given size and */ - /* kind, as long as possible, and */ - /* as long as the corr. free list is */ - /* empty. */ -void GC_reclaim_or_delete_all GC_PROTO((void)); - /* Arrange for all reclaim lists to be */ - /* empty. Judiciously choose between */ - /* sweeping and discarding each page. */ -GC_bool GC_reclaim_all GC_PROTO((GC_stop_func stop_func, GC_bool ignore_old)); - /* Reclaim all blocks. Abort (in a */ - /* consistent state) if f returns TRUE. */ -GC_bool GC_block_empty GC_PROTO((hdr * hhdr)); - /* Block completely unmarked? */ -GC_bool GC_never_stop_func GC_PROTO((void)); - /* Returns FALSE. */ -GC_bool GC_try_to_collect_inner GC_PROTO((GC_stop_func f)); - - /* Collect; caller must have acquired */ - /* lock and disabled signals. */ - /* Collection is aborted if f returns */ - /* TRUE. Returns TRUE if it completes */ - /* successfully. */ -# define GC_gcollect_inner() \ - (void) GC_try_to_collect_inner(GC_never_stop_func) -void GC_finish_collection GC_PROTO((void)); - /* Finish collection. Mark bits are */ - /* consistent and lock is still held. */ -GC_bool GC_collect_or_expand GC_PROTO(( \ - word needed_blocks, GC_bool ignore_off_page)); - /* Collect or expand heap in an attempt */ - /* make the indicated number of free */ - /* blocks available. Should be called */ - /* until the blocks are available or */ - /* until it fails by returning FALSE. */ - -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 */ - /* GC_init */ -#endif - -void GC_collect_a_little_inner GC_PROTO((int n)); - /* Do n units worth of garbage */ - /* collection work, if appropriate. */ - /* A unit is an amount appropriate for */ - /* HBLKSIZE bytes of allocation. */ -ptr_t GC_generic_malloc GC_PROTO((word lb, int k)); - /* Allocate an object of the given */ - /* kind. By default, there are only */ - /* a few kinds: composite(pointerfree), */ - /* atomic, uncollectable, etc. */ - /* We claim it's possible for clever */ - /* client code that understands GC */ - /* internals to add more, e.g. to */ - /* communicate object layout info */ - /* to the collector. */ -ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k)); - /* As above, but pointers past the */ - /* first page of the resulting object */ - /* are ignored. */ -ptr_t GC_generic_malloc_inner GC_PROTO((word lb, int k)); - /* Ditto, but I already hold lock, etc. */ -ptr_t GC_generic_malloc_words_small GC_PROTO((size_t lw, int k)); - /* As above, but size in units of words */ - /* Bypasses MERGE_SIZES. Assumes */ - /* words <= MAXOBJSZ. */ -ptr_t GC_generic_malloc_inner_ignore_off_page GC_PROTO((size_t lb, int k)); - /* Allocate an object, where */ - /* the client guarantees that there */ - /* will always be a pointer to the */ - /* beginning of the object while the */ - /* object is live. */ -ptr_t GC_allocobj GC_PROTO((word sz, int kind)); - /* Make the indicated */ - /* free list nonempty, and return its */ - /* head. */ - -void GC_init_headers GC_PROTO((void)); -struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h)); - /* Install a header for block h. */ - /* Return 0 on failure, or the header */ - /* otherwise. */ -GC_bool GC_install_counts GC_PROTO((struct hblk * h, word sz)); - /* Set up forwarding counts for block */ - /* h of size sz. */ - /* Return FALSE on failure. */ -void GC_remove_header GC_PROTO((struct hblk * h)); - /* Remove the header for block h. */ -void GC_remove_counts GC_PROTO((struct hblk * h, word sz)); - /* Remove forwarding counts for h. */ -hdr * GC_find_header GC_PROTO((ptr_t h)); /* Debugging only. */ - -void GC_finalize GC_PROTO((void)); - /* Perform all indicated finalization actions */ - /* on unmarked objects. */ - /* Unreachable finalizable objects are enqueued */ - /* for processing by GC_invoke_finalizers. */ - /* Invoked with lock. */ - -void GC_notify_or_invoke_finalizers GC_PROTO((void)); - /* If GC_finalize_on_demand is not set, invoke */ - /* eligible finalizers. Otherwise: */ - /* Call *GC_finalizer_notifier if there are */ - /* finalizers to be run, and we haven't called */ - /* this procedure yet this GC cycle. */ - -void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes)); - /* Add a HBLKSIZE aligned chunk to the heap. */ - -void GC_print_obj GC_PROTO((ptr_t p)); - /* P points to somewhere inside an object with */ - /* debugging info. Print a human readable */ - /* description of the object to stderr. */ -extern void (*GC_check_heap) GC_PROTO((void)); - /* Check that all objects in the heap with */ - /* debugging info are intact. */ - /* 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 */ - /* referred to by p. */ - -extern GC_bool GC_print_stats; /* Produce at least some logging output */ - /* Set from environment variable. */ - -/* Macros used for collector internal allocation. */ -/* These assume the collector lock is held. */ -#ifdef DBG_HDRS_ALL - extern GC_PTR GC_debug_generic_malloc_inner(size_t lb, int k); - extern GC_PTR GC_debug_generic_malloc_inner_ignore_off_page(size_t lb, - int k); -# define GC_INTERNAL_MALLOC GC_debug_generic_malloc_inner -# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \ - GC_debug_generic_malloc_inner_ignore_off_page -# ifdef THREADS -# define GC_INTERNAL_FREE GC_debug_free_inner -# else -# define GC_INTERNAL_FREE GC_debug_free -# endif -#else -# define GC_INTERNAL_MALLOC GC_generic_malloc_inner -# define GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE \ - GC_generic_malloc_inner_ignore_off_page -# ifdef THREADS -# define GC_INTERNAL_FREE GC_free_inner -# else -# define GC_INTERNAL_FREE GC_free -# endif -#endif - -/* Memory unmapping: */ -#ifdef USE_MUNMAP - void GC_unmap_old(void); - void GC_merge_unmapped(void); - void GC_unmap(ptr_t start, word bytes); - void GC_remap(ptr_t start, word bytes); - void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2); -#endif - -/* Virtual dirty bit implementation: */ -/* Each implementation exports the following: */ -void GC_read_dirty GC_PROTO((void)); - /* Retrieve dirty bits. */ -GC_bool GC_page_was_dirty GC_PROTO((struct hblk *h)); - /* Read retrieved dirty bits. */ -GC_bool GC_page_was_ever_dirty GC_PROTO((struct hblk *h)); - /* Could the page contain valid heap pointers? */ -void GC_is_fresh GC_PROTO((struct hblk *h, word n)); - /* Assert the region currently contains no */ - /* valid pointers. */ -void GC_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: */ -GC_API GC_bool GC_is_marked GC_PROTO((ptr_t p)); -void GC_clear_mark_bit GC_PROTO((ptr_t p)); -void GC_set_mark_bit GC_PROTO((ptr_t p)); - -/* Stubborn objects: */ -void GC_read_changed GC_PROTO((void)); /* Analogous to GC_read_dirty */ -GC_bool GC_page_was_changed GC_PROTO((struct hblk * h)); - /* Analogous to GC_page_was_dirty */ -void GC_clean_changing_list GC_PROTO((void)); - /* Collect obsolete changing list entries */ -void GC_stubborn_init GC_PROTO((void)); - -/* Debugging print routines: */ -void GC_print_block_list GC_PROTO((void)); -void GC_print_hblkfreelist GC_PROTO((void)); -void GC_print_heap_sects GC_PROTO((void)); -void GC_print_static_roots GC_PROTO((void)); -void GC_dump GC_PROTO((void)); - -#ifdef KEEP_BACK_PTRS - void GC_store_back_pointer(ptr_t source, ptr_t dest); - void GC_marked_for_finalization(ptr_t dest); -# define GC_STORE_BACK_PTR(source, dest) GC_store_back_pointer(source, dest) -# define GC_MARKED_FOR_FINALIZATION(dest) GC_marked_for_finalization(dest) -#else -# define GC_STORE_BACK_PTR(source, dest) -# define GC_MARKED_FOR_FINALIZATION(dest) -#endif - -/* Make arguments appear live to compiler */ -# ifdef __WATCOMC__ - void GC_noop(void*, ...); -# else -# ifdef __DMC__ - GC_API void GC_noop(...); -# else - GC_API void GC_noop(); -# endif -# endif - -void GC_noop1 GC_PROTO((word)); - -/* Logging and diagnostic output: */ -GC_API void GC_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long)); - /* A version of printf that doesn't allocate, */ - /* is restricted to long arguments, and */ - /* (unfortunately) doesn't use varargs for */ - /* portability. Restricted to 6 args and */ - /* 1K total output length. */ - /* (We use sprintf. Hopefully that doesn't */ - /* allocate for long arguments.) */ -# define GC_printf0(f) GC_printf(f, 0l, 0l, 0l, 0l, 0l, 0l) -# define GC_printf1(f,a) GC_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l) -# define GC_printf2(f,a,b) GC_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l) -# define GC_printf3(f,a,b,c) GC_printf(f, (long)a, (long)b, (long)c, 0l, 0l, 0l) -# define GC_printf4(f,a,b,c,d) GC_printf(f, (long)a, (long)b, (long)c, \ - (long)d, 0l, 0l) -# define GC_printf5(f,a,b,c,d,e) GC_printf(f, (long)a, (long)b, (long)c, \ - (long)d, (long)e, 0l) -# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \ - (long)d, (long)e, (long)g) - -GC_API void GC_err_printf GC_PROTO((GC_CONST char * format, long, long, long, long, long, long)); -# define GC_err_printf0(f) GC_err_puts(f) -# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l) -# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l) -# define GC_err_printf3(f,a,b,c) GC_err_printf(f, (long)a, (long)b, (long)c, \ - 0l, 0l, 0l) -# define GC_err_printf4(f,a,b,c,d) GC_err_printf(f, (long)a, (long)b, \ - (long)c, (long)d, 0l, 0l) -# define GC_err_printf5(f,a,b,c,d,e) GC_err_printf(f, (long)a, (long)b, \ - (long)c, (long)d, \ - (long)e, 0l) -# define GC_err_printf6(f,a,b,c,d,e,g) GC_err_printf(f, (long)a, (long)b, \ - (long)c, (long)d, \ - (long)e, (long)g) - /* Ditto, writes to stderr. */ - -void GC_err_puts GC_PROTO((GC_CONST char *s)); - /* Write s to stderr, don't buffer, don't add */ - /* newlines, don't ... */ - -#if defined(LINUX) && !defined(SMALL_CONFIG) - void GC_err_write GC_PROTO((GC_CONST char *buf, size_t len)); - /* Write buf to stderr, don't buffer, don't add */ - /* newlines, don't ... */ -#endif - - -# ifdef GC_ASSERTIONS -# define GC_ASSERT(expr) if(!(expr)) {\ - GC_err_printf2("Assertion failure: %s:%ld\n", \ - __FILE__, (unsigned long)__LINE__); \ - ABORT("assertion failure"); } -# else -# define GC_ASSERT(expr) -# 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 */ - /* than the main garbage collector lock; standard pthreads-based */ - /* implementations should be sufficient. */ - - /* The mark lock and condition variable. If the GC lock is also */ - /* acquired, the GC lock must be acquired first. The mark lock is */ - /* used to both protect some variables used by the parallel */ - /* marker, and to protect GC_fl_builder_count, below. */ - /* GC_notify_all_marker() is called when */ - /* the state of the parallel marker changes */ - /* in some significant way (see gc_mark.h for details). The */ - /* latter set of events includes incrementing GC_mark_no. */ - /* GC_notify_all_builder() is called when GC_fl_builder_count */ - /* reaches 0. */ - - extern void GC_acquire_mark_lock(); - extern void GC_release_mark_lock(); - extern void GC_notify_all_builder(); - /* extern void GC_wait_builder(); */ - extern void GC_wait_for_reclaim(); - - extern word GC_fl_builder_count; /* Protected by mark lock. */ -# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */ -# ifdef PARALLEL_MARK - extern void GC_notify_all_marker(); - extern void GC_wait_marker(); - extern word GC_mark_no; /* Protected by mark lock. */ - - extern void GC_help_marker(word my_mark_no); - /* Try to help out parallel marker for mark cycle */ - /* my_mark_no. Returns if the mark cycle finishes or */ - /* was already done, or there was nothing to do for */ - /* some other reason. */ -# endif /* PARALLEL_MARK */ - -# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) - /* We define the thread suspension signal here, so that we can refer */ - /* to it in the dirty bit implementation, if necessary. Ideally we */ - /* would allocate a (real-time ?) signal using the standard mechanism.*/ - /* unfortunately, there is no standard mechanism. (There is one */ - /* 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) || 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. */ -# define SIG_SUSPEND SIGLOST -# else - /* Linuxthreads itself uses SIGUSR1 and SIGUSR2. */ -# define SIG_SUSPEND SIGPWR -# endif -# else /* !GC_LINUX_THREADS */ -# if defined(_SIGRTMIN) -# define SIG_SUSPEND _SIGRTMIN + 6 -# else -# define SIG_SUSPEND SIGRTMIN + 6 -# endif -# endif -# endif /* !SIG_SUSPEND */ - -# endif - -# endif /* GC_PRIVATE_H */ diff --git a/gc/include/private/gcconfig.h b/gc/include/private/gcconfig.h deleted file mode 100644 index c3adaa2..0000000 --- a/gc/include/private/gcconfig.h +++ /dev/null @@ -1,1986 +0,0 @@ -/* - * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. - * Copyright (c) 1996 by Silicon Graphics. All rights reserved. - * Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved. - * - * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED - * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. - * - * Permission is hereby granted to use or copy this program - * for any purpose, provided the above notices are retained on all copies. - * Permission to modify the code and to distribute modified code is granted, - * provided the above notices are retained, and a notice that the code was - * modified is included with the above copyright notice. - */ - -#ifndef GCCONFIG_H - -# define GCCONFIG_H - -/* Machine dependent parameters. Some tuning parameters can be found */ -/* near the top of gc_private.h. */ - -/* Machine specific parts contributed by various people. See README file. */ - -/* First a unified test for Linux: */ -# if defined(linux) || defined(__linux__) -# define LINUX -# endif - -/* And one for NetBSD: */ -# if defined(__NetBSD__) -# define NETBSD -# endif - -/* And one for OpenBSD: */ -# if defined(__OpenBSD__) -# 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 -# define mach_type_known -# endif -# if defined(hp9000s300) -# define M68K -# define HP -# define mach_type_known -# endif -# if defined(OPENBSD) && defined(m68k) -# define M68K -# define mach_type_known -# endif -# if defined(OPENBSD) && defined(__sparc__) -# define SPARC -# define mach_type_known -# endif -# if defined(NETBSD) && defined(m68k) -# define M68K -# define mach_type_known -# endif -# if defined(NETBSD) && defined(__powerpc__) -# define POWERPC -# define mach_type_known -# endif -# if defined(NETBSD) && defined(__arm32__) -# define ARM32 -# define mach_type_known -# endif -# if defined(vax) -# define VAX -# ifdef ultrix -# define ULTRIX -# else -# define BSD -# endif -# define mach_type_known -# endif -# if defined(mips) || defined(__mips) || defined(_mips) -# define MIPS -# if defined(nec_ews) || defined(_nec_ews) -# define EWS4800 -# endif -# if !defined(LINUX) && !defined(EWS4800) -# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__) -# define ULTRIX -# else -# if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) \ - || defined(__SYSTYPE_SVR4__) -# define IRIX5 /* or IRIX 6.X */ -# else -# define RISCOS /* or IRIX 4.X */ -# endif -# endif -# endif /* !LINUX */ -# if defined(__NetBSD__) && defined(__MIPSEL__) -# undef ULTRIX -# 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 -# define mach_type_known -# endif -# if defined(sun) && (defined(i386) || defined(__i386__)) -# define I386 -# define SUNOS5 -# define mach_type_known -# endif -# if (defined(__OS2__) || defined(__EMX__)) && defined(__32BIT__) -# define I386 -# define OS2 -# define mach_type_known -# endif -# if defined(ibm032) -# define RT -# define mach_type_known -# endif -# if defined(sun) && (defined(sparc) || defined(__sparc)) -# define SPARC - /* Test for SunOS 5.x */ -# include <errno.h> -# ifdef ECHRNG -# define SUNOS5 -# else -# define SUNOS4 -# endif -# define mach_type_known -# endif -# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \ - && !defined(__OpenBSD__) && !(__NetBSD__) -# define SPARC -# define DRSNX -# define mach_type_known -# endif -# if defined(_IBMR2) -# define RS6000 -# define mach_type_known -# endif -# if defined(__NetBSD__) && defined(__sparc__) -# define SPARC -# define mach_type_known -# endif -# if defined(_M_XENIX) && defined(_M_SYSV) && defined(_M_I386) - /* The above test may need refinement */ -# define I386 -# if defined(_SCO_ELF) -# define SCO_ELF -# else -# define SCO -# endif -# define mach_type_known -# endif -# if defined(_AUX_SOURCE) -# define M68K -# define SYSV -# define mach_type_known -# endif -# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \ - || defined(hppa) || defined(__hppa__) -# define HP_PA -# ifndef LINUX -# define HPUX -# endif -# define mach_type_known -# endif -# if defined(__ia64) && defined(_HPUX_SOURCE) -# define IA64 -# define HPUX -# define mach_type_known -# endif -# if defined(__BEOS__) && defined(_X86_) -# define I386 -# define BEOS -# define mach_type_known -# endif -# if defined(LINUX) && (defined(i386) || defined(__i386__)) -# define I386 -# define mach_type_known -# endif -# if defined(LINUX) && (defined(__ia64__) || defined(__ia64)) -# 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 -# endif -# if defined(LINUX) && defined(__mc68000__) -# define M68K -# define mach_type_known -# endif -# if defined(LINUX) && (defined(sparc) || defined(__sparc__)) -# define SPARC -# define mach_type_known -# endif -# if defined(LINUX) && defined(__arm__) -# define ARM32 -# define mach_type_known -# endif -# if defined(LINUX) && defined(__sh__) -# define SH -# define mach_type_known -# endif -# if defined(__alpha) || defined(__alpha__) -# define ALPHA -# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) && !defined(FREEBSD) -# define OSF1 /* a.k.a Digital Unix */ -# endif -# define mach_type_known -# endif -# if defined(_AMIGA) && !defined(AMIGA) -# define AMIGA -# endif -# ifdef AMIGA -# define M68K -# define mach_type_known -# endif -# if defined(THINK_C) || defined(__MWERKS__) && !defined(__powerc) -# define M68K -# define MACOS -# define mach_type_known -# endif -# 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 POWERPC -# define mach_type_known -# endif -# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__) -# define MACOSX -# define I386 - --> Not really supported, but at least we recognize it. -# endif -# if defined(NeXT) && defined(mc68000) -# define M68K -# define NEXT -# define mach_type_known -# endif -# if defined(NeXT) && (defined(i386) || defined(__i386__)) -# define I386 -# define NEXT -# define mach_type_known -# endif -# if defined(__OpenBSD__) && (defined(i386) || defined(__i386__)) -# define I386 -# define OPENBSD -# define mach_type_known -# endif -# if defined(FREEBSD) && (defined(i386) || defined(__i386__)) -# define I386 -# define mach_type_known -# endif -# if defined(__NetBSD__) && (defined(i386) || defined(__i386__)) -# define I386 -# define mach_type_known -# endif -# if defined(bsdi) && (defined(i386) || defined(__i386__)) -# define I386 -# define BSDI -# define mach_type_known -# endif -# if !defined(mach_type_known) && defined(__386BSD__) -# define I386 -# define THREE86BSD -# define mach_type_known -# endif -# if defined(_CX_UX) && defined(_M88K) -# define M88K -# define CX_UX -# define mach_type_known -# endif -# if defined(DGUX) && defined(m88k) -# define M88K - /* DGUX defined */ -# define mach_type_known -# endif -# if defined(_WIN32_WCE) - /* SH3, SH4, MIPS already defined for corresponding architectures */ -# if defined(SH3) || defined(SH4) -# define SH -# endif -# if defined(x86) -# define I386 -# endif -# if defined(ARM) -# define ARM32 -# endif -# define MSWINCE -# define mach_type_known -# else -# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \ - || defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) -# define I386 -# define MSWIN32 /* or Win32s */ -# define mach_type_known -# endif -# endif -# if defined(__DJGPP__) -# define I386 -# ifndef DJGPP -# define DJGPP /* MSDOS running the DJGPP port of GCC */ -# endif -# define mach_type_known -# endif -# if defined(__CYGWIN32__) || defined(__CYGWIN__) -# define I386 -# define CYGWIN32 -# define mach_type_known -# endif -# if defined(__MINGW32__) -# define I386 -# define MSWIN32 -# define mach_type_known -# endif -# if defined(__BORLANDC__) -# define I386 -# define MSWIN32 -# define mach_type_known -# endif -# if defined(_UTS) && !defined(mach_type_known) -# define S370 -# define UTS4 -# define mach_type_known -# endif -# if defined(__pj__) -# define PJ -# define mach_type_known -# endif -# if defined(__embedded__) && defined(PPC) -# define POWERPC -# define NOSYS -# define mach_type_known -# endif -/* Ivan Demakov */ -# if defined(__WATCOMC__) && defined(__386__) -# define I386 -# if !defined(OS2) && !defined(MSWIN32) && !defined(DOS4GW) -# if defined(__OS2__) -# define OS2 -# else -# if defined(__WINDOWS_386__) || defined(__NT__) -# define MSWIN32 -# else -# define DOS4GW -# endif -# endif -# endif -# define mach_type_known -# endif -# if defined(__s390__) && defined(LINUX) -# define S370 -# define mach_type_known -# endif -# if defined(__GNU__) -# if defined(__i386__) -/* The Debian Hurd running on generic PC */ -# define HURD -# define I386 -# define mach_type_known -# endif -# endif - -/* Feel free to add more clauses here */ - -/* Or manually define the machine type here. A machine type is */ -/* characterized by the architecture. Some */ -/* machine types are further subdivided by OS. */ -/* the macros ULTRIX, RISCOS, and BSD to distinguish. */ -/* Note that SGI IRIX is treated identically to RISCOS. */ -/* SYSV on an M68K actually means A/UX. */ -/* The distinction in these cases is usually the stack starting address */ -# ifndef mach_type_known - --> unknown machine type -# endif - /* Mapping is: M68K ==> Motorola 680X0 */ - /* (SUNOS4,HP,NEXT, and SYSV (A/UX), */ - /* MACOS and AMIGA variants) */ - /* I386 ==> Intel 386 */ - /* (SEQUENT, OS2, SCO, LINUX, NETBSD, */ - /* FREEBSD, THREE86BSD, MSWIN32, */ - /* BSDI,SUNOS5, NEXT, other variants) */ - /* NS32K ==> Encore Multimax */ - /* MIPS ==> R2000 or R3000 */ - /* (RISCOS, ULTRIX variants) */ - /* VAX ==> DEC VAX */ - /* (BSD, ULTRIX variants) */ - /* RS6000 ==> IBM RS/6000 AIX3.X */ - /* RT ==> IBM PC/RT */ - /* HP_PA ==> HP9000/700 & /800 */ - /* HP/UX, LINUX */ - /* SPARC ==> SPARC v7/v8/v9 */ - /* (SUNOS4, SUNOS5, LINUX, */ - /* DRSNX variants) */ - /* ALPHA ==> DEC Alpha */ - /* (OSF1 and LINUX variants) */ - /* M88K ==> Motorola 88XX0 */ - /* (CX_UX and DGUX) */ - /* S370 ==> 370-like machine */ - /* running Amdahl UTS4 */ - /* or a 390 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) */ - - -/* - * For each architecture and OS, the following need to be defined: - * - * CPP_WORD_SZ is a simple integer constant representing the word size. - * in bits. We assume byte addressibility, where a byte has 8 bits. - * We also assume CPP_WORD_SZ is either 32 or 64. - * (We care about the length of pointers, not hardware - * bus widths. Thus a 64 bit processor with a C compiler that uses - * 32 bit pointers should use CPP_WORD_SZ of 32, not 64. Default is 32.) - * - * MACH_TYPE is a string representation of the machine type. - * OS_TYPE is analogous for the OS. - * - * ALIGNMENT is the largest N, such that - * all pointer are guaranteed to be aligned on N byte boundaries. - * defining it to be 1 will always work, but perform poorly. - * - * DATASTART is the beginning of the data segment. - * 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[];''. - * 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. - * - * STACKBOTTOM is the cool end of the stack, which is usually the - * highest address in the stack. - * Under PCR or OS/2, we have other ways of finding thread stacks. - * For each machine, the following should: - * 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 - * the next multiple of STACK_GRAN. - * HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly - * in small steps (decrement if STACK_GROWS_UP), and read the value - * at each location. Remember the value when the first - * Segmentation violation or Bus error is signalled. Round that - * to the nearest plausible page boundary, and use that instead - * of STACKBOTTOM. - * - * Gustavo Rodriguez-Rivera points out that on most (all?) Unix machines, - * the value of environ is a pointer that can serve as STACKBOTTOM. - * I expect that HEURISTIC2 can be replaced by this approach, which - * interferes far less with debugging. However it has the disadvantage - * that it's confused by a putenv call before the collector is initialized. - * This could be dealt with by intercepting putenv ... - * - * If no expression for STACKBOTTOM can be found, and neither of the above - * heuristics are usable, the collector can still be used with all of the above - * undefined, provided one of the following is done: - * 1) GC_mark_roots can be changed to somehow mark from the correct stack(s) - * without reference to STACKBOTTOM. This is appropriate for use in - * conjunction with thread packages, since there will be multiple stacks. - * (Allocating thread stacks in the heap, and treating them as ordinary - * heap data objects is also possible as a last resort. However, this is - * likely to introduce significant amounts of excess storage retention - * unless the dead parts of the thread stacks are periodically cleared.) - * 2) Client code may set GC_stackbottom before calling any GC_ routines. - * If the author of the client code controls the main program, this is - * easily accomplished by introducing a new main program, setting - * GC_stackbottom to the address of a local variable, and then calling - * the original main program. The new main program would read something - * like: - * - * # include "gc_private.h" - * - * main(argc, argv, envp) - * int argc; - * char **argv, **envp; - * { - * int dummy; - * - * GC_stackbottom = (ptr_t)(&dummy); - * return(real_main(argc, argv, envp)); - * } - * - * - * Each architecture may also define the style of virtual dirty bit - * implementation to be used: - * MPROTECT_VDB: Write protect the heap and catch faults. - * PROC_VDB: Use the SVR4 /proc primitives to read dirty bits. - * - * An architecture may define DYNAMIC_LOADING if dynamic_load.c - * defined GC_register_dynamic_libraries() for the architecture. - * - * An architecture may define PREFETCH(x) to preload the cache with *x. - * This defaults to a no-op. - * - * PREFETCH_FOR_WRITE(x) is used if *x is about to be written. - * - * 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() - * to push the relevant registers onto the stack. This generally makes - * USE_GENERIC_PUSH_REGS the preferred approach for marking from registers. - */ -# if defined(__GNUC__) && ((__GNUC__ >= 3) || \ - (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) -# define HAVE_BUILTIN_UNWIND_INIT -# endif - -# define STACK_GRAN 0x1000000 -# ifdef M68K -# define MACH_TYPE "M68K" -# define ALIGNMENT 2 -# ifdef OPENBSD -# define OS_TYPE "OPENBSD" -# define HEURISTIC2 - 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)) -# endif -# ifdef LINUX -# define OS_TYPE "LINUX" -# define STACKBOTTOM ((ptr_t)0xf0000000) -/* # 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 -# else /* !GLIBC2 */ - extern char **__environ; -# define DATASTART ((ptr_t)(&__environ)) - /* hideous kludge: __environ is the first */ - /* word in crt0.o, and delimits the start */ - /* of the data segment, no matter which */ - /* ld options were passed through. */ - /* We could use _etext instead, but that */ - /* would include .rodata, which may */ - /* contain large read-only data tables */ - /* that we'd rather not scan. */ -# endif /* !GLIBC2 */ - extern int _end[]; -# define DATAEND (_end) -# else - 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)) -# define HEURISTIC1 /* differs */ -# define DYNAMIC_LOADING -# endif -# ifdef HP -# define OS_TYPE "HP" - extern char etext[]; -# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) -# define STACKBOTTOM ((ptr_t) 0xffeffffc) - /* empirically determined. seems to work. */ -# include <unistd.h> -# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE) -# endif -# ifdef SYSV -# define OS_TYPE "SYSV" - extern etext[]; -# define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \ - & ~0x3fffff) \ - +((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, - handling both would require having the magic-number available. - -- Parag - */ -# define STACKBOTTOM ((ptr_t)0xFFFFFFFE) - /* The stack starts at the top of memory, but */ - /* 0x0 cannot be used as setjump_test complains */ - /* that the stack direction is incorrect. Two */ - /* bytes down from 0x0 should be safe enough. */ - /* --Parag */ -# include <sys/mmu.h> -# define GETPAGESIZE() PAGESIZE /* Is this still right? */ -# endif -# ifdef AMIGA -# define OS_TYPE "AMIGA" - /* STACKBOTTOM and DATASTART handled specially */ - /* in os_dep.c */ -# define DATAEND /* not needed */ -# define GETPAGESIZE() 4096 -# endif -# ifdef MACOS -# ifndef __LOWMEM__ -# include <LowMem.h> -# endif -# define OS_TYPE "MACOS" - /* see os_dep.c for details of global data segments. */ -# define STACKBOTTOM ((ptr_t) LMGetCurStackBase()) -# define DATAEND /* not needed */ -# define GETPAGESIZE() 4096 -# endif -# ifdef NEXT -# define OS_TYPE "NEXT" -# define DATASTART ((ptr_t) get_etext()) -# define STACKBOTTOM ((ptr_t) 0x4000000) -# define DATAEND /* not needed */ -# endif -# endif - -# ifdef POWERPC -# define MACH_TYPE "POWERPC" -# ifdef MACOS -# define ALIGNMENT 2 /* Still necessary? Could it be 4? */ -# ifndef __LOWMEM__ -# include <LowMem.h> -# endif -# define OS_TYPE "MACOS" - /* see os_dep.c for details of global data segments. */ -# define STACKBOTTOM ((ptr_t) LMGetCurStackBase()) -# define DATAEND /* not needed */ -# endif -# ifdef LINUX -# define ALIGNMENT 4 /* Guess. Can someone verify? */ - /* This was 2, but that didn't sound right. */ -# define OS_TYPE "LINUX" -# define HEURISTIC1 -# define DYNAMIC_LOADING -# undef STACK_GRAN -# define STACK_GRAN 0x10000000 - /* Stack usually starts at 0x80000000 */ -# define LINUX_DATA_START - extern int _end[]; -# define DATAEND (_end) -# endif -# ifdef MACOSX - /* There are reasons to suspect this may not be reliable. */ -# define ALIGNMENT 4 -# define OS_TYPE "MACOSX" -# define DATASTART ((ptr_t) get_etext()) -# define STACKBOTTOM ((ptr_t) 0xc0000000) -# define DATAEND /* not needed */ -# define MPROTECT_VDB -# include <unistd.h> -# define GETPAGESIZE() getpagesize() -# endif -# ifdef NETBSD -# define ALIGNMENT 4 -# define OS_TYPE "NETBSD" -# define HEURISTIC2 - 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) - /* Stack starts at 0xE0000000 for the simulator. */ -# undef STACK_GRAN -# define STACK_GRAN 0x10000000 -# define HEURISTIC1 -# endif -# endif - -# 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)) -# ifdef BSD -# define OS_TYPE "BSD" -# define HEURISTIC1 - /* HEURISTIC2 may be OK, but it's hard to test. */ -# endif -# ifdef ULTRIX -# define OS_TYPE "ULTRIX" -# define STACKBOTTOM ((ptr_t) 0x7fffc800) -# endif -# endif - -# ifdef RT -# define MACH_TYPE "RT" -# define ALIGNMENT 4 -# define DATASTART ((ptr_t) 0x10000000) -# define STACKBOTTOM ((ptr_t) 0x1fffd800) -# endif - -# ifdef SPARC -# 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 char * GC_SysVGetDataStart(); -# 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 */ - /* heap interleaved with thread stacks, which can result in */ - /* excessive blacklisting. Sbrk is unusable since it */ - /* doesn't interact correctly with the system malloc. */ -# endif -# ifdef USE_MMAP -# define HEAP_START (ptr_t)0x40000000 -# else -# define HEAP_START DATAEND -# endif -# define PROC_VDB -/* HEURISTIC1 reportedly no longer works under 2.7. */ -/* HEURISTIC2 probably works, but this appears to be preferable. */ -/* Apparently USRSTACK is defined to be USERLIMIT, but in some */ -/* installations that's undefined. We work around this with a */ -/* gross hack: */ -# include <sys/vmparam.h> -# ifdef USERLIMIT - /* This should work everywhere, but doesn't. */ -# define STACKBOTTOM USRSTACK -# else -# define HEURISTIC2 -# endif -# include <unistd.h> -# define GETPAGESIZE() sysconf(_SC_PAGESIZE) - /* getpagesize() appeared to be missing from at least one */ - /* Solaris 5.4 installation. Weird. */ -# define DYNAMIC_LOADING -# endif -# ifdef SUNOS4 -# 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)) */ - /* This fails occasionally, due to an ancient, but very */ - /* 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 */ - /* was done by Robert Ehrlich, Manuel Serrano, and Bernard */ - /* Serpette of INRIA. */ - /* This assumes ZMAGIC, i.e. demand-loadable executables. */ -# define TEXTSTART 0x2000 -# define DATASTART ((ptr_t)(*(int *)(TEXTSTART+0x4)+TEXTSTART)) -# define MPROTECT_VDB -# define HEURISTIC1 -# define DYNAMIC_LOADING -# endif -# ifdef DRSNX -# define OS_TYPE "DRSNX" - extern char * GC_SysVGetDataStart(); - extern int etext[]; -# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext) -# define MPROTECT_VDB -# define STACKBOTTOM ((ptr_t) 0xdfff0000) -# define DYNAMIC_LOADING -# endif -# ifdef LINUX -# define OS_TYPE "LINUX" -# ifdef __ELF__ -# define DYNAMIC_LOADING -# else - Linux Sparc/a.out not supported -# endif - 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) -# else -# 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)) -# endif -# 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 -# endif -# endif - -# ifdef I386 -# define MACH_TYPE "I386" -# define ALIGNMENT 4 /* Appears to hold for all "32 bit" compilers */ - /* except Borland. The -a4 option fixes */ - /* Borland. */ - /* Ivan Demakov: For Watcom the option is -zp4. */ -# ifndef SMALL_CONFIG -# define ALIGN_DOUBLE /* Not strictly necessary, but may give speed */ - /* improvement on Pentiums. */ -# endif -# ifdef HAVE_BUILTIN_UNWIND_INIT -# define USE_GENERIC_PUSH_REGS -# endif -# ifdef SEQUENT -# define OS_TYPE "SEQUENT" - 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)) -# endif -# ifdef SUNOS5 -# define OS_TYPE "SUNOS5" - 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, */ -/* 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. */ -/* HEURISTIC2 probably works, but this appears to be preferable. */ -# include <sys/vm.h> -# define STACKBOTTOM USRSTACK -/* At least in Solaris 2.5, PROC_VDB gives wrong values for dirty bits. */ -/* It appears to be fixed in 2.8 and 2.9. */ -# ifdef SOLARIS25_PROC_VDB_BUG_FIXED -# define PROC_VDB -# endif -# define DYNAMIC_LOADING -# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC) -# define USE_MMAP - /* Otherwise we now use calloc. Mmap may result in the */ - /* heap interleaved with thread stacks, which can result in */ - /* excessive blacklisting. Sbrk is unusable since it */ - /* doesn't interact correctly with the system malloc. */ -# endif -# ifdef USE_MMAP -# define HEAP_START (ptr_t)0x40000000 -# else -# define HEAP_START DATAEND -# endif -# endif -# ifdef SCO -# define OS_TYPE "SCO" - extern int etext[]; -# define DATASTART ((ptr_t)((((word) (etext)) + 0x3fffff) \ - & ~0x3fffff) \ - +((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)) -# 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 -# define HEURISTIC1 -# undef STACK_GRAN -# define STACK_GRAN 0x10000000 - /* STACKBOTTOM is usually 0xc0000000, but this changes with */ - /* different kernel configurations. In particular, systems */ - /* with 2GB physical memory will usually move the user */ - /* address space limit, and hence initial SP to 0x80000000. */ -# endif -# if !defined(GC_LINUX_THREADS) || !defined(REDIRECT_MALLOC) -# define MPROTECT_VDB -# else - /* We seem to get random errors in incremental mode, */ - /* 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)) -# endif -# include <features.h> -# if defined(__GLIBC__) && __GLIBC__ >= 2 -# define LINUX_DATA_START -# else - extern char **__environ; -# define DATASTART ((ptr_t)(&__environ)) - /* hideous kludge: __environ is the first */ - /* word in crt0.o, and delimits the start */ - /* of the data segment, no matter which */ - /* ld options were passed through. */ - /* We could use _etext instead, but that */ - /* would include .rodata, which may */ - /* contain large read-only data tables */ - /* that we'd rather not scan. */ -# endif - extern int _end[]; -# define DATAEND (_end) -# else - extern int etext[]; -# define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) -# endif -# ifdef USE_I686_PREFETCH -# define PREFETCH(x) \ - __asm__ __volatile__ (" prefetchnta %0": : "m"(*(char *)(x))) - /* Empirically prefetcht0 is much more effective at reducing */ - /* cache miss stalls for the targetted load instructions. But it */ - /* seems to interfere enough with other cache traffic that the net */ - /* result is worse than prefetchnta. */ -# if 0 - /* Using prefetches for write seems to have a slight negative */ - /* impact on performance, at least for a PIII/500. */ -# define PREFETCH_FOR_WRITE(x) \ - __asm__ __volatile__ (" prefetcht0 %0": : "m"(*(char *)(x))) -# endif -# endif -# ifdef USE_3DNOW_PREFETCH -# define PREFETCH(x) \ - __asm__ __volatile__ (" prefetch %0": : "m"(*(char *)(x))) -# define PREFETCH_FOR_WRITE(x) \ - __asm__ __volatile__ (" prefetchw %0": : "m"(*(char *)(x))) -# endif -# endif -# ifdef CYGWIN32 -# define OS_TYPE "CYGWIN32" - 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__ */ - /* whereas for some earlier versions it was */ - /* DATASTART = _bss_start__ */ - /* DATAEND = _data_end__ */ - /* To get it right for both, we take the */ - /* 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__)) -# undef STACK_GRAN -# define STACK_GRAN 0x10000 -# define HEURISTIC1 -# endif -# ifdef OS2 -# define OS_TYPE "OS2" - /* STACKBOTTOM and DATASTART are handled specially in */ - /* os_dep.c. OS2 actually has the right */ - /* system call! */ -# define DATAEND /* not needed */ -# define USE_GENERIC_PUSH_REGS -# endif -# ifdef MSWIN32 -# define OS_TYPE "MSWIN32" - /* STACKBOTTOM and DATASTART are handled specially in */ - /* os_dep.c. */ -# ifndef __WATCOMC__ -# define MPROTECT_VDB -# endif -# define DATAEND /* not needed */ -# endif -# ifdef MSWINCE -# define OS_TYPE "MSWINCE" -# define DATAEND /* not needed */ -# endif -# ifdef DJGPP -# define OS_TYPE "DJGPP" -# include "stubinfo.h" - extern int etext[]; - extern int _stklen; - extern int __djgpp_stack_limit; -# 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)) - /* This may not be right. */ -# endif -# ifdef OPENBSD -# define OS_TYPE "OPENBSD" -# endif -# ifdef FREEBSD -# define OS_TYPE "FREEBSD" -# ifndef GC_FREEBSD_THREADS -# define MPROTECT_VDB -# endif -# define SIG_SUSPEND SIGUSR1 -# define SIG_THR_RESTART SIGUSR2 -# define FREEBSD_STACKBOTTOM -# ifdef __ELF__ -# define DYNAMIC_LOADING -# endif - 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" -# endif -# ifdef BSDI -# define OS_TYPE "BSDI" -# endif -# if defined(OPENBSD) || defined(NETBSD) \ - || defined(THREE86BSD) || defined(BSDI) -# define HEURISTIC2 - extern char etext[]; -# define DATASTART ((ptr_t)(etext)) -# endif -# ifdef NEXT -# define OS_TYPE "NEXT" -# define DATASTART ((ptr_t) get_etext()) -# define STACKBOTTOM ((ptr_t)0xc0000000) -# define DATAEND /* not needed */ -# endif -# ifdef DOS4GW -# define OS_TYPE "DOS4GW" - extern long __nullarea; - extern char _end; - extern char *_STACKTOP; - /* Depending on calling conventions Watcom C either precedes - or does not precedes with undescore names of C-variables. - Make sure startup code variables always have the same names. */ - #pragma aux __nullarea "*"; - #pragma aux _end "*"; -# define STACKBOTTOM ((ptr_t) _STACKTOP) - /* confused? me too. */ -# define DATASTART ((ptr_t) &__nullarea) -# define DATAEND ((ptr_t) &_end) -# endif -# ifdef HURD -# 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)) -/* # define MPROTECT_VDB Not quite working yet? */ -# define DYNAMIC_LOADING -# endif -# endif - -# ifdef NS32K -# define MACH_TYPE "NS32K" -# define ALIGNMENT 4 - extern char **environ; -# define DATASTART ((ptr_t)(&environ)) - /* hideous kludge: environ is the first */ - /* word in crt0.o, and delimits the start */ - /* of the data segment, no matter which */ - /* ld options were passed through. */ -# define STACKBOTTOM ((ptr_t) 0xfffff000) /* for Encore */ -# endif - -# ifdef MIPS -# define MACH_TYPE "MIPS" -# ifdef LINUX - /* This was developed for a linuxce style platform. Probably */ - /* needs to be tweaked for workstation class machines. */ -# define OS_TYPE "LINUX" -# 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 -# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2 -# define LINUX_STACKBOTTOM -# else -# define STACKBOTTOM 0x80000000 -# endif -# endif /* Linux */ -# ifdef EWS4800 -# define HEURISTIC2 -# if defined(_MIPS_SZPTR) && (_MIPS_SZPTR == 64) - extern int _fdata[], _end[]; -# define DATASTART ((ptr_t)_fdata) -# define DATAEND ((ptr_t)_end) -# 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) -# define ALIGNMENT 4 -# endif -# define OS_TYPE "EWS4800" -# define USE_GENERIC_PUSH_REGS 1 -# endif -# ifdef ULTRIX -# define HEURISTIC2 -# define DATASTART (ptr_t)0x10000000 - /* Could probably be slightly higher since */ - /* startup code allocates lots of stuff. */ -# define OS_TYPE "ULTRIX" -# define ALIGNMENT 4 -# endif -# ifdef RISCOS -# define HEURISTIC2 -# define DATASTART (ptr_t)0x10000000 -# define OS_TYPE "RISCOS" -# define ALIGNMENT 4 /* Required by hardware */ -# endif -# ifdef IRIX5 -# define HEURISTIC2 - extern int _fdata[]; -# define DATASTART ((ptr_t)(_fdata)) -# ifdef USE_MMAP -# define HEAP_START (ptr_t)0x30000000 -# else -# define HEAP_START DATASTART -# endif - /* Lowest plausible heap address. */ - /* In the MMAP case, we map there. */ - /* In either case it is used to identify */ - /* heap sections so they're not */ - /* considered as roots. */ -# define OS_TYPE "IRIX5" -# define MPROTECT_VDB -# ifdef _MIPS_SZPTR -# define CPP_WORDSZ _MIPS_SZPTR -# define ALIGNMENT (_MIPS_SZPTR/8) -# if CPP_WORDSZ != 64 -# define ALIGN_DOUBLE -# endif -# else -# define ALIGNMENT 4 -# define ALIGN_DOUBLE -# endif -# define DYNAMIC_LOADING -# endif -# ifdef MSWINCE -# define OS_TYPE "MSWINCE" -# define ALIGNMENT 4 -# define DATAEND /* not needed */ -# endif -# if defined(NETBSD) - /* This also checked for __MIPSEL__ . Why? NETBSD recognition */ - /* should be handled at the top of the file. */ -# define ALIGNMENT 4 -# define OS_TYPE "NETBSD" -# define HEURISTIC2 -# define USE_GENERIC_PUSH_REGS -# 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 __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 USE_GENERIC_PUSH_REGS -# define DYNAMIC_LOADING - /* For really old versions of AIX, this may have to be removed. */ -# endif - -# ifdef HP_PA -# define MACH_TYPE "HP_PA" -# ifdef __LP64__ -# define CPP_WORDSZ 64 -# define ALIGNMENT 8 -# else -# define CPP_WORDSZ 32 -# define ALIGNMENT 4 -# define ALIGN_DOUBLE -# endif -# if !defined(GC_HPUX_THREADS) && !defined(GC_LINUX_THREADS) -# ifndef LINUX /* For now. */ -# define MPROTECT_VDB -# endif -# else -# define GENERIC_COMPARE_AND_SWAP - /* No compare-and-swap instruction. Use pthread mutexes */ - /* when we absolutely have to. */ -# ifdef PARALLEL_MARK -# define USE_MARK_BYTES - /* Minimize compare-and-swap usage. */ -# endif -# endif -# define STACK_GROWS_UP -# ifdef HPUX -# define OS_TYPE "HPUX" - 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 */ - /* collections than HEURISTIC2, which may involve scanning */ - /* segments that directly precede the stack. It is not the */ - /* default, since it may not work on older machine/OS */ - /* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */ - /* this.) */ -# define STACKBOTTOM ((ptr_t) 0x7b033000) /* from /etc/conf/h/param.h */ -# else - /* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */ - /* to this. Note that the GC must be initialized before the */ - /* first putenv call. */ - extern char ** environ; -# define STACKBOTTOM ((ptr_t)environ) -# endif -# define DYNAMIC_LOADING -# include <unistd.h> -# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE) -# ifndef __GNUC__ -# define PREFETCH(x) { \ - register long addr = (long)(x); \ - (void) _asm ("LDW", 0, 0, addr, 0); \ - } -# endif -# endif /* HPUX */ -# ifdef LINUX -# define OS_TYPE "LINUX" -# define LINUX_STACKBOTTOM -# define DYNAMIC_LOADING -# define SEARCH_FOR_DATA_START - extern int _end[]; -# define DATAEND (&_end) -# endif /* LINUX */ -# endif /* HP_PA */ - -# ifdef ALPHA -# define MACH_TYPE "ALPHA" -# define ALIGNMENT 8 -# 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 -# define DATASTART GC_data_start -# 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 -# define ELFCLASS64 64 -# define ELF_CLASS ELFCLASS64 -# else /* ECOFF, until OpenBSD/Alpha 2.7 */ -# 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[]; -# 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 */ - /* initialization. */ -# define STACKBOTTOM ((ptr_t)(((word)(environ) | (getpagesize()-1))+1)) -/* # define HEURISTIC2 */ - /* Normally HEURISTIC2 is too conervative, since */ - /* 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))) -# define CPP_WORDSZ 64 -# define MPROTECT_VDB -# 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 DYNAMIC_LOADING -# else -# define DATASTART ((ptr_t) 0x140000000) -# endif - extern int _end[]; -# define DATAEND (_end) -# define MPROTECT_VDB - /* Has only been superficially tested. May not */ - /* work on all versions. */ -# endif -# endif - -# ifdef IA64 -# define MACH_TYPE "IA64" -# define USE_GENERIC_PUSH_REGS - /* We need to get preserved registers in addition to register */ - /* windows. That's easiest to do with setjmp. */ -# ifdef PARALLEL_MARK -# define USE_MARK_BYTES - /* Compare-and-exchange is too expensive to use for */ - /* setting mark bits. */ -# endif -# ifdef HPUX -# ifdef _ILP32 -# define CPP_WORDSZ 32 -# define ALIGN_DOUBLE - /* Requires 8 byte alignment for malloc */ -# define ALIGNMENT 4 -# else -# ifndef _LP64 - ---> unknown ABI -# endif -# define CPP_WORDSZ 64 -# define ALIGN_DOUBLE - /* Requires 16 byte alignment for malloc */ -# define ALIGNMENT 8 -# endif -# define OS_TYPE "HPUX" - 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. */ - extern char ** environ; -# define STACKBOTTOM ((ptr_t)environ) -# define DYNAMIC_LOADING -# include <unistd.h> -# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE) - /* The following was empirically determined, and is probably */ - /* not very robust. */ - /* Note that the backing store base seems to be at a nice */ - /* address minus one page. */ -# define BACKING_STORE_DISPLACEMENT 0x1000000 -# define BACKING_STORE_ALIGNMENT 0x1000 -# define BACKING_STORE_BASE \ - (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1) \ - & ~(BACKING_STORE_ALIGNMENT - 1)) -# endif -# ifdef LINUX -# define CPP_WORDSZ 64 -# define ALIGN_DOUBLE - /* Requires 16 byte alignment for malloc */ -# define ALIGNMENT 8 -# define OS_TYPE "LINUX" - /* The following works on NUE and older kernels: */ -/* # define STACKBOTTOM ((ptr_t) 0xa000000000000000l) */ - /* This does not work on NUE: */ -# define LINUX_STACKBOTTOM - /* We also need the base address of the register stack */ - /* backing store. This is computed in */ - /* GC_linux_register_stack_base based on the following */ - /* constants: */ -# define BACKING_STORE_ALIGNMENT 0x100000 -# define BACKING_STORE_DISPLACEMENT 0x80000000 - extern char * GC_register_stackbottom; -# define BACKING_STORE_BASE ((ptr_t)GC_register_stackbottom) -# define SEARCH_FOR_DATA_START -# ifdef __GNUC__ -# define DYNAMIC_LOADING -# else - /* In the Intel compiler environment, we seem to end up with */ - /* statically linked executables and an undefined reference */ - /* to _DYNAMIC */ -# endif -# define MPROTECT_VDB - /* Requires Linux 2.3.47 or later. */ - extern int _end[]; -# define DATAEND (_end) -# ifdef __GNUC__ -# define PREFETCH(x) \ - __asm__ (" lfetch [%0]": : "r"((void *)(x))) -# define PREFETCH_FOR_WRITE(x) \ - __asm__ (" lfetch.excl [%0]": : "r"((void *)(x))) -# define CLEAR_DOUBLE(x) \ - __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x))) -# endif -# endif -# endif - -# ifdef M88K -# define MACH_TYPE "M88K" -# define ALIGNMENT 4 -# define ALIGN_DOUBLE - extern int etext[]; -# ifdef CX_UX -# define OS_TYPE "CX_UX" -# 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) -# endif -# define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */ -# endif - -# ifdef S370 -# 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 _end[]; - extern char * GC_SysVGetDataStart(); -# 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)) -# endif -# endif - -# if defined(PJ) -# define ALIGNMENT 4 - extern int _etext[]; -# define DATASTART ((ptr_t)(_etext)) -# define HEURISTIC1 -# endif - -# ifdef ARM32 -# define CPP_WORDSZ 32 -# define MACH_TYPE "ARM32" -# define ALIGNMENT 4 -# ifdef NETBSD -# define OS_TYPE "NETBSD" -# define HEURISTIC2 - extern char etext[]; -# define DATASTART ((ptr_t)(etext)) -# define USE_GENERIC_PUSH_REGS -# endif -# ifdef LINUX -# define OS_TYPE "LINUX" -# define HEURISTIC1 -# undef STACK_GRAN -# define STACK_GRAN 0x10000000 -# define USE_GENERIC_PUSH_REGS -# ifdef __ELF__ -# define DYNAMIC_LOADING -# include <features.h> -# if defined(__GLIBC__) && __GLIBC__ >= 2 -# define LINUX_DATA_START -# else - extern char **__environ; -# define DATASTART ((ptr_t)(&__environ)) - /* hideous kludge: __environ is the first */ - /* word in crt0.o, and delimits the start */ - /* of the data segment, no matter which */ - /* ld options were passed through. */ - /* We could use _etext instead, but that */ - /* would include .rodata, which may */ - /* contain large read-only data tables */ - /* that we'd rather not scan. */ -# endif - extern int _end[]; -# define DATAEND (_end) -# else - 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 -# define MACH_TYPE "SH" -# define ALIGNMENT 4 -# ifdef MSWINCE -# define OS_TYPE "MSWINCE" -# define DATAEND /* not needed */ -# endif -# ifdef LINUX -# define OS_TYPE "LINUX" -# define STACKBOTTOM ((ptr_t) 0x7c000000) -# define USE_GENERIC_PUSH_REGS -# define DYNAMIC_LOADING -# define LINUX_DATA_START - extern int _end[]; -# define DATAEND (_end) -# endif -# endif - -# ifdef SH4 -# define MACH_TYPE "SH4" -# define OS_TYPE "MSWINCE" -# define ALIGNMENT 4 -# define DATAEND /* not needed */ -# 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 */ - /* work with collectable memory, we have to scan memory allocated */ - /* by rld's internal malloc. */ -# define USE_PROC_FOR_LIBRARIES -#endif - -# ifndef STACK_GROWS_UP -# define STACK_GROWS_DOWN -# endif - -# ifndef CPP_WORDSZ -# define CPP_WORDSZ 32 -# endif - -# ifndef OS_TYPE -# define OS_TYPE "" -# endif - -# ifndef DATAEND - extern int end[]; -# define DATAEND (end) -# endif - -# if defined(SVR4) && !defined(GETPAGESIZE) -# include <unistd.h> -# define GETPAGESIZE() sysconf(_SC_PAGESIZE) -# endif - -# ifndef GETPAGESIZE -# if defined(SUNOS5) || defined(IRIX5) -# include <unistd.h> -# endif -# define GETPAGESIZE() getpagesize() -# endif - -# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4) - /* 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. */ -# define SUNOS5DL - /* OS has SUNOS5 style signal handlers. */ -# define SUNOS5SIGS -# endif - -# if defined(HPUX) -# define SUNOS5SIGS -# endif - -# if defined(SVR4) || defined(LINUX) || defined(IRIX) || defined(HPUX) \ - || 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 -# endif - -# ifdef PCR -# undef DYNAMIC_LOADING -# undef STACKBOTTOM -# undef HEURISTIC1 -# undef HEURISTIC2 -# undef PROC_VDB -# undef MPROTECT_VDB -# define PCR_VDB -# endif - -# ifdef SRC_M3 - /* Postponed for now. */ -# undef PROC_VDB -# undef MPROTECT_VDB -# endif - -# ifdef SMALL_CONFIG - /* Presumably not worth the space it takes. */ -# undef PROC_VDB -# undef MPROTECT_VDB -# endif - -# ifdef USE_MUNMAP -# undef MPROTECT_VDB /* Can't deal with address space holes. */ -# endif - -# ifdef PARALLEL_MARK -# undef MPROTECT_VDB /* For now. */ -# endif - -# if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB) -# define DEFAULT_VDB -# endif - -# ifndef PREFETCH -# define PREFETCH(x) -# define NO_PREFETCH -# endif - -# ifndef PREFETCH_FOR_WRITE -# define PREFETCH_FOR_WRITE(x) -# define NO_PREFETCH_FOR_WRITE -# endif - -# ifndef CACHE_LINE_SIZE -# 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; -# endif /* CLEAR_DOUBLE */ - - /* 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 -# endif -# if defined(GC_LINUX_THREADS) && !defined(LINUX) - --> inconsistent configuration -# endif -# if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5) - --> inconsistent configuration -# endif -# if defined(GC_HPUX_THREADS) && !defined(HPUX) - --> 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 -# endif - -# if defined(PCR) || defined(SRC_M3) || \ - 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(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(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 -# 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 deleted file mode 100644 index 7d49c29..0000000 --- a/gc/include/private/solaris_threads.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifdef GC_SOLARIS_THREADS - -/* The set of all known threads. We intercept thread creation and */ -/* joins. We never actually create detached threads. We allocate all */ -/* new thread stacks ourselves. These allow us to maintain this */ -/* data structure. */ -/* Protected by GC_thr_lock. */ -/* Some of this should be declared volatile, but that's incosnsistent */ -/* with some library routine declarations. In particular, the */ -/* definition of cond_t doesn't mention volatile! */ - typedef struct GC_Thread_Rep { - struct GC_Thread_Rep * next; - thread_t id; - word flags; -# define FINISHED 1 /* Thread has exited. */ -# define DETACHED 2 /* Thread is intended to be detached. */ -# define CLIENT_OWNS_STACK 4 - /* Stack was supplied by client. */ -# define SUSPNDED 8 /* Currently suspended. */ - /* SUSPENDED is used insystem header. */ - ptr_t stack; - size_t stack_size; - cond_t join_cv; - void * status; - } * GC_thread; - extern GC_thread GC_new_thread(thread_t id); - - extern GC_bool GC_thr_initialized; - extern volatile GC_thread GC_threads[]; - extern size_t GC_min_stack_sz; - extern size_t GC_page_sz; - extern void GC_thr_init(void); - -# endif /* GC_SOLARIS_THREADS */ - diff --git a/gc/include/private/specific.h b/gc/include/private/specific.h deleted file mode 100644 index 399f84f..0000000 --- a/gc/include/private/specific.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * This is a reimplementation of a subset of the pthread_getspecific/setspecific - * interface. This appears to outperform the standard linuxthreads one - * by a significant margin. - * The major restriction is that each thread may only make a single - * pthread_setspecific call on a single key. (The current data structure - * doesn't really require that. The restriction should be easily removable.) - * We don't currently support the destruction functions, though that - * could be done. - * We also currently assume that only one pthread_setspecific call - * can be executed at a time, though that assumption would be easy to remove - * by adding a lock. - */ - -#include <errno.h> - -/* Called during key creation or setspecific. */ -/* For the GC we already hold lock. */ -/* Currently allocated objects leak on thread exit. */ -/* That's hard to fix, but OK if we allocate garbage */ -/* collected memory. */ -#define MALLOC_CLEAR(n) GC_INTERNAL_MALLOC(n, NORMAL) -#define PREFIXED(name) GC_##name - -#define TS_CACHE_SIZE 1024 -#define CACHE_HASH(n) (((((long)n) >> 8) ^ (long)n) & (TS_CACHE_SIZE - 1)) -#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; - struct thread_specific_entry *next; - pthread_t thread; -} tse; - - -/* We represent each thread-specific datum as two tables. The first is */ -/* 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. */ -/* The second is a hash table, indexed by pthread_self(). It is used */ -/* only as a backup. */ - -/* Return the "quick thread id". Default version. Assumes page size, */ -/* or at least thread stack separation, is at least 4K. */ -/* 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 (unsigned long)(&dummy) >> 12; -} - -#define INVALID_QTID ((unsigned long)0) -#define INVALID_THREADID ((pthread_t)0) - -typedef struct thread_specific_data { - tse * volatile cache[TS_CACHE_SIZE]; - /* A faster index to the hash table */ - tse * hash[TS_HASH_SIZE]; - pthread_mutex_t lock; -} tsd; - -typedef tsd * PREFIXED(key_t); - -extern int PREFIXED(key_create) (tsd ** key_ptr, void (* destructor)(void *)); - -extern int PREFIXED(setspecific) (tsd * key, void * value); - -extern void PREFIXED(remove_specific) (tsd * key); - -/* An internal version of getspecific that assumes a cache miss. */ -void * PREFIXED(slow_getspecific) (tsd * key, unsigned long qtid, - tse * volatile * cache_entry); - -static __inline__ void * PREFIXED(getspecific) (tsd * key) { - long qtid = quick_thread_id(); - 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) { - GC_ASSERT(entry -> thread == pthread_self()); - return entry -> value; - } - return PREFIXED(slow_getspecific) (key, qtid, entry_ptr); -} - - |