diff options
42 files changed, 1274 insertions, 707 deletions
diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog index 635eb37e411..e1efa19d1c2 100644 --- a/boehm-gc/ChangeLog +++ b/boehm-gc/ChangeLog @@ -1,3 +1,8 @@ +2001-08-17 Tom Tromey <tromey@redhat.com> + + * Makefile.am, acinclude.m4, configure.in: Imported GC 6.0 and + merged local changes. + 2001-08-02 David Billinghurst <David.Billinghurst> * configure: Rebuilt. diff --git a/boehm-gc/Makefile.am b/boehm-gc/Makefile.am index f272879f4f2..0949ed8a373 100644 --- a/boehm-gc/Makefile.am +++ b/boehm-gc/Makefile.am @@ -37,13 +37,13 @@ libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS) libgcjgc_la_DEPENDENCIES = @addobjs@ libgcjgc_la_LDFLAGS = -version-info 1:1:0 -rpath $(toolexeclibdir) -EXTRA_libgcjgc_la_SOURCES = alpha_mach_dep.s hpux_test_and_clear.s \ +EXTRA_libgcjgc_la_SOURCES = alpha_mach_dep.s \ mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \ rs6000_mach_dep.s sparc_mach_dep.s sparc_netbsd_mach_dep.s \ sparc_sunos4_mach_dep.s -AM_CXXFLAGS = @BOEHM_GC_CFLAGS@ -AM_CFLAGS = @BOEHM_GC_CFLAGS@ +AM_CXXFLAGS = @GC_CFLAGS@ +AM_CFLAGS = @GC_CFLAGS@ check_PROGRAMS = gctest # The following hack produces a warning from automake, but we need it in order @@ -71,10 +71,10 @@ include/private/gc_hdrs.h include/gc.h include/gc_gcj.h include/gc_mark.h ## CFLAGS, not those passed in from the top level make. LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(MY_CFLAGS) $(BOEHM_GC_CFLAGS) + $(AM_CFLAGS) $(MY_CFLAGS) $(GC_CFLAGS) LINK = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(MY_CFLAGS) $(LDFLAGS) -o $@ -AM_CFLAGS = @BOEHM_GC_CFLAGS@ +AM_CFLAGS = @GC_CFLAGS@ # Work around what appears to be a GNU make bug handling MAKEFLAGS # values defined in terms of make variables, as is the case for CC and diff --git a/boehm-gc/Makefile.dj b/boehm-gc/Makefile.dj index 264344924c6..09fae4e613f 100644 --- a/boehm-gc/Makefile.dj +++ b/boehm-gc/Makefile.dj @@ -62,10 +62,11 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIO # code from the heap. Currently this only affects the incremental # collector on UNIX machines. It may greatly improve its performance, # since this may avoid some expensive cache synchronization. -# -DOPERATOR_NEW_ARRAY declares that the C++ compiler supports the -# new syntax "operator new[]" for allocating and deleting arrays. +# -DGC_NO_OPERATOR_NEW_ARRAY declares that the C++ compiler does not support +# the new syntax "operator new[]" for allocating and deleting arrays. # See gc_cpp.h for details. No effect on the C part of the collector. -# This is defined implicitly in a few environments. +# This is defined implicitly in a few environments. Must also be defined +# by clients that use gc_cpp.h. # -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined # as aliases for X, GC_realloc, and GC_free, respectively. # Calloc is redefined in terms of the new malloc. X should diff --git a/boehm-gc/Makefile.in b/boehm-gc/Makefile.in index e8fb04fa94b..e0900025f90 100644 --- a/boehm-gc/Makefile.in +++ b/boehm-gc/Makefile.in @@ -65,7 +65,6 @@ target_alias = @target_alias@ target_triplet = @target@ AR = @AR@ AS = @AS@ -BOEHM_GC_CFLAGS = @BOEHM_GC_CFLAGS@ CC = @CC@ CPP = @CPP@ CXX = @CXX@ @@ -76,6 +75,7 @@ EXEEXT = @EXEEXT@ EXTRA_TEST_LIBS = @EXTRA_TEST_LIBS@ GCJ = @GCJ@ GCJFLAGS = @GCJFLAGS@ +GC_CFLAGS = @GC_CFLAGS@ INCLUDES = @INCLUDES@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ @@ -90,7 +90,7 @@ STRIP = @STRIP@ THREADLIBS = @THREADLIBS@ VERSION = @VERSION@ addobjs = @addobjs@ -boehm_gc_basedir = @boehm_gc_basedir@ +gc_basedir = @gc_basedir@ mkinstalldirs = @mkinstalldirs@ target_all = @target_all@ @@ -125,15 +125,15 @@ libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS) libgcjgc_la_DEPENDENCIES = @addobjs@ libgcjgc_la_LDFLAGS = -version-info 1:1:0 -rpath $(toolexeclibdir) -EXTRA_libgcjgc_la_SOURCES = alpha_mach_dep.s hpux_test_and_clear.s \ +EXTRA_libgcjgc_la_SOURCES = alpha_mach_dep.s \ mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \ rs6000_mach_dep.s sparc_mach_dep.s sparc_netbsd_mach_dep.s \ sparc_sunos4_mach_dep.s -AM_CXXFLAGS = @BOEHM_GC_CFLAGS@ +AM_CXXFLAGS = @GC_CFLAGS@ -AM_CFLAGS = @BOEHM_GC_CFLAGS@ +AM_CFLAGS = @GC_CFLAGS@ check_PROGRAMS = gctest gctest_OBJECTS = test.o @@ -146,7 +146,7 @@ all_objs = @addobjs@ $(libgcjgc_la_OBJECTS) LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(MY_CFLAGS) $(BOEHM_GC_CFLAGS) + $(AM_CFLAGS) $(MY_CFLAGS) $(GC_CFLAGS) LINK = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(MY_CFLAGS) $(LDFLAGS) -o $@ @@ -216,7 +216,8 @@ CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) DIST_COMMON = ChangeLog Makefile.am Makefile.in acinclude.m4 aclocal.m4 \ -configure configure.in +config.guess config.sub configure configure.in install-sh ltconfig \ +ltmain.sh mkinstalldirs DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) diff --git a/boehm-gc/acinclude.m4 b/boehm-gc/acinclude.m4 index aa651f18eb4..1957026a946 100644 --- a/boehm-gc/acinclude.m4 +++ b/boehm-gc/acinclude.m4 @@ -1,10 +1,23 @@ +# Copyright (c) 1999-2001 by Red Hat, Inc. 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. +# +# Original author: Tom Tromey + # FIXME: We temporarily define our own version of AC_PROG_CC. This is # copied from autoconf 2.12, but does not call AC_PROG_CC_WORKS. We # are probably using a cross compiler, which will not be able to fully # link an executable. This should really be fixed in autoconf # itself. -AC_DEFUN(BOEHM_CONFIGURE, +AC_DEFUN(GC_CONFIGURE, [ dnl Default to --enable-multilib AC_ARG_ENABLE(multilib, @@ -18,17 +31,18 @@ AC_ARG_ENABLE(multilib, dnl We may get other options which we don't document: dnl --with-target-subdir, --with-multisrctop, --with-multisubdir +dnl I needed to add the -n test to allow configuration in src directory - HB if test "[$]{srcdir}" = "."; then - if test "[$]{with_target_subdir}" != "."; then - boehm_gc_basedir="[$]{srcdir}/[$]{with_multisrctop}../$1" + if test "[$]{with_target_subdir}" != "." -a -n "[$]{with_target_subdir}"; then + gc_basedir="[$]{srcdir}/[$]{with_multisrctop}../$1" else - boehm_gc_basedir="[$]{srcdir}/[$]{with_multisrctop}$1" + gc_basedir="[$]{srcdir}/[$]{with_multisrctop}$1" fi else - boehm_gc_basedir="[$]{srcdir}/$1" + gc_basedir="[$]{srcdir}/$1" fi -AC_SUBST(boehm_gc_basedir) -AC_CONFIG_AUX_DIR($boehm_gc_basedir/..) +AC_SUBST(gc_basedir) +AC_CONFIG_AUX_DIR($gc_basedir/..) if :; then :; else # This overrides the previous occurrence for automake, but not for # autoconf, which is exactly what we want. @@ -41,7 +55,7 @@ AC_CANONICAL_SYSTEM mkinstalldirs="`cd $ac_aux_dir && pwd`/mkinstalldirs" AC_SUBST(mkinstalldirs) -AM_INIT_AUTOMAKE(boehm-gc, 5.1, no-define) +AM_INIT_AUTOMAKE(gc, 6.0, no-define) # FIXME: We temporarily define our own version of AC_PROG_CC. This is # copied from autoconf 2.12, but does not call AC_PROG_CC_WORKS. We @@ -150,22 +164,22 @@ fi . [$]{srcdir}/configure.host -case [$]{boehm_gc_basedir} in -/* | [A-Za-z]:[/\\]*) boehm_gc_flagbasedir=[$]{boehm_gc_basedir} ;; -*) boehm_gc_flagbasedir='[$](top_builddir)/'[$]{boehm_gc_basedir} ;; +case [$]{gc_basedir} in +/* | [A-Za-z]:[/\\]*) gc_flagbasedir=[$]{gc_basedir} ;; +*) gc_flagbasedir='[$](top_builddir)/'[$]{gc_basedir} ;; esac -boehm_gc_cflags="[$]{boehm_gc_cflags} -I"'[$](top_builddir)'"/$1/targ-include -I[$]{boehm_gc_flagbasedir}/libc/include" +gc_cflags="[$]{gc_cflags} -I"'[$](top_builddir)'"/$1/targ-include -I[$]{gc_flagbasedir}/libc/include" case "${host}" in *-*-cygwin32*) - boehm_gc_cflags="[$]{boehm_gc_cflags} -I[$]{boehm_gc_flagbasedir}/../winsup/include" + gc_cflags="[$]{gc_cflags} -I[$]{gc_flagbasedir}/../winsup/include" ;; esac -boehm_gc_cflags="[$]{boehm_gc_cflags} -fno-builtin" +dnl gc_cflags="[$]{gc_cflags} -fno-builtin" -BOEHM_GC_CFLAGS=${boehm_gc_cflags} -AC_SUBST(BOEHM_GC_CFLAGS) +GC_CFLAGS=${gc_cflags} +AC_SUBST(GC_CFLAGS) ])) )))) diff --git a/boehm-gc/aclocal.m4 b/boehm-gc/aclocal.m4 index ab624da2693..f35b954b0fc 100644 --- a/boehm-gc/aclocal.m4 +++ b/boehm-gc/aclocal.m4 @@ -10,13 +10,26 @@ dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A dnl PARTICULAR PURPOSE. +# Copyright (c) 1999-2001 by Red Hat, Inc. 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. +# +# Original author: Tom Tromey + # FIXME: We temporarily define our own version of AC_PROG_CC. This is # copied from autoconf 2.12, but does not call AC_PROG_CC_WORKS. We # are probably using a cross compiler, which will not be able to fully # link an executable. This should really be fixed in autoconf # itself. -AC_DEFUN(BOEHM_CONFIGURE, +AC_DEFUN(GC_CONFIGURE, [ dnl Default to --enable-multilib AC_ARG_ENABLE(multilib, @@ -30,17 +43,18 @@ AC_ARG_ENABLE(multilib, dnl We may get other options which we don't document: dnl --with-target-subdir, --with-multisrctop, --with-multisubdir +dnl I needed to add the -n test to allow configuration in src directory - HB if test "[$]{srcdir}" = "."; then - if test "[$]{with_target_subdir}" != "."; then - boehm_gc_basedir="[$]{srcdir}/[$]{with_multisrctop}../$1" + if test "[$]{with_target_subdir}" != "." -a -n "[$]{with_target_subdir}"; then + gc_basedir="[$]{srcdir}/[$]{with_multisrctop}../$1" else - boehm_gc_basedir="[$]{srcdir}/[$]{with_multisrctop}$1" + gc_basedir="[$]{srcdir}/[$]{with_multisrctop}$1" fi else - boehm_gc_basedir="[$]{srcdir}/$1" + gc_basedir="[$]{srcdir}/$1" fi -AC_SUBST(boehm_gc_basedir) -AC_CONFIG_AUX_DIR($boehm_gc_basedir/..) +AC_SUBST(gc_basedir) +AC_CONFIG_AUX_DIR($gc_basedir/..) if :; then :; else # This overrides the previous occurrence for automake, but not for # autoconf, which is exactly what we want. @@ -53,7 +67,7 @@ AC_CANONICAL_SYSTEM mkinstalldirs="`cd $ac_aux_dir && pwd`/mkinstalldirs" AC_SUBST(mkinstalldirs) -AM_INIT_AUTOMAKE(boehm-gc, 5.1, no-define) +AM_INIT_AUTOMAKE(gc, 6.0, no-define) # FIXME: We temporarily define our own version of AC_PROG_CC. This is # copied from autoconf 2.12, but does not call AC_PROG_CC_WORKS. We @@ -162,22 +176,22 @@ fi . [$]{srcdir}/configure.host -case [$]{boehm_gc_basedir} in -/* | [A-Za-z]:[/\\]*) boehm_gc_flagbasedir=[$]{boehm_gc_basedir} ;; -*) boehm_gc_flagbasedir='[$](top_builddir)/'[$]{boehm_gc_basedir} ;; +case [$]{gc_basedir} in +/* | [A-Za-z]:[/\\]*) gc_flagbasedir=[$]{gc_basedir} ;; +*) gc_flagbasedir='[$](top_builddir)/'[$]{gc_basedir} ;; esac -boehm_gc_cflags="[$]{boehm_gc_cflags} -I"'[$](top_builddir)'"/$1/targ-include -I[$]{boehm_gc_flagbasedir}/libc/include" +gc_cflags="[$]{gc_cflags} -I"'[$](top_builddir)'"/$1/targ-include -I[$]{gc_flagbasedir}/libc/include" case "${host}" in *-*-cygwin32*) - boehm_gc_cflags="[$]{boehm_gc_cflags} -I[$]{boehm_gc_flagbasedir}/../winsup/include" + gc_cflags="[$]{gc_cflags} -I[$]{gc_flagbasedir}/../winsup/include" ;; esac -boehm_gc_cflags="[$]{boehm_gc_cflags} -fno-builtin" +dnl gc_cflags="[$]{gc_cflags} -fno-builtin" -BOEHM_GC_CFLAGS=${boehm_gc_cflags} -AC_SUBST(BOEHM_GC_CFLAGS) +GC_CFLAGS=${gc_cflags} +AC_SUBST(GC_CFLAGS) ])) )))) diff --git a/boehm-gc/add_gc_prefix.c b/boehm-gc/add_gc_prefix.c index 0d1ab6d4d36..59515c7866e 100644 --- a/boehm-gc/add_gc_prefix.c +++ b/boehm-gc/add_gc_prefix.c @@ -1,4 +1,5 @@ # include <stdio.h> +# include "version.h" int main(argc, argv, envp) int argc; @@ -8,7 +9,12 @@ char ** envp; int i; for (i = 1; i < argc; i++) { - printf("gc/%s ", argv[i]); + if (GC_ALPHA_VERSION == GC_NOT_ALPHA) { + printf("gc%d.%d/%s ", GC_VERSION_MAJOR, GC_VERSION_MINOR, argv[i]); + } else { + printf("gc%d.%dalpha%d/%s ", GC_VERSION_MAJOR, + GC_VERSION_MINOR, GC_ALPHA_VERSION, argv[i]); + } } return(0); } diff --git a/boehm-gc/allchblk.c b/boehm-gc/allchblk.c index 5b7bcff050f..76296721416 100644 --- a/boehm-gc/allchblk.c +++ b/boehm-gc/allchblk.c @@ -627,7 +627,8 @@ int n; while ((ptr_t)lasthbp <= search_end && (thishbp = GC_is_black_listed(lasthbp, - (word)eff_size_needed))) { + (word)eff_size_needed)) + != 0) { lasthbp = thishbp; } size_avail -= (ptr_t)lasthbp - (ptr_t)hbp; @@ -654,7 +655,7 @@ int n; && orig_avail - size_needed > (signed_word)BL_LIMIT) { /* Punt, since anything else risks unreasonable heap growth. */ - if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) { + if (0 == GETENV("GC_NO_BLACKLIST_WARNING")) { WARN("Needed to allocate blacklisted block at 0x%lx\n", (word)hbp); } diff --git a/boehm-gc/alloc.c b/boehm-gc/alloc.c index d8173fa3f48..1664e4a4df5 100644 --- a/boehm-gc/alloc.c +++ b/boehm-gc/alloc.c @@ -105,7 +105,7 @@ CLOCK_TYPE GC_start_time; /* Time at which we stopped world. */ int GC_n_attempts = 0; /* Number of attempts at finishing */ /* collection within TIME_LIMIT */ -#ifdef SMALL_CONFIG +#if defined(SMALL_CONFIG) || defined(NO_CLOCK) # define GC_timeout_stop_func GC_never_stop_func #else int GC_timeout_stop_func GC_PROTO((void)) @@ -250,7 +250,11 @@ void GC_maybe_gc() GC_gcollect_inner(); n_partial_gcs = 0; return; - } else if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) { + } else { +# ifdef PARALLEL_MARK + GC_wait_for_reclaim(); +# endif + if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) { # ifdef CONDPRINT if (GC_print_stats) { GC_printf2( @@ -260,23 +264,21 @@ void GC_maybe_gc() } # endif GC_promote_black_lists(); -# ifdef PARALLEL_MARK - GC_wait_for_reclaim(); -# endif (void)GC_reclaim_all((GC_stop_func)0, TRUE); GC_clear_marks(); n_partial_gcs = 0; GC_notify_full_gc(); GC_is_full_gc = TRUE; - } else { + } else { n_partial_gcs++; - } + } + } /* We try to mark with the world stopped. */ /* If we run out of time, this turns into */ /* incremental marking. */ -#ifndef NO_CLOCK - GET_TIME(GC_start_time); -#endif +# ifndef NO_CLOCK + GET_TIME(GC_start_time); +# endif if (GC_stopped_mark(GC_timeout_stop_func)) { # ifdef SAVE_CALL_CHAIN GC_save_callers(GC_last_stack); @@ -367,7 +369,7 @@ GC_stop_func stop_func; # define GC_RATE 10 # define MAX_PRIOR_ATTEMPTS 1 /* Maximum number of prior attempts at world stop marking */ - /* A value of 1 means that we finish the seconf time, no matter */ + /* A value of 1 means that we finish the second time, no matter */ /* how long it takes. Doesn't count the initial root scan */ /* for a full GC. */ @@ -386,6 +388,9 @@ int n; # ifdef SAVE_CALL_CHAIN GC_save_callers(GC_last_stack); # endif +# ifdef PARALLEL_MARK + GC_wait_for_reclaim(); +# endif if (GC_n_attempts < MAX_PRIOR_ATTEMPTS) { GET_TIME(GC_start_time); if (!GC_stopped_mark(GC_timeout_stop_func)) { @@ -506,6 +511,57 @@ GC_stop_func stop_func; return(TRUE); } +/* Set all mark bits for the free list whose first entry is q */ +#ifdef __STDC__ + void GC_set_fl_marks(ptr_t q) +#else + void GC_set_fl_marks(q) + ptr_t q; +#endif +{ + ptr_t p; + struct hblk * h, * last_h = 0; + hdr *hhdr; + int word_no; + + for (p = q; p != 0; p = obj_link(p)){ + h = HBLKPTR(p); + if (h != last_h) { + last_h = h; + hhdr = HDR(h); + } + word_no = (((word *)p) - ((word *)h)); + set_mark_bit_from_hdr(hhdr, word_no); + } +} + +/* Clear all mark bits for the free list whose first entry is q */ +/* Decrement GC_mem_found by number of words on free list. */ +#ifdef __STDC__ + void GC_clear_fl_marks(ptr_t q) +#else + void GC_clear_fl_marks(q) + ptr_t q; +#endif +{ + ptr_t p; + struct hblk * h, * last_h = 0; + hdr *hhdr; + int word_no; + + for (p = q; p != 0; p = obj_link(p)){ + h = HBLKPTR(p); + if (h != last_h) { + last_h = h; + hhdr = HDR(h); + } + word_no = (((word *)p) - ((word *)h)); + clear_mark_bit_from_hdr(hhdr, word_no); +# ifdef GATHERSTATS + GC_mem_found -= hhdr -> hb_sz; +# endif + } +} /* Finish up a collection. Assumes lock is held, signals are disabled, */ /* but the world is otherwise running. */ @@ -533,21 +589,13 @@ void GC_finish_collection() /* marked when we're done. */ { register word size; /* current object size */ - register ptr_t p; /* pointer to current object */ - register struct hblk * h; /* pointer to block containing *p */ - register hdr * hhdr; - register int word_no; /* "index" of *p in *q */ int kind; + ptr_t q; for (kind = 0; kind < GC_n_kinds; kind++) { for (size = 1; size <= MAXOBJSZ; size++) { - for (p= GC_obj_kinds[kind].ok_freelist[size]; - p != 0; p=obj_link(p)){ - h = HBLKPTR(p); - hhdr = HDR(h); - word_no = (((word *)p) - ((word *)h)); - set_mark_bit_from_hdr(hhdr, word_no); - } + q = GC_obj_kinds[kind].ok_freelist[size]; + if (q != 0) GC_set_fl_marks(q); } } } @@ -565,32 +613,20 @@ void GC_finish_collection() # endif /* Clear free list mark bits, in case they got accidentally marked */ - /* Note: HBLKPTR(p) == pointer to head of block containing *p */ - /* (or GC_find_leak is set and they were intentionally marked.) */ + /* (or GC_find_leak is set and they were intentionally marked). */ /* Also subtract memory remaining from GC_mem_found count. */ /* Note that composite objects on free list are cleared. */ /* Thus accidentally marking a free list is not a problem; only */ /* objects on the list itself will be marked, and that's fixed here. */ { register word size; /* current object size */ - register ptr_t p; /* pointer to current object */ - register struct hblk * h; /* pointer to block containing *p */ - register hdr * hhdr; - register int word_no; /* "index" of *p in *q */ + register ptr_t q; /* pointer to current object */ int kind; for (kind = 0; kind < GC_n_kinds; kind++) { for (size = 1; size <= MAXOBJSZ; size++) { - for (p= GC_obj_kinds[kind].ok_freelist[size]; - p != 0; p=obj_link(p)){ - h = HBLKPTR(p); - hhdr = HDR(h); - word_no = (((word *)p) - ((word *)h)); - clear_mark_bit_from_hdr(hhdr, word_no); -# ifdef GATHERSTATS - GC_mem_found -= size; -# endif - } + q = GC_obj_kinds[kind].ok_freelist[size]; + if (q != 0) GC_clear_fl_marks(q); } } } diff --git a/boehm-gc/configure b/boehm-gc/configure index 560ccb3c04e..271ce5c2f5f 100755 --- a/boehm-gc/configure +++ b/boehm-gc/configure @@ -37,9 +37,13 @@ ac_help="$ac_help --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer" ac_help="$ac_help - --enable-java-gc=TYPE choose garbage collector [boehm]" + --enable-threads=TYPE choose threading package" +ac_help="$ac_help + --enable-parallel-mark parallelize marking and free list construction" ac_help="$ac_help --with-ecos enable runtime eCos target support" +ac_help="$ac_help + --enable-full-debug include full support for pointer backtracing etc." # Initialize some variables set by options. # The variables have the same names as the options, with @@ -562,6 +566,26 @@ fi +ac_aux_dir= +for ac_dir in . $srcdir/.; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in . $srcdir/." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: @@ -574,7 +598,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:578: checking for a BSD compatible install" >&5 +echo "configure:602: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -627,7 +651,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 -echo "configure:631: checking whether build environment is sane" >&5 +echo "configure:655: checking whether build environment is sane" >&5 # Just in case sleep 1 echo timestamp > conftestfile @@ -684,7 +708,7 @@ test "$program_suffix" != NONE && test "$program_transform_name" = "" && program_transform_name="s,x,x," echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 -echo "configure:688: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:712: checking whether ${MAKE-make} sets \${MAKE}" >&5 set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -717,12 +741,12 @@ else fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:721: checking for Cygwin environment" >&5 +echo "configure:745: checking for Cygwin environment" >&5 if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 726 "configure" +#line 750 "configure" #include "confdefs.h" int main() { @@ -733,7 +757,7 @@ int main() { return __CYGWIN__; ; return 0; } EOF -if { (eval echo configure:737: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:761: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -750,19 +774,19 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6 CYGWIN= test "$ac_cv_cygwin" = yes && CYGWIN=yes echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6 -echo "configure:754: checking for mingw32 environment" >&5 +echo "configure:778: checking for mingw32 environment" >&5 if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 759 "configure" +#line 783 "configure" #include "confdefs.h" int main() { return __MINGW32__; ; return 0; } EOF -if { (eval echo configure:766: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:790: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -793,17 +817,17 @@ fi if test "${srcdir}" = "."; then - if test "${with_target_subdir}" != "."; then - boehm_gc_basedir="${srcdir}/${with_multisrctop}../." + if test "${with_target_subdir}" != "." -a -n "${with_target_subdir}"; then + gc_basedir="${srcdir}/${with_multisrctop}../." else - boehm_gc_basedir="${srcdir}/${with_multisrctop}." + gc_basedir="${srcdir}/${with_multisrctop}." fi else - boehm_gc_basedir="${srcdir}/." + gc_basedir="${srcdir}/." fi ac_aux_dir= -for ac_dir in $boehm_gc_basedir/.. $srcdir/$boehm_gc_basedir/..; do +for ac_dir in $gc_basedir/.. $srcdir/$gc_basedir/..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" @@ -815,7 +839,7 @@ for ac_dir in $boehm_gc_basedir/.. $srcdir/$boehm_gc_basedir/..; do fi done if test -z "$ac_aux_dir"; then - { echo "configure: error: can not find install-sh or install.sh in $boehm_gc_basedir/.. $srcdir/$boehm_gc_basedir/.." 1>&2; exit 1; } + { echo "configure: error: can not find install-sh or install.sh in $gc_basedir/.. $srcdir/$gc_basedir/.." 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub @@ -873,7 +897,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } fi echo $ac_n "checking host system type""... $ac_c" 1>&6 -echo "configure:877: checking host system type" >&5 +echo "configure:901: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -894,7 +918,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$host" 1>&6 echo $ac_n "checking target system type""... $ac_c" 1>&6 -echo "configure:898: checking target system type" >&5 +echo "configure:922: checking target system type" >&5 target_alias=$target case "$target_alias" in @@ -912,7 +936,7 @@ target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` echo "$ac_t""$target" 1>&6 echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:916: checking build system type" >&5 +echo "configure:940: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -940,9 +964,9 @@ mkinstalldirs="`cd $ac_aux_dir && pwd`/mkinstalldirs" -PACKAGE=boehm-gc +PACKAGE=gc -VERSION=5.1 +VERSION=6.0 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } @@ -952,7 +976,7 @@ fi missing_dir=`cd $ac_aux_dir && pwd` echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 -echo "configure:956: checking for working aclocal" >&5 +echo "configure:980: checking for working aclocal" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -965,7 +989,7 @@ else fi echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 -echo "configure:969: checking for working autoconf" >&5 +echo "configure:993: checking for working autoconf" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -978,7 +1002,7 @@ else fi echo $ac_n "checking for working automake""... $ac_c" 1>&6 -echo "configure:982: checking for working automake" >&5 +echo "configure:1006: checking for working automake" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -991,7 +1015,7 @@ else fi echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 -echo "configure:995: checking for working autoheader" >&5 +echo "configure:1019: checking for working autoheader" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1004,7 +1028,7 @@ else fi echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 -echo "configure:1008: checking for working makeinfo" >&5 +echo "configure:1032: checking for working makeinfo" >&5 # Run test in a subshell; some versions of sh will print an error if # an executable is not found, even if stderr is redirected. # Redirect stdin to placate older versions of autoconf. Sigh. @@ -1030,7 +1054,7 @@ fi # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1034: checking for $ac_word" >&5 +echo "configure:1058: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1060,7 +1084,7 @@ if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1064: checking for $ac_word" >&5 +echo "configure:1088: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1109,7 +1133,7 @@ fi fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1113: checking whether we are using GNU C" >&5 +echo "configure:1137: checking whether we are using GNU C" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1118,7 +1142,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1122: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1146: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no @@ -1133,7 +1157,7 @@ if test $ac_cv_prog_gcc = yes; then ac_save_CFLAGS="$CFLAGS" CFLAGS= echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 -echo "configure:1137: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1161: checking whether ${CC-cc} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1170,7 +1194,7 @@ do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1174: checking for $ac_word" >&5 +echo "configure:1198: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1203,7 +1227,7 @@ test -n "$CXX" || CXX="gcc" test -z "$CXX" && { echo "configure: error: no acceptable c++ found in \$PATH" 1>&2; exit 1; } echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6 -echo "configure:1207: checking whether we are using GNU C++" >&5 +echo "configure:1231: checking whether we are using GNU C++" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1212,7 +1236,7 @@ else yes; #endif EOF -if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1216: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then +if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1240: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then ac_cv_prog_gxx=yes else ac_cv_prog_gxx=no @@ -1227,7 +1251,7 @@ if test $ac_cv_prog_gxx = yes; then ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS= echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6 -echo "configure:1231: checking whether ${CXX-g++} accepts -g" >&5 +echo "configure:1255: checking whether ${CXX-g++} accepts -g" >&5 if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1260,7 +1284,7 @@ fi # NEWLIB_CONFIGURE, which doesn't work because that means that it will # be run before AC_CANONICAL_HOST. echo $ac_n "checking build system type""... $ac_c" 1>&6 -echo "configure:1264: checking build system type" >&5 +echo "configure:1288: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -1281,7 +1305,7 @@ echo "$ac_t""$build" 1>&6 # Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args. set dummy ${ac_tool_prefix}as; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1285: checking for $ac_word" >&5 +echo "configure:1309: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1313,7 +1337,7 @@ fi # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1317: checking for $ac_word" >&5 +echo "configure:1341: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1345,7 +1369,7 @@ fi # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1349: checking for $ac_word" >&5 +echo "configure:1373: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1377,7 +1401,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:1381: checking for $ac_word" >&5 +echo "configure:1405: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1422,7 +1446,7 @@ fi # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 -echo "configure:1426: checking for a BSD compatible install" >&5 +echo "configure:1450: checking for a BSD compatible install" >&5 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1476,7 +1500,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 -echo "configure:1480: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "configure:1504: checking whether to enable maintainer-specific portions of Makefiles" >&5 # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then enableval="$enable_maintainer_mode" @@ -1514,7 +1538,7 @@ if false; then echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:1518: checking for executable suffix" >&5 +echo "configure:1542: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1524,7 +1548,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:1528: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:1552: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; @@ -1548,21 +1572,20 @@ fi . ${srcdir}/configure.host -case ${boehm_gc_basedir} in -/* | A-Za-z:/\\*) boehm_gc_flagbasedir=${boehm_gc_basedir} ;; -*) boehm_gc_flagbasedir='$(top_builddir)/'${boehm_gc_basedir} ;; +case ${gc_basedir} in +/* | A-Za-z:/\\*) gc_flagbasedir=${gc_basedir} ;; +*) gc_flagbasedir='$(top_builddir)/'${gc_basedir} ;; esac -boehm_gc_cflags="${boehm_gc_cflags} -I"'$(top_builddir)'"/./targ-include -I${boehm_gc_flagbasedir}/libc/include" +gc_cflags="${gc_cflags} -I"'$(top_builddir)'"/./targ-include -I${gc_flagbasedir}/libc/include" case "${host}" in *-*-cygwin32*) - boehm_gc_cflags="${boehm_gc_cflags} -I${boehm_gc_flagbasedir}/../winsup/include" + gc_cflags="${gc_cflags} -I${gc_flagbasedir}/../winsup/include" ;; esac -boehm_gc_cflags="${boehm_gc_cflags} -fno-builtin" -BOEHM_GC_CFLAGS=${boehm_gc_cflags} +GC_CFLAGS=${gc_cflags} @@ -1647,7 +1670,7 @@ ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6 -echo "configure:1651: checking for ld used by GCC" >&5 +echo "configure:1674: checking for ld used by GCC" >&5 case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw @@ -1677,10 +1700,10 @@ echo "configure:1651: checking for ld used by GCC" >&5 esac elif test "$with_gnu_ld" = yes; then echo $ac_n "checking for GNU ld""... $ac_c" 1>&6 -echo "configure:1681: checking for GNU ld" >&5 +echo "configure:1704: checking for GNU ld" >&5 else echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 -echo "configure:1684: checking for non-GNU ld" >&5 +echo "configure:1707: checking for non-GNU ld" >&5 fi if eval "test \"`echo '$''{'lt_cv_path_LD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -1715,7 +1738,7 @@ else fi test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; } echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6 -echo "configure:1719: checking if the linker ($LD) is GNU ld" >&5 +echo "configure:1742: checking if the linker ($LD) is GNU ld" >&5 if eval "test \"`echo '$''{'lt_cv_prog_gnu_ld'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1732,7 +1755,7 @@ with_gnu_ld=$lt_cv_prog_gnu_ld echo $ac_n "checking for $LD option to reload object files""... $ac_c" 1>&6 -echo "configure:1736: checking for $LD option to reload object files" >&5 +echo "configure:1759: checking for $LD option to reload object files" >&5 if eval "test \"`echo '$''{'lt_cv_ld_reload_flag'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1744,7 +1767,7 @@ reload_flag=$lt_cv_ld_reload_flag test -n "$reload_flag" && reload_flag=" $reload_flag" echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 -echo "configure:1748: checking for BSD-compatible nm" >&5 +echo "configure:1771: checking for BSD-compatible nm" >&5 if eval "test \"`echo '$''{'lt_cv_path_NM'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1782,7 +1805,7 @@ NM="$lt_cv_path_NM" echo "$ac_t""$NM" 1>&6 echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:1786: checking whether ln -s works" >&5 +echo "configure:1809: checking whether ln -s works" >&5 if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1803,7 +1826,7 @@ else fi echo $ac_n "checking how to recognise dependant libraries""... $ac_c" 1>&6 -echo "configure:1807: checking how to recognise dependant libraries" >&5 +echo "configure:1830: checking how to recognise dependant libraries" >&5 if eval "test \"`echo '$''{'lt_cv_deplibs_check_method'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1967,13 +1990,13 @@ file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method echo $ac_n "checking for object suffix""... $ac_c" 1>&6 -echo "configure:1971: checking for object suffix" >&5 +echo "configure:1994: checking for object suffix" >&5 if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else rm -f conftest* echo 'int i = 1;' > conftest.$ac_ext -if { (eval echo configure:1977: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:2000: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then for ac_file in conftest.*; do case $ac_file in *.c) ;; @@ -1997,7 +2020,7 @@ case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then echo $ac_n "checking for ${ac_tool_prefix}file""... $ac_c" 1>&6 -echo "configure:2001: checking for ${ac_tool_prefix}file" >&5 +echo "configure:2024: checking for ${ac_tool_prefix}file" >&5 if eval "test \"`echo '$''{'lt_cv_path_MAGIC_CMD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2059,7 +2082,7 @@ fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then echo $ac_n "checking for file""... $ac_c" 1>&6 -echo "configure:2063: checking for file" >&5 +echo "configure:2086: checking for file" >&5 if eval "test \"`echo '$''{'lt_cv_path_MAGIC_CMD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2130,7 +2153,7 @@ esac # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2134: checking for $ac_word" >&5 +echo "configure:2157: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2162,7 +2185,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2166: checking for $ac_word" >&5 +echo "configure:2189: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2197,7 +2220,7 @@ fi # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2201: checking for $ac_word" >&5 +echo "configure:2224: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2229,7 +2252,7 @@ if test -n "$ac_tool_prefix"; then # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2233: checking for $ac_word" >&5 +echo "configure:2256: checking for $ac_word" >&5 if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2296,8 +2319,8 @@ test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic" case $host in *-*-irix6*) # Find out which ABI we are using. - echo '#line 2300 "configure"' > conftest.$ac_ext - if { (eval echo configure:2301: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + echo '#line 2323 "configure"' > conftest.$ac_ext + if { (eval echo configure:2324: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" @@ -2318,7 +2341,7 @@ case $host in SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6 -echo "configure:2322: checking whether the C compiler needs -belf" >&5 +echo "configure:2345: checking whether the C compiler needs -belf" >&5 if eval "test \"`echo '$''{'lt_cv_cc_needs_belf'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2331,14 +2354,14 @@ ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$a cross_compiling=$ac_cv_prog_cc_cross cat > conftest.$ac_ext <<EOF -#line 2335 "configure" +#line 2358 "configure" #include "confdefs.h" int main() { ; return 0; } EOF -if { (eval echo configure:2342: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* lt_cv_cc_needs_belf=yes else @@ -2368,7 +2391,7 @@ echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6 esac echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6 -echo "configure:2372: checking how to run the C++ preprocessor" >&5 +echo "configure:2395: checking how to run the C++ preprocessor" >&5 if test -z "$CXXCPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2381,12 +2404,12 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes cross_compiling=$ac_cv_prog_cxx_cross CXXCPP="${CXX-g++} -E" cat > conftest.$ac_ext <<EOF -#line 2385 "configure" +#line 2408 "configure" #include "confdefs.h" #include <stdlib.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:2390: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:2413: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -2533,7 +2556,7 @@ fi echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 -echo "configure:2537: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "configure:2560: checking whether to enable maintainer-specific portions of Makefiles" >&5 # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then enableval="$enable_maintainer_mode" @@ -2566,7 +2589,7 @@ if false; then echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:2570: checking for executable suffix" >&5 +echo "configure:2593: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2576,7 +2599,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:2580: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:2603: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; @@ -2598,10 +2621,34 @@ ac_exeext=$EXEEXT fi -echo $ac_n "checking for thread model used by GCC""... $ac_c" 1>&6 -echo "configure:2603: checking for thread model used by GCC" >&5 -THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` -echo "$ac_t""$THREADS" 1>&6 +echo $ac_n "checking for threads package to use""... $ac_c" 1>&6 +echo "configure:2626: checking for threads package to use" >&5 +# Check whether --enable-threads or --disable-threads was given. +if test "${enable_threads+set}" = set; then + enableval="$enable_threads" + THREADS=$enableval +else + echo $ac_n "checking for thread model used by GCC""... $ac_c" 1>&6 +echo "configure:2633: checking for thread model used by GCC" >&5 + THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` + if test -z "$THREADS"; then + THREADS=no + fi + echo "$ac_t""$THREADS" 1>&6 +fi + + +# Check whether --enable-parallel-mark or --disable-parallel-mark was given. +if test "${enable_parallel_mark+set}" = set; then + enableval="$enable_parallel_mark" + case "$THREADS" in + no | none | single) + { echo "configure: error: Parallel mark requires --enable-threads=x spec" 1>&2; exit 1; } + ;; + esac + +fi + INCLUDES=-I${srcdir}/include THREADLIBS= @@ -2613,9 +2660,29 @@ case "$THREADS" in THREADS=posix THREADLIBS=-lpthread case "$host" in + x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux*) + cat >> confdefs.h <<\EOF +#define GC_LINUX_THREADS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _REENTRANT 1 +EOF + + if test "${enable_parallel_mark}"; then + cat >> confdefs.h <<\EOF +#define PARALLEL_MARK 1 +EOF + + fi + cat >> confdefs.h <<\EOF +#define THREAD_LOCAL_ALLOC 1 +EOF + + ;; *-*-linux*) cat >> confdefs.h <<\EOF -#define LINUX_THREADS 1 +#define GC_LINUX_THREADS 1 EOF cat >> confdefs.h <<\EOF @@ -2623,6 +2690,28 @@ EOF EOF ;; + *-*-hpux*) + echo "configure: warning: "Only HP/UX 11 threads are supported."" 1>&2 + cat >> confdefs.h <<\EOF +#define GC_HPUX_THREADS 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_C_SOURCE 199506L +EOF + + if test "${enable_parallel_mark}" = yes; then + cat >> confdefs.h <<\EOF +#define PARALLEL_MARK 1 +EOF + + fi + cat >> confdefs.h <<\EOF +#define THREAD_LOCAL_ALLOC 1 +EOF + + THREADLIBS="-lpthread -lrt" + ;; *-*-freebsd*) echo "configure: warning: "FreeBSD does not yet fully support threads with Boehm GC."" 1>&2 cat >> confdefs.h <<\EOF @@ -2634,17 +2723,17 @@ EOF ;; *-*-solaris*) cat >> confdefs.h <<\EOF -#define SOLARIS_THREADS 1 +#define GC_SOLARIS_THREADS 1 EOF cat >> confdefs.h <<\EOF -#define _SOLARIS_PTHREADS 1 +#define GC_SOLARIS_PTHREADS 1 EOF ;; *-*-irix*) cat >> confdefs.h <<\EOF -#define IRIX_THREADS 1 +#define GC_IRIX_THREADS 1 EOF ;; @@ -2663,7 +2752,7 @@ esac echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "configure:2667: checking for dlopen in -ldl" >&5 +echo "configure:2756: checking for dlopen in -ldl" >&5 ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 @@ -2671,7 +2760,7 @@ else ac_save_LIBS="$LIBS" LIBS="-ldl $LIBS" cat > conftest.$ac_ext <<EOF -#line 2675 "configure" +#line 2764 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -2682,7 +2771,7 @@ int main() { dlopen() ; return 0; } EOF -if { (eval echo configure:2686: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:2775: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -2704,19 +2793,7 @@ fi -# Check whether --enable-java-gc or --disable-java-gc was given. -if test "${enable_java_gc+set}" = set; then - enableval="$enable_java_gc" - - GC=$enableval -else - GC=boehm -fi - -target_all= -if test "$GC" = "boehm"; then - target_all=libgcjgc.la -fi +target_all=libgcjgc.la TARGET_ECOS="no" @@ -2816,6 +2893,15 @@ cat >> confdefs.h <<\EOF EOF cat >> confdefs.h <<\EOF +#define NO_EXECUTE_PERMISSION 1 +EOF + +cat >> confdefs.h <<\EOF +#define ALL_INTERIOR_POINTERS 1 +EOF + + +cat >> confdefs.h <<\EOF #define JAVA_FINALIZATION 1 EOF @@ -2823,6 +2909,10 @@ cat >> confdefs.h <<\EOF #define GC_GCJ_SUPPORT 1 EOF +cat >> confdefs.h <<\EOF +#define ATOMIC_UNCOLLECTABLE 1 +EOF + if test -n "${with_cross_host}"; then cat >> confdefs.h <<\EOF @@ -2843,6 +2933,32 @@ EOF fi +# Check whether --enable-full-debug or --disable-full-debug was given. +if test "${enable_full_debug+set}" = set; then + enableval="$enable_full_debug" + if test "$enable_full_debug" = "yes"; then + echo "configure: warning: "Must define GC_DEBUG and use debug alloc. in clients."" 1>&2 + cat >> confdefs.h <<\EOF +#define KEEP_BACK_PTRS 1 +EOF + + cat >> confdefs.h <<\EOF +#define DBG_HDRS_ALL 1 +EOF + + case $host in + x86-*-linux* | i586-*-linux* | i686-*-linux* ) + echo "configure: warning: "Client must not use -fomit-frame-pointer."" 1>&2 + cat >> confdefs.h <<\EOF +#define SAVE_CALL_COUNT 8 +EOF + + ;; + esac + fi +fi + + if test -z "$with_cross_host"; then @@ -3004,7 +3120,7 @@ s%@includedir@%$includedir%g s%@oldincludedir@%$oldincludedir%g s%@infodir@%$infodir%g s%@mandir@%$mandir%g -s%@boehm_gc_basedir@%$boehm_gc_basedir%g +s%@gc_basedir@%$gc_basedir%g s%@host@%$host%g s%@host_alias@%$host_alias%g s%@host_cpu@%$host_cpu%g @@ -3041,7 +3157,7 @@ s%@MAINTAINER_MODE_TRUE@%$MAINTAINER_MODE_TRUE%g s%@MAINTAINER_MODE_FALSE@%$MAINTAINER_MODE_FALSE%g s%@MAINT@%$MAINT%g s%@EXEEXT@%$EXEEXT%g -s%@BOEHM_GC_CFLAGS@%$BOEHM_GC_CFLAGS%g +s%@GC_CFLAGS@%$GC_CFLAGS%g s%@LN_S@%$LN_S%g s%@OBJEXT@%$OBJEXT%g s%@STRIP@%$STRIP%g @@ -3164,7 +3280,7 @@ target=${target} with_multisubdir=${with_multisubdir} ac_configure_args="${multilib_arg} ${ac_configure_args}" CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} -boehm_gc_basedir=${boehm_gc_basedir} +gc_basedir=${gc_basedir} CC="${CC}" DEFS="$DEFS" @@ -3174,7 +3290,7 @@ cat >> $CONFIG_STATUS <<\EOF echo "$DEFS" > boehm-cflags if test -n "$CONFIG_FILES"; then - ac_file=Makefile . ${boehm_gc_basedir}/../config-ml.in + ac_file=Makefile . ${gc_basedir}/../config-ml.in fi exit 0 EOF diff --git a/boehm-gc/configure.host b/boehm-gc/configure.host index 323668dd33a..da2b5b31a0e 100644 --- a/boehm-gc/configure.host +++ b/boehm-gc/configure.host @@ -1,6 +1,7 @@ # configure.host -# This shell script handles all host based configuration for boehm_gc. +# This shell script handles all host based configuration for the garbage +# collector. # It sets various shell variables based on the the host and the # configuration options. You can modify this shell script without # needing to rerun autoconf. @@ -15,16 +16,25 @@ # target_optspace --enable-target-optspace ("yes", "no", "") # It sets the following shell variables: -# boehm_gc_cflags Special CFLAGS to use when building +# gc_cflags Special CFLAGS to use when building -boehm_gc_cflags=-fexceptions +# We should set -fexceptions if we are using gcc and might be used +# inside something like gcj. This is the zeroth approximation: +case "$host" in + *-*-linux* ) + gc_cflags=-fexceptions + ;; + *-*-hpux* ) + gc_cflags=+ESdbgasm + ;; +esac case "${target_optspace}:${host}" in yes:*) - boehm_gc_cflags="${boehm_gc_cflags} -Os" + gc_cflags="${gc_cflags} -Os" ;; :m32r-* | :d10v-* | :d30v-*) - boehm_gc_cflags="${boehm_gc_cflags} -Os" + gc_cflags="${gc_cflags} -Os" ;; no:* | :*) # Nothing. diff --git a/boehm-gc/configure.in b/boehm-gc/configure.in index ec835e11c36..5a0092ecadc 100644 --- a/boehm-gc/configure.in +++ b/boehm-gc/configure.in @@ -1,8 +1,24 @@ +# Copyright (c) 1999-2001 by Red Hat, Inc. 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. +# +# Original author: Tom Tromey + dnl Process this file with autoconf to produce configure. AC_INIT(gcj_mlc.c) -BOEHM_CONFIGURE(.) +dnl Can't be done in GC_CONFIGURE because that confuses automake. +AC_CONFIG_AUX_DIR(.) + +GC_CONFIGURE(.) AM_PROG_LIBTOOL @@ -25,9 +41,24 @@ if false; then AC_EXEEXT fi -AC_MSG_CHECKING([for thread model used by GCC]) -THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` -AC_MSG_RESULT([$THREADS]) +AC_MSG_CHECKING([for threads package to use]) +AC_ARG_ENABLE(threads, [ --enable-threads=TYPE choose threading package], + THREADS=$enableval, + [ AC_MSG_CHECKING([for thread model used by GCC]) + THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'` + if test -z "$THREADS"; then + THREADS=no + fi + AC_MSG_RESULT([$THREADS])]) + +AC_ARG_ENABLE(parallel-mark, +[ --enable-parallel-mark parallelize marking and free list construction], + [case "$THREADS" in + no | none | single) + AC_MSG_ERROR([Parallel mark requires --enable-threads=x spec]) + ;; + esac] +) INCLUDES=-I${srcdir}/include THREADLIBS= @@ -39,10 +70,28 @@ case "$THREADS" in THREADS=posix THREADLIBS=-lpthread case "$host" in + x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux*) + AC_DEFINE(GC_LINUX_THREADS) + AC_DEFINE(_REENTRANT) + if test "${enable_parallel_mark}"; then + AC_DEFINE(PARALLEL_MARK) + fi + AC_DEFINE(THREAD_LOCAL_ALLOC) + ;; *-*-linux*) - AC_DEFINE(LINUX_THREADS) + AC_DEFINE(GC_LINUX_THREADS) AC_DEFINE(_REENTRANT) ;; + *-*-hpux*) + AC_MSG_WARN("Only HP/UX 11 threads are supported.") + AC_DEFINE(GC_HPUX_THREADS) + AC_DEFINE(_POSIX_C_SOURCE,199506L) + if test "${enable_parallel_mark}" = yes; then + AC_DEFINE(PARALLEL_MARK) + fi + AC_DEFINE(THREAD_LOCAL_ALLOC) + THREADLIBS="-lpthread -lrt" + ;; *-*-freebsd*) AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.") AC_DEFINE(FREEBSD_THREADS) @@ -50,11 +99,11 @@ case "$THREADS" in THREADLIBS=-pthread ;; *-*-solaris*) - AC_DEFINE(SOLARIS_THREADS) - AC_DEFINE(_SOLARIS_PTHREADS) + AC_DEFINE(GC_SOLARIS_THREADS) + AC_DEFINE(GC_SOLARIS_PTHREADS) ;; *-*-irix*) - AC_DEFINE(IRIX_THREADS) + AC_DEFINE(GC_IRIX_THREADS) ;; *-*-cygwin*) THREADLIBS= @@ -73,16 +122,7 @@ AC_SUBST(THREADLIBS) AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl") AC_SUBST(EXTRA_TEST_LIBS) -AC_ARG_ENABLE(java-gc, -changequote(<<,>>)dnl -<< --enable-java-gc=TYPE choose garbage collector [boehm]>>, -changequote([,]) - GC=$enableval, - GC=boehm) -target_all= -if test "$GC" = "boehm"; then - target_all=libgcjgc.la -fi +target_all=libgcjgc.la AC_SUBST(target_all) dnl If the target is an eCos system, use the appropriate eCos @@ -162,12 +202,17 @@ dnl We need to override the top-level CFLAGS. This is how we do it. MY_CFLAGS="$CFLAGS" AC_SUBST(MY_CFLAGS) -dnl Define a few things to retarget the library towards -dnl embedded Java. +dnl Include defines that have become de facto standard. +dnl ALL_INTERIOR_POINTERS can be overridden in startup code. AC_DEFINE(SILENT) AC_DEFINE(NO_SIGNALS) +AC_DEFINE(NO_EXECUTE_PERMISSION) +AC_DEFINE(ALL_INTERIOR_POINTERS) + +dnl By default, make the library as general as possible. AC_DEFINE(JAVA_FINALIZATION) AC_DEFINE(GC_GCJ_SUPPORT) +AC_DEFINE(ATOMIC_UNCOLLECTABLE) dnl This is something of a hack. When cross-compiling we turn off dnl some functionality. We also enable the "small" configuration. @@ -179,6 +224,20 @@ if test -n "${with_cross_host}"; then AC_DEFINE(NO_DEBUGGING) fi +AC_ARG_ENABLE(full-debug, +[ --enable-full-debug include full support for pointer backtracing etc.], +[ if test "$enable_full_debug" = "yes"; then + AC_MSG_WARN("Must define GC_DEBUG and use debug alloc. in clients.") + AC_DEFINE(KEEP_BACK_PTRS) + AC_DEFINE(DBG_HDRS_ALL) + case $host in + x86-*-linux* | i586-*-linux* | i686-*-linux* ) + AC_MSG_WARN("Client must not use -fomit-frame-pointer.") + AC_DEFINE(SAVE_CALL_COUNT, 8) + ;; + esac ] + fi) + AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host") if test "${multilib}" = "yes"; then @@ -187,15 +246,12 @@ else multilib_arg= fi -AC_OUTPUT(Makefile, -[ -dnl Put all the -D options in a file. These are required before -dnl boehm-config.h can be included. This is a huge hack brought -dnl about by overall poor structuring of this entire library. +AC_OUTPUT(Makefile, [ +dnl Put all the -D options in a file. echo "$DEFS" > boehm-cflags if test -n "$CONFIG_FILES"; then - ac_file=Makefile . ${boehm_gc_basedir}/../config-ml.in + ac_file=Makefile . ${gc_basedir}/../config-ml.in fi], srcdir=${srcdir} host=${host} @@ -203,7 +259,7 @@ target=${target} with_multisubdir=${with_multisubdir} ac_configure_args="${multilib_arg} ${ac_configure_args}" CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} -boehm_gc_basedir=${boehm_gc_basedir} +gc_basedir=${gc_basedir} CC="${CC}" DEFS="$DEFS" ) diff --git a/boehm-gc/dbg_mlc.c b/boehm-gc/dbg_mlc.c index abda26aa858..a56a93c63d7 100644 --- a/boehm-gc/dbg_mlc.c +++ b/boehm-gc/dbg_mlc.c @@ -26,7 +26,7 @@ GC_API void GC_register_finalizer_no_order /* 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. */ -/* This excludes the check as to whether tha back pointer is */ +/* This excludes the check as to whether the back pointer is */ /* odd, which is added by the GC_HAS_DEBUG_INFO macro. */ /* Note that if DBG_HDRS_ALL is set, uncollectable objects */ /* on free lists may not have debug information set. Thus it's */ @@ -233,7 +233,7 @@ ptr_t p; ptr_t GC_store_debug_info(p, sz, string, integer) register ptr_t p; /* base pointer */ word sz; /* bytes */ -char * string; +GC_CONST char * string; word integer; { register word * result = (word *)((oh *)p + 1); @@ -252,7 +252,7 @@ word integer; ((oh *)p) -> oh_sz = sz; ((oh *)p) -> oh_sf = START_FLAG ^ (word)result; ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] = - result[ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result; + result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result; # endif UNLOCK(); return((ptr_t)result); @@ -273,7 +273,7 @@ word integer; /* But that's expensive. And this way things should only appear */ /* inconsistent while we're in the handler. */ # ifdef KEEP_BACK_PTRS - ((oh *)p) -> oh_back_ptr = 0; + ((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED); # endif ((oh *)p) -> oh_string = string; ((oh *)p) -> oh_int = integer; @@ -281,7 +281,7 @@ word integer; ((oh *)p) -> oh_sz = sz; ((oh *)p) -> oh_sf = START_FLAG ^ (word)result; ((word *)p)[BYTES_TO_WORDS(GC_size(p))-1] = - result[ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result; + result[SIMPLE_ROUNDED_UP_WORDS(sz)] = END_FLAG ^ (word)result; # endif return((ptr_t)result); } @@ -305,9 +305,9 @@ register oh * ohdr; if (((word *)ohdr)[BYTES_TO_WORDS(gc_sz)-1] != (END_FLAG ^ (word)body)) { return((ptr_t)((word *)ohdr + BYTES_TO_WORDS(gc_sz)-1)); } - if (((word *)body)[ROUNDED_UP_WORDS(ohdr -> oh_sz)] + if (((word *)body)[SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz)] != (END_FLAG ^ (word)body)) { - return((ptr_t)((word *)body + ROUNDED_UP_WORDS(ohdr -> oh_sz))); + return((ptr_t)((word *)body + SIMPLE_ROUNDED_UP_WORDS(ohdr -> oh_sz))); } return(0); } @@ -964,15 +964,21 @@ struct closure { GC_make_closure(fn,cd), ofn, ocd); } +#ifdef GC_ADD_CALLER +# define RA GC_RETURN_ADDR, +#else +# define RA +#endif + GC_PTR GC_debug_malloc_replacement(lb) size_t lb; { - return GC_debug_malloc(lb, "unknown", 0); + return GC_debug_malloc(lb, RA "unknown", 0); } GC_PTR GC_debug_realloc_replacement(p, lb) GC_PTR p; size_t lb; { - return GC_debug_realloc(p, lb, "unknown", 0); + return GC_debug_realloc(p, lb, RA "unknown", 0); } diff --git a/boehm-gc/doc/README b/boehm-gc/doc/README index cbd432388f6..c6b48c3bb41 100644 --- a/boehm-gc/doc/README +++ b/boehm-gc/doc/README @@ -9,6 +9,9 @@ Copyright (c) 1998 by Fergus Henderson. All rights reserved. The files Makefile.am, and configure.in are Copyright (c) 2001 by Red Hat Inc. All rights reserved. +The files config.guess and a few others are copyrighted by the Free +Software Foundation. + THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -18,7 +21,13 @@ 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 version 6.0alpha7 of a conservative garbage collector for C and C++. +A few of the files needed to use the GNU-style build procedure come with +slightly different licenses, though they are all similar in spirit. A few +are GPL'ed, but with an exception that should cover all uses in the +collector. (If you are concerned about such things, I recommend you look +at the notice in config.guess or ltmain.sh.) + +This is version 6.0 of a conservative garbage collector for C and C++. You might find a more recent version of this at diff --git a/boehm-gc/doc/README.MacOSX b/boehm-gc/doc/README.MacOSX index 82343dd9efa..2abf0b400f7 100644 --- a/boehm-gc/doc/README.MacOSX +++ b/boehm-gc/doc/README.MacOSX @@ -17,3 +17,11 @@ June, 1 2000 Dietmar Planitzer dave.pl@ping.at + +Note from Andrew Begel: + +One more fix to enable gc.a to link successfully into a shared library for +MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX +disallows common symbols in anything that eventually finds its way into a +shared library. (I don't completely understand why, but -fno-common seems to +work and doesn't mess up the garbage collector's functionality). diff --git a/boehm-gc/doc/README.changes b/boehm-gc/doc/README.changes index b0676888c1d..c018c8b64d0 100644 --- a/boehm-gc/doc/README.changes +++ b/boehm-gc/doc/README.changes @@ -1291,7 +1291,103 @@ Since 6.0alpha6: There seemed to be some problems with the encoding of root and finalizer references. +Since 6.0alpha7: + - Changed GC_debug_malloc_replacement and GC_debug_realloc_replacement + so that they compile under Irix. (Thanks to Dave Love.) + - Updated powerpc_macosx_mach_dep.s so that it works if the collector + is in a dynamic library. (Thanks to Andrew Begel.) + - Transformed README.debugging into debugging.html, updating and + expanding it in the process. Added gcdescr.html and tree.html + from the web site to the GC distribution. + - Fixed several problems related to PRINT_BLACK_LIST. This involved + restructuring some of the marker macros. + - Fixed some problems with the sizing of objects with debug information. + Finalization was broken KEEP_BACK_PTRS or PRINT_BLACK_LIST. Reduced the + object size with SHORT_DEBUG_HDRS by another word. + - The "Needed to allocate blacklisted ..." warning had inadvertently + been turned off by default, due to a buggy test in allchblk.c. Turned + it back on. + - Removed the marker macros to deal with 2 pointers in interleaved fashion. + They were messy and the performance improvement seemed minimal. We'll + leave such scheduling issues to the compiler. + - Changed Linux/PowerPC test to also check for __powerpc__ in response + to a discussion on the gcc mailing list. + - On Matthew Flatt's suggestion removed the "static" from the jmp_buf + declaration in GC_generic_push_regs. This was causing problems in + systems that register all of their own roots. It looks far more correct + to me without the "static" anyway. + - Fixed several problems with thread local allocation of pointerfree or + typed objects. The collector was reclaiming thread-local free lists, since + it wasn't following the link fields. + - There was apparently a long-standing race condition related to multithreaded + incremental collection. A collection could be started and a thread stopped + between the memory unprotect system call and the setting of the + corresponding dirt bit. I believe this did not affect Solaris or PCR, which + use a different dirty-bit implementation. Fixed this by installing + signal handlers with sigaction instead of signal, and disabling the thread + suspend signal while in the write-protect handler. (It is unclear + whether this scenario ever actually occurred. I found it while tracking + down the following:) + - Incremental collection did not cooperate correctly with the PARALLEL_MARK + implementation of GC_malloc_many or the local_malloc primitves. It still + doesn't work well, but it shouldn't lose memory anymore. + - Integrated some changes from the gcc source tree that I had previously + missed. (Thanks to Bryce McKinley for the reminder/diff.) + - Added Makefile.direct as a copy of the default Makefile, which would + normally be overwritten if configure is run. + - Changed the gc.tar target in Makefile.direct to embed the version number + in the gc directory name. This will affect future tar file distributions. + - Changed the Irix dynamic library finding code to no longer try to + eliminate writable text segments under Irix6.x, since that is probably no + longer necessary, and can apparently be unsafe on occasion. (Thanks to + Shiro Kawai for pointing this out.) + - GC_cleanup with GC_DEBUG enabled passed a real object base address to + GC_debug_register_finalizer_ignore_self, which expected a pointer past the + debug header. Call GC_register_finalizer_ignore_self instead, even with + debugging enabled. (Thanks to Jean-Daniel Fekete for catching this.) + - The collector didn't build with call chain saving enabled but NARGS=0. + (Thanks to Maarten Thibaut.) + - Fixed up the GNU-style build files enough so that they work in some + obvious cases. + - Added initial port to Digital Mars compiler for win32. (Thanks to Walter + Bright.) + +Since 6.0alpha8: + - added README.macros. + - Made gc.mak a symbolic link to work around winzip's tendency to ignore + hard links. + - Simplified the setting of NEED_FIND_LIMIT in os_dep.c, possibly breaking + it on untested platforms. + - Integrated initial GNU HURD port. (Thanks to Chris Lingard and Igor + Khavkine.) + - A few more fixes for Digital Mars compiler. + - Fixed gcc version recognition. Renamed OPERATOR_NEW_ARRAY to + GC_OPERATOR_NEW_ARRAY. Changed GC_OPERATOR_NEW_ARRAY to be the default. + It can be overridden with -DGC_NO_OPERATOR_NEW_ARRAY. (Thanks to + Cesar Eduardo Barros.) + - Changed the byte size to free-list mapping in thread local allocation + so that size 0 allocations are handled correctly. + - Fixed Linux/MIPS stackbottom for new toolchain. (Thanks to Ryan Murray.) + - Changed finalization registration to invoke GC_oom_fn when it runs out + of memory. + - Removed lvalue cast in finalize.c. This caused some debug configurations + not to build with some non-gcc compilers. + +Since 6.0alpha9: + - Two more bug fixes for KEEP_BACK_PTRS and DBG_HDRS_ALL. + - Fixed a stack clearing problem that resulted in SIGILL with a + misaligned stack pointer for multithreaded SPARC builds. + - Integrated another HURD patch (thanks to Igor Khavkine). + + To do: + - There seem to be outstanding issues on Solaris/X86, possibly with + finding the data segment starting address. Information/patches would + ne appreciated. + - New_gc_alloc.h is apparently no longer compatible with the latest C++ + standard library in gcc3.0. (This isn't technically a bug, since it only + claimed compatibility with the SGI STL. But we may need a new C++ STL + allocator interface.) - Very large root set sizes (> 16 MB or so) could cause the collector to abort with an unexpected mark stack overflow. (Thanks again to Peter Chubb.) NOT YET FIXED. Workaround is to increase the initial diff --git a/boehm-gc/doc/README.cords b/boehm-gc/doc/README.cords index 16ce00889f6..3485e0145af 100644 --- a/boehm-gc/doc/README.cords +++ b/boehm-gc/doc/README.cords @@ -18,6 +18,20 @@ See cord.h for a description of the functions provided. Ec.h describes to a cord. These allow for efficient construction of cords without requiring a bound on the size of a cord. +More details on the data structure can be found in + +Boehm, Atkinson, and Plass, "Ropes: An Alternative to Strings", +Software Practice and Experience 25, 12, December 1995, pp. 1315-1330. + +A fundamentally similar "rope" data structure is also part of SGI's standard +template library implementation, and its descendents, which include the +GNU C++ library. That uses reference counting by default. +There is a short description of that data structure at +http://reality.sgi.com/boehm/ropeimpl.html . (The more official location +http://www.sgi.com/tech/stl/ropeimpl.html is missing a figure.) + +All of these are descendents of the "ropes" in Xerox Cedar. + de.c is a very dumb text editor that illustrates the use of cords. It maintains a list of file versions. Each version is simply a cord representing the file contents. Nonetheless, standard diff --git a/boehm-gc/doc/README.debugging b/boehm-gc/doc/README.debugging deleted file mode 100644 index f4dd65676aa..00000000000 --- a/boehm-gc/doc/README.debugging +++ /dev/null @@ -1,68 +0,0 @@ -Debugging suggestions: - -****If you get a segmentation fault or bus error while debugging with a debugger: -If the fault occurred in GC_find_limit, or with incremental collection enabled, this is probably normal. The collector installs handlers to take care of these. You will not see these unless you are using a debugger. Your debugger should allow you to continue. It's preferable to tell the debugger to ignore SIGBUS and SIGSEGV ("handle" in gdb, "ignore" in most versions of dbx) and set a breakpoint in abort. The collector will call abort if the signal had another cause, and there was not other handler previously installed. I recommend debugging without incremental collection if possible. (This applies directly to UNIX systems. Debugging with incremental collection under win32 is worse. See README.win32.) - -****If you get warning messages informing you that the collector needed to allocate blacklisted blocks: - -0) Ignore these warnings while you are using GC_DEBUG. Some of the routines mentioned below don't have debugging equivalents. (Alternatively, write the missing routines and send them to me.) - -1) Replace allocator calls that request large blocks with calls to GC_malloc_ignore_off_page or GC_malloc_atomic_ignore_off_page. You may want to set a breakpoint in GC_default_warn_proc to help you identify such calls. Make sure that a pointer to somewhere near the beginning of the resulting block is maintained in a (preferably volatile) variable as long as the block is needed. - -2) If the large blocks are allocated with realloc, I suggest instead allocating them with something like the following. Note that the realloc size increment should be fairly large (e.g. a factor of 3/2) for this to exhibit reasonable performance. But we all know we should do that anyway. - -void * big_realloc(void *p, size_t new_size) -{ - size_t old_size = GC_size(p); - void * result; - - if (new_size <= 10000) return(GC_realloc(p, new_size)); - if (new_size <= old_size) return(p); - result = GC_malloc_ignore_off_page(new_size); - if (result == 0) return(0); - memcpy(result,p,old_size); - GC_free(p); - return(result); -} - -3) In the unlikely case that even relatively small object (<20KB) allocations are triggering these warnings, then your address space contains lots of "bogus pointers", i.e. values that appear to be pointers but aren't. Usually this can be solved by using GC_malloc_atomic or the routines in gc_typed.h to allocate large pointerfree regions of bitmaps, etc. Sometimes the problem can be solved with trivial changes of encoding in certain values. It is possible, though not pleasant, to identify the source of the bogus pointers by setting a breakpoint in GC_add_to_black_list_stack, and looking at the value of current_p in the GC_mark_from_mark_stack frame. Current_p contains the address of the bogus pointer. - -4) If you get only a fixed number of these warnings, you are probably only introducing a bounded leak by ignoring them. If the data structures being allocated are intended to be permanent, then it is also safe to ignore them. The warnings can be turned off by calling GC_set_warn_proc with a procedure that ignores these warnings (e.g. by doing absolutely nothing). - - -****If the collector dies in GC_malloc while trying to remove a free list element: - -1) With > 99% probability, you wrote past the end of an allocated object. Try setting GC_DEBUG and using the debugging facilities in gc.h. - - -****If the heap grows too much: - -1) Consider using GC_malloc_atomic for objects containing nonpointers. This is especially important for large arrays containg compressed data, pseudo-random numbers, and the like. (This isn't all that likely to solve your problem, but it's a useful and easy optimization anyway, and this is a good time to try it.) If you allocate large objects containg only one or two pointers at the beginning, either try the typed allocation primitives is gc.h, or separate out the pointerfree component. -2) If you are using the collector in its default mode, with interior pointer recognition enabled, consider using GC_malloc_ignore_off_page to allocate large objects. (See gc.h and above for details. Large means > 100K in most environments.) -3) GC_print_block_list() will print a list of all currently allocated heap blocks and what size objects they contain. GC_print_hblkfreelist() will print a list of free heap blocks, and whether they are blacklisted. GC_dump calls both of these, and also prints information about heap sections, and root segments. -4) Build the collector with -DKEEP_BACK_PTRS, and use the backptr.h -interface to determine why objects are being retained. - - -****If the collector appears to be losing objects: - -1) Replace all calls to GC_malloc_atomic and typed allocation by GC_malloc calls. If this fixes the problem, gradually reinsert your optimizations. -2) You may also want to try the safe(r) pointer manipulation primitives in gc.h. But those are hard to use until the preprocessor becomes available. -3) Try using the GC_DEBUG facilities. This is less likely to be successful here than if the collector crashes. -[The rest of these are primarily for wizards. You shouldn't need them unless you're doing something really strange, or debugging a collector port.] -4) Don't turn on incremental collection. If that fixes the problem, suspect a bug in the dirty bit implementation. Try compiling with -DCHECKSUMS to check for modified, but supposedly clean, pages. -5) On a SPARC, in a single-threaded environment, GC_print_callers(GC_arrays._last_stack) prints a cryptic stack trace as of the time of the last collection. (You will need a debugger to decipher the result.) The question to ask then is "why should this object have been accessible at the time of the last collection? Where was a pointer to it stored?". This facility should be easy to add for some other collector ports (namely if it's easy to traverse stack frames), but will be hard for others. -6) "print *GC_find_header(p)" in dbx or gdb will print the garbage collector block header information associated with the object p (e.g. object size, etc.) -7) GC_is_marked(p) determines whether p is the base address of a marked object. Note that objects allocated since the last collection should not be marked, and that unmarked objects are reclaimed incrementally. It's usually most interesting to set a breakpoint in GC_finish_collection and then to determine how much of the damaged data structure is marked at that point. -8) Look at the tracing facility in mark.c. (Ignore this suggestion unless you are very familiar with collector internals.) -9) [From Melissa O'Neill:] -If you're using multiple threads, double check that all thread -creation goes through the GC_ wrapper functions rather than -calling the thread-creation functions themselves (e.g., -GC_pthread_create rather than pthread_create). The gc.h header -file includes suitable preprocessor definitions to accomplish -this mapping transparently -- the question is: are you including -it in all the modules that create threads? - - - diff --git a/boehm-gc/doc/README.environment b/boehm-gc/doc/README.environment index 4681acf63bb..5760342a86a 100644 --- a/boehm-gc/doc/README.environment +++ b/boehm-gc/doc/README.environment @@ -29,6 +29,9 @@ GC_NPROCS=<n> - Linux w/threads only. Explicitly sets the number of processors when multiple processors are available will preserve correctness, but may lead to really horrible performance. +GC_NO_BLACKLIST_WARNING - Prevents the collector from issuing + "Needed to allocate blacklisted block at ..." warnings. + The following turn on runtime flags that are also program settable. Checked only during initialization. We expect that they will usually be set through other means, but this may help with debugging and testing: diff --git a/boehm-gc/dyn_load.c b/boehm-gc/dyn_load.c index 4f4ef51348d..508fd24179a 100644 --- a/boehm-gc/dyn_load.c +++ b/boehm-gc/dyn_load.c @@ -53,7 +53,7 @@ !(defined(ALPHA) && defined(OSF1)) && \ !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \ !defined(RS6000) && !defined(SCO_ELF) && \ - !(defined(NETBSD) && defined(__ELF__)) + !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) --> We only know how to find data segments of dynamic libraries for the --> above. Additional SVR4 variants might not be too --> hard to add. @@ -243,7 +243,7 @@ void GC_register_dynamic_libraries() # endif /* SUNOS */ #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \ - (defined(NETBSD) && defined(__ELF__)) + (defined(NETBSD) && defined(__ELF__)) || defined(HURD) #ifdef USE_PROC_FOR_LIBRARIES @@ -514,6 +514,10 @@ void GC_register_dynamic_libraries() #include <fcntl.h> #include <elf.h> #include <errno.h> +#include <signal.h> /* Only for the following test. */ +#ifndef _sigargs +# define IRIX6 +#endif extern void * GC_roots_present(); /* The type is a lie, since the real type doesn't make sense here, */ @@ -574,7 +578,8 @@ void GC_register_dynamic_libraries() if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant; if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE)) goto irrelevant; - /* The latter test is empirically useless. Other than the */ + /* The latter test is empirically useless in very old Irix */ + /* versions. Other than the */ /* main data and stack segments, everything appears to be */ /* mapped readable, writable, executable, and shared(!!). */ /* This makes no sense to me. - HB */ @@ -587,7 +592,11 @@ void GC_register_dynamic_libraries() # endif /* MMAP_STACKS */ limit = start + addr_map[i].pr_size; - if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) { + /* The following seemed to be necessary for very old versions */ + /* of Irix, but it has been reported to discard relevant */ + /* segments under Irix 6.5. */ +# ifndef IRIX6 + if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) { /* Discard text segments, i.e. 0-offset mappings against */ /* executable files which appear to have ELF headers. */ caddr_t arg; @@ -614,7 +623,8 @@ void GC_register_dynamic_libraries() goto irrelevant; } } - } + } +# endif /* !IRIX6 */ GC_add_roots_inner(start, limit, TRUE); irrelevant: ; } diff --git a/boehm-gc/finalize.c b/boehm-gc/finalize.c index 4c41eb54bf9..229d828632c 100644 --- a/boehm-gc/finalize.c +++ b/boehm-gc/finalize.c @@ -202,15 +202,27 @@ signed_word * log_size_ptr; } new_dl = (struct disappearing_link *) GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL); - if (new_dl != 0) { - new_dl -> dl_hidden_obj = HIDE_POINTER(obj); - new_dl -> dl_hidden_link = HIDE_POINTER(link); - dl_set_next(new_dl, dl_head[index]); - dl_head[index] = new_dl; - GC_dl_entries++; - } else { - GC_finalization_failures++; + if (0 == new_dl) { +# ifdef THREADS + UNLOCK(); + ENABLE_SIGNALS(); +# endif + new_dl == GC_oom_fn(sizeof(struct disappearing_link)); + if (0 == new_dl) { + GC_finalization_failures++; + return(0); + } + /* It's not likely we'll make it here, but ... */ +# ifdef THREADS + DISABLE_SIGNALS(); + LOCK(); +# endif } + new_dl -> dl_hidden_obj = HIDE_POINTER(obj); + new_dl -> dl_hidden_link = HIDE_POINTER(link); + dl_set_next(new_dl, dl_head[index]); + dl_head[index] = new_dl; + GC_dl_entries++; # ifdef THREADS UNLOCK(); ENABLE_SIGNALS(); @@ -245,7 +257,7 @@ signed_word * log_size_ptr; UNLOCK(); ENABLE_SIGNALS(); # ifdef DBG_HDRS_ALL - dl_next(curr_dl) = 0; + dl_set_next(curr_dl, 0); # else GC_free((GC_PTR)curr_dl); # endif @@ -416,18 +428,30 @@ finalization_mark_proc * mp; } new_fo = (struct finalizable_object *) GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL); - if (new_fo != 0) { - new_fo -> fo_hidden_base = (word)HIDE_POINTER(base); - new_fo -> fo_fn = fn; - new_fo -> fo_client_data = (ptr_t)cd; - new_fo -> fo_object_size = hhdr -> hb_sz; - new_fo -> fo_mark_proc = mp; - fo_set_next(new_fo, fo_head[index]); - GC_fo_entries++; - fo_head[index] = new_fo; - } else { - GC_finalization_failures++; + if (0 == new_fo) { +# ifdef THREADS + UNLOCK(); + ENABLE_SIGNALS(); +# endif + new_fo == GC_oom_fn(sizeof(struct finalizable_object)); + if (0 == new_fo) { + GC_finalization_failures++; + return; + } + /* It's not likely we'll make it here, but ... */ +# ifdef THREADS + DISABLE_SIGNALS(); + LOCK(); +# endif } + new_fo -> fo_hidden_base = (word)HIDE_POINTER(base); + new_fo -> fo_fn = fn; + new_fo -> fo_client_data = (ptr_t)cd; + new_fo -> fo_object_size = hhdr -> hb_sz; + new_fo -> fo_mark_proc = mp; + fo_set_next(new_fo, fo_head[index]); + GC_fo_entries++; + fo_head[index] = new_fo; # ifdef THREADS UNLOCK(); ENABLE_SIGNALS(); @@ -593,7 +617,7 @@ void GC_finalize() GC_words_finalized += ALIGNED_WORDS(curr_fo -> fo_object_size) + ALIGNED_WORDS(sizeof(struct finalizable_object)); - GC_ASSERT(GC_is_marked((ptr_t)curr_fo)); + GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo))); curr_fo = next_fo; } else { prev_fo = curr_fo; diff --git a/boehm-gc/gcj_mlc.c b/boehm-gc/gcj_mlc.c index 5f5636d02a5..7e79521eb1f 100644 --- a/boehm-gc/gcj_mlc.c +++ b/boehm-gc/gcj_mlc.c @@ -36,7 +36,6 @@ * 3) FASTLOCK is not a significant win. */ -#include "private/gc_priv.h" #include "private/gc_pmark.h" #include "gc_gcj.h" #include "private/dbg_mlc.h" diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h index b1449f5dc8a..aaf29ee35ba 100644 --- a/boehm-gc/include/gc.h +++ b/boehm-gc/include/gc.h @@ -80,10 +80,6 @@ typedef long ptrdiff_t; /* ptrdiff_t is not defined */ # endif -#if defined(__CYGWIN32__) && defined(GC_USE_DLL) -#include "libgc_globals.h" -#endif - #if defined(__MINGW32__) && defined(WIN32_THREADS) # ifdef GC_BUILD # define GC_API __declspec(dllexport) @@ -92,8 +88,9 @@ # endif #endif -#if defined(_MSC_VER) && (defined(_DLL) && !defined(NOT_GC_DLL) \ - || defined(GC_DLL)) +#if (defined(__DMC__) || defined(_MSC_VER)) \ + && (defined(_DLL) && !defined(GC_NOT_DLL) \ + || defined(GC_DLL)) # ifdef GC_BUILD # define GC_API extern __declspec(dllexport) # else @@ -347,6 +344,10 @@ GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR)); /* Return a pointer to the base (lowest address) of an object given */ /* a pointer to a location within the object. */ +/* I.e. map an interior pointer to the corresponding bas pointer. */ +/* Note that with debugging allocation, this returns a pointer to the */ +/* actual base of the object, i.e. the debug information, not to */ +/* the base of the user object. */ /* Return 0 if displaced_pointer doesn't point to within a valid */ /* object. */ GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer)); @@ -701,7 +702,7 @@ GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p)); /* Returns old warning procedure. */ /* The following is intended to be used by a higher level */ -/* (e.g. cedar-like) finalization facility. It is expected */ +/* (e.g. Java-like) finalization facility. It is expected */ /* that finalization code will arrange for hidden pointers to */ /* disappear. Otherwise objects can be accessed after they */ /* have been collected. */ diff --git a/boehm-gc/include/gc_cpp.h b/boehm-gc/include/gc_cpp.h index 6aacd0aea04..ceb73f50a65 100644 --- a/boehm-gc/include/gc_cpp.h +++ b/boehm-gc/include/gc_cpp.h @@ -83,7 +83,7 @@ Cautions: 1. Be sure the collector has been augmented with "make c++". 2. If your compiler supports the new "operator new[]" syntax, then -add -DOPERATOR_NEW_ARRAY to the Makefile. +add -DGC_OPERATOR_NEW_ARRAY to the Makefile. If your compiler doesn't support "operator new[]", beware that an array of type T, where T is derived from "gc", may or may not be @@ -137,10 +137,17 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined. #define _cdecl #endif -#if ! defined( OPERATOR_NEW_ARRAY ) \ - && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6) \ - || __WATCOMC__ >= 1050 || _MSC_VER >= 1100) -# define OPERATOR_NEW_ARRAY +#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \ + && !defined(_ENABLE_ARRAYNEW) /* Digimars */ \ + && (defined(__BORLANDC__) && (__BORLANDC__ < 0x450) \ + || (defined(__GNUC__) && \ + (__GNUC__ < 2 || __GNUC__ == 2 && __GNUC_MINOR__ < 6)) \ + || (defined(__WATCOMC__) && __WATCOMC__ < 1050)) +# define GC_NO_OPERATOR_NEW_ARRAY +#endif + +#if !defined(GC_NO_OPERATOR_NEW_ARRAY) && !defined(GC_OPERATOR_NEW_ARRAY) +# define GC_OPERATOR_NEW_ARRAY #endif enum GCPlacement {UseGC, @@ -154,11 +161,11 @@ class gc {public: inline void* operator new( size_t size, GCPlacement gcp ); inline void operator delete( void* obj ); -#ifdef OPERATOR_NEW_ARRAY +#ifdef GC_OPERATOR_NEW_ARRAY inline void* operator new[]( size_t size ); inline void* operator new[]( size_t size, GCPlacement gcp ); inline void operator delete[]( void* obj ); -#endif /* OPERATOR_NEW_ARRAY */ +#endif /* GC_OPERATOR_NEW_ARRAY */ }; /* Instances of classes derived from "gc" will be allocated in the @@ -204,7 +211,7 @@ inline void* operator new( classes derived from "gc_cleanup" or containing members derived from "gc_cleanup". */ -#ifdef OPERATOR_NEW_ARRAY +#ifdef GC_OPERATOR_NEW_ARRAY #ifdef _MSC_VER /** This ensures that the system default operator new[] doesn't get @@ -257,7 +264,7 @@ inline void* operator new[]( /* The operator new for arrays, identical to the above. */ -#endif /* OPERATOR_NEW_ARRAY */ +#endif /* GC_OPERATOR_NEW_ARRAY */ /**************************************************************************** @@ -280,7 +287,7 @@ inline void gc::operator delete( void* obj ) { GC_FREE( obj );} -#ifdef OPERATOR_NEW_ARRAY +#ifdef GC_OPERATOR_NEW_ARRAY inline void* gc::operator new[]( size_t size ) { return gc::operator new( size );} @@ -291,7 +298,7 @@ inline void* gc::operator new[]( size_t size, GCPlacement gcp ) { inline void gc::operator delete[]( void* obj ) { gc::operator delete( obj );} -#endif /* OPERATOR_NEW_ARRAY */ +#endif /* GC_OPERATOR_NEW_ARRAY */ inline gc_cleanup::~gc_cleanup() { @@ -305,11 +312,12 @@ inline gc_cleanup::gc_cleanup() { void* oldData; void* base = GC_base( (void *) this ); if (0 != base) { - GC_REGISTER_FINALIZER_IGNORE_SELF( + // Don't call the debug version, since this is a real base address. + GC_register_finalizer_ignore_self( base, (GC_finalization_proc)cleanup, (void*) ((char*) this - (char*) base), &oldProc, &oldData ); if (0 != oldProc) { - GC_REGISTER_FINALIZER_IGNORE_SELF( base, oldProc, oldData, 0, 0 );}}} + GC_register_finalizer_ignore_self( base, oldProc, oldData, 0, 0 );}}} inline void* operator new( size_t size, @@ -331,7 +339,7 @@ inline void* operator new( return obj;} -#ifdef OPERATOR_NEW_ARRAY +#ifdef GC_OPERATOR_NEW_ARRAY inline void* operator new[]( size_t size, @@ -341,7 +349,7 @@ inline void* operator new[]( { return ::operator new( size, gcp, cleanup, clientData );} -#endif /* OPERATOR_NEW_ARRAY */ +#endif /* GC_OPERATOR_NEW_ARRAY */ #endif /* GC_CPP_H */ diff --git a/boehm-gc/include/private/dbg_mlc.h b/boehm-gc/include/private/dbg_mlc.h index 1ee814db19b..6f5b3c8677d 100644 --- a/boehm-gc/include/private/dbg_mlc.h +++ b/boehm-gc/include/private/dbg_mlc.h @@ -19,7 +19,7 @@ * 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 filrd that are frequently included by clients. + * included from header files that are frequently included by clients. */ #ifndef _DBG_MLC_H @@ -32,11 +32,31 @@ # 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) + /* 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 { @@ -48,16 +68,13 @@ typedef struct { /* overwrite a value with the least significant */ /* bit clear, thus ensuring that we never overwrite */ /* a free list link field. */ + /* Note that blocks dropped by black-listing will */ + /* also have the lsb clear once debugging has */ + /* started. */ /* The following are special back pointer values. */ /* Note that the "hidden" (i.e. bitwise */ /* complemented version) of these is actually */ /* stored. */ -# 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. */ # if ALIGNMENT == 1 /* Fudge back pointer to be even. */ # define HIDE_BACK_PTR(p) HIDE_POINTER(~1 & (GC_word)(p)) @@ -68,7 +85,7 @@ typedef struct { word oh_dummy; # endif # endif - char * oh_string; /* object descriptor string */ + GC_CONST char * oh_string; /* object descriptor string */ word oh_int; /* object descriptor integers */ # ifdef NEED_CALLINFO struct callinfo oh_ci[NFRAMES]; @@ -81,13 +98,17 @@ typedef struct { /* The size of the above structure is assumed not to dealign things, */ /* and to be a multiple of the word length. */ -#define DEBUG_BYTES (sizeof (oh) + sizeof (word)) +#ifdef SHORT_DBG_HDRS +# define DEBUG_BYTES (sizeof (oh)) +#else + /* Add space for END_FLAG, but use any extra space that was already */ + /* added to catch off-the-end pointers. */ +# define DEBUG_BYTES (sizeof (oh) + sizeof (word) - EXTRA_BYTES) +#endif #define USR_PTR_FROM_BASE(p) ((ptr_t)(p) + sizeof(oh)) -/* There is no reason to ever add a byte at the end explicitly, since we */ -/* already add a guard word. */ -#undef ROUNDED_UP_WORDS -#define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1) +/* 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) #ifdef SAVE_CALL_CHAIN # define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci) diff --git a/boehm-gc/include/private/gc_hdrs.h b/boehm-gc/include/private/gc_hdrs.h index 6966a9a1a87..dd615455f3b 100644 --- a/boehm-gc/include/private/gc_hdrs.h +++ b/boehm-gc/include/private/gc_hdrs.h @@ -26,13 +26,11 @@ typedef struct hblkhdr hdr; * table. * * This defines HDR, GET_HDR, and SET_HDR, the main macros used to - * retrieve and set object headers. We also define some variants to - * retrieve 2 unrelated headers in interleaved fashion. This - * slightly improves scheduling. + * 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 and HC_GET_HDR2 macros use and maintain this + * 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. */ @@ -67,16 +65,13 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */ /* Check whether p and corresponding hhdr point to long or invalid */ -/* object. If so, advance them to */ +/* object. If so, advance hhdr to */ /* beginning of block, or set hhdr to GC_invalid_header. */ #define ADVANCE(p, hhdr, source) \ - if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \ - p = GC_FIND_START(p, hhdr, (word)source); \ - if (p == 0) { \ - hhdr = GC_invalid_header; \ - } else { \ - hhdr = GC_find_header(p); \ - } \ + { \ + hdr * new_hdr = GC_invalid_header; \ + p = GC_FIND_START(p, hhdr, &new_hdr, (word)source); \ + hhdr = new_hdr; \ } #ifdef USE_HDR_CACHE @@ -124,35 +119,12 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */ } else { \ HC_MISS(); \ GET_HDR(p, hhdr); \ - ADVANCE(p, hhdr, source); \ - hce -> block_addr = (word)(p) >> LOG_HBLKSIZE; \ - hce -> hce_hdr = hhdr; \ - } \ - } - -# define HC_GET_HDR2(p1, hhdr1, source1, p2, hhdr2, source2) \ - { \ - hdr_cache_entry * hce1 = HCE(p1); \ - hdr_cache_entry * hce2 = HCE(p2); \ - if (HCE_VALID_FOR(hce1, p1)) { \ - HC_HIT(); \ - hhdr1 = hce1 -> hce_hdr; \ - } else { \ - HC_MISS(); \ - GET_HDR(p1, hhdr1); \ - ADVANCE(p1, hhdr1, source1); \ - hce1 -> block_addr = (word)(p1) >> LOG_HBLKSIZE; \ - hce1 -> hce_hdr = hhdr1; \ - } \ - if (HCE_VALID_FOR(hce2, p2)) { \ - HC_HIT(); \ - hhdr2 = hce2 -> hce_hdr; \ - } else { \ - HC_MISS(); \ - GET_HDR(p2, hhdr2); \ - ADVANCE(p2, hhdr2, source2); \ - hce2 -> block_addr = (word)(p2) >> LOG_HBLKSIZE; \ - hce2 -> hce_hdr = hhdr2; \ + if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \ + ADVANCE(p, hhdr, source); \ + } else { \ + hce -> block_addr = (word)(p) >> LOG_HBLKSIZE; \ + hce -> hce_hdr = hhdr; \ + } \ } \ } @@ -165,16 +137,10 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */ # define HC_GET_HDR(p, hhdr, source) \ { \ GET_HDR(p, hhdr); \ - ADVANCE(p, hhdr, source); \ - } - -# define HC_GET_HDR2(p1, hhdr1, source1, p2, hhdr2, source2) \ - { \ - GET_HDR2(p1, hhdr1, p2, hhdr2); \ - ADVANCE(p1, hhdr1, source1); \ - ADVANCE(p2, hhdr2, source2); \ + if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \ + ADVANCE(p, hhdr, source); \ + } \ } - #endif typedef struct bi { @@ -229,8 +195,6 @@ typedef struct bi { # 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)) -# define GET_HDR2(p1, hhdr1, p2, hhdr2) \ - { GET_HDR(p1, hhdr1); GET_HDR(p2, hhdr2); } # else /* hash */ /* Hash function for tree top level */ # define TL_HASH(hi) ((hi) & (TOP_SZ - 1)) @@ -257,40 +221,6 @@ typedef struct bi { # define SET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \ *_ha = (hhdr); } # define HDR(p) GC_find_header((ptr_t)(p)) - /* And some interleaved versions for two pointers at once. */ - /* This hopefully helps scheduling on processors like IA64. */ -# define GET_BI2(p1, bottom_indx1, p2, bottom_indx2) \ - { \ - register word hi1 = \ - (word)(p1) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \ - register word hi2 = \ - (word)(p2) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \ - register bottom_index * _bi1 = GC_top_index[TL_HASH(hi1)]; \ - register bottom_index * _bi2 = GC_top_index[TL_HASH(hi2)]; \ - \ - while (_bi1 -> key != hi1 && _bi1 != GC_all_nils) \ - _bi1 = _bi1 -> hash_link; \ - while (_bi2 -> key != hi2 && _bi2 != GC_all_nils) \ - _bi2 = _bi2 -> hash_link; \ - (bottom_indx1) = _bi1; \ - (bottom_indx2) = _bi2; \ - } -# define GET_HDR_ADDR2(p1, ha1, p2, ha2) \ - { \ - register bottom_index * bi1; \ - register bottom_index * bi2; \ - \ - GET_BI2(p1, bi1, p2, bi2); \ - (ha1) = &(HDR_FROM_BI(bi1, p1)); \ - (ha2) = &(HDR_FROM_BI(bi2, p2)); \ - } -# define GET_HDR2(p1, hhdr1, p2, hhdr2) \ - { register hdr ** _ha1; \ - register hdr ** _ha2; \ - GET_HDR_ADDR2(p1, _ha1, p2, _ha2); \ - (hhdr1) = *_ha1; \ - (hhdr2) = *_ha2; \ - } # endif /* Is the result a forwarding address to someplace closer to the */ diff --git a/boehm-gc/include/private/gc_locks.h b/boehm-gc/include/private/gc_locks.h index b9ff0cf1933..eed9f1050f8 100644 --- a/boehm-gc/include/private/gc_locks.h +++ b/boehm-gc/include/private/gc_locks.h @@ -43,6 +43,7 @@ * */ # 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" @@ -236,7 +237,7 @@ /* "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(addr); *(volatile unsigned int *)addr = 1; +# define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1; /* The above needs a memory barrier! */ # define GC_CLEAR_DEFINED # endif diff --git a/boehm-gc/include/private/gc_pmark.h b/boehm-gc/include/private/gc_pmark.h index 0eec53376a8..43077e9f616 100644 --- a/boehm-gc/include/private/gc_pmark.h +++ b/boehm-gc/include/private/gc_pmark.h @@ -25,7 +25,7 @@ #ifndef GC_PMARK_H # define GC_PMARK_H -# ifdef KEEP_BACK_PTRS +# if defined(KEEP_BACK_PTRS) || defined(PRINT_BLACK_LIST) # include "dbg_mlc.h" # endif # ifndef GC_MARK_H @@ -132,12 +132,17 @@ extern mse * GC_mark_stack; */ #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, word source); + 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); -# define source 0 + 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(mse *msp); @@ -169,11 +174,11 @@ mse *GC_signal_mark_stack_overflow(mse *msp); } #ifdef PRINT_BLACK_LIST -# define GC_FIND_START(current, hhdr, source) \ - GC_find_start(current, hhdr, source) +# define GC_FIND_START(current, hhdr, new_hdr_p, source) \ + GC_find_start(current, hhdr, new_hdr_p, source) #else -# define GC_FIND_START(current, hhdr, source) \ - GC_find_start(current, hhdr) +# define GC_FIND_START(current, hhdr, new_hdr_p, source) \ + GC_find_start(current, hhdr, new_hdr_p) #endif /* Push the contents of current onto the mark stack if it is a valid */ @@ -188,9 +193,10 @@ mse *GC_signal_mark_stack_overflow(mse *msp); \ GET_HDR(my_current, my_hhdr); \ if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \ - my_current = GC_FIND_START(my_current, my_hhdr, (word)source); \ - if (my_current == 0) goto exit_label; \ - my_hhdr = GC_find_header(my_current); \ + hdr * new_hdr = GC_invalid_header; \ + my_current = GC_FIND_START(my_current, my_hhdr, \ + &new_hdr, (word)source); \ + my_hhdr = new_hdr; \ } \ PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \ source, exit_label, my_hhdr); \ @@ -210,27 +216,6 @@ exit_label: ; \ exit_label: ; \ } -/* As above, but deal with two pointers in interleaved fashion. */ -# define HC_PUSH_CONTENTS2(current1, current2, mark_stack_top, \ - mark_stack_limit, \ - source1, source2, exit_label1, exit_label2) \ -{ \ - hdr * hhdr1; \ - ptr_t my_current1 = current1; \ - hdr * hhdr2; \ - ptr_t my_current2 = current2; \ - \ - HC_GET_HDR2(my_current1, hhdr1, source1, my_current2, hhdr2, source2); \ - PUSH_CONTENTS_HDR(my_current1, mark_stack_top, mark_stack_limit, \ - source1, exit_label1, hhdr1); \ -exit_label1: ; \ - if (0 != hhdr2) { \ - PUSH_CONTENTS_HDR(my_current2, mark_stack_top, mark_stack_limit, \ - source2, exit_label2, hhdr2); \ - } \ -exit_label2: ; \ -} - /* Set mark bit, exit if it was already set. */ # ifdef USE_MARK_BYTES @@ -257,10 +242,12 @@ exit_label2: ; \ # 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. Since we */ -/* already have the header, we only look at the low order bits of */ -/* current. (The value of current doesn't matter if hhdr = */ -/* GC_invalid_header.) */ +/* 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) \ { \ @@ -346,7 +333,7 @@ mse * GC_mark_from GC_PROTO((mse * top, mse * bottom, mse *limit)); 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)); \ + while (!GC_mark_some((ptr_t)0)) {} \ } \ } diff --git a/boehm-gc/include/private/gc_priv.h b/boehm-gc/include/private/gc_priv.h index d06cd8b872c..5135e3e9b0a 100644 --- a/boehm-gc/include/private/gc_priv.h +++ b/boehm-gc/include/private/gc_priv.h @@ -634,7 +634,7 @@ extern GC_warn_proc GC_current_warn_proc; # else # define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n) # endif -# define SMALL_OBJ(bytes) ((bytes) < (MAXOBJBYTES -EXTRA_BYTES)) +# 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. */ @@ -1456,6 +1456,9 @@ 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 */ @@ -1484,9 +1487,9 @@ void GC_bl_init GC_PROTO((void)); /* 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, source); \ + GC_add_to_black_list_stack(bits, (ptr_t)(source)); \ } else { \ - GC_add_to_black_list_normal(bits, source); \ + GC_add_to_black_list_normal(bits, (ptr_t)(source)); \ } # else void GC_add_to_black_list_normal GC_PROTO((word p)); @@ -1796,12 +1799,16 @@ void GC_dump GC_PROTO((void)); /* Make arguments appear live to compiler */ # ifdef __WATCOMC__ - void GC_noop(void*, ...); + void GC_noop(void*, ...); # else - GC_API void GC_noop(); +# ifdef __DMC__ + GC_API void GC_noop(...); +# else + GC_API void GC_noop(); +# endif # endif -void GC_noop1 GC_PROTO((word arg)); +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)); @@ -1859,7 +1866,7 @@ void GC_err_puts GC_PROTO((GC_CONST char *s)); # define GC_ASSERT(expr) # endif -# ifdef PARALLEL_MARK +# 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 */ @@ -1878,13 +1885,15 @@ void GC_err_puts GC_PROTO((GC_CONST char *s)); extern void GC_acquire_mark_lock(); extern void GC_release_mark_lock(); - extern void GC_notify_all_marker(); extern void GC_notify_all_builder(); - extern void GC_wait_marker(); /* 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); @@ -1894,4 +1903,29 @@ void GC_err_puts GC_PROTO((GC_CONST char *s)); /* some other reason. */ # endif /* PARALLEL_MARK */ +# if defined(LINUX_THREADS) || defined(IRIX_THREADS) \ + || defined(HPUX_THREADS) || defined(OSF1_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(LINUX_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 uses SIGUSR1 and SIGUSR2. */ +# define SIG_SUSPEND SIGPWR +# endif +# else /* !LINUX_THREADS */ +# define SIG_SUSPEND _SIGRTMIN + 6 +# endif +# endif /* !SIG_SUSPEND */ + +# endif + # endif /* GC_PRIVATE_H */ diff --git a/boehm-gc/include/private/gcconfig.h b/boehm-gc/include/private/gcconfig.h index 0f7fe248073..e8bac1bcdc2 100644 --- a/boehm-gc/include/private/gcconfig.h +++ b/boehm-gc/include/private/gcconfig.h @@ -174,7 +174,7 @@ # define IA64 # define mach_type_known # endif -# if defined(LINUX) && defined(powerpc) +# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__)) # define POWERPC # define mach_type_known # endif @@ -350,6 +350,14 @@ # 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 */ @@ -497,6 +505,14 @@ * word stores of 0 are used instead. */ +/* 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 @@ -804,6 +820,9 @@ # 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; @@ -1023,6 +1042,17 @@ # 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 @@ -1039,7 +1069,6 @@ # ifdef MIPS # define MACH_TYPE "MIPS" -/* # define STACKBOTTOM ((ptr_t)0x7fff8000) sometimes also works. */ # ifdef LINUX /* This was developed for a linuxce style platform. Probably */ /* needs to be tweaked for workstation class machines. */ @@ -1047,8 +1076,9 @@ extern int __data_start; # define DATASTART ((ptr_t)(&__data_start)) # define ALIGNMENT 4 -# define USE_GENERIC_PUSH_REGS 1 -# define STACKBOTTOM 0x80000000 +# define USE_GENERIC_PUSH_REGS +# define STACKBOTTOM ((ptr_t)0x7fff8000) + /* Older toolchains may need 0x80000000. */ /* In many cases, this should probably use LINUX_STACKBOTTOM */ /* instead. But some kernel versions seem to give the wrong */ /* value from /proc. */ @@ -1106,7 +1136,7 @@ # define ALIGNMENT 4 # define OS_TYPE "NETBSD" # define HEURISTIC2 -# define USE_GENERIC_PUSH_REGS 1 +# define USE_GENERIC_PUSH_REGS # ifdef __ELF__ extern int etext; # define DATASTART GC_data_start @@ -1587,6 +1617,12 @@ # if defined(HPUX_THREADS) && !defined(HPUX) --> inconsistent configuration # endif +# if defined(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(SOLARIS_THREADS) || defined(WIN32_THREADS) || \ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \ diff --git a/boehm-gc/irix_threads.c b/boehm-gc/irix_threads.c index 101f5b1f412..12aba546ab9 100644 --- a/boehm-gc/irix_threads.c +++ b/boehm-gc/irix_threads.c @@ -100,8 +100,8 @@ GC_thread GC_lookup_thread(pthread_t id); * The only way to suspend threads given the pthread interface is to send * signals. Unfortunately, this means we have to reserve * a signal, and intercept client calls to change the signal mask. + * We use SIG_SUSPEND, defined in gc_priv.h. */ -# define SIG_SUSPEND (SIGRTMIN + 6) pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER; /* Number of threads stopped so far */ diff --git a/boehm-gc/linux_threads.c b/boehm-gc/linux_threads.c index 37537bcef3e..8ab140b6b38 100644 --- a/boehm-gc/linux_threads.c +++ b/boehm-gc/linux_threads.c @@ -55,6 +55,12 @@ || defined(GC_OSF1_THREADS) || defined(OSF1_THREADS) \ # include "private/gc_priv.h" + +# if defined(HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \ + && !defined(USE_HPUX_TLS) +# define USE_HPUX_TLS +# endif + # ifdef THREAD_LOCAL_ALLOC # if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_HPUX_TLS) # include "private/specific.h" @@ -161,15 +167,16 @@ typedef struct GC_Thread_Rep { # ifdef THREAD_LOCAL_ALLOC # if CPP_WORDSZ == 64 && defined(ALIGN_DOUBLE) # define GRANULARITY 16 -# define NFREELISTS 48 +# define NFREELISTS 49 # else # define GRANULARITY 8 -# define NFREELISTS 64 +# define NFREELISTS 65 # endif - /* The ith free list corresponds to size (i+1)*GRANULARITY */ -# define INDEX_FROM_BYTES(n) (ADD_SLOP(n) - 1)/GRANULARITY -# define BYTES_FROM_INDEX(i) (((i) + 1) * GRANULARITY - EXTRA_BYTES) -# define SMALL_ENOUGH(bytes) (ADD_SLOP(bytes) <= NFREELISTS*GRANULARITY) + /* The ith free list corresponds to size i*GRANULARITY */ +# define INDEX_FROM_BYTES(n) ((ADD_SLOP(n) + GRANULARITY - 1)/GRANULARITY) +# define BYTES_FROM_INDEX(i) ((i) * GRANULARITY - EXTRA_BYTES) +# define SMALL_ENOUGH(bytes) (ADD_SLOP(bytes) <= \ + (NFREELISTS-1)*GRANULARITY) ptr_t ptrfree_freelists[NFREELISTS]; ptr_t normal_freelists[NFREELISTS]; # ifdef GC_GCJ_SUPPORT @@ -194,12 +201,12 @@ typedef struct GC_Thread_Rep { GC_thread GC_lookup_thread(pthread_t id); -static GC_bool fully_initialized = FALSE; +static GC_bool parallel_initialized = FALSE; # if defined(__GNUC__) - void GC_full_init() __attribute__ ((constructor)); + void GC_init_parallel() __attribute__ ((constructor)); # else - void GC_full_init(); + void GC_init_parallel(); # endif # if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL) @@ -223,8 +230,8 @@ static void return_freelists(ptr_t *fl, ptr_t *gfl) ptr_t q, *qptr; size_t nwords; - for (i = 0; i < NFREELISTS; ++i) { - nwords = (i + 1) * (GRANULARITY/sizeof(word)); + for (i = 1; i < NFREELISTS; ++i) { + nwords = i * (GRANULARITY/sizeof(word)); qptr = fl + i; q = *qptr; if ((word)q < HBLKSIZE) continue; @@ -243,6 +250,12 @@ static void return_freelists(ptr_t *fl, ptr_t *gfl) } } +/* We statically allocate a single "size 0" object. It is linked to */ +/* itself, and is thus repeatedly reused for all size 0 allocation */ +/* requests. (Size 0 gcj allocation requests are incorrect, and */ +/* we arrange for those to fault asap.) */ +static ptr_t size_zero_object = (ptr_t)(&size_zero_object); + /* Each thread structure must be initialized. */ /* This call must be made from the new thread. */ /* Caller holds allocation lock. */ @@ -259,13 +272,19 @@ void GC_init_thread_local(GC_thread p) if (0 != GC_setspecific(GC_thread_key, p)) { ABORT("Failed to set thread specific allocation pointers"); } - for (i = 0; i < NFREELISTS; ++i) { + for (i = 1; i < NFREELISTS; ++i) { p -> ptrfree_freelists[i] = (ptr_t)1; p -> normal_freelists[i] = (ptr_t)1; # ifdef GC_GCJ_SUPPORT p -> gcj_freelists[i] = (ptr_t)1; # endif } + /* Set up the size 0 free lists. */ + p -> ptrfree_freelists[0] = (ptr_t)(&size_zero_object); + p -> normal_freelists[0] = (ptr_t)(&size_zero_object); +# ifdef GC_GCJ_SUPPORT + p -> gcj_freelists[0] = (ptr_t)(-1); +# endif } #ifdef GC_GCJ_SUPPORT @@ -303,7 +322,7 @@ GC_PTR GC_local_malloc(size_t bytes) /* This can happen if we get called when the world is */ /* being initialized. Whether we can actually complete */ /* the initialization then is unclear. */ - GC_full_init(); + GC_init_parallel(); k = GC_thread_key; } # endif @@ -326,10 +345,8 @@ GC_PTR GC_local_malloc(size_t bytes) *my_fl = my_entry + index + 1; return GC_malloc(bytes); } else { - my_entry = GC_generic_malloc_many(BYTES_FROM_INDEX(index), - NORMAL); - *my_fl = my_entry; - if (my_entry == 0) return GC_oom_fn(bytes); + GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl); + if (*my_fl == 0) return GC_oom_fn(bytes); return GC_local_malloc(bytes); } } @@ -352,10 +369,11 @@ GC_PTR GC_local_malloc_atomic(size_t bytes) *my_fl = my_entry + index + 1; return GC_malloc_atomic(bytes); } else { - my_entry = GC_generic_malloc_many(BYTES_FROM_INDEX(index), - PTRFREE); - *my_fl = my_entry; - if (my_entry == 0) return GC_oom_fn(bytes); + GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl); + /* *my_fl is updated while the collector is excluded; */ + /* the free list is always visible to the collector as */ + /* such. */ + if (*my_fl == 0) return GC_oom_fn(bytes); return GC_local_malloc_atomic(bytes); } } @@ -390,18 +408,22 @@ GC_PTR GC_local_gcj_malloc(size_t bytes, /* allocation of the next object, but to see this object */ /* still containing a free list pointer. Otherwise the */ /* marker might find a random "mark descriptor". */ - *my_fl = obj_link(my_entry); - *(void **)result = ptr_to_struct_containing_descr; + *(volatile ptr_t *)my_fl = obj_link(my_entry); + /* We must update the freelist before we store the pointer. */ + /* Otherwise a GC at this point would see a corrupted */ + /* free list. */ + /* A memory barrier is probably never needed, since the */ + /* action of stopping this thread will cause prior writes */ + /* to complete. */ + *(void * volatile *)result = ptr_to_struct_containing_descr; return result; } else if ((word)my_entry - 1 < DIRECT_GRANULES) { *my_fl = my_entry + index + 1; return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr); } else { - my_entry = GC_generic_malloc_many(BYTES_FROM_INDEX(index), - GC_gcj_kind); - *my_fl = my_entry; - if (my_entry == 0) return GC_oom_fn(bytes); - return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr); + GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl); + if (*my_fl == 0) return GC_oom_fn(bytes); + return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr); } } } @@ -415,22 +437,16 @@ GC_PTR GC_local_gcj_malloc(size_t bytes, # endif /* !THREAD_LOCAL_ALLOC */ /* - * The only way to suspend threads given the pthread interface is to send - * signals. We can't use SIGSTOP directly, because we need to get the - * thread to save its stack pointer in the GC thread table before - * suspending. So we have to reserve a signal of our own for this. - * This means we have to intercept client calls to change the signal mask. - * The linuxthreads package already uses SIGUSR1 and SIGUSR2, - * so we need to reuse something else. I chose SIGPWR. - * (Perhaps SIGUNUSED would be a better choice.) + * We use signals to stop threads during GC. + * + * Suspended threads wait in signal handler for SIG_THR_RESTART. + * That's more portable than semaphores or condition variables. + * (We do use sem_post from a signal handler, but that should be portable.) + * + * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h. + * Note that we can't just stop a thread; we need it to save its stack + * pointer(s) and acknowledge. */ -#ifndef SIG_SUSPEND -# if defined(HPUX_THREADS) || defined(GC_OSF1_THREADS) -# define SIG_SUSPEND _SIGRTMIN + 6 -# else -# define SIG_SUSPEND SIGPWR -# endif -#endif #ifndef SIG_THR_RESTART # if defined(HPUX_THREADS) || defined(GC_OSF1_THREADS) @@ -440,12 +456,6 @@ GC_PTR GC_local_gcj_malloc(size_t bytes, # endif #endif -/* SPARC/Linux doesn't properly define SIGPWR in <signal.h>. - * It is aliased to SIGLOST in asm/signal.h, though. */ -#if defined(SPARC) && !defined(SIGPWR) -# define SIGPWR SIGLOST -#endif - sem_t GC_suspend_ack_sem; #if !defined(HPUX_THREADS) && !defined(GC_OSF1_THREADS) @@ -654,6 +664,34 @@ void GC_push_thread_structures GC_PROTO((void)) GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads)); } +#ifdef THREAD_LOCAL_ALLOC +/* We must explicitly mark ptrfree and gcj free lists, since the free */ +/* list links wouldn't otherwise be found. We also set them in the */ +/* normal free lists, since that involves touching less memory than if */ +/* we scanned them normally. */ +void GC_mark_thread_local_free_lists(void) +{ + int i, j; + GC_thread p; + ptr_t q; + + for (i = 0; i < THREAD_TABLE_SZ; ++i) { + for (p = GC_threads[i]; 0 != p; p = p -> next) { + for (j = 1; j < NFREELISTS; ++j) { + q = p -> ptrfree_freelists[j]; + if ((word)q > HBLKSIZE) GC_set_fl_marks(q); + q = p -> normal_freelists[j]; + if ((word)q > HBLKSIZE) GC_set_fl_marks(q); +# ifdef GC_GCJ_SUPPORT + q = p -> gcj_freelists[j]; + if ((word)q > HBLKSIZE) GC_set_fl_marks(q); +# endif /* GC_GCJ_SUPPORT */ + } + } + } +} +#endif /* THREAD_LOCAL_ALLOC */ + /* Add a thread to GC_threads. We assume it wasn't already there. */ /* Caller holds allocation lock. */ GC_thread GC_new_thread(pthread_t id) @@ -752,7 +790,6 @@ void GC_stop_world() GC_stopping_thread = my_thread; /* debugging only. */ GC_stopping_pid = getpid(); /* debugging only. */ - /* Make sure all free list construction has stopped before we start. */ /* No new construction can start, since free list construction is */ /* required to acquire and release the GC lock before it starts, */ @@ -795,6 +832,7 @@ void GC_stop_world() #if DEBUG_THREADS GC_printf1("World stopped 0x%x\n", pthread_self()); #endif + GC_stopping_thread = 0; /* debugging only */ } /* Caller holds allocation lock, and has held it continuously since */ @@ -1072,9 +1110,12 @@ void GC_thr_init() /* may require allocation. */ /* Called as constructor without allocation lock. */ /* Must be called before a second thread is created. */ -void GC_full_init() +/* Called without allocation lock. */ +void GC_init_parallel() { - if (fully_initialized) return; + if (parallel_initialized) return; + parallel_initialized = TRUE; + /* GC_init() calls us back, so set flag first. */ if (!GC_is_initialized) GC_init(); /* If we are using a parallel marker, start the helper threads. */ # ifdef PARALLEL_MARK @@ -1086,7 +1127,6 @@ void GC_full_init() GC_init_thread_local(GC_lookup_thread(pthread_self())); UNLOCK(); # endif - fully_initialized = TRUE; } @@ -1327,7 +1367,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread, LOCK(); si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info), NORMAL); UNLOCK(); - if (!fully_initialized) GC_full_init(); + if (!parallel_initialized) GC_init_parallel(); if (0 == si) return(ENOMEM); sem_init(&(si -> registered), 0, 0); si -> start_routine = start_routine; @@ -1539,7 +1579,7 @@ void GC_lock() #endif /* !USE_SPINLOCK */ -#ifdef PARALLEL_MARK +#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) #ifdef GC_ASSERTIONS pthread_t GC_mark_lock_holder = NO_THREAD; @@ -1559,8 +1599,6 @@ void GC_lock() static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER; #endif -static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER; - static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER; void GC_acquire_mark_lock() @@ -1587,13 +1625,18 @@ void GC_release_mark_lock() } } -void GC_wait_marker() +/* Collector must wait for a freelist builders for 2 reasons: */ +/* 1) Mark bits may still be getting examined without lock. */ +/* 2) Partial free lists referenced only by locals may not be scanned */ +/* correctly, e.g. if they contain "pointer-free" objects, since the */ +/* free-list link may be ignored. */ +void GC_wait_builder() { GC_ASSERT(GC_mark_lock_holder == pthread_self()); # ifdef GC_ASSERTIONS GC_mark_lock_holder = NO_THREAD; # endif - if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) { + if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) { ABORT("pthread_cond_wait failed"); } GC_ASSERT(GC_mark_lock_holder == NO_THREAD); @@ -1602,13 +1645,36 @@ void GC_wait_marker() # endif } -void GC_wait_builder() +void GC_wait_for_reclaim() +{ + GC_acquire_mark_lock(); + while (GC_fl_builder_count > 0) { + GC_wait_builder(); + } + GC_release_mark_lock(); +} + +void GC_notify_all_builder() +{ + GC_ASSERT(GC_mark_lock_holder == pthread_self()); + if (pthread_cond_broadcast(&builder_cv) != 0) { + ABORT("pthread_cond_broadcast failed"); + } +} + +#endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */ + +#ifdef PARALLEL_MARK + +static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER; + +void GC_wait_marker() { GC_ASSERT(GC_mark_lock_holder == pthread_self()); # ifdef GC_ASSERTIONS GC_mark_lock_holder = NO_THREAD; # endif - if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) { + if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) { ABORT("pthread_cond_wait failed"); } GC_ASSERT(GC_mark_lock_holder == NO_THREAD); @@ -1624,22 +1690,6 @@ void GC_notify_all_marker() } } -void GC_notify_all_builder() -{ - GC_ASSERT(GC_mark_lock_holder == pthread_self()); - if (pthread_cond_broadcast(&builder_cv) != 0) { - ABORT("pthread_cond_broadcast failed"); - } -} - -void GC_wait_for_reclaim() -{ - GC_acquire_mark_lock(); - while (GC_fl_builder_count > 0) { - GC_wait_builder(); - } - GC_release_mark_lock(); -} #endif /* PARALLEL_MARK */ # endif /* LINUX_THREADS */ diff --git a/boehm-gc/mach_dep.c b/boehm-gc/mach_dep.c index 45cae1f8c39..776bf6909bc 100644 --- a/boehm-gc/mach_dep.c +++ b/boehm-gc/mach_dep.c @@ -228,7 +228,7 @@ void GC_push_regs() && !(defined(NETBSD) && defined(__ELF__)) \ && !(defined(OPENBSD) && defined(__ELF__)) \ && !(defined(BEOS) && defined(__ELF__)) \ - && !defined(DOS4GW) + && !defined(DOS4GW) && !defined(HURD) /* I386 code, generic code does not appear to work */ /* It does appear to work under OS2, and asms dont */ /* This is used for some 38g UNIX variants and for CYGWIN32 */ @@ -244,7 +244,8 @@ void GC_push_regs() # if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \ || ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \ || ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \ - || ( defined(I386) && defined(OPENBSD) && defined(__ELF__) ) + || ( defined(I386) && defined(OPENBSD) && defined(__ELF__) ) \ + || ( defined(I386) && defined(HURD) && defined(__ELF__) ) /* This is modified for Linux with ELF (Note: _ELF_ only) */ /* This section handles FreeBSD with ELF. */ @@ -391,8 +392,8 @@ void GC_push_regs() # endif /* other machines... */ -# if !(defined M68K) && !(defined VAX) && !(defined RT) -# if !(defined SPARC) && !(defined I386) && !(defined NS32K) +# if !defined(M68K) && !defined(VAX) && !defined(RT) +# if !defined(SPARC) && !defined(I386) && !defined(NS32K) # if !defined(POWERPC) && !defined(UTS4) # if !defined(PJ) && !(defined(MIPS) && defined(LINUX)) --> bad news <-- @@ -407,27 +408,35 @@ void GC_push_regs() void GC_generic_push_regs(cold_gc_frame) ptr_t cold_gc_frame; { - /* Generic code */ - /* The idea is due to Parag Patel at HP. */ - /* We're not sure whether he would like */ - /* to be he acknowledged for it or not. */ { - static jmp_buf regs; - register word * i = (word *) regs; - register ptr_t lim = (ptr_t)(regs) + (sizeof regs); - - /* Setjmp on Sun 3s doesn't clear all of the buffer. */ - /* That tends to preserve garbage. Clear it. */ +# ifdef HAVE_BUILTIN_UNWIND_INIT + /* This was suggested by Richard Henderson as the way to */ + /* force callee-save registers and register windows onto */ + /* the stack. */ + __builtin_unwind_init(); +# else /* !HAVE_BUILTIN_UNWIND_INIT */ + /* Generic code */ + /* The idea is due to Parag Patel at HP. */ + /* We're not sure whether he would like */ + /* to be he acknowledged for it or not. */ + jmp_buf regs; + register word * i = (word *) regs; + register ptr_t lim = (ptr_t)(regs) + (sizeof regs); + + /* Setjmp doesn't always clear all of the buffer. */ + /* That tends to preserve garbage. Clear it. */ for (; (char *)i < lim; i++) { *i = 0; } -# if defined(POWERPC) || defined(MSWIN32) || defined(MSWINCE) \ - || defined(UTS4) || defined(LINUX) - (void) setjmp(regs); -# else - (void) _setjmp(regs); -# endif -# if defined(SPARC) || defined(IA64) +# if defined(POWERPC) || defined(MSWIN32) || defined(MSWINCE) \ + || defined(UTS4) || defined(LINUX) + (void) setjmp(regs); +# else + (void) _setjmp(regs); +# endif +# endif /* !HAVE_BUILTIN_UNWIND_INIT */ +# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \ + || defined(IA64) /* On a register window machine, we need to save register */ /* contents on the stack for this to work. The setjmp */ /* is probably not needed on SPARC, since pointers are */ @@ -438,6 +447,10 @@ ptr_t cold_gc_frame; word GC_save_regs_in_stack(); GC_save_regs_ret_val = GC_save_regs_in_stack(); + /* On IA64 gcc, could use __builtin_ia64_flushrs() and */ + /* __builtin_ia64_flushrs(). The latter will be done */ + /* implicitly by __builtin_unwind_init() for gcc3.0.1 */ + /* and later. */ } # endif GC_push_current_stack(cold_gc_frame); @@ -511,7 +524,7 @@ ptr_t cold_gc_frame; /* returns arg. Stack clearing is crucial on SPARC, so we supply */ /* an assembly version that's more careful. Assumes limit is hotter */ /* than sp, and limit is 8 byte aligned. */ -#if defined(ASM_CLEAR_CODE) && !defined(THREADS) +#if defined(ASM_CLEAR_CODE) #ifndef SPARC --> fix it #endif diff --git a/boehm-gc/mallocx.c b/boehm-gc/mallocx.c index 77c750fafbc..031fcaf91a8 100644 --- a/boehm-gc/mallocx.c +++ b/boehm-gc/mallocx.c @@ -323,10 +323,15 @@ extern ptr_t GC_reclaim_generic(); /* GC_malloc_many or friends to replenish it. (We do not round up */ /* object sizes, since a call indicates the intention to consume many */ /* objects of exactly this size.) */ +/* We return the free-list by assigning it to *result, since it is */ +/* not safe to return, e.g. a linked list of pointer-free objects, */ +/* since the collector would not retain the entire list if it were */ +/* invoked just as we were returning. */ /* Note that the client should usually clear the link field. */ -ptr_t GC_generic_malloc_many(lb, k) +void GC_generic_malloc_many(lb, k, result) register word lb; register int k; +ptr_t *result; { ptr_t op; ptr_t p; @@ -345,13 +350,20 @@ DCL_LOCK_STATE; if (!SMALL_OBJ(lb)) { op = GC_generic_malloc(lb, k); if(0 != op) obj_link(op) = 0; - return(op); + *result = op; + return; } lw = ALIGNED_WORDS(lb); GC_INVOKE_FINALIZERS(); DISABLE_SIGNALS(); LOCK(); if (!GC_is_initialized) GC_init_inner(); + /* Do our share of marking work */ + if (GC_incremental && !GC_dont_gc) { + ENTER_GC(); + GC_collect_a_little_inner(1); + EXIT_GC(); + } /* First see if we can reclaim a page of objects waiting to be */ /* reclaimed. */ { @@ -403,6 +415,7 @@ DCL_LOCK_STATE; GC_mem_found += my_words_allocd; # endif # ifdef PARALLEL_MARK + *result = op; (void)GC_atomic_add( (volatile GC_word *)(&GC_words_allocd_tmp), (GC_word)(my_words_allocd)); @@ -410,7 +423,8 @@ DCL_LOCK_STATE; -- GC_fl_builder_count; if (GC_fl_builder_count == 0) GC_notify_all_builder(); GC_release_mark_lock(); - return GC_clear_stack(op); + (void) GC_clear_stack(0); + return; # else GC_words_allocd += my_words_allocd; goto out; @@ -464,11 +478,13 @@ DCL_LOCK_STATE; op = GC_build_fl(h, lw, ok -> ok_init, 0); # ifdef PARALLEL_MARK + *result = op; GC_acquire_mark_lock(); -- GC_fl_builder_count; if (GC_fl_builder_count == 0) GC_notify_all_builder(); GC_release_mark_lock(); - return GC_clear_stack(op); + (void) GC_clear_stack(0); + return; # else goto out; # endif @@ -481,14 +497,17 @@ DCL_LOCK_STATE; if (0 != op) obj_link(op) = 0; out: + *result = op; UNLOCK(); ENABLE_SIGNALS(); - return(GC_clear_stack(op)); + (void) GC_clear_stack(0); } GC_PTR GC_malloc_many(size_t lb) { - return(GC_generic_malloc_many(lb, NORMAL)); + ptr_t result; + GC_generic_malloc_many(lb, NORMAL, &result); + return result; } /* Note that the "atomic" version of this would be unsafe, since the */ diff --git a/boehm-gc/mark.c b/boehm-gc/mark.c index 18b5749c351..4d7504799d4 100644 --- a/boehm-gc/mark.c +++ b/boehm-gc/mark.c @@ -427,21 +427,22 @@ GC_bool GC_mark_stack_empty() #endif /* Given a pointer to someplace other than a small object page or the */ -/* first page of a large object, return a pointer either to the */ -/* start of the large object or NIL. */ -/* In the latter case black list the address current. */ -/* Returns NIL without black listing if current points to a block */ -/* with IGNORE_OFF_PAGE set. */ +/* first page of a large object, either: */ +/* - return a pointer to somewhere in the first page of the large */ +/* object, if current points to a large object. */ +/* In this case *hhdr is replaced with a pointer to the header */ +/* for the large object. */ +/* - just return current if it does not point to a large object. */ /*ARGSUSED*/ # ifdef PRINT_BLACK_LIST - ptr_t GC_find_start(current, hhdr, source) - word source; + ptr_t GC_find_start(current, hhdr, new_hdr_p, source) + ptr_t source; # else - ptr_t GC_find_start(current, hhdr) + ptr_t GC_find_start(current, hhdr, new_hdr_p) # define source 0 # endif register ptr_t current; -register hdr * hhdr; +register hdr *hhdr, **new_hdr_p; { if (GC_all_interior_pointers) { if (hhdr != 0) { @@ -457,17 +458,15 @@ register hdr * hhdr; if ((word *)orig - (word *)current >= (ptrdiff_t)(hhdr->hb_sz)) { /* Pointer past the end of the block */ - GC_ADD_TO_BLACK_LIST_NORMAL((word)orig, source); - return(0); + return(orig); } + *new_hdr_p = hhdr; return(current); } else { - GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); - return(0); + return(current); } } else { - GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); - return(0); + return(current); } # undef source } diff --git a/boehm-gc/mark_rts.c b/boehm-gc/mark_rts.c index 8480a0e1a4a..251a0d1458f 100644 --- a/boehm-gc/mark_rts.c +++ b/boehm-gc/mark_rts.c @@ -471,8 +471,9 @@ ptr_t cold_gc_frame; cold_gc_bs_pointer = bsp - 2048; if (cold_gc_bs_pointer < BACKING_STORE_BASE) { cold_gc_bs_pointer = BACKING_STORE_BASE; + } else { + GC_push_all_stack(BACKING_STORE_BASE, cold_gc_bs_pointer); } - GC_push_all_stack(BACKING_STORE_BASE, cold_gc_bs_pointer); } else { cold_gc_bs_pointer = BACKING_STORE_BASE; } @@ -501,6 +502,10 @@ void GC_push_gc_structures GC_PROTO((void)) # endif } +#ifdef THREAD_LOCAL_ALLOC + void GC_mark_thread_local_free_lists(); +#endif + /* * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional * on groups of pointers) on every top level accessible pointer. @@ -552,6 +557,12 @@ ptr_t cold_gc_frame; GC_push_gc_structures(); } + /* Mark thread local free lists, even if their mark */ + /* descriptor excludes the link field. */ +# ifdef THREAD_LOCAL_ALLOC + GC_mark_thread_local_free_lists(); +# endif + /* * Now traverse stacks. */ diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c index 8ece80d9154..94ef15d3c3f 100644 --- a/boehm-gc/misc.c +++ b/boehm-gc/misc.c @@ -45,7 +45,7 @@ mutex_t GC_allocate_ml; /* Implicitly initialized. */ # else # ifdef WIN32_THREADS -# if defined(_DLL) || defined(GC_DLL) +# if !defined(GC_NOT_DLL) && (defined(_DLL) || defined(GC_DLL)) __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml; # else CRITICAL_SECTION GC_allocate_ml; @@ -301,6 +301,8 @@ ptr_t arg; if (++random_no % 13 == 0) { limit = sp; MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word)); + limit &= ~0xf; /* Make it sufficiently aligned for assembly */ + /* implementations of GC_clear_stack_inner. */ return GC_clear_stack_inner(arg, limit); } else { BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word)); @@ -441,6 +443,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) @@ -682,7 +693,7 @@ out: } int GC_write(buf, len) - char * buf; + GC_CONST char * buf; size_t len; { BOOL tmp; @@ -735,7 +746,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; @@ -867,7 +878,7 @@ GC_CONST char * msg; /* 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(;;); + for(;;) {} } # ifdef MSWIN32 DebugBreak(); diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c index a7f6d194005..71fc3b68e20 100644 --- a/boehm-gc/os_dep.c +++ b/boehm-gc/os_dep.c @@ -63,25 +63,24 @@ /* Blatantly OS dependent routines, except for those that are related */ /* to dynamic loading. */ -# if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2) +# if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START) # define NEED_FIND_LIMIT # endif -# if defined(IRIX_THREADS) || defined(HPUX_THREADS) +# if !defined(STACKBOTTOM) && defined(HEURISTIC2) # define NEED_FIND_LIMIT # endif -# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR) +# if defined(IRIX_THREADS) || defined(HPUX_THREADS) # define NEED_FIND_LIMIT # endif -# if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR) +# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR) # define NEED_FIND_LIMIT # endif -# if defined(LINUX) && \ - (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64) \ - || defined(MIPS)) +# if (defined(SVR4) || defined(AUX) || defined(DGUX) \ + || (defined(LINUX) && defined(SPARC))) && !defined(PCR) # define NEED_FIND_LIMIT # endif @@ -123,8 +122,10 @@ # include <fcntl.h> #endif -#ifdef SUNOS5SIGS -# include <sys/siginfo.h> +#if defined(SUNOS5SIGS) || defined (HURD) || defined(LINUX) +# ifdef SUNOS5SIGS +# include <sys/siginfo.h> +# endif # undef setjmp # undef longjmp # define setjmp(env) sigsetjmp(env, 1) @@ -338,7 +339,7 @@ void GC_enable_signals(void) && !defined(MSWINCE) \ && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) -# if defined(sigmask) && !defined(UTS4) +# if defined(sigmask) && !defined(UTS4) && !defined(HURD) /* Use the traditional BSD interface */ # define SIGSET_T int # define SIG_DEL(set, signal) (set) &= ~(sigmask(signal)) @@ -519,7 +520,7 @@ ptr_t GC_get_stack_base() # undef GC_AMIGA_SB # endif /* AMIGA */ -# if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE) +# if defined(NEED_FIND_LIMIT) || (defined(UNIX_LIKE) && !defined(ECOS)) # ifdef __STDC__ typedef void (*handler)(int); @@ -527,9 +528,9 @@ ptr_t GC_get_stack_base() typedef void (*handler)(); # endif -# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) || defined(HURD) static struct sigaction old_segv_act; -# if defined(_sigargs) || defined(HPUX) /* !Irix6.x */ +# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) || defined(HURD) static struct sigaction old_bus_act; # endif # else @@ -544,11 +545,16 @@ ptr_t GC_get_stack_base() # endif { # ifndef ECOS -# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) +# if defined(SUNOS5SIGS) || defined(IRIX5) \ + || defined(OSF1) || defined(HURD) struct sigaction act; act.sa_handler = h; - act.sa_flags = SA_RESTART | SA_NODEFER; +# ifdef SUNOS5SIGS + act.sa_flags = SA_RESTART | SA_NODEFER; +# else + act.sa_flags = SA_RESTART; +# endif /* The presence of SA_NODEFER represents yet another gross */ /* hack. Under Solaris 2.3, siglongjmp doesn't appear to */ /* interact correctly with -lthread. We hide the confusion */ @@ -564,7 +570,7 @@ ptr_t GC_get_stack_base() # else (void) sigaction(SIGSEGV, &act, &old_segv_act); # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) + || defined(HPUX) || defined(HURD) /* Under Irix 5.x or HP/UX, we may get SIGBUS. */ /* Pthreads doesn't exist under Irix 5.x, so we */ /* don't have to worry in the threads case. */ @@ -601,10 +607,11 @@ ptr_t GC_get_stack_base() void GC_reset_fault_handler() { # ifndef ECOS -# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) +# if defined(SUNOS5SIGS) || defined(IRIX5) \ + || defined(OSF1) || defined(HURD) (void) sigaction(SIGSEGV, &old_segv_act, 0); # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ - || defined(HPUX) + || defined(HPUX) || defined(HURD) (void) sigaction(SIGBUS, &old_bus_act, 0); # endif # else @@ -753,7 +760,7 @@ ptr_t GC_get_stack_base() #endif /* FREEBSD_STACKBOTTOM */ #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \ - && !defined(MSWINCE) && !defined(OS2) + && !defined(MSWINCE) && !defined(OS2) && !defined(ECOS) ptr_t GC_get_stack_base() { @@ -1808,7 +1815,8 @@ struct hblk *h; #if defined(SUNOS4) || defined(FREEBSD) typedef void (* SIG_PF)(); #endif -#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) || defined(MACOSX) +#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \ + || defined(MACOSX) || defined(HURD) # ifdef __STDC__ typedef void (* SIG_PF)(int); # else @@ -1826,7 +1834,7 @@ struct hblk *h; # define SIG_DFL (SIG_PF) (-1) #endif -#if defined(IRIX5) || defined(OSF1) +#if defined(IRIX5) || defined(OSF1) || defined(HURD) typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *); #endif #if defined(SUNOS5SIGS) @@ -2013,7 +2021,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ #ifdef GC_TEST_AND_SET_DEFINED static VOLATILE unsigned int fault_handler_lock = 0; void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) { - while (GC_test_and_set(&fault_handler_lock)); + while (GC_test_and_set(&fault_handler_lock)) {} /* Could also revert to set_pht_entry_from_index_safe if initial */ /* GC_test_and_set fails. */ set_pht_entry_from_index(db, index); @@ -2067,16 +2075,21 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # define CODE_OK (code == BUS_PAGE_FAULT) # endif # endif -# if defined(IRIX5) || defined(OSF1) +# if defined(IRIX5) || defined(OSF1) || defined(HURD) # include <errno.h> void GC_write_fault_handler(int sig, int code, struct sigcontext *scp) -# define SIG_OK (sig == SIGSEGV) # ifdef OSF1 +# define SIG_OK (sig == SIGSEGV) # define CODE_OK (code == 2 /* experimentally determined */) # endif # ifdef IRIX5 +# define SIG_OK (sig == SIGSEGV) # define CODE_OK (code == EACCES) # endif +# ifdef HURD +# define SIG_OK (sig == SIGBUS || sig == SIGSEGV) +# define CODE_OK TRUE +# endif # endif # if defined(LINUX) # if defined(ALPHA) || defined(M68K) @@ -2131,6 +2144,9 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif { register unsigned i; +# if defined(HURD) + char *addr = (char *) code; +# endif # ifdef IRIX5 char * addr = (char *) (size_t) (scp -> sc_badvaddr); # endif @@ -2254,7 +2270,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif return; # endif -# if defined (IRIX5) || defined(OSF1) +# if defined (IRIX5) || defined(OSF1) || defined(HURD) (*(REAL_SIG_PF)old_handler) (sig, code, scp); return; # endif @@ -2266,13 +2282,24 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif } } + UNPROTECT(h, GC_page_size); + /* We need to make sure that no collection occurs between */ + /* the UNPROTECT and the setting of the dirty bit. Otherwise */ + /* a write by a third thread might go unnoticed. Reversing */ + /* the order is just as bad, since we would end up unprotecting */ + /* a page in a GC cycle during which it's not marked. */ + /* Currently we do this by disabling the thread stopping */ + /* signals while this handler is running. An alternative might */ + /* be to record the fact that we're about to unprotect, or */ + /* have just unprotected a page in the GC's thread structure, */ + /* and then to have the thread stopping code set the dirty */ + /* flag, if necessary. */ for (i = 0; i < divHBLKSZ(GC_page_size); i++) { register int index = PHT_HASH(h+i); async_set_pht_entry_from_index(GC_dirty_pages, index); } - UNPROTECT(h, GC_page_size); -# if defined(OSF1) || defined(LINUX) +# if defined(OSF1) /* These reset the signal handler each time by default. */ signal(SIGSEGV, (SIG_PF) GC_write_fault_handler); # endif @@ -2321,16 +2348,25 @@ struct hblk *h; void GC_dirty_init() { -# if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */ +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \ + defined(OSF1) || defined(HURD) struct sigaction act, oldact; -# ifdef IRIX5 + /* We should probably specify SA_SIGINFO for Linux, and handle */ + /* the different architectures more uniformly. */ +# if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD) act.sa_flags = SA_RESTART; - act.sa_handler = GC_write_fault_handler; + act.sa_handler = (SIG_PF)GC_write_fault_handler; # else act.sa_flags = SA_RESTART | SA_SIGINFO; act.sa_sigaction = GC_write_fault_handler; # endif (void)sigemptyset(&act.sa_mask); +# ifdef SIG_SUSPEND + /* Arrange to postpone SIG_SUSPEND while we're in a write fault */ + /* handler. This effectively makes the handler atomic w.r.t. */ + /* stopping the world for GC. */ + (void)sigaddset(&act.sa_mask, SIG_SUSPEND); +# endif /* SIG_SUSPEND */ # endif # if defined(MACOSX) struct sigaction act, oldact; @@ -2359,7 +2395,7 @@ void GC_dirty_init() # endif } # endif -# if defined(OSF1) || defined(SUNOS4) || defined(LINUX) +# if defined(SUNOS4) GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler); if (GC_old_segv_handler == SIG_IGN) { GC_err_printf0("Previously ignored segmentation violation!?"); @@ -2371,18 +2407,20 @@ void GC_dirty_init() # endif } # endif -# if defined(SUNOS5SIGS) || defined(IRIX5) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) \ + || defined(OSF1) || defined(HURD) + /* SUNOS5SIGS includes HPUX */ # if defined(IRIX_THREADS) sigaction(SIGSEGV, 0, &oldact); sigaction(SIGSEGV, &act, 0); # else sigaction(SIGSEGV, &act, &oldact); # endif -# if defined(_sigargs) +# if defined(_sigargs) || defined(HURD) /* This is Irix 5.x, not 6.x. Irix 5.x does not have */ /* sa_sigaction. */ GC_old_segv_handler = oldact.sa_handler; -# else /* Irix 6.x or SUNOS5SIGS */ +# else /* Irix 6.x or SUNOS5SIGS or LINUX */ if (oldact.sa_flags & SA_SIGINFO) { GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction); } else { @@ -2399,7 +2437,7 @@ void GC_dirty_init() # endif } # endif -# if defined(MACOSX) || defined(HPUX) +# if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD) sigaction(SIGBUS, &act, &oldact); GC_old_bus_handler = oldact.sa_handler; if (GC_old_bus_handler == SIG_IGN) { @@ -2411,7 +2449,7 @@ void GC_dirty_init() GC_err_printf0("Replaced other SIGBUS handler\n"); # endif } -# endif /* MACOS || HPUX */ +# endif /* MACOS || HPUX || LINUX */ # if defined(MSWIN32) GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler); if (GC_old_segv_handler != NULL) { @@ -2548,10 +2586,14 @@ word len; result = readv(fd, &iov, 1); } # else +# if defined(HURD) + result = __read(fd, buf, nbyte); +# else /* The two zero args at the end of this list are because one IA-64 syscall() implementation actually requires six args to be passed, even though they aren't always used. */ result = syscall(SYS_read, fd, buf, nbyte, 0, 0); +# endif /* !HURD */ # endif GC_end_syscall(); return(result); @@ -3005,9 +3047,11 @@ struct callinfo info[NFRAMES]; register int i; info[nframes].ci_pc = fp->FR_SAVPC; - for (i = 0; i < NARGS; i++) { - info[nframes].ci_arg[i] = ~(fp->fr_arg[i]); - } +# if NARGS > 0 + for (i = 0; i < NARGS; i++) { + info[nframes].ci_arg[i] = ~(fp->fr_arg[i]); + } +# endif /* NARGS > 0 */ } if (nframes < NFRAMES) info[nframes].ci_pc = 0; } diff --git a/boehm-gc/powerpc_macosx_mach_dep.s b/boehm-gc/powerpc_macosx_mach_dep.s index fad41d1c661..92f06286e73 100644 --- a/boehm-gc/powerpc_macosx_mach_dep.s +++ b/boehm-gc/powerpc_macosx_mach_dep.s @@ -1,4 +1,5 @@ - .text + +.text .set linkageArea,24 .set params,4 @@ -15,52 +16,80 @@ _GC_push_regs: stw r0,8(r1) ; save return address stwu r1,-spaceToSave(r1) ; skip over caller save area ; - mr r3,r2 ; mark from r2. Well I'm not really sure + mr r3,r2 ; mark from r2. Well Im not really sure ; that this is necessary or even the right - ; thing to do - at least it doesn't harm... - ; According to Apple's docs it points to + ; thing to do - at least it doesnt harm... + ; According to Apples docs it points to ; the direct data area, whatever that is... - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r13 ; mark from r13-r31 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r14 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r15 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r16 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r17 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r18 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r19 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r20 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r21 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r22 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r23 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r24 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r25 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r26 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r27 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r28 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r29 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r30 - bl _GC_push_one + bl L_GC_push_one$stub mr r3,r31 - bl _GC_push_one + bl L_GC_push_one$stub ; EPILOG lwz r0,spaceToSave8(r1) ; get return address back mtlr r0 ; reset link register addic r1,r1,spaceToSave ; restore stack pointer blr + +.data +.picsymbol_stub +L_GC_push_one$stub: + .indirect_symbol _GC_push_one + mflr r0 + bcl 20,31,L0$_GC_push_one +L0$_GC_push_one: + mflr r11 + addis r11,r11,ha16(L_GC_push_one$lazy_ptr-L0$_GC_push_one) + mtlr r0 + lwz r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11) + mtctr r12 + addi r11,r11,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one) + bctr +.data +.lazy_symbol_pointer +L_GC_push_one$lazy_ptr: + .indirect_symbol _GC_push_one + .long dyld_stub_binding_helper +.non_lazy_symbol_pointer +L_GC_push_one$non_lazy_ptr: + .indirect_symbol _GC_push_one + .long 0 + + + + diff --git a/boehm-gc/reclaim.c b/boehm-gc/reclaim.c index f8f057d6171..78995f3985f 100644 --- a/boehm-gc/reclaim.c +++ b/boehm-gc/reclaim.c @@ -20,7 +20,7 @@ signed_word GC_mem_found = 0; /* Number of words of memory reclaimed */ -#ifdef PARALLEL_MARK +#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) word GC_fl_builder_count = 0; /* Number of threads currently building free lists without */ /* holding GC lock. It is not safe to collect if this is */ @@ -866,6 +866,9 @@ int report_if_found; /* Abort if a GC_reclaimable object is found */ { int kind; +# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) + GC_ASSERT(0 == GC_fl_builder_count); +# endif /* Clear reclaim- and free-lists */ for (kind = 0; kind < GC_n_kinds; kind++) { register ptr_t *fop; @@ -902,6 +905,9 @@ int report_if_found; /* Abort if a GC_reclaimable object is found */ /* so that you can convince yourself that it really is very stupid. */ GC_reclaim_all((GC_stop_func)0, FALSE); # endif +# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC) + GC_ASSERT(0 == GC_fl_builder_count); +# endif } diff --git a/boehm-gc/tests/test.c b/boehm-gc/tests/test.c index c7b537cba6c..1bd98d64e0f 100644 --- a/boehm-gc/tests/test.c +++ b/boehm-gc/tests/test.c @@ -14,6 +14,9 @@ */ /* An incomplete test for the garbage collector. */ /* Some more obscure entry points are not tested at all. */ +/* This must be compiled with the same flags used to build the */ +/* GC. It uses GC internals to allow more precise results */ +/* checking for some of the tests. */ # undef GC_BUILD @@ -238,8 +241,8 @@ sexpr y; #ifdef GC_GCJ_SUPPORT -#include "private/dbg_mlc.h" -#include "private/gc_pmark.h" +#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. */ @@ -267,16 +270,12 @@ struct GC_ms_entry * fake_gcj_mark_proc(word * addr, addr = (word *)USR_PTR_FROM_BASE(addr); } x = (sexpr)(addr + 1); /* Skip the vtable pointer. */ - /* We could just call PUSH_CONTENTS directly here. But any real */ - /* real client would try to filter out the obvious misses. */ - if (0 != x -> sexpr_cdr) { - PUSH_CONTENTS((ptr_t)(x -> sexpr_cdr), mark_stack_ptr, - mark_stack_limit, &(x -> sexpr_cdr), exit1); - } - if ((ptr_t)(x -> sexpr_car) > (ptr_t) GC_least_plausible_heap_addr) { - PUSH_CONTENTS((ptr_t)(x -> sexpr_car), mark_stack_ptr, - mark_stack_limit, &(x -> sexpr_car), exit2); - } + mark_stack_ptr = GC_MARK_AND_PUSH( + (GC_PTR)(x -> sexpr_cdr), mark_stack_ptr, + mark_stack_limit, (GC_PTR *)&(x -> sexpr_cdr)); + mark_stack_ptr = GC_MARK_AND_PUSH( + (GC_PTR)(x -> sexpr_car), mark_stack_ptr, + mark_stack_limit, (GC_PTR *)&(x -> sexpr_car)); return(mark_stack_ptr); } @@ -703,6 +702,13 @@ int n; # endif collectable_count++; +# ifdef THREAD_LOCAL_ALLOC + /* Minimally exercise thread local allocation */ + { + char * result = (char *)GC_LOCAL_MALLOC_ATOMIC(17); + memset(result, 'a', 17); + } +# endif /* THREAD_LOCAL_ALLOC */ # if defined(MACOS) /* get around static data limitations. */ if (!live_indicators) diff --git a/boehm-gc/version.h b/boehm-gc/version.h index b265b9760f5..7efee18fd67 100644 --- a/boehm-gc/version.h +++ b/boehm-gc/version.h @@ -1,6 +1,6 @@ #define GC_VERSION_MAJOR 6 #define GC_VERSION_MINOR 0 -#define GC_ALPHA_VERSION 7 +#define GC_ALPHA_VERSION GC_NOT_ALPHA # define GC_NOT_ALPHA 0xff |