Index: boehm-gc/alloc.c =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/alloc.c,v retrieving revision 1.12 diff -u -r1.12 alloc.c --- boehm-gc/alloc.c 20 Feb 2004 01:48:51 -0000 1.12 +++ boehm-gc/alloc.c 17 Mar 2004 20:09:28 -0000 @@ -228,10 +228,15 @@ for (i = 0; i < NWORDS; i++) frames[i] = 0; } +/* Heap size at which we need a collection to avoid expanding past */ +/* limits used by blacklisting. */ +static word GC_collect_at_heapsize = (word)(-1); + /* Have we allocated enough to amortize a collection? */ GC_bool GC_should_collect() { - return(GC_adj_words_allocd() >= min_words_allocd()); + return(GC_adj_words_allocd() >= min_words_allocd() + || GC_heapsize >= GC_collect_at_heapsize); } @@ -924,22 +929,32 @@ # endif } # endif - expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd()); - if (5 * HBLKSIZE * MAXHINCR > expansion_slop) { - expansion_slop = 5 * HBLKSIZE * MAXHINCR; - } + expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE; if (GC_last_heap_addr == 0 && !((word)space & SIGNB) || GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) { /* Assume the heap is growing up */ GC_greatest_plausible_heap_addr = - GC_max(GC_greatest_plausible_heap_addr, - (ptr_t)space + bytes + expansion_slop); + (GC_PTR)GC_max((ptr_t)GC_greatest_plausible_heap_addr, + (ptr_t)space + bytes + expansion_slop); } else { /* Heap is growing down */ GC_least_plausible_heap_addr = - GC_min(GC_least_plausible_heap_addr, - (ptr_t)space - expansion_slop); + (GC_PTR)GC_min((ptr_t)GC_least_plausible_heap_addr, + (ptr_t)space - expansion_slop); } + /* Force GC before we are likely to allocate past expansion_slop */ + GC_collect_at_heapsize = + GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE; +# if defined(LARGE_CONFIG) + if (GC_collect_at_heapsize < GC_heapsize /* wrapped */) + GC_collect_at_heapsize = (word)(-1); + if (((ptr_t)GC_greatest_plausible_heap_addr <= (ptr_t)space + bytes + || (ptr_t)GC_least_plausible_heap_addr >= (ptr_t)space) + && GC_heapsize > 0) { + /* GC_add_to_heap will fix this, but ... */ + WARN("Too close to address space limit: blacklisting ineffective\n", 0); + } +# endif GC_prev_heap_addr = GC_last_heap_addr; GC_last_heap_addr = (ptr_t)space; GC_add_to_heap(space, bytes); Index: boehm-gc/configure.in =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/configure.in,v retrieving revision 1.62 diff -u -r1.62 configure.in --- boehm-gc/configure.in 27 Feb 2004 00:58:16 -0000 1.62 +++ boehm-gc/configure.in 17 Mar 2004 20:09:28 -0000 @@ -472,6 +472,7 @@ AC_MSG_WARN("Must define GC_DEBUG and use debug alloc. in clients.") AC_DEFINE(KEEP_BACK_PTRS) AC_DEFINE(DBG_HDRS_ALL) + AC_DEFINE(LIBGCJ_GC_DEBUG) case $host in ia64-*-linux* ) AC_DEFINE(MAKE_BACK_GRAPH) Index: boehm-gc/dbg_mlc.c =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/dbg_mlc.c,v retrieving revision 1.13 diff -u -r1.13 dbg_mlc.c --- boehm-gc/dbg_mlc.c 28 Jul 2003 04:18:20 -0000 1.13 +++ boehm-gc/dbg_mlc.c 17 Mar 2004 20:09:28 -0000 @@ -195,13 +195,13 @@ (unsigned long)i); switch(source) { case GC_REFD_FROM_ROOT: - GC_err_printf1("root at 0x%lx\n", (unsigned long)base); + GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base); goto out; case GC_REFD_FROM_REG: - GC_err_printf0("root in register\n"); + GC_err_printf0("root in register\n\n"); goto out; case GC_FINALIZER_REFD: - GC_err_printf0("list of finalizable objects\n"); + GC_err_printf0("list of finalizable objects\n\n"); goto out; case GC_REFD_FROM_HEAP: GC_err_printf1("offset %ld in object:\n", (unsigned long)offset); @@ -217,15 +217,20 @@ /* Force a garbage collection and generate a backtrace from a */ /* random heap address. */ - void GC_generate_random_backtrace(void) + void GC_generate_random_backtrace_no_gc(void) { void * current; - GC_gcollect(); current = GC_generate_random_valid_address(); - GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current); + GC_printf1("\n****Chose address 0x%lx in object\n", (unsigned long)current); GC_print_backtrace(current); } + void GC_generate_random_backtrace(void) + { + GC_gcollect(); + GC_generate_random_backtrace_no_gc(); + } + #endif /* KEEP_BACK_PTRS */ # define CROSSES_HBLK(p, sz) \ @@ -325,6 +330,58 @@ } #endif /* !SHORT_DBG_HDRS */ +static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0}; + +void GC_register_describe_type_fn(kind, fn) +int kind; +GC_describe_type_fn fn; +{ + GC_describe_type_fns[kind] = fn; +} + +/* Print a type description for the object whose client-visible address */ +/* is p. */ +void GC_print_type(p) +ptr_t p; +{ + hdr * hhdr = GC_find_header(p); + char buffer[GC_TYPE_DESCR_LEN + 1]; + int kind = hhdr -> hb_obj_kind; + + if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) { + /* This should preclude free list objects except with */ + /* thread-local allocation. */ + buffer[GC_TYPE_DESCR_LEN] = 0; + (GC_describe_type_fns[kind])(p, buffer); + GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0); + GC_err_puts(buffer); + } else { + switch(kind) { + case PTRFREE: + GC_err_puts("PTRFREE"); + break; + case NORMAL: + GC_err_puts("NORMAL"); + break; + case UNCOLLECTABLE: + GC_err_puts("UNCOLLECTABLE"); + break; +# ifdef ATOMIC_UNCOLLECTABLE + case AUNCOLLECTABLE: + GC_err_puts("ATOMIC UNCOLLECTABLE"); + break; +# endif + case STUBBORN: + GC_err_puts("STUBBORN"); + break; + default: + GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr); + } + } +} + + + void GC_print_obj(p) ptr_t p; { @@ -334,11 +391,13 @@ GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh))); GC_err_puts(ohdr -> oh_string); # ifdef SHORT_DBG_HDRS - GC_err_printf1(":%ld)\n", (unsigned long)(ohdr -> oh_int)); + GC_err_printf1(":%ld, ", (unsigned long)(ohdr -> oh_int)); # else - GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), + GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int), (unsigned long)(ohdr -> oh_sz)); # endif + GC_print_type((ptr_t)(ohdr + 1)); + GC_err_puts(")\n"); PRINT_CALL_CHAIN(ohdr); } @@ -403,6 +462,8 @@ GC_register_displacement((word)sizeof(oh)); } +size_t GC_debug_header_size = sizeof(oh); + # if defined(__STDC__) || defined(__cplusplus) void GC_debug_register_displacement(GC_word offset) # else @@ -1013,7 +1074,8 @@ GC_finalization_proc my_old_fn; GC_PTR my_old_cd; ptr_t base = GC_base(obj); - if (0 == base || (ptr_t)obj - base != sizeof(oh)) { + if (0 == base) return; + if ((ptr_t)obj - base != sizeof(oh)) { GC_err_printf1( "GC_debug_register_finalizer called with non-base-pointer 0x%lx\n", obj); @@ -1045,7 +1107,8 @@ GC_finalization_proc my_old_fn; GC_PTR my_old_cd; ptr_t base = GC_base(obj); - if (0 == base || (ptr_t)obj - base != sizeof(oh)) { + if (0 == base) return; + if ((ptr_t)obj - base != sizeof(oh)) { GC_err_printf1( "GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n", obj); @@ -1078,7 +1141,8 @@ GC_finalization_proc my_old_fn; GC_PTR my_old_cd; ptr_t base = GC_base(obj); - if (0 == base || (ptr_t)obj - base != sizeof(oh)) { + if (0 == base) return; + if ((ptr_t)obj - base != sizeof(oh)) { GC_err_printf1( "GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n", obj); Index: boehm-gc/finalize.c =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/finalize.c,v retrieving revision 1.12 diff -u -r1.12 finalize.c --- boehm-gc/finalize.c 28 Jul 2003 04:18:20 -0000 1.12 +++ boehm-gc/finalize.c 17 Mar 2004 20:09:28 -0000 @@ -809,6 +809,31 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void)) { + /* This is a convenient place to generate backtraces if appropriate, */ + /* since that code is not callable with the allocation lock. */ +# ifdef KEEP_BACK_PTRS + if (GC_backtraces > 0) { + static word last_back_trace_gc_no = 3; /* Skip early ones. */ + long i; + + LOCK(); + if (GC_gc_no > last_back_trace_gc_no) { + /* Stops when GC_gc_no wraps; that's OK. */ + last_back_trace_gc_no = (word)(-1); /* disable others. */ + for (i = 0; i < GC_backtraces; ++i) { + /* FIXME: This tolerates concurrent heap mutation, */ + /* which may cause occasional mysterious results. */ + /* We need to release the GC lock, since GC_print_callers */ + /* acquires it. It probably shouldn't. */ + UNLOCK(); + GC_generate_random_backtrace_no_gc(); + LOCK(); + } + last_back_trace_gc_no = GC_gc_no; + } + UNLOCK(); + } +# endif if (GC_finalize_now == 0) return; if (!GC_finalize_on_demand) { (void) GC_invoke_finalizers(); Index: boehm-gc/misc.c =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/misc.c,v retrieving revision 1.28 diff -u -r1.28 misc.c --- boehm-gc/misc.c 3 Oct 2003 18:43:06 -0000 1.28 +++ boehm-gc/misc.c 17 Mar 2004 20:09:29 -0000 @@ -116,6 +116,11 @@ GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */ #endif +#ifdef KEEP_BACK_PTRS + long GC_backtraces = 0; /* Number of random backtraces to */ + /* generate for each GC. */ +#endif + #ifdef FIND_LEAK int GC_find_leak = 1; #else @@ -575,6 +580,15 @@ GC_dump_regularly = 1; } # endif +# ifdef KEEP_BACK_PTRS + { + char * backtraces_string = GETENV("GC_BACKTRACES"); + if (0 != backtraces_string) { + GC_backtraces = atol(backtraces_string); + if (backtraces_string[0] == '\0') GC_backtraces = 1; + } + } +# endif if (0 != GETENV("GC_FIND_LEAK")) { GC_find_leak = 1; # ifdef __STDC__ @@ -1062,6 +1076,74 @@ LOCK(); GC_dont_gc++; UNLOCK(); +} + +/* Helper procedures for new kind creation. */ +void ** GC_new_free_list_inner() +{ + void *result = GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE); + if (result == 0) ABORT("Failed to allocate freelist for new kind"); + BZERO(result, (MAXOBJSZ+1)*sizeof(ptr_t)); + return result; +} + +void ** GC_new_free_list() +{ + void *result; + LOCK(); DISABLE_SIGNALS(); + result = GC_new_free_list_inner(); + UNLOCK(); ENABLE_SIGNALS(); + return result; +} + +int GC_new_kind_inner(fl, descr, adjust, clear) +void **fl; +GC_word descr; +int adjust; +int clear; +{ + int result = GC_n_kinds++; + + if (GC_n_kinds > MAXOBJKINDS) ABORT("Too many kinds"); + GC_obj_kinds[result].ok_freelist = (ptr_t *)fl; + GC_obj_kinds[result].ok_reclaim_list = 0; + GC_obj_kinds[result].ok_descriptor = descr; + GC_obj_kinds[result].ok_relocate_descr = adjust; + GC_obj_kinds[result].ok_init = clear; + return result; +} + +int GC_new_kind(fl, descr, adjust, clear) +void **fl; +GC_word descr; +int adjust; +int clear; +{ + int result; + LOCK(); DISABLE_SIGNALS(); + result = GC_new_kind_inner(fl, descr, adjust, clear); + UNLOCK(); ENABLE_SIGNALS(); + return result; +} + +int GC_new_proc_inner(proc) +GC_mark_proc proc; +{ + int result = GC_n_mark_procs++; + + if (GC_n_mark_procs > MAX_MARK_PROCS) ABORT("Too many mark procedures"); + GC_mark_procs[result] = proc; + return result; +} + +int GC_new_proc(proc) +GC_mark_proc proc; +{ + int result; + LOCK(); DISABLE_SIGNALS(); + result = GC_new_proc_inner(proc); + UNLOCK(); ENABLE_SIGNALS(); + return result; } #if !defined(NO_DEBUGGING) Index: boehm-gc/gcj_mlc.c =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/gcj_mlc.c,v retrieving revision 1.8 diff -u -r1.8 gcj_mlc.c --- boehm-gc/gcj_mlc.c 28 Jul 2003 04:18:20 -0000 1.8 +++ boehm-gc/gcj_mlc.c 17 Mar 2004 20:09:29 -0000 @@ -72,46 +72,36 @@ GC_printf0("Gcj-style type information is disabled!\n"); } # endif + GC_ASSERT(GC_mark_procs[mp_index] == (GC_mark_proc)0); /* unused */ GC_mark_procs[mp_index] = (GC_mark_proc)mp; if (mp_index >= GC_n_mark_procs) ABORT("GC_init_gcj_malloc: bad index"); /* Set up object kind gcj-style indirect descriptor. */ - GC_gcjobjfreelist = (ptr_t *) - GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE); - if (GC_gcjobjfreelist == 0) ABORT("Couldn't allocate GC_gcjobjfreelist"); - BZERO(GC_gcjobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t)); - GC_gcj_kind = GC_n_kinds++; - GC_obj_kinds[GC_gcj_kind].ok_freelist = GC_gcjobjfreelist; - GC_obj_kinds[GC_gcj_kind].ok_reclaim_list = 0; + GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner(); if (ignore_gcj_info) { /* Use a simple length-based descriptor, thus forcing a fully */ /* conservative scan. */ - GC_obj_kinds[GC_gcj_kind].ok_descriptor = (0 | GC_DS_LENGTH); - GC_obj_kinds[GC_gcj_kind].ok_relocate_descr = TRUE; + GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist, + (0 | GC_DS_LENGTH), + TRUE, TRUE); } else { - GC_obj_kinds[GC_gcj_kind].ok_descriptor = - (((word)(-MARK_DESCR_OFFSET - GC_INDIR_PER_OBJ_BIAS)) - | GC_DS_PER_OBJECT); - GC_obj_kinds[GC_gcj_kind].ok_relocate_descr = FALSE; + GC_gcj_kind = GC_new_kind_inner( + (void **)GC_gcjobjfreelist, + (((word)(-MARK_DESCR_OFFSET - GC_INDIR_PER_OBJ_BIAS)) + | GC_DS_PER_OBJECT), + FALSE, TRUE); } - GC_obj_kinds[GC_gcj_kind].ok_init = TRUE; /* Set up object kind for objects that require mark proc call. */ - GC_gcjdebugobjfreelist = (ptr_t *) - GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE); - if (GC_gcjdebugobjfreelist == 0) - ABORT("Couldn't allocate GC_gcjdebugobjfreelist"); - BZERO(GC_gcjdebugobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t)); - GC_gcj_debug_kind = GC_n_kinds++; - GC_obj_kinds[GC_gcj_debug_kind].ok_freelist = GC_gcjdebugobjfreelist; - GC_obj_kinds[GC_gcj_debug_kind].ok_reclaim_list = 0; if (ignore_gcj_info) { - GC_obj_kinds[GC_gcj_kind].ok_descriptor = (0 | GC_DS_LENGTH); - GC_obj_kinds[GC_gcj_kind].ok_relocate_descr = TRUE; + GC_gcj_debug_kind = GC_gcj_kind; + GC_gcjdebugobjfreelist = GC_gcjobjfreelist; } else { - GC_obj_kinds[GC_gcj_debug_kind].ok_descriptor = - GC_MAKE_PROC(mp_index, 1 /* allocated with debug info */); - GC_obj_kinds[GC_gcj_debug_kind].ok_relocate_descr = FALSE; + GC_gcjdebugobjfreelist = (ptr_t *)GC_new_free_list_inner(); + GC_gcj_debug_kind = GC_new_kind_inner( + (void **)GC_gcjdebugobjfreelist, + GC_MAKE_PROC(mp_index, + 1 /* allocated with debug info */), + FALSE, TRUE); } - GC_obj_kinds[GC_gcj_debug_kind].ok_init = TRUE; UNLOCK(); ENABLE_SIGNALS(); } @@ -179,8 +169,7 @@ { GC_PTR result; - /* We clone the code from GC_debug_gcj_malloc, so that we */ - /* dont end up with extra frames on the stack, which could */ + /* We're careful to avoid extra calls, which could */ /* confuse the backtrace. */ LOCK(); result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind); Index: boehm-gc/doc/README.environment =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/doc/README.environment,v retrieving revision 1.6 diff -u -r1.6 README.environment --- boehm-gc/doc/README.environment 28 Jul 2003 04:18:22 -0000 1.6 +++ boehm-gc/doc/README.environment 17 Mar 2004 20:09:29 -0000 @@ -26,6 +26,14 @@ if you have a bug to report, but please include only the last complete dump. +GC_BACKTRACES= - Generate n random backtraces (for heap profiling) after + each GC. Collector must have been built with + KEEP_BACK_PTRS. This won't generate useful output unless + most objects in the heap were allocated through debug + allocators. This is intended to be only a statistical + sample; individual traces may be erroneous due to + concurrent heap mutation. + GC_PRINT_ADDRESS_MAP - Linux only. Dump /proc/self/maps, i.e. various address maps for the process, to stderr on every GC. Useful for mapping root addresses to source for deciphering leak Index: boehm-gc/include/gc_mark.h =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/include/gc_mark.h,v retrieving revision 1.3 diff -u -r1.3 gc_mark.h --- boehm-gc/include/gc_mark.h 28 Jul 2003 04:18:23 -0000 1.3 +++ boehm-gc/include/gc_mark.h 17 Mar 2004 20:09:29 -0000 @@ -19,10 +19,8 @@ * This interface should not be used by normal C or C++ clients. * It will be useful to runtimes for other languages. * - * Note that this file is not "namespace-clean", i.e. it introduces names - * not prefixed with GC_, which may collide with the client's names. It - * should be included only in those few places that directly provide - * information to the collector. + * This is an experts-only interface! There are many ways to break the + * collector in subtle ways by using this functionality. */ #ifndef GC_MARK_H # define GC_MARK_H @@ -142,6 +140,64 @@ (GC_word)obj <= (GC_word)GC_greatest_plausible_heap_addr)? \ GC_mark_and_push(obj, msp, lim, src) : \ msp) + +extern size_t GC_debug_header_size; + /* The size of the header added to objects allocated through */ + /* the GC_debug routines. */ + /* Defined as a variable so that client mark procedures don't */ + /* need to be recompiled for collector version changes. */ +#define GC_USR_PTR_FROM_BASE(p) ((GC_PTR)((char *)(p) + GC_debug_header_size)) + +/* And some routines to support creation of new "kinds", e.g. with */ +/* custom mark procedures, by language runtimes. */ +/* The _inner versions assume the caller holds the allocation lock. */ + +/* Return a new free list array. */ +void ** GC_new_free_list GC_PROTO((void)); +void ** GC_new_free_list_inner GC_PROTO((void)); + +/* Return a new kind, as specified. */ +int GC_new_kind GC_PROTO((void **free_list, GC_word mark_descriptor_template, + int add_size_to_descriptor, int clear_new_objects)); + /* The last two parameters must be zero or one. */ +int GC_new_kind_inner GC_PROTO((void **free_list, + GC_word mark_descriptor_template, + int add_size_to_descriptor, + int clear_new_objects)); + +/* Return a new mark procedure identifier, suitable for use as */ +/* the first argument in GC_MAKE_PROC. */ +int GC_new_proc GC_PROTO((GC_mark_proc)); +int GC_new_proc_inner GC_PROTO((GC_mark_proc)); + +/* Allocate an object of a given kind. Note that in multithreaded */ +/* contexts, this is usually unsafe for kinds that have the descriptor */ +/* in the object itself, since there is otherwise a window in which */ +/* the descriptor is not correct. Even in the single-threaded case, */ +/* we need to be sure that cleared objects on a free list don't */ +/* cause a GC crash if they are accidentally traced. */ +/* ptr_t */char * GC_generic_malloc GC_PROTO((GC_word lb, int k)); + +/* FIXME - Should return void *, but that requires other changes. */ + +typedef void (*GC_describe_type_fn) GC_PROTO((void *p, char *out_buf)); + /* A procedure which */ + /* produces a human-readable */ + /* description of the "type" of object */ + /* p into the buffer out_buf of length */ + /* GC_TYPE_DESCR_LEN. This is used by */ + /* the debug support when printing */ + /* objects. */ + /* These functions should be as robust */ + /* as possible, though we do avoid */ + /* invoking them on objects on the */ + /* global free list. */ +# define GC_TYPE_DESCR_LEN 40 + +void GC_register_describe_type_fn GC_PROTO((int kind, GC_describe_type_fn knd)); + /* Register a describe_type function */ + /* to be used when printing objects */ + /* of a particular kind. */ #endif /* GC_MARK_H */ Index: boehm-gc/include/javaxfc.h =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/include/javaxfc.h,v retrieving revision 1.2 diff -u -r1.2 javaxfc.h --- boehm-gc/include/javaxfc.h 17 Aug 2001 18:30:50 -0000 1.2 +++ boehm-gc/include/javaxfc.h 17 Mar 2004 20:09:29 -0000 @@ -17,25 +17,3 @@ * Thus this is not recommended for general use. */ void GC_finalize_all(); - -/* - * A version of GC_register_finalizer that allows the object to be - * finalized before the objects it references. This is again error - * prone, in that it makes it easy to accidentally reference finalized - * objects. Again, recommended only for JVM implementors. - */ -void GC_register_finalizer_no_order(GC_PTR obj, - GC_finalization_proc fn, GC_PTR cd, - GC_finalization_proc *ofn, GC_PTR * ocd); - -void GC_debug_register_finalizer_no_order(GC_PTR obj, - GC_finalization_proc fn, GC_PTR cd, - GC_finalization_proc *ofn, GC_PTR * ocd); - -#ifdef GC_DEBUG -# define GC_REGISTER_FINALIZER(p, f, d, of, od) \ - GC_debug_register_finalizer_no_order(p, f, d, of, od) -#else -# define GC_REGISTER_FINALIZER(p, f, d, of, od) \ - GC_register_finalizer_no_order(p, f, d, of, od) -#endif Index: boehm-gc/include/gc_gcj.h =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/include/gc_gcj.h,v retrieving revision 1.3 diff -u -r1.3 gc_gcj.h --- boehm-gc/include/gc_gcj.h 16 Oct 2001 09:01:38 -0000 1.3 +++ boehm-gc/include/gc_gcj.h 17 Mar 2004 20:09:29 -0000 @@ -53,7 +53,7 @@ /* respectively for the allocated objects. Mark_proc will be */ /* used to build the descriptor for objects allocated through the */ /* debugging interface. The mark_proc will be invoked on all such */ -/* objects with an "environment" value of 1. The client may chose */ +/* objects with an "environment" value of 1. The client may choose */ /* to use the same mark_proc for some of its generated mark descriptors.*/ /* In that case, it should use a different "environment" value to */ /* detect the presence or absence of the debug header. */ @@ -87,6 +87,17 @@ /* beginning of the resulting object is always maintained. */ extern void * GC_gcj_malloc_ignore_off_page(size_t lb, void * ptr_to_struct_containing_descr); + +/* The kind numbers of normal and debug gcj objects. */ +/* Useful only for debug support, we hope. */ +extern int GC_gcj_kind; + +extern int GC_gcj_debug_kind; + +# if defined(GC_LOCAL_ALLOC_H) && defined(GC_REDIRECT_TO_LOCAL) + --> gc_local_alloc.h should be included after this. Otherwise + --> we undo the redirection. +# endif # ifdef GC_DEBUG # define GC_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS) Index: boehm-gc/include/private/dbg_mlc.h =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/include/private/dbg_mlc.h,v retrieving revision 1.5 diff -u -r1.5 dbg_mlc.h --- boehm-gc/include/private/dbg_mlc.h 28 Jul 2003 04:18:23 -0000 1.5 +++ boehm-gc/include/private/dbg_mlc.h 17 Mar 2004 20:09:29 -0000 @@ -123,7 +123,6 @@ # 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) Index: boehm-gc/include/private/gc_priv.h =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/include/private/gc_priv.h,v retrieving revision 1.13 diff -u -r1.13 gc_priv.h --- boehm-gc/include/private/gc_priv.h 3 Oct 2003 18:43:06 -0000 1.13 +++ boehm-gc/include/private/gc_priv.h 17 Mar 2004 20:09:29 -0000 @@ -1610,7 +1610,7 @@ /* 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)); +/* 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), */ @@ -1620,6 +1620,7 @@ /* internals to add more, e.g. to */ /* communicate object layout info */ /* to the collector. */ + /* The actual decl is in gc_mark.h. */ 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 */ @@ -1715,6 +1716,10 @@ # define COND_DUMP if (GC_dump_regularly) GC_dump(); #else # define COND_DUMP +#endif + +#ifdef KEEP_BACK_PTRS + extern long GC_backtraces; #endif /* Macros used for collector internal allocation. */ Index: boehm-gc/tests/test.c =================================================================== RCS file: /cvs/gcc/gcc/boehm-gc/tests/test.c,v retrieving revision 1.8 diff -u -r1.8 test.c --- boehm-gc/tests/test.c 28 Jul 2003 04:18:23 -0000 1.8 +++ boehm-gc/tests/test.c 17 Mar 2004 20:09:29 -0000 @@ -208,7 +208,6 @@ #ifdef GC_GCJ_SUPPORT #include "gc_mark.h" -#include "private/dbg_mlc.h" /* For USR_PTR_FROM_BASE */ #include "gc_gcj.h" /* The following struct emulates the vtable in gcj. */ @@ -233,7 +232,7 @@ sexpr x; if (1 == env) { /* Object allocated with debug allocator. */ - addr = (word *)USR_PTR_FROM_BASE(addr); + addr = (word *)GC_USR_PTR_FROM_BASE(addr); } x = (sexpr)(addr + 1); /* Skip the vtable pointer. */ mark_stack_ptr = GC_MARK_AND_PUSH( Index: libjava/boehm.cc =================================================================== RCS file: /cvs/gcc/gcc/libjava/boehm.cc,v retrieving revision 1.42 diff -u -r1.42 boehm.cc --- libjava/boehm.cc 4 Dec 2003 13:07:07 -0000 1.42 +++ libjava/boehm.cc 17 Mar 2004 20:09:29 -0000 @@ -8,6 +8,10 @@ Libgcj License. Please consult the file "LIBGCJ_LICENSE" for details. */ +#ifdef LIBGCJ_GC_DEBUG +# define GC_DEBUG +#endif + #include #include @@ -27,17 +31,14 @@ extern "C" { -#include +#include #include +#include // GC_finalize_all declaration. #ifdef THREAD_LOCAL_ALLOC # define GC_REDIRECT_TO_LOCAL # include #endif - - // These aren't declared in any Boehm GC header. - void GC_finalize_all (void); - ptr_t GC_debug_generic_malloc (size_t size, int k, GC_EXTRA_PARAMS); }; #define MAYBE_MARK(Obj, Top, Limit, Source, Exit) \ @@ -47,10 +48,7 @@ static int array_kind_x; // Freelist used for Java arrays. -static ptr_t *array_free_list; - -// Lock used to protect access to Boehm's GC_enable/GC_disable functions. -static _Jv_Mutex_t disable_gc_mutex; +static void * *array_free_list; @@ -58,15 +56,14 @@ // object. We use `void *' arguments and return, and not what the // Boehm GC wants, to avoid pollution in our headers. void * -_Jv_MarkObj (void *addr, void *msp, void *msl, void * /* env */) +_Jv_MarkObj (void *addr, void *msp, void *msl, void * env) { - mse *mark_stack_ptr = (mse *) msp; - mse *mark_stack_limit = (mse *) msl; - jobject obj = (jobject) addr; + struct GC_ms_entry *mark_stack_ptr = (struct GC_ms_entry *)msp; + struct GC_ms_entry *mark_stack_limit = (struct GC_ms_entry *)msl; - // FIXME: if env is 1, this object was allocated through the debug - // interface, and addr points to the beginning of the debug header. - // In that case, we should really add the size of the header to addr. + if (env == (void *)1) /* Object allocated with debug allocator. */ + addr = (GC_PTR)GC_USR_PTR_FROM_BASE(addr); + jobject obj = (jobject) addr; _Jv_VTable *dt = *(_Jv_VTable **) addr; // The object might not yet have its vtable set, or it might @@ -78,15 +75,15 @@ if (__builtin_expect (! dt || !(dt -> get_finalizer()), false)) return mark_stack_ptr; jclass klass = dt->clas; - ptr_t p; + GC_PTR p; # ifndef JV_HASH_SYNCHRONIZATION // Every object has a sync_info pointer. - p = (ptr_t) obj->sync_info; + p = (GC_PTR) obj->sync_info; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o1label); # endif // Mark the object's class. - p = (ptr_t) klass; + p = (GC_PTR) klass; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, o2label); if (__builtin_expect (klass == &java::lang::Class::class$, false)) @@ -105,25 +102,25 @@ // of our root set. - HB jclass c = (jclass) addr; - p = (ptr_t) c->name; + p = (GC_PTR) c->name; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c3label); - p = (ptr_t) c->superclass; + p = (GC_PTR) c->superclass; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c4label); for (int i = 0; i < c->constants.size; ++i) { /* FIXME: We could make this more precise by using the tags -KKT */ - p = (ptr_t) c->constants.data[i].p; + p = (GC_PTR) c->constants.data[i].p; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5label); } #ifdef INTERPRETER if (_Jv_IsInterpretedClass (c)) { - p = (ptr_t) c->constants.tags; + p = (GC_PTR) c->constants.tags; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5alabel); - p = (ptr_t) c->constants.data; + p = (GC_PTR) c->constants.data; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5blabel); - p = (ptr_t) c->vtable; + p = (GC_PTR) c->vtable; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c5clabel); } #endif @@ -131,7 +128,7 @@ // If the class is an array, then the methods field holds a // pointer to the element class. If the class is primitive, // then the methods field holds a pointer to the array class. - p = (ptr_t) c->methods; + p = (GC_PTR) c->methods; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c6label); // The vtable might have been set, but the rest of the class @@ -147,34 +144,34 @@ // points to a methods structure. for (int i = 0; i < c->method_count; ++i) { - p = (ptr_t) c->methods[i].name; + p = (GC_PTR) c->methods[i].name; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cm1label); - p = (ptr_t) c->methods[i].signature; + p = (GC_PTR) c->methods[i].signature; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cm2label); } } // Mark all the fields. - p = (ptr_t) c->fields; + p = (GC_PTR) c->fields; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8label); for (int i = 0; i < c->field_count; ++i) { _Jv_Field* field = &c->fields[i]; #ifndef COMPACT_FIELDS - p = (ptr_t) field->name; + p = (GC_PTR) field->name; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8alabel); #endif - p = (ptr_t) field->type; + p = (GC_PTR) field->type; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8blabel); // For the interpreter, we also need to mark the memory // containing static members if ((field->flags & java::lang::reflect::Modifier::STATIC)) { - p = (ptr_t) field->u.addr; + p = (GC_PTR) field->u.addr; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8clabel); // also, if the static member is a reference, @@ -184,29 +181,29 @@ if (JvFieldIsRef (field) && field->isResolved()) { jobject val = *(jobject*) field->u.addr; - p = (ptr_t) val; + p = (GC_PTR) val; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c8elabel); } } } - p = (ptr_t) c->vtable; + p = (GC_PTR) c->vtable; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, c9label); - p = (ptr_t) c->interfaces; + p = (GC_PTR) c->interfaces; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cAlabel); for (int i = 0; i < c->interface_count; ++i) { - p = (ptr_t) c->interfaces[i]; + p = (GC_PTR) c->interfaces[i]; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cClabel); } - p = (ptr_t) c->loader; + p = (GC_PTR) c->loader; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cBlabel); - p = (ptr_t) c->arrayclass; + p = (GC_PTR) c->arrayclass; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cDlabel); - p = (ptr_t) c->protectionDomain; + p = (GC_PTR) c->protectionDomain; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cPlabel); - p = (ptr_t) c->hack_signers; + p = (GC_PTR) c->hack_signers; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cSlabel); #ifdef INTERPRETER @@ -214,12 +211,12 @@ { _Jv_InterpClass* ic = (_Jv_InterpClass*) c; - p = (ptr_t) ic->interpreted_methods; + p = (GC_PTR) ic->interpreted_methods; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, cElabel); for (int i = 0; i < c->method_count; i++) { - p = (ptr_t) ic->interpreted_methods[i]; + p = (GC_PTR) ic->interpreted_methods[i]; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, \ cFlabel); @@ -231,7 +228,7 @@ = (_Jv_InterpMethod *) ic->interpreted_methods[i]; if (im) { - p = (ptr_t) im->prepared; + p = (GC_PTR) im->prepared; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, \ cFlabel); } @@ -239,12 +236,12 @@ // The interpreter installs a heap-allocated trampoline // here, so we'll mark it. - p = (ptr_t) c->methods[i].ncode; + p = (GC_PTR) c->methods[i].ncode; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, c, cm3label); } - p = (ptr_t) ic->field_initializers; + p = (GC_PTR) ic->field_initializers; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, ic, cGlabel); } @@ -271,7 +268,7 @@ if (JvFieldIsRef (field)) { jobject val = JvGetObjectField (obj, field); - p = (ptr_t) val; + p = (GC_PTR) val; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, obj, elabel); } @@ -288,10 +285,13 @@ // array (of objects). We use `void *' arguments and return, and not // what the Boehm GC wants, to avoid pollution in our headers. void * -_Jv_MarkArray (void *addr, void *msp, void *msl, void * /*env*/) +_Jv_MarkArray (void *addr, void *msp, void *msl, void * env) { - mse *mark_stack_ptr = (mse *) msp; - mse *mark_stack_limit = (mse *) msl; + struct GC_ms_entry *mark_stack_ptr = (struct GC_ms_entry *)msp; + struct GC_ms_entry *mark_stack_limit = (struct GC_ms_entry *)msl; + + if (env == (void *)1) /* Object allocated with debug allocator. */ + addr = (void *)GC_USR_PTR_FROM_BASE(addr); jobjectArray array = (jobjectArray) addr; _Jv_VTable *dt = *(_Jv_VTable **) addr; @@ -301,21 +301,21 @@ if (__builtin_expect (! dt || !(dt -> get_finalizer()), false)) return mark_stack_ptr; jclass klass = dt->clas; - ptr_t p; + GC_PTR p; # ifndef JV_HASH_SYNCHRONIZATION // Every object has a sync_info pointer. - p = (ptr_t) array->sync_info; + p = (GC_PTR) array->sync_info; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array, e1label); # endif // Mark the object's class. - p = (ptr_t) klass; + p = (GC_PTR) klass; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, &(dt -> clas), o2label); for (int i = 0; i < JvGetArrayLength (array); ++i) { jobject obj = elements (array)[i]; - p = (ptr_t) obj; + p = (GC_PTR) obj; MAYBE_MARK (p, mark_stack_ptr, mark_stack_limit, array, e2label); } @@ -364,7 +364,7 @@ // If we find a field outside the range of our bitmap, // fall back to procedure marker. The bottom 2 bits are // reserved. - if (off >= bits_per_word - 2) + if (off >= (unsigned)bits_per_word - 2) return (void *) (GCJ_DEFAULT_DESCR); desc |= 1ULL << (bits_per_word - off - 1); } @@ -392,12 +392,44 @@ return r; } +#ifdef LIBGCJ_GC_DEBUG + +void * +_Jv_AllocObj (jsize size, jclass klass) +{ + return GC_GCJ_MALLOC (size, klass->vtable); +} + +void * +_Jv_AllocPtrFreeObj (jsize size, jclass klass) +{ +#ifdef JV_HASH_SYNCHRONIZATION + void * obj = GC_MALLOC_ATOMIC(size); + *((_Jv_VTable **) obj) = klass->vtable; +#else + void * obj = GC_GCJ_MALLOC(size, klass->vtable); +#endif + return obj; +} + +#endif /* LIBGCJ_GC_DEBUG */ +// In the non-debug case, the above two functions are defined +// as inline functions in boehm-gc.h. In the debug case we +// really want to take advantage of the definitions in gc_gcj.h. + // Allocate space for a new Java array. // Used only for arrays of objects. void * _Jv_AllocArray (jsize size, jclass klass) { void *obj; + +#ifdef LIBGCJ_GC_DEBUG + // There isn't much to lose by scanning this conservatively. + // If we didn't, the mark proc would have to understand that + // it needed to skip the header. + obj = GC_MALLOC(size); +#else const jsize min_heap_addr = 16*1024; // A heuristic. If size is less than this value, the size // stored in the array can't possibly be misinterpreted as @@ -405,12 +437,6 @@ // completely conservatively, since no misidentification can // take place. -#ifdef GC_DEBUG - // There isn't much to lose by scanning this conservatively. - // If we didn't, the mark proc would have to understand that - // it needed to skip the header. - obj = GC_MALLOC(size); -#else if (size < min_heap_addr) obj = GC_MALLOC(size); else @@ -495,17 +521,13 @@ void _Jv_DisableGC (void) { - _Jv_MutexLock (&disable_gc_mutex); GC_disable(); - _Jv_MutexUnlock (&disable_gc_mutex); } void _Jv_EnableGC (void) { - _Jv_MutexLock (&disable_gc_mutex); GC_enable(); - _Jv_MutexUnlock (&disable_gc_mutex); } static void * handle_out_of_memory(size_t) @@ -513,6 +535,29 @@ _Jv_ThrowNoMemory(); } +static void +gcj_describe_type_fn(void *obj, char *out_buf) +{ + _Jv_VTable *dt = *(_Jv_VTable **) obj; + + if (! dt /* Shouldn't happen */) + { + strcpy(out_buf, "GCJ (bad)"); + return; + } + jclass klass = dt->clas; + if (!klass /* shouldn't happen */) + { + strcpy(out_buf, "GCJ (bad)"); + return; + } + jstring name = klass -> getName(); + size_t len = name -> length(); + if (len >= GC_TYPE_DESCR_LEN) len = GC_TYPE_DESCR_LEN - 1; + JvGetStringUTFRegion (name, 0, len, out_buf); + out_buf[len] = '\0'; +} + void _Jv_InitGC (void) { @@ -523,6 +568,8 @@ // Configure the collector to use the bitmap marking descriptors that we // stash in the class vtable. + // We always use mark proc descriptor 0, since the compiler knows + // about it. GC_init_gcj_malloc (0, (void *) _Jv_MarkObj); // Cause an out of memory error to be thrown from the allocators, @@ -533,23 +580,14 @@ // We use a different mark procedure for object arrays. This code // configures a different object `kind' for object array allocation and - // marking. FIXME: see above. - array_free_list = (ptr_t *) GC_generic_malloc_inner ((MAXOBJSZ + 1) - * sizeof (ptr_t), - PTRFREE); - memset (array_free_list, 0, (MAXOBJSZ + 1) * sizeof (ptr_t)); - - proc = GC_n_mark_procs++; - GC_mark_procs[proc] = (GC_mark_proc) _Jv_MarkArray; - - array_kind_x = GC_n_kinds++; - GC_obj_kinds[array_kind_x].ok_freelist = array_free_list; - GC_obj_kinds[array_kind_x].ok_reclaim_list = 0; - GC_obj_kinds[array_kind_x].ok_descriptor = GC_MAKE_PROC (proc, 0); - GC_obj_kinds[array_kind_x].ok_relocate_descr = FALSE; - GC_obj_kinds[array_kind_x].ok_init = TRUE; - - _Jv_MutexInit (&disable_gc_mutex); + // marking. + array_free_list = GC_new_free_list(); + proc = GC_new_proc((GC_mark_proc)_Jv_MarkArray); + array_kind_x = GC_new_kind(array_free_list, GC_MAKE_PROC (proc, 0), 0, 1); + + /* Arrange to have the GC print Java class names in backtraces, etc. */ + GC_register_describe_type_fn(GC_gcj_kind, gcj_describe_type_fn); + GC_register_describe_type_fn(GC_gcj_debug_kind, gcj_describe_type_fn); } #ifdef JV_HASH_SYNCHRONIZATION Index: libjava/include/boehm-gc.h =================================================================== RCS file: /cvs/gcc/gcc/libjava/include/boehm-gc.h,v retrieving revision 1.6 diff -u -r1.6 boehm-gc.h --- libjava/include/boehm-gc.h 28 Dec 2002 06:38:52 -0000 1.6 +++ libjava/include/boehm-gc.h 17 Mar 2004 20:09:29 -0000 @@ -33,6 +33,8 @@ extern "C" void * GC_local_malloc_atomic(size_t); #endif +#ifndef LIBGCJ_GC_DEBUG + inline void * _Jv_AllocObj (jsize size, jclass klass) { @@ -64,6 +66,16 @@ #endif return obj; } + +#else /* LIBGCJ_GC_DEBUG */ + +void * +_Jv_AllocObj (jsize size, jclass klass); + +void * +_Jv_AllocPtrFreeObj (jsize size, jclass klass); + +#endif /* LIBGCJ_GC_DEBUG */ // _Jv_AllocBytes (jsize size) should go here, too. But clients don't // usually include this header. Index: libjava/java/lang/natObject.cc =================================================================== RCS file: /cvs/gcc/gcc/libjava/java/lang/natObject.cc,v retrieving revision 1.29 diff -u -r1.29 natObject.cc --- libjava/java/lang/natObject.cc 23 Oct 2003 21:48:36 -0000 1.29 +++ libjava/java/lang/natObject.cc 17 Mar 2004 20:09:29 -0000 @@ -286,6 +286,9 @@ // operations is already ridiculous, and would become worse if we // went through the proper intermediaries. #else +# ifdef LIBGCJ_GC_DEBUG +# define GC_DEBUG +# endif # include "gc.h" #endif