diff options
author | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-11-01 23:15:51 +0000 |
---|---|---|
committer | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-11-01 23:15:51 +0000 |
commit | 9bc8642e1f366a35c305b9abe9e01bf934b584b9 (patch) | |
tree | 9c24ba1ebabff472b9caddbff07ef957dbf2c24c /boehm-gc | |
parent | 79eaf784f16b0e8079d9dca062a0fc959d289d18 (diff) | |
download | ppe42-gcc-9bc8642e1f366a35c305b9abe9e01bf934b584b9.tar.gz ppe42-gcc-9bc8642e1f366a35c305b9abe9e01bf934b584b9.zip |
Merged GC 5.0alpha4 with local changes, plus:
* Makefile.in: Rebuilt.
* Makefile.am (gctest_LDADD): Added THREADLIB.
(TESTS): New macro.
* configure: Rebuilt.
* configure.in (INCLUDES): New subst.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@30332 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'boehm-gc')
60 files changed, 3741 insertions, 1927 deletions
diff --git a/boehm-gc/BCC_MAKEFILE b/boehm-gc/BCC_MAKEFILE index c65a73e2eb8..225a1ed4998 100644 --- a/boehm-gc/BCC_MAKEFILE +++ b/boehm-gc/BCC_MAKEFILE @@ -39,7 +39,7 @@ OBJS= $(XXXOBJS:XXX=) all: gctest.exe cord\de.exe test_cpp.exe
-$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h config.h MAKEFILE
+$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h gcconfig.h MAKEFILE
gc.lib: $(OBJS)
-del gc.lib
diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog index fcb5d49c7fc..b4e4175176c 100644 --- a/boehm-gc/ChangeLog +++ b/boehm-gc/ChangeLog @@ -1,3 +1,11 @@ +1999-11-01 Tom Tromey <tromey@cygnus.com> + + * Makefile.in: Rebuilt. + * Makefile.am (gctest_LDADD): Added THREADLIB. + (TESTS): New macro. + * configure: Rebuilt. + * configure.in (INCLUDES): New subst. + 1999-09-29 Steve Chamberlain <sac@pobox.com> * config.h: Added picoJava target. diff --git a/boehm-gc/EMX_MAKEFILE b/boehm-gc/EMX_MAKEFILE index 1ade12adc5c..54a06ce3881 100644 --- a/boehm-gc/EMX_MAKEFILE +++ b/boehm-gc/EMX_MAKEFILE @@ -72,7 +72,7 @@ SPECIALCFLAGS = all: gc.a gctest.exe $(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \ - $(srcdir)/config.h $(srcdir)/gc_typed.h + $(srcdir)/gcconfig.h $(srcdir)/gc_typed.h # The dependency on Makefile is needed. Changing # options such as -DSILENT affects the size of GC_arrays, # invalidating all .o files that rely on gc_priv.h diff --git a/boehm-gc/MacOS.c b/boehm-gc/MacOS.c index 420ea500e3e..cc12cd15d98 100644 --- a/boehm-gc/MacOS.c +++ b/boehm-gc/MacOS.c @@ -135,3 +135,20 @@ void GC_MacFreeTemporaryMemory() # endif } } + +#if __option(far_data) + + void* GC_MacGetDataEnd() + { + CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0); + if (code0) { + long aboveA5Size = (**code0).aboveA5; + ReleaseResource((Handle)code0); + return (LMGetCurrentA5() + aboveA5Size); + } + fprintf(stderr, "Couldn't load the jump table."); + exit(-1); + return 0; + } + +#endif /* __option(far_data) */ diff --git a/boehm-gc/Makefile.am b/boehm-gc/Makefile.am index 9cf838b3a71..6ab97ff2612 100644 --- a/boehm-gc/Makefile.am +++ b/boehm-gc/Makefile.am @@ -46,8 +46,9 @@ AM_CFLAGS = @BOEHM_GC_CFLAGS@ check_PROGRAMS = gctest gctest_SOURCES = test.c -gctest_LDADD = ./libgcjgc.la +gctest_LDADD = ./libgcjgc.la $(THREADLIB) +TESTS = gctest ## FIXME: relies on internal code generated by automake. all_objs = @addobjs@ $(libgcjgc_la_OBJECTS) diff --git a/boehm-gc/Makefile.dj b/boehm-gc/Makefile.dj index 979ac6f33e7..54f77db9f66 100644 --- a/boehm-gc/Makefile.dj +++ b/boehm-gc/Makefile.dj @@ -7,15 +7,23 @@ # and runs some tests of collector and cords. Does not add cords or # c++ interface to gc.a # cord/de$(EXE_SUFFIX) - builds dumb editor based on cords. -CC=gcc -CXX=gcc -x c++ -CXXLD=gxx -RM=rm -f -MV=mv +ABI_FLAG= +CC=gcc $(ABI_FLAG) +CXX=gxx $(ABI_FLAG) +AS=gcc -c -x assembler-with-cpp $(ABI_FLAG) +# The above doesn't work with gas, which doesn't run cpp. +# Define AS as `gcc -c -x assembler-with-cpp' instead. +# Under Irix 6, you will have to specify the ABI (-o32, -n32, or -64) +# if you use something other than the default ABI on your machine. + +# special defines for DJGPP +CXXLD=gxx $(ABI_FLAG) EXE_SUFFIX=.exe -RANLIB=ranlib -CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DATOMIC_UNCOLLECTABLE +CFLAGS= -O -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION -DSILENT + +# For dynamic library builds, it may be necessary to add flags to generate +# PIC code, e.g. -fPIC on Linux. # Setjmp_test may yield overly optimistic results when compiled # without optimization. @@ -29,8 +37,12 @@ CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DATOMIC_UNCOLLECTABLE # -DSOLARIS_THREADS enables support for Solaris (thr_) threads. # (Clients should also define SOLARIS_THREADS and then include # gc.h before performing thr_ or dl* or GC_ operations.) -# This is broken on nonSPARC machines. +# Must also define -D_REENTRANT. +# -D_SOLARIS_PTHREADS enables support for Solaris pthreads. +# Define SOLARIS_THREADS as well. # -DIRIX_THREADS enables support for Irix pthreads. See README.irix. +# -DLINUX_THREADS enables support for Xavier Leroy's Linux threads. +# see README.linux. -D_REENTRANT may also be required. # -DALL_INTERIOR_POINTERS allows all pointers to the interior # of objects to be recognized. (See gc_priv.h for consequences.) # -DSMALL_CONFIG tries to tune the collector for small heap sizes, @@ -78,9 +90,34 @@ CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DATOMIC_UNCOLLECTABLE # in a sepearte postpass, and hence their memory won't be reclaimed. # Not recommended unless you are implementing a language that specifies # these semantics. +# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response +# to explicit GC_invoke_finalizers() calls. # -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable. # This is useful if either the vendor malloc implementation is poor, # or if REDIRECT_MALLOC is used. +# -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly +# sets the heap block size. Each heap block is devoted to a single size and +# kind of object. For the incremental collector it makes sense to match +# the most likely page size. Otherwise large values result in more +# fragmentation, but generally better performance for large heaps. +# -DUSE_MMAP use MMAP instead of sbrk to get new memory. +# Works for Solaris and Irix. +# -DMMAP_STACKS (for Solaris threads) Use mmap from /dev/zero rather than +# GC_scratch_alloc() to get stack memory. +# -DPRINT_BLACK_LIST Whenever a black list entry is added, i.e. whenever +# the garbage collector detects a value that looks almost, but not quite, +# like a pointer, print both the address containing the value, and the +# value of the near-bogus-pointer. Can be used to identifiy regions of +# memory that are likely to contribute misidentified pointers. +# -DOLD_BLOCK_ALLOC Use the old, possibly faster, large block +# allocation strategy. The new strategy tries harder to minimize +# fragmentation, sometimes at the expense of spending more time in the +# large block allocator and/or collecting more frequently. +# If you expect the allocator to promtly use an explicitly expanded +# heap, this is highly recommended. +# + + LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \ -DREDIRECT_MALLOC=GC_malloc_uncollectable \ @@ -98,9 +135,9 @@ RANLIB= ranlib srcdir = . VPATH = $(srcdir) -OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o typd_mlc.o ptr_chck.o mallocx.o +OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o linux_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o -CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c typd_mlc.c ptr_chck.c mallocx.c +CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c linux_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c cord/cord.h cord/ec.h cord/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga @@ -108,16 +145,17 @@ CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \ sparc_mach_dep.s gc.h gc_typed.h gc_hdrs.h gc_priv.h gc_private.h \ - config.h gc_mark.h include/gc_inl.h include/gc_inline.h gc.man \ + gcconfig.h gc_mark.h include/gc_inl.h include/gc_inline.h gc.man \ threadlibs.c if_mach.c if_not_there.c gc_cpp.cc gc_cpp.h weakpointer.h \ gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h gc_alloc.h \ - $(CORD_SRCS) + include/new_gc_alloc.h include/javaxfc.h sparc_sunos4_mach_dep.s \ + solaris_threads.h $(CORD_SRCS) OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \ README test.c test_cpp.cc setjmp_t.c SMakefile.amiga \ SCoptions.amiga README.amiga README.win32 cord/README \ cord/gc.h include/gc.h include/gc_typed.h include/cord.h \ - include/ec.h include/private/cord_pos.h include/private/config.h \ + include/ec.h include/private/cord_pos.h include/private/gcconfig.h \ include/private/gc_hdrs.h include/private/gc_priv.h \ include/gc_cpp.h README.rs6000 \ include/weakpointer.h README.QUICK callprocs pc_excludes \ @@ -126,12 +164,14 @@ OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \ include/gc_cpp.h Mac_files/datastart.c Mac_files/dataend.c \ Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \ add_gc_prefix.c README.solaris2 README.sgi README.hp README.uts \ - win32_threads.c NT_THREADS_MAKEFILE gc.mak README.dj Makefile.dj + win32_threads.c NT_THREADS_MAKEFILE gc.mak README.dj Makefile.dj \ + README.alpha README.linux version.h Makefile.DLLs \ + WCC_MAKEFILE CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \ $(srcdir)/cord/private/cord_pos.h -UTILS= if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) threadlibs$(EXE_SUFFIX) +UTILS= if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) # Libraries needed for curses applications. Only needed for de. CURSES= -lcurses -ltermlib @@ -149,12 +189,12 @@ SPECIALCFLAGS = all: gc.a gctest$(EXE_SUFFIX) -pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h config.h mach_dep.o $(SRCS) +pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h gcconfig.h mach_dep.o $(SRCS) make -f PCR-Makefile depend make -f PCR-Makefile $(OBJS) test.o dyn_load.o dyn_load_sunos53.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \ - $(srcdir)/config.h $(srcdir)/gc_typed.h Makefile + $(srcdir)/gcconfig.h $(srcdir)/gc_typed.h Makefile # The dependency on Makefile is needed. Changing # options such as -DSILENT affects the size of GC_arrays, # invalidating all .o files that rely on gc_priv.h @@ -163,128 +203,160 @@ mark.o typd_mlc.o finalize.o: $(srcdir)/gc_mark.h base_lib gc.a: $(OBJS) dyn_load.o $(UTILS) echo > base_lib - $(RM) on_sparc_sunos5 - ./if_mach SPARC SUNOS5 touch on_sparc_sunos5 + rm -f on_sparc_sunos5_1 + ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_1 ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o - ./if_not_there on_sparc_sunos5 $(AR) ru gc.a $(OBJS) dyn_load.o - -./if_not_there on_sparc_sunos5 $(RANLIB) gc.a + ./if_not_there on_sparc_sunos5_1 $(AR) ru gc.a $(OBJS) dyn_load.o + -./if_not_there on_sparc_sunos5_1 $(RANLIB) gc.a # ignore ranlib failure; that usually means it doesn't exist, and isn't needed -libgc.a: - make CFLAGS="$(LIBGC_CFLAGS)" clean gc.a gcc_support.o - $(MV) gc.a libgc.a - -$(RM) on_sparc_sunos5 - ./if_mach SPARC SUNOS5 touch on_sparc_sunos5 - ./if_mach SPARC SUNOS5 $(AR) rus libgc.a gcc_support.o - ./if_not_there on_sparc_sunos5 $(AR) ru libgc.a gcc_support.o - -./if_not_there on_sparc_sunos5 $(RANLIB) libgc.a - cords: $(CORD_OBJS) cord/cordtest$(EXE_SUFFIX) $(UTILS) - -$(RM) on_sparc_sunos5 - ./if_mach SPARC SUNOS5 touch on_sparc_sunos5 + rm -f on_sparc_sunos5_3 + ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_3 ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS) - ./if_not_there on_sparc_sunos5 $(AR) ru gc.a $(CORD_OBJS) - -./if_not_there on_sparc_sunos5 $(RANLIB) gc.a + ./if_not_there on_sparc_sunos5_3 $(AR) ru gc.a $(CORD_OBJS) + -./if_not_there on_sparc_sunos5_3 $(RANLIB) gc.a gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/gc_cpp.h $(srcdir)/gc.h Makefile $(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc -test_cpp: $(srcdir)/test_cpp.cc $(srcdir)/gc_cpp.h gc_cpp.o $(srcdir)/gc.h \ +test_cpp$(EXE_SUFFIX): $(srcdir)/test_cpp.cc $(srcdir)/gc_cpp.h gc_cpp.o $(srcdir)/gc.h \ base_lib $(UTILS) - -$(RM) test_cpp test_cpp$(EXE_SUFFIX) + rm -f test_cpp test_cpp$(EXE_SUFFIX) ./if_mach HP_PA "" $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a -ldld - ./if_not_there test_cpp$(EXE_SUFFIX) $(CXXLD) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a - $(RM) test_cpp - -c++: gc_cpp.o $(srcdir)/gc_cpp.h test_cpp - -$(RM) on_sparc_sunos5 - $(AR) ru gc.a gc_cpp.o - $(RANLIB) gc.a + ./if_not_there test_cpp$(EXE_SUFFIX) $(CXXLD) $(CXXFLAGS) -o test_cpp$(EXE_SUFFIX) $(srcdir)/test_cpp.cc gc_cpp.o gc.a + rm -f test_cpp + +c++: gc_cpp.o $(srcdir)/gc_cpp.h test_cpp$(EXE_SUFFIX) + rm -f on_sparc_sunos5_4 + ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_4 + ./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o + ./if_not_there on_sparc_sunos5_4 $(AR) ru gc.a gc_cpp.o + -./if_not_there on_sparc_sunos5_4 $(RANLIB) gc.a ./test_cpp$(EXE_SUFFIX) 1 echo > c++ dyn_load_sunos53.o: dyn_load.c $(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c $(srcdir)/dyn_load.c -o $@ -mach_dep.o: $(srcdir)/mach_dep.c - -$(RM) mach_dep.o - $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c - -mark_rts.o: $(srcdir)/mark_rts.c - -$(RM) mark_rts.o - $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c +# SunOS5 shared library version of the collector +sunos5gc.so: $(OBJS) dyn_load_sunos53.o + $(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o -ldl + ln sunos5gc.so libgc.so + +# Alpha/OSF shared library version of the collector +libalphagc.so: $(OBJS) + ld -shared -o libalphagc.so $(OBJS) dyn_load.o -lc + ln libalphagc.so libgc.so + +# IRIX shared library version of the collector +libirixgc.so: $(OBJS) dyn_load.o + ld -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc + ln libirixgc.so libgc.so + +# Linux shared library version of the collector +liblinuxgc.so: $(OBJS) dyn_load.o + gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo + ln liblinuxgc.so libgc.so + +mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s $(srcdir)/rs6000_mach_dep.s $(UTILS) + rm -f mach_dep.o + ./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s + ./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s + ./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s + ./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s + ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s + ./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.s + ./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s + ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c + +mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there $(UTILS) + rm -f mark_rts.o + -./if_mach ALPHA OSF1 $(CC) -c $(CFLAGS) -Wo,-notail $(srcdir)/mark_rts.c + ./if_not_there mark_rts.o $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c +# Work-around for DEC optimizer tail recursion elimination bug. +# The ALPHA-specific line should be removed if gcc is used. + +alloc.o: version.h cord/cordbscs.o: $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES) - $(CC) $(CFLAGS) -c $(srcdir)/cord/cordbscs.c - $(MV) cordbscs.o cord/cordbscs.o + $(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordbscs.c + mv cordbscs.o cord/cordbscs.o # not all compilers understand -o filename cord/cordxtra.o: $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES) - $(CC) $(CFLAGS) -c $(srcdir)/cord/cordxtra.c - $(MV) cordxtra.o cord/cordxtra.o + $(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordxtra.c + mv cordxtra.o cord/cordxtra.o cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES) - $(CC) $(CFLAGS) -c $(srcdir)/cord/cordprnt.c - $(MV) cordprnt.o cord/cordprnt.o - -cord/cordtest$(EXE_SUFFIX): $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS) - -$(RM) cord/cordtest$(EXE_SUFFIX) - $(CC) $(CFLAGS) -o cordtest $(srcdir)/cord/cordtest.c\ - $(CORD_OBJS) gc.a - ./if_not_there cord/cordtest$(EXE_SUFFIX) \ - $(MV) cordtest$(EXE_SUFFIX) cord/cordtest$(EXE_SUFFIX) - -cord/de$(EXE_SUFFIX): $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a - -$(RM) cord/de$(EXE_SUFFIX) - ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\ -cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb - ./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\ -cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld - ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\ -cord/cordbscs.o cord/cordxtra.o gc.a -lcurses - ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\ -cord/cordbscs.o cord/cordxtra.o gc.a -lcurses - ./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\ -cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) - ./if_not_there cord/de$(EXE_SUFFIX) \ - $(MV) de$(EXE_SUFFIX) cord/de$(EXE_SUFFIX) - -if_mach$(EXE_SUFFIX): $(srcdir)/if_mach.c $(srcdir)/config.h + $(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordprnt.c + mv cordprnt.o cord/cordprnt.o + +cord/cordtest$(EXE_SUFFIX): $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS) /tmp + rm -f cord/cordtest$(EXE_SUFFIX) + ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lucb + ./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -ldld + ./if_not_there cord/cordtest$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a + rm -f cord/cordtest cordtest + -mv cordtest$(EXE_SUFFIX) cord/ + +/tmp: $(UTILS) + ./if_not_there /tmp mkdir /tmp + +cord/de$(EXE_SUFFIX): $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS) + rm -f cord/de cord/de$(EXE_SUFFIX) + ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs` + ./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld + ./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses + ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs` + ./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses + ./if_not_there cord/de$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/de$(EXE_SUFFIX) $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) + +if_mach$(EXE_SUFFIX): $(srcdir)/if_mach.c $(srcdir)/gcconfig.h + rm -f if_mach if_mach$(EXE_SUFFIX) $(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c - -$(RM) if_mach + rm -f if_mach -threadlibs$(EXE_SUFFIX): $(srcdir)/threadlibs.c $(srcdir)/config.h Makefile +threadlibs$(EXE_SUFFIX): $(srcdir)/threadlibs.c $(srcdir)/gcconfig.h Makefile + rm -f threadlibs threadlibs$(EXE_SUFFIX) $(CC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c - -$(RM) threadlibs + rm -f threadlibs if_not_there$(EXE_SUFFIX): $(srcdir)/if_not_there.c + rm -f if_not_there if_not_there$(EXE_SUFFIX) $(CC) $(CFLAGS) -o if_not_there $(srcdir)/if_not_there.c - -$(RM) if_not_there - -clean: - -$(RM) gc.a *.o - -$(RM) *.o - -$(RM) gctest gctest_dyn_link test_cpp \ - setjmp_test mon.out gmon.out a.out core if_not_there if_mach \ - $(CORD_OBJS) cordtest cord/cordtest de cord/de - -$(RM) gctest$(EXE_SUFFIX) gctest_dyn_link$(EXE_SUFFIX) test_cpp$(EXE_SUFFIX) \ - setjmp_test$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) if_mach$(EXE_SUFFIX) \ - cord/cordtest$(EXE_SUFFIX) - -$(RM) *~ - -gctest$(EXE_SUFFIX): test.o gc.a - -$(RM) gctest$(EXE_SUFFIX) - $(CC) $(CFLAGS) -o gctest test.o gc.a - $(RM) gctest + rm -f if_not_there + +# Clean removes *.o several times, +# because as the first one doesn't seem to get them all! +clean: + rm -f gc.a *.o + rm -f *.o + rm -f *.o + rm -f cord/*.o + rm -f gctest gctest_dyn_link test_cpp + rm -f setjmp_test mon.out gmon.out a.out core if_not_there if_mach + rm -f threadlibs $(CORD_OBJS) cordtest cord/cordtest de cord/de + rm -f gctest$(EXE_SUFFIX) gctest_dyn_link$(EXE_SUFFIX) test_cpp$(EXE_SUFFIX) + rm -f setjmp_test$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) if_mach$(EXE_SUFFIX) + rm -f threadlibs$(EXE_SUFFIX) cord/cordtest$(EXE_SUFFIX) + -rm -f *~ + +gctest$(EXE_SUFFIX): test.o gc.a if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) + rm -f gctest gctest$(EXE_SUFFIX) + ./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o gctest test.o gc.a -lucb + ./if_mach HP_PA "" $(CC) $(CFLAGS) -o gctest test.o gc.a -ldld + ./if_not_there gctest$(EXE_SUFFIX) $(CC) $(CFLAGS) -o gctest$(EXE_SUFFIX) test.o gc.a + rm -f gctest # If an optimized setjmp_test generates a segmentation fault, # odds are your compiler is broken. Gctest may still work. # Try compiling setjmp_t.c unoptimized. setjmp_test$(EXE_SUFFIX): $(srcdir)/setjmp_t.c $(srcdir)/gc.h \ if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) - -$(RM) setjmp_test$(EXE_SUFFIX) + rm -f setjmp_test$(EXE_SUFFIX) $(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c - $(RM) setjmp_test + rm -f setjmp_test test: KandRtest cord/cordtest$(EXE_SUFFIX) ./cord/cordtest$(EXE_SUFFIX) @@ -294,3 +366,71 @@ KandRtest: setjmp_test$(EXE_SUFFIX) gctest$(EXE_SUFFIX) ./setjmp_test$(EXE_SUFFIX) ./gctest$(EXE_SUFFIX) +add_gc_prefix$(EXE_SUFFIX): add_gc_prefix.c + $(CC) -o add_gc_prefix$(EXE_SUFFIX) $(srcdir)/add_gc_prefix.c + rm -f add_gc_prefix + +gc.tar: $(SRCS) $(OTHER_FILES) add_gc_prefix + ./add_gc_prefix$(EXE_SUFFIX) $(SRCS) $(OTHER_FILES) > /tmp/gc.tar-files + (cd $(srcdir)/.. ; tar cvfh - `cat /tmp/gc.tar-files`) > gc.tar + +pc_gc.tar: $(SRCS) $(OTHER_FILES) + tar cvfX pc_gc.tar pc_excludes $(SRCS) $(OTHER_FILES) + +floppy: pc_gc.tar + -mmd a:/cord + -mmd a:/cord/private + -mmd a:/include + -mmd a:/include/private + mkdir /tmp/pc_gc + cat pc_gc.tar | (cd /tmp/pc_gc; tar xvf -) + -mcopy -tmn /tmp/pc_gc/* a: + -mcopy -tmn /tmp/pc_gc/cord/* a:/cord + -mcopy -mn /tmp/pc_gc/cord/de_win.ICO a:/cord + -mcopy -tmn /tmp/pc_gc/cord/private/* a:/cord/private + -mcopy -tmn /tmp/pc_gc/include/* a:/include + -mcopy -tmn /tmp/pc_gc/include/private/* a:/include/private + rm -r /tmp/pc_gc + +gc.tar.Z: gc.tar + compress gc.tar + +gc.tar.gz: gc.tar + gzip gc.tar + +lint: $(CSRCS) test.c + lint -DLINT $(CSRCS) test.c | egrep -v "possible pointer alignment problem|abort|exit|sbrk|mprotect|syscall" + +# BTL: added to test shared library version of collector. +# Currently works only under SunOS5. Requires GC_INIT call from statically +# loaded client code. +ABSDIR = `pwd` +gctest_dyn_link: test.o libgc.so + $(CC) -L$(ABSDIR) -R$(ABSDIR) -o gctest_dyn_link test.o -lgc -ldl -lthread + +gctest_irix_dyn_link: test.o libirixgc.so + $(CC) -L$(ABSDIR) -o gctest_irix_dyn_link test.o -lirixgc + +test_dll.o: test.c libgc_globals.h + $(CC) $(CFLAGS) -DGC_USE_DLL -c test.c -o test_dll.o + +test_dll: test_dll.o libgc_dll.a libgc.dll + $(CC) test_dll.o -L$(ABSDIR) -lgc_dll -o test_dll + +SYM_PREFIX-libgc=GC + +# Uncomment the following line to build a GNU win32 DLL +# include Makefile.DLLs + +reserved_namespace: $(SRCS) + for file in $(SRCS) test.c test_cpp.cc; do \ + sed s/GC_/_GC_/g < $$file > tmp; \ + cp tmp $$file; \ + done + +user_namespace: $(SRCS) + for file in $(SRCS) test.c test_cpp.cc; do \ + sed s/_GC_/GC_/g < $$file > tmp; \ + cp tmp $$file; \ + done + diff --git a/boehm-gc/Makefile.in b/boehm-gc/Makefile.in index 3efddbee8cb..3e5b4a6aee5 100644 --- a/boehm-gc/Makefile.in +++ b/boehm-gc/Makefile.in @@ -84,6 +84,7 @@ NM = @NM@ OBJDUMP = @OBJDUMP@ PACKAGE = @PACKAGE@ RANLIB = @RANLIB@ +THREADLIB = @THREADLIB@ VERSION = @VERSION@ addobjs = @addobjs@ boehm_gc_basedir = @boehm_gc_basedir@ @@ -131,7 +132,9 @@ AM_CFLAGS = @BOEHM_GC_CFLAGS@ check_PROGRAMS = gctest gctest_SOURCES = test.c -gctest_LDADD = ./libgcjgc.la +gctest_LDADD = ./libgcjgc.la $(THREADLIB) + +TESTS = gctest all_objs = @addobjs@ $(libgcjgc_la_OBJECTS) @@ -400,11 +403,37 @@ distdir: $(DISTFILES) || cp -p $$d/$$file $(distdir)/$$file || :; \ fi; \ done +check-TESTS: $(TESTS) + @failed=0; all=0; \ + srcdir=$(srcdir); export srcdir; \ + for tst in $(TESTS); do \ + if test -f $$tst; then dir=.; \ + else dir="$(srcdir)"; fi; \ + if $(TESTS_ENVIRONMENT) $$dir/$$tst; then \ + all=`expr $$all + 1`; \ + echo "PASS: $$tst"; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + failed=`expr $$failed + 1`; \ + echo "FAIL: $$tst"; \ + fi; \ + done; \ + if test "$$failed" -eq 0; then \ + banner="All $$all tests passed"; \ + else \ + banner="$$failed of $$all tests failed"; \ + fi; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes"; \ + test "$$failed" -eq 0 info-am: info: info-am dvi-am: dvi: dvi-am check-am: $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am installcheck-am: installcheck: installcheck-am @@ -477,11 +506,11 @@ maintainer-clean-compile mostlyclean-libtool distclean-libtool \ clean-libtool maintainer-clean-libtool mostlyclean-checkPROGRAMS \ distclean-checkPROGRAMS clean-checkPROGRAMS \ maintainer-clean-checkPROGRAMS tags mostlyclean-tags distclean-tags \ -clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ -check-am installcheck-am installcheck install-info-am install-info \ -install-exec-am install-exec install-data-am install-data install-am \ -install uninstall-am uninstall all-redirect all-am all installdirs \ -mostlyclean-generic distclean-generic clean-generic \ +clean-tags maintainer-clean-tags distdir check-TESTS info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-info-am \ +install-info install-exec-am install-exec install-data-am install-data \ +install-am install uninstall-am uninstall all-redirect all-am all \ +installdirs mostlyclean-generic distclean-generic clean-generic \ maintainer-clean-generic clean mostlyclean distclean maintainer-clean $(all_objs) : config.h gc_priv.h gc_hdrs.h gc.h gc_mark.h diff --git a/boehm-gc/PCR-Makefile b/boehm-gc/PCR-Makefile index 7b80637fb29..1eae3672556 100644 --- a/boehm-gc/PCR-Makefile +++ b/boehm-gc/PCR-Makefile @@ -59,7 +59,7 @@ mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there ./if_mach SPARC SUNOS5 as -o mach_dep.o sparc_mach_dep.s ./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c -if_mach: if_mach.c config.h +if_mach: if_mach.c gcconfig.h $(CC) $(CFLAGS) -o if_mach if_mach.c if_not_there: if_not_there.c diff --git a/boehm-gc/README b/boehm-gc/README index 98d8389dae9..4461e303102 100644 --- a/boehm-gc/README +++ b/boehm-gc/README @@ -1,6 +1,7 @@ Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. -Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved. +Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. +Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. [ This version of the collector modified by Cygnus Solutions. See the file ChangeLog for details ] @@ -14,18 +15,25 @@ 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 4.13alpha2 of a conservative garbage collector for C and C++. +This is version 5.0alpha4 of a conservative garbage collector for C and C++. You might find a more recent version of this at -http://reality.sgi.com/boehm/gc.html +http://www.hpl.hp.com/personal/Hans_Boehm/gc HISTORY - Early versions of this collector were developed as a part of research projects supported in part by the National Science Foundation and the Defense Advance Research Projects Agency. -Much of the code was rewritten by Hans-J. Boehm at Xerox PARC. +Much of the code was rewritten by Hans-J. Boehm (boehm@acm.org) at Xerox PARC +and at SGI. + +Some other contributors: + +More recent contributors are mentioned in the modification history at the +end of this file. My apologies for any omissions. + The SPARC specific code was contributed by Mark Weiser (weiser@parc.xerox.com). The Encore Multimax modifications were supplied by Kevin Kenny (kenny@m.cs.uiuc.edu). The adaptation to the RT is largely due @@ -36,8 +44,8 @@ Robert Brazile (brazile@diamond.bbn.com) originally supplied the ULTRIX code. Al Dosser (dosser@src.dec.com) and Regis Cridlig (Regis.Cridlig@cl.cam.ac.uk) subsequently provided updates and information on variation between ULTRIX systems. Parag Patel (parag@netcom.com) supplied the A/UX code. -Jesper Peterson(jep@mtiame.mtia.oz.au) and -Michel Schinz supplied the Amiga port. +Jesper Peterson(jep@mtiame.mtia.oz.au), Michel Schinz, and +Martin Tauchmann (martintauchmann@bigfoot.com) supplied the Amiga port. Thomas Funke (thf@zelator.in-berlin.de(?)) and Brian D.Carlstrom (bdc@clark.lcs.mit.edu) supplied the NeXT ports. Douglas Steel (doug@wg.icl.co.uk) provided ICL DRS6000 code. @@ -62,8 +70,7 @@ made it into the released version of the collector, yet.) (Blame for misinstallation of these modifications goes to the first author, however.) -Credits for some more recent modifications are given in the modification -history at the end of this file. +OVERVIEW This is intended to be a general purpose, garbage collecting storage allocator. The algorithms used are described in: @@ -92,7 +99,7 @@ of the ACM SIGPLAN '96 Conference on Programming Language Design and Implementation. (Both are also available from -http://reality.sgi.com/employees/boehm_mti/papers/, among other places.) +http://reality.sgi.com/boehm/papers/, among other places.) Unlike the collector described in the second reference, this collector operates either with the mutator stopped during the entire collection @@ -259,7 +266,7 @@ or win16 is hard. For machines not already mentioned, or for nonstandard compilers, the following are likely to require change: -1. The parameters in config.h. +1. The parameters in gcconfig.h. The parameters that will usually require adjustment are STACKBOTTOM, ALIGNMENT and DATASTART. Setjmp_test prints its guesses of the first two. @@ -276,7 +283,7 @@ following are likely to require change: On some machines, it is difficult to obtain such a value that is valid across a variety of MMUs, OS releases, etc. A number of alternatives exist for using the collector in spite of this. See the - discussion in config.h immediately preceding the various + discussion in gcconfig.h immediately preceding the various definitions of STACKBOTTOM. 2. mach_dep.c. @@ -313,7 +320,7 @@ following are likely to require change: in gc_priv.h will need to be suitably redefined. The incremental collector requires page dirty information, which is acquired through routines defined in os_dep.c. Unless directed - otherwise by config.h, these are implemented as stubs that simply + otherwise by gcconfig.h, these are implemented as stubs that simply treat all pages as dirty. (This of course makes the incremental collector much less useful.) @@ -325,7 +332,7 @@ following are likely to require change: For a different version of UN*X or different machines using the Motorola 68000, Vax, SPARC, 80386, NS 32000, PC/RT, or MIPS architecture, -it should frequently suffice to change definitions in config.h. +it should frequently suffice to change definitions in gcconfig.h. THE C INTERFACE TO THE ALLOCATOR @@ -609,7 +616,7 @@ reclaimed. Exclusive-or'ing forward and backward links in a list doesn't cut it. Some C optimizers may lose the last undisguised pointer to a memory object as a consequence of clever optimizations. This has almost -never been observed in practice. Send mail to boehm@mti.sgi.com +never been observed in practice. Send mail to boehm@acm.org for suggestions on how to fix your compiler. This is not a real-time collector. In the standard configuration, percentage of time required for collection should be constant across @@ -618,7 +625,7 @@ heap sizes. But collection pauses will increase for larger heaps. per MB of accessible memory that needs to be scanned. Your mileage may vary.) The incremental/generational collection facility helps, but is portable only if "stubborn" allocation is used. - Please address bug reports to boehm@mti.sgi.com. If you are + Please address bug reports to boehm@acm.org. If you are contemplating a major addition, you might also send mail to ask whether it's already been done (or whether we tried and discarded it). @@ -1371,9 +1378,156 @@ Since alpha1: - USE_MMAP had some serious bugs. This caused the collector to fail consistently on Solaris with -DSMALL_CONFIG. - Added Linux threads support, thanks largely to Fergus Henderson. +Since alpha2: + - Fixed more Linux threads problems. + - Changed default GC_free_space_divisor to 3 with new large block allocation. + (Thanks to Matthew Flatt for some measurements that suggest the old + value sometimes favors space too much over time.) + - More CYGWIN32 fixes. + - Integrated Tyson-Dowd's Linux-M68K port. + - Minor HP PA and DEC UNIX fixes from Fergus Henderson. + - Integrated Christoffe Raffali's Linux-SPARC changes. + - Allowed for one more GC fixup iteration after a full GC in incremental + mode. Some quick measurements suggested that this significantly + reduces pause times even with smaller GC_RATE values. + - Moved some more GC data structures into GC_arrays. This decreases + pause times and GC overhead, but makes debugging slightly less convenient. + - Fixed namespace pollution problem ("excl_table"). + - Made GC_incremental a constant for -DSMALL_CONFIG, hopefully shrinking + that slightly. + - Added some win32 threads fixes. + - Integrated Ivan Demakov and David Stes' Watcom fixes. + - Various other minor fixes contributed by many people. + - Renamed config.h to gcconfig.h, since config.h tends to be used for + many other things. + - Integrated Matthew Flatt's support for 68K MacOS "far globals". + - Fixed up some of the dynamic library Makefile targets for consistency + across platforms. + - Fixed a USE_MMAP typo that caused out-of-memory handling to fail + on Solaris. + - Added code to test.c to test thread creation a bit more. + - Integrated GC_win32_free_heap, as suggested by Ivan Demakov. + - Fixed Solaris 2.7 stack base finding problem. (This may actually + have been done in an earlier alpha release.) +Since alpha3: + - Fixed MSWIN32 recognition test, which interfered with cygwin. + - Removed unnecessary gc_watcom.asm from distribution. Removed + some obsolete README.win32 text. + - Added Alpha Linux incremental GC support. (Thanks to Philipp Tomsich + for code for retrieving the fault address in a signal handler.) + Changed Linux signal handler context argument to be a pointer. + - Took care of some new warnings generated by the 7.3 SGI compiler. + - Integrated Phillip Musumeci's FreeBSD/ELF fixes. + - -DIRIX_THREADS was broken with the -o32 ABI (typo in gc_priv.h> + +Since 4.13: + - Fixed GC_print_source_ptr to not use a prototype. + - generalized CYGWIN test. + - gc::new did the wrong thing with PointerFreeGC placement. + (Thanks to Rauli Ruohonen.) + - In the ALL_INTERIOR_POINTERS (default) case, some callee-save register + values could fail to be scanned if the register was saved and + reused in a GC frame. This showed up in verbose mode with gctest + compiled with an unreleased SGI compiler. I vaguely recall an old + bug report that may have been related. The bug was probably quite old. + (The problem was that the stack scanning could be deferred until + after the relevant frame was overwritten, and the new save location + might be outside the scanned area. Fixed by more eager stack scanning.) + - PRINT_BLACK_LIST had some problems. A few source addresses were garbage. + - Replaced Makefile.dj and added -I flags to cord make targets. + (Thanks to Gary Leavens.) + - GC_try_to_collect was broken with the nonincremental collector. + - gc_cleanup destructors could pass the wrong address to + GC_register_finalizer_ignore_self in the presence of multiple + inheritance. (Thanks to Darrell Schiebel.) + - Changed PowerPC Linux stack finding code. + +Since 4.14alpha1 + - -DSMALL_CONFIG did not work reliably with large (> 4K) pages. + Recycling the mark stack during expansion could result in a size + zero heap segment, which confused things. (This was probably also an + issue with the normal config and huge pages.) + - Did more work to make sure that callee-save registers were scanned + completely, even with the setjmp-based code. Added USE_GENERIC_PUSH_REGS + macro to facilitate testing on machines I have access to. + - Added code to explicitly push register contents for win32 threads. + This seems to be necessary. (Thanks to Pierre de Rop.) + +Since 4.14alpha2 + - changed STACKBOTTOM for DJGPP (Thanks to Salvador Eduardo Tropea). + +Since 4.14 + - Reworked large block allocator. Now uses multiple doubly linked free + lists to approximate best fit. + - Changed heap expansion heuristic. Entirely free blocks are no longer + counted towards the heap size. This seems to have a major impact on + heap size stability; the old version could expand the heap way too + much in the presence of large block fragmentation. + - added -DGC_ASSERTIONS and some simple assertions inside the collector. + This is mainlyt for collector debugging. + - added -DUSE_MUNMAP to allow the heap to shrink. Suupported on only + a few UNIX-like platforms for now. + - added GC_dump_regions() for debugging of fragmentation issues. + - Changed PowerPC pointer alignment under Linux to 4. (This needs + checking by someone who has one. The suggestions came to me via a + rather circuitous path.) + - Changed the Linux/Alpha port to walk the data segment backwards until + it encounters a SIGSEGV. The old way to find the start of the data + segment broke with a recent release. + - cordxtra.c needed to call GC_REGISTER_FINALIZER instead of + GC_register_finalizer, so that it would continue to work with GC_DEBUG. + - allochblk sometimes cleared the wrong block for debugging purposes + when it dropped blacklisted blocks. This could result in spurious + error reports with GC_DEBUG. + - added MACOS X Server support. (Thanks to Andrew Stone.) + - Changed the Solaris threads code to ignore stack limits > 8 MB with + a warning. Empirically, it is not safe to access arbitrary pages + in such large stacks. And the dirty bit implementation does not + guarantee that none of them will be accessed. + - Integrated Martin Tauchmann's Amiga changes. + - Integrated James Dominy's OpenBSD/SPARC port. + +Since 5.0alpha1 + - Fixed bugs introduced in alpha1 (OpenBSD & large block initialization). + - Added -DKEEP_BACK_PTRS and backptr.h interface. (The implementation + idea came from Al Demers.) + +Since 5.0alpha2 + - Added some highly incomplete code to support a copied young generation. + Comments on nursery.h are appreciated. + - Changed -DFIND_LEAK, -DJAVA_FINALIZATION, and -DFINALIZE_ON_DEMAND, + so the same effect could be obtained with a runtime switch. This is + a step towards standardizing on a single dynamic GC library. + - Significantly changed the way leak detection is handled, as a consequence + of the above. + +Since 5.0 alpha3 + - Added protection fault handling patch for Linux/M68K from Fergus + Henderson and Roman Hodek. + - Removed the tests for SGI_SOURCE in new_gc_alloc.h. This was causing that + interface to fail on nonSGI platforms. + - Changed the Linux stack finding code to use /proc, after chnging it + to use HEURISTIC1. (Thanks to David Mossberger for pointing out the + /proc hook.) + - Added HP/UX incremental GC support and HP/UX 11 thread support. + - Added basic Linux/IA64 support. + - Integrated Anthony Green's PicoJava support. + - Integrated Scott Ananian's StrongARM/NetBSD support. + - Fixed some fairly serious performance bugs in the incremental + collector. These have probably been there essentially forever. + (Mark bits were sometimes set before scanning dirty pages. + The reclaim phase unnecessarily dirtied full small object pages.) + - Changed the reclaim phase to ignore nearly full pages to avoid + touching them. + - Limited GC_black_list_spacing to roughly the heap growth increment. + - Changed full collection triggering heuristic to decrease full GC + frequency by default, but to explicitly trigger full GCs during + heap growth. This doesn't always improve things, but on average it's + probably a win. + - GC_debug_free(0, ...) failed. Thanks to Fergus Henderson for the + bug report and fix. To do: - - I have a backlog of unintegrated contributed platform-specific changes. - 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 @@ -1386,4 +1540,6 @@ To do: be possible to conditionally intercept mmap and use GC_exclude_static_roots. The real fix is to walk rld data structures, which looks possible. - Integrate MIT and DEC pthreads ports. - + - Incremental collector should handle large objects better. Currently, + it looks like the whole object is treated as dirty if any part of it + is. diff --git a/boehm-gc/README.Mac b/boehm-gc/README.Mac index 6d2fa74358d..04f468251a1 100644 --- a/boehm-gc/README.Mac +++ b/boehm-gc/README.Mac @@ -320,7 +320,7 @@ Very few. Just one tiny in the GC, not strictly needed. alloc dummy_to_fool_the_compiler_into_doing_things_it_currently_cant_handle; ------------ -- config.h +- config.h [now gcconfig.h] __MWERKS__ does not have to mean MACOS. You can use Codewarrior to build a Win32 or BeOS library and soon a Rhapsody library. You may have to change that #if... diff --git a/boehm-gc/README.QUICK b/boehm-gc/README.QUICK index 3273c8ba4eb..ddebf82ca50 100644 --- a/boehm-gc/README.QUICK +++ b/boehm-gc/README.QUICK @@ -1,5 +1,7 @@ Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers -Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. +Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. +Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. +Copyright (c) 1999 by Hewlett-Packard. All rights reserved. THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK. diff --git a/boehm-gc/README.alpha b/boehm-gc/README.alpha index b187fd5bc45..213a13e3fef 100644 --- a/boehm-gc/README.alpha +++ b/boehm-gc/README.alpha @@ -5,6 +5,13 @@ Incremental gc not yet supported under Linux because signal handler for SIGSEGV can't get a hold of fault address. Dynamic library support is also missing from Linux/alpha, probably for no good reason. +Currently there is no thread support in the standard distribution. There +exists a separate port to DEC Unix pthreads. It should be possible to +port the X86 Linux threads support to Alpha without much trouble. + +If you get asssembler errors, be sure to read the first few lines of the +Makefile. + From Philippe Queinnec: System: DEC/Alpha OSF1 v3.2, vendor cc diff --git a/boehm-gc/README.amiga b/boehm-gc/README.amiga index 865642be4b4..47b15884354 100644 --- a/boehm-gc/README.amiga +++ b/boehm-gc/README.amiga @@ -1,4 +1,51 @@ +=========================================================================== + Martin Tauchmann's notes (1-Apr-99) +=========================================================================== + +Works now, also with the GNU-C compiler V2.7.2.1. <ftp://ftp.unina.it/pub/amiga/geekgadgets/amiga/m68k/snapshots/971125/amiga-bin/> +Modify the `Makefile` +CC=cc $(ABI_FLAG) +to +CC=gcc $(ABI_FLAG) + +TECHNICAL NOTES + +- `GC_get_stack_base()`, `GC_register_data_segments()` works now with every + C compiler; also Workbench. + +- Removed AMIGA_SKIP_SEG, but the Code-Segment must not be scanned by GC. + + +PROBLEMS +- When the Linker, does`t merge all Code-Segments to an single one. LD of GCC + do it always. + +- With ixemul.library V47.3, when an GC program launched from another program + (example: `Make` or `if_mach M68K AMIGA gctest`), `GC_register_data_segments()` + found the Segment-List of the caller program. + Can be fixed, if the run-time initialization code (for C programs, usually *crt0*) + support `__data` and `__bss`. + +- PowerPC Amiga currently not supported. + +- Dynamic libraries (dyn_load.c) not supported. + + +TESTED WITH SOFTWARE + +`Optimized Oberon 2 C` (oo2c) <http://cognac.informatik.uni-kl.de/download/index.html> + + +TESTED WITH HARDWARE + +MC68030 + + +CONTACT +Please, contact me at <martintauchmann@bigfoot.com>, when you change the +Amiga port. <http://martintauchmann.home.pages.de> + =========================================================================== Michel Schinz's notes =========================================================================== diff --git a/boehm-gc/README.hp b/boehm-gc/README.hp index 869aaea67c1..072ba5386ac 100644 --- a/boehm-gc/README.hp +++ b/boehm-gc/README.hp @@ -1,9 +1,16 @@ Dynamic loading support requires that executables be linked with -ldld. The alternative is to build the collector without defining DYNAMIC_LOADING -in config.h and ensuring that all garbage collectable objects are +in gcconfig.h and ensuring that all garbage collectable objects are accessible without considering statically allocated variables in dynamic libraries. The collector should compile with either plain cc or cc -Ae. CC -Aa fails to define _HPUX_SOURCE and thus will not configure the collector correctly. + +Incremental collection support was reccently added, and should now work. + +Thread support for HP/UX 11 Pthreads was also recently added. It is still +flakey in this release. (It has only been tested on a uniprocessor. Even +there some fraction of thread creation calls fail with a not-yet-understood +error return from sem_wait.) diff --git a/boehm-gc/README.linux b/boehm-gc/README.linux index ffe735bc182..b4f136afb5c 100644 --- a/boehm-gc/README.linux +++ b/boehm-gc/README.linux @@ -1,7 +1,11 @@ -See README.alpha for Linux on DEC AXP info. This file applies to -Linux/Intel. +See README.alpha for Linux on DEC AXP info. -Incremental GC is supported. +This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K +and PowerPC are also integrated. They should behave similarly, except that +the PowerPC port lacks incremental GC support, and it is unknown to what +extent the Linux threads code is functional. + +Incremental GC is supported on Intel IA32 and M68K. Dynamic libraries are supported on an ELF system. A static executable should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0". @@ -37,3 +41,10 @@ To use threads, you need to abide by the following requirements: probably be an inconsistent state when a thread calling the loader is is stopped for GC. (It's possible that this is fixable in the same way it is handled for SOLARIS_THREADS, with GC_dlopen.) + +5) The combination of LINUX_THREADS, REDIRECT_MALLOC, and incremental + collection fails in seemingly random places. This hasn't been tracked + down yet, but is perhaps not completely astonishing. The thread package + uses malloc, and thus can presumably get SIGSEGVs while inside the + package. There is no real guarantee that signals are handled properly + at that point. diff --git a/boehm-gc/README.rs6000 b/boehm-gc/README.rs6000 index 0444ac4cce0..f5630b20a32 100644 --- a/boehm-gc/README.rs6000 +++ b/boehm-gc/README.rs6000 @@ -4,3 +4,6 @@ startup. The supplied value sometimes causes failure under AIX 4.1, though it appears to work under 3.X. HEURISTIC2 seems to work under 4.1, but involves a substantial performance penalty, and will fail if there is no limit on stack size. + +There is no thread support. (I assume recent versions of AIX provide +pthreads? I no longer have access to a machine ...) diff --git a/boehm-gc/README.sgi b/boehm-gc/README.sgi index 186e4977106..e67124b5544 100644 --- a/boehm-gc/README.sgi +++ b/boehm-gc/README.sgi @@ -35,3 +35,7 @@ The garbage collector uses signals to stop threads.) initiated. Applications with many such threads may not exhibit acceptable performance with the collector. (Increasing the heap size may help.) +6) The collector should not be compiled with -DREDIRECT_MALLOC. This +confuses some library calls made by the pthreads implementation, which +expect the standard malloc. + diff --git a/boehm-gc/README.solaris2 b/boehm-gc/README.solaris2 index 9ef4648d04a..e5935131c77 100644 --- a/boehm-gc/README.solaris2 +++ b/boehm-gc/README.solaris2 @@ -1,7 +1,7 @@ The collector supports both incremental collection and threads under Solaris 2. The incremental collector normally retrieves page dirty information through the appropriate /proc calls. But it can also be configured -(by defining MPROTECT_VDB instead of PROC_VDB in config.h) to use mprotect +(by defining MPROTECT_VDB instead of PROC_VDB in gcconfig.h) to use mprotect and signals. This may result in shorter pause times, but it is no longer safe to issue arbitrary system calls that write to the heap. @@ -14,7 +14,7 @@ and sbrk() only when you know that malloc() definitely will not be used by any library routine." This doesn't make a lot of sense to me, since there seems to be no documentation as to which routines can transitively call malloc. Nonetheless, under Solaris2, the collector now (since 4.12) allocates -memory using mmap by default. (It defines USE_MMAP in config.h.) +memory using mmap by default. (It defines USE_MMAP in gcconfig.h.) You may want to reverse this decisions if you use -DREDIRECT_MALLOC=... diff --git a/boehm-gc/README.win32 b/boehm-gc/README.win32 index 76c4c6e3816..d78816b555d 100644 --- a/boehm-gc/README.win32 +++ b/boehm-gc/README.win32 @@ -23,7 +23,11 @@ the two systems, and under different versions of win32s.) The collector test program "gctest" is linked as a GUI application, but does not open any windows. Its output appears in the file "gc.log". It may be started from the file manager. The hour glass -cursor will appear as long as it's running. +cursor will appear as long as it's running. If it is started from the +command line, it will usually run in the background. Wait a few +minutes (a few seconds on a modern machine) before you check the output. +You should see either a failure indication or a "Collector appears to +work" message. The cord test program has not been ported (but should port easily). A toy editor (cord/de.exe) based on cords (heavyweight @@ -46,7 +50,7 @@ the line "include Makefile.DLLs". The latter should be necessary only if you want to package the collector as a DLL. The GNU-win32 port is believed to work only for b18, not b19, probably dues to linker changes in b19. This is probably fixable with a different definition of -DATASTART and DATAEND in config.h. +DATASTART and DATAEND in gcconfig.h. For Borland tools, use BCC_MAKEFILE. Note that Borland's compiler defaults to 1 byte alignment in structures (-a1), @@ -56,7 +60,7 @@ LEAST 4 BYTE ALIGNMENT. Thus the BORLAND DEFAULT MUST BE OVERRIDDEN. (In my opinion, it should usually be anyway. I expect that -a1 introduces major performance penalties on a 486 or Pentium.) Note that this changes structure layouts. (As a last -resort, config.h can be changed to allow 1 byte alignment. But +resort, gcconfig.h can be changed to allow 1 byte alignment. But this has significant negative performance implications.) The Makefile is set up to assume Borland 4.5. If you have another version, change the line near the top. By default, it does not @@ -97,67 +101,49 @@ test with VC++ from the command line, use nmake /F ".\gc.mak" CFG="gctest - Win32 Release" This requires that the subdirectory gctest\Release exist. +The test program and DLL will reside in the Release directory. This version relies on the collector residing in a dll. This version currently supports incremental collection only if it is enabled before any additional threads are created. -It is known to not be completely solid. At a minimum it can deadlock -if a thread starts in the middle of an allocation. There may be -other problems. If you need solid support for win32 threads, you -check with Geodesic Systems. I haven't tried it, but they claim -to support it. +Version 4.13 attempts to fix some of the earlier problems, but there +may be other issues. If you need solid support for win32 threads, you +might check with Geodesic Systems. Their collector must be licensed, +but they have invested far more time in win32-specific issues. Hans Ivan V. Demakov's README for the Watcom port: -[ He points out in a later message that there may be a problem compiling - under Windows-3.11 for Windows NT. ] +The collector has been compiled with Watcom C 10.6 and 11.0. +It runs under win32, win32s, and even under msdos with dos4gw +dos-extender. It should also run under OS/2, though this isn't +tested. Under win32 the collector can be built either as dll +or as static library. -Watcom C/C++ 10.5, 10.6, 11.0 tested. +Note that all compilations were done under Windows 95 or NT. +For unknown reason compiling under Windows 3.11 for NT (one +attempt has been made) leads to broken executables. -The collector runs on WIN32 and DOS4GW dos-extender with both -stack and register based calling conventions (options -5r and -5s). -Incremental collection not supported. +Incremental collection is not supported. -OS/2 not tested, but should work (only some #ifdef's added for OS/2 port). +cord is not ported. -cord not ported. Watcom C fails to compile it, from first attempt. -Since I don't use it, I don't try to fix it. +Before compiling you may need to edit WCC_MAKEFILE to set target +platform, library type (dynamic or static), calling conventions, and +optimization options. -cpp_test succeeds, but not compiled automaticaly with WCC_MAKEFILE. +To compile the collector and testing programs use the command: + wmake -f WCC_MAKEFILE +All programs using gc should be compiled with 4-byte alignment. +For further explanations on this see comments about Borland. -My changes: +If gc compiled as dll, the macro ``GC_DLL'' should be defined before +including "gc.h" (for example, with -DGC_DLL compiler option). It's +important, otherwise resulting programs will not run. - * config.h Added definitions for Watcom C/C++. - Undefined MPROTECT_VDB for Watcom C/C++ MSWIN32, - I don't have idea why it not work. - - * gc.h Explicitly declared GC_noop. This prevents - program crash, compiled with -5r option. - - * gc_priv.h Changed declaration for GC_push_one to make - compiler happy. - Added GC_dos4gw_get_mem declaration and - GET_MEM uses it in DOS4GW environment. - - * os_dep.c Added __WATCOMC__ and DOS4GW #ifdef's. - Added GC_dos4gw_get_mem. - - * mach_dep.c For Watcom used setjmp method of marking registers. - - * WCC_MAKEFILE New file. Makefile for Watcom C/C++. - - * gc_watcom.asm New file. Some functions for DOS4GW. - This functions may (probably) be done in C, - but I can't figure out how do this for all - possible options of compiler. - - * README.watcom This file. - - - Ivan Demakov (email: dem@tgrad.nsk.su) +Ivan Demakov (email: ivan@tgrad.nsk.su) diff --git a/boehm-gc/SMakefile.amiga b/boehm-gc/SMakefile.amiga index b1aa340e538..e9602c08cdc 100644 --- a/boehm-gc/SMakefile.amiga +++ b/boehm-gc/SMakefile.amiga @@ -1,6 +1,6 @@ OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o -INC= gc_private.h gc_hdrs.h gc.h config.h +INC= gc_private.h gc_hdrs.h gc.h gcconfig.h all: gctest setjmp_t diff --git a/boehm-gc/WCC_MAKEFILE b/boehm-gc/WCC_MAKEFILE index cc0ef136742..087ff6a31d8 100644 --- a/boehm-gc/WCC_MAKEFILE +++ b/boehm-gc/WCC_MAKEFILE @@ -1,95 +1,130 @@ -# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW . -# May work with Watcom 10.0 . -# +# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW. +# May work with Watcom 10.0. -# -# Uncoment one of line for cross compiling +# Uncoment one of the lines below for cross compilation. +SYSTEM=MSWIN32 #SYSTEM=DOS4GW -#SYSTEM=MSWIN32 #SYSTEM=OS2 -!ifndef SYSTEM +# The collector can be built either as dynamic or as static library. +# Select the library type you need. +#MAKE_AS_DLL=1 +MAKE_AS_LIB=1 -!ifdef __MSDOS__ -SYSTEM=DOS4GW -!endif +# Select calling conventions. +# Possible choices are r and s. +CALLING=s -!ifdef __NT__ -SYSTEM=MSWIN32 -!endif +# Select target CPU. +# Possible choices are 3, 4, 5, and 6. +# The last choice available only since version 11.0. +CPU=5 -!ifdef __OS2__ -SYSTEM=OS2 -!endif +# Set optimization options. +# Watcom before 11.0 does not support option "-oh". +OPTIM=-oneatx -s +#OPTIM=-ohneatx -s -D_SYSTEM= +DEFS=-DALL_INTERIOR_POINTERS -DSILENT -DNO_SIGNALS #-DSMALL_CONFIG #-DGC_DEBUG -!else -D_SYSTEM=-D$(SYSTEM) +##### +!ifndef SYSTEM +!ifdef __MSDOS__ +SYSTEM=DOS4GW +!else ifdef __NT__ +SYSTEM=MSWIN32 +!else ifdef __OS2__ +SYSTEM=OS2 +!else +SYSTEM=Unknown +!endif !endif !define $(SYSTEM) +!ifdef DOS4GW +SYSFLAG=-DDOS4GW -bt=dos +!else ifdef MSWIN32 +SYSFLAG=-DMSWIN32 -bt=nt +!else ifdef OS2 +SYSFLAG=-DOS2 -bt=os2 +!else +!error undefined or unsupported target platform: $(SYSTEM) +!endif +!ifdef MAKE_AS_DLL +DLLFLAG=-bd -DGC_DLL +TEST_DLLFLAG=-DGC_DLL +!else ifdef MAKE_AS_LIB +DLLFLAG= +TEST_DLLFLAG= +!else +!error Either MAKE_AS_LIB or MAKE_AS_DLL should be defined +!endif CC=wcc386 CXX=wpp386 -AS=wasm - - -# Watcom before 11.0 not support option -oh -# Remove it if you get error -OPTIM=-oneatxh -s -CALLING=-5s - -DEFS=-DALL_INTERIOR_POINTERS -DSILENT #-DSMALL_CONFIG #-DGC_DEBUG - -# ! -DUSE_GENERIC required ! -CFLAGS=$(OPTIM) -zp4 $(CALLING) -zc -DUSE_GENERIC $(D_SYSTEM) $(DEFS) +# -DUSE_GENERIC is required ! +CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(DLLFLAG) -DGC_BUILD -DUSE_GENERIC $(DEFS) CXXFLAGS= $(CFLAGS) -ASFLAGS=$(CALLING) +TEST_CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(TEST_DLLFLAG) $(DEFS) +TEST_CXXFLAGS= $(TEST_CFLAGS) OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj & mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj & obj_map.obj blacklst.obj finalize.obj new_hblk.obj & dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj & - typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj + typd_mlc.obj ptr_chck.obj mallocx.obj +all: gc.lib gctest.exe test_cpp.exe -all: gc.lib gctest.exe +!ifdef MAKE_AS_DLL -# this file required for DOS4GW only -gc_watcom.obj: gc_watcom.asm WCC_MAKEFILE - $(AS) $(ASFLAGS) gc_watcom.asm +gc.lib: gc.dll gc_cpp.obj + *wlib -b -c -n -p=512 $@ +gc.dll +gc_cpp.obj +gc.dll: $(OBJS) .AUTODEPEND + @%create $*.lnk !ifdef DOS4GW -gc.lib: $(OBJS) gc_watcom.obj - @%create $*.lb1 - @for %i in ($(OBJS)) do @%append $*.lb1 +'%i' - @@%append $*.lb1 +'gc_watcom.obj' - *wlib -b -c -n -p=512 $@ @$*.lb1 + @%append $*.lnk sys os2v2_dll +!else ifdef MSWIN32 + @%append $*.lnk sys nt_dll +!else ifdef OS2 + @%append $*.lnk sys os2v2_dll +!endif + @%append $*.lnk name $* + @for %i in ($(OBJS)) do @%append $*.lnk file '%i' +!ifeq CALLING s + @%append $*.lnk export GC_is_marked + @%append $*.lnk export GC_incr_words_allocd + @%append $*.lnk export GC_incr_mem_freed + @%append $*.lnk export GC_generic_malloc_words_small +!else + @%append $*.lnk export GC_is_marked_ + @%append $*.lnk export GC_incr_words_allocd_ + @%append $*.lnk export GC_incr_mem_freed_ + @%append $*.lnk export GC_generic_malloc_words_small_ +!endif + *wlink @$*.lnk !else -gc.lib: $(OBJS) +gc.lib: $(OBJS) gc_cpp.obj @%create $*.lb1 @for %i in ($(OBJS)) do @%append $*.lb1 +'%i' + @%append $*.lb1 +'gc_cpp.obj' *wlib -b -c -n -p=512 $@ @$*.lb1 -!endif +!endif -test.obj: test.c - $(CC) $(CFLAGS) $*.c gctest.exe: test.obj gc.lib %create $*.lnk !ifdef DOS4GW @%append $*.lnk sys dos4g -!endif -!ifdef MSWIN32 +!else ifdef MSWIN32 @%append $*.lnk sys nt -!endif -!ifdef OS2 +!else ifdef OS2 @%append $*.lnk sys os2v2 !endif @%append $*.lnk op case @@ -97,8 +132,47 @@ gctest.exe: test.obj gc.lib @%append $*.lnk name $* @%append $*.lnk file test.obj @%append $*.lnk library gc.lib +!ifdef MAKE_AS_DLL +!ifeq CALLING s + @%append $*.lnk import GC_is_marked gc +!else + @%append $*.lnk import GC_is_marked_ gc +!endif +!endif + *wlink @$*.lnk +test_cpp.exe: test_cpp.obj gc.lib + %create $*.lnk +!ifdef DOS4GW + @%append $*.lnk sys dos4g +!else ifdef MSWIN32 + @%append $*.lnk sys nt +!else ifdef OS2 + @%append $*.lnk sys os2v2 +!endif + @%append $*.lnk op case + @%append $*.lnk op stack=256K + @%append $*.lnk name $* + @%append $*.lnk file test_cpp.obj + @%append $*.lnk library gc.lib +!ifdef MAKE_AS_DLL +!ifeq CALLING s + @%append $*.lnk import GC_incr_words_allocd gc + @%append $*.lnk import GC_incr_mem_freed gc + @%append $*.lnk import GC_generic_malloc_words_small gc +!else + @%append $*.lnk import GC_incr_words_allocd_ gc + @%append $*.lnk import GC_incr_mem_freed_ gc + @%append $*.lnk import GC_generic_malloc_words_small_ gc +!endif +!endif *wlink @$*.lnk +gc_cpp.obj: gc_cpp.cc .AUTODEPEND + $(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc +test.obj: test.c .AUTODEPEND + $(CC) $(TEST_CFLAGS) $*.c +test_cpp.obj: test_cpp.cc .AUTODEPEND + $(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc .c.obj: .AUTODEPEND @@ -107,9 +181,6 @@ gctest.exe: test.obj gc.lib .cc.obj: .AUTODEPEND $(CXX) $(CXXFLAGS) $*.cc -.cpp.obj: .AUTODEPEND - $(CXX) $(CXXFLAGS) $*.cpp - clean : .SYMBOLIC @if exist *.obj del *.obj @if exist *.map del *.map @@ -121,3 +192,5 @@ clean : .SYMBOLIC @if exist *.lst del *.lst @if exist *.exe del *.exe @if exist *.log del *.log + @if exist *.lib del *.lib + @if exist *.dll del *.dll diff --git a/boehm-gc/aclocal.m4 b/boehm-gc/aclocal.m4 index 6a4111921a2..0c758ff8b79 100644 --- a/boehm-gc/aclocal.m4 +++ b/boehm-gc/aclocal.m4 @@ -294,7 +294,7 @@ else fi]) -# serial 35 AC_PROG_LIBTOOL +# serial 40 AC_PROG_LIBTOOL AC_DEFUN(AC_PROG_LIBTOOL, [AC_REQUIRE([AC_LIBTOOL_SETUP])dnl @@ -303,8 +303,9 @@ AC_CACHE_SAVE # Actually configure libtool. ac_aux_dir is where install-sh is found. CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ -LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ -DLLTOOL="$DLLTOOL" AS="$AS" \ +LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \ +DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \ ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ $libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ || AC_MSG_ERROR([libtool configure failed]) @@ -335,8 +336,6 @@ AC_REQUIRE([AC_PROG_RANLIB])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_LD])dnl AC_REQUIRE([AC_PROG_NM])dnl -AC_REQUIRE([AC_SYS_NM_PARSE])dnl -AC_REQUIRE([AC_SYS_SYMBOL_UNDERSCORE])dnl AC_REQUIRE([AC_PROG_LN_S])dnl dnl @@ -345,10 +344,16 @@ libtool_flags="--cache-file=$cache_file" test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" -test "$lt_dlopen" = yes && libtool_flags="$libtool_flags --enable-dlopen" -test "$silent" = yes && libtool_flags="$libtool_flags --silent" test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" +ifdef([AC_PROVIDE_AC_LIBTOOL_DLOPEN], +[libtool_flags="$libtool_flags --enable-dlopen"]) +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[libtool_flags="$libtool_flags --enable-win32-dll"]) +AC_ARG_ENABLE(libtool-lock, + [ --disable-libtool-lock avoid locking (might break parallel builds)]) +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" # Some flags need to be propagated to the compiler or linker for good # libtool support. @@ -384,33 +389,28 @@ case "$host" in fi ;; -*-*-cygwin*) - AC_SYS_LIBTOOL_CYGWIN +ifdef([AC_PROVIDE_AC_LIBTOOL_WIN32_DLL], +[*-*-cygwin* | *-*-mingw*) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; - +]) esac - -# enable the --disable-libtool-lock switch - -AC_ARG_ENABLE(libtool-lock, -[ --disable-libtool-lock force libtool not to do file locking], -need_locks=$enableval, -need_locks=yes) - -if test x"$need_locks" = xno; then - libtool_flags="$libtool_flags --disable-lock" -fi ]) -# AC_LIBTOOL_DLOPEN - check for dlopen support -AC_DEFUN(AC_LIBTOOL_DLOPEN, [lt_dlopen=yes]) +# AC_LIBTOOL_DLOPEN - enable checks for dlopen support +AC_DEFUN(AC_LIBTOOL_DLOPEN, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])]) + +# AC_LIBTOOL_WIN32_DLL - declare package support for building win32 dll's +AC_DEFUN(AC_LIBTOOL_WIN32_DLL, [AC_BEFORE([$0], [AC_LIBTOOL_SETUP])]) # AC_ENABLE_SHARED - implement the --enable-shared flag # Usage: AC_ENABLE_SHARED[(DEFAULT)] # Where DEFAULT is either `yes' or `no'. If omitted, it defaults to # `yes'. -AC_DEFUN(AC_ENABLE_SHARED, -[define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl +AC_DEFUN(AC_ENABLE_SHARED, [dnl +define([AC_ENABLE_SHARED_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE(shared, changequote(<<, >>)dnl << --enable-shared[=PKGS] build shared libraries [default=>>AC_ENABLE_SHARED_DEFAULT], @@ -435,15 +435,15 @@ enable_shared=AC_ENABLE_SHARED_DEFAULT)dnl ]) # AC_DISABLE_SHARED - set the default shared flag to --disable-shared -AC_DEFUN(AC_DISABLE_SHARED, -[AC_ENABLE_SHARED(no)]) +AC_DEFUN(AC_DISABLE_SHARED, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_SHARED(no)]) # AC_ENABLE_STATIC - implement the --enable-static flag # Usage: AC_ENABLE_STATIC[(DEFAULT)] # Where DEFAULT is either `yes' or `no'. If omitted, it defaults to # `yes'. -AC_DEFUN(AC_ENABLE_STATIC, -[define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl +AC_DEFUN(AC_ENABLE_STATIC, [dnl +define([AC_ENABLE_STATIC_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE(static, changequote(<<, >>)dnl << --enable-static[=PKGS] build static libraries [default=>>AC_ENABLE_STATIC_DEFAULT], @@ -468,16 +468,16 @@ enable_static=AC_ENABLE_STATIC_DEFAULT)dnl ]) # AC_DISABLE_STATIC - set the default static flag to --disable-static -AC_DEFUN(AC_DISABLE_STATIC, -[AC_ENABLE_STATIC(no)]) +AC_DEFUN(AC_DISABLE_STATIC, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_STATIC(no)]) # AC_ENABLE_FAST_INSTALL - implement the --enable-fast-install flag # Usage: AC_ENABLE_FAST_INSTALL[(DEFAULT)] # Where DEFAULT is either `yes' or `no'. If omitted, it defaults to # `yes'. -AC_DEFUN(AC_ENABLE_FAST_INSTALL, -[define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl +AC_DEFUN(AC_ENABLE_FAST_INSTALL, [dnl +define([AC_ENABLE_FAST_INSTALL_DEFAULT], ifelse($1, no, no, yes))dnl AC_ARG_ENABLE(fast-install, changequote(<<, >>)dnl << --enable-fast-install[=PKGS] optimize for fast installation [default=>>AC_ENABLE_FAST_INSTALL_DEFAULT], @@ -502,9 +502,8 @@ enable_fast_install=AC_ENABLE_FAST_INSTALL_DEFAULT)dnl ]) # AC_ENABLE_FAST_INSTALL - set the default to --disable-fast-install -AC_DEFUN(AC_DISABLE_FAST_INSTALL, -[AC_ENABLE_FAST_INSTALL(no)]) - +AC_DEFUN(AC_DISABLE_FAST_INSTALL, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl +AC_ENABLE_FAST_INSTALL(no)]) # AC_PROG_LD - find the path to the GNU or non-GNU linker AC_DEFUN(AC_PROG_LD, @@ -522,7 +521,7 @@ if test "$ac_cv_prog_gcc" = yes; then case "$ac_prog" in # Accept absolute paths. changequote(,)dnl - /* | [A-Za-z]:[\\/]*) + [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' changequote([,])dnl # Canonicalize the path of ld @@ -548,10 +547,10 @@ else fi AC_CACHE_VAL(ac_cv_path_LD, [if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog"; then + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ac_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. @@ -596,10 +595,10 @@ AC_CACHE_VAL(ac_cv_path_NM, # Let the user override the test. ac_cv_path_NM="$NM" else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/nm; then + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored @@ -623,227 +622,22 @@ AC_MSG_RESULT([$NM]) AC_SUBST(NM) ]) -# AC_SYS_NM_PARSE - Check for command to grab the raw symbol name followed -# by C symbol name from nm. -AC_DEFUN(AC_SYS_NM_PARSE, +# AC_CHECK_LIBM - check for math library +AC_DEFUN(AC_CHECK_LIBM, [AC_REQUIRE([AC_CANONICAL_HOST])dnl -AC_REQUIRE([AC_PROG_NM])dnl -# Check for command to grab the raw symbol name followed by C symbol from nm. -AC_MSG_CHECKING([command to parse $NM output]) -AC_CACHE_VAL(ac_cv_sys_global_symbol_pipe, -[# These are sane defaults that work on at least a few old systems. -# {They come from Ultrix. What could be older than Ultrix?!! ;)} - -changequote(,)dnl -# Character class describing NM global symbol codes. -ac_symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -ac_sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Transform the above into a raw symbol and a C symbol. -ac_symxfrm='\1 \2\3 \3' - -# Transform an extracted symbol line into a proper C declaration -ac_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" - -# Define system-specific variables. -case "$host_os" in -aix*) - ac_symcode='[BCDT]' - ;; -cygwin* | mingw*) - ac_symcode='[ABCDGISTW]' - ;; -hpux*) - ac_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" +LIBM= +case "$host" in +*-*-beos* | *-*-cygwin*) + # These system don't have libm ;; -irix*) - ac_symcode='[BCDEGRST]' +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, main, LIBM="$LIBM -lm") ;; -solaris*) - ac_symcode='[BDT]' +*) + AC_CHECK_LIB(m, main, LIBM="-lm") ;; esac - -# If we're using GNU nm, then use its standard symbol codes. -if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then - ac_symcode='[ABCDGISTW]' -fi -changequote([,])dnl - -# Try without a prefix undercore, then with it. -for ac_symprfx in "" "_"; do - - ac_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($ac_symcode\)[ ][ ]*\($ac_symprfx\)$ac_sympat$/$ac_symxfrm/p'" - - # Check to see that the pipe works correctly. - ac_pipe_works=no - rm -f conftest.$ac_ext - cat > conftest.$ac_ext <<EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(){} -#ifdef __cplusplus -} -#endif -int main(){nm_test_var='a';nm_test_func;return 0;} -EOF - - if AC_TRY_EVAL(ac_compile); then - # Now try to grab the symbols. - ac_nlist=conftest.nm - - if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then - - # Try sorting and uniquifying the output. - if sort "$ac_nlist" | uniq > "$ac_nlist"T; then - mv -f "$ac_nlist"T "$ac_nlist" - else - rm -f "$ac_nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if egrep ' nm_test_var$' "$ac_nlist" >/dev/null; then - if egrep ' nm_test_func$' "$ac_nlist" >/dev/null; then - cat <<EOF > conftest.c -#ifdef __cplusplus -extern "C" { -#endif - -EOF - # Now generate the symbol file. - eval "$ac_global_symbol_to_cdecl"' < "$ac_nlist" >> conftest.c' - - cat <<EOF >> conftest.c -#if defined (__STDC__) && __STDC__ -# define lt_ptr_t void * -#else -# define lt_ptr_t char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr_t address; -} -changequote(,)dnl -lt_preloaded_symbols[] = -changequote([,])dnl -{ -EOF - sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$ac_nlist" >> conftest.c - cat <<\EOF >> conftest.c - {0, (lt_ptr_t) 0} -}; - -#ifdef __cplusplus -} -#endif -EOF - # Now try linking the two files. - mv conftest.$ac_objext conftestm.$ac_objext - ac_save_LIBS="$LIBS" - ac_save_CFLAGS="$CFLAGS" - LIBS="conftestm.$ac_objext" - CFLAGS="$CFLAGS$no_builtin_flag" - if AC_TRY_EVAL(ac_link) && test -s conftest; then - ac_pipe_works=yes - else - echo "configure: failed program was:" >&AC_FD_CC - cat conftest.c >&AC_FD_CC - fi - LIBS="$ac_save_LIBS" - CFLAGS="$ac_save_CFLAGS" - else - echo "cannot find nm_test_func in $ac_nlist" >&AC_FD_CC - fi - else - echo "cannot find nm_test_var in $ac_nlist" >&AC_FD_CC - fi - else - echo "cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC - fi - else - echo "$progname: failed program was:" >&AC_FD_CC - cat conftest.c >&AC_FD_CC - fi - rm -rf conftest* - - # Do not use the global_symbol_pipe unless it works. - if test "$ac_pipe_works" = yes; then - if test x"$ac_symprfx" = x"_"; then - ac_cv_sys_symbol_underscore=yes - else - ac_cv_sys_symbol_underscore=no - fi - break - else - ac_cv_sys_global_symbol_pipe= - fi -done -]) - -ac_result=yes -if test -z "$ac_cv_sys_global_symbol_pipe"; then - ac_result=no -fi -AC_MSG_RESULT($ac_result) -]) - -# AC_SYS_LIBTOOL_CYGWIN - find tools needed on cygwin -AC_DEFUN(AC_SYS_LIBTOOL_CYGWIN, -[AC_CHECK_TOOL(DLLTOOL, dlltool, false) -AC_CHECK_TOOL(AS, as, false) -]) - -# AC_SYS_SYMBOL_UNDERSCORE - does the compiler prefix global symbols -# with an underscore? -AC_DEFUN(AC_SYS_SYMBOL_UNDERSCORE, -[AC_REQUIRE([AC_PROG_NM])dnl -AC_REQUIRE([AC_SYS_NM_PARSE])dnl -AC_MSG_CHECKING([for _ prefix in compiled symbols]) -AC_CACHE_VAL(ac_cv_sys_symbol_underscore, -[ac_cv_sys_symbol_underscore=no -cat > conftest.$ac_ext <<EOF -void nm_test_func(){} -int main(){nm_test_func;return 0;} -EOF -if AC_TRY_EVAL(ac_compile); then - # Now try to grab the symbols. - ac_nlist=conftest.nm - if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if egrep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - ac_cv_sys_symbol_underscore=yes - else - if egrep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC - fi - fi - else - echo "configure: cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC - fi -else - echo "configure: failed program was:" >&AC_FD_CC - cat conftest.c >&AC_FD_CC -fi -rm -rf conftest* -]) -AC_MSG_RESULT($ac_cv_sys_symbol_underscore) -USE_SYMBOL_UNDERSCORE=${ac_cv_sys_symbol_underscore=no} -AC_SUBST(USE_SYMBOL_UNDERSCORE)dnl -]) - -# AC_CHECK_LIBM - check for math library -AC_DEFUN(AC_CHECK_LIBM, [ -AC_CHECK_LIB(mw, _mwvalidcheckl) -AC_CHECK_LIB(m, cos) ]) # AC_LIBLTDL_CONVENIENCE[(dir)] - sets LIBLTDL to the link flags for @@ -854,13 +648,14 @@ AC_CHECK_LIB(m, cos) # '${top_builddir}/' (note the single quotes!) if your package is not # flat, and, if you're not using automake, define top_builddir as # appropriate in the Makefiles. -AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [ +AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl case "$enable_ltdl_convenience" in no) AC_MSG_ERROR([this package needs a convenience libltdl]) ;; "") enable_ltdl_convenience=yes ac_configure_args="$ac_configure_args --enable-ltdl-convenience" ;; esac LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdlc.la + INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl']) ]) # AC_LIBLTDL_INSTALLABLE[(dir)] - sets LIBLTDL to the link flags for @@ -872,16 +667,23 @@ AC_DEFUN(AC_LIBLTDL_CONVENIENCE, [ # flat, and, if you're not using automake, define top_builddir as # appropriate in the Makefiles. # In the future, this macro may have to be called after AC_PROG_LIBTOOL. -AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [ - AC_CHECK_LIB(ltdl, main, LIBLTDL="-lltdl", [ - case "$enable_ltdl_install" in - no) AC_MSG_WARN([libltdl not installed, but installation disabled]) ;; - "") enable_ltdl_install=yes - ac_configure_args="$ac_configure_args --enable-ltdl-install" ;; - esac +AC_DEFUN(AC_LIBLTDL_INSTALLABLE, [AC_BEFORE([$0],[AC_LIBTOOL_SETUP])dnl + AC_CHECK_LIB(ltdl, main, + [test x"$enable_ltdl_install" != xyes && enable_ltdl_install=no], + [if test x"$enable_ltdl_install" = xno; then + AC_MSG_WARN([libltdl not installed, but installation disabled]) + else + enable_ltdl_install=yes + fi ]) - if test x"$enable_ltdl_install" != x"no"; then + if test x"$enable_ltdl_install" = x"yes"; then + ac_configure_args="$ac_configure_args --enable-ltdl-install" LIBLTDL=ifelse($#,1,$1,['${top_builddir}/libltdl'])/libltdl.la + INCLTDL=ifelse($#,1,-I$1,['-I${top_builddir}/libltdl']) + else + ac_configure_args="$ac_configure_args --enable-ltdl-install=no" + LIBLTDL="-lltdl" + INCLTDL= fi ]) @@ -893,7 +695,7 @@ AC_DEFUN(AM_DISABLE_SHARED, [indir([AC_DISABLE_SHARED], $@)])dnl AC_DEFUN(AM_DISABLE_STATIC, [indir([AC_DISABLE_STATIC], $@)])dnl AC_DEFUN(AM_PROG_LD, [indir([AC_PROG_LD])])dnl AC_DEFUN(AM_PROG_NM, [indir([AC_PROG_NM])])dnl -AC_DEFUN(AM_SYS_NM_PARSE, [indir([AC_SYS_NM_PARSE])])dnl -AC_DEFUN(AM_SYS_SYMBOL_UNDERSCORE, [indir([AC_SYS_SYMBOL_UNDERSCORE])])dnl -AC_DEFUN(AM_SYS_LIBTOOL_CYGWIN, [indir([AC_SYS_LIBTOOL_CYGWIN])])dnl + +dnl This is just to silence aclocal about the macro not being used +ifelse([AC_DISABLE_FAST_INSTALL])dnl diff --git a/boehm-gc/allchblk.c b/boehm-gc/allchblk.c index 7a5a3a1c3ab..189b94214a7 100644 --- a/boehm-gc/allchblk.c +++ b/boehm-gc/allchblk.c @@ -1,7 +1,8 @@ /* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. - * Copyright (c) 1998 by Silicon Graphics. All rights reserved. + * Copyright (c) 1998-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -12,7 +13,6 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, August 9, 1995 5:08 pm PDT */ #define DEBUG #undef DEBUG @@ -21,39 +21,68 @@ /* - * allocate/free routines for heap blocks - * Note that everything called from outside the garbage collector - * should be prepared to abort at any point as the result of a signal. + * Free heap blocks are kept on one of several free lists, + * depending on the size of the block. Each free list is doubly linked. + * Adjacent free blocks are coalesced. */ -/* - * Free heap blocks are kept on a list sorted by address. - * The hb_hdr.hbh_sz field of a free heap block contains the length - * (in bytes) of the entire block. - * Neighbors are coalesced. - */ # define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE) /* largest block we will allocate starting on a black */ /* listed block. Must be >= HBLKSIZE. */ -struct hblk * GC_hblkfreelist = 0; -struct hblk *GC_savhbp = (struct hblk *)0; /* heap block preceding next */ - /* block to be examined by */ - /* GC_allochblk. */ +# define UNIQUE_THRESHOLD 32 + /* Sizes up to this many HBLKs each have their own free list */ +# define HUGE_THRESHOLD 256 + /* Sizes of at least this many heap blocks are mapped to a */ + /* single free list. */ +# define FL_COMPRESSION 8 + /* In between sizes map this many distinct sizes to a single */ + /* bin. */ + +# define N_HBLK_FLS (HUGE_THRESHOLD - UNIQUE_THRESHOLD)/FL_COMPRESSION \ + + UNIQUE_THRESHOLD + +struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 }; + +/* Map a number of blocks to the appropriate large block free list index. */ +int GC_hblk_fl_from_blocks(blocks_needed) +word blocks_needed; +{ + if (blocks_needed <= UNIQUE_THRESHOLD) return blocks_needed; + if (blocks_needed >= HUGE_THRESHOLD) return N_HBLK_FLS; + return (blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION + + UNIQUE_THRESHOLD; + +} + +# define HBLK_IS_FREE(hdr) ((hdr) -> hb_map == GC_invalid_map) +# define PHDR(hhdr) HDR(hhdr -> hb_prev) +# define NHDR(hhdr) HDR(hhdr -> hb_next) + +# ifdef USE_MUNMAP +# define IS_MAPPED(hhdr) (((hhdr) -> hb_flags & WAS_UNMAPPED) == 0) +# else /* !USE_MMAP */ +# define IS_MAPPED(hhdr) 1 +# endif /* USE_MUNMAP */ # if !defined(NO_DEBUGGING) void GC_print_hblkfreelist() { - struct hblk * h = GC_hblkfreelist; + struct hblk * h; word total_free = 0; - hdr * hhdr = HDR(h); + hdr * hhdr; word sz; + int i; - while (h != 0) { + for (i = 0; i <= N_HBLK_FLS; ++i) { + h = GC_hblkfreelist[i]; + if (0 != h) GC_printf1("Free list %ld:\n", (unsigned long)i); + while (h != 0) { + hhdr = HDR(h); sz = hhdr -> hb_sz; - GC_printf2("0x%lx size %lu ", (unsigned long)h, (unsigned long)sz); + GC_printf2("\t0x%lx size %lu ", (unsigned long)h, (unsigned long)sz); total_free += sz; if (GC_is_black_listed(h, HBLKSIZE) != 0) { GC_printf0("start black listed\n"); @@ -63,11 +92,90 @@ void GC_print_hblkfreelist() GC_printf0("not black listed\n"); } h = hhdr -> hb_next; - hhdr = HDR(h); + } + } + if (total_free != GC_large_free_bytes) { + GC_printf1("GC_large_free_bytes = %lu (INCONSISTENT!!)\n", + (unsigned long) GC_large_free_bytes); } GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free); } +/* Return the free list index on which the block described by the header */ +/* appears, or -1 if it appears nowhere. */ +int free_list_index_of(wanted) +hdr * wanted; +{ + struct hblk * h; + hdr * hhdr; + int i; + + for (i = 0; i <= N_HBLK_FLS; ++i) { + h = GC_hblkfreelist[i]; + while (h != 0) { + hhdr = HDR(h); + if (hhdr == wanted) return i; + h = hhdr -> hb_next; + } + } + return -1; +} + +void GC_dump_regions() +{ + unsigned i; + ptr_t start, end; + ptr_t p; + size_t bytes; + hdr *hhdr; + for (i = 0; i < GC_n_heap_sects; ++i) { + start = GC_heap_sects[i].hs_start; + bytes = GC_heap_sects[i].hs_bytes; + end = start + bytes; + /* Merge in contiguous sections. */ + while (i+1 < GC_n_heap_sects && GC_heap_sects[i+1].hs_start == end) { + ++i; + end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes; + } + GC_printf2("***Section from 0x%lx to 0x%lx\n", start, end); + for (p = start; p < end;) { + hhdr = HDR(p); + GC_printf1("\t0x%lx ", (unsigned long)p); + if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { + GC_printf1("Missing header!!\n", hhdr); + p += HBLKSIZE; + continue; + } + if (HBLK_IS_FREE(hhdr)) { + int correct_index = GC_hblk_fl_from_blocks( + divHBLKSZ(hhdr -> hb_sz)); + int actual_index; + + GC_printf1("\tfree block of size 0x%lx bytes", + (unsigned long)(hhdr -> hb_sz)); + if (IS_MAPPED(hhdr)) { + GC_printf0("\n"); + } else { + GC_printf0("(unmapped)\n"); + } + actual_index = free_list_index_of(hhdr); + if (-1 == actual_index) { + GC_printf1("\t\tBlock not on free list %ld!!\n", + correct_index); + } else if (correct_index != actual_index) { + GC_printf2("\t\tBlock on list %ld, should be on %ld!!\n", + actual_index, correct_index); + } + p += hhdr -> hb_sz; + } else { + GC_printf1("\tused for blocks of size 0x%lx bytes\n", + (unsigned long)WORDS_TO_BYTES(hhdr -> hb_sz)); + p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz); + } + } + } +} + # endif /* NO_DEBUGGING */ /* Initialize hdr for a block containing the indicated size and */ @@ -100,18 +208,265 @@ unsigned char flags; return(TRUE); } -#ifdef EXACT_FIRST -# define LAST_TRIP 2 -#else -# define LAST_TRIP 1 -#endif +#define FL_UNKNOWN -1 +/* + * Remove hhdr from the appropriate free list. + * We assume it is on the nth free list, or on the size + * appropriate free list if n is FL_UNKNOWN. + */ +void GC_remove_from_fl(hhdr, n) +hdr * hhdr; +int n; +{ + GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0); + if (hhdr -> hb_prev == 0) { + int index; + if (FL_UNKNOWN == n) { + index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz)); + } else { + index = n; + } + GC_ASSERT(HDR(GC_hblkfreelist[index]) == hhdr); + GC_hblkfreelist[index] = hhdr -> hb_next; + } else { + PHDR(hhdr) -> hb_next = hhdr -> hb_next; + } + if (0 != hhdr -> hb_next) { + GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr))); + NHDR(hhdr) -> hb_prev = hhdr -> hb_prev; + } +} + +/* + * Return a pointer to the free block ending just before h, if any. + */ +struct hblk * GC_free_block_ending_at(h) +struct hblk *h; +{ + struct hblk * p = h - 1; + hdr * phdr = HDR(p); + + while (0 != phdr && IS_FORWARDING_ADDR_OR_NIL(phdr)) { + p = FORWARDED_ADDR(p,phdr); + phdr = HDR(p); + } + if (0 != phdr && HBLK_IS_FREE(phdr)) return p; + p = GC_prev_block(h - 1); + if (0 != p) { + phdr = HDR(p); + if (HBLK_IS_FREE(phdr) && (ptr_t)p + phdr -> hb_sz == (ptr_t)h) { + return p; + } + } + return 0; +} + +/* + * Add hhdr to the appropriate free list. + * We maintain individual free lists sorted by address. + */ +void GC_add_to_fl(h, hhdr) +struct hblk *h; +hdr * hhdr; +{ + int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz)); + struct hblk *second = GC_hblkfreelist[index]; +# ifdef GC_ASSERTIONS + struct hblk *next = (struct hblk *)((word)h + hhdr -> hb_sz); + hdr * nexthdr = HDR(next); + struct hblk *prev = GC_free_block_ending_at(h); + hdr * prevhdr = HDR(prev); + GC_ASSERT(nexthdr == 0 || !HBLK_IS_FREE(nexthdr) || !IS_MAPPED(nexthdr)); + GC_ASSERT(prev == 0 || !HBLK_IS_FREE(prevhdr) || !IS_MAPPED(prevhdr)); +# endif + GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0); + GC_hblkfreelist[index] = h; + hhdr -> hb_next = second; + hhdr -> hb_prev = 0; + if (0 != second) HDR(second) -> hb_prev = h; + GC_invalidate_map(hhdr); +} + +#ifdef USE_MUNMAP + +/* Unmap blocks that haven't been recently touched. This is the only way */ +/* way blocks are ever unmapped. */ +void GC_unmap_old(void) +{ + struct hblk * h; + hdr * hhdr; + word sz; + unsigned short last_rec, threshold; + int i; +# define UNMAP_THRESHOLD 6 + + for (i = 0; i <= N_HBLK_FLS; ++i) { + for (h = GC_hblkfreelist[i]; 0 != h; h = hhdr -> hb_next) { + hhdr = HDR(h); + if (!IS_MAPPED(hhdr)) continue; + threshold = (unsigned short)(GC_gc_no - UNMAP_THRESHOLD); + last_rec = hhdr -> hb_last_reclaimed; + if (last_rec > GC_gc_no + || last_rec < threshold && threshold < GC_gc_no + /* not recently wrapped */) { + sz = hhdr -> hb_sz; + GC_unmap((ptr_t)h, sz); + hhdr -> hb_flags |= WAS_UNMAPPED; + } + } + } +} + +/* Merge all unmapped blocks that are adjacent to other free */ +/* blocks. This may involve remapping, since all blocks are either */ +/* fully mapped or fully unmapped. */ +void GC_merge_unmapped(void) +{ + struct hblk * h, *next; + hdr * hhdr, *nexthdr; + word size, nextsize; + int i; + + for (i = 0; i <= N_HBLK_FLS; ++i) { + h = GC_hblkfreelist[i]; + while (h != 0) { + hhdr = HDR(h); + size = hhdr->hb_sz; + next = (struct hblk *)((word)h + size); + nexthdr = HDR(next); + /* Coalesce with successor, if possible */ + if (0 != nexthdr && HBLK_IS_FREE(nexthdr)) { + nextsize = nexthdr -> hb_sz; + if (IS_MAPPED(hhdr)) { + GC_ASSERT(!IS_MAPPED(nexthdr)); + /* make both consistent, so that we can merge */ + if (size > nextsize) { + GC_remap((ptr_t)next, nextsize); + } else { + GC_unmap((ptr_t)h, size); + hhdr -> hb_flags |= WAS_UNMAPPED; + } + } else if (IS_MAPPED(nexthdr)) { + GC_ASSERT(!IS_MAPPED(hhdr)); + if (size > nextsize) { + GC_unmap((ptr_t)next, nextsize); + } else { + GC_remap((ptr_t)h, size); + hhdr -> hb_flags &= ~WAS_UNMAPPED; + } + } else { + /* Unmap any gap in the middle */ + GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nexthdr -> hb_sz); + } + /* If they are both unmapped, we merge, but leave unmapped. */ + GC_remove_from_fl(hhdr, i); + GC_remove_from_fl(nexthdr, FL_UNKNOWN); + hhdr -> hb_sz += nexthdr -> hb_sz; + GC_remove_header(next); + GC_add_to_fl(h, hhdr); + /* Start over at beginning of list */ + h = GC_hblkfreelist[i]; + } else /* not mergable with successor */ { + h = hhdr -> hb_next; + } + } /* while (h != 0) ... */ + } /* for ... */ +} + +#endif /* USE_MUNMAP */ + +/* + * Return a pointer to a block starting at h of length bytes. + * Memory for the block is mapped. + * Remove the block from its free list, and return the remainder (if any) + * to its appropriate free list. + * May fail by returning 0. + * The header for the returned block must be set up by the caller. + * If the return value is not 0, then hhdr is the header for it. + */ +struct hblk * GC_get_first_part(h, hhdr, bytes, index) +struct hblk *h; +hdr * hhdr; +word bytes; +int index; +{ + word total_size = hhdr -> hb_sz; + struct hblk * rest; + hdr * rest_hdr; + + GC_ASSERT((total_size & (HBLKSIZE-1)) == 0); + GC_remove_from_fl(hhdr, index); + if (total_size == bytes) return h; + rest = (struct hblk *)((word)h + bytes); + if (!GC_install_header(rest)) return(0); + rest_hdr = HDR(rest); + rest_hdr -> hb_sz = total_size - bytes; + rest_hdr -> hb_flags = 0; +# ifdef GC_ASSERTIONS + // Mark h not free, to avoid assertion about adjacent free blocks. + hhdr -> hb_map = 0; +# endif + GC_add_to_fl(rest, rest_hdr); + return h; +} + +/* + * H is a free block. N points at an address inside it. + * A new header for n has already been set up. Fix up h's header + * to reflect the fact that it is being split, move it to the + * appropriate free list. + * N replaces h in the original free list. + * + * Nhdr is not completely filled in, since it is about to allocated. + * It may in fact end up on the wrong free list for its size. + * (Hence adding it to a free list is silly. But this path is hopefully + * rare enough that it doesn't matter. The code is cleaner this way.) + */ +void GC_split_block(h, hhdr, n, nhdr, index) +struct hblk *h; +hdr * hhdr; +struct hblk *n; +hdr * nhdr; +int index; /* Index of free list */ +{ + word total_size = hhdr -> hb_sz; + word h_size = (word)n - (word)h; + struct hblk *prev = hhdr -> hb_prev; + struct hblk *next = hhdr -> hb_next; + + /* Replace h with n on its freelist */ + nhdr -> hb_prev = prev; + nhdr -> hb_next = next; + nhdr -> hb_sz = total_size - h_size; + nhdr -> hb_flags = 0; + if (0 != prev) { + HDR(prev) -> hb_next = n; + } else { + GC_hblkfreelist[index] = n; + } + if (0 != next) { + HDR(next) -> hb_prev = n; + } +# ifdef GC_ASSERTIONS + nhdr -> hb_map = 0; /* Don't fail test for consecutive */ + /* free blocks in GC_add_to_fl. */ +# endif +# ifdef USE_MUNMAP + hhdr -> hb_last_reclaimed = GC_gc_no; +# endif + hhdr -> hb_sz = h_size; + GC_add_to_fl(h, hhdr); + GC_invalidate_map(nhdr); +} +struct hblk * GC_allochblk_nth(); + /* * Allocate (and return pointer to) a heap block - * for objects of size sz words. + * for objects of size sz words, searching the nth free list. * * NOTE: We set obj_map field in header correctly. - * Caller is resposnsible for building an object freelist in block. + * Caller is responsible for building an object freelist in block. * * We clear the block if it is destined for large objects, and if * kind requires that newly allocated objects be cleared. @@ -122,44 +477,42 @@ word sz; int kind; unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ { - register struct hblk *thishbp; - register hdr * thishdr; /* Header corr. to thishbp */ + int start_list = GC_hblk_fl_from_blocks(OBJ_SZ_TO_BLOCKS(sz)); + int i; + for (i = start_list; i <= N_HBLK_FLS; ++i) { + struct hblk * result = GC_allochblk_nth(sz, kind, flags, i); + if (0 != result) return result; + } + return 0; +} +/* + * The same, but with search restricted to nth free list. + */ +struct hblk * +GC_allochblk_nth(sz, kind, flags, n) +word sz; +int kind; +unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ +int n; +{ register struct hblk *hbp; register hdr * hhdr; /* Header corr. to hbp */ - struct hblk *prevhbp; - register hdr * phdr; /* Header corr. to prevhbp */ + register struct hblk *thishbp; + register hdr * thishdr; /* Header corr. to hbp */ signed_word size_needed; /* number of bytes in requested objects */ signed_word size_avail; /* bytes available in this block */ - int trip_count = 0; size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz); /* search for a big enough block in free list */ - hbp = GC_savhbp; + hbp = GC_hblkfreelist[n]; hhdr = HDR(hbp); - for(;;) { - - prevhbp = hbp; - phdr = hhdr; - hbp = (prevhbp == 0? GC_hblkfreelist : phdr->hb_next); - hhdr = HDR(hbp); - - if( prevhbp == GC_savhbp) { - if (trip_count == LAST_TRIP) return(0); - ++trip_count; - } - - if( hbp == 0 ) continue; - + for(; 0 != hbp; hbp = hhdr -> hb_next, hhdr = HDR(hbp)) { size_avail = hhdr->hb_sz; -# ifdef EXACT_FIRST - if (trip_count <= 1 && size_avail != size_needed) continue; -# endif if (size_avail < size_needed) continue; # ifdef PRESERVE_LAST if (size_avail != size_needed - && !GC_incremental - && GC_in_last_heap_sect(hbp) && GC_should_collect()) { + && !GC_incremental && GC_should_collect()) { continue; } # endif @@ -170,13 +523,14 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ signed_word next_size; thishbp = hhdr -> hb_next; - if (thishbp == 0) thishbp = GC_hblkfreelist; - thishdr = HDR(thishbp); - next_size = (signed_word)(thishdr -> hb_sz); - if (next_size < size_avail + if (thishbp != 0) { + thishdr = HDR(thishbp); + next_size = (signed_word)(thishdr -> hb_sz); + if (next_size < size_avail && next_size >= size_needed && !GC_is_black_listed(thishbp, (word)size_needed)) { continue; + } } } if ( !IS_UNCOLLECTABLE(kind) && @@ -198,19 +552,21 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ thishbp = lasthbp; if (size_avail >= size_needed) { if (thishbp != hbp && GC_install_header(thishbp)) { + /* Make sure it's mapped before we mangle it. */ +# ifdef USE_MUNMAP + if (!IS_MAPPED(hhdr)) { + GC_remap((ptr_t)hbp, size_avail); + hhdr -> hb_flags &= ~WAS_UNMAPPED; + } +# endif /* Split the block at thishbp */ thishdr = HDR(thishbp); - /* GC_invalidate_map not needed, since we will */ - /* allocate this block. */ - thishdr -> hb_next = hhdr -> hb_next; - thishdr -> hb_sz = size_avail; - hhdr -> hb_sz = (ptr_t)thishbp - (ptr_t)hbp; - hhdr -> hb_next = thishbp; + GC_split_block(hbp, hhdr, thishbp, thishdr, n); /* Advance to thishbp */ - prevhbp = hbp; - phdr = hhdr; hbp = thishbp; hhdr = thishdr; + /* We must now allocate thishbp, since it may */ + /* be on the wrong free list. */ } } else if (size_needed > (signed_word)BL_LIMIT && orig_avail - size_needed @@ -218,12 +574,10 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ /* Punt, since anything else risks unreasonable heap growth. */ WARN("Needed to allocate blacklisted block at 0x%lx\n", (word)hbp); - thishbp = hbp; size_avail = orig_avail; - } else if (size_avail == 0 - && size_needed == HBLKSIZE - && prevhbp != 0) { -# ifndef FIND_LEAK + } else if (size_avail == 0 && size_needed == HBLKSIZE + && IS_MAPPED(hhdr)) { + if (!GC_find_leak) { static unsigned count = 0; /* The block is completely blacklisted. We need */ @@ -235,11 +589,14 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ /* Allocate and drop the block in small chunks, to */ /* maximize the chance that we will recover some */ /* later. */ - struct hblk * limit = hbp + (hhdr->hb_sz/HBLKSIZE); + word total_size = hhdr -> hb_sz; + struct hblk * limit = hbp + divHBLKSZ(total_size); struct hblk * h; + struct hblk * prev = hhdr -> hb_prev; - GC_words_wasted += hhdr->hb_sz; - phdr -> hb_next = hhdr -> hb_next; + GC_words_wasted += total_size; + GC_large_free_bytes -= total_size; + GC_remove_from_fl(hhdr, n); for (h = hbp; h < limit; h++) { if (h == hbp || GC_install_header(h)) { hhdr = HDR(h); @@ -248,69 +605,53 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ BYTES_TO_WORDS(HBLKSIZE - HDR_BYTES), PTRFREE, 0); /* Cant fail */ if (GC_debugging_started) { - BZERO(hbp + HDR_BYTES, HBLKSIZE - HDR_BYTES); + BZERO(h + HDR_BYTES, HBLKSIZE - HDR_BYTES); } } } /* Restore hbp to point at free block */ - if (GC_savhbp == hbp) GC_savhbp = prevhbp; - hbp = prevhbp; - hhdr = phdr; - if (hbp == GC_savhbp) --trip_count; + hbp = prev; + if (0 == hbp) { + return GC_allochblk_nth(sz, kind, flags, n); + } + hhdr = HDR(hbp); } -# endif + } } } if( size_avail >= size_needed ) { - /* found a big enough block */ - /* let thishbp --> the block */ - /* set prevhbp, hbp to bracket it */ - thishbp = hbp; - thishdr = hhdr; - if( size_avail == size_needed ) { - hbp = hhdr->hb_next; - hhdr = HDR(hbp); - } else { - hbp = (struct hblk *) - (((word)thishbp) + size_needed); - if (!GC_install_header(hbp)) { - hbp = thishbp; - continue; - } - hhdr = HDR(hbp); - GC_invalidate_map(hhdr); - hhdr->hb_next = thishdr->hb_next; - hhdr->hb_sz = size_avail - size_needed; - } - /* remove *thishbp from hblk freelist */ - if( prevhbp == 0 ) { - GC_hblkfreelist = hbp; - } else { - phdr->hb_next = hbp; - } - /* save current list search position */ - GC_savhbp = hbp; +# ifdef USE_MUNMAP + if (!IS_MAPPED(hhdr)) { + GC_remap((ptr_t)hbp, size_avail); + hhdr -> hb_flags &= ~WAS_UNMAPPED; + } +# endif + /* hbp may be on the wrong freelist; the parameter n */ + /* is important. */ + hbp = GC_get_first_part(hbp, hhdr, size_needed, n); break; } } + + if (0 == hbp) return 0; /* Notify virtual dirty bit implementation that we are about to write. */ - GC_write_hint(thishbp); + GC_write_hint(hbp); /* Add it to map of valid blocks */ - if (!GC_install_counts(thishbp, (word)size_needed)) return(0); + if (!GC_install_counts(hbp, (word)size_needed)) return(0); /* This leaks memory under very rare conditions. */ /* Set up header */ - if (!setup_header(thishdr, sz, kind, flags)) { - GC_remove_counts(thishbp, (word)size_needed); + if (!setup_header(hhdr, sz, kind, flags)) { + GC_remove_counts(hbp, (word)size_needed); return(0); /* ditto */ } /* Clear block if necessary */ if (GC_debugging_started || sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) { - BZERO(thishbp + HDR_BYTES, size_needed - HDR_BYTES); + BZERO(hbp + HDR_BYTES, size_needed - HDR_BYTES); } /* We just successfully allocated a block. Restart count of */ @@ -320,8 +661,11 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */ GC_fail_count = 0; } + + GC_large_free_bytes -= size_needed; - return( thishbp ); + GC_ASSERT(IS_MAPPED(hhdr)); + return( hbp ); } struct hblk * GC_freehblk_ptr = 0; /* Search position hint for GC_freehblk */ @@ -334,75 +678,50 @@ struct hblk * GC_freehblk_ptr = 0; /* Search position hint for GC_freehblk */ * All mark words are assumed to be cleared. */ void -GC_freehblk(p) -register struct hblk *p; +GC_freehblk(hbp) +struct hblk *hbp; { -register hdr *phdr; /* Header corresponding to p */ -register struct hblk *hbp, *prevhbp; -register hdr *hhdr, *prevhdr; -register signed_word size; +struct hblk *next, *prev; +hdr *hhdr, *prevhdr, *nexthdr; +signed_word size; - /* GC_savhbp may become invalid due to coalescing. Clear it. */ - GC_savhbp = (struct hblk *)0; - phdr = HDR(p); - size = phdr->hb_sz; - size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size); - GC_remove_counts(p, (word)size); - phdr->hb_sz = size; - GC_invalidate_map(phdr); - prevhbp = 0; - - /* The following optimization was suggested by David Detlefs. */ - /* Note that the header cannot be NIL, since there cannot be an */ - /* intervening call to GC_freehblk without resetting */ - /* GC_freehblk_ptr. */ - if (GC_freehblk_ptr != 0 && - HDR(GC_freehblk_ptr)->hb_map == GC_invalid_map && - (ptr_t)GC_freehblk_ptr < (ptr_t)p) { - hbp = GC_freehblk_ptr; - } else { - hbp = GC_hblkfreelist; - }; hhdr = HDR(hbp); - - while( (hbp != 0) && (hbp < p) ) { - prevhbp = hbp; - prevhdr = hhdr; - hbp = hhdr->hb_next; - hhdr = HDR(hbp); - } - GC_freehblk_ptr = prevhbp; + size = hhdr->hb_sz; + size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size); + GC_remove_counts(hbp, (word)size); + hhdr->hb_sz = size; /* Check for duplicate deallocation in the easy case */ - if (hbp != 0 && (ptr_t)p + size > (ptr_t)hbp - || prevhbp != 0 && (ptr_t)prevhbp + prevhdr->hb_sz > (ptr_t)p) { + if (HBLK_IS_FREE(hhdr)) { GC_printf1("Duplicate large block deallocation of 0x%lx\n", - (unsigned long) p); - GC_printf2("Surrounding free blocks are 0x%lx and 0x%lx\n", - (unsigned long) prevhbp, (unsigned long) hbp); + (unsigned long) hbp); } + GC_ASSERT(IS_MAPPED(hhdr)); + GC_invalidate_map(hhdr); + next = (struct hblk *)((word)hbp + size); + nexthdr = HDR(next); + prev = GC_free_block_ending_at(hbp); /* Coalesce with successor, if possible */ - if( (((word)p)+size) == ((word)hbp) ) { - phdr->hb_next = hhdr->hb_next; - phdr->hb_sz += hhdr->hb_sz; - GC_remove_header(hbp); - } else { - phdr->hb_next = hbp; + if(0 != nexthdr && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)) { + GC_remove_from_fl(nexthdr, FL_UNKNOWN); + hhdr -> hb_sz += nexthdr -> hb_sz; + GC_remove_header(next); + } + /* Coalesce with predecessor, if possible. */ + if (0 != prev) { + prevhdr = HDR(prev); + if (IS_MAPPED(prevhdr)) { + GC_remove_from_fl(prevhdr, FL_UNKNOWN); + prevhdr -> hb_sz += hhdr -> hb_sz; + GC_remove_header(hbp); + hbp = prev; + hhdr = prevhdr; + } } - - if( prevhbp == 0 ) { - GC_hblkfreelist = p; - } else if( (((word)prevhbp) + prevhdr->hb_sz) - == ((word)p) ) { - /* Coalesce with predecessor */ - prevhdr->hb_next = phdr->hb_next; - prevhdr->hb_sz += phdr->hb_sz; - GC_remove_header(p); - } else { - prevhdr->hb_next = p; - } + GC_large_free_bytes += size; + GC_add_to_fl(hbp, hhdr); } diff --git a/boehm-gc/alloc.c b/boehm-gc/alloc.c index c9d145e0369..3d0ddf05b36 100644 --- a/boehm-gc/alloc.c +++ b/boehm-gc/alloc.c @@ -1,6 +1,8 @@ /* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. + * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. + * Copyright (c) 1998 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -12,7 +14,6 @@ * modified is included with the above copyright notice. * */ -/* Boehm, February 16, 1996 2:26 pm PST */ # include "gc_priv.h" @@ -58,15 +59,25 @@ word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */ word GC_gc_no = 0; -int GC_incremental = 0; /* By default, stop the world. */ +#ifndef SMALL_CONFIG + int GC_incremental = 0; /* By default, stop the world. */ +#endif + +int GC_full_freq = 19; /* Every 20th collection is a full */ + /* collection, whether we need it */ + /* or not. */ + +GC_bool GC_need_full_gc = FALSE; + /* Need full GC do to heap growth. */ -int GC_full_freq = 4; /* Every 5th collection is a full */ - /* collection. */ +#define USED_HEAP_SIZE (GC_heapsize - GC_large_free_bytes) + +word GC_used_heap_size_after_full = 0; char * GC_copyright[] = {"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ", "Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. ", -"Copyright (c) 1996-1997 by Silicon Graphics. All rights reserved. ", +"Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved. ", "THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY", " EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.", "See source code for details." }; @@ -80,16 +91,24 @@ extern signed_word GC_mem_found; /* Number of reclaimed longwords */ GC_bool GC_dont_expand = 0; -word GC_free_space_divisor = 4; +word GC_free_space_divisor = 3; extern GC_bool GC_collection_in_progress(); + /* Collection is in progress, or was abandoned. */ int GC_never_stop_func GC_PROTO((void)) { return(0); } -CLOCK_TYPE GC_start_time; +CLOCK_TYPE GC_start_time; /* Time at which we stopped world. */ + /* used only in GC_timeout_stop_func. */ -int GC_timeout_stop_func GC_PROTO((void)) -{ +int GC_n_attempts = 0; /* Number of attempts at finishing */ + /* collection within TIME_LIMIT */ + +#ifdef SMALL_CONFIG +# define GC_timeout_stop_func GC_never_stop_func +#else + int GC_timeout_stop_func GC_PROTO((void)) + { CLOCK_TYPE current_time; static unsigned count = 0; unsigned long time_diff; @@ -101,13 +120,15 @@ int GC_timeout_stop_func GC_PROTO((void)) if (time_diff >= TIME_LIMIT) { # ifdef PRINTSTATS GC_printf0("Abandoning stopped marking after "); - GC_printf1("%lu msecs\n", (unsigned long)time_diff); + GC_printf1("%lu msecs", (unsigned long)time_diff); + GC_printf1("(attempt %d)\n", (unsigned long) GC_n_attempts); # endif return(1); } #endif return(0); -} + } +#endif /* !SMALL_CONFIG */ /* Return the minimum number of words that must be allocated between */ /* collections to amortize the collection cost. */ @@ -120,18 +141,22 @@ static word min_words_allocd() int dummy; register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom; # endif - register word total_root_size; /* includes double stack size, */ + word total_root_size; /* includes double stack size, */ /* since the stack is expensive */ /* to scan. */ + word scan_size; /* Estimate of memory to be scanned */ + /* during normal GC. */ if (stack_size < 0) stack_size = -stack_size; total_root_size = 2 * stack_size + GC_root_size; + scan_size = BYTES_TO_WORDS(GC_heapsize - GC_large_free_bytes + + (GC_large_free_bytes >> 2) + /* use a bit more of large empty heap */ + + total_root_size); if (GC_incremental) { - return(BYTES_TO_WORDS(GC_heapsize + total_root_size) - / (2 * GC_free_space_divisor)); + return scan_size / (2 * GC_free_space_divisor); } else { - return(BYTES_TO_WORDS(GC_heapsize + total_root_size) - / GC_free_space_divisor); + return scan_size / GC_free_space_divisor; } } @@ -196,6 +221,7 @@ GC_bool GC_should_collect() return(GC_adj_words_allocd() >= min_words_allocd()); } + void GC_notify_full_gc() { if (GC_start_call_back != (void (*)())0) { @@ -203,6 +229,8 @@ void GC_notify_full_gc() } } +GC_bool GC_is_full_gc = FALSE; + /* * Initiate a garbage collection if appropriate. * Choose judiciously @@ -212,13 +240,14 @@ void GC_notify_full_gc() void GC_maybe_gc() { static int n_partial_gcs = 0; + if (GC_should_collect()) { if (!GC_incremental) { GC_notify_full_gc(); GC_gcollect_inner(); n_partial_gcs = 0; return; - } else if (n_partial_gcs >= GC_full_freq) { + } else if (GC_need_full_gc || n_partial_gcs >= GC_full_freq) { # ifdef PRINTSTATS GC_printf2( "***>Full mark for collection %lu after %ld allocd bytes\n", @@ -230,6 +259,7 @@ void GC_maybe_gc() GC_clear_marks(); n_partial_gcs = 0; GC_notify_full_gc(); + GC_is_full_gc = TRUE; } else { n_partial_gcs++; } @@ -244,7 +274,12 @@ void GC_maybe_gc() GC_save_callers(GC_last_stack); # endif GC_finish_collection(); - } + } else { + if (!GC_is_full_gc) { + /* Count this as the first attempt */ + GC_n_attempts++; + } + } } } @@ -256,7 +291,7 @@ void GC_maybe_gc() GC_bool GC_try_to_collect_inner(stop_func) GC_stop_func stop_func; { - if (GC_collection_in_progress()) { + if (GC_incremental && GC_collection_in_progress()) { # ifdef PRINTSTATS GC_printf0( "GC_try_to_collect_inner: finishing collection in progress\n"); @@ -287,6 +322,7 @@ GC_stop_func stop_func; # ifdef SAVE_CALL_CHAIN GC_save_callers(GC_last_stack); # endif + GC_is_full_gc = TRUE; if (!GC_stopped_mark(stop_func)) { if (!GC_incremental) { /* We're partially done and have no way to complete or use */ @@ -306,32 +342,48 @@ GC_stop_func stop_func; /* * Perform n units of garbage collection work. A unit is intended to touch - * roughly a GC_RATE pages. Every once in a while, we do more than that. + * roughly GC_RATE pages. Every once in a while, we do more than that. + * This needa to be a fairly large number with our current incremental + * GC strategy, since otherwise we allocate too much during GC, and the + * cleanup gets expensive. */ -# define GC_RATE 8 +# 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 */ + /* how long it takes. Doesn't count the initial root scan */ + /* for a full GC. */ int GC_deficit = 0; /* The number of extra calls to GC_mark_some */ /* that we have made. */ - /* Negative values are equivalent to 0. */ void GC_collect_a_little_inner(n) int n; { register int i; - if (GC_collection_in_progress()) { + if (GC_incremental && GC_collection_in_progress()) { for (i = GC_deficit; i < GC_RATE*n; i++) { - if (GC_mark_some()) { + if (GC_mark_some((ptr_t)0)) { /* Need to finish a collection */ # ifdef SAVE_CALL_CHAIN GC_save_callers(GC_last_stack); # endif - (void) GC_stopped_mark(GC_never_stop_func); + if (GC_n_attempts < MAX_PRIOR_ATTEMPTS) { + GET_TIME(GC_start_time); + if (!GC_stopped_mark(GC_timeout_stop_func)) { + GC_n_attempts++; + break; + } + } else { + (void)GC_stopped_mark(GC_never_stop_func); + } GC_finish_collection(); break; } } if (GC_deficit > 0) GC_deficit -= GC_RATE*n; + if (GC_deficit < 0) GC_deficit = 0; } else { GC_maybe_gc(); } @@ -354,15 +406,14 @@ int GC_collect_a_little GC_PROTO(()) /* * Assumes lock is held, signals are disabled. * We stop the world. - * If final is TRUE, then we finish the collection, no matter how long - * it takes. - * Otherwise we may fail and return FALSE if this takes too long. + * If stop_func() ever returns TRUE, we may fail and return FALSE. * Increment GC_gc_no if we succeed. */ GC_bool GC_stopped_mark(stop_func) GC_stop_func stop_func; { register int i; + int dummy; # ifdef PRINTSTATS CLOCK_TYPE start_time, current_time; # endif @@ -393,7 +444,7 @@ GC_stop_func stop_func; START_WORLD(); return(FALSE); } - if (GC_mark_some()) break; + if (GC_mark_some((ptr_t)(&dummy))) break; } GC_gc_no++; @@ -439,7 +490,7 @@ void GC_finish_collection() # ifdef GATHERSTATS GC_mem_found = 0; # endif -# ifdef FIND_LEAK + if (GC_find_leak) { /* Mark all objects on the free list. All objects should be */ /* marked when we're done. */ { @@ -462,25 +513,26 @@ void GC_finish_collection() } } } - /* Check that everything is marked */ GC_start_reclaim(TRUE); -# else + /* The above just checks; it doesn't really reclaim anything. */ + } + + GC_finalize(); +# ifdef STUBBORN_ALLOC + GC_clean_changing_list(); +# endif - GC_finalize(); -# ifdef STUBBORN_ALLOC - GC_clean_changing_list(); -# endif - -# ifdef PRINTTIMES - GET_TIME(finalize_time); -# endif - - /* Clear free list mark bits, in case they got accidentally marked */ - /* Note: HBLKPTR(p) == pointer to head of block containing *p */ - /* 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. */ +# ifdef PRINTTIMES + GET_TIME(finalize_time); +# 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.) */ + /* 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 */ @@ -506,26 +558,37 @@ void GC_finish_collection() } -# ifdef PRINTSTATS +# ifdef PRINTSTATS GC_printf1("Bytes recovered before sweep - f.l. count = %ld\n", (long)WORDS_TO_BYTES(GC_mem_found)); -# endif - +# endif /* Reconstruct free lists to contain everything not marked */ - GC_start_reclaim(FALSE); - -# endif /* !FIND_LEAK */ + GC_start_reclaim(FALSE); + if (GC_is_full_gc) { + GC_used_heap_size_after_full = USED_HEAP_SIZE; + GC_need_full_gc = FALSE; + } else { + GC_need_full_gc = + BYTES_TO_WORDS(USED_HEAP_SIZE - GC_used_heap_size_after_full) + > min_words_allocd(); + } # ifdef PRINTSTATS GC_printf2( - "Immediately reclaimed %ld bytes in heap of size %lu bytes\n", + "Immediately reclaimed %ld bytes in heap of size %lu bytes", (long)WORDS_TO_BYTES(GC_mem_found), (unsigned long)GC_heapsize); - GC_printf2("%lu (atomic) + %lu (composite) collectable bytes in use\n", - (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use), - (unsigned long)WORDS_TO_BYTES(GC_composite_in_use)); +# ifdef USE_MUNMAP + GC_printf1("(%lu unmapped)", GC_unmapped_bytes); +# endif + GC_printf2( + "\n%lu (atomic) + %lu (composite) collectable bytes in use\n", + (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use), + (unsigned long)WORDS_TO_BYTES(GC_composite_in_use)); # endif + GC_n_attempts = 0; + GC_is_full_gc = FALSE; /* Reset or increment counters for next cycle */ GC_words_allocd_before_gc += GC_words_allocd; GC_non_gc_bytes_at_gc = GC_non_gc_bytes; @@ -533,6 +596,9 @@ void GC_finish_collection() GC_words_wasted = 0; GC_mem_freed = 0; +# ifdef USE_MUNMAP + GC_unmap_old(); +# endif # ifdef PRINTTIMES GET_TIME(done_time); GC_printf2("Finalize + initiate sweep took %lu + %lu msecs\n", @@ -576,7 +642,7 @@ void GC_gcollect GC_PROTO(()) word GC_n_heap_sects = 0; /* Number of sections currently in heap. */ /* - * Use the chunk of memory starting at p of syze bytes as part of the heap. + * Use the chunk of memory starting at p of size bytes as part of the heap. * Assumes p is HBLKSIZE aligned, and bytes is a multiple of HBLKSIZE. */ void GC_add_to_heap(p, bytes) @@ -584,6 +650,7 @@ struct hblk *p; word bytes; { word words; + hdr * phdr; if (GC_n_heap_sects >= MAX_HEAP_SECTS) { ABORT("Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS"); @@ -598,7 +665,10 @@ word bytes; GC_heap_sects[GC_n_heap_sects].hs_bytes = bytes; GC_n_heap_sects++; words = BYTES_TO_WORDS(bytes - HDR_BYTES); - HDR(p) -> hb_sz = words; + phdr = HDR(p); + phdr -> hb_sz = words; + phdr -> hb_map = (char *)1; /* A value != GC_invalid_map */ + phdr -> hb_flags = 0; GC_freehblk(p); GC_heapsize += bytes; if ((ptr_t)p <= GC_least_plausible_heap_addr @@ -614,21 +684,6 @@ word bytes; } } -#ifdef PRESERVE_LAST -GC_bool GC_in_last_heap_sect(p) -ptr_t p; -{ - struct HeapSect * last_heap_sect = &(GC_heap_sects[GC_n_heap_sects-1]); - ptr_t start = last_heap_sect -> hs_start; - ptr_t end; - - if (p < start) return FALSE; - end = start + last_heap_sect -> hs_bytes; - if (p >= end) return FALSE; - return TRUE; -} -#endif - # if !defined(NO_DEBUGGING) void GC_print_heap_sects() { @@ -772,7 +827,6 @@ GC_bool GC_collect_or_expand(needed_blocks, ignore_off_page) word needed_blocks; GC_bool ignore_off_page; { - if (!GC_incremental && !GC_dont_gc && GC_should_collect()) { GC_notify_full_gc(); GC_gcollect_inner(); @@ -805,9 +859,11 @@ GC_bool ignore_off_page; WARN("Out of Memory! Returning NIL!\n", 0); return(FALSE); } - } else if (GC_fail_count) { + } else { # ifdef PRINTSTATS - GC_printf0("Memory available again ...\n"); + if (GC_fail_count) { + GC_printf0("Memory available again ...\n"); + } # endif } } diff --git a/boehm-gc/blacklst.c b/boehm-gc/blacklst.c index 44455e5ba47..e5a3a26a8cf 100644 --- a/boehm-gc/blacklst.c +++ b/boehm-gc/blacklst.c @@ -63,11 +63,16 @@ ptr_t p; void (*GC_print_heap_obj)(/* char * s, ptr_t p */) = GC_default_print_heap_obj_proc; -void GC_print_source_ptr(ptr_t p) +void GC_print_source_ptr(p) +ptr_t p; { ptr_t base = GC_base(p); if (0 == base) { - GC_err_printf0("in root set"); + if (0 == p) { + GC_err_printf0("in register"); + } else { + GC_err_printf0("in root set"); + } } else { GC_err_printf0("in object at "); (*GC_print_heap_obj)(base); @@ -140,6 +145,13 @@ void GC_promote_black_lists() if (GC_black_list_spacing < 3 * HBLKSIZE) { GC_black_list_spacing = 3 * HBLKSIZE; } + if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) { + GC_black_list_spacing = MAXHINCR * HBLKSIZE; + /* Makes it easier to allocate really huge blocks, which otherwise */ + /* may have problems with nonuniform blacklist distributions. */ + /* This way we should always succeed immediately after growing the */ + /* heap. */ + } } void GC_unpromote_black_lists() diff --git a/boehm-gc/configure b/boehm-gc/configure index d1510a718c7..f378f3c4367 100755 --- a/boehm-gc/configure +++ b/boehm-gc/configure @@ -25,7 +25,7 @@ ac_help="$ac_help ac_help="$ac_help --with-gnu-ld assume the C compiler uses GNU ld [default=no]" ac_help="$ac_help - --disable-libtool-lock force libtool not to do file locking" + --disable-libtool-lock avoid locking (might break parallel builds)" ac_help="$ac_help --with-target-subdir=SUBDIR configuring with a cross compiler" @@ -57,7 +57,6 @@ program_suffix=NONE program_transform_name=s,x,x, silent= site= -sitefile= srcdir= target=NONE verbose= @@ -172,7 +171,6 @@ Configuration: --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages - --site-file=FILE use FILE as the site file --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX @@ -343,11 +341,6 @@ EOF -site=* | --site=* | --sit=*) site="$ac_optarg" ;; - -site-file | --site-file | --site-fil | --site-fi | --site-f) - ac_prev=sitefile ;; - -site-file=* | --site-file=* | --site-fil=* | --site-fi=* | --site-f=*) - sitefile="$ac_optarg" ;; - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) @@ -513,16 +506,12 @@ fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. -if test -z "$sitefile"; then - if test -z "$CONFIG_SITE"; then - if test "x$prefix" != xNONE; then - CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" - else - CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" - fi +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -else - CONFIG_SITE="$sitefile" fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then @@ -610,7 +599,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:614: checking host system type" >&5 +echo "configure:603: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -631,7 +620,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:635: checking target system type" >&5 +echo "configure:624: checking target system type" >&5 target_alias=$target case "$target_alias" in @@ -649,7 +638,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:653: checking build system type" >&5 +echo "configure:642: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -684,7 +673,7 @@ test "$host_alias" != "$target_alias" && # 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:688: checking for a BSD compatible install" >&5 +echo "configure:677: 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 @@ -737,7 +726,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:741: checking whether build environment is sane" >&5 +echo "configure:730: checking whether build environment is sane" >&5 # Just in case sleep 1 echo timestamp > conftestfile @@ -794,7 +783,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:798: checking whether ${MAKE-make} sets \${MAKE}" >&5 +echo "configure:787: 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 @@ -827,12 +816,12 @@ else fi echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 -echo "configure:831: checking for Cygwin environment" >&5 +echo "configure:820: 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 836 "configure" +#line 825 "configure" #include "confdefs.h" int main() { @@ -843,7 +832,7 @@ int main() { return __CYGWIN__; ; return 0; } EOF -if { (eval echo configure:847: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:836: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_cygwin=yes else @@ -860,19 +849,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:864: checking for mingw32 environment" >&5 +echo "configure:853: 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 869 "configure" +#line 858 "configure" #include "confdefs.h" int main() { return __MINGW32__; ; return 0; } EOF -if { (eval echo configure:876: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:865: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_mingw32=yes else @@ -920,7 +909,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:924: checking host system type" >&5 +echo "configure:913: checking host system type" >&5 host_alias=$host case "$host_alias" in @@ -954,7 +943,7 @@ fi missing_dir=`cd $ac_aux_dir && pwd` echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 -echo "configure:958: checking for working aclocal" >&5 +echo "configure:947: 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. @@ -967,7 +956,7 @@ else fi echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 -echo "configure:971: checking for working autoconf" >&5 +echo "configure:960: 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. @@ -980,7 +969,7 @@ else fi echo $ac_n "checking for working automake""... $ac_c" 1>&6 -echo "configure:984: checking for working automake" >&5 +echo "configure:973: 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. @@ -993,7 +982,7 @@ else fi echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 -echo "configure:997: checking for working autoheader" >&5 +echo "configure:986: 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. @@ -1006,7 +995,7 @@ else fi echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 -echo "configure:1010: checking for working makeinfo" >&5 +echo "configure:999: 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. @@ -1032,7 +1021,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:1036: checking for $ac_word" >&5 +echo "configure:1025: 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 @@ -1062,7 +1051,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:1066: checking for $ac_word" >&5 +echo "configure:1055: 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 @@ -1111,7 +1100,7 @@ fi fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 -echo "configure:1115: checking whether we are using GNU C" >&5 +echo "configure:1104: 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 @@ -1120,7 +1109,7 @@ else yes; #endif EOF -if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1124: \"$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:1113: \"$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 @@ -1135,7 +1124,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:1139: checking whether ${CC-cc} accepts -g" >&5 +echo "configure:1128: 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 @@ -1172,7 +1161,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:1176: checking for $ac_word" >&5 +echo "configure:1165: 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 @@ -1205,7 +1194,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:1209: checking whether we are using GNU C++" >&5 +echo "configure:1198: 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 @@ -1214,7 +1203,7 @@ else yes; #endif EOF -if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1218: \"$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:1207: \"$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 @@ -1229,7 +1218,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:1233: checking whether ${CXX-g++} accepts -g" >&5 +echo "configure:1222: 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 @@ -1262,7 +1251,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:1266: checking build system type" >&5 +echo "configure:1255: checking build system type" >&5 build_alias=$build case "$build_alias" in @@ -1283,7 +1272,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:1287: checking for $ac_word" >&5 +echo "configure:1276: 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 @@ -1315,7 +1304,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:1319: checking for $ac_word" >&5 +echo "configure:1308: 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 @@ -1347,7 +1336,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:1351: checking for $ac_word" >&5 +echo "configure:1340: 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 @@ -1379,7 +1368,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:1383: checking for $ac_word" >&5 +echo "configure:1372: 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 @@ -1424,7 +1413,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:1428: checking for a BSD compatible install" >&5 +echo "configure:1417: 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 @@ -1478,7 +1467,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:1482: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "configure:1471: 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" @@ -1512,7 +1501,7 @@ if false; then echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:1516: checking for executable suffix" >&5 +echo "configure:1505: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1522,7 +1511,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:1526: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:1515: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; @@ -1636,7 +1625,7 @@ fi # 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:1640: checking for $ac_word" >&5 +echo "configure:1629: 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 @@ -1675,11 +1664,11 @@ ac_prog=ld if test "$ac_cv_prog_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:1679: checking for ld used by GCC" >&5 +echo "configure:1668: checking for ld used by GCC" >&5 ac_prog=`($CC -print-prog-name=ld) 2>&5` case "$ac_prog" in # Accept absolute paths. - /* | [A-Za-z]:[\\/]*) + [\\/]* | [A-Za-z]:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the path of ld ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` @@ -1699,19 +1688,19 @@ echo "configure:1679: 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:1703: checking for GNU ld" >&5 +echo "configure:1692: checking for GNU ld" >&5 else echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6 -echo "configure:1706: checking for non-GNU ld" >&5 +echo "configure:1695: checking for non-GNU ld" >&5 fi if eval "test \"`echo '$''{'ac_cv_path_LD'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -z "$LD"; then - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog"; then + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then ac_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some GNU ld's only accept -v. @@ -1738,7 +1727,7 @@ 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:1742: checking if the linker ($LD) is GNU ld" >&5 +echo "configure:1731: checking if the linker ($LD) is GNU ld" >&5 if eval "test \"`echo '$''{'ac_cv_prog_gnu_ld'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1754,7 +1743,7 @@ echo "$ac_t""$ac_cv_prog_gnu_ld" 1>&6 echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6 -echo "configure:1758: checking for BSD-compatible nm" >&5 +echo "configure:1747: checking for BSD-compatible nm" >&5 if eval "test \"`echo '$''{'ac_cv_path_NM'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -1762,10 +1751,10 @@ else # Let the user override the test. ac_cv_path_NM="$NM" else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" for ac_dir in $PATH /usr/ccs/bin /usr/ucb /bin; do test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/nm; then + if test -f $ac_dir/nm || test -f $ac_dir/nm$ac_exeext ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored @@ -1790,212 +1779,8 @@ NM="$ac_cv_path_NM" echo "$ac_t""$NM" 1>&6 -# Check for command to grab the raw symbol name followed by C symbol from nm. -echo $ac_n "checking command to parse $NM output""... $ac_c" 1>&6 -echo "configure:1796: checking command to parse $NM output" >&5 -if eval "test \"`echo '$''{'ac_cv_sys_global_symbol_pipe'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - # These are sane defaults that work on at least a few old systems. -# {They come from Ultrix. What could be older than Ultrix?!! ;)} - -# Character class describing NM global symbol codes. -ac_symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -ac_sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Transform the above into a raw symbol and a C symbol. -ac_symxfrm='\1 \2\3 \3' - -# Transform an extracted symbol line into a proper C declaration -ac_global_symbol_to_cdecl="sed -n -e 's/^. .* \(.*\)$/extern char \1;/p'" - -# Define system-specific variables. -case "$host_os" in -aix*) - ac_symcode='[BCDT]' - ;; -cygwin* | mingw*) - ac_symcode='[ABCDGISTW]' - ;; -hpux*) - ac_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern char \1();/p' -e 's/^. .* \(.*\)$/extern char \1;/p'" - ;; -irix*) - ac_symcode='[BCDEGRST]' - ;; -solaris*) - ac_symcode='[BDT]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then - ac_symcode='[ABCDGISTW]' -fi - -# Try without a prefix undercore, then with it. -for ac_symprfx in "" "_"; do - - ac_cv_sys_global_symbol_pipe="sed -n -e 's/^.* \($ac_symcode\) *\($ac_symprfx\)$ac_sympat$/$ac_symxfrm/p'" - - # Check to see that the pipe works correctly. - ac_pipe_works=no - rm -f conftest.$ac_ext - cat > conftest.$ac_ext <<EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(){} -#ifdef __cplusplus -} -#endif -int main(){nm_test_var='a';nm_test_func;return 0;} -EOF - - if { (eval echo configure:1859: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - # Now try to grab the symbols. - ac_nlist=conftest.nm - - if { (eval echo configure:1863: \"$NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist\") 1>&5; (eval $NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5; } && test -s "$ac_nlist"; then - - # Try sorting and uniquifying the output. - if sort "$ac_nlist" | uniq > "$ac_nlist"T; then - mv -f "$ac_nlist"T "$ac_nlist" - else - rm -f "$ac_nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if egrep ' nm_test_var$' "$ac_nlist" >/dev/null; then - if egrep ' nm_test_func$' "$ac_nlist" >/dev/null; then - cat <<EOF > conftest.c -#ifdef __cplusplus -extern "C" { -#endif - -EOF - # Now generate the symbol file. - eval "$ac_global_symbol_to_cdecl"' < "$ac_nlist" >> conftest.c' - - cat <<EOF >> conftest.c -#if defined (__STDC__) && __STDC__ -# define lt_ptr_t void * -#else -# define lt_ptr_t char * -# define const -#endif - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - lt_ptr_t address; -} -lt_preloaded_symbols[] = -{ -EOF - sed 's/^. \(.*\) \(.*\)$/ {"\2", (lt_ptr_t) \&\2},/' < "$ac_nlist" >> conftest.c - cat <<\EOF >> conftest.c - {0, (lt_ptr_t) 0} -}; - -#ifdef __cplusplus -} -#endif -EOF - # Now try linking the two files. - mv conftest.$ac_objext conftestm.$ac_objext - ac_save_LIBS="$LIBS" - ac_save_CFLAGS="$CFLAGS" - LIBS="conftestm.$ac_objext" - CFLAGS="$CFLAGS$no_builtin_flag" - if { (eval echo configure:1915: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then - ac_pipe_works=yes - else - echo "configure: failed program was:" >&5 - cat conftest.c >&5 - fi - LIBS="$ac_save_LIBS" - CFLAGS="$ac_save_CFLAGS" - else - echo "cannot find nm_test_func in $ac_nlist" >&5 - fi - else - echo "cannot find nm_test_var in $ac_nlist" >&5 - fi - else - echo "cannot run $ac_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.c >&5 - fi - rm -rf conftest* - - # Do not use the global_symbol_pipe unless it works. - if test "$ac_pipe_works" = yes; then - if test x"$ac_symprfx" = x"_"; then - ac_cv_sys_symbol_underscore=yes - else - ac_cv_sys_symbol_underscore=no - fi - break - else - ac_cv_sys_global_symbol_pipe= - fi -done - -fi - - -ac_result=yes -if test -z "$ac_cv_sys_global_symbol_pipe"; then - ac_result=no -fi -echo "$ac_t""$ac_result" 1>&6 - -echo $ac_n "checking for _ prefix in compiled symbols""... $ac_c" 1>&6 -echo "configure:1961: checking for _ prefix in compiled symbols" >&5 -if eval "test \"`echo '$''{'ac_cv_sys_symbol_underscore'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_cv_sys_symbol_underscore=no -cat > conftest.$ac_ext <<EOF -void nm_test_func(){} -int main(){nm_test_func;return 0;} -EOF -if { (eval echo configure:1970: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - # Now try to grab the symbols. - ac_nlist=conftest.nm - if { (eval echo configure:1973: \"$NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist\") 1>&5; (eval $NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) 2>&5; } && test -s "$ac_nlist"; then - # See whether the symbols have a leading underscore. - if egrep '^. _nm_test_func' "$ac_nlist" >/dev/null; then - ac_cv_sys_symbol_underscore=yes - else - if egrep '^. nm_test_func ' "$ac_nlist" >/dev/null; then - : - else - echo "configure: cannot find nm_test_func in $ac_nlist" >&5 - fi - fi - else - echo "configure: cannot run $ac_cv_sys_global_symbol_pipe" >&5 - fi -else - echo "configure: failed program was:" >&5 - cat conftest.c >&5 -fi -rm -rf conftest* - -fi - -echo "$ac_t""$ac_cv_sys_symbol_underscore" 1>&6 -USE_SYMBOL_UNDERSCORE=${ac_cv_sys_symbol_underscore=no} - echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6 -echo "configure:1999: checking whether ln -s works" >&5 +echo "configure:1784: 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 @@ -2021,18 +1806,26 @@ libtool_flags="--cache-file=$cache_file" test "$enable_shared" = no && libtool_flags="$libtool_flags --disable-shared" test "$enable_static" = no && libtool_flags="$libtool_flags --disable-static" test "$enable_fast_install" = no && libtool_flags="$libtool_flags --disable-fast-install" -test "$lt_dlopen" = yes && libtool_flags="$libtool_flags --enable-dlopen" -test "$silent" = yes && libtool_flags="$libtool_flags --silent" test "$ac_cv_prog_gcc" = yes && libtool_flags="$libtool_flags --with-gcc" test "$ac_cv_prog_gnu_ld" = yes && libtool_flags="$libtool_flags --with-gnu-ld" + +# Check whether --enable-libtool-lock or --disable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then + enableval="$enable_libtool_lock" + : +fi + +test "x$enable_libtool_lock" = xno && libtool_flags="$libtool_flags --disable-lock" +test x"$silent" = xyes && libtool_flags="$libtool_flags --silent" + # Some flags need to be propagated to the compiler or linker for good # libtool support. case "$host" in *-*-irix6*) # Find out which ABI we are using. - echo '#line 2035 "configure"' > conftest.$ac_ext - if { (eval echo configure:2036: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + echo '#line 1828 "configure"' > conftest.$ac_ext + if { (eval echo configure:1829: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then case "`/usr/bin/file conftest.o`" in *32-bit*) LD="${LD-ld} -32" @@ -2053,19 +1846,19 @@ 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:2057: checking whether the C compiler needs -belf" >&5 +echo "configure:1850: 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 cat > conftest.$ac_ext <<EOF -#line 2062 "configure" +#line 1855 "configure" #include "confdefs.h" int main() { ; return 0; } EOF -if { (eval echo configure:2069: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1862: \"$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 @@ -2084,161 +1877,9 @@ echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6 fi ;; -*-*-cygwin*) - # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. -set dummy ${ac_tool_prefix}dlltool; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2092: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -DLLTOOL="$ac_cv_prog_DLLTOOL" -if test -n "$DLLTOOL"; then - echo "$ac_t""$DLLTOOL" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - -if test -z "$ac_cv_prog_DLLTOOL"; then -if test -n "$ac_tool_prefix"; then - # Extract the first word of "dlltool", so it can be a program name with args. -set dummy dlltool; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2124: checking for $ac_word" >&5 -if eval "test \"`echo '$''{'ac_cv_prog_DLLTOOL'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - if test -n "$DLLTOOL"; then - ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_DLLTOOL="dlltool" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_DLLTOOL" && ac_cv_prog_DLLTOOL="false" -fi -fi -DLLTOOL="$ac_cv_prog_DLLTOOL" -if test -n "$DLLTOOL"; then - echo "$ac_t""$DLLTOOL" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -else - DLLTOOL="false" -fi -fi - -# 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:2159: 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 - if test -n "$AS"; then - ac_cv_prog_AS="$AS" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_AS="${ac_tool_prefix}as" - break - fi - done - IFS="$ac_save_ifs" -fi -fi -AS="$ac_cv_prog_AS" -if test -n "$AS"; then - echo "$ac_t""$AS" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - - -if test -z "$ac_cv_prog_AS"; then -if test -n "$ac_tool_prefix"; then - # Extract the first word of "as", so it can be a program name with args. -set dummy as; ac_word=$2 -echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 -echo "configure:2191: 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 - if test -n "$AS"; then - ac_cv_prog_AS="$AS" # Let the user override the test. -else - IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" - ac_dummy="$PATH" - for ac_dir in $ac_dummy; do - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/$ac_word; then - ac_cv_prog_AS="as" - break - fi - done - IFS="$ac_save_ifs" - test -z "$ac_cv_prog_AS" && ac_cv_prog_AS="false" -fi -fi -AS="$ac_cv_prog_AS" -if test -n "$AS"; then - echo "$ac_t""$AS" 1>&6 -else - echo "$ac_t""no" 1>&6 -fi - -else - AS="false" -fi -fi - - - ;; esac -# enable the --disable-libtool-lock switch - -# Check whether --enable-libtool-lock or --disable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then - enableval="$enable_libtool_lock" - need_locks=$enableval -else - need_locks=yes -fi - - -if test x"$need_locks" = xno; then - libtool_flags="$libtool_flags --disable-lock" -fi - # Save cache, so that ltconfig can load it cat > confcache <<\EOF @@ -2291,8 +1932,9 @@ rm -f confcache # Actually configure libtool. ac_aux_dir is where install-sh is found. CC="$CC" CFLAGS="$CFLAGS" CPPFLAGS="$CPPFLAGS" \ -LD="$LD" NM="$NM" RANLIB="$RANLIB" LN_S="$LN_S" \ -DLLTOOL="$DLLTOOL" AS="$AS" \ +LD="$LD" LDFLAGS="$LDFLAGS" LIBS="$LIBS" \ +LN_S="$LN_S" NM="$NM" RANLIB="$RANLIB" \ +DLLTOOL="$DLLTOOL" AS="$AS" OBJDUMP="$OBJDUMP" \ ${CONFIG_SHELL-/bin/sh} $ac_aux_dir/ltconfig --no-reexec \ $libtool_flags --no-verify $ac_aux_dir/ltmain.sh $host \ || { echo "configure: error: libtool configure failed" 1>&2; exit 1; } @@ -2332,7 +1974,7 @@ fi echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 -echo "configure:2336: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo "configure:1978: 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" @@ -2361,7 +2003,7 @@ if test "x" = "y"; then echo $ac_n "checking for executable suffix""... $ac_c" 1>&6 -echo "configure:2365: checking for executable suffix" >&5 +echo "configure:2007: checking for executable suffix" >&5 if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else @@ -2371,7 +2013,7 @@ else rm -f conftest* echo 'int main () { return 0; }' > conftest.$ac_ext ac_cv_exeext= - if { (eval echo configure:2375: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then + if { (eval echo configure:2017: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then for file in conftest.*; do case $file in *.c | *.o | *.obj | *.ilk | *.pdb) ;; @@ -2394,7 +2036,7 @@ ac_exeext=$EXEEXT fi echo $ac_n "checking for threads package to use""... $ac_c" 1>&6 -echo "configure:2398: checking for threads package to use" >&5 +echo "configure:2040: 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" @@ -2434,6 +2076,7 @@ if test "$THREADS" = yes; then fi INCLUDES= +THREADLIB= case "$THREADS" in no | none | single) THREADS=none @@ -2468,6 +2111,7 @@ EOF ;; esac + THREADLIB=-lpthread ;; qt) cat >> confdefs.h <<\EOF @@ -2475,6 +2119,7 @@ EOF EOF INCLUDES="-I${boehm_gc_basedir}/../qthreads" + THREADLIB=../qthreads/libgcjcoop.la ;; decosf1 | irix | mach | os2 | solaris | win32 | dce | vxworks) { echo "configure: error: thread package $THREADS not yet supported" 1>&2; exit 1; } @@ -2485,6 +2130,7 @@ EOF esac echo "$ac_t""$THREADS" 1>&6 + # Check whether --enable-java-gc or --disable-java-gc was given. if test "${enable_java_gc+set}" = set; then enableval="$enable_java_gc" @@ -2822,10 +2468,9 @@ s%@EXEEXT@%$EXEEXT%g s%@BOEHM_GC_CFLAGS@%$BOEHM_GC_CFLAGS%g s%@LD@%$LD%g s%@NM@%$NM%g -s%@USE_SYMBOL_UNDERSCORE@%$USE_SYMBOL_UNDERSCORE%g s%@LN_S@%$LN_S%g -s%@DLLTOOL@%$DLLTOOL%g s%@LIBTOOL@%$LIBTOOL%g +s%@THREADLIB@%$THREADLIB%g s%@target_all@%$target_all%g s%@INCLUDES@%$INCLUDES%g s%@CXXINCLUDES@%$CXXINCLUDES%g diff --git a/boehm-gc/configure.in b/boehm-gc/configure.in index 182277a3cd4..29725423b2a 100644 --- a/boehm-gc/configure.in +++ b/boehm-gc/configure.in @@ -62,6 +62,7 @@ if test "$THREADS" = yes; then fi INCLUDES= +THREADLIB= case "$THREADS" in no | none | single) THREADS=none @@ -81,10 +82,12 @@ case "$THREADS" in AC_DEFINE(IRIX_THREADS) ;; esac + THREADLIB=-lpthread ;; qt) AC_DEFINE(QUICK_THREADS) INCLUDES="-I${boehm_gc_basedir}/../qthreads" + THREADLIB=../qthreads/libgcjcoop.la ;; decosf1 | irix | mach | os2 | solaris | win32 | dce | vxworks) AC_MSG_ERROR(thread package $THREADS not yet supported) @@ -94,6 +97,7 @@ case "$THREADS" in ;; esac AC_MSG_RESULT($THREADS) +AC_SUBST(THREADLIB) AC_ARG_ENABLE(java-gc, changequote(<<,>>)dnl diff --git a/boehm-gc/dbg_mlc.c b/boehm-gc/dbg_mlc.c index 079e43be7cb..cf6514b2836 100644 --- a/boehm-gc/dbg_mlc.c +++ b/boehm-gc/dbg_mlc.c @@ -12,8 +12,16 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, October 9, 1995 1:16 pm PDT */ +# define I_HIDE_POINTERS # include "gc_priv.h" +# ifdef KEEP_BACK_PTRS +# include "backptr.h" +# endif + +void GC_default_print_heap_obj_proc(); +GC_API void GC_register_finalizer_no_order + GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, + GC_finalization_proc *ofn, GC_PTR *ocd)); /* Do we want to and know how to save the call stack at the time of */ /* an allocation? How much space do we want to use in each object? */ @@ -26,6 +34,14 @@ /* Object header */ typedef struct { +# ifdef KEEP_BACK_PTRS + ptr_t oh_back_ptr; +# define MARKED_FOR_FINALIZATION (ptr_t)(-1) + /* Object was marked because it is finalizable. */ +# ifdef ALIGN_DOUBLE + word oh_dummy; +# endif +# endif char * oh_string; /* object descriptor string */ word oh_int; /* object descriptor integers */ # ifdef NEED_CALLINFO @@ -80,15 +96,133 @@ ptr_t p; return(FALSE); } -/* Return start of object that might have debugging info. */ -ptr_t GC_debug_object_start(p) -ptr_t p; -{ - register word * result = (word *)((oh *)p + 1); - if (! GC_has_debug_info(p)) - return(p); - return((ptr_t)result); -} +#ifdef KEEP_BACK_PTRS + /* Store back pointer to source in dest, if that appears to be possible. */ + /* This is not completely safe, since we may mistakenly conclude that */ + /* dest has a debugging wrapper. But the error probability is very */ + /* small, and this shouldn't be used in production code. */ + /* We assume that dest is the real base pointer. Source will usually */ + /* be a pointer to the interior of an object. */ + void GC_store_back_pointer(ptr_t source, ptr_t dest) + { + if (GC_has_debug_info(dest)) { + ((oh *)dest) -> oh_back_ptr = (ptr_t)HIDE_POINTER(source); + } + } + + void GC_marked_for_finalization(ptr_t dest) { + GC_store_back_pointer(MARKED_FOR_FINALIZATION, dest); + } + + /* Store information about the object referencing dest in *base_p */ + /* and *offset_p. */ + /* source is root ==> *base_p = 0, *offset_p = address */ + /* source is heap object ==> *base_p != 0, *offset_p = offset */ + /* Returns 1 on success, 0 if source couldn't be determined. */ + /* Dest can be any address within a heap object. */ + GC_ref_kind GC_get_back_ptr_info(void *dest, void **base_p, size_t *offset_p) + { + oh * hdr = (oh *)GC_base(dest); + ptr_t bp; + ptr_t bp_base; + if (!GC_has_debug_info((ptr_t) hdr)) return GC_NO_SPACE; + bp = hdr -> oh_back_ptr; + if (MARKED_FOR_FINALIZATION == bp) return GC_FINALIZER_REFD; + if (0 == bp) return GC_UNREFERENCED; + bp = REVEAL_POINTER(bp); + bp_base = GC_base(bp); + if (0 == bp_base) { + *base_p = bp; + *offset_p = 0; + return GC_REFD_FROM_ROOT; + } else { + if (GC_has_debug_info(bp_base)) bp_base += sizeof(oh); + *base_p = bp_base; + *offset_p = bp - bp_base; + return GC_REFD_FROM_HEAP; + } + } + + /* Generate a random heap address. */ + /* The resulting address is in the heap, but */ + /* not necessarily inside a valid object. */ + void *GC_generate_random_heap_address(void) + { + int i; + int heap_offset = random() % GC_heapsize; + for (i = 0; i < GC_n_heap_sects; ++ i) { + int size = GC_heap_sects[i].hs_bytes; + if (heap_offset < size) { + return GC_heap_sects[i].hs_start + heap_offset; + } else { + heap_offset -= size; + } + } + ABORT("GC_generate_random_heap_address: size inconsistency"); + /*NOTREACHED*/ + return 0; + } + + /* Generate a random address inside a valid marked heap object. */ + void *GC_generate_random_valid_address(void) + { + ptr_t result; + ptr_t base; + for (;;) { + result = GC_generate_random_heap_address(); + base = GC_base(result); + if (0 == base) continue; + if (!GC_is_marked(base)) continue; + return result; + } + } + + /* Force a garbage collection and generate a backtrace from a */ + /* random heap address. */ + void GC_generate_random_backtrace(void) + { + void * current; + int i; + void * base; + size_t offset; + GC_ref_kind source; + GC_gcollect(); + current = GC_generate_random_valid_address(); + GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current); + GC_print_heap_obj(GC_base(current)); + GC_err_printf0("\n"); + for (i = 0; ; ++i) { + source = GC_get_back_ptr_info(current, &base, &offset); + if (GC_UNREFERENCED == source) { + GC_err_printf0("Reference could not be found\n"); + goto out; + } + if (GC_NO_SPACE == source) { + GC_err_printf0("No debug info in object: Can't find reference\n"); + goto out; + } + GC_err_printf1("Reachable via %d levels of pointers from ", + (unsigned long)i); + switch(source) { + case GC_REFD_FROM_ROOT: + GC_err_printf1("root at 0x%lx\n", (unsigned long)base); + goto out; + case GC_FINALIZER_REFD: + GC_err_printf0("list of finalizable objects\n"); + goto out; + case GC_REFD_FROM_HEAP: + GC_err_printf1("offset %ld in object:\n", (unsigned long)offset); + /* Take GC_base(base) to get real base, i.e. header. */ + GC_print_heap_obj(GC_base(base)); + GC_err_printf0("\n"); + break; + } + current = base; + } + out:; + } + +#endif /* KEEP_BACK_PTRS */ /* Store debugging info into p. Return displaced pointer. */ /* Assumes we don't hold allocation lock. */ @@ -105,6 +239,9 @@ word integer; /* But that's expensive. And this way things should only appear */ /* inconsistent while we're in the handler. */ LOCK(); +# ifdef KEEP_BACK_PTRS + ((oh *)p) -> oh_back_ptr = 0; +# endif ((oh *)p) -> oh_string = string; ((oh *)p) -> oh_int = integer; ((oh *)p) -> oh_sz = sz; @@ -115,7 +252,7 @@ word integer; return((ptr_t)result); } -/* Check the object with debugging info at p */ +/* Check the object with debugging info at ohdr */ /* return NIL if it's OK. Else return clobbered */ /* address. */ ptr_t GC_check_annotated_obj(ohdr) @@ -144,7 +281,7 @@ ptr_t p; { register oh * ohdr = (oh *)GC_base(p); - GC_err_printf1("0x%lx (", (unsigned long)ohdr + sizeof(oh)); + GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh))); GC_err_puts(ohdr -> oh_string); GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int), (unsigned long)(ohdr -> oh_sz)); @@ -171,7 +308,7 @@ ptr_t p, clobbered_addr; if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz)) || ohdr -> oh_string == 0) { GC_err_printf1("<smashed>, appr. sz = %ld)\n", - GC_size((ptr_t)ohdr) - DEBUG_BYTES); + (GC_size((ptr_t)ohdr) - DEBUG_BYTES)); } else { if (ohdr -> oh_string[0] == '\0') { GC_err_puts("EMPTY(smashed?)"); @@ -206,10 +343,10 @@ void GC_start_debugging() } # ifdef GC_ADD_CALLER -# define EXTRA_ARGS word ra, char * s, int i +# define EXTRA_ARGS word ra, CONST char * s, int i # define OPT_RA ra, # else -# define EXTRA_ARGS char * s, int i +# define EXTRA_ARGS CONST char * s, int i # define OPT_RA # endif @@ -423,13 +560,15 @@ GC_PTR p; GC_PTR p; # endif { - register GC_PTR base = GC_base(p); + register GC_PTR base; register ptr_t clobbered; + if (0 == p) return; + base = GC_base(p); if (base == 0) { GC_err_printf1("Attempt to free invalid pointer %lx\n", (unsigned long)p); - if (p != 0) ABORT("free(invalid pointer)"); + ABORT("free(invalid pointer)"); } if ((ptr_t)p - (ptr_t)base != sizeof(oh)) { GC_err_printf1( @@ -442,31 +581,29 @@ GC_PTR p; GC_err_printf0( "GC_debug_free: found previously deallocated (?) object at "); } else { - GC_err_printf0("GC_debug_free: found smashed object at "); + GC_err_printf0("GC_debug_free: found smashed location at "); } GC_print_smashed_obj(p, clobbered); } /* Invalidate size */ ((oh *)base) -> oh_sz = GC_size(base); } -# ifdef FIND_LEAK + if (GC_find_leak) { GC_free(base); -# else - { - register hdr * hhdr = HDR(p); - GC_bool uncollectable = FALSE; + } else { + register hdr * hhdr = HDR(p); + GC_bool uncollectable = FALSE; - if (hhdr -> hb_obj_kind == UNCOLLECTABLE) { - uncollectable = TRUE; - } -# ifdef ATOMIC_UNCOLLECTABLE - if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) { - uncollectable = TRUE; - } -# endif - if (uncollectable) GC_free(base); + if (hhdr -> hb_obj_kind == UNCOLLECTABLE) { + uncollectable = TRUE; } -# endif +# ifdef ATOMIC_UNCOLLECTABLE + if (hhdr -> hb_obj_kind == AUNCOLLECTABLE) { + uncollectable = TRUE; + } +# endif + if (uncollectable) GC_free(base); + } /* !GC_find_leak */ } # ifdef __STDC__ @@ -525,7 +662,7 @@ GC_PTR p; } clobbered = GC_check_annotated_obj((oh *)base); if (clobbered != 0) { - GC_err_printf0("GC_debug_realloc: found smashed object at "); + GC_err_printf0("GC_debug_realloc: found smashed location at "); GC_print_smashed_obj(p, clobbered); } old_sz = ((oh *)base) -> oh_sz; @@ -562,7 +699,7 @@ word dummy; if (clobbered != 0) { GC_err_printf0( - "GC_check_heap_block: found smashed object at "); + "GC_check_heap_block: found smashed location at "); GC_print_smashed_obj((ptr_t)p, clobbered); } } @@ -643,12 +780,12 @@ struct closure { } # ifdef __STDC__ - void GC_debug_register_finalizer_ignore_self + void GC_debug_register_finalizer_no_order (GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd) # else - void GC_debug_register_finalizer_ignore_self + void GC_debug_register_finalizer_no_order (obj, fn, cd, ofn, ocd) GC_PTR obj; GC_finalization_proc fn; @@ -660,15 +797,15 @@ struct closure { ptr_t base = GC_base(obj); if (0 == base || (ptr_t)obj - base != sizeof(oh)) { GC_err_printf1( - "GC_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n", - obj); + "GC_register_finalizer_no_order called with non-base-pointer 0x%lx\n", + obj); } - GC_register_finalizer_ignore_self(base, GC_debug_invoke_finalizer, - GC_make_closure(fn,cd), ofn, ocd); -} + GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer, + GC_make_closure(fn,cd), ofn, ocd); + } # ifdef __STDC__ - void GC_debug_register_finalizer_no_order + void GC_debug_register_finalizer_ignore_self (GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd) diff --git a/boehm-gc/dyn_load.c b/boehm-gc/dyn_load.c index d0f523c3400..b9de4c11db4 100644 --- a/boehm-gc/dyn_load.c +++ b/boehm-gc/dyn_load.c @@ -47,7 +47,7 @@ #if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR) #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \ !defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \ - !defined(HP_PA) && (!defined(LINUX) && !defined(__ELF__)) && \ + !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \ !defined(RS6000) && !defined(SCO_ELF) --> We only know how to find data segments of dynamic libraries for the --> above. Additional SVR4 variants might not be too @@ -284,11 +284,9 @@ void GC_register_dynamic_libraries() static struct link_map * GC_FirstDLOpenedLinkMap() { -#ifdef __GNUC__ - /* On some Linux systems, `_DYNAMIC' will not be defined when a - static link is done. */ -# pragma weak _DYNAMIC -#endif +# ifdef __GNUC__ +# pragma weak _DYNAMIC +# endif extern ElfW(Dyn) _DYNAMIC[]; ElfW(Dyn) *dp; struct r_debug *r; @@ -356,6 +354,8 @@ void GC_register_dynamic_libraries() #include <errno.h> extern void * GC_roots_present(); + /* The type is a lie, since the real type doesn't make sense here, */ + /* and we only test for NULL. */ extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena */ @@ -382,6 +382,8 @@ void GC_register_dynamic_libraries() if (fd < 0) { sprintf(buf, "/proc/%d", getpid()); + /* The above generates a lint complaint, since pid_t varies. */ + /* It's unclear how to improve this. */ fd = open(buf, O_RDONLY); if (fd < 0) { ABORT("/proc open failed"); @@ -394,7 +396,8 @@ void GC_register_dynamic_libraries() if (needed_sz >= current_sz) { current_sz = needed_sz * 2 + 1; /* Expansion, plus room for 0 record */ - addr_map = (prmap_t *)GC_scratch_alloc(current_sz * sizeof(prmap_t)); + addr_map = (prmap_t *)GC_scratch_alloc((word) + (current_sz * sizeof(prmap_t))); } if (ioctl(fd, PIOCMAP, addr_map) < 0) { GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n", @@ -656,7 +659,7 @@ void GC_register_dynamic_libraries() } #endif -#if defined(HP_PA) +#if defined(HPUX) #include <errno.h> #include <dl.h> @@ -679,6 +682,11 @@ void GC_register_dynamic_libraries() /* Check if this is the end of the list or if some error occured */ if (status != 0) { +# ifdef HPUX_THREADS + /* I've seen errno values of 0. The man page is not clear */ + /* as to whether errno should get set on a -1 return. */ + break; +# else if (errno == EINVAL) { break; /* Moved past end of shared library list --> finished */ } else { @@ -689,6 +697,7 @@ void GC_register_dynamic_libraries() } ABORT("shl_get failed"); } +# endif } # ifdef VERBOSE @@ -711,7 +720,7 @@ void GC_register_dynamic_libraries() index++; } } -#endif /* HP_PA */ +#endif /* HPUX */ #ifdef RS6000 #pragma alloca diff --git a/boehm-gc/finalize.c b/boehm-gc/finalize.c index d825bf91a36..2ee927fe432 100644 --- a/boehm-gc/finalize.c +++ b/boehm-gc/finalize.c @@ -1,6 +1,7 @@ /* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -16,6 +17,18 @@ # include "gc_priv.h" # include "gc_mark.h" +# ifdef FINALIZE_ON_DEMAND + int GC_finalize_on_demand = 1; +# else + int GC_finalize_on_demand = 0; +# endif + +# ifdef JAVA_FINALIZATION + int GC_java_finalization = 1; +# else + int GC_java_finalization = 0; +# endif + /* Type of mark procedure used for marking from finalizable object. */ /* This procedure normally does not mark the object, only its */ /* descendents. */ @@ -249,7 +262,7 @@ out: /* Possible finalization_marker procedures. Note that mark stack */ /* overflow is handled by the caller, and is not a disaster. */ -void GC_normal_finalize_mark_proc(p) +GC_API void GC_normal_finalize_mark_proc(p) ptr_t p; { hdr * hhdr = HDR(p); @@ -261,7 +274,7 @@ ptr_t p; /* This only pays very partial attention to the mark descriptor. */ /* It does the right thing for normal and atomic objects, and treats */ /* most others as normal. */ -void GC_ignore_self_finalize_mark_proc(p) +GC_API void GC_ignore_self_finalize_mark_proc(p) ptr_t p; { hdr * hhdr = HDR(p); @@ -278,13 +291,13 @@ ptr_t p; for (q = p; q <= scan_limit; q += ALIGNMENT) { r = *(ptr_t *)q; if (r < p || r > target_limit) { - GC_PUSH_ONE_HEAP((word)r); + GC_PUSH_ONE_HEAP((word)r, q); } } } /*ARGSUSED*/ -void GC_null_finalize_mark_proc(p) +GC_API void GC_null_finalize_mark_proc(p) ptr_t p; { } @@ -295,7 +308,11 @@ ptr_t p; /* in the nonthreads case, we try to avoid disabling signals, */ /* since it can be expensive. Threads packages typically */ /* make it cheaper. */ -void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp) +/* The last parameter is a procedure that determines */ +/* marking for finalization ordering. Any objects marked */ +/* by that procedure will be guaranteed to not have been */ +/* finalized when this finalizer is invoked. */ +GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp) GC_PTR obj; GC_finalization_proc fn; GC_PTR cd; @@ -505,6 +522,7 @@ void GC_finalize() for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) { real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base); if (!GC_is_marked(real_ptr)) { + GC_MARKED_FOR_FINALIZATION(real_ptr); GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc); if (GC_is_marked(real_ptr)) { WARN("Finalization cycle involving %lx\n", real_ptr); @@ -521,9 +539,9 @@ void GC_finalize() while (curr_fo != 0) { real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base); if (!GC_is_marked(real_ptr)) { -# ifndef JAVA_FINALIZATION - GC_set_mark_bit(real_ptr); -# endif + if (!GC_java_finalization) { + GC_set_mark_bit(real_ptr); + } /* Delete from hash table */ next_fo = fo_next(curr_fo); if (prev_fo == 0) { @@ -555,20 +573,20 @@ void GC_finalize() } } -# ifdef JAVA_FINALIZATION - /* make sure we mark everything reachable from objects finalized - using the no_order mark_proc */ - for (curr_fo = GC_finalize_now; - curr_fo != NULL; curr_fo = fo_next(curr_fo)) { - real_ptr = (ptr_t)curr_fo -> fo_hidden_base; - if (!GC_is_marked(real_ptr)) { - if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) { - GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc); - } - GC_set_mark_bit(real_ptr); - } - } -# endif + if (GC_java_finalization) { + /* make sure we mark everything reachable from objects finalized + using the no_order mark_proc */ + for (curr_fo = GC_finalize_now; + curr_fo != NULL; curr_fo = fo_next(curr_fo)) { + real_ptr = (ptr_t)curr_fo -> fo_hidden_base; + if (!GC_is_marked(real_ptr)) { + if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) { + GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc); + } + GC_set_mark_bit(real_ptr); + } + } + } /* Remove dangling disappearing links. */ for (i = 0; i < dl_size; i++) { @@ -594,7 +612,7 @@ void GC_finalize() } } -#ifdef JAVA_FINALIZATION +#ifndef JAVA_FINALIZATION_NOT_NEEDED /* Enqueue all remaining finalizers to be run - Assumes lock is * held, and signals are disabled */ @@ -648,10 +666,16 @@ void GC_enqueue_all_finalizers() * which can make the runtime guarantee that all finalizers are run. * Unfortunately, the Java standard implies we have to keep running * finalizers until there are no more left, a potential infinite loop. - * YUCK. * This routine is externally callable, so is called without - * the allocation lock + * YUCK. + * Note that this is even more dangerous than the usual Java + * finalizers, in that objects reachable from static variables + * may have been finalized when these finalizers are run. + * Finalizers run at this point must be prepared to deal with a + * mostly broken world. + * This routine is externally callable, so is called without + * the allocation lock. */ -void GC_finalize_all() +GC_API void GC_finalize_all() { DCL_LOCK_STATE; diff --git a/boehm-gc/gc.h b/boehm-gc/gc.h index a4d57e860d1..535ff63ac03 100644 --- a/boehm-gc/gc.h +++ b/boehm-gc/gc.h @@ -36,11 +36,19 @@ #endif #if defined(_MSC_VER) && defined(_DLL) -#ifdef GC_BUILD -#define GC_API __declspec(dllexport) -#else -#define GC_API __declspec(dllimport) +# ifdef GC_BUILD +# define GC_API __declspec(dllexport) +# else +# define GC_API __declspec(dllimport) +# endif #endif + +#if defined(__WATCOMC__) && defined(GC_DLL) +# ifdef GC_BUILD +# define GC_API extern __declspec(dllexport) +# else +# define GC_API extern __declspec(dllimport) +# endif #endif #ifndef GC_API @@ -50,9 +58,11 @@ # if defined(__STDC__) || defined(__cplusplus) # define GC_PROTO(args) args typedef void * GC_PTR; +# define GC_CONST const # else # define GC_PROTO(args) () typedef char * GC_PTR; +# define GC_CONST # endif # ifdef __cplusplus @@ -88,11 +98,31 @@ GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)); /* pointer to a previously allocated heap */ /* object. */ +GC_API int GC_find_leak; + /* Do not actually garbage collect, but simply */ + /* report inaccessible memory that was not */ + /* deallocated with GC_free. Initial value */ + /* is determined by FIND_LEAK macro. */ + GC_API int GC_quiet; /* Disable statistics output. Only matters if */ /* collector has been compiled with statistics */ /* enabled. This involves a performance cost, */ /* and is thus not the default. */ +GC_API int GC_finalize_on_demand; + /* If nonzero, finalizers will only be run in */ + /* response to an eplit GC_invoke_finalizers */ + /* call. The default is determined by whether */ + /* the FINALIZE_ON_DEMAND macro is defined */ + /* when the collector is built. */ + +GC_API int GC_java_finalization; + /* Mark objects reachable from finalizable */ + /* objects in a separate postpass. This makes */ + /* it a bit safer to use non-topologically- */ + /* ordered finalization. Default value is */ + /* determined by JAVA_FINALIZATION macro. */ + GC_API int GC_dont_gc; /* Dont collect unless explicitly requested, e.g. */ /* because it's not safe. */ @@ -103,6 +133,12 @@ GC_API int GC_dont_expand; GC_API int GC_full_freq; /* Number of partial collections between */ /* full collections. Matters only if */ /* GC_incremental is set. */ + /* Full collections are also triggered if */ + /* the collector detects a substantial */ + /* increase in the number of in-use heap */ + /* blocks. Values in the tens are now */ + /* perfectly reasonable, unlike for */ + /* earlier GC versions. */ GC_API GC_word GC_non_gc_bytes; /* Bytes not considered candidates for collection. */ @@ -126,7 +162,19 @@ GC_API GC_word GC_max_retries; /* reporting out of memory after heap */ /* expansion fails. Initially 0. */ - + +GC_API char *GC_stackbottom; /* Cool end of user stack. */ + /* May be set in the client prior to */ + /* calling any GC_ routines. This */ + /* avoids some overhead, and */ + /* potentially some signals that can */ + /* confuse debuggers. Otherwise the */ + /* collector attempts to set it */ + /* automatically. */ + /* For multithreaded code, this is the */ + /* cold end of the stack for the */ + /* primordial thread. */ + /* Public procedures */ /* * general purpose allocation routines, with roughly malloc calling conv. @@ -193,8 +241,8 @@ GC_API size_t GC_size GC_PROTO((GC_PTR object_addr)); /* If the argument is stubborn, the result will have changes enabled. */ /* It is an error to have changes enabled for the original object. */ /* Follows ANSI comventions for NULL old_object. */ -GC_API GC_PTR GC_realloc GC_PROTO((GC_PTR old_object, - size_t new_size_in_bytes)); +GC_API GC_PTR GC_realloc + GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes)); /* Explicitly increase the heap size. */ /* Returns 0 on failure, 1 on success. */ @@ -248,6 +296,7 @@ GC_API void GC_gcollect GC_PROTO((void)); /* than normal pause times for incremental collection. However, */ /* aborted collections do no useful work; the next collection needs */ /* to start from the beginning. */ +/* Return 0 if the collection was aborted, 1 if it succeeded. */ typedef int (* GC_stop_func) GC_PROTO((void)); GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func)); @@ -256,6 +305,9 @@ GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func)); /* Includes some pages that were allocated but never written. */ GC_API size_t GC_get_heap_size GC_PROTO((void)); +/* Return a lower bound on the number of free bytes in the heap. */ +GC_API size_t GC_get_free_bytes GC_PROTO((void)); + /* Return the number of bytes allocated since the last collection. */ GC_API size_t GC_get_bytes_since_gc GC_PROTO((void)); @@ -300,10 +352,11 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb)); #ifdef GC_ADD_CALLER # define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__ -# define GC_EXTRA_PARAMS GC_word ra, char * descr_string, int descr_int +# define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * descr_string, + int descr_int #else # define GC_EXTRAS __FILE__, __LINE__ -# define GC_EXTRA_PARAMS char * descr_string, int descr_int +# define GC_EXTRA_PARAMS GC_CONST char * descr_string, int descr_int #endif /* Debugging (annotated) allocation. GC_gcollect will check */ @@ -502,7 +555,7 @@ GC_API int GC_invoke_finalizers GC_PROTO((void)); /* be finalized. Return the number of finalizers */ /* that were run. Normally this is also called */ /* implicitly during some allocations. If */ - /* FINALIZE_ON_DEMAND is defined, it must be called */ + /* GC-finalize_on_demand is nonzero, it must be called */ /* explicitly. */ /* GC_set_warn_proc can be used to redirect or filter warning messages. */ @@ -617,6 +670,10 @@ GC_API void (*GC_is_valid_displacement_print_proc) GC_API void (*GC_is_visible_print_proc) GC_PROTO((GC_PTR p)); +#if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS) +# define SOLARIS_THREADS +#endif + #ifdef SOLARIS_THREADS /* We need to intercept calls to many of the threads primitives, so */ /* that we can locate thread stacks and stop the world. */ @@ -656,7 +713,7 @@ GC_API void (*GC_is_visible_print_proc) # endif /* SOLARIS_THREADS */ -#if defined(IRIX_THREADS) || defined(LINUX_THREADS) +#if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) /* We treat these similarly. */ # include <pthread.h> # include <signal.h> @@ -673,10 +730,14 @@ GC_API void (*GC_is_visible_print_proc) #endif /* IRIX_THREADS || LINUX_THREADS */ -#if defined(THREADS) && !defined(SRC_M3) +# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \ + defined(IRIX_THREADS) || defined(LINUX_THREADS) || \ + defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) + /* Any flavor of threads except SRC_M3. */ /* This returns a list of objects, linked through their first */ /* word. Its use can greatly reduce lock contention problems, since */ /* the allocation lock can be acquired and released many fewer times. */ +/* lb must be large enough to hold the pointer field. */ GC_PTR GC_malloc_many(size_t lb); #define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */ /* in returned list. */ @@ -704,6 +765,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */ # endif #endif +#if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \ + || defined(_WIN32) + /* win32S may not free all resources on process exit. */ + /* This explicitly deallocates the heap. */ + GC_API void GC_win32_free_heap (); +#endif + #ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/boehm-gc/gc.mak b/boehm-gc/gc.mak index fdd0c9c6dc3..0fd22b70d60 100644 --- a/boehm-gc/gc.mak +++ b/boehm-gc/gc.mak @@ -5,7 +5,7 @@ # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 !IF "$(CFG)" == "" -CFG=cord - Win32 Debug +CFG=gctest - Win32 Release !MESSAGE No configuration specified. Defaulting to cord - Win32 Debug. !ENDIF @@ -768,7 +768,7 @@ SOURCE=.\reclaim.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_RECLA=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -788,7 +788,7 @@ NODEP_CPP_RECLA=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_RECLA=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -816,7 +816,7 @@ SOURCE=.\os_dep.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_OS_DE=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -840,7 +840,7 @@ NODEP_CPP_OS_DE=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_OS_DE=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -872,7 +872,7 @@ SOURCE=.\misc.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_MISC_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -893,7 +893,7 @@ NODEP_CPP_MISC_=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_MISC_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -922,7 +922,7 @@ SOURCE=.\mark_rts.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_MARK_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -942,7 +942,7 @@ NODEP_CPP_MARK_=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_MARK_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -970,7 +970,7 @@ SOURCE=.\mach_dep.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_MACH_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -990,7 +990,7 @@ NODEP_CPP_MACH_=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_MACH_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1018,7 +1018,7 @@ SOURCE=.\headers.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_HEADE=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1038,7 +1038,7 @@ NODEP_CPP_HEADE=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_HEADE=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1066,7 +1066,7 @@ SOURCE=.\alloc.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_ALLOC=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1086,7 +1086,7 @@ NODEP_CPP_ALLOC=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_ALLOC=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1114,7 +1114,7 @@ SOURCE=.\allchblk.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_ALLCH=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1134,7 +1134,7 @@ NODEP_CPP_ALLCH=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_ALLCH=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1162,7 +1162,7 @@ SOURCE=.\stubborn.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_STUBB=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1182,7 +1182,7 @@ NODEP_CPP_STUBB=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_STUBB=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1210,7 +1210,7 @@ SOURCE=.\obj_map.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_OBJ_M=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1230,7 +1230,7 @@ NODEP_CPP_OBJ_M=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_OBJ_M=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1258,7 +1258,7 @@ SOURCE=.\new_hblk.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_NEW_H=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1278,7 +1278,7 @@ NODEP_CPP_NEW_H=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_NEW_H=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1306,7 +1306,7 @@ SOURCE=.\mark.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_MARK_C=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1327,7 +1327,7 @@ NODEP_CPP_MARK_C=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_MARK_C=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1356,7 +1356,7 @@ SOURCE=.\malloc.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_MALLO=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1376,7 +1376,7 @@ NODEP_CPP_MALLO=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_MALLO=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1404,7 +1404,7 @@ SOURCE=.\mallocx.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_MALLX=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1424,7 +1424,7 @@ NODEP_CPP_MALLX=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_MALLX=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1452,7 +1452,7 @@ SOURCE=.\finalize.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_FINAL=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1473,7 +1473,7 @@ NODEP_CPP_FINAL=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_FINAL=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1502,7 +1502,7 @@ SOURCE=.\dbg_mlc.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_DBG_M=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1522,7 +1522,7 @@ NODEP_CPP_DBG_M=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_DBG_M=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1550,7 +1550,7 @@ SOURCE=.\blacklst.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_BLACK=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1570,7 +1570,7 @@ NODEP_CPP_BLACK=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_BLACK=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1598,7 +1598,7 @@ SOURCE=.\typd_mlc.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_TYPD_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1620,7 +1620,7 @@ NODEP_CPP_TYPD_=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_TYPD_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1650,7 +1650,7 @@ SOURCE=.\ptr_chck.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_PTR_C=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1671,7 +1671,7 @@ NODEP_CPP_PTR_C=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_PTR_C=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_mark.h"\ @@ -1700,7 +1700,7 @@ SOURCE=.\dyn_load.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_DYN_L=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1723,7 +1723,7 @@ NODEP_CPP_DYN_L=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_DYN_L=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1754,7 +1754,7 @@ SOURCE=.\win32_threads.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_WIN32=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1774,7 +1774,7 @@ NODEP_CPP_WIN32=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_WIN32=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1802,7 +1802,7 @@ SOURCE=.\checksums.c !IF "$(CFG)" == "gc - Win32 Release" DEP_CPP_CHECK=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1822,7 +1822,7 @@ NODEP_CPP_CHECK=\ !ELSEIF "$(CFG)" == "gc - Win32 Debug" DEP_CPP_CHECK=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ @@ -1878,7 +1878,7 @@ NODEP_CPP_CHECK=\ SOURCE=.\test.c DEP_CPP_TEST_=\ - ".\config.h"\ + ".\gcconfig.h"\ ".\gc.h"\ ".\gc_hdrs.h"\ ".\gc_priv.h"\ diff --git a/boehm-gc/gc_alloc.h b/boehm-gc/gc_alloc.h index 1d912db2f0b..1f1d54aff95 100644 --- a/boehm-gc/gc_alloc.h +++ b/boehm-gc/gc_alloc.h @@ -13,7 +13,7 @@ // // This is a C++ header file that is intended to replace the SGI STL -// alloc.h. +// alloc.h. This assumes SGI STL version < 3.0. // // This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE // and -DALL_INTERIOR_POINTERS. We also recommend diff --git a/boehm-gc/gc_cpp.cc b/boehm-gc/gc_cpp.cc index a766a01a328..547c56f96a1 100644 --- a/boehm-gc/gc_cpp.cc +++ b/boehm-gc/gc_cpp.cc @@ -32,6 +32,20 @@ void* operator new( size_t size ) { void operator delete( void* obj ) { GC_FREE( obj );} +#ifdef _MSC_VER +// This new operator is used by VC++ in case of Debug builds ! +void* operator new( size_t size, + int ,//nBlockUse, + const char * szFileName, + int nLine + ) { +# ifndef GC_DEBUG + return GC_malloc_uncollectable( size ); +# else + return GC_debug_malloc_uncollectable(size, szFileName, nLine); +# endif +} +#endif #ifdef OPERATOR_NEW_ARRAY diff --git a/boehm-gc/gc_cpp.h b/boehm-gc/gc_cpp.h index e2f456fb526..ad7df5d71fa 100644 --- a/boehm-gc/gc_cpp.h +++ b/boehm-gc/gc_cpp.h @@ -133,7 +133,8 @@ uses explicit invocation. #endif #if ! defined( OPERATOR_NEW_ARRAY ) \ - && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6)) + && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6) \ + || __WATCOMC__ >= 1050) # define OPERATOR_NEW_ARRAY #endif @@ -212,6 +213,8 @@ inline void* gc::operator new( size_t size ) { inline void* gc::operator new( size_t size, GCPlacement gcp ) { if (gcp == GC) return GC_MALLOC( size ); + else if (gcp == PointerFreeGC) + return GC_MALLOC_ATOMIC( size ); else return GC_MALLOC_UNCOLLECTABLE( size );} @@ -234,7 +237,7 @@ inline void gc::operator delete[]( void* obj ) { inline gc_cleanup::~gc_cleanup() { - GC_REGISTER_FINALIZER_IGNORE_SELF( this, 0, 0, 0, 0 );} + GC_REGISTER_FINALIZER_IGNORE_SELF( GC_base(this), 0, 0, 0, 0 );} inline void gc_cleanup::cleanup( void* obj, void* displ ) { ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();} diff --git a/boehm-gc/gc_hdrs.h b/boehm-gc/gc_hdrs.h index 2f2d1bf9b8a..60dc2ad37d6 100644 --- a/boehm-gc/gc_hdrs.h +++ b/boehm-gc/gc_hdrs.h @@ -49,14 +49,16 @@ typedef struct bi { hdr * index[BOTTOM_SZ]; /* * The bottom level index contains one of three kinds of values: - * 0 means we're not responsible for this block. + * 0 means we're not responsible for this block, + * or this is a block other than the first one in a free block. * 1 < (long)X <= MAX_JUMP means the block starts at least * X * HBLKSIZE bytes before the current address. * A valid pointer points to a hdr structure. (The above can't be * valid pointers due to the GET_MEM return convention.) */ struct bi * asc_link; /* All indices are linked in */ - /* ascending order. */ + /* ascending order... */ + struct bi * desc_link; /* ... and in descending order. */ word key; /* high order address bits. */ # ifdef HASH_TL struct bi * hash_link; /* Hash chain link. */ diff --git a/boehm-gc/gc_mark.h b/boehm-gc/gc_mark.h index ade98a91857..4628323f990 100644 --- a/boehm-gc/gc_mark.h +++ b/boehm-gc/gc_mark.h @@ -38,12 +38,17 @@ /* subset of the places the conservative marker would. It must be safe */ /* to invoke the normal mark procedure instead. */ # define PROC_BYTES 100 -typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr, - mark_stack_limit, env */); +/* The real declarations of the following are in gc_priv.h, so that */ +/* we can avoid scanning the following table. */ +/* +typedef struct ms_entry * (*mark_proc)( word * addr, mark_stack_ptr, + mark_stack_limit, env ); # define LOG_MAX_MARK_PROCS 6 # define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) extern mark_proc GC_mark_procs[MAX_MARK_PROCS]; +*/ + extern word GC_n_mark_procs; /* Object descriptors on mark stack or in objects. Low order two */ @@ -166,6 +171,8 @@ mse * GC_signal_mark_stack_overflow(); /* Mark bit is already set */ \ goto exit_label; \ } \ + GC_STORE_BACK_PTR((ptr_t)source, (ptr_t)HBLKPTR(current) \ + + WORDS_TO_BYTES(displ)); \ *mark_word_addr = mark_word | mark_bit; \ } \ PUSH_OBJ(((word *)(HBLKPTR(current)) + displ), hhdr, \ @@ -173,18 +180,24 @@ mse * GC_signal_mark_stack_overflow(); exit_label: ; \ } +#ifdef PRINT_BLACK_LIST +# define PUSH_ONE_CHECKED(p, ip, source) \ + GC_push_one_checked(p, ip, (ptr_t)(source)) +#else +# define PUSH_ONE_CHECKED(p, ip, source) \ + GC_push_one_checked(p, ip) +#endif /* * Push a single value onto mark stack. Mark from the object pointed to by p. - * GC_push_one is normally called by GC_push_regs, and thus must be defined. * P is considered valid even if it is an interior pointer. * Previously marked objects are not pushed. Hence we make progress even * if the mark stack overflows. */ -# define GC_PUSH_ONE_STACK(p) \ +# define GC_PUSH_ONE_STACK(p, source) \ if ((ptr_t)(p) >= GC_least_plausible_heap_addr \ && (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \ - GC_push_one_checked(p,TRUE); \ + PUSH_ONE_CHECKED(p, TRUE, source); \ } /* @@ -196,10 +209,10 @@ mse * GC_signal_mark_stack_overflow(); # else # define AIP FALSE # endif -# define GC_PUSH_ONE_HEAP(p) \ +# define GC_PUSH_ONE_HEAP(p,source) \ if ((ptr_t)(p) >= GC_least_plausible_heap_addr \ && (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \ - GC_push_one_checked(p,AIP); \ + PUSH_ONE_CHECKED(p,AIP,source); \ } /* @@ -213,7 +226,7 @@ mse * GC_signal_mark_stack_overflow(); while (!GC_mark_stack_empty()) GC_mark_from_mark_stack(); \ if (GC_mark_state != MS_NONE) { \ GC_set_mark_bit(real_ptr); \ - while (!GC_mark_some()); \ + while (!GC_mark_some((ptr_t)0)); \ } \ } @@ -233,8 +246,8 @@ typedef int mark_state_t; /* Current state of marking, as follows:*/ /* Invariant I: all roots and marked */ /* objects p are either dirty, or point */ - /* objects q that are either marked or */ - /* a pointer to q appears in a range */ + /* to objects q that are either marked */ + /* or a pointer to q appears in a range */ /* on the mark stack. */ # define MS_NONE 0 /* No marking in progress. I holds. */ diff --git a/boehm-gc/gc_priv.h b/boehm-gc/gc_priv.h index cda9c23bacb..8dd496f31e1 100644 --- a/boehm-gc/gc_priv.h +++ b/boehm-gc/gc_priv.h @@ -1,6 +1,9 @@ /* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. + * * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -42,7 +45,7 @@ typedef GC_word word; typedef GC_signed_word signed_word; # ifndef CONFIG_H -# include "config.h" +# include "gcconfig.h" # endif # ifndef HEADERS_H @@ -64,16 +67,16 @@ typedef char * ptr_t; /* A generic pointer to which we can add */ # include <stddef.h> # endif # define VOLATILE volatile -# define CONST const #else # ifdef MSWIN32 # include <stdlib.h> # endif # define VOLATILE -# define CONST #endif -#ifdef AMIGA +#define CONST GC_CONST + +#if 0 /* was once defined for AMIGA */ # define GC_FAR __far #else # define GC_FAR @@ -336,6 +339,9 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); /* space is assumed to be cleared. */ /* In the case os USE_MMAP, the argument must also be a */ /* physical page size. */ +/* GET_MEM is currently not assumed to retrieve 0 filled space, */ +/* though we should perhaps take advantage of the case in which */ +/* does. */ # ifdef PCR char * real_malloc(); # define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \ @@ -347,7 +353,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); + GC_page_size) \ + GC_page_size-1) # else -# if defined(AMIGA) || defined(NEXT) || defined(DOS4GW) +# if defined(AMIGA) || defined(NEXT) || defined(MACOSX) || defined(DOS4GW) # define GET_MEM(bytes) HBLKPTR((size_t) \ calloc(1, (size_t)bytes + GC_page_size) \ + GC_page_size-1) @@ -433,7 +439,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); # endif # ifdef LINUX_THREADS # include <pthread.h> -# ifdef __i386__ +# if defined(I386) inline static int GC_test_and_set(volatile unsigned int *addr) { int oldval; /* Note: the "xchg" instruction does not need a "lock" prefix */ @@ -442,55 +448,58 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); : "0"(1), "m"(*(addr))); return oldval; } - inline static void GC_clear(volatile unsigned int *addr) { - *(addr) = 0; - } -# elif defined(__alpha__) +# else +# if defined(POWERPC) inline static int GC_test_and_set(volatile unsigned int *addr) { - long oldval, temp; + int oldval; + int temp = 1; // locked value __asm__ __volatile__( - "1:\tldl_l %0,%3\n" - "\tbne %0,2f\n" - "\tor $31,1,%1\n" - "\tstl_c %1,%2\n" - "\tbeq %1,1b\n" - "2:\tmb\n" - : "=&r"(oldval), "=&r"(temp), "=m"(*(addr)) - : "m"(*(addr)) + "1:\tlwarx %0,0,%3\n" // load and reserve + "\tcmpwi %0, 0\n" // if load is + "\tbne 2f\n" // non-zero, return already set + "\tstwcx. %2,0,%1\n" // else store conditional + "\tbne- 1b\n" // retry if lost reservation + "2:\t\n" // oldval is zero if we set + : "=&r"(oldval), "=p"(addr) + : "r"(temp), "1"(addr) : "memory"); return (int)oldval; } - inline static void GC_clear(volatile unsigned int *addr) { - __asm__ __volatile__("mb": : :"memory"); - *(addr) = 0; - } -# elif defined(__powerpc__) - inline static int GC_test_and_set(volatile unsigned int *addr) { - int ret, oldval=0, newval=1; - - __asm__ __volatile__("sync" : : : "memory"); - __asm__ __volatile__( - "0: lwarx %0,0,%1 ;" - " xor. %0,%3,%0;" - " bne 1f;" - " stwcx. %2,0,%1;" - " bne- 0b;" - "1: " - : "=&r"(ret) - : "r"(addr), "r"(newval), "r"(oldval) - : "cr0", "memory"); - __asm__ __volatile__("sync" : : : "memory"); - return ret == 0; - } - inline static void GC_clear(volatile unsigned int *addr) { - __asm__ __volatile__("sync": : :"memory"); - *(addr) = 0; - } - -# else - -- > Need implementation of GC_test_and_set() +# else +# ifdef ALPHA + inline static int GC_test_and_set(volatile unsigned int * +addr) + { + unsigned long oldvalue; + unsigned long temp; + + __asm__ __volatile__( + "1: ldl_l %0,%1\n" + " and %0,%3,%2\n" + " bne %2,2f\n" + " xor %0,%3,%0\n" + " stl_c %0,%1\n" + " beq %0,3f\n" + " mb\n" + "2:\n" + ".section .text2,\"ax\"\n" + "3: br 1b\n" + ".previous" + :"=&r" (temp), "=m" (*addr), "=&r" +(oldvalue) + :"Ir" (1), "m" (*addr)); + + return oldvalue; + } +# else + -- > Need implementation of GC_test_and_set() +# endif +# endif # endif + inline static void GC_clear(volatile unsigned int *addr) { + *(addr) = 0; + } extern volatile unsigned int GC_allocate_lock; /* This is not a mutex because mutexes that obey the (optional) */ @@ -504,15 +513,10 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); # define NO_THREAD (pthread_t)(-1) # define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD # define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) -# ifdef UNDEFINED -# define LOCK() pthread_mutex_lock(&GC_allocate_ml) -# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) -# else -# define LOCK() \ +# define LOCK() \ { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } -# define UNLOCK() \ +# define UNLOCK() \ GC_clear(&GC_allocate_lock) -# endif extern GC_bool GC_collecting; # define ENTER_GC() \ { \ @@ -520,15 +524,30 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); } # define EXIT_GC() GC_collecting = 0; # endif /* LINUX_THREADS */ -# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) +# if defined(HPUX_THREADS) +# include <pthread.h> + extern pthread_mutex_t GC_allocate_ml; +# define LOCK() pthread_mutex_lock(&GC_allocate_ml) +# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) +# endif +# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) + /* This may also eventually be appropriate for HPUX_THREADS */ # include <pthread.h> -# include <mutex.h> +# ifndef HPUX_THREADS + /* This probably should never be included, but I can't test */ + /* on Irix anymore. */ +# include <mutex.h> +# endif -# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ +# ifndef HPUX_THREADS +# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ || !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700 # define GC_test_and_set(addr, v) test_and_set(addr,v) -# else +# else # define GC_test_and_set(addr, v) __test_and_set(addr,v) +# endif +# else + /* I couldn't find a way to do this inline on HP/UX */ # endif extern unsigned long GC_allocate_lock; /* This is not a mutex because mutexes that obey the (optional) */ @@ -542,15 +561,17 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); # define NO_THREAD (pthread_t)(-1) # define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD # define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) -# ifdef UNDEFINED -# define LOCK() pthread_mutex_lock(&GC_allocate_ml) -# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) +# ifdef HPUX_THREADS +# define LOCK() { if (!GC_test_and_clear(&GC_allocate_lock)) GC_lock(); } + /* The following is INCORRECT, since the memory model is too weak. */ +# define UNLOCK() { GC_noop1(&GC_allocate_lock); \ + *(volatile unsigned long *)(&GC_allocate_lock) = 1; } # else -# define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); } -# if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64)) \ +# define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); } +# if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64)) \ && defined(_COMPILER_VERSION) && _COMPILER_VERSION >= 700 # define UNLOCK() __lock_release(&GC_allocate_lock) -# else +# else /* The function call in the following should prevent the */ /* compiler from moving assignments to below the UNLOCK. */ /* This is probably not necessary for ucode or gcc 2.8. */ @@ -558,7 +579,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); /* versions. */ # define UNLOCK() { GC_noop1(&GC_allocate_lock); \ *(volatile unsigned long *)(&GC_allocate_lock) = 0; } -# endif +# endif # endif extern GC_bool GC_collecting; # define ENTER_GC() \ @@ -653,7 +674,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */); # else # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \ - || defined(IRIX_JDK_THREADS) + || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) void GC_stop_world(); void GC_start_world(); # define STOP_WORLD() GC_stop_world() @@ -869,6 +890,7 @@ struct hblkhdr { struct hblk * hb_next; /* Link field for hblk free list */ /* and for lists of chunks waiting to be */ /* reclaimed. */ + struct hblk * hb_prev; /* Backwards link for free list. */ word hb_descr; /* object descriptor for marking. See */ /* mark.h. */ char* hb_map; /* A pointer to a pointer validity map of the block. */ @@ -883,14 +905,28 @@ struct hblkhdr { # define IGNORE_OFF_PAGE 1 /* Ignore pointers that do not */ /* point to the first page of */ /* this object. */ +# define WAS_UNMAPPED 2 /* This is a free block, which has */ + /* been unmapped from the address */ + /* space. */ + /* GC_remap must be invoked on it */ + /* before it can be reallocated. */ + /* Only set with USE_MUNMAP. */ unsigned short hb_last_reclaimed; /* Value of GC_gc_no when block was */ /* last allocated or swept. May wrap. */ + /* For a free block, this is maintained */ + /* unly for USE_MUNMAP, and indicates */ + /* when the header was allocated, or */ + /* when the size of the block last */ + /* changed. */ word hb_marks[MARK_BITS_SZ]; /* Bit i in the array refers to the */ /* object starting at the ith word (header */ /* INCLUDED) in the heap block. */ /* The lsb of word 0 is numbered 0. */ + /* Unused bits are invalid, and are */ + /* occasionally set, e.g for uncollectable */ + /* objects. */ }; /* heap block body */ @@ -922,7 +958,69 @@ struct hblk { /* Object free list link */ # define obj_link(p) (*(ptr_t *)(p)) -/* lists of all heap blocks and free lists */ +/* The type of mark procedures. This really belongs in gc_mark.h. */ +/* But we put it here, so that we can avoid scanning the mark proc */ +/* table. */ +typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr, + mark_stack_limit, env */); +# define LOG_MAX_MARK_PROCS 6 +# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) + +/* Root sets. Logically private to mark_rts.c. But we don't want the */ +/* tables scanned, so we put them here. */ +/* MAX_ROOT_SETS is the maximum number of ranges that can be */ +/* registered as static roots. */ +# ifdef LARGE_CONFIG +# define MAX_ROOT_SETS 4096 +# else +# ifdef PCR +# define MAX_ROOT_SETS 1024 +# else +# ifdef MSWIN32 +# define MAX_ROOT_SETS 512 + /* Under NT, we add only written pages, which can result */ + /* in many small root sets. */ +# else +# define MAX_ROOT_SETS 64 +# endif +# endif +# endif + +# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4) +/* Maximum number of segments that can be excluded from root sets. */ + +/* + * Data structure for excluded static roots. + */ +struct exclusion { + ptr_t e_start; + ptr_t e_end; +}; + +/* Data structure for list of root sets. */ +/* We keep a hash table, so that we can filter out duplicate additions. */ +/* Under Win32, we need to do a better job of filtering overlaps, so */ +/* we resort to sequential search, and pay the price. */ +struct roots { + ptr_t r_start; + ptr_t r_end; +# ifndef MSWIN32 + struct roots * r_next; +# endif + GC_bool r_tmp; + /* Delete before registering new dynamic libraries */ +}; + +#ifndef MSWIN32 + /* Size of hash table index to roots. */ +# define LOG_RT_SIZE 6 +# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */ +#endif + +/* Lists of all heap blocks and free lists */ +/* as well as other random data structures */ +/* that should not be scanned by the */ +/* collector. */ /* These are grouped together in a struct */ /* so that they can be easily skipped by the */ /* GC_mark routine. */ @@ -943,6 +1041,9 @@ struct _GC_arrays { word _max_heapsize; ptr_t _last_heap_addr; ptr_t _prev_heap_addr; + word _large_free_bytes; + /* Total bytes contained in blocks on large object free */ + /* list. */ word _words_allocd_before_gc; /* Number of words allocated before this */ /* collection cycle. */ @@ -962,7 +1063,10 @@ struct _GC_arrays { word _mem_freed; /* Number of explicitly deallocated words of memory */ /* since last collection. */ - + mark_proc _mark_procs[MAX_MARK_PROCS]; + /* Table of user-defined mark procedures. There is */ + /* a small number of these, which can be referenced */ + /* by DS_PROC mark descriptors. See gc_mark.h. */ ptr_t _objfreelist[MAXOBJSZ+1]; /* free list for objects */ ptr_t _aobjfreelist[MAXOBJSZ+1]; @@ -986,6 +1090,9 @@ struct _GC_arrays { /* Number of words in accessible atomic */ /* objects. */ # endif +# ifdef USE_MUNMAP + word _unmapped_bytes; +# endif # ifdef MERGE_SIZES unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)]; /* Number of words to allocate for a given allocation request in */ @@ -1003,7 +1110,7 @@ struct _GC_arrays { /* to an object at */ /* block_start+i&~3 - WORDS_TO_BYTES(j). */ /* (If ALL_INTERIOR_POINTERS is defined, then */ - /* instead ((short *)(hbh_map[sz])[i] is j if */ + /* instead ((short *)(hb_map[sz])[i] is j if */ /* block_start+WORDS_TO_BYTES(i) is in the */ /* interior of an object starting at */ /* block_start+WORDS_TO_BYTES(i-j)). */ @@ -1044,17 +1151,24 @@ struct _GC_arrays { /* GC_modws_valid_offsets[i%sizeof(word)] */ # endif # ifdef STUBBORN_ALLOC - page_hash_table _changed_pages; + page_hash_table _changed_pages; /* Stubborn object pages that were changes since last call to */ /* GC_read_changed. */ - page_hash_table _prev_changed_pages; + page_hash_table _prev_changed_pages; /* Stubborn object pages that were changes before last call to */ /* GC_read_changed. */ # endif # if defined(PROC_VDB) || defined(MPROTECT_VDB) - page_hash_table _grungy_pages; /* Pages that were dirty at last */ + page_hash_table _grungy_pages; /* Pages that were dirty at last */ /* GC_read_dirty. */ # endif +# ifdef MPROTECT_VDB + VOLATILE page_hash_table _dirty_pages; + /* Pages dirtied since last GC_read_dirty. */ +# endif +# ifdef PROC_VDB + page_hash_table _written_pages; /* Pages ever dirtied */ +# endif # ifdef LARGE_CONFIG # if CPP_WORDSZ > 32 # define MAX_HEAP_SECTS 4096 /* overflows at roughly 64 GB */ @@ -1071,6 +1185,11 @@ struct _GC_arrays { ptr_t _heap_bases[MAX_HEAP_SECTS]; /* Start address of memory regions obtained from kernel. */ # endif + struct roots _static_roots[MAX_ROOT_SETS]; +# ifndef MSWIN32 + struct roots * _root_index[RT_SIZE]; +# endif + struct exclusion _excl_table[MAX_EXCLUSIONS]; /* Block header index; see gc_headers.h */ bottom_index * _all_nils; bottom_index * _top_index [TOP_SZ]; @@ -1104,22 +1223,36 @@ GC_API GC_FAR struct _GC_arrays GC_arrays; # define GC_prev_heap_addr GC_arrays._prev_heap_addr # define GC_words_allocd GC_arrays._words_allocd # define GC_words_wasted GC_arrays._words_wasted +# define GC_large_free_bytes GC_arrays._large_free_bytes # define GC_words_finalized GC_arrays._words_finalized # define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc # define GC_mem_freed GC_arrays._mem_freed +# define GC_mark_procs GC_arrays._mark_procs # define GC_heapsize GC_arrays._heapsize # define GC_max_heapsize GC_arrays._max_heapsize # define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc # define GC_heap_sects GC_arrays._heap_sects # define GC_last_stack GC_arrays._last_stack +# ifdef USE_MUNMAP +# define GC_unmapped_bytes GC_arrays._unmapped_bytes +# endif # ifdef MSWIN32 # define GC_heap_bases GC_arrays._heap_bases # endif +# define GC_static_roots GC_arrays._static_roots +# define GC_root_index GC_arrays._root_index +# define GC_excl_table GC_arrays._excl_table # define GC_all_nils GC_arrays._all_nils # define GC_top_index GC_arrays._top_index # if defined(PROC_VDB) || defined(MPROTECT_VDB) # define GC_grungy_pages GC_arrays._grungy_pages # endif +# ifdef MPROTECT_VDB +# define GC_dirty_pages GC_arrays._dirty_pages +# endif +# ifdef PROC_VDB +# define GC_written_pages GC_arrays._written_pages +# endif # ifdef GATHERSTATS # define GC_composite_in_use GC_arrays._composite_in_use # define GC_atomic_in_use GC_arrays._atomic_in_use @@ -1131,11 +1264,9 @@ GC_API GC_FAR struct _GC_arrays GC_arrays; # define beginGC_arrays ((ptr_t)(&GC_arrays)) # define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays)) -GC_API word GC_fo_entries; - +/* Object kinds: */ # define MAXOBJKINDS 16 -/* Object kinds: */ extern struct obj_kind { ptr_t *ok_freelist; /* Array of free listheaders for this kind of object */ /* Point either to GC_arrays or to storage allocated */ @@ -1149,8 +1280,14 @@ extern struct obj_kind { /* Add object size in bytes to descriptor */ /* template to obtain descriptor. Otherwise */ /* template is used as is. */ - GC_bool ok_init; /* Clear objects before putting them on the free list. */ + GC_bool ok_init; /* Clear objects before putting them on the free list. */ } GC_obj_kinds[MAXOBJKINDS]; + +# define endGC_obj_kinds (((ptr_t)(&GC_obj_kinds)) + (sizeof GC_obj_kinds)) + +# define end_gc_area ((ptr_t)endGC_arrays == (ptr_t)(&GC_obj_kinds) ? \ + endGC_obj_kinds : endGC_arrays) + /* Predefined kinds: */ # define PTRFREE 0 # define NORMAL 1 @@ -1166,6 +1303,8 @@ extern struct obj_kind { extern int GC_n_kinds; +GC_API word GC_fo_entries; + extern word GC_n_heap_sects; /* Number of separately added heap */ /* sections. */ @@ -1189,7 +1328,7 @@ extern char * GC_invalid_map; /* Pointer to the nowhere valid hblk map */ /* Blocks pointing to this map are free. */ -extern struct hblk * GC_hblkfreelist; +extern struct hblk * GC_hblkfreelist[]; /* List of completely empty heap blocks */ /* Linked through hb_next field of */ /* header structure associated with */ @@ -1200,17 +1339,19 @@ extern GC_bool GC_is_initialized; /* GC_init() has been run. */ extern GC_bool GC_objects_are_marked; /* There are marked objects in */ /* the heap. */ -extern GC_bool GC_incremental; /* Using incremental/generational collection. */ +#ifndef SMALL_CONFIG + extern GC_bool GC_incremental; + /* Using incremental/generational collection. */ +#else +# define GC_incremental TRUE + /* Hopefully allow optimizer to remove some code. */ +#endif extern GC_bool GC_dirty_maintained; /* Dirty bits are being maintained, */ /* either for incremental collection, */ /* or to limit the root set. */ -# ifndef PCR - extern ptr_t GC_stackbottom; /* Cool end of user stack */ -# endif - extern word GC_root_size; /* Total size of registered root sections */ extern GC_bool GC_debugging_started; /* GC_debug_malloc has been called. */ @@ -1262,7 +1403,12 @@ GC_bool GC_should_collect(); void GC_apply_to_all_blocks(/*fn, client_data*/); /* Invoke fn(hbp, client_data) for each */ /* allocated heap block. */ -struct hblk * GC_next_block(/* struct hblk * h */); +struct hblk * GC_next_used_block(/* struct hblk * h */); + /* Return first in-use block >= h */ +struct hblk * GC_prev_block(/* struct hblk * h */); + /* Return last block <= h. Returned block */ + /* is managed by GC, but may or may not be in */ + /* use. */ void GC_mark_init(); void GC_clear_marks(); /* Clear mark bits for all heap objects. */ void GC_invalidate_mark_state(); /* Tell the marker that marked */ @@ -1274,7 +1420,8 @@ void GC_mark_from_mark_stack(); /* Mark from everything on the mark stack. */ /* Return after about one pages worth of */ /* work. */ GC_bool GC_mark_stack_empty(); -GC_bool GC_mark_some(); /* Perform about one pages worth of marking */ +GC_bool GC_mark_some(/* cold_gc_frame */); + /* Perform about one pages worth of marking */ /* work of whatever kind is needed. Returns */ /* quickly if no collection is in progress. */ /* Return TRUE if mark phase finished. */ @@ -1296,7 +1443,31 @@ void GC_push_dirty(/*b,t*/); /* Push all possibly changed */ /* on the third arg. */ void GC_push_all_stack(/*b,t*/); /* As above, but consider */ /* interior pointers as valid */ -void GC_push_roots(/* GC_bool all */); /* Push all or dirty roots. */ +void GC_push_all_eager(/*b,t*/); /* Same as GC_push_all_stack, but */ + /* ensures that stack is scanned */ + /* immediately, not just scheduled */ + /* for scanning. */ +#ifndef THREADS + void GC_push_all_stack_partially_eager(/* bottom, top, cold_gc_frame */); + /* Similar to GC_push_all_eager, but only the */ + /* part hotter than cold_gc_frame is scanned */ + /* immediately. Needed to endure that callee- */ + /* save registers are not missed. */ +#else + /* In the threads case, we push part of the current thread stack */ + /* with GC_push_all_eager when we push the registers. This gets the */ + /* callee-save registers that may disappear. The remainder of the */ + /* stacks are scheduled for scanning in *GC_push_other_roots, which */ + /* is thread-package-specific. */ +#endif +void GC_push_current_stack(/* ptr_t cold_gc_frame */); + /* Push enough of the current stack eagerly to */ + /* ensure that callee-save registers saved in */ + /* GC frames are scanned. */ + /* In the non-threads case, schedule entire */ + /* stack for scanning. */ +void GC_push_roots(/* GC_bool all, ptr_t cold_gc_frame */); + /* Push all or dirty roots. */ extern void (*GC_push_other_roots)(); /* Push system or application specific roots */ /* onto the mark stack. In some environments */ @@ -1310,8 +1481,14 @@ extern void (*GC_start_call_back)(/* void */); /* lock held. */ /* 0 by default. */ void GC_push_regs(); /* Push register contents onto mark stack. */ + /* If NURSERY is defined, the default push */ + /* action can be overridden with GC_push_proc */ void GC_remark(); /* Mark from all marked objects. Used */ /* only if we had to drop something. */ + +# ifdef NURSERY + extern void (*GC_push_proc)(ptr_t); +# endif # if defined(MSWIN32) void __cdecl GC_push_one(); # else @@ -1461,7 +1638,7 @@ GC_bool GC_collect_or_expand(/* needed_blocks */); /* blocks available. Should be called */ /* until the blocks are available or */ /* until it fails by returning FALSE. */ -void GC_init(); /* Initialize collector. */ +GC_API void GC_init(); /* Initialize collector. */ void GC_collect_a_little_inner(/* int n */); /* Do n units worth of garbage */ /* collection work, if appropriate. */ @@ -1538,6 +1715,15 @@ extern void (*GC_print_heap_obj)(/* ptr_t p */); /* detailed description of the object */ /* referred to by p. */ +/* Memory unmapping: */ +#ifdef USE_MUNMAP + void GC_unmap_old(void); + void GC_merge_unmapped(void); + void GC_unmap(ptr_t start, word bytes); + void GC_remap(ptr_t start, word bytes); + void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2); +#endif + /* Virtual dirty bit implementation: */ /* Each implementation exports the following: */ void GC_read_dirty(); /* Retrieve dirty bits. */ @@ -1553,7 +1739,7 @@ void GC_write_hint(/* struct hblk * h */); void GC_dirty_init(); /* Slow/general mark bit manipulation: */ -GC_bool GC_is_marked(); +GC_API GC_bool GC_is_marked(); void GC_clear_mark_bit(); void GC_set_mark_bit(); @@ -1570,6 +1756,16 @@ void GC_print_heap_sects(); void GC_print_static_roots(); void GC_dump(); +#ifdef KEEP_BACK_PTRS + void GC_store_back_pointer(ptr_t source, ptr_t dest); + void GC_marked_for_finalization(ptr_t dest); +# define GC_STORE_BACK_PTR(source, dest) GC_store_back_pointer(source, dest) +# define GC_MARKED_FOR_FINALIZATION(dest) GC_marked_for_finalization(dest) +#else +# define GC_STORE_BACK_PTR(source, dest) +# define GC_MARKED_FOR_FINALIZATION(dest) +#endif + /* Make arguments appear live to compiler */ # ifdef __WATCOMC__ void GC_noop(void*, ...); @@ -1620,4 +1816,13 @@ void GC_err_puts(/* char *s */); /* newlines, don't ... */ +# ifdef GC_ASSERTIONS +# define GC_ASSERT(expr) if(!(expr)) {\ + GC_err_printf2("Assertion failure: %s:%ld\n", \ + __FILE__, (unsigned long)__LINE__); \ + ABORT("assertion failure"); } +# else +# define GC_ASSERT(expr) +# endif + # endif /* GC_PRIVATE_H */ diff --git a/boehm-gc/headers.c b/boehm-gc/headers.c index b5cc1af8a8d..9564a6a5359 100644 --- a/boehm-gc/headers.c +++ b/boehm-gc/headers.c @@ -25,6 +25,12 @@ # include "gc_priv.h" bottom_index * GC_all_bottom_indices = 0; + /* Pointer to first (lowest addr) */ + /* bottom_index. */ + +bottom_index * GC_all_bottom_indices_end = 0; + /* Pointer to last (highest addr) */ + /* bottom_index. */ /* Non-macro version of header location routine */ hdr * GC_find_header(h) @@ -53,7 +59,6 @@ ptr_t GC_scratch_alloc(bytes) register word bytes; { register ptr_t result = scratch_free_ptr; - register word bytes_needed = bytes; # ifdef ALIGN_DOUBLE # define GRANULARITY (2 * sizeof(word)) @@ -90,7 +95,7 @@ register word bytes; bytes_to_get = bytes; # ifdef USE_MMAP bytes_to_get += GC_page_size - 1; - bytes_to_get &= (GC_page_size - 1); + bytes_to_get &= ~(GC_page_size - 1); # endif return((ptr_t)GET_MEM(bytes_to_get)); } @@ -126,7 +131,7 @@ hdr * hhdr; void GC_init_headers() { - register int i; + register unsigned i; GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index)); BZERO(GC_all_nils, sizeof(bottom_index)); @@ -138,16 +143,17 @@ void GC_init_headers() /* Make sure that there is a bottom level index block for address addr */ /* Return FALSE on failure. */ static GC_bool get_index(addr) -register word addr; +word addr; { - register word hi = - (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); - register bottom_index * r; - register bottom_index * p; - register bottom_index ** prev; + word hi = (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); + bottom_index * r; + bottom_index * p; + bottom_index ** prev; + bottom_index *pi; + # ifdef HASH_TL - register unsigned i = TL_HASH(hi); - register bottom_index * old; + unsigned i = TL_HASH(hi); + bottom_index * old; old = p = GC_top_index[i]; while(p != GC_all_nils) { @@ -165,11 +171,21 @@ register word addr; if (r == 0) return(FALSE); GC_top_index[hi] = r; BZERO(r, sizeof (bottom_index)); -# endif +# endif r -> key = hi; /* Add it to the list of bottom indices */ - prev = &GC_all_bottom_indices; - while ((p = *prev) != 0 && p -> key < hi) prev = &(p -> asc_link); + prev = &GC_all_bottom_indices; /* pointer to p */ + pi = 0; /* bottom_index preceding p */ + while ((p = *prev) != 0 && p -> key < hi) { + pi = p; + prev = &(p -> asc_link); + } + r -> desc_link = pi; + if (0 == p) { + GC_all_bottom_indices_end = r; + } else { + p -> desc_link = r; + } r -> asc_link = p; *prev = r; return(TRUE); @@ -186,6 +202,9 @@ register struct hblk * h; if (!get_index((word) h)) return(FALSE); result = alloc_hdr(); SET_HDR(h, result); +# ifdef USE_MUNMAP + result -> hb_last_reclaimed = GC_gc_no; +# endif return(result != 0); } @@ -262,7 +281,7 @@ word client_data; /* Get the next valid block whose address is at least h */ /* Return 0 if there is none. */ -struct hblk * GC_next_block(h) +struct hblk * GC_next_used_block(h) struct hblk * h; { register bottom_index * bi; @@ -277,15 +296,16 @@ struct hblk * h; } while(bi != 0) { while (j < BOTTOM_SZ) { - if (IS_FORWARDING_ADDR_OR_NIL(bi -> index[j])) { + hdr * hhdr = bi -> index[j]; + if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { j++; } else { - if (bi->index[j]->hb_map != GC_invalid_map) { + if (hhdr->hb_map != GC_invalid_map) { return((struct hblk *) (((bi -> key << LOG_BOTTOM_SZ) + j) << LOG_HBLKSIZE)); } else { - j += divHBLKSZ(bi->index[j] -> hb_sz); + j += divHBLKSZ(hhdr -> hb_sz); } } } @@ -294,3 +314,38 @@ struct hblk * h; } return(0); } + +/* Get the last (highest address) block whose address is */ +/* at most h. Return 0 if there is none. */ +/* Unlike the above, this may return a free block. */ +struct hblk * GC_prev_block(h) +struct hblk * h; +{ + register bottom_index * bi; + register signed_word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1); + + GET_BI(h, bi); + if (bi == GC_all_nils) { + register word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); + bi = GC_all_bottom_indices_end; + while (bi != 0 && bi -> key > hi) bi = bi -> desc_link; + j = BOTTOM_SZ - 1; + } + while(bi != 0) { + while (j >= 0) { + hdr * hhdr = bi -> index[j]; + if (0 == hhdr) { + --j; + } else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { + j -= (signed_word)hhdr; + } else { + return((struct hblk *) + (((bi -> key << LOG_BOTTOM_SZ) + j) + << LOG_HBLKSIZE)); + } + } + j = BOTTOM_SZ - 1; + bi = bi -> desc_link; + } + return(0); +} diff --git a/boehm-gc/if_mach.c b/boehm-gc/if_mach.c index da2b7f90a62..af013637bf2 100644 --- a/boehm-gc/if_mach.c +++ b/boehm-gc/if_mach.c @@ -1,6 +1,6 @@ -/* Conditionally execute a command based on machine and OS from config.h */ -/* Boehm, November 21, 1994 1:40 pm PST */ -# include "config.h" +/* Conditionally execute a command based on machine and OS from gcconfig.h */ + +# include "gcconfig.h" # include <stdio.h> int main(argc, argv, envp) diff --git a/boehm-gc/if_not_there.c b/boehm-gc/if_not_there.c index 9616309d824..a93795f1c78 100644 --- a/boehm-gc/if_not_there.c +++ b/boehm-gc/if_not_there.c @@ -1,6 +1,6 @@ /* Conditionally execute a command based if the file argv[1] doesn't exist */ /* Except for execvp, we stick to ANSI C. */ -# include "config.h" +# include "gcconfig.h" # include <stdio.h> int main(argc, argv, envp) diff --git a/boehm-gc/irix_threads.c b/boehm-gc/irix_threads.c index f45c4631c6e..5efca211034 100644 --- a/boehm-gc/irix_threads.c +++ b/boehm-gc/irix_threads.c @@ -25,6 +25,7 @@ # include "gc_priv.h" # include <pthread.h> +# include <semaphore.h> # include <time.h> # include <errno.h> # include <unistd.h> @@ -411,6 +412,7 @@ void GC_thr_init() GC_thread t; struct sigaction act; + if (GC_thr_initialized) return; GC_thr_initialized = TRUE; GC_min_stack_sz = HBLKSIZE; GC_page_sz = sysconf(_SC_PAGESIZE); @@ -445,9 +447,14 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) struct start_info { void *(*start_routine)(void *); void *arg; + word flags; + ptr_t stack; + size_t stack_size; + sem_t registered; /* 1 ==> in our thread table, but */ + /* parent hasn't yet noticed. */ }; -void GC_thread_exit_proc(void *dummy) +void GC_thread_exit_proc(void *arg) { GC_thread me; @@ -472,6 +479,9 @@ int GC_pthread_join(pthread_t thread, void **retval) /* cant have been recycled by pthreads. */ UNLOCK(); result = pthread_join(thread, retval); + /* Some versions of the Irix pthreads library can erroneously */ + /* return EINTR when the call succeeds. */ + if (EINTR == result) result = 0; LOCK(); /* Here the pthread thread id may have been recycled. */ GC_delete_gc_thread(thread, thread_gc_id); @@ -484,12 +494,34 @@ void * GC_start_routine(void * arg) struct start_info * si = arg; void * result; GC_thread me; - + pthread_t my_pthread; + void *(*start)(void *); + void *start_arg; + + my_pthread = pthread_self(); + /* If a GC occurs before the thread is registered, that GC will */ + /* ignore this thread. That's fine, since it will block trying to */ + /* acquire the allocation lock, and won't yet hold interesting */ + /* pointers. */ LOCK(); - me = GC_lookup_thread(pthread_self()); + /* We register the thread here instead of in the parent, so that */ + /* we don't need to hold the allocation lock during pthread_create. */ + /* Holding the allocation lock there would make REDIRECT_MALLOC */ + /* impossible. It probably still doesn't work, but we're a little */ + /* closer ... */ + /* This unfortunately means that we have to be careful the parent */ + /* doesn't try to do a pthread_join before we're registered. */ + me = GC_new_thread(my_pthread); + me -> flags = si -> flags; + me -> stack = si -> stack; + me -> stack_size = si -> stack_size; + me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word); UNLOCK(); + start = si -> start_routine; + start_arg = si -> arg; + sem_post(&(si -> registered)); pthread_cleanup_push(GC_thread_exit_proc, 0); - result = (*(si -> start_routine))(si -> arg); + result = (*start)(start_arg); me -> status = result; me -> flags |= FINISHED; pthread_cleanup_pop(1); @@ -506,15 +538,17 @@ GC_pthread_create(pthread_t *new_thread, { int result; GC_thread t; - pthread_t my_new_thread; void * stack; size_t stacksize; pthread_attr_t new_attr; int detachstate; word my_flags = 0; struct start_info * si = GC_malloc(sizeof(struct start_info)); + /* This is otherwise saved only in an area mmapped by the thread */ + /* library, which isn't visible to the collector. */ if (0 == si) return(ENOMEM); + sem_init(&(si -> registered), 0, 0); si -> start_routine = start_routine; si -> arg = arg; LOCK(); @@ -540,20 +574,20 @@ GC_pthread_create(pthread_t *new_thread, my_flags |= CLIENT_OWNS_STACK; } if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED; - result = pthread_create(&my_new_thread, &new_attr, GC_start_routine, si); - /* No GC can start until the thread is registered, since we hold */ - /* the allocation lock. */ - if (0 == result) { - t = GC_new_thread(my_new_thread); - t -> flags = my_flags; - t -> stack = stack; - t -> stack_size = stacksize; - t -> stack_ptr = (ptr_t)stack + stacksize - sizeof(word); - if (0 != new_thread) *new_thread = my_new_thread; - } else if (!(my_flags & CLIENT_OWNS_STACK)) { + si -> flags = my_flags; + si -> stack = stack; + si -> stack_size = stacksize; + result = pthread_create(new_thread, &new_attr, GC_start_routine, si); + if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) { GC_stack_free(stack, stacksize); } UNLOCK(); + /* Wait until child has been added to the thread table. */ + /* This also ensures that we hold onto si until the child is done */ + /* with it. Thus it doesn't matter whether it is otherwise */ + /* visible to the collector. */ + if (0 != sem_wait(&(si -> registered))) ABORT("sem_wait failed"); + sem_destroy(&(si -> registered)); /* pthread_attr_destroy(&new_attr); */ return(result); } diff --git a/boehm-gc/linux_threads.c b/boehm-gc/linux_threads.c index f83e1dd37b2..8287dce647b 100644 --- a/boehm-gc/linux_threads.c +++ b/boehm-gc/linux_threads.c @@ -28,9 +28,13 @@ * there too. */ -# if defined(LINUX_THREADS) +/* #define DEBUG_THREADS 1 */ +/* ANSI C requires that a compilation unit contains something */ # include "gc_priv.h" + +# if defined(LINUX_THREADS) + # include <pthread.h> # include <time.h> # include <errno.h> @@ -114,17 +118,12 @@ GC_linux_thread_top_of_stack() relies on implementation details of LinuxThreads, namely that thread stacks are allocated on 2M boundaries and grow to no more than 2M. To make sure that we're using LinuxThreads and not some other thread -package, we generate a dummy reference to `__pthread_initial_thread_bos', +package, we generate a dummy reference to `pthread_kill_other_threads_np' +(was `__pthread_initial_thread_bos' but that disappeared), which is a symbol defined in LinuxThreads, but (hopefully) not in other thread packages. */ -#if 0 -/* Note: on Caldera OpenLinux, this symbols is `local' in the - libpthread.so (but not in libpthread.a). We don't really need - this, so we just comment it out. */ -extern char * __pthread_initial_thread_bos; -char **dummy_var_to_force_linux_threads = &__pthread_initial_thread_bos; -#endif +void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np; #define LINUX_THREADS_STACK_SIZE (2 * 1024 * 1024) @@ -424,6 +423,7 @@ void GC_thr_init() GC_thread t; struct sigaction act; + if (GC_thr_initialized) return; GC_thr_initialized = TRUE; if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0) @@ -446,7 +446,7 @@ void GC_thr_init() /* Add the initial thread, so we can stop it. */ t = GC_new_thread(pthread_self()); - t -> stack_ptr = (ptr_t)(&t); + t -> stack_ptr = 0; t -> flags = DETACHED | MAIN_THREAD; } @@ -465,11 +465,16 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) struct start_info { void *(*start_routine)(void *); void *arg; + word flags; + sem_t registered; /* 1 ==> in our thread table, but */ + /* parent hasn't yet noticed. */ }; -void GC_thread_exit_proc(void *dummy) + +void GC_thread_exit_proc(void *arg) { GC_thread me; + struct start_info * si = arg; LOCK(); me = GC_lookup_thread(pthread_self()); @@ -504,26 +509,37 @@ void * GC_start_routine(void * arg) struct start_info * si = arg; void * result; GC_thread me; + pthread_t my_pthread; + void *(*start)(void *); + void *start_arg; + my_pthread = pthread_self(); LOCK(); - me = GC_lookup_thread(pthread_self()); + me = GC_new_thread(my_pthread); + me -> flags = si -> flags; + me -> stack_ptr = 0; + me -> stack_end = 0; UNLOCK(); - pthread_cleanup_push(GC_thread_exit_proc, 0); + start = si -> start_routine; + start_arg = si -> arg; + sem_post(&(si -> registered)); + pthread_cleanup_push(GC_thread_exit_proc, si); # ifdef DEBUG_THREADS - GC_printf1("Starting thread 0x%x\n", pthread_self()); + GC_printf1("Starting thread 0x%lx\n", pthread_self()); GC_printf1("pid = %ld\n", (long) getpid()); GC_printf1("sp = 0x%lx\n", (long) &arg); + GC_printf1("start_routine = 0x%lx\n", start); # endif - result = (*(si -> start_routine))(si -> arg); + result = (*start)(start_arg); #if DEBUG_THREADS GC_printf1("Finishing thread 0x%x\n", pthread_self()); #endif me -> status = result; me -> flags |= FINISHED; pthread_cleanup_pop(1); - /* This involves acquiring the lock, ensuring that we can't exit */ - /* while a collection that thinks we're alive is trying to stop */ - /* us. */ + /* Cleanup acquires lock, ensuring that we can't exit */ + /* while a collection that thinks we're alive is trying to stop */ + /* us. */ return(result); } @@ -541,8 +557,11 @@ GC_pthread_create(pthread_t *new_thread, int detachstate; word my_flags = 0; struct start_info * si = GC_malloc(sizeof(struct start_info)); + /* This is otherwise saved only in an area mmapped by the thread */ + /* library, which isn't visible to the collector. */ if (0 == si) return(ENOMEM); + sem_init(&(si -> registered), 0, 0); si -> start_routine = start_routine; si -> arg = arg; LOCK(); @@ -555,17 +574,16 @@ GC_pthread_create(pthread_t *new_thread, } pthread_attr_getdetachstate(&new_attr, &detachstate); if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED; - result = pthread_create(&my_new_thread, &new_attr, GC_start_routine, si); - /* No GC can start until the thread is registered, since we hold */ - /* the allocation lock. */ - if (0 == result) { - t = GC_new_thread(my_new_thread); - t -> flags = my_flags; - t -> stack_ptr = 0; - t -> stack_end = 0; - if (0 != new_thread) *new_thread = my_new_thread; - } - UNLOCK(); + si -> flags = my_flags; + UNLOCK(); + result = pthread_create(new_thread, &new_attr, GC_start_routine, si); + /* Wait until child has been added to the thread table. */ + /* This also ensures that we hold onto si until the child is done */ + /* with it. Thus it doesn't matter whether it is otherwise */ + /* visible to the collector. */ + if (0 != sem_wait(&(si -> registered))) ABORT("sem_wait failed"); + sem_destroy(&(si -> registered)); + /* pthread_attr_destroy(&new_attr); */ /* pthread_attr_destroy(&new_attr); */ return(result); } diff --git a/boehm-gc/mach_dep.c b/boehm-gc/mach_dep.c index e39880b46ac..52f86346761 100644 --- a/boehm-gc/mach_dep.c +++ b/boehm-gc/mach_dep.c @@ -20,7 +20,11 @@ # define _longjmp(b,v) longjmp(b,v) # endif # ifdef AMIGA -# include <dos.h> +# ifndef __GNUC__ +# include <dos/dos.h> +# else +# include <machine/reg.h> +# endif # endif #if defined(__MWERKS__) && !defined(POWERPC) @@ -58,12 +62,19 @@ asm static void PushMacRegisters() #endif /* __MWERKS__ */ +# if defined(SPARC) || defined(IA64) + /* Value returned from register flushing routine; either sp (SPARC) */ + /* or ar.bsp (IA64) */ + word GC_save_regs_ret_val; +# endif + /* Routine to mark from registers that are preserved by the C compiler. */ /* This must be ported to every new architecture. There is a generic */ /* version at the end, that is likely, but not guaranteed to work */ /* on your architecture. Run the test_setjmp program to see whether */ /* there is any chance it will work. */ +#ifndef USE_GENERIC_PUSH_REGS void GC_push_regs() { # ifdef RT @@ -125,9 +136,28 @@ void GC_push_regs() asm("addq.w &0x4,%sp"); /* put stack back where it was */ # endif /* M68K HP */ -# ifdef AMIGA - /* AMIGA - could be replaced by generic code */ - /* a0, a1, d0 and d1 are caller save */ +# if defined(M68K) && defined(AMIGA) + /* AMIGA - could be replaced by generic code */ + /* a0, a1, d0 and d1 are caller save */ + +# ifdef __GNUC__ + asm("subq.w &0x4,%sp"); /* allocate word on top of stack */ + + asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one"); + /* Skip frame pointer and stack pointer */ + asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one"); + asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one"); + + asm("addq.w &0x4,%sp"); /* put stack back where it was */ +# else /* !__GNUC__ */ GC_push_one(getreg(REG_A2)); GC_push_one(getreg(REG_A3)); GC_push_one(getreg(REG_A4)); @@ -140,7 +170,8 @@ void GC_push_regs() GC_push_one(getreg(REG_D5)); GC_push_one(getreg(REG_D6)); GC_push_one(getreg(REG_D7)); -# endif +# endif /* !__GNUC__ */ +# endif /* AMIGA */ # if defined(M68K) && defined(MACOS) # if defined(THINK_C) @@ -169,8 +200,10 @@ void GC_push_regs() # endif /* MACOS */ # if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) \ - && !defined(SCO) && !defined(SCO_ELF) && !(defined(LINUX) \ - && defined(__ELF__)) && !defined(DOS4GW) && !defined(FREEBSD) + && !defined(SCO) && !defined(SCO_ELF) \ + && !(defined(LINUX) && defined(__ELF__)) \ + && !(defined(__FreeBSD__) && defined(__ELF__)) \ + && !defined(DOS4GW) /* 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 */ @@ -183,8 +216,11 @@ void GC_push_regs() asm("pushl %ebx"); asm("call _GC_push_one"); asm("addl $4,%esp"); # endif -# if defined(I386) && (defined(LINUX) || defined(FREEBSD)) && defined(__ELF__) - /* This is modified for Linux/FreeBSD with ELF (Note: _ELF_ only) */ +# if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \ + || ( defined(I386) && defined(__FreeBSD__) && defined(__ELF__) ) + + /* This is modified for Linux with ELF (Note: _ELF_ only) */ + /* This section handles FreeBSD with ELF. */ asm("pushl %eax"); asm("call GC_push_one"); asm("addl $4,%esp"); asm("pushl %ecx"); asm("call GC_push_one"); asm("addl $4,%esp"); asm("pushl %edx"); asm("call GC_push_one"); asm("addl $4,%esp"); @@ -238,12 +274,12 @@ void GC_push_regs() asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4"); # endif -# ifdef SPARC +# if defined(SPARC) || defined(IA64) { word GC_save_regs_in_stack(); /* generic code will not work */ - (void)GC_save_regs_in_stack(); + GC_save_regs_ret_val = GC_save_regs_in_stack(); } # endif @@ -303,8 +339,32 @@ void GC_push_regs() # endif /* !__GNUC__ */ # endif /* M68K/SYSV */ +# if defined(PJ) + { + register int * sp asm ("optop"); + extern int *__libc_stack_end; -# if defined(HP_PA) || defined(M88K) || defined(POWERPC) || (defined(I386) && (defined(OS2) || defined(USE_GENERIC))) || defined(UTS4) + GC_push_all_stack (sp, __libc_stack_end); + } +# endif + + /* other machines... */ +# if !(defined M68K) && !(defined VAX) && !(defined RT) +# if !(defined SPARC) && !(defined I386) && !(defined NS32K) +# if !defined(POWERPC) && !defined(UTS4) && !defined(IA64) +# if !defined(PJ) + --> bad news <-- +# endif +# endif +# endif +# endif +} +#endif /* !USE_GENERIC_PUSH_REGS */ + +#if defined(USE_GENERIC_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 */ @@ -324,28 +384,10 @@ void GC_push_regs() # else (void) _setjmp(regs); # endif - GC_push_all_stack((ptr_t)regs, lim); + GC_push_current_stack(cold_gc_frame); } -# endif -# if defined(PJ) - { - register int * sp asm ("optop"); - extern int *__libc_stack_end; - - GC_push_all_stack (sp, __libc_stack_end); - } -# endif - /* other machines... */ -# if !(defined M68K) && !(defined VAX) && !(defined RT) -# if !(defined SPARC) && !(defined I386) && !(defined NS32K) -# if !defined(HP_PA) && !defined(M88K) && !defined(POWERPC) -# if !defined(UTS4) && !defined(PJ) - --> bad news <-- -# endif -# endif -# endif -# endif } +#endif /* USE_GENERIC_PUSH_REGS */ /* On register window machines, we need a way to force registers into */ /* the stack. Return sp. */ @@ -372,6 +414,27 @@ void GC_push_regs() # endif # endif +/* On IA64, we also need to flush register windows. But they end */ +/* up on the other side of the stack segment. */ +/* Returns the backing store pointer for the register stack. */ +# ifdef IA64 + asm(" .text"); + asm(" .psr abi64"); + asm(" .psr lsb"); + asm(" .lsb"); + asm(""); + asm(" .text"); + asm(" .align 16"); + asm(" .global GC_save_regs_in_stack"); + asm(" .proc GC_save_regs_in_stack"); + asm("GC_save_regs_in_stack:"); + asm(" .body"); + asm(" flushrs"); + asm(" ;;"); + asm(" mov r8=ar.bsp"); + asm(" br.ret.sptk.few rp"); + asm(" .endp GC_save_regs_in_stack"); +# endif /* GC_clear_stack_inner(arg, limit) clears stack area up to limit and */ /* returns arg. Stack clearing is crucial on SPARC, so we supply */ diff --git a/boehm-gc/malloc.c b/boehm-gc/malloc.c index 41553b7f376..66e62d29694 100644 --- a/boehm-gc/malloc.c +++ b/boehm-gc/malloc.c @@ -93,8 +93,16 @@ register ptr_t *opp; if(GC_incremental && !GC_dont_gc) GC_collect_a_little_inner((int)n_blocks); lw = ROUNDED_UP_WORDS(lb); - while ((h = GC_allochblk(lw, k, 0)) == 0 - && GC_collect_or_expand(n_blocks, FALSE)); + h = GC_allochblk(lw, k, 0); +# ifdef USE_MUNMAP + if (0 == h) { + GC_merge_unmapped(); + h = GC_allochblk(lw, k, 0); + } +# endif + while (0 == h && GC_collect_or_expand(n_blocks, FALSE)) { + h = GC_allochblk(lw, k, 0); + } if (h == 0) { op = 0; } else { @@ -220,6 +228,9 @@ DCL_LOCK_STATE; /* * Thread initialisation can call malloc before * we're ready for it. + * It's not clear that this is enough to help matters. + * The thread implementation may well call malloc at other + * inopportune times. */ if (!GC_is_initialized) return sbrk(lb); # endif /* I386 && SOLARIS_THREADS */ @@ -375,6 +386,12 @@ int obj_kind; /* Required by ANSI. It's not my fault ... */ h = HBLKPTR(p); hhdr = HDR(h); +# if defined(REDIRECT_MALLOC) && \ + (defined(SOLARIS_THREADS) || defined(LINUX_THREADS)) + /* We have to redirect malloc calls during initialization. */ + /* Don't try to deallocate that memory. */ + if (0 == hhdr) return; +# endif knd = hhdr -> hb_obj_kind; sz = hhdr -> hb_sz; ok = &GC_obj_kinds[knd]; diff --git a/boehm-gc/mallocx.c b/boehm-gc/mallocx.c index ae8bfffb8af..8c07fa98846 100644 --- a/boehm-gc/mallocx.c +++ b/boehm-gc/mallocx.c @@ -57,8 +57,16 @@ register int k; if(GC_incremental && !GC_dont_gc) GC_collect_a_little_inner((int)n_blocks); lw = ROUNDED_UP_WORDS(lb); - while ((h = GC_allochblk(lw, k, IGNORE_OFF_PAGE)) == 0 - && GC_collect_or_expand(n_blocks, TRUE)); + h = GC_allochblk(lw, k, IGNORE_OFF_PAGE); +# ifdef USE_MUNMAP + if (0 == h) { + GC_merge_unmapped(); + h = GC_allochblk(lw, k, IGNORE_OFF_PAGE); + } +# endif + while (0 == h && GC_collect_or_expand(n_blocks, TRUE)) { + h = GC_allochblk(lw, k, IGNORE_OFF_PAGE); + } if (h == 0) { op = 0; } else { @@ -130,7 +138,7 @@ void GC_incr_mem_freed(size_t n) ptr_t GC_generic_malloc_words_small(size_t lw, int k) #else ptr_t GC_generic_malloc_words_small(lw, k) - register size_t lw; + register word lw; register int k; #endif { @@ -148,7 +156,7 @@ DCL_LOCK_STATE; GC_init_inner(); } if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) { - op = GC_clear_stack(GC_allocobj(lw, k)); + op = GC_clear_stack(GC_allocobj((word)lw, k)); } if (op == 0) { UNLOCK(); diff --git a/boehm-gc/mark.c b/boehm-gc/mark.c index 632e792c56f..ef0e0c088e0 100644 --- a/boehm-gc/mark.c +++ b/boehm-gc/mark.c @@ -21,7 +21,11 @@ /* We put this here to minimize the risk of inlining. */ /*VARARGS*/ -void GC_noop() {} +#ifdef __WATCOMC__ + void GC_noop(void *p, ...) {} +#else + void GC_noop() {} +#endif /* Single argument version, robust against whole program analysis. */ void GC_noop1(x) @@ -32,7 +36,8 @@ word x; sink = x; } -mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0}; +/* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */ + word GC_n_mark_procs = 0; /* Initialize GC_obj_kinds properly and standard free lists properly. */ @@ -82,6 +87,10 @@ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = { # define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE) /* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a */ /* multiple of HBLKSIZE. */ + /* The incremental collector actually likes a larger */ + /* size, since it want to push all marked dirty objs */ + /* before marking anything new. Currently we let it */ + /* grow dynamically. */ # endif /* @@ -108,6 +117,9 @@ GC_bool GC_mark_stack_too_small = FALSE; GC_bool GC_objects_are_marked = FALSE; /* Are there collectable marked */ /* objects in the heap? */ +/* Is a collection in progress? Note that this can return true in the */ +/* nonincremental case, if a collection has been abandoned and the */ +/* mark state is now MS_INVALID. */ GC_bool GC_collection_in_progress() { return(GC_mark_state != MS_NONE); @@ -233,7 +245,12 @@ static void alloc_mark_stack(); /* Perform a small amount of marking. */ /* We try to touch roughly a page of memory. */ /* Return TRUE if we just finished a mark phase. */ -GC_bool GC_mark_some() +/* Cold_gc_frame is an address inside a GC frame that */ +/* remains valid until all marking is complete. */ +/* A zero value indicates that it's OK to miss some */ +/* register values. */ +GC_bool GC_mark_some(cold_gc_frame) +ptr_t cold_gc_frame; { switch(GC_mark_state) { case MS_NONE: @@ -241,7 +258,12 @@ GC_bool GC_mark_some() case MS_PUSH_RESCUERS: if (GC_mark_stack_top - >= GC_mark_stack + INITIAL_MARK_STACK_SIZE/4) { + >= GC_mark_stack + GC_mark_stack_size + - INITIAL_MARK_STACK_SIZE/2) { + /* Go ahead and mark, even though that might cause us to */ + /* see more marked dirty objects later on. Avoid this */ + /* in the future. */ + GC_mark_stack_too_small = TRUE; GC_mark_from_mark_stack(); return(FALSE); } else { @@ -251,7 +273,7 @@ GC_bool GC_mark_some() GC_printf1("Marked from %lu dirty pages\n", (unsigned long)GC_n_rescuing_pages); # endif - GC_push_roots(FALSE); + GC_push_roots(FALSE, cold_gc_frame); GC_objects_are_marked = TRUE; if (GC_mark_state != MS_INVALID) { GC_mark_state = MS_ROOTS_PUSHED; @@ -268,7 +290,7 @@ GC_bool GC_mark_some() } else { scan_ptr = GC_push_next_marked_uncollectable(scan_ptr); if (scan_ptr == 0) { - GC_push_roots(TRUE); + GC_push_roots(TRUE, cold_gc_frame); GC_objects_are_marked = TRUE; if (GC_mark_state != MS_INVALID) { GC_mark_state = MS_ROOTS_PUSHED; @@ -299,14 +321,17 @@ GC_bool GC_mark_some() GC_mark_from_mark_stack(); return(FALSE); } - if (scan_ptr == 0 - && (GC_mark_state == MS_INVALID || GC_mark_stack_too_small)) { - alloc_mark_stack(2*GC_mark_stack_size); + if (scan_ptr == 0 && GC_mark_state == MS_INVALID) { + /* About to start a heap scan for marked objects. */ + /* Mark stack is empty. OK to reallocate. */ + if (GC_mark_stack_too_small) { + alloc_mark_stack(2*GC_mark_stack_size); + } GC_mark_state = MS_PARTIALLY_INVALID; } scan_ptr = GC_push_next_marked(scan_ptr); if (scan_ptr == 0 && GC_mark_state == MS_PARTIALLY_INVALID) { - GC_push_roots(TRUE); + GC_push_roots(TRUE, cold_gc_frame); GC_objects_are_marked = TRUE; if (GC_mark_state != MS_INVALID) { GC_mark_state = MS_ROOTS_PUSHED; @@ -388,6 +413,7 @@ mse * GC_signal_mark_stack_overflow(msp) mse * msp; { GC_mark_state = MS_INVALID; + GC_mark_stack_too_small = TRUE; # ifdef PRINTSTATS GC_printf1("Mark stack overflow; current size = %lu entries\n", GC_mark_stack_size); @@ -507,13 +533,15 @@ word n; if (GC_mark_stack_size != 0) { if (new_stack != 0) { word displ = (word)GC_mark_stack & (GC_page_size - 1); - word size = GC_mark_stack_size * sizeof(struct ms_entry); + signed_word size = GC_mark_stack_size * sizeof(struct ms_entry); /* Recycle old space */ if (0 != displ) displ = GC_page_size - displ; size = (size - displ) & ~(GC_page_size - 1); - GC_add_to_heap((struct hblk *) - ((word)GC_mark_stack + displ), size); + if (size > 0) { + GC_add_to_heap((struct hblk *) + ((word)GC_mark_stack + displ), (word)size); + } GC_mark_stack = new_stack; GC_mark_stack_size = n; # ifdef PRINTSTATS @@ -655,7 +683,13 @@ int all; # endif word p; { - GC_PUSH_ONE_STACK(p); +# ifdef NURSERY + if (0 != GC_push_proc) { + GC_push_proc(p); + return; + } +# endif + GC_PUSH_ONE_STACK(p, 0); } # ifdef __STDC__ @@ -665,7 +699,7 @@ word p; # endif /* As above, but argument passed preliminary test. */ -# ifdef PRINT_BLACK_LIST +# if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS) void GC_push_one_checked(p, interior_ptrs, source) ptr_t source; # else @@ -694,13 +728,18 @@ register GC_bool interior_ptrs; displ = HBLKDISPL(p); map_entry = MAP_ENTRY((hhdr -> hb_map), displ); if (map_entry == OBJ_INVALID) { - if (interior_ptrs) { - r = BASE(p); - displ = BYTES_TO_WORDS(HBLKDISPL(r)); - if (r == 0) hhdr = 0; - } else { - hhdr = 0; - } +# ifndef ALL_INTERIOR_POINTERS + if (interior_ptrs) { + r = BASE(p); + displ = BYTES_TO_WORDS(HBLKDISPL(r)); + if (r == 0) hhdr = 0; + } else { + hhdr = 0; + } +# else + /* map already reflects interior pointers */ + hhdr = 0; +# endif } else { displ = BYTES_TO_WORDS(displ); displ -= map_entry; @@ -723,6 +762,7 @@ register GC_bool interior_ptrs; } else { if (!mark_bit_from_hdr(hhdr, displ)) { set_mark_bit_from_hdr(hhdr, displ); + GC_STORE_BACK_PTR(source, (ptr_t)r); PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top, &(GC_mark_stack[GC_mark_stack_size])); } @@ -776,17 +816,13 @@ void GC_print_trace(word gc_no, GC_bool lock) /* * A version of GC_push_all that treats all interior pointers as valid + * and scans the entire region immediately, in case the contents + * change. */ -void GC_push_all_stack(bottom, top) +void GC_push_all_eager(bottom, top) ptr_t bottom; ptr_t top; { -# ifdef ALL_INTERIOR_POINTERS - GC_push_all(bottom, top); -# ifdef TRACE_BUF - GC_add_trace_entry("GC_push_all_stack", bottom, top); -# endif -# else word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1)); word * t = (word *)(((long) top) & ~(ALIGNMENT-1)); register word *p; @@ -803,10 +839,58 @@ ptr_t top; lim = t - 1 /* longword */; for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) { q = *p; - GC_PUSH_ONE_STACK(q); + GC_PUSH_ONE_STACK(q, p); } # undef GC_greatest_plausible_heap_addr # undef GC_least_plausible_heap_addr +} + +#ifndef THREADS +/* + * A version of GC_push_all that treats all interior pointers as valid + * and scans part of the area immediately, to make sure that saved + * register values are not lost. + * Cold_gc_frame delimits the stack section that must be scanned + * eagerly. A zero value indicates that no eager scanning is needed. + */ +void GC_push_all_stack_partially_eager(bottom, top, cold_gc_frame) +ptr_t bottom; +ptr_t top; +ptr_t cold_gc_frame; +{ +# ifdef ALL_INTERIOR_POINTERS +# define EAGER_BYTES 1024 + /* Push the hot end of the stack eagerly, so that register values */ + /* saved inside GC frames are marked before they disappear. */ + /* The rest of the marking can be deferred until later. */ + if (0 == cold_gc_frame) { + GC_push_all_stack(bottom, top); + return; + } +# ifdef STACK_GROWS_DOWN + GC_push_all_eager(bottom, cold_gc_frame); + GC_push_all(cold_gc_frame - sizeof(ptr_t), top); +# else /* STACK_GROWS_UP */ + GC_push_all_eager(cold_gc_frame, top); + GC_push_all(bottom, cold_gc_frame + sizeof(ptr_t)); +# endif /* STACK_GROWS_UP */ +# else + GC_push_all_eager(bottom, top); +# endif +# ifdef TRACE_BUF + GC_add_trace_entry("GC_push_all_stack", bottom, top); +# endif +} +#endif /* !THREADS */ + +void GC_push_all_stack(bottom, top) +ptr_t bottom; +ptr_t top; +{ +# ifdef ALL_INTERIOR_POINTERS + GC_push_all(bottom, top); +# else + GC_push_all_eager(bottom, top); # endif } @@ -838,7 +922,7 @@ register hdr * hhdr; while(mark_word != 0) { if (mark_word & 1) { q = p[i]; - GC_PUSH_ONE_HEAP(q); + GC_PUSH_ONE_HEAP(q, p + i); } i++; mark_word >>= 1; @@ -879,9 +963,9 @@ register hdr * hhdr; while(mark_word != 0) { if (mark_word & 1) { q = p[i]; - GC_PUSH_ONE_HEAP(q); + GC_PUSH_ONE_HEAP(q, p + i); q = p[i+1]; - GC_PUSH_ONE_HEAP(q); + GC_PUSH_ONE_HEAP(q, p + i); } i += 2; mark_word >>= 2; @@ -921,13 +1005,13 @@ register hdr * hhdr; while(mark_word != 0) { if (mark_word & 1) { q = p[i]; - GC_PUSH_ONE_HEAP(q); + GC_PUSH_ONE_HEAP(q, p + i); q = p[i+1]; - GC_PUSH_ONE_HEAP(q); + GC_PUSH_ONE_HEAP(q, p + i + 1); q = p[i+2]; - GC_PUSH_ONE_HEAP(q); + GC_PUSH_ONE_HEAP(q, p + i + 2); q = p[i+3]; - GC_PUSH_ONE_HEAP(q); + GC_PUSH_ONE_HEAP(q, p + i + 3); } i += 4; mark_word >>= 4; @@ -1037,7 +1121,7 @@ struct hblk *h; { register hdr * hhdr; - h = GC_next_block(h); + h = GC_next_used_block(h); if (h == 0) return(0); hhdr = HDR(h); GC_push_marked(h, hhdr); @@ -1049,11 +1133,11 @@ struct hblk *h; struct hblk * GC_push_next_marked_dirty(h) struct hblk *h; { - register hdr * hhdr = HDR(h); + register hdr * hhdr; if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); } for (;;) { - h = GC_next_block(h); + h = GC_next_used_block(h); if (h == 0) return(0); hhdr = HDR(h); # ifdef STUBBORN_ALLOC @@ -1082,7 +1166,7 @@ struct hblk *h; register hdr * hhdr = HDR(h); for (;;) { - h = GC_next_block(h); + h = GC_next_used_block(h); if (h == 0) return(0); hhdr = HDR(h); if (hhdr -> hb_obj_kind == UNCOLLECTABLE) break; diff --git a/boehm-gc/mark_rts.c b/boehm-gc/mark_rts.c index efe6b64058f..0e84f2732fc 100644 --- a/boehm-gc/mark_rts.c +++ b/boehm-gc/mark_rts.c @@ -15,46 +15,27 @@ # include <stdio.h> # include "gc_priv.h" -/* MAX_ROOT_SETS is the maximum number of ranges that can be */ -/* registered as static roots. */ -# ifdef LARGE_CONFIG -# define MAX_ROOT_SETS 4096 -# else -# ifdef PCR -# define MAX_ROOT_SETS 1024 -# else -# ifdef MSWIN32 -# define MAX_ROOT_SETS 512 - /* Under NT, we add only written pages, which can result */ - /* in many small root sets. */ -# else -# define MAX_ROOT_SETS 64 -# endif -# endif -# endif - -# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4) -/* Maximum number of segments that can be excluded from root sets. */ - /* Data structure for list of root sets. */ /* We keep a hash table, so that we can filter out duplicate additions. */ /* Under Win32, we need to do a better job of filtering overlaps, so */ /* we resort to sequential search, and pay the price. */ +/* This is really declared in gc_priv.h: struct roots { ptr_t r_start; ptr_t r_end; -# ifndef MSWIN32 + # ifndef MSWIN32 struct roots * r_next; -# endif + # endif GC_bool r_tmp; - /* Delete before registering new dynamic libraries */ + -- Delete before registering new dynamic libraries }; -static struct roots static_roots[MAX_ROOT_SETS]; +struct roots GC_static_roots[MAX_ROOT_SETS]; +*/ static int n_root_sets = 0; - /* static_roots[0..n_root_sets) contains the valid root sets. */ + /* GC_static_roots[0..n_root_sets) contains the valid root sets. */ # if !defined(NO_DEBUGGING) /* For debugging: */ @@ -65,14 +46,14 @@ void GC_print_static_roots() for (i = 0; i < n_root_sets; i++) { GC_printf2("From 0x%lx to 0x%lx ", - (unsigned long) static_roots[i].r_start, - (unsigned long) static_roots[i].r_end); - if (static_roots[i].r_tmp) { + (unsigned long) GC_static_roots[i].r_start, + (unsigned long) GC_static_roots[i].r_end); + if (GC_static_roots[i].r_tmp) { GC_printf0(" (temporary)\n"); } else { GC_printf0("\n"); } - total += static_roots[i].r_end - static_roots[i].r_start; + total += GC_static_roots[i].r_end - GC_static_roots[i].r_start; } GC_printf1("Total size: %ld\n", (unsigned long) total); if (GC_root_size != total) { @@ -92,11 +73,11 @@ ptr_t p; register int i; - if (p >= static_roots[last_root_set].r_start - && p < static_roots[last_root_set].r_end) return(TRUE); + if (p >= GC_static_roots[last_root_set].r_start + && p < GC_static_roots[last_root_set].r_end) return(TRUE); for (i = 0; i < n_root_sets; i++) { - if (p >= static_roots[i].r_start - && p < static_roots[i].r_end) { + if (p >= GC_static_roots[i].r_start + && p < GC_static_roots[i].r_end) { last_root_set = i; return(TRUE); } @@ -105,12 +86,15 @@ ptr_t p; } #ifndef MSWIN32 +/* # define LOG_RT_SIZE 6 -# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */ +# define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS - static struct roots * root_index[RT_SIZE]; - /* Hash table header. Used only to check whether a range is */ - /* already present. */ + struct roots * GC_root_index[RT_SIZE]; + -- Hash table header. Used only to check whether a range is + -- already present. + -- really defined in gc_priv.h +*/ static int rt_hash(addr) char * addr; @@ -134,7 +118,7 @@ struct roots * GC_roots_present(b) char *b; { register int h = rt_hash(b); - register struct roots *p = root_index[h]; + register struct roots *p = GC_root_index[h]; while (p != 0) { if (p -> r_start == (ptr_t)b) return(p); @@ -149,8 +133,8 @@ struct roots *p; { register int h = rt_hash(p -> r_start); - p -> r_next = root_index[h]; - root_index[h] = p; + p -> r_next = GC_root_index[h]; + GC_root_index[h] = p; } # else /* MSWIN32 */ @@ -200,7 +184,7 @@ GC_bool tmp; register int i; for (i = 0; i < n_root_sets; i++) { - old = static_roots + i; + old = GC_static_roots + i; if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) { if ((ptr_t)b < old -> r_start) { old -> r_start = (ptr_t)b; @@ -219,7 +203,7 @@ GC_bool tmp; struct roots *other; for (i++; i < n_root_sets; i++) { - other = static_roots + i; + other = GC_static_roots + i; b = (char *)(other -> r_start); e = (char *)(other -> r_end); if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) { @@ -234,8 +218,8 @@ GC_bool tmp; old -> r_tmp &= other -> r_tmp; /* Delete this entry. */ GC_root_size -= (other -> r_end - other -> r_start); - other -> r_start = static_roots[n_root_sets-1].r_start; - other -> r_end = static_roots[n_root_sets-1].r_end; + other -> r_start = GC_static_roots[n_root_sets-1].r_start; + other -> r_end = GC_static_roots[n_root_sets-1].r_end; n_root_sets--; } } @@ -255,13 +239,13 @@ GC_bool tmp; if (n_root_sets == MAX_ROOT_SETS) { ABORT("Too many root sets\n"); } - static_roots[n_root_sets].r_start = (ptr_t)b; - static_roots[n_root_sets].r_end = (ptr_t)e; - static_roots[n_root_sets].r_tmp = tmp; + GC_static_roots[n_root_sets].r_start = (ptr_t)b; + GC_static_roots[n_root_sets].r_end = (ptr_t)e; + GC_static_roots[n_root_sets].r_tmp = tmp; # ifndef MSWIN32 - static_roots[n_root_sets].r_next = 0; + GC_static_roots[n_root_sets].r_next = 0; # endif - add_roots_to_index(static_roots + n_root_sets); + add_roots_to_index(GC_static_roots + n_root_sets); GC_root_size += (ptr_t)e - (ptr_t)b; n_root_sets++; } @@ -278,7 +262,7 @@ void GC_clear_roots GC_PROTO((void)) { register int i; - for (i = 0; i < RT_SIZE; i++) root_index[i] = 0; + for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0; } # endif UNLOCK(); @@ -291,11 +275,12 @@ void GC_remove_tmp_roots() register int i; for (i = 0; i < n_root_sets; ) { - if (static_roots[i].r_tmp) { - GC_root_size -= (static_roots[i].r_end - static_roots[i].r_start); - static_roots[i].r_start = static_roots[n_root_sets-1].r_start; - static_roots[i].r_end = static_roots[n_root_sets-1].r_end; - static_roots[i].r_tmp = static_roots[n_root_sets-1].r_tmp; + if (GC_static_roots[i].r_tmp) { + GC_root_size -= + (GC_static_roots[i].r_end - GC_static_roots[i].r_start); + GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start; + GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end; + GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp; n_root_sets--; } else { i++; @@ -305,8 +290,9 @@ void GC_remove_tmp_roots() { register int i; - for (i = 0; i < RT_SIZE; i++) root_index[i] = 0; - for (i = 0; i < n_root_sets; i++) add_roots_to_index(static_roots + i); + for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0; + for (i = 0; i < n_root_sets; i++) + add_roots_to_index(GC_static_roots + i); } # endif @@ -321,16 +307,19 @@ ptr_t GC_approx_sp() /* * Data structure for excluded static roots. - */ + * Real declaration is in gc_priv.h. + struct exclusion { ptr_t e_start; ptr_t e_end; }; -struct exclusion excl_table[MAX_EXCLUSIONS]; - /* Array of exclusions, ascending */ - /* address order. */ -size_t excl_table_entries = 0; /* Number of entries in use. */ +struct exclusion GC_excl_table[MAX_EXCLUSIONS]; + -- Array of exclusions, ascending + -- address order. +*/ + +size_t GC_excl_table_entries = 0; /* Number of entries in use. */ /* Return the first exclusion range that includes an address >= start_addr */ /* Assumes the exclusion table contains at least one entry (namely the */ @@ -339,20 +328,20 @@ struct exclusion * GC_next_exclusion(start_addr) ptr_t start_addr; { size_t low = 0; - size_t high = excl_table_entries - 1; + size_t high = GC_excl_table_entries - 1; size_t mid; while (high > low) { mid = (low + high) >> 1; /* low <= mid < high */ - if ((word) excl_table[mid].e_end <= (word) start_addr) { + if ((word) GC_excl_table[mid].e_end <= (word) start_addr) { low = mid + 1; } else { high = mid; } } - if ((word) excl_table[low].e_end <= (word) start_addr) return 0; - return excl_table + low; + if ((word) GC_excl_table[low].e_end <= (word) start_addr) return 0; + return GC_excl_table + low; } void GC_exclude_static_roots(start, finish) @@ -362,7 +351,7 @@ GC_PTR finish; struct exclusion * next; size_t next_index, i; - if (0 == excl_table_entries) { + if (0 == GC_excl_table_entries) { next = 0; } else { next = GC_next_exclusion(start); @@ -377,17 +366,17 @@ GC_PTR finish; next -> e_start = (ptr_t)start; return; } - next_index = next - excl_table; - for (i = excl_table_entries; i > next_index; --i) { - excl_table[i] = excl_table[i-1]; + next_index = next - GC_excl_table; + for (i = GC_excl_table_entries; i > next_index; --i) { + GC_excl_table[i] = GC_excl_table[i-1]; } } else { - next_index = excl_table_entries; + next_index = GC_excl_table_entries; } - if (excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions"); - excl_table[next_index].e_start = (ptr_t)start; - excl_table[next_index].e_end = (ptr_t)finish; - ++excl_table_entries; + if (GC_excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions"); + GC_excl_table[next_index].e_start = (ptr_t)start; + GC_excl_table[next_index].e_end = (ptr_t)finish; + ++GC_excl_table_entries; } /* Invoke push_conditional on ranges that are not excluded. */ @@ -411,13 +400,72 @@ int all; } /* + * In the absence of threads, push the stack contents. + * In the presence of threads, push enough of the current stack + * to ensure that callee-save registers saved in collector frames have been + * seen. + */ +void GC_push_current_stack(cold_gc_frame) +ptr_t cold_gc_frame; +{ +# if defined(THREADS) + if (0 == cold_gc_frame) return; +# ifdef STACK_GROWS_DOWN + GC_push_all_eager(GC_approx_sp(), cold_gc_frame); +# ifdef IA64 + --> fix this +# endif +# else + GC_push_all_eager( cold_gc_frame, GC_approx_sp() ); +# endif +# else +# ifdef STACK_GROWS_DOWN + GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom, + cold_gc_frame ); +# ifdef IA64 + /* We also need to push the register stack backing store. */ + /* This should really be done in the same way as the */ + /* regular stack. For now we fudge it a bit. */ + /* Note that the backing store grows up, so we can't use */ + /* GC_push_all_stack_partially_eager. */ + { + extern word GC_save_regs_ret_val; + /* Previously set to backing store pointer. */ + ptr_t bsp = (ptr_t) GC_save_regs_ret_val; + ptr_t cold_gc_bs_pointer; +# ifdef ALL_INTERIOR_POINTERS + cold_gc_bs_pointer = bsp - 2048; + if (cold_gc_bs_pointer < BACKING_STORE_BASE) { + cold_gc_bs_pointer = BACKING_STORE_BASE; + } + GC_push_all(BACKING_STORE_BASE, cold_gc_bs_pointer); +# else + cold_gc_bs_pointer = BACKING_STORE_BASE; +# endif + GC_push_all_eager(cold_gc_bs_pointer, bsp); + /* All values should be sufficiently aligned that we */ + /* dont have to worry about the boundary. */ + } +# endif +# else + GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(), + cold_gc_frame ); +# endif +# endif /* !THREADS */ +} + +/* * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional * on groups of pointers) on every top level accessible pointer. * If all is FALSE, arrange to push only possibly altered values. + * Cold_gc_frame is an address inside a GC frame that + * remains valid until all marking is complete. + * A zero value indicates that it's OK to miss some + * register values. */ - -void GC_push_roots(all) +void GC_push_roots(all, cold_gc_frame) GC_bool all; +ptr_t cold_gc_frame; { register int i; @@ -425,7 +473,11 @@ GC_bool all; * push registers - i.e., call GC_push_one(r) for each * register contents r. */ +# ifdef USE_GENERIC_PUSH_REGS + GC_generic_push_regs(cold_gc_frame); +# else GC_push_regs(); /* usually defined in machine_dep.c */ +# endif /* * Next push static data. This must happen early on, since it's @@ -440,20 +492,19 @@ GC_bool all; /* Mark everything in static data areas */ for (i = 0; i < n_root_sets; i++) { GC_push_conditional_with_exclusions( - static_roots[i].r_start, - static_roots[i].r_end, all); + GC_static_roots[i].r_start, + GC_static_roots[i].r_end, all); } /* * Now traverse stacks. */ -# ifndef THREADS - /* Mark everything on the stack. */ -# ifdef STACK_GROWS_DOWN - GC_push_all_stack( GC_approx_sp(), GC_stackbottom ); -# else - GC_push_all_stack( GC_stackbottom, GC_approx_sp() ); -# endif +# if !defined(USE_GENERIC_PUSH_REGS) + GC_push_current_stack(cold_gc_frame); + /* IN the threads case, this only pushes collector frames. */ + /* In the USE_GENERIC_PUSH_REGS case, this is done inside */ + /* GC_push_regs, so that we catch callee-save registers saved */ + /* inside the GC_push_regs frame. */ # endif if (GC_push_other_roots != 0) (*GC_push_other_roots)(); /* In the threads case, this also pushes thread stacks. */ diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c index 70f583f982d..348d08aa3b1 100644 --- a/boehm-gc/misc.c +++ b/boehm-gc/misc.c @@ -42,17 +42,19 @@ # ifdef WIN32_THREADS GC_API CRITICAL_SECTION GC_allocate_ml; # else -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) -# ifdef UNDEFINED - pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER; -# endif +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ + || defined(IRIX_JDK_THREADS) pthread_t GC_lock_holder = NO_THREAD; # else -# if defined(QUICK_THREADS) - /* Nothing. */ -# else - --> declare allocator lock here -# endif +# if defined(HPUX_THREADS) + pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER; +# else +# if defined(QUICK_THREADS) + /* Nothing */ +# else + --> declare allocator lock here +# endif +# endif # endif # endif # endif @@ -80,6 +82,12 @@ GC_bool GC_dont_gc = 0; GC_bool GC_quiet = 0; +#ifdef FIND_LEAK + int GC_find_leak = 1; +#else + int GC_find_leak = 0; +#endif + /*ARGSUSED*/ GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested)) { @@ -392,6 +400,11 @@ size_t GC_get_heap_size GC_PROTO(()) return ((size_t) GC_heapsize); } +size_t GC_get_free_bytes GC_PROTO(()) +{ + return ((size_t) GC_large_free_bytes); +} + size_t GC_get_bytes_since_gc GC_PROTO(()) { return ((size_t) WORDS_TO_BYTES(GC_words_allocd)); @@ -429,27 +442,34 @@ void GC_init_inner() if (GC_is_initialized) return; GC_setpagesize(); - GC_exclude_static_roots(beginGC_arrays, endGC_arrays); + GC_exclude_static_roots(beginGC_arrays, end_gc_area); +# ifdef PRINTSTATS + if ((ptr_t)endGC_arrays != (ptr_t)(&GC_obj_kinds)) { + GC_printf0("Reordering linker, didn't exclude obj_kinds\n"); + } +# endif # ifdef MSWIN32 GC_init_win32(); # endif # if defined(LINUX) && defined(POWERPC) GC_init_linuxppc(); # endif -# if defined(LINUX) && defined(ALPHA) - GC_init_linuxalpha(); +# if defined(LINUX) && \ + (defined(POWERPC) || defined(ALPHA) || defined(SPARC) || defined(IA64)) + GC_init_linux_data_start(); # endif # ifdef SOLARIS_THREADS GC_thr_init(); /* We need dirty bits in order to find live stack sections. */ GC_dirty_init(); # endif -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) - GC_thr_init(); +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ + || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) + GC_thr_init(); # endif # if !defined(THREADS) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \ - || defined (QUICK_THREADS) + || defined(HPUX_THREADS) || defined(QUICK_THREADS) if (GC_stackbottom == 0) { GC_stackbottom = GC_get_stack_base(); } @@ -564,9 +584,10 @@ void GC_init_inner() void GC_enable_incremental GC_PROTO(()) { +# if !defined(SMALL_CONFIG) + if (!GC_find_leak) { DCL_LOCK_STATE; -# ifndef FIND_LEAK DISABLE_SIGNALS(); LOCK(); if (GC_incremental) goto out; @@ -602,6 +623,7 @@ void GC_enable_incremental GC_PROTO(()) out: UNLOCK(); ENABLE_SIGNALS(); + } # endif } @@ -781,7 +803,7 @@ char * msg; void GC_print_callers (info) struct callinfo info[NFRAMES]; { - register int i,j; + register int i; # if NFRAMES == 1 GC_err_printf0("\tCaller at allocation:\n"); @@ -791,6 +813,9 @@ struct callinfo info[NFRAMES]; for (i = 0; i < NFRAMES; i++) { if (info[i].ci_pc == 0) break; # if NARGS > 0 + { + int j; + GC_err_printf0("\t\targs: "); for (j = 0; j < NARGS; j++) { if (j != 0) GC_err_printf0(", "); @@ -798,6 +823,7 @@ struct callinfo info[NFRAMES]; ~(info[i].ci_arg[j])); } GC_err_printf0("\n"); + } # endif GC_err_printf1("\t\t##PC##= 0x%X\n", info[i].ci_pc); } diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c index 29cf8ff99ec..744b1e0898b 100644 --- a/boehm-gc/os_dep.c +++ b/boehm-gc/os_dep.c @@ -1,6 +1,8 @@ /* + * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. - * Copyright (c) 1996-1997 by Silicon Graphics. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -30,8 +32,12 @@ /* prototypes, so we have to include the top-level sigcontext.h to */ /* make sure the former gets defined to be the latter if appropriate. */ # include <features.h> -# if 2 <= __GLIBC__ && 0 == __GLIBC_MINOR__ -# include <sigcontext.h> +# if 2 <= __GLIBC__ +# if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__ + /* glibc 2.1 no longer has sigcontext.h. But signal.h */ + /* has the right declaration for glibc 2.1. */ +# include <sigcontext.h> +# endif /* 0 == __GLIBC_MINOR__ */ # else /* not 2 <= __GLIBC__ */ /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */ /* one. Check LINUX_VERSION_CODE to see which we should reference. */ @@ -50,13 +56,13 @@ # include <signal.h> /* Blatantly OS dependent routines, except for those that are related */ -/* dynamic loading. */ +/* to dynamic loading. */ # if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2) # define NEED_FIND_LIMIT # endif -# if defined(IRIX_THREADS) +# if defined(IRIX_THREADS) || defined(HPUX_THREADS) # define NEED_FIND_LIMIT # endif @@ -68,7 +74,8 @@ # define NEED_FIND_LIMIT # endif -# if defined(LINUX) && (defined(POWERPC) || defined(ALPHA)) +# if defined(LINUX) && \ + (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64)) # define NEED_FIND_LIMIT # endif @@ -135,92 +142,21 @@ # define OPT_PROT_EXEC 0 #endif -#if defined(LINUX) && defined(POWERPC) +#if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA) \ + || defined(IA64)) + /* The I386 case can be handled without a search. The Alpha case */ + /* used to be handled differently as well, but the rules changed */ + /* for recent Linux versions. This seems to be the easiest way to */ + /* cover all versions. */ ptr_t GC_data_start; - void GC_init_linuxppc() - { - extern ptr_t GC_find_limit(); - extern char **_environ; - /* This may need to be environ, without the underscore, for */ - /* some versions. */ - GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE); - } -#endif + extern char * GC_copyright[]; /* Any data symbol would do. */ -#if defined(LINUX) && defined(ALPHA) - ptr_t GC_data_start; - - void GC_init_linuxalpha() + void GC_init_linux_data_start() { -# ifdef USE_PROC - FILE *fp = fopen("/proc/self/maps", "r"); - - if (fp) { - extern void *_etext; - ptr_t stacktop = 0, stackbottom = 0; - ptr_t textstart = 0, textend = 0; - ptr_t datastart = 0, dataend = 0; - ptr_t bssstart = 0, bssend = 0; - - while (!feof(fp)) { - ptr_t start, end, offset; - unsigned short major, minor; - char r, w, x, p; - unsigned int inode; - - int n = fscanf(fp, "%lx-%lx %c%c%c%c %lx %hx:%hx %d", - &start, &end, &r, &w, &x, &p, &offset, &major, &minor, &inode); - if (n < 10) break; - - /* - * If local variable lies within segment, it is stack. - * Else if segment lies below _end and is executable, - * it is text. Otherwise, if segment start lies between - * _etext and _end and segment is writable and is mapped - * to the executable image it is data, otherwise bss. - */ - if (start < (ptr_t)&fp && end > (ptr_t)&fp && w == 'w') { - stacktop = start; - stackbottom = end; - } else if (start < (ptr_t)&_end && w == '-' && x == 'x') { - textstart = start; - textend = end; - } else if (start >= (ptr_t)&_etext && - start < (ptr_t)&_end && w == 'w') { - if (inode > 0) { - datastart = start; - dataend = end; - } else { - bssstart = start; - bssend = end; - } - } - - //printf("%016lx-%016lx %c%c%c%c %016lx %02hx:%02hx %d\n", - // start, end, r, w, x, p, offset, major, minor, inode); - - while (fgetc(fp) != '\n') ; - } - fclose(fp); - - //fprintf(stderr, "text: %lx-%lx\n", textstart, textend); - //fprintf(stderr, "data: %lx-%lx\n", datastart, dataend); - //fprintf(stderr, "bss: %lx-%lx\n", bssstart, bssend); - //fprintf(stderr, "stack: %lx-%lx\n", stacktop, stackbottom); + extern ptr_t GC_find_limit(); - GC_data_start = datastart; - } else { -# endif - extern ptr_t GC_find_limit(); - extern int _edata; - /* This may need to be environ, without the underscore, for */ - /* some versions. */ - GC_data_start = GC_find_limit((ptr_t)&_edata, FALSE); -# ifdef USE_PROC - } -# endif - //fprintf(stderr, "GC_data_start = %p\n", GC_data_start); + GC_data_start = GC_find_limit((ptr_t)GC_copyright, FALSE); } #endif @@ -455,7 +391,8 @@ word GC_page_size; } # else -# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) +# if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) \ + || defined(USE_MUNMAP) void GC_setpagesize() { GC_page_size = GETPAGESIZE(); @@ -534,6 +471,24 @@ ptr_t GC_get_stack_base() ptr_t GC_get_stack_base() { + struct Process *proc = (struct Process*)SysBase->ThisTask; + + /* Reference: Amiga Guru Book Pages: 42,567,574 */ + if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS + && proc->pr_CLI != NULL) { + /* first ULONG is StackSize */ + /*longPtr = proc->pr_ReturnAddr; + size = longPtr[0];*/ + + return (char *)proc->pr_ReturnAddr + sizeof(ULONG); + } else { + return (char *)proc->pr_Task.tc_SPUpper; + } +} + +#if 0 /* old version */ +ptr_t GC_get_stack_base() +{ extern struct WBStartup *_WBenchMsg; extern long __base; extern long __stack; @@ -556,10 +511,9 @@ ptr_t GC_get_stack_base() } return (ptr_t)(__base + GC_max(size, __stack)); } +#endif /* 0 */ -# else - - +# else /* !AMIGA, !OS2, ... */ # ifdef NEED_FIND_LIMIT /* Some tools to implement HEURISTIC2 */ @@ -579,9 +533,11 @@ ptr_t GC_get_stack_base() typedef void (*handler)(); # endif -# if defined(SUNOS5SIGS) || defined(IRIX5) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) static struct sigaction old_segv_act; - static struct sigaction old_bus_act; +# if defined(_sigargs) || defined(HPUX) /* !Irix6.x */ + static struct sigaction old_bus_act; +# endif # else static handler old_segv_handler, old_bus_handler; # endif @@ -589,7 +545,7 @@ ptr_t GC_get_stack_base() void GC_setup_temporary_fault_handler() { # ifndef ECOS -# if defined(SUNOS5SIGS) || defined(IRIX5) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) struct sigaction act; act.sa_handler = GC_fault_handler; @@ -608,10 +564,11 @@ ptr_t GC_get_stack_base() (void) sigaction(SIGSEGV, &act, 0); # else (void) sigaction(SIGSEGV, &act, &old_segv_act); -# ifdef _sigargs /* Irix 5.x, not 6.x */ - /* Under 5.x, we may get SIGBUS. */ - /* Pthreads doesn't exist under 5.x, so we don't */ - /* have to worry in the threads case. */ +# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ + || defined(HPUX) + /* 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. */ (void) sigaction(SIGBUS, &act, &old_bus_act); # endif # endif /* IRIX_THREADS */ @@ -627,9 +584,10 @@ ptr_t GC_get_stack_base() void GC_reset_fault_handler() { # ifndef ECOS -# if defined(SUNOS5SIGS) || defined(IRIX5) +# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) (void) sigaction(SIGSEGV, &old_segv_act, 0); -# ifdef _sigargs /* Irix 5.x, not 6.x */ +# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \ + || defined(HPUX) (void) sigaction(SIGBUS, &old_bus_act, 0); # endif # else @@ -679,8 +637,43 @@ ptr_t GC_get_stack_base() } # endif - # ifndef ECOS + +#ifdef LINUX_STACKBOTTOM + +# define STAT_SKIP 27 /* Number of fields preceding startstack */ + /* field in /proc/<pid>/stat */ + + ptr_t GC_linux_stack_base(void) + { + char buf[50]; + FILE *f; + char c; + word result = 0; + int i; + + sprintf(buf, "/proc/%d/stat", getpid()); + f = fopen(buf, "r"); + if (NULL == f) ABORT("Couldn't open /proc/<pid>/stat"); + c = getc(f); + /* Skip the required number of fields. This number is hopefully */ + /* constant across all Linux implementations. */ + for (i = 0; i < STAT_SKIP; ++i) { + while (isspace(c)) c = getc(f); + while (!isspace(c)) c = getc(f); + } + while (isspace(c)) c = getc(f); + while (isdigit(c)) { + result *= 10; + result += c - '0'; + c = getc(f); + } + if (result < 0x10000000) ABORT("Absurd stack bottom value"); + return (ptr_t)result; + } + +#endif /* LINUX_STACKBOTTOM */ + ptr_t GC_get_stack_base() { word dummy; @@ -705,6 +698,9 @@ ptr_t GC_get_stack_base() & ~STACKBOTTOM_ALIGNMENT_M1); # endif # endif /* HEURISTIC1 */ +# ifdef LINUX_STACKBOTTOM + result = GC_linux_stack_base(); +# endif # ifdef HEURISTIC2 # ifdef STACK_GROWS_DOWN result = GC_find_limit((ptr_t)(&dummy), TRUE); @@ -725,6 +721,9 @@ ptr_t GC_get_stack_base() # endif # endif /* HEURISTIC2 */ +# ifdef STACK_GROWS_DOWN + if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t)); +# endif return(result); # endif /* STACKBOTTOM */ # endif /* STACKBASE */ @@ -954,6 +953,72 @@ void GC_register_data_segments() # else # ifdef AMIGA + void GC_register_data_segments() + { + struct Process *proc; + struct CommandLineInterface *cli; + BPTR myseglist; + ULONG *data; + + int num; + + +# ifdef __GNUC__ + ULONG dataSegSize; + GC_bool found_segment = FALSE; + extern char __data_size[]; + + dataSegSize=__data_size+8; + /* Can`t find the Location of __data_size, because + it`s possible that is it, inside the segment. */ + +# endif + + proc= (struct Process*)SysBase->ThisTask; + + /* Reference: Amiga Guru Book Pages: 538ff,565,573 + and XOper.asm */ + if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) { + if (proc->pr_CLI == NULL) { + myseglist = proc->pr_SegList; + } else { + /* ProcLoaded 'Loaded as a command: '*/ + cli = BADDR(proc->pr_CLI); + myseglist = cli->cli_Module; + } + } else { + ABORT("Not a Process."); + } + + if (myseglist == NULL) { + ABORT("Arrrgh.. can't find segments, aborting"); + } + + /* xoper hunks Shell Process */ + + num=0; + for (data = (ULONG *)BADDR(myseglist); data != NULL; + data = (ULONG *)BADDR(data[0])) { + if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) || + ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) { +# ifdef __GNUC__ + if (dataSegSize == data[-1]) { + found_segment = TRUE; + } +# endif + GC_add_roots_inner((char *)&data[1], + ((char *)&data[1]) + data[-1], FALSE); + } + ++num; + } /* for */ +# ifdef __GNUC__ + if (!found_segment) { + ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library"); + } +# endif + } + +#if 0 /* old version */ void GC_register_data_segments() { extern struct WBStartup *_WBenchMsg; @@ -995,6 +1060,7 @@ void GC_register_data_segments() } } } +#endif /* old version */ # else @@ -1035,7 +1101,8 @@ int * etext_addr; void GC_register_data_segments() { -# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) +# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \ + && !defined(MACOSX) # if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS) /* As of Solaris 2.3, the Solaris threads implementation */ /* allocates the data structure for the initial thread with */ @@ -1049,7 +1116,7 @@ void GC_register_data_segments() GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE); # endif # endif -# if !defined(PCR) && defined(NEXT) +# if !defined(PCR) && (defined(NEXT) || defined(MACOSX)) GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE); # endif # if defined(MACOS) @@ -1063,9 +1130,19 @@ void GC_register_data_segments() # if defined(__MWERKS__) # if !__POWERPC__ extern void* GC_MacGetDataStart(void); + /* MATTHEW: Function to handle Far Globals (CW Pro 3) */ +# if __option(far_data) + extern void* GC_MacGetDataEnd(void); +# endif /* globals begin above stack and end at a5. */ GC_add_roots_inner((ptr_t)GC_MacGetDataStart(), (ptr_t)LMGetCurrentA5(), FALSE); + /* MATTHEW: Handle Far Globals */ +# if __option(far_data) + /* Far globals follow he QD globals: */ + GC_add_roots_inner((ptr_t)LMGetCurrentA5(), + (ptr_t)GC_MacGetDataEnd(), FALSE); +# endif # else extern char __data_start__[], __data_end__[]; GC_add_roots_inner((ptr_t)&__data_start__, @@ -1132,7 +1209,15 @@ word bytes; #else /* Not RS6000 */ #if defined(USE_MMAP) -/* Tested only under IRIX5 */ +/* Tested only under IRIX5 and Solaris 2 */ + +#ifdef USE_MMAP_FIXED +# define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE + /* Seems to yield better performance on Solaris 2, but can */ + /* be unreliable if something is already mapped at the address. */ +#else +# define GC_MMAP_FLAGS MAP_PRIVATE +#endif ptr_t GC_unix_get_mem(bytes) word bytes; @@ -1148,7 +1233,7 @@ word bytes; } if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg"); result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC, - MAP_PRIVATE | MAP_FIXED, fd, 0/* offset */); + GC_MMAP_FLAGS, fd, 0/* offset */); if (result == MAP_FAILED) return(0); last_addr = (ptr_t)result + bytes + GC_page_size - 1; last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1)); @@ -1232,8 +1317,108 @@ word bytes; return(result); } +void GC_win32_free_heap () +{ + if (GC_win32s) { + while (GC_n_heap_bases > 0) { + GlobalFree (GC_heap_bases[--GC_n_heap_bases]); + GC_heap_bases[GC_n_heap_bases] = 0; + } + } +} + + # endif +#ifdef USE_MUNMAP + +/* For now, this only works on some Unix-like systems. If you */ +/* have something else, don't define USE_MUNMAP. */ +/* We assume ANSI C to support this feature. */ +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> + +/* Compute a page aligned starting address for the unmap */ +/* operation on a block of size bytes starting at start. */ +/* Return 0 if the block is too small to make this feasible. */ +ptr_t GC_unmap_start(ptr_t start, word bytes) +{ + ptr_t result = start; + /* Round start to next page boundary. */ + result += GC_page_size - 1; + result = (ptr_t)((word)result & ~(GC_page_size - 1)); + if (result + GC_page_size > start + bytes) return 0; + return result; +} + +/* Compute end address for an unmap operation on the indicated */ +/* block. */ +ptr_t GC_unmap_end(ptr_t start, word bytes) +{ + ptr_t end_addr = start + bytes; + end_addr = (ptr_t)((word)end_addr & ~(GC_page_size - 1)); + return end_addr; +} + +/* We assume that GC_remap is called on exactly the same range */ +/* as a previous call to GC_unmap. It is safe to consistently */ +/* round the endpoints in both places. */ +void GC_unmap(ptr_t start, word bytes) +{ + ptr_t start_addr = GC_unmap_start(start, bytes); + ptr_t end_addr = GC_unmap_end(start, bytes); + word len = end_addr - start_addr; + if (0 == start_addr) return; + if (munmap(start_addr, len) != 0) ABORT("munmap failed"); + GC_unmapped_bytes += len; +} + + +void GC_remap(ptr_t start, word bytes) +{ + static int zero_descr = -1; + ptr_t start_addr = GC_unmap_start(start, bytes); + ptr_t end_addr = GC_unmap_end(start, bytes); + word len = end_addr - start_addr; + ptr_t result; + + if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR); + if (0 == start_addr) return; + result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, zero_descr, 0); + if (result != start_addr) { + ABORT("mmap remapping failed"); + } + GC_unmapped_bytes -= len; +} + +/* Two adjacent blocks have already been unmapped and are about to */ +/* be merged. Unmap the whole block. This typically requires */ +/* that we unmap a small section in the middle that was not previously */ +/* unmapped due to alignment constraints. */ +void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2) +{ + ptr_t start1_addr = GC_unmap_start(start1, bytes1); + ptr_t end1_addr = GC_unmap_end(start1, bytes1); + ptr_t start2_addr = GC_unmap_start(start2, bytes2); + ptr_t end2_addr = GC_unmap_end(start2, bytes2); + ptr_t start_addr = end1_addr; + ptr_t end_addr = start2_addr; + word len; + GC_ASSERT(start1 + bytes1 == start2); + if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2); + if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2); + if (0 == start_addr) return; + len = end_addr - start_addr; + if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed"); + GC_unmapped_bytes += len; +} + +#endif /* USE_MUNMAP */ + /* Routine for pushing any additional roots. In THREADS */ /* environment, this is also responsible for marking from */ /* thread stacks. In the SRC_M3 case, it also handles */ @@ -1351,6 +1536,7 @@ void GC_default_push_other_roots() # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \ + || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS) \ || defined(QUICK_THREADS) extern void GC_push_all_stacks(); @@ -1478,12 +1664,12 @@ struct hblk *h; # include <sys/syscall.h> # define PROTECT(addr, len) \ - if (mprotect((caddr_t)(addr), (int)(len), \ + if (mprotect((caddr_t)(addr), (size_t)(len), \ PROT_READ | OPT_PROT_EXEC) < 0) { \ ABORT("mprotect failed"); \ } # define UNPROTECT(addr, len) \ - if (mprotect((caddr_t)(addr), (int)(len), \ + if (mprotect((caddr_t)(addr), (size_t)(len), \ PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \ ABORT("un-mprotect failed"); \ } @@ -1508,14 +1694,15 @@ struct hblk *h; # endif -VOLATILE page_hash_table GC_dirty_pages; - /* Pages dirtied since last GC_read_dirty. */ - #if defined(SUNOS4) || defined(FREEBSD) typedef void (* SIG_PF)(); #endif #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) +# ifdef __STDC__ typedef void (* SIG_PF)(int); +# else + typedef void (* SIG_PF)(); +# endif #endif #if defined(MSWIN32) typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF; @@ -1527,15 +1714,46 @@ VOLATILE page_hash_table GC_dirty_pages; typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *); #endif #if defined(SUNOS5SIGS) - typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *); +# ifdef HPUX +# define SIGINFO __siginfo +# else +# define SIGINFO siginfo +# endif +# ifdef __STDC__ + typedef void (* REAL_SIG_PF)(int, struct SIGINFO *, void *); +# else + typedef void (* REAL_SIG_PF)(); +# endif #endif #if defined(LINUX) # include <linux/version.h> -# if (LINUX_VERSION_CODE >= 0x20100) - typedef void (* REAL_SIG_PF)(int, struct sigcontext); +# if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(IA64) + typedef struct sigcontext s_c; +# else + typedef struct sigcontext_struct s_c; +# endif +# if defined(ALPHA) || defined(M68K) + typedef void (* REAL_SIG_PF)(int, int, s_c *); # else - typedef void (* REAL_SIG_PF)(int, struct sigcontext_struct); +# if defined(IA64) + typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *); +# else + typedef void (* REAL_SIG_PF)(int, s_c); +# endif # endif +# ifdef ALPHA + /* Retrieve fault address from sigcontext structure by decoding */ + /* instruction. */ + char * get_fault_addr(s_c *sc) { + unsigned instr; + word faultaddr; + + instr = *((unsigned *)(sc->sc_pc)); + faultaddr = sc->sc_regs[(instr >> 16) & 0x1f]; + faultaddr += (word) (((int)instr << 16) >> 16); + return (char *)faultaddr; + } +# endif /* !ALPHA */ # endif SIG_PF GC_old_bus_handler; @@ -1570,21 +1788,41 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # endif # endif # if defined(LINUX) -# if (LINUX_VERSION_CODE >= 0x20100) - void GC_write_fault_handler(int sig, struct sigcontext sc) +# if defined(ALPHA) || defined(M68K) + void GC_write_fault_handler(int sig, int code, s_c * sc) # else - void GC_write_fault_handler(int sig, struct sigcontext_struct sc) +# if defined(IA64) + void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp) +# else + void GC_write_fault_handler(int sig, s_c sc) +# endif # endif # define SIG_OK (sig == SIGSEGV) # define CODE_OK TRUE - /* Empirically c.trapno == 14, but is that useful? */ - /* We assume Intel architecture, so alignment */ - /* faults are not possible. */ + /* Empirically c.trapno == 14, on IA32, but is that useful? */ + /* Should probably consider alignment issues on other */ + /* architectures. */ # endif # if defined(SUNOS5SIGS) - void GC_write_fault_handler(int sig, struct siginfo *scp, void * context) -# define SIG_OK (sig == SIGSEGV) -# define CODE_OK (scp -> si_code == SEGV_ACCERR) +# ifdef __STDC__ + void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context) +# else + void GC_write_fault_handler(sig, scp, context) + int sig; + struct SIGINFO *scp; + void * context; +# endif +# ifdef HPUX +# define SIG_OK (sig == SIGSEGV || sig == SIGBUS) +# define CODE_OK (scp -> si_code == SEGV_ACCERR) \ + || (scp -> si_code == BUS_ADRERR) \ + || (scp -> si_code == BUS_UNKNOWN) \ + || (scp -> si_code == SEGV_UNKNOWN) \ + || (scp -> si_code == BUS_OBJERR) +# else +# define SIG_OK (sig == SIGSEGV) +# define CODE_OK (scp -> si_code == SEGV_ACCERR) +# endif # endif # if defined(MSWIN32) LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info) @@ -1608,7 +1846,45 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # ifdef I386 char * addr = (char *) (sc.cr2); # else - char * addr = /* As of 1.3.90 there seemed to be no way to do this. */; +# if defined(M68K) + char * addr = NULL; + + struct sigcontext *scp = (struct sigcontext *)(&sc); + + int format = (scp->sc_formatvec >> 12) & 0xf; + unsigned long *framedata = (unsigned long *)(scp + 1); + unsigned long ea; + + if (format == 0xa || format == 0xb) { + /* 68020/030 */ + ea = framedata[2]; + } else if (format == 7) { + /* 68040 */ + ea = framedata[3]; + } else if (format == 4) { + /* 68060 */ + ea = framedata[0]; + if (framedata[1] & 0x08000000) { + /* correct addr on misaligned access */ + ea = (ea+4095)&(~4095); + } + } + addr = (char *)ea; +# else +# ifdef ALPHA + char * addr = get_fault_addr(sc); +# else +# ifdef IA64 + char * addr = si -> si_addr; +# else +# if defined(POWERPC) + char * addr = (char *) (sc.regs->dar); +# else + --> architecture not supported +# endif +# endif +# endif +# endif # endif # endif # if defined(MSWIN32) @@ -1644,6 +1920,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ } if (old_handler == SIG_DFL) { # ifndef MSWIN32 + GC_err_printf1("Segfault at 0x%lx\n", addr); ABORT("Unexpected bus error or segmentation fault"); # else return(EXCEPTION_CONTINUE_SEARCH); @@ -1658,7 +1935,15 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ return; # endif # if defined (LINUX) - (*(REAL_SIG_PF)old_handler) (sig, sc); +# if defined(ALPHA) || defined(M68K) + (*(REAL_SIG_PF)old_handler) (sig, code, sc); +# else +# if defined(IA64) + (*(REAL_SIG_PF)old_handler) (sig, si, scp); +# else + (*(REAL_SIG_PF)old_handler) (sig, sc); +# endif +# endif return; # endif # if defined (IRIX5) || defined(OSF1) @@ -1691,6 +1976,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ #ifdef MSWIN32 return EXCEPTION_CONTINUE_SEARCH; #else + GC_err_printf1("Segfault at 0x%lx\n", addr); ABORT("Unexpected bus error or segmentation fault"); #endif } @@ -1724,7 +2010,7 @@ struct hblk *h; void GC_dirty_init() { -#if defined(SUNOS5SIGS) || defined(IRIX5) +#if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */ struct sigaction act, oldact; # ifdef IRIX5 act.sa_flags = SA_RESTART; @@ -1768,7 +2054,7 @@ void GC_dirty_init() } # endif # if defined(SUNOS5SIGS) || defined(IRIX5) -# ifdef IRIX_THREADS +# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS) sigaction(SIGSEGV, 0, &oldact); sigaction(SIGSEGV, &act, 0); # else @@ -1794,6 +2080,15 @@ void GC_dirty_init() GC_err_printf0("Replaced other SIGSEGV handler\n"); # endif } +# ifdef HPUX + sigaction(SIGBUS, &act, &oldact); + GC_old_bus_handler = oldact.sa_handler; + if (GC_old_segv_handler != SIG_DFL) { +# ifdef PRINTSTATS + GC_err_printf0("Replaced other SIGBUS handler\n"); +# endif + } +# endif # endif # if defined(MSWIN32) GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler); @@ -1969,8 +2264,6 @@ word n; word GC_proc_buf_size = INITIAL_BUF_SZ; char *GC_proc_buf; -page_hash_table GC_written_pages = { 0 }; /* Pages ever dirtied */ - #ifdef SOLARIS_THREADS /* We don't have exact sp values for threads. So we count on */ /* occasionally declaring stack pages to be fresh. Thus we */ @@ -2261,14 +2554,18 @@ struct hblk *h; * Call stack save code for debugging. * Should probably be in mach_dep.c, but that requires reorganization. */ -#if defined(SPARC) +#if defined(SPARC) && !defined(LINUX) # if defined(SUNOS4) # include <machine/frame.h> # else # if defined (DRSNX) # include <sys/sparc/frame.h> # else -# include <sys/frame.h> +# if defined(OPENBSD) +# include <frame.h> +# else +# include <sys/frame.h> +# endif # endif # endif # if NARGS > 6 @@ -2278,6 +2575,15 @@ struct hblk *h; #ifdef SAVE_CALL_CHAIN /* Fill in the pc and argument information for up to NFRAMES of my */ /* callers. Ignore my frame and my callers frame. */ + +#ifdef OPENBSD +# define FR_SAVFP fr_fp +# define FR_SAVPC fr_pc +#else +# define FR_SAVFP fr_savfp +# define FR_SAVPC fr_savpc +#endif + void GC_save_callers (info) struct callinfo info[NFRAMES]; { @@ -2288,11 +2594,11 @@ struct callinfo info[NFRAMES]; frame = (struct frame *) GC_save_regs_in_stack (); - for (fp = frame -> fr_savfp; fp != 0 && nframes < NFRAMES; - fp = fp -> fr_savfp, nframes++) { + for (fp = frame -> FR_SAVFP; fp != 0 && nframes < NFRAMES; + fp = fp -> FR_SAVFP, nframes++) { register int i; - info[nframes].ci_pc = fp->fr_savpc; + info[nframes].ci_pc = fp->FR_SAVPC; for (i = 0; i < NARGS; i++) { info[nframes].ci_arg[i] = ~(fp->fr_arg[i]); } diff --git a/boehm-gc/reclaim.c b/boehm-gc/reclaim.c index 407b4c68194..6e0f53bb058 100644 --- a/boehm-gc/reclaim.c +++ b/boehm-gc/reclaim.c @@ -1,6 +1,8 @@ /* * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers - * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. + * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. + * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. + * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -11,7 +13,6 @@ * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. */ -/* Boehm, February 15, 1996 2:41 pm PST */ #include <stdio.h> #include "gc_priv.h" @@ -19,7 +20,6 @@ signed_word GC_mem_found = 0; /* Number of words of memory reclaimed */ -# ifdef FIND_LEAK static void report_leak(p, sz) ptr_t p; word sz; @@ -39,13 +39,10 @@ word sz; } # define FOUND_FREE(hblk, word_no) \ - if (abort_if_found) { \ + { \ report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \ HDR(hblk) -> hb_sz); \ } -# else -# define FOUND_FREE(hblk, word_no) -# endif /* * reclaim phase @@ -71,6 +68,139 @@ register hdr * hhdr; return(TRUE); } +/* The following functions sometimes return a DONT_KNOW value. */ +#define DONT_KNOW 2 + +#ifdef SMALL_CONFIG +# define GC_block_nearly_full1(hhdr, pat1) DONT_KNOW +# define GC_block_nearly_full3(hhdr, pat1, pat2) DONT_KNOW +# define GC_block_nearly_full(hhdr) DONT_KNOW +#else + +/* + * Test whether nearly all of the mark words consist of the same + * repeating pattern. + */ +#define FULL_THRESHOLD (MARK_BITS_SZ/16) + +GC_bool GC_block_nearly_full1(hhdr, pat1) +hdr *hhdr; +word pat1; +{ + unsigned i; + unsigned misses = 0; + GC_ASSERT((MARK_BITS_SZ & 1) == 0); + for (i = 0; i < MARK_BITS_SZ; ++i) { + if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { + if (++misses > FULL_THRESHOLD) return FALSE; + } + } + return TRUE; +} + +/* + * Test whether the same repeating 3 word pattern occurs in nearly + * all the mark bit slots. + * This is used as a heuristic, so we're a bit sloppy and ignore + * the last one or two words. + */ +GC_bool GC_block_nearly_full3(hhdr, pat1, pat2, pat3) +hdr *hhdr; +word pat1, pat2, pat3; +{ + unsigned i; + unsigned misses = 0; + + if (MARK_BITS_SZ < 4) { + return DONT_KNOW; + } + for (i = 0; i < MARK_BITS_SZ - 2; i += 3) { + if ((hhdr -> hb_marks[i] | ~pat1) != ONES) { + if (++misses > FULL_THRESHOLD) return FALSE; + } + if ((hhdr -> hb_marks[i+1] | ~pat2) != ONES) { + if (++misses > FULL_THRESHOLD) return FALSE; + } + if ((hhdr -> hb_marks[i+2] | ~pat3) != ONES) { + if (++misses > FULL_THRESHOLD) return FALSE; + } + } + return TRUE; +} + +/* Check whether a small object block is nearly full by looking at only */ +/* the mark bits. */ +/* We manually precomputed the mark bit patterns that need to be */ +/* checked for, and we give up on the ones that are unlikely to occur, */ +/* or have period > 3. */ +/* This would be a lot easier with a mark bit per object instead of per */ +/* word, but that would rewuire computing object numbers in the mark */ +/* loop, which would require different data structures ... */ +GC_bool GC_block_nearly_full(hhdr) +hdr *hhdr; +{ + int sz = hhdr -> hb_sz; + +# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64 + return DONT_KNOW; /* Shouldn't be used in any standard config. */ +# endif + if (0 != HDR_WORDS) return DONT_KNOW; + /* Also shouldn't happen */ +# if CPP_WORDSZ == 32 + switch(sz) { + case 1: + return GC_block_nearly_full1(hhdr, 0xffffffffl); + case 2: + return GC_block_nearly_full1(hhdr, 0x55555555l); + case 4: + return GC_block_nearly_full1(hhdr, 0x11111111l); + case 6: + return GC_block_nearly_full3(hhdr, 0x41041041l, + 0x10410410l, + 0x04104104l); + case 8: + return GC_block_nearly_full1(hhdr, 0x01010101l); + case 12: + return GC_block_nearly_full3(hhdr, 0x01001001l, + 0x10010010l, + 0x00100100l); + case 16: + return GC_block_nearly_full1(hhdr, 0x00010001l); + case 32: + return GC_block_nearly_full1(hhdr, 0x00000001l); + default: + return DONT_KNOW; + } +# endif +# if CPP_WORDSZ == 64 + switch(sz) { + case 1: + return GC_block_nearly_full1(hhdr, 0xffffffffffffffffl); + case 2: + return GC_block_nearly_full1(hhdr, 0x5555555555555555l); + case 4: + return GC_block_nearly_full1(hhdr, 0x1111111111111111l); + case 6: + return GC_block_nearly_full3(hhdr, 0x1041041041041041l, + 0x4104104104104104l, + 0x0410410410410410l); + case 8: + return GC_block_nearly_full1(hhdr, 0x0101010101010101l); + case 12: + return GC_block_nearly_full3(hhdr, 0x1001001001001001l, + 0x0100100100100100l, + 0x0010010010010010l); + case 16: + return GC_block_nearly_full1(hhdr, 0x0001000100010001l); + case 32: + return GC_block_nearly_full1(hhdr, 0x0000000100000001l); + default: + return DONT_KNOW; + } +# endif +} +#endif /* !SMALL_CONFIG */ + # ifdef GATHERSTATS # define INCR_WORDS(sz) n_words_found += (sz) # else @@ -82,10 +212,9 @@ register hdr * hhdr; * Clears unmarked objects. */ /*ARGSUSED*/ -ptr_t GC_reclaim_clear(hbp, hhdr, sz, list, abort_if_found) +ptr_t GC_reclaim_clear(hbp, hhdr, sz, list) register struct hblk *hbp; /* ptr to current heap block */ register hdr * hhdr; -GC_bool abort_if_found; /* Abort if a reclaimable object is found */ register ptr_t list; register word sz; { @@ -105,7 +234,6 @@ register word sz; if( mark_bit_from_hdr(hhdr, word_no) ) { p += sz; } else { - FOUND_FREE(hbp, word_no); INCR_WORDS(sz); /* object is available - put on list */ obj_link(p) = list; @@ -131,10 +259,9 @@ register word sz; * A special case for 2 word composite objects (e.g. cons cells): */ /*ARGSUSED*/ -ptr_t GC_reclaim_clear2(hbp, hhdr, list, abort_if_found) +ptr_t GC_reclaim_clear2(hbp, hhdr, list) register struct hblk *hbp; /* ptr to current heap block */ hdr * hhdr; -GC_bool abort_if_found; /* Abort if a reclaimable object is found */ register ptr_t list; { register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); @@ -146,7 +273,6 @@ register ptr_t list; register int i; # define DO_OBJ(start_displ) \ if (!(mark_word & ((word)1 << start_displ))) { \ - FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ p[start_displ+1] = 0; \ @@ -179,10 +305,9 @@ register ptr_t list; * Another special case for 4 word composite objects: */ /*ARGSUSED*/ -ptr_t GC_reclaim_clear4(hbp, hhdr, list, abort_if_found) +ptr_t GC_reclaim_clear4(hbp, hhdr, list) register struct hblk *hbp; /* ptr to current heap block */ hdr * hhdr; -GC_bool abort_if_found; /* Abort if a reclaimable object is found */ register ptr_t list; { register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); @@ -193,7 +318,6 @@ register ptr_t list; register word mark_word; # define DO_OBJ(start_displ) \ if (!(mark_word & ((word)1 << start_displ))) { \ - FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ p[start_displ+1] = 0; \ @@ -239,10 +363,9 @@ register ptr_t list; /* The same thing, but don't clear objects: */ /*ARGSUSED*/ -ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list, abort_if_found) +ptr_t GC_reclaim_uninit(hbp, hhdr, sz, list) register struct hblk *hbp; /* ptr to current heap block */ register hdr * hhdr; -GC_bool abort_if_found; /* Abort if a reclaimable object is found */ register ptr_t list; register word sz; { @@ -260,7 +383,6 @@ register word sz; /* go through all words in block */ while( p <= plim ) { if( !mark_bit_from_hdr(hhdr, word_no) ) { - FOUND_FREE(hbp, word_no); INCR_WORDS(sz); /* object is available - put on list */ obj_link(p) = list; @@ -275,15 +397,42 @@ register word sz; return(list); } +/* Don't really reclaim objects, just check for unmarked ones: */ +/*ARGSUSED*/ +void GC_reclaim_check(hbp, hhdr, sz) +register struct hblk *hbp; /* ptr to current heap block */ +register hdr * hhdr; +register word sz; +{ + register int word_no; + register word *p, *plim; +# ifdef GATHERSTATS + register int n_words_found = 0; +# endif + + p = (word *)(hbp->hb_body); + word_no = HDR_WORDS; + plim = (word *)((((word)hbp) + HBLKSIZE) + - WORDS_TO_BYTES(sz)); + + /* go through all words in block */ + while( p <= plim ) { + if( !mark_bit_from_hdr(hhdr, word_no) ) { + FOUND_FREE(hbp, word_no); + } + p += sz; + word_no += sz; + } +} + #ifndef SMALL_CONFIG /* * Another special case for 2 word atomic objects: */ /*ARGSUSED*/ -ptr_t GC_reclaim_uninit2(hbp, hhdr, list, abort_if_found) +ptr_t GC_reclaim_uninit2(hbp, hhdr, list) register struct hblk *hbp; /* ptr to current heap block */ hdr * hhdr; -GC_bool abort_if_found; /* Abort if a reclaimable object is found */ register ptr_t list; { register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); @@ -295,7 +444,6 @@ register ptr_t list; register int i; # define DO_OBJ(start_displ) \ if (!(mark_word & ((word)1 << start_displ))) { \ - FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ INCR_WORDS(2); \ @@ -327,10 +475,9 @@ register ptr_t list; * Another special case for 4 word atomic objects: */ /*ARGSUSED*/ -ptr_t GC_reclaim_uninit4(hbp, hhdr, list, abort_if_found) +ptr_t GC_reclaim_uninit4(hbp, hhdr, list) register struct hblk *hbp; /* ptr to current heap block */ hdr * hhdr; -GC_bool abort_if_found; /* Abort if a reclaimable object is found */ register ptr_t list; { register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); @@ -341,7 +488,6 @@ register ptr_t list; register word mark_word; # define DO_OBJ(start_displ) \ if (!(mark_word & ((word)1 << start_displ))) { \ - FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ INCR_WORDS(4); \ @@ -382,10 +528,9 @@ register ptr_t list; /* Finally the one word case, which never requires any clearing: */ /*ARGSUSED*/ -ptr_t GC_reclaim1(hbp, hhdr, list, abort_if_found) +ptr_t GC_reclaim1(hbp, hhdr, list) register struct hblk *hbp; /* ptr to current heap block */ hdr * hhdr; -GC_bool abort_if_found; /* Abort if a reclaimable object is found */ register ptr_t list; { register word * mark_word_addr = &(hhdr->hb_marks[divWORDSZ(HDR_WORDS)]); @@ -397,7 +542,6 @@ register ptr_t list; register int i; # define DO_OBJ(start_displ) \ if (!(mark_word & ((word)1 << start_displ))) { \ - FOUND_FREE(hbp, p - (word *)hbp + start_displ); \ p[start_displ] = (word)list; \ list = (ptr_t)(p+start_displ); \ INCR_WORDS(1); \ @@ -433,15 +577,16 @@ register ptr_t list; * If entirely empty blocks are to be completely deallocated, then * caller should perform that check. */ -void GC_reclaim_small_nonempty_block(hbp, abort_if_found) +void GC_reclaim_small_nonempty_block(hbp, report_if_found) register struct hblk *hbp; /* ptr to current heap block */ -int abort_if_found; /* Abort if a reclaimable object is found */ +int report_if_found; /* Abort if a reclaimable object is found */ { hdr * hhdr; - register word sz; /* size of objects in current block */ - register struct obj_kind * ok; - register ptr_t * flh; - register int kind; + word sz; /* size of objects in current block */ + struct obj_kind * ok; + ptr_t * flh; + int kind; + GC_bool full; hhdr = HDR(hbp); sz = hhdr -> hb_sz; @@ -449,43 +594,70 @@ int abort_if_found; /* Abort if a reclaimable object is found */ kind = hhdr -> hb_obj_kind; ok = &GC_obj_kinds[kind]; flh = &(ok -> ok_freelist[sz]); - GC_write_hint(hbp); - if (ok -> ok_init) { + if (report_if_found) { + GC_reclaim_check(hbp, hhdr, sz); + } else if (ok -> ok_init) { switch(sz) { # ifndef SMALL_CONFIG case 1: - *flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found); + full = GC_block_nearly_full1(hhdr, 0xffffffffl); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + /* In the DONT_KNOW case, we let reclaim fault. */ + *flh = GC_reclaim1(hbp, hhdr, *flh); break; case 2: - *flh = GC_reclaim_clear2(hbp, hhdr, *flh, abort_if_found); + full = GC_block_nearly_full1(hhdr, 0x55555555l); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + *flh = GC_reclaim_clear2(hbp, hhdr, *flh); break; case 4: - *flh = GC_reclaim_clear4(hbp, hhdr, *flh, abort_if_found); + full = GC_block_nearly_full1(hhdr, 0x11111111l); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + *flh = GC_reclaim_clear4(hbp, hhdr, *flh); break; # endif default: - *flh = GC_reclaim_clear(hbp, hhdr, sz, *flh, abort_if_found); + full = GC_block_nearly_full(hhdr); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + *flh = GC_reclaim_clear(hbp, hhdr, sz, *flh); break; } } else { switch(sz) { # ifndef SMALL_CONFIG case 1: - *flh = GC_reclaim1(hbp, hhdr, *flh, abort_if_found); + full = GC_block_nearly_full1(hhdr, 0xffffffffl); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + *flh = GC_reclaim1(hbp, hhdr, *flh); break; case 2: - *flh = GC_reclaim_uninit2(hbp, hhdr, *flh, abort_if_found); + full = GC_block_nearly_full1(hhdr, 0x55555555l); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + *flh = GC_reclaim_uninit2(hbp, hhdr, *flh); break; case 4: - *flh = GC_reclaim_uninit4(hbp, hhdr, *flh, abort_if_found); + full = GC_block_nearly_full1(hhdr, 0x11111111l); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + *flh = GC_reclaim_uninit4(hbp, hhdr, *flh); break; # endif default: - *flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh, abort_if_found); + full = GC_block_nearly_full(hhdr); + if (TRUE == full) goto out; + if (FALSE == full) GC_write_hint(hbp); + *flh = GC_reclaim_uninit(hbp, hhdr, sz, *flh); break; } } +out: if (IS_UNCOLLECTABLE(kind)) GC_set_hdr_marks(hhdr); } @@ -494,11 +666,12 @@ int abort_if_found; /* Abort if a reclaimable object is found */ * to the heap block free list. * Otherwise enqueue the block for later processing * by GC_reclaim_small_nonempty_block. - * If abort_if_found is TRUE, then process any block immediately. + * If report_if_found is TRUE, then process any block immediately, and + * simply report free objects; do not actually reclaim them. */ -void GC_reclaim_block(hbp, abort_if_found) +void GC_reclaim_block(hbp, report_if_found) register struct hblk *hbp; /* ptr to current heap block */ -word abort_if_found; /* Abort if a reclaimable object is found */ +word report_if_found; /* Abort if a reclaimable object is found */ { register hdr * hhdr; register word sz; /* size of objects in current block */ @@ -511,16 +684,19 @@ word abort_if_found; /* Abort if a reclaimable object is found */ if( sz > MAXOBJSZ ) { /* 1 big object */ if( !mark_bit_from_hdr(hhdr, HDR_WORDS) ) { - FOUND_FREE(hbp, HDR_WORDS); -# ifdef GATHERSTATS + if (report_if_found) { + FOUND_FREE(hbp, HDR_WORDS); + } else { +# ifdef GATHERSTATS GC_mem_found += sz; -# endif - GC_freehblk(hbp); +# endif + GC_freehblk(hbp); + } } } else { GC_bool empty = GC_block_empty(hhdr); - if (abort_if_found) { - GC_reclaim_small_nonempty_block(hbp, (int)abort_if_found); + if (report_if_found) { + GC_reclaim_small_nonempty_block(hbp, (int)report_if_found); } else if (empty) { # ifdef GATHERSTATS GC_mem_found += BYTES_TO_WORDS(HBLKSIZE); @@ -600,11 +776,11 @@ void GC_print_block_list() #endif /* NO_DEBUGGING */ /* - * Do the same thing on the entire heap, after first clearing small object - * free lists (if we are not just looking for leaks). + * Perform GC_reclaim_block on the entire heap, after first clearing + * small object free lists (if we are not just looking for leaks). */ -void GC_start_reclaim(abort_if_found) -int abort_if_found; /* Abort if a GC_reclaimable object is found */ +void GC_start_reclaim(report_if_found) +int report_if_found; /* Abort if a GC_reclaimable object is found */ { int kind; @@ -617,7 +793,7 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */ register struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list; if (rlist == 0) continue; /* This kind not used. */ - if (!abort_if_found) { + if (!report_if_found) { lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJSZ+1]); for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) { *fop = 0; @@ -637,7 +813,7 @@ int abort_if_found; /* Abort if a GC_reclaimable object is found */ /* Go through all heap blocks (in hblklist) and reclaim unmarked objects */ /* or enqueue the block for later processing. */ - GC_apply_to_all_blocks(GC_reclaim_block, (word)abort_if_found); + GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found); } diff --git a/boehm-gc/setjmp_t.c b/boehm-gc/setjmp_t.c index 9ed92138b6c..1c9253e98a6 100644 --- a/boehm-gc/setjmp_t.c +++ b/boehm-gc/setjmp_t.c @@ -25,7 +25,7 @@ #include <stdio.h> #include <setjmp.h> #include <string.h> -#include "config.h" +#include "gcconfig.h" #ifdef OS2 /* GETPAGESIZE() is set to getpagesize() by default, but that */ diff --git a/boehm-gc/solaris_threads.c b/boehm-gc/solaris_threads.c index 1f5ebcdc390..65b2c6517b1 100644 --- a/boehm-gc/solaris_threads.c +++ b/boehm-gc/solaris_threads.c @@ -616,6 +616,25 @@ GC_thread GC_lookup_thread(thread_t id) return(p); } +# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024) + +word GC_get_orig_stack_size() { + struct rlimit rl; + static int warned = 0; + int result; + + if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed"); + result = (word)rl.rlim_cur & ~(HBLKSIZE-1); + if (result > MAX_ORIG_STACK_SIZE) { + if (!warned) { + WARN("Large stack limit(%ld): only scanning 8 MB", result); + warned = 1; + } + result = MAX_ORIG_STACK_SIZE; + } + return result; +} + /* Notify dirty bit implementation of unused parts of my stack. */ /* Caller holds allocation lock. */ void GC_my_stack_limits() @@ -628,12 +647,9 @@ void GC_my_stack_limits() if (stack_size == 0) { /* original thread */ - struct rlimit rl; - - if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed"); /* Empirically, what should be the stack page with lowest */ /* address is actually inaccessible. */ - stack_size = ((word)rl.rlim_cur & ~(HBLKSIZE-1)) - GC_page_sz; + stack_size = GC_get_orig_stack_size() - GC_page_sz; stack = GC_stackbottom - stack_size + GC_page_sz; } else { stack = me -> stack; @@ -671,8 +687,7 @@ void GC_push_all_stacks() top = p -> stack + p -> stack_size; } else { /* The original stack. */ - if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed"); - bottom = GC_stackbottom - rl.rlim_cur + GC_page_sz; + bottom = GC_stackbottom - GC_get_orig_stack_size() + GC_page_sz; top = GC_stackbottom; } if ((word)sp > (word)bottom && (word)sp < (word)top) bottom = sp; diff --git a/boehm-gc/sparc_mach_dep.s b/boehm-gc/sparc_mach_dep.s index a6a0a241080..9831c6ca402 100644 --- a/boehm-gc/sparc_mach_dep.s +++ b/boehm-gc/sparc_mach_dep.s @@ -1,4 +1,4 @@ -! SPARCompiler 3.0 and later apparently no loner handles +! SPARCompiler 3.0 and later apparently no longer handles ! asm outside functions. So we need a separate .s file ! This is only set up for SunOS 5, not SunOS 4. ! Assumes this is called before the stack contents are @@ -35,4 +35,4 @@ loop: -
\ No newline at end of file + diff --git a/boehm-gc/sparc_sunos4_mach_dep.s b/boehm-gc/sparc_sunos4_mach_dep.s index 7accadd3dfb..41858073ef9 100644 --- a/boehm-gc/sparc_sunos4_mach_dep.s +++ b/boehm-gc/sparc_sunos4_mach_dep.s @@ -1,4 +1,4 @@ -! SPARCompiler 3.0 and later apparently no loner handles +! SPARCompiler 3.0 and later apparently no longer handles ! asm outside functions. So we need a separate .s file ! This is only set up for SunOS 4. ! Assumes this is called before the stack contents are diff --git a/boehm-gc/test.c b/boehm-gc/test.c index 2fc51e12ed7..43b09010f80 100644 --- a/boehm-gc/test.c +++ b/boehm-gc/test.c @@ -25,7 +25,7 @@ # include "gc.h" # include "gc_typed.h" # include "gc_priv.h" /* For output, locking, and some statistics */ -# include "config.h" +# include "gcconfig.h" # ifdef MSWIN32 # include <windows.h> @@ -45,7 +45,7 @@ # include <synch.h> # endif -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) # include <pthread.h> # endif @@ -53,9 +53,6 @@ # include <process.h> static CRITICAL_SECTION incr_cs; # endif -# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) -# define THREADS -# endif # ifdef AMIGA long __stack = 200000; @@ -266,6 +263,72 @@ struct { #define a A.aa /* + * A tiny list reversal test to check thread creation. + */ +#ifdef THREADS + +# ifdef WIN32_THREADS + unsigned __stdcall tiny_reverse_test(void * arg) +# else + void * tiny_reverse_test(void * arg) +# endif +{ + check_ints(reverse(reverse(ints(1,10))), 1, 10); + return 0; +} + +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ + || defined(SOLARIS_PTHREADS) || defined(HPUX_THREADS) + void fork_a_thread() + { + pthread_t t; + int code; + if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) { + (void)GC_printf1("Small thread creation failed %lu\n", + (unsigned long)code); + FAIL; + } + if ((code = pthread_join(t, 0)) != 0) { + (void)GC_printf1("Small thread join failed %lu\n", + (unsigned long)code); + FAIL; + } + } + +# elif defined(WIN32_THREADS) + void fork_a_thread() + { + unsigned thread_id; + HANDLE h; + h = (HANDLE)_beginthreadex(NULL, 0, tiny_reverse_test, + 0, 0, &thread_id); + if (h == (HANDLE)-1) { + (void)GC_printf1("Small thread creation failed %lu\n", + (unsigned long)GetLastError()); + FAIL; + } + if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) { + (void)GC_printf1("Small thread wait failed %lu\n", + (unsigned long)GetLastError()); + FAIL; + } + } + +/* # elif defined(SOLARIS_THREADS) */ + +# else + +# define fork_a_thread() + +# endif + +#else + +# define fork_a_thread() + +#endif + +/* * Repeatedly reverse lists built out of very different sized cons cells. * Check that we didn't lose anything. */ @@ -296,14 +359,14 @@ void reverse_test() d = uncollectable_ints(1, 100); e = uncollectable_ints(1, 1); /* Check that realloc updates object descriptors correctly */ - f = (sexpr *)GC_malloc(4 * sizeof(sexpr)); - f = (sexpr *)GC_realloc((GC_PTR)f, 6 * sizeof(sexpr)); + f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr)); + f = (sexpr *)GC_REALLOC((GC_PTR)f, 6 * sizeof(sexpr)); f[5] = ints(1,17); - g = (sexpr *)GC_malloc(513 * sizeof(sexpr)); - g = (sexpr *)GC_realloc((GC_PTR)g, 800 * sizeof(sexpr)); + g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr)); + g = (sexpr *)GC_REALLOC((GC_PTR)g, 800 * sizeof(sexpr)); g[799] = ints(1,18); - h = (sexpr *)GC_malloc(1025 * sizeof(sexpr)); - h = (sexpr *)GC_realloc((GC_PTR)h, 2000 * sizeof(sexpr)); + h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr)); + h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr)); h[1999] = ints(1,19); /* Try to force some collections and reuse of small list elements */ for (i = 0; i < 10; i++) { @@ -327,6 +390,7 @@ void reverse_test() check_ints(b,1,50); check_ints(a,1,49); for (i = 0; i < 60; i++) { + if (i % 10 == 0) fork_a_thread(); /* This maintains the invariant that a always points to a list of */ /* 49 integers. Thus this is thread safe without locks, */ /* assuming atomic pointer assignments. */ @@ -386,7 +450,7 @@ VOLATILE int dropped_something = 0; static mutex_t incr_lock; mutex_lock(&incr_lock); # endif -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&incr_lock); # endif @@ -404,7 +468,7 @@ VOLATILE int dropped_something = 0; # ifdef SOLARIS_THREADS mutex_unlock(&incr_lock); # endif -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS) pthread_mutex_unlock(&incr_lock); # endif # ifdef WIN32_THREADS @@ -465,7 +529,8 @@ int n; static mutex_t incr_lock; mutex_lock(&incr_lock); # endif -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ + || defined(HPUX_THREADS) static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_lock(&incr_lock); # endif @@ -481,7 +546,8 @@ int n; # ifdef SOLARIS_THREADS mutex_unlock(&incr_lock); # endif -# if defined(IRIX_THREADS) || defined(LINUX_THREADS) +# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \ + || defined(HPUX_THREADS) pthread_mutex_unlock(&incr_lock); # endif # ifdef WIN32_THREADS @@ -538,13 +604,13 @@ int n; chktree(t -> rchild, n-1); } -# ifdef SOLARIS_THREADS +# if defined(SOLARIS_THREADS) && !defined(_SOLARIS_PTHREADS) thread_key_t fl_key; void * alloc8bytes() { -# ifdef SMALL_CONFIG - return(GC_malloc(8)); +# if defined(SMALL_CONFIG) || defined(GC_DEBUG) + return(GC_MALLOC(8)); # else void ** my_free_list_ptr; void * my_free_list; @@ -575,7 +641,44 @@ void * alloc8bytes() } #else -# define alloc8bytes() GC_MALLOC_ATOMIC(8) + +# if defined(_SOLARIS_PTHREADS) || defined(IRIX_THREADS) \ + || defined(LINUX_THREADS) || defined(HPUX_THREADS) +pthread_key_t fl_key; + +void * alloc8bytes() +{ +# ifdef SMALL_CONFIG + return(GC_malloc(8)); +# else + void ** my_free_list_ptr; + void * my_free_list; + + my_free_list_ptr = (void **)pthread_getspecific(fl_key); + if (my_free_list_ptr == 0) { + my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *); + if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) { + (void)GC_printf0("pthread_setspecific failed\n"); + FAIL; + } + } + my_free_list = *my_free_list_ptr; + if (my_free_list == 0) { + my_free_list = GC_malloc_many(8); + if (my_free_list == 0) { + (void)GC_printf0("alloc8bytes out of memory\n"); + FAIL; + } + } + *my_free_list_ptr = GC_NEXT(my_free_list); + GC_NEXT(my_free_list) = 0; + return(my_free_list); +# endif +} + +# else +# define alloc8bytes() GC_MALLOC_ATOMIC(8) +# endif #endif void alloc_small(n) @@ -753,6 +856,7 @@ void run_one_test() (void)GC_printf0("GC_malloc_uncollectable(0) failed\n"); FAIL; } + GC_FREE(0); GC_is_valid_displacement_print_proc = fail_proc1; GC_is_visible_print_proc = fail_proc1; x = GC_malloc(16); @@ -775,7 +879,7 @@ void run_one_test() FAIL; } if (!TEST_FAIL_COUNT(1)) { -# if!(defined(RS6000) || defined(POWERPC)) +# if!(defined(RS6000) || defined(POWERPC) || defined(IA64)) /* ON RS6000s function pointers point to a descriptor in the */ /* data segment, so there should have been no failures. */ (void)GC_printf0("GC_is_visible produced wrong failure indication\n"); @@ -826,7 +930,7 @@ void check_heap_stats() int late_finalize_count = 0; if (sizeof(char *) > 4) { - max_heap_sz = 13000000; + max_heap_sz = 15000000; } else { max_heap_sz = 11000000; } @@ -926,7 +1030,8 @@ void SetMinimumStack(long minSize) #if !defined(PCR) && !defined(SOLARIS_THREADS) && !defined(WIN32_THREADS) \ - && !defined(IRIX_THREADS) && !defined(LINUX_THREADS) || defined(LINT) + && !defined(IRIX_THREADS) && !defined(LINUX_THREADS) \ + && !defined(HPUX_THREADS) || defined(LINT) #ifdef MSWIN32 int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) #else @@ -980,6 +1085,9 @@ void SetMinimumStack(long minSize) GC_set_max_heap_size, GC_get_bytes_since_gc, GC_pre_incr, GC_post_incr); # endif +# ifdef MSWIN32 + GC_win32_free_heap(); +# endif return(0); } # endif @@ -1054,7 +1162,8 @@ test() } #endif -#if defined(SOLARIS_THREADS) || defined(IRIX_THREADS) || defined(LINUX_THREADS) +#if defined(SOLARIS_THREADS) || defined(IRIX_THREADS) \ + || defined(HPUX_THREADS) || defined(LINUX_THREADS) void * thr_run_one_test(void * arg) { run_one_test(); @@ -1115,7 +1224,7 @@ main() *((volatile char *)&code - 1024*1024) = 0; /* Require 1 Mb */ # endif /* IRIX_THREADS */ pthread_attr_init(&attr); -# ifdef IRIX_THREADS +# if defined(IRIX_THREADS) || defined(HPUX_THREADS) pthread_attr_setstacksize(&attr, 1000000); # endif n_tests = 0; @@ -1125,6 +1234,10 @@ main() (void) GC_printf0("Emulating dirty bits with mprotect/signals\n"); # endif (void) GC_set_warn_proc(warn_proc); + if ((code = pthread_key_create(&fl_key, 0)) != 0) { + (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code); + FAIL; + } if ((code = pthread_create(&th1, &attr, thr_run_one_test, 0)) != 0) { (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code); FAIL; @@ -1149,4 +1262,4 @@ main() return(0); } #endif /* pthreads */ -#endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS */ +#endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS || HPUX_THREADS */ diff --git a/boehm-gc/threadlibs.c b/boehm-gc/threadlibs.c index c8530e6fe33..df4eb77bb1d 100644 --- a/boehm-gc/threadlibs.c +++ b/boehm-gc/threadlibs.c @@ -1,4 +1,4 @@ -# include "config.h" +# include "gcconfig.h" # include <stdio.h> int main() @@ -6,6 +6,9 @@ int main() # if defined(IRIX_THREADS) || defined(LINUX_THREADS) printf("-lpthread\n"); # endif +# if defined(HPUX_THREADS) + printf("-lpthread -lrt\n"); +# endif # ifdef SOLARIS_THREADS printf("-lthread -ldl\n"); # endif diff --git a/boehm-gc/typd_mlc.c b/boehm-gc/typd_mlc.c index 387d2305829..74f455d926c 100644 --- a/boehm-gc/typd_mlc.c +++ b/boehm-gc/typd_mlc.c @@ -632,7 +632,7 @@ ptr_t GC_clear_stack(); (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k)) #define GENERAL_MALLOC_IOP(lb,k) \ - (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page((word)lb, k)) + (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k)) #if defined(__STDC__) || defined(__cplusplus) void * GC_malloc_explicitly_typed(size_t lb, GC_descr d) @@ -702,7 +702,7 @@ DCL_LOCK_STATE; FASTLOCK(); if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) { FASTUNLOCK(); - op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind); + op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind); # ifdef MERGE_SIZES lw = GC_size_map[lb]; /* May have been uninitialized. */ # endif @@ -712,7 +712,7 @@ DCL_LOCK_STATE; FASTUNLOCK(); } } else { - op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind); + op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind); if (op != NULL) lw = BYTES_TO_WORDS(GC_size(op)); } diff --git a/boehm-gc/version.h b/boehm-gc/version.h index 5611487373c..df0770c9b04 100644 --- a/boehm-gc/version.h +++ b/boehm-gc/version.h @@ -1,6 +1,6 @@ -#define GC_VERSION_MAJOR 4 -#define GC_VERSION_MINOR 13 -#define GC_ALPHA_VERSION 2 +#define GC_VERSION_MAJOR 5 +#define GC_VERSION_MINOR 0 +#define GC_ALPHA_VERSION 4 # define GC_NOT_ALPHA 0xff diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c index eb485bdc064..f6f74bd1111 100644 --- a/boehm-gc/win32_threads.c +++ b/boehm-gc/win32_threads.c @@ -8,22 +8,32 @@ #define MAX_THREADS 64 struct thread_entry { + LONG in_use; DWORD id; HANDLE handle; - void *stack; /* The cold end of the stack. */ + void *stack; /* The cold end of the stack. */ + /* 0 ==> entry not valid. */ + /* !in_use ==> stack == 0 */ CONTEXT context; + GC_bool suspended; }; -struct thread_entry thread_table[MAX_THREADS]; +volatile GC_bool GC_please_stop = FALSE; + +volatile struct thread_entry thread_table[MAX_THREADS]; void GC_stop_world() { DWORD thread_id = GetCurrentThreadId(); int i; + + GC_please_stop = TRUE; for (i = 0; i < MAX_THREADS; i++) - if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) { + if (thread_table[i].stack != 0 + && thread_table[i].id != thread_id) { if (SuspendThread(thread_table[i].handle) == (DWORD)-1) ABORT("SuspendThread failed"); + thread_table[i].suspended = TRUE; } } @@ -32,10 +42,13 @@ void GC_start_world() DWORD thread_id = GetCurrentThreadId(); int i; for (i = 0; i < MAX_THREADS; i++) - if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) { + if (thread_table[i].stack != 0 && thread_table[i].suspended + && thread_table[i].id != thread_id) { if (ResumeThread(thread_table[i].handle) == (DWORD)-1) ABORT("ResumeThread failed"); + thread_table[i].suspended = FALSE; } + GC_please_stop = FALSE; } ptr_t GC_current_stackbottom() @@ -78,6 +91,12 @@ void GC_push_all_stacks() if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack || thread_table[i].context.Esp < (DWORD)bottom) ABORT("Thread stack pointer out of range"); + GC_push_one ((word) thread_table[i].context.Edi); + GC_push_one ((word) thread_table[i].context.Esi); + GC_push_one ((word) thread_table[i].context.Ebx); + GC_push_one ((word) thread_table[i].context.Edx); + GC_push_one ((word) thread_table[i].context.Ecx); + GC_push_one ((word) thread_table[i].context.Eax); GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack); } } @@ -117,20 +136,34 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) switch (reason) { case DLL_PROCESS_ATTACH: InitializeCriticalSection(&GC_allocate_ml); + GC_init(); /* Force initialization before thread attach. */ /* fall through */ case DLL_THREAD_ATTACH: { int i; - LOCK(); + /* It appears to be unsafe to acquire a lock here, since this */ + /* code is apparently not preeemptible on some systems. */ + /* (This is based on complaints, not on Microsoft's official */ + /* documentation, which says this should perform "only simple */ + /* inititalization tasks".) */ + /* Hence we make do with nonblocking synchronization. */ + /* The following should be a noop according to the win32 */ /* documentation. There is empirical evidence that it */ /* isn't. - HB */ - if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler); - for (i = 0; thread_table[i].stack != 0; i++) { +# ifndef SMALL_CONFIG + if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler); +# endif + + for (i = 0; InterlockedExchange(&thread_table[i].in_use,1) != 0; i++) { + /* Compare-and-swap would make this cleaner, but that's not */ + /* supported before Windows 98 and NT 4.0. In Windows 2000, */ + /* InterlockedExchange is supposed to be replaced by */ + /* InterlockedExchangePointer, but that's not really what I */ + /* want here. */ if (i == MAX_THREADS - 1) ABORT("too many threads"); } - thread_table[i].stack = GC_get_stack_base(); thread_table[i].id = GetCurrentThreadId(); if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), @@ -143,7 +176,11 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) GC_printf1("Last error code: %lx\n", last_error); ABORT("DuplicateHandle failed"); } - UNLOCK(); + thread_table[i].stack = GC_get_stack_base(); + /* If this thread is being created while we are trying to stop */ + /* the world, wait here. Hopefully this can't happen on any */ + /* systems that don't allow us to block here. */ + while (GC_please_stop) Sleep(20); } break; case DLL_PROCESS_DETACH: @@ -152,10 +189,14 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) int i; DWORD thread_id = GetCurrentThreadId(); LOCK(); - for (i = 0; thread_table[i].stack == 0 || thread_table[i].id != thread_id; i++) + for (i = 0; + thread_table[i].stack == 0 || thread_table[i].id != thread_id; + i++) { if (i == MAX_THREADS - 1) ABORT("thread not found on detach"); + } thread_table[i].stack = 0; + thread_table[i].in_use = FALSE; CloseHandle(thread_table[i].handle); BZERO(&thread_table[i].context, sizeof(CONTEXT)); UNLOCK(); |