diff options
Diffstat (limited to 'misc.c')
-rw-r--r-- | misc.c | 219 |
1 files changed, 149 insertions, 70 deletions
@@ -20,7 +20,7 @@ #endif #define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */ -#include "private/gc_priv.h" +#include "private/gc_pmark.h" #ifdef SOLARIS_THREADS # include <sys/syscall.h> @@ -71,6 +71,10 @@ # endif # endif +#ifdef ECOS +#undef STACKBASE +#endif + GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */; @@ -83,16 +87,30 @@ void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0; ptr_t GC_stackbottom = 0; +#ifdef IA64 + ptr_t GC_register_stackbottom = 0; +#endif + GC_bool GC_dont_gc = 0; +GC_bool GC_dont_precollect = 0; + GC_bool GC_quiet = 0; +GC_bool GC_print_stats = 0; + #ifdef FIND_LEAK int GC_find_leak = 1; #else int GC_find_leak = 0; #endif +#ifdef ALL_INTERIOR_POINTERS + int GC_all_interior_pointers = 1; +#else + int GC_all_interior_pointers = 0; +#endif + /*ARGSUSED*/ GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested)) { @@ -122,8 +140,8 @@ extern signed_word GC_mem_found; for (i = 0; i < sizeof(word); i++) { GC_size_map[i] = MIN_WORDS; } -# ifdef USE_MARK_BYTES - GC_size_map[sizeof(word)] = ALIGNED_WORDS(sizeof(word)); +# if MIN_WORDS > 1 + GC_size_map[sizeof(word)] = MIN_WORDS; # else GC_size_map[sizeof(word)] = ROUNDED_UP_WORDS(sizeof(word)); # endif @@ -191,10 +209,10 @@ extern signed_word GC_mem_found; # endif } byte_sz = WORDS_TO_BYTES(word_sz); -# ifdef ADD_BYTE_AT_END + if (GC_all_interior_pointers) { /* We need one extra byte; don't fill in GC_size_map[byte_sz] */ byte_sz--; -# endif + } for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz; } @@ -211,39 +229,24 @@ extern signed_word GC_mem_found; */ word GC_stack_last_cleared = 0; /* GC_no when we last did this */ # ifdef THREADS -# define CLEAR_SIZE 2048 -# else -# define CLEAR_SIZE 213 +# define BIG_CLEAR_SIZE 2048 /* Clear this much now and then. */ +# define SMALL_CLEAR_SIZE 256 /* Clear this much every time. */ # endif +# define CLEAR_SIZE 213 /* Granularity for GC_clear_stack_inner */ # define DEGRADE_RATE 50 word GC_min_sp; /* Coolest stack pointer value from which we've */ /* already cleared the stack. */ -# 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 - word GC_high_water; /* "hottest" stack pointer value we have seen */ /* recently. Degrades over time. */ word GC_words_allocd_at_reset; -#if defined(ASM_CLEAR_CODE) && !defined(THREADS) +#if defined(ASM_CLEAR_CODE) extern ptr_t GC_clear_stack_inner(); -#endif - -#if !defined(ASM_CLEAR_CODE) && !defined(THREADS) +#else /* Clear the stack up to about limit. Return arg. */ /*ARGSUSED*/ ptr_t GC_clear_stack_inner(arg, limit) @@ -271,10 +274,13 @@ ptr_t arg; { register word sp = (word)GC_approx_sp(); /* Hotter than actual sp */ # ifdef THREADS - word dummy[CLEAR_SIZE]; -# else - register word limit; + word dummy[SMALL_CLEAR_SIZE]; + static unsigned random_no = 0; + /* Should be more random than it is ... */ + /* Used to occasionally clear a bigger */ + /* chunk. */ # endif + register word limit; # define SLOP 400 /* Extra bytes we clear every time. This clears our own */ @@ -292,7 +298,14 @@ ptr_t arg; /* thus more junk remains accessible, thus the heap gets */ /* larger ... */ # ifdef THREADS - BZERO(dummy, CLEAR_SIZE*sizeof(word)); + if (++random_no % 13 == 0) { + limit = sp; + MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word)); + return GC_clear_stack_inner(arg, limit); + } else { + BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word)); + return arg; + } # else if (GC_gc_no > GC_stack_last_cleared) { /* Start things over, so we clear the entire stack again */ @@ -322,8 +335,8 @@ ptr_t arg; if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water; GC_words_allocd_at_reset = GC_words_allocd; } + return(arg); # endif - return(arg); } @@ -352,37 +365,27 @@ ptr_t arg; /* to the beginning. */ while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) { h = FORWARDED_ADDR(h,candidate_hdr); - r = (word)h + HDR_BYTES; + r = (word)h; candidate_hdr = HDR(h); } if (candidate_hdr -> hb_map == GC_invalid_map) return(0); /* Make sure r points to the beginning of the object */ r &= ~(WORDS_TO_BYTES(1) - 1); { - register int offset = (char *)r - (char *)(HBLKPTR(r)); + register int offset = HBLKDISPL(r); register signed_word sz = candidate_hdr -> hb_sz; - -# ifdef ALL_INTERIOR_POINTERS - register map_entry_type map_entry; + register signed_word map_entry; - map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset); - if (map_entry == OBJ_INVALID) { - return(0); - } - r -= WORDS_TO_BYTES(map_entry); - limit = r + WORDS_TO_BYTES(sz); -# else - register int correction; - - offset = BYTES_TO_WORDS(offset - HDR_BYTES); - correction = offset % sz; - r -= (WORDS_TO_BYTES(correction)); - limit = r + WORDS_TO_BYTES(sz); - if (limit > (word)(h + 1) - && sz <= BYTES_TO_WORDS(HBLKSIZE) - HDR_WORDS) { + map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset); + if (map_entry > CPP_MAX_OFFSET) { + map_entry = (signed_word)(BYTES_TO_WORDS(offset)) % sz; + } + r -= WORDS_TO_BYTES(map_entry); + limit = r + WORDS_TO_BYTES(sz); + if (limit > (word)(h + 1) + && sz <= BYTES_TO_WORDS(HBLKSIZE)) { return(0); - } -# endif + } if ((word)p >= limit) return(0); } return((GC_PTR)r); @@ -403,11 +406,7 @@ ptr_t arg; register hdr * hhdr = HDR(p); sz = WORDS_TO_BYTES(hhdr -> hb_sz); - if (sz < 0) { - return(-sz); - } else { - return(sz); - } + return(sz); } size_t GC_get_heap_size GC_PROTO(()) @@ -425,6 +424,11 @@ size_t GC_get_bytes_since_gc GC_PROTO(()) return ((size_t) WORDS_TO_BYTES(GC_words_allocd)); } +size_t GC_get_total_bytes GC_PROTO(()) +{ + return ((size_t) WORDS_TO_BYTES(GC_words_allocd+GC_words_allocd_before_gc)); +} + GC_bool GC_is_initialized = FALSE; void GC_init() @@ -437,6 +441,15 @@ void GC_init() UNLOCK(); ENABLE_SIGNALS(); +# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) + /* Make sure marker threads and started and thread local */ + /* allocation is initialized, in case we didn't get */ + /* called from GC_init_parallel(); */ + { + extern void GC_init_parallel(void); + GC_init_parallel(); + } +# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */ } #if defined(MSWIN32) || defined(MSWINCE) @@ -449,13 +462,50 @@ void GC_init() extern void GC_setpagesize(); +#ifdef UNIX_LIKE + +extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int))); + +static void looping_handler(sig) +int sig; +{ + GC_err_printf1("Caught signal %d: looping in handler\n", sig); + for(;;); +} +#endif + void GC_init_inner() { -# ifndef THREADS +# if !defined(THREADS) && defined(GC_ASSERTIONS) word dummy; # endif + word initial_heap_sz = (word)MINHINCR; if (GC_is_initialized) return; +# ifdef PRINTSTATS + GC_print_stats = 1; +# endif + if (0 != GETENV("GC_PRINT_STATS")) { + GC_print_stats = 1; + } + if (0 != GETENV("GC_FIND_LEAK")) { + GC_find_leak = 1; + } + if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) { + GC_all_interior_pointers = 1; + } + if (0 != GETENV("GC_DONT_GC")) { + GC_dont_gc = 1; + } +# ifdef UNIX_LIKE + if (0 != GETENV("GC_LOOP_ON_ABORT")) { + GC_set_and_save_fault_handler(looping_handler); + } +# endif + /* Adjust normal object descriptor for extra allocation. */ + if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) { + GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH); + } # if defined(MSWIN32) || defined(MSWINCE) InitializeCriticalSection(&GC_write_cs); # endif @@ -470,9 +520,11 @@ void GC_init_inner() GC_init_win32(); # endif # if defined(SEARCH_FOR_DATA_START) - /* This doesn't really work if the collector is in a shared library. */ GC_init_linux_data_start(); # endif +# if defined(NETBSD) && defined(__ELF__) + GC_init_netbsd_elf(); +# endif # if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ || defined(HPUX_THREADS) || defined(SOLARIS_THREADS) GC_thr_init(); @@ -486,6 +538,9 @@ void GC_init_inner() || defined(HPUX_THREADS) if (GC_stackbottom == 0) { GC_stackbottom = GC_get_stack_base(); +# if defined(LINUX) && defined(IA64) + GC_register_stackbottom = GC_get_register_stack_base(); +# endif } # endif GC_ASSERT(sizeof (ptr_t) == sizeof(word)); @@ -518,7 +573,18 @@ void GC_init_inner() GC_init_headers(); GC_bl_init(); GC_mark_init(); - if (!GC_expand_hp_inner((word)MINHINCR)) { + { + char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE"); + if (sz_str != NULL) { + initial_heap_sz = atoi(sz_str); + if (initial_heap_sz <= MINHINCR * HBLKSIZE) { + WARN("Bad initial heap size %s - ignoring it.\n", + sz_str); + } + initial_heap_sz = divHBLKSZ(initial_heap_sz); + } + } + if (!GC_expand_hp_inner(initial_heap_sz)) { GC_err_printf0("Can't start up: not enough memory\n"); EXIT(); } @@ -543,14 +609,11 @@ void GC_init_inner() GC_pcr_install(); # endif /* Get black list set up */ - GC_gcollect_inner(); + if (!GC_dont_precollect) GC_gcollect_inner(); GC_is_initialized = TRUE; # ifdef STUBBORN_ALLOC GC_stubborn_init(); # endif -# ifdef LINUX_THREADS - GC_thr_late_init(); -# endif /* Convince lint that some things are used */ # ifdef LINT { @@ -681,7 +744,7 @@ int GC_tmp; /* Should really be local ... */ #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) && !defined(MACOS) int GC_write(fd, buf, len) int fd; -char *buf; +GC_CONST char *buf; size_t len; { register int bytes_written = 0; @@ -701,6 +764,15 @@ size_t len; } #endif /* UN*X */ +#if defined(ECOS) +int GC_write(fd, buf, len) +{ + _Jv_diag_write (buf, len); + return len; +} +#endif + + #if defined(MSWIN32) || defined(MSWINCE) # define WRITE(f, buf, len) GC_write(buf, len) #else @@ -750,6 +822,15 @@ GC_CONST char *s; if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed"); } +#if defined(LINUX) && !defined(SMALL_CONFIG) +void GC_err_write(buf, len) +GC_CONST char *buf; +size_t len; +{ + if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed"); +} +#endif + # if defined(__STDC__) || defined(__cplusplus) void GC_default_warn_proc(char *msg, GC_word arg) # else @@ -790,15 +871,13 @@ GC_CONST char * msg; # else GC_err_printf1("%s\n", msg); # endif -# if defined(LINUX) || defined(HPUX) || defined(SUNOS5) || defined(IRIX) - if (getenv("GC_LOOP_ON_ABORT") != NULL) { + if (GETENV("GC_LOOP_ON_ABORT") != NULL) { /* In many cases it's easier to debug a running process. */ /* It's arguably nicer to sleep, but that makes it harder */ /* to look at the thread if the debugger doesn't know much */ /* about threads. */ - for(;;); - } -# endif + for(;;) {} + } # ifdef MSWIN32 DebugBreak(); # else |