OSDN Git Service

Merged GC 5.0alpha4 with local changes, plus:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 1 Nov 1999 23:15:51 +0000 (23:15 +0000)
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 1 Nov 1999 23:15:51 +0000 (23:15 +0000)
* 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

60 files changed:
boehm-gc/BCC_MAKEFILE
boehm-gc/ChangeLog
boehm-gc/EMX_MAKEFILE
boehm-gc/MacOS.c
boehm-gc/Makefile.am
boehm-gc/Makefile.dj
boehm-gc/Makefile.in
boehm-gc/PCR-Makefile
boehm-gc/README
boehm-gc/README.Mac
boehm-gc/README.QUICK
boehm-gc/README.alpha
boehm-gc/README.amiga
boehm-gc/README.hp
boehm-gc/README.linux
boehm-gc/README.rs6000
boehm-gc/README.sgi
boehm-gc/README.solaris2
boehm-gc/README.win32
boehm-gc/SMakefile.amiga
boehm-gc/WCC_MAKEFILE
boehm-gc/aclocal.m4
boehm-gc/allchblk.c
boehm-gc/alloc.c
boehm-gc/blacklst.c
boehm-gc/configure
boehm-gc/configure.in
boehm-gc/dbg_mlc.c
boehm-gc/dyn_load.c
boehm-gc/finalize.c
boehm-gc/gc.h
boehm-gc/gc.mak
boehm-gc/gc_alloc.h
boehm-gc/gc_cpp.cc
boehm-gc/gc_cpp.h
boehm-gc/gc_hdrs.h
boehm-gc/gc_mark.h
boehm-gc/gc_priv.h
boehm-gc/headers.c
boehm-gc/if_mach.c
boehm-gc/if_not_there.c
boehm-gc/irix_threads.c
boehm-gc/linux_threads.c
boehm-gc/mach_dep.c
boehm-gc/malloc.c
boehm-gc/mallocx.c
boehm-gc/mark.c
boehm-gc/mark_rts.c
boehm-gc/misc.c
boehm-gc/os_dep.c
boehm-gc/reclaim.c
boehm-gc/setjmp_t.c
boehm-gc/solaris_threads.c
boehm-gc/sparc_mach_dep.s
boehm-gc/sparc_sunos4_mach_dep.s
boehm-gc/test.c
boehm-gc/threadlibs.c
boehm-gc/typd_mlc.c
boehm-gc/version.h
boehm-gc/win32_threads.c

index c65a73e..225a1ed 100644 (file)
@@ -39,7 +39,7 @@ OBJS= $(XXXOBJS:XXX=)
 \r
 all: gctest.exe cord\de.exe test_cpp.exe\r
 \r
-$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h config.h MAKEFILE\r
+$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h gcconfig.h MAKEFILE\r
 \r
 gc.lib: $(OBJS)\r
     -del gc.lib\r
index fcb5d49..b4e4175 100644 (file)
@@ -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.
index 1ade12a..54a06ce 100644 (file)
@@ -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
index 420ea50..cc12cd1 100644 (file)
@@ -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) */
index 9cf838b..6ab97ff 100644 (file)
@@ -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)
index 979ac6f..54f77db 100644 (file)
@@ -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
+
index 3efddbe..3e5b4a6 100644 (file)
@@ -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
index 7b80637..1eae367 100644 (file)
@@ -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
index 98d8389..4461e30 100644 (file)
@@ -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.
index 6d2fa74..04f4682 100644 (file)
@@ -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...
index 3273c8b..ddebf82 100644 (file)
@@ -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.
index b187fd5..213a13e 100644 (file)
@@ -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
index 865642b..47b1588 100644 (file)
@@ -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
 ===========================================================================
index 869aaea..072ba53 100644 (file)
@@ -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.)
index ffe735b..b4f136a 100644 (file)
@@ -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.
index 0444ac4..f5630b2 100644 (file)
@@ -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 ...)
index 186e497..e67124b 100644 (file)
@@ -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.
+
index 9ef4648..e593513 100644 (file)
@@ -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=...
 
 
index 76c4c6e..d78816b 100644 (file)
@@ -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)
 
 
index b1aa340..e9602c0 100644 (file)
@@ -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
 
index cc0ef13..087ff6a 100644 (file)
-# 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
index 6a41119..0c758ff 100644 (file)
@@ -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
 
index 7a5a3a1..189b942 100644 (file)
@@ -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
 
 
 /*
- * 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);    
 }
 
index c9d145e..3d0ddf0 100644 (file)
@@ -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
       }
     }
index 44455e5..e5a3a26 100644 (file)
@@ -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()
index d1510a7..f378f3c 100755 (executable)
@@ -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
index 182277a..2972542 100644 (file)
@@ -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
index 079e43b..cf6514b 100644 (file)
  * 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?    */
 
 /* 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)
index d0f523c..b9de4c1 100644 (file)
@@ -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
index d825bf9..2ee927f 100644 (file)
@@ -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.
 # 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;
 
index a4d57e8..535ff63 100644 (file)
 #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
 # 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
index fdd0c9c..0fd22b7 100644 (file)
@@ -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"\
index 1d912db..1f1d54a 100644 (file)
@@ -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
index a766a01..547c56f 100644 (file)
@@ -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
 
index e2f456f..ad7df5d 100644 (file)
@@ -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();}
index 2f2d1bf..60dc2ad 100644 (file)
@@ -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.             */
index ade98a9..4628323 100644 (file)
 /* 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.     */
index cda9c23..8dd496f 100644 (file)
@@ -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 */
index b5cc1af..9564a6a 100644 (file)
 # 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);
+}
index da2b7f9..af01363 100644 (file)
@@ -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)
index 9616309..a93795f 100644 (file)
@@ -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)
index f45c463..5efca21 100644 (file)
@@ -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);
 }
index f83e1dd..8287dce 100644 (file)
  * 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);
 }
index e39880b..52f8634 100644 (file)
 #   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      */
index 41553b7..66e62d2 100644 (file)
@@ -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;
       /*