gc4.6 tarball import gc4_6
authorHans Boehm <boehm@acm.org>
Thu, 9 Nov 1995 00:00:00 +0000 (00:00 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Sat, 17 May 2014 13:21:00 +0000 (17:21 +0400)
47 files changed:
BCC_MAKEFILE
Makefile
NT_MAKEFILE
OS2_MAKEFILE
README
README.debugging
add_gc_prefix.c [new file with mode: 0644]
allchblk.c
alloc.c
blacklst.c
config.h
cord/cord.h
cord/cordbscs.c
cord/cordprnt.c
cord/gc.h
cord/private/cord_pos.h [moved from cord/cord_pos.h with 100% similarity]
dbg_mlc.c
dyn_load.c
finalize.c
gc.h
gc_cpp.h
gc_hdrs.h
gc_priv.h
gcc_support.c [new file with mode: 0644]
include/cord.h
include/gc.h
include/gc_c++.h [deleted file]
include/gc_cpp.h
include/gc_inl.h
include/private/config.h [new file with mode: 0644]
include/private/gc_hdrs.h [new file with mode: 0644]
include/private/gc_priv.h [new file with mode: 0644]
include/weakpointer.h [new file with mode: 0644]
mach_dep.c
malloc.c
mark.c
mark_rts.c
misc.c
obj_map.c
os_dep.c
ptr_chck.c
setjmp_t.c
stubborn.c
test.c
test_cpp.cc
typd_mlc.c
weakpointer.h [new file with mode: 0644]

index 63f0707..b430cc8 100644 (file)
@@ -50,7 +50,7 @@ gctest.exe: test.obj gc.lib
         $(cflags) -W -e$* test.obj gc.lib\r
 |\r
 \r
-cord\de.obj cord\de_win.obj: cord\cord.h cord\cord_pos.h cord\de_win.h \\r
+cord\de.obj cord\de_win.obj: cord\cord.h cord\private\cord_pos.h cord\de_win.h \\r
     cord\de_cmds.h\r
 \r
 cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \\r
@@ -71,11 +71,10 @@ test_cpp.cpp: test_cpp.cc
 \r
 test_cpp.exe: test_cpp.obj gc_cpp.h gc.h gc.lib\r
     $(cc) @&&|\r
-        $(cflags) -WC -e$* test_cpp.obj gc.lib\r
+        $(cflags) -W -e$* test_cpp.obj gc.lib\r
 |\r
 \r
 scratch:\r
     -del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm\r
 \r
 \r
-\1a
index c1f8175..5ba9978 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@
 # Primary targets:
 # gc.a - builds basic library
+# libgc.a - builds library for use with g++ "-fgc-keyword" extension
 # c++ - adds C++ interface to library
 # cords - adds cords (heavyweight strings) to library
 # test - prints porting information, then builds basic version of gc.a,
@@ -7,11 +8,18 @@
 #       c++ interface to gc.a
 # cord/de - builds dumb editor based on cords.
 CC= cc
-CXX=g++ -ansi
-# Needed only for "make c++", which adds the c++ interface
+CXX=gcc
 AS=as
+#  The above doesn't work with gas, which doesn't run cpp.
+#  Define AS as `gcc -c -x assembler-with-cpp' instead.
+
+CFLAGS= -O -DNO_SIGNALS -DSILENT -DALL_INTERIOR_POINTERS
+
+LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
+    -DREDIRECT_MALLOC=GC_malloc_uncollectable \
+    -DDONT_ADD_BYTE_AT_END -DALL_INTERIOR_POINTERS
+#   Flags for building libgc.a -- the last two are required.
 
-CFLAGS= -O -DALL_INTERIOR_POINTERS -DNO_SIGNALS -DSILENT
 # Setjmp_test may yield overly optimistic results when compiled
 # without optimization.
 # -DSILENT disables statistics printing, and improves performance.
@@ -60,7 +68,7 @@ CFLAGS= -O -DALL_INTERIOR_POINTERS -DNO_SIGNALS -DSILENT
 # -DNO_DEBUG removes GC_dump and the debugging routines it calls.
 #   Reduces code size slightly at the expense of debuggability.
 
-CXXFLAGS= $(CFLAGS)
+CXXFLAGS= $(CFLAGS) 
 AR= ar
 RANLIB= ranlib
 
@@ -75,25 +83,31 @@ OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers
 
 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 typd_mlc.c ptr_chck.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/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
+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
 
 CORD_OBJS=  cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
 
-SRCS= $(CSRCS) mips_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 if_mach.c if_not_there.c gc_cpp.cc gc_cpp.h $(CORD_SRCS)
+SRCS= $(CSRCS) mips_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 \
+    if_mach.c if_not_there.c gc_cpp.cc gc_cpp.h weakpointer.h \
+    gcc_support.c $(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/gc_c++.h \
-           README.QUICK callprocs pc_excludes barrett_diagram \
-           README.OS2 README.Mac MacProjects.sit.hqx MacOS.c \
-           EMX_MAKEFILE makefile.depend README.debugging \
+           include/ec.h include/private/cord_pos.h include/private/config.h \
+           include/private/gc_hdrs.h include/private/gc_priv.h include/gc_cpp.h \
+           include/weakpointer.h README.QUICK callprocs pc_excludes \
+           barrett_diagram README.OS2 README.Mac MacProjects.sit.hqx \
+           MacOS.c EMX_MAKEFILE makefile.depend README.debugging \
            include/gc_cpp.h Mac_files/datastart.c Mac_files/dataend.c \
-           Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h
+           Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
+           add_gc_prefix.c
 
 CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
-           $(srcdir)/cord/cord_pos.h
+           $(srcdir)/cord/private/cord_pos.h
 
 # Libraries needed for curses applications.  Only needed for de.
 CURSES= -lcurses -ltermlib
@@ -109,9 +123,6 @@ SPECIALCFLAGS =
 # not time-critical anyway.
 # Set SPECIALCFLAGS to -q nodirect_code on Encore.
 
-ALPHACFLAGS = -non_shared
-# Extra flags for linking compilation on DEC Alpha
-
 all: gc.a gctest
 
 pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h config.h mach_dep.o $(SRCS)
@@ -134,6 +145,15 @@ gc.a: $(OBJS) dyn_load.o
        ./if_not_there on_sparc_sunos5 $(RANLIB) gc.a || cat /dev/null
 #      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 -f 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 || cat /dev/null
+
 cords: $(CORD_OBJS) cord/cordtest
        rm -f on_sparc_sunos5
        ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
@@ -143,9 +163,11 @@ cords: $(CORD_OBJS) cord/cordtest
 
 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 gc.a
-       $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a
+       rm -f test_cpp
+       ./if_mach SPARC SUNOS5 $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a -lthread -ldl
+       ./if_not_there test_cpp $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a
 
 c++: gc_cpp.o $(srcdir)/gc_cpp.h test_cpp
        rm -f on_sparc_sunos5
@@ -156,7 +178,7 @@ c++: gc_cpp.o $(srcdir)/gc_cpp.h test_cpp
        ./test_cpp 1
 
 dyn_load_sunos53.o: dyn_load.c
-       $(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c dyn_load.c -o $@
+       $(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c $(srcdir)/dyn_load.c -o $@
 
 # SunOS5 shared library version of the collector
 libgc.so: $(OBJS) dyn_load_sunos53.o
@@ -166,12 +188,13 @@ libgc.so: $(OBJS) dyn_load_sunos53.o
 libalphagc.so: $(OBJS)
        ld -shared -o libalphagc.so $(OBJS) dyn_load.o -lc
 
+# IRIX shared library version of the collector
+libirixgc.so: $(OBJS) dyn_load.o
+       ld -shared -o libirixgc.so $(OBJS) dyn_load.o -lc
+
 mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_mach_dep.s $(srcdir)/rs6000_mach_dep.s if_mach if_not_there
        rm -f mach_dep.o
        ./if_mach MIPS "" $(AS) -o mach_dep.o $(srcdir)/mips_mach_dep.s
-#  The above doesn't work with gas, which doesn't run cpp.
-#  Rename the above file to end in .S, and then use
-#  gcc -c -o mach_dep.o mips_mach_dep.S instead.
        ./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
@@ -179,7 +202,7 @@ mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_mach_dep.s $(srcdir)/rs6000_mach
 
 mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there
        rm -f mark_rts.o
-       ./if_mach ALPHA "" $(CC) -c $(CFLAGS) -Wo,-notail $(srcdir)/mark_rts.c
+       -./if_mach ALPHA "" $(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
 
@@ -242,32 +265,57 @@ KandRtest: setjmp_test gctest
        ./setjmp_test
        ./gctest
 
-gc.tar: $(SRCS) $(OTHER_FILES)
-       tar cvf gc.tar $(SRCS) $(OTHER_FILES)
-
+add_gc_prefix: add_gc_prefix.c
+       $(CC) -o add_gc_prefix add_gc_prefix.c
+       
+gc.tar: $(SRCS) $(OTHER_FILES) add_gc_prefix
+       tar cvfh gc.tar `add_gc_prefix $(SRCS) $(OTHER_FILES)`
+       
 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/include/* 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
+
+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 7c732c5..3aa57d9 100644 (file)
@@ -2,6 +2,7 @@
 # DLLs are included in the root set under NT, but not under win32S.
 # Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
 
+CPU= i386
 !include <ntwin32.mak>
 
 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
@@ -31,7 +32,7 @@ gctest.exe: test.obj gc.lib
 cord\de_win.rbj: cord\de_win.res
        cvtres -$(CPU) cord\de_win.res -o cord\de_win.rbj
 
-cord\de.obj cord\de_win.obj: cord\cord.h cord\cord_pos.h cord\de_win.h cord\de_cmds.h
+cord\de.obj cord\de_win.obj: cord\cord.h cord\private\cord_pos.h cord\de_win.h cord\de_cmds.h
 
 cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
        $(rc) $(rcvars) -r -fo cord\de_win.res $(cvars) cord\de_win.rc
@@ -50,10 +51,9 @@ test_cpp.cpp: test_cpp.cc
 
 # This generates the C++ test executable.  The executable expects
 # a single numeric argument, which is the number of iterations.
-# Unlike the other test programs, this is currently a console application,
-# and hence does not run under win32s.
+# The output appears in the file "gc.log".
 test_cpp.exe: test_cpp.obj gc_cpp.h gc.h gc.lib
-       $(link) -debug:full -debugtype:cv $(conflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(conlibs)
+       $(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
 
 
 
index a019c3e..46ee5e4 100644 (file)
@@ -32,14 +32,14 @@ mach_dep.obj: mach_dep.c
 gctest.exe: test.obj gc.lib
         $(CC) $(CFLAGS) /B"/STACK:524288" /Fegctest test.obj gc.lib
 
-cord\cordbscs.obj: cord\cordbscs.c cord\cord.h cord\cord_pos.h
+cord\cordbscs.obj: cord\cordbscs.c cord\cord.h cord\private\cord_pos.h
         $(CC) $(CFLAGS) /C /Focord\cordbscs cord\cordbscs.c
 
-cord\cordxtra.obj: cord\cordxtra.c cord\cord.h cord\cord_pos.h cord\ec.h
+cord\cordxtra.obj: cord\cordxtra.c cord\cord.h cord\private\cord_pos.h cord\ec.h
         $(CC) $(CFLAGS) /C /Focord\cordxtra cord\cordxtra.c
 
-cord\cordprnt.obj: cord\cordprnt.c cord\cord.h cord\cord_pos.h cord\ec.h
+cord\cordprnt.obj: cord\cordprnt.c cord\cord.h cord\private\cord_pos.h cord\ec.h
         $(CC) $(CFLAGS) /C /Focord\cordprnt cord\cordprnt.c
 
-cord\cordtest.exe: cord\cordtest.c cord\cord.h cord\cord_pos.h cord\ec.h $(CORDOBJS) gc.lib
+cord\cordtest.exe: cord\cordtest.c cord\cord.h cord\private\cord_pos.h cord\ec.h $(CORDOBJS) gc.lib
         $(CC) $(CFLAGS) /B"/STACK:65536" /Fecord\cordtest cord\cordtest.c gc.lib $(CORDOBJS)
\ No newline at end of file
diff --git a/README b/README
index 53d4935..985036f 100644 (file)
--- a/README
+++ b/README
@@ -10,7 +10,7 @@ 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.5 of a conservative garbage collector for C and C++.
+This is version 4.6 of a conservative garbage collector for C and C++.
 
 HISTORY -
 
@@ -1078,4 +1078,47 @@ Since version 4.4:
    wouldn't scan the expanded part of the object.  (Thanks to Clay Spence
    (cds@peanut.sarnoff.com) for noticing the problem, and helping me to
    track it down.)
-   
\ No newline at end of file
+   
+Since version 4.5:
+ - Added Linux ELF support.  (Thanks to Arrigo Triulzi <arrigo@ic.ac.uk>.)
+ - GC_base crashed if it was called before any other GC_ routines.
+   This could happen if a gc_cleanup object was allocated outside the heap
+   before any heap allocation.
+ - The heap expansion heuristic was not stable if all objects had finalization
+   enabled.  Fixed finalize.c to count memory in finalization queue and
+   avoid explicit deallocation.  Changed alloc.c to also consider this count.
+   (This is still not recommended.  It's expensive if nothing else.)  Thanks
+   to John Ellis for pointing this out.
+ - GC_malloc_uncollectable(0) was broken.  Thanks to Phong Vo for pointing
+   this out.
+ - The collector didn't compile under Linux 1.3.X.  (Thanks to Fred Gilham for
+   pointing this out.)  The current workaround is ugly, but expected to be
+   temporary.
+ - Fixed a formatting problem for SPARC stack traces.
+ - Fixed some '=='s in os_dep.c that should have been assignments.
+   Fortunately these were in code that should never be executed anyway.
+   (Thanks to Fergus Henderson.)
+ - Fixed the heap block allocator to only drop blacklisted blocks in small
+   chunks.  Made BL_LIMIT self adjusting.  (Both of these were in response
+   to heap growth observed by Paul Graham.)
+ - Fixed the Metrowerks/68K Mac code to also mark from a6.  (Thanks
+   to Patrick Beard.)
+ - Significantly updated README.debugging.
+ - Fixed some problems with longjmps out of signal handlers, especially under
+   Solaris.  Added a workaround for the fact that siglongjmp doesn't appear to
+   do the right thing with -lthread under Solaris.
+ - Added MSDOS/djgpp port.  (Thanks to Mitch Harris  (maharri@uiuc.edu).)
+ - Added "make reserved_namespace" and "make user_namespace".  The
+   first renames ALL "GC_xxx" identifiers as "_GC_xxx".  The second is the
+   inverse transformation.  Note that doing this is guaranteed to break all
+   clients written for the other names.
+ - descriptor field for kinf NORMAL in GC_obj_kinds with ADD_BYTE_AT_END
+   defined should be -ALIGNMENT not WORDS_TO_BYTES(-1).  This is
+   a serious bug on machines with pointer alignment of less than a word.
+ - GC_ignore_self_finalize_mark_proc didn't handle pointers to very near the
+   end of the object correctly.  Caused failures of the C++ test on a DEC Alpha
+   with g++.
+ - gc_inl.h still had problems.  Partially fixed.  Added warnings at the
+   beginning to hopefully specify the remaining dangers.
+ - Added DATAEND definition to config.h.
+ - Fixed some of the .h file organization.  Fixed "make floppy".
\ No newline at end of file
index b000ace..bd8dc45 100644 (file)
@@ -1,29 +1,55 @@
 Debugging suggestions:
 
-If the collector dies in GC_malloc while trying to remove a free list element:
+****If you get warning messages informing you that the collector needed to allocate blacklisted blocks:
+
+0) Ignore these warnings while you are using GC_DEBUG.  Some of the routines mentioned below don't have debugging equivalents.  (Alternatively, write the missing routines and send them to me.)
+
+1) Replace allocator calls that request large blocks with calls to GC_malloc_ignore_off_page or GC_malloc_atomic_ignore_off_page.  You may want to set a breakpoint in GC_default_warn_proc to help you identify such calls.  Make sure that a pointer to somewhere near the beginning of the resulting block is maintained in a (preferably volatile) variable as long as the block is needed.
+
+2) If the large blocks are allocated with realloc, I suggest instead allocating them with something like the following.  Note that the realloc size increment should be fairly large (e.g. a factor of 3/2) for this to exhibit reasonable performance.  But we all know we should do that anyway.
+
+void * big_realloc(void *p, size_t new_size)
+{
+    size_t old_size = GC_size(p);
+    void * result;
+    if (new_size <= 10000) return(GC_realloc(p, new_size));
+    if (new_size <= old_size) return(p);
+    result = GC_malloc_ignore_off_page(new_size);
+    if (result == 0) return(0);
+    memcpy(result,p,old_size);
+    GC_free(p);
+    return(result);
+}
+
+3) In the unlikely case that even relatively small object (<20KB) allocations are triggering these warnings, then your address space contains lots of "bogus pointers", i.e. values that appear to be pointers but aren't.  Usually this can be solved by using GC_malloc_atomic or the routines in gc_typed.h to allocate large pointerfree regions of bitmaps, etc.  Sometimes the problem can be solved with trivial changes of encoding in certain values.  It is possible, though not pleasant, to identify the source of the bogus pointers by setting a breakpoint in GC_add_to_black_list_stack, and looking at the value of current_p in the GC_mark_from_mark_stack frame.  Current_p contains the address of the bogus pointer.
+
+4) If you get only a fixed number of these warnings, you are probably only introducing a bounded leak by ignoring them.  If the data structures being allocated are intended to be permanent, then it is also safe to ignore them.  The warnings can be turned off by calling GC_set_warn_proc with a procedure that ignores these warnings (e.g. by doing absolutely nothing).
+
+
+****If the collector dies in GC_malloc while trying to remove a free list element:
 
 1) With > 99% probability, you wrote past the end of an allocated object.  Try setting GC_DEBUG and using the debugging facilities in gc.h.
 
 
-If the heap grows too much:
+****If the heap grows too much:
 
 1) Consider using GC_malloc_atomic for objects containing nonpointers.  This is especially important for large arrays containg compressed data, pseudo-random numbers, and the like.  (This isn't all that likely to solve your problem, but it's a useful and easy optimization anyway, and this is a good time to try it.)   If you allocate large objects containg only one or two pointers at the beginning, either try the typed allocation primitives is gc.h, or separate out the pointerfree component.
-2) If you are using the collector in its default mode, with interior pointer recognition enabled, consider using GC_malloc_ignore_off_page to allocate large objects.  (See gc.h for details.  Large means > 100K in most environments.)  You can determine whether this is necessary by compiling the collector with logging on (without -DSILENT).  If the collector expands the heap many times, without intervening colllections, it is unable to find a sufficiently large chunk of memory that is not "referenced" by "false pointers".  In that case, use GC_malloc_ignore_off_page.  Also
-use GC_malloc_ignore_off_page if you see warnings that blacklisting is being ignored.
+2) If you are using the collector in its default mode, with interior pointer recognition enabled, consider using GC_malloc_ignore_off_page to allocate large objects.  (See gc.h and above for details.  Large means > 100K in most environments.)
 3) GC_print_block_list() will print a list of all currently allocated heap blocks and what size objects they contain.  GC_print_hblkfreelist() will print a list of free heap blocks, and whether they are blacklisted.  GC_dump calls both of these, and also prints information about heap sections, and root segments.
 4) Write a tool that traces back references to the appropriate root.  Send me the code.  (I have code that does this for old PCR.)
 
 
-If the collector appears to be losing objects:
+****If the collector appears to be losing objects:
 
 1) Replace all calls to GC_malloc_atomic and typed allocation by GC_malloc calls.  If this fixes the problem, gradually reinsert your optimizations.
 2) You may also want to try the safe(r) pointer manipulation primitives in gc.h.  But those are hard to use until the preprocessor becomes available.
-3) Try using the GC_DEBUG facilities.  This is lless likely to be successful here than if the collector crashes.
+3) Try using the GC_DEBUG facilities.  This is less likely to be successful here than if the collector crashes.
 [The rest of these are primarily for wizards.  You shouldn't need them unless you're doing something really strange, or debugging a collector port.]
 4) Don't turn on incremental collection.  If that fixes the problem, suspect a bug in the dirty bit implementation.  Try compiling with -DCHECKSUMS to check for modified, but supposedly clean, pages.
 5) On a SPARC, in a single-threaded environment, GC_print_callers(GC_arrays._last_stack) prints a cryptic stack trace as of the time of the last collection.  (You will need a debugger to decipher the result.)  The question to ask then is "why should this object have been accessible at the time of the last collection?  Where was a pointer to it stored?".  This facility should be easy to add for some other collector ports (namely if it's easy to traverse stack frames), but will be hard for others.
 6) "print *GC_find_header(p)" in dbx or gdb will print the garbage collector block header information associated with the object p (e.g. object size, etc.)
-7) GC_is_marked(p) determines whether p is the base address of a marked object.  Note that objects allocated since the last collection should not be marked, and that unmarked objects are reclaimed incrementally.
+7) GC_is_marked(p) determines whether p is the base address of a marked object.  Note that objects allocated since the last collection should not be marked, and that unmarked objects are reclaimed incrementally.  It's usually most interesting to set a breakpoint in GC_finish_collection and then to determine how much of the damaged data structure is marked at that point.
 8) Look at the tracing facility in mark.c.  (Ignore this suggestion unless you are very familiar with collector internals.)
 
 
diff --git a/add_gc_prefix.c b/add_gc_prefix.c
new file mode 100644 (file)
index 0000000..0d1ab6d
--- /dev/null
@@ -0,0 +1,14 @@
+# include <stdio.h>
+int main(argc, argv, envp)
+int argc;
+char ** argv;
+char ** envp;
+{
+    int i;
+    
+    for (i = 1; i < argc; i++) {
+       printf("gc/%s ", argv[i]);
+    }
+    return(0);
+}
index 8912590..c08f9c9 100644 (file)
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, June 13, 1995 3:34 pm PDT */
+/* Boehm, August 9, 1995 5:08 pm PDT */
 
 #define DEBUG
 #undef DEBUG
@@ -167,7 +167,7 @@ unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
                 (kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC)) {
              struct hblk * lasthbp = hbp;
              ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
-             word orig_avail = size_avail;
+             signed_word orig_avail = size_avail;
              signed_word eff_size_needed = ((flags & IGNORE_OFF_PAGE)?
                                                HBLKSIZE
                                                : size_needed);
@@ -196,10 +196,11 @@ unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
                      hbp = thishbp;
                      hhdr = thishdr;
                }
-             } else if (size_needed > BL_LIMIT
-                        && orig_avail - size_needed > BL_LIMIT) {
+             } else if (size_needed > (signed_word)BL_LIMIT
+                        && orig_avail - size_needed
+                           > (signed_word)BL_LIMIT) {
                /* Punt, since anything else risks unreasonable heap growth. */
-               WARN("Needed to allocate blacklisted block at %ld\n",
+               WARN("Needed to allocate blacklisted block at 0x%lx\n",
                     (word)hbp);
                thishbp = hbp;
                size_avail = orig_avail;
@@ -215,19 +216,27 @@ unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
                  /* blocks are unpopular.                              */
                  /* A dropped block will be reconsidered at next GC.   */
                  if ((++count & 3) == 0) {
-                   /* Allocate and drop the block */
-                     if (GC_install_counts(hbp, hhdr->hb_sz)) {
-                       phdr -> hb_next = hhdr -> hb_next;
-                       (void) setup_header(
+                   /* 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);
+                     struct hblk * h;
+                     
+                     phdr -> hb_next = hhdr -> hb_next;
+                     for (h = hbp; h < limit; h++) {
+                       if (h == hbp || GC_install_header(h)) {
+                         hhdr = HDR(h);
+                         (void) setup_header(
                                  hhdr,
-                                 BYTES_TO_WORDS(hhdr->hb_sz - HDR_BYTES),
+                                 BYTES_TO_WORDS(HBLKSIZE - HDR_BYTES),
                                  PTRFREE, 0); /* Cant fail */
-                       if (GC_debugging_started) {
-                           BZERO(hbp + HDR_BYTES, hhdr->hb_sz - HDR_BYTES);
-                       }
-                       if (GC_savhbp == hbp) GC_savhbp = prevhbp;
+                         if (GC_debugging_started) {
+                           BZERO(hbp + 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) first_time = TRUE;
diff --git a/alloc.c b/alloc.c
index d765094..7da237d 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -12,7 +12,7 @@
  * modified is included with the above copyright notice.
  *
  */
-/* Boehm, April 28, 1995 4:36 pm PDT */
+/* Boehm, October 9, 1995 1:03 pm PDT */
 
 
 # include "gc_priv.h"
@@ -79,11 +79,11 @@ bool GC_dont_expand = 0;
 
 word GC_free_space_divisor = 4;
 
-int GC_never_stop_func(NO_PARAMS) { return(0); }
+int GC_never_stop_func GC_PROTO((void)) { return(0); }
 
 CLOCK_TYPE GC_start_time;
 
-int GC_timeout_stop_func(NO_PARAMS)
+int GC_timeout_stop_func GC_PROTO((void))
 {
     CLOCK_TYPE current_time;
     static unsigned count = 0;
@@ -144,8 +144,15 @@ word GC_adj_words_allocd()
     /* is playing by the rules.                                                */
     result = (signed_word)GC_words_allocd
             - (signed_word)GC_mem_freed - expl_managed;
-    if (result > (signed_word)GC_words_allocd) result = GC_words_allocd;
+    if (result > (signed_word)GC_words_allocd) {
+        result = GC_words_allocd;
        /* probably client bug or unfortunate scheduling */
+    }
+    result += GC_words_finalized;
+       /* We count objects enqueued for finalization as though they    */
+       /* had been reallocated this round. Finalization is user        */
+       /* visible progress.  And if we don't count this, we have       */
+       /* stability problems for programs that finalize all objects.   */
     result += GC_words_wasted;
        /* This doesn't reflect useful work.  But if there is lots of   */
        /* new fragmentation, the same is probably true of the heap,    */
@@ -294,7 +301,7 @@ int n;
     }
 }
 
-int GC_collect_a_little(NO_PARAMS)
+int GC_collect_a_little GC_PROTO(())
 {
     int result;
     DCL_LOCK_STATE;
@@ -522,7 +529,7 @@ void GC_finish_collection()
     return(result);
 }
 
-void GC_gcollect(NO_PARAMS)
+void GC_gcollect GC_PROTO(())
 {
     (void)GC_try_to_collect(GC_never_stop_func);
 }
@@ -580,7 +587,7 @@ void GC_print_heap_sects()
         struct hblk *h;
         unsigned nbl = 0;
         
-       GC_printf3("Section %ld form 0x%lx to 0x%lx ", (unsigned long)i,
+       GC_printf3("Section %ld from 0x%lx to 0x%lx ", (unsigned long)i,
                   start, (unsigned long)(start + len));
        for (h = (struct hblk *)start; h < (struct hblk *)(start + len); h++) {
            if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
@@ -606,8 +613,12 @@ ptr_t x, y;
     return(x < y? x : y);
 }
 
-void GC_set_max_heap_size(n)
-word n;
+# if defined(__STDC__) || defined(__cplusplus)
+    void GC_set_max_heap_size(GC_word n)
+# else
+    void GC_set_max_heap_size(n)
+    GC_word n;
+# endif
 {
     GC_max_heapsize = n;
 }
@@ -672,8 +683,12 @@ word n;
 
 /* Really returns a bool, but it's externally visible, so that's clumsy. */
 /* Arguments is in bytes.                                              */
-int GC_expand_hp(bytes)
-size_t bytes;
+# if defined(__STDC__) || defined(__cplusplus)
+  int GC_expand_hp(size_t bytes)
+# else
+  int GC_expand_hp(bytes)
+  size_t bytes;
+# endif
 {
     int result;
     DCL_LOCK_STATE;
index c7836ea..f4f7069 100644 (file)
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, May 19, 1994 1:56 pm PDT */
+/* Boehm, August 9, 1995 6:09 pm PDT */
 # include "gc_priv.h"
 
 /*
@@ -46,6 +46,10 @@ word * GC_incomplete_normal_bl;
 word * GC_old_stack_bl;
 word * GC_incomplete_stack_bl;
 
+word GC_total_black_listed;
+
+word GC_black_list_spacing = 10000000;
+
 void GC_clear_bl();
 
 void GC_bl_init()
@@ -85,6 +89,8 @@ word *new, *old;
     BCOPY(old, new, sizeof(page_hash_table));
 }
 
+static word total_black_listed();
+
 /* Signal the completion of a collection.  Turn the incomplete black   */
 /* lists into new black lists, etc.                                    */                       
 void GC_promote_black_lists()
@@ -100,6 +106,17 @@ void GC_promote_black_lists()
     GC_clear_bl(very_old_stack_bl);
     GC_incomplete_normal_bl = very_old_normal_bl;
     GC_incomplete_stack_bl = very_old_stack_bl;
+    GC_total_black_listed = total_black_listed();
+#   ifdef PRINTSTATS
+       GC_printf1("%ld blacklisted bytes in heap\n",
+                  (unsigned long)GC_total_black_listed);
+#   endif
+    if (GC_total_black_listed != 0) {
+        GC_black_list_spacing = HBLKSIZE*(GC_heapsize/GC_total_black_listed);
+    }
+    if (GC_black_list_spacing < 3 * HBLKSIZE) {
+       GC_black_list_spacing = 3 * HBLKSIZE;
+    }
 }
 
 void GC_unpromote_black_lists()
@@ -193,3 +210,38 @@ word len;
     return(0);
 }
 
+
+/* Return the number of blacklisted blocks in a given range.   */
+/* Used only for statistical purposes.                         */
+/* Looks only at the GC_incomplete_stack_bl.                   */
+word GC_number_stack_black_listed(start, endp1)
+struct hblk *start, *endp1;
+{
+    register struct hblk * h;
+    word result = 0;
+    
+    for (h = start; h < endp1; h++) {
+        register int index = PHT_HASH((word)h);
+        
+        if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
+    }
+    return(result);
+}
+
+
+/* Return the total number of (stack) black-listed bytes. */
+static word total_black_listed()
+{
+    register unsigned i;
+    word total = 0;
+    
+    for (i = 0; i < GC_n_heap_sects; i++) {
+       struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
+       word len = (word) GC_heap_sects[i].hs_bytes;
+       struct hblk * endp1 = start + len/HBLKSIZE;
+       
+       total += GC_number_stack_black_listed(start, endp1);
+    }
+    return(total * HBLKSIZE);
+}
+
index c0004e6..62492c3 100644 (file)
--- a/config.h
+++ b/config.h
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, May 30, 1995 5:04 pm PDT */
+/* Boehm, October 3, 1995 6:39 pm PDT */
  
 #ifndef CONFIG_H
 
@@ -52,7 +52,7 @@
 #    if defined(ultrix) || defined(__ultrix)
 #      define ULTRIX
 #    else
-#      ifdef _SYSTYPE_SVR4
+#      if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__)
 #        define IRIX5
 #      else
 #        define RISCOS  /* or IRIX 4.X */
 #   define MSWIN32     /* or Win32s */
 #   define mach_type_known
 # endif
+# if defined(GO32)
+#   define I386
+#   define DJGPP  /* MSDOS running the DJGPP port of GCC */
+#   define mach_type_known
+# endif
 # if defined(__BORLANDC__)
 #   define I386
 #   define MSWIN32
 #      define OS_TYPE "AMIGA"
                /* STACKBOTTOM and DATASTART handled specially  */
                /* in os_dep.c                                  */
+#      define DATAEND  /* not needed */
 #   endif
 #   ifdef MACOS
 #     ifndef __LOWMEM__
 #     define OS_TYPE "MACOS"
                        /* see os_dep.c for details of global data segments. */
 #     define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
+#     define DATAEND   /* not needed */
 #   endif
 #   ifdef NEXT
 #      define OS_TYPE "NEXT"
 #      define DATASTART ((ptr_t) get_etext())
 #      define STACKBOTTOM ((ptr_t) 0x4000000)
+#      define DATAEND  /* not needed */
 #   endif
 # endif
 
 #     define OS_TYPE "MACOS"
                        /* see os_dep.c for details of global data segments. */
 #     define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
+#     define DATAEND  /* not needed */
 #   endif
 # endif
 
     extern int etext;
 #   ifdef SUNOS5
 #      define OS_TYPE "SUNOS5"
-       extern int etext;
+       extern int _etext;
+       extern int _end;
        extern char * GC_SysVGetDataStart();
-#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
+#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &_etext)
+#      define DATAEND (&_end)
 #      define PROC_VDB
 #      define HEURISTIC1
 #   endif
                /* STACKBOTTOM and DATASTART are handled specially in   */
                /* os_dep.c. OS2 actually has the right                 */
                /* system call!                                         */
+#      define DATAEND  /* not needed */
 #   endif
 #   ifdef MSWIN32
 #      define OS_TYPE "MSWIN32"
                /* STACKBOTTOM and DATASTART are handled specially in   */
                /* os_dep.c.                                            */
 #      define MPROTECT_VDB
+#       define DATAEND  /* not needed */
+#   endif
+#   ifdef DJGPP
+#       define OS_TYPE "DJGPP"
+        extern int etext;
+#       define DATASTART ((ptr_t)(&etext))
+#       define STACKBOTTOM ((ptr_t)0x00080000)
 #   endif
 #   ifdef FREEBSD
 #      define OS_TYPE "FREEBSD"
 #      define OS_TYPE "NEXT"
 #      define DATASTART ((ptr_t) get_etext())
 #      define STACKBOTTOM ((ptr_t)0xc0000000)
+#      define DATAEND  /* not needed */
 #   endif
 # endif
 
 #   define OS_TYPE ""
 # endif
 
+# ifndef DATAEND
+    extern int end;
+#   define DATAEND (&end)
+# endif
+
 # if defined(SUNOS5) || defined(DRSNX)
     /* OS has SVR4 generic features.  Probably others also qualify.    */
 #   define SVR4
index 8386962..8c9c8be 100644 (file)
@@ -12,7 +12,7 @@
  *
  * Author: Hans-J. Boehm (boehm@parc.xerox.com)
  */
-/* Boehm, October 4, 1994 5:34 pm PDT */
+/* Boehm, October 5, 1995 4:20 pm PDT */
  
 /*
  * Cords are immutable character strings.  A number of operations
@@ -81,6 +81,8 @@ CORD CORD_cat(CORD x, CORD y);
 /* Concatenate a cord and a C string with known length.  Except for the        */
 /* empty string case, this is a special case of CORD_cat.  Since the   */
 /* length is known, it can be faster.                                  */
+/* The string y is shared with the resulting CORD.  Hence it should    */
+/* not be altered by the caller.                                       */
 CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
 
 /* Compute the length of a cord */
@@ -152,7 +154,7 @@ int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
 /* described below.  Also note that                                    */
 /* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function        */
 /* definitions.  The former may evaluate their argument more than once. */
-# include "cord_pos.h"
+# include "private/cord_pos.h"
 
 /*
        Visible definitions from above:
@@ -198,7 +200,7 @@ extern void (* CORD_oom_fn)(void);
 void CORD_dump(CORD x);
 
 /* The following could easily be implemented by the client.  They are  */
-/* provided in cord_xtra.c for convenience.                            */
+/* provided in cordxtra.c for convenience.                             */
 
 /* Concatenate a character to the end of a cord.       */
 CORD CORD_cat_char(CORD x, char c);
index bbcc92a..d377662 100644 (file)
@@ -518,10 +518,11 @@ int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
        register const char *p = x + i;
        register char c;
                
-       while (p >= x) {
+       for(;;) {
            c = *p;
            if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
             if ((*f1)(c, client_data)) return(1);
+           if (p == x) break;
             p--;
        }
        return(0);
index e27c1e9..667560f 100644 (file)
@@ -20,7 +20,7 @@
 /* We assume that void * and char * have the same size.                        */
 /* All this cruft is needed because we want to rely on the underlying  */
 /* sprintf implementation whenever possible.                           */
-/* Boehm, October 3, 1994 5:15 pm PDT */
+/* Boehm, September 21, 1995 6:00 pm PDT */
 
 #include "cord.h"
 #include "ec.h"
@@ -304,7 +304,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
                    }
                    res = vsprintf(buf, conv_spec, vsprintf_args);
                    len = (size_t)res;
-                   if ((char *)res == buf) {
+                   if ((char *)(GC_word)res == buf) {
                        /* old style vsprintf */
                        len = strlen(buf);
                    } else if (res < 0) {
index c9fb14f..ab7944e 100644 (file)
--- a/cord/gc.h
+++ b/cord/gc.h
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, January 28, 1995 3:59 pm PST */
+/* Boehm, October 9, 1995 1:14 pm PDT */
 
 /*
  * Note that this defines a large number of tuning hooks, which can
 
 # define _GC_H
 
+# if defined(__STDC__) || defined(__cplusplus)
+#   define GC_PROTO(args) args
+    typedef void * GC_PTR;
+# else
+#   define GC_PROTO(args) ()
+    typedef char * GC_PTR;
+#  endif
+
 # ifdef __cplusplus
     extern "C" {
 # endif
@@ -100,23 +108,10 @@ extern GC_word GC_free_space_divisor;
  * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
  * object implicitly update GC_non_gc_bytes appropriately.
  */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void * GC_malloc(size_t size_in_bytes);
-  extern void * GC_malloc_atomic(size_t size_in_bytes);
-  extern void * GC_malloc_uncollectable(size_t size_in_bytes);
-  extern void * GC_malloc_stubborn(size_t size_in_bytes);
-# else
-  extern char * GC_malloc(/* size_in_bytes */);
-  extern char * GC_malloc_atomic(/* size_in_bytes */);
-  extern char * GC_malloc_uncollectable(/* size_in_bytes */);
-  extern char * GC_malloc_stubborn(/* size_in_bytes */);
-# endif
-
-#if defined(__STDC__) && !defined(__cplusplus)
-# define NO_PARAMS void
-#else
-# define NO_PARAMS
-#endif
+extern GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
 
 /* Explicitly deallocate an object.  Dangerous if used incorrectly.     */
 /* Requires a pointer to the base of an object.                                */
@@ -124,11 +119,7 @@ extern GC_word GC_free_space_divisor;
 /* An object should not be enable for finalization when it is          */
 /* explicitly deallocated.                                             */
 /* GC_free(0) is a no-op, as required by ANSI C for free.              */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void GC_free(void * object_addr);
-# else
-  extern void GC_free(/* object_addr */);
-# endif
+extern void GC_free GC_PROTO((GC_PTR object_addr));
 
 /*
  * Stubborn objects may be changed only if the collector is explicitly informed.
@@ -145,27 +136,19 @@ extern GC_word GC_free_space_divisor;
  * do so.  The same applies to dropping stubborn objects that are still
  * changeable.
  */
-void GC_change_stubborn(/* p */);
-void GC_end_stubborn_change(/* p */);
+extern void GC_change_stubborn GC_PROTO((GC_PTR));
+extern void GC_end_stubborn_change GC_PROTO((GC_PTR));
 
 /* Return a pointer to the base (lowest address) of an object given    */
 /* a pointer to a location within the object.                          */
 /* Return 0 if displaced_pointer doesn't point to within a valid       */
 /* object.                                                             */
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_base(void * displaced_pointer);
-# else
-  char * GC_base(/* char * displaced_pointer */);
-# endif
+extern GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
 
 /* Given a pointer to the base of an object, return its size in bytes. */
 /* The returned size may be slightly larger than what was originally   */
 /* requested.                                                          */
-# if defined(__STDC__) || defined(__cplusplus)
-  size_t GC_size(void * object_addr);
-# else
-  size_t GC_size(/* char * object_addr */);
-# endif
+extern size_t GC_size GC_PROTO((GC_PTR object_addr));
 
 /* For compatibility with C library.  This is occasionally faster than */
 /* a malloc followed by a bcopy.  But if you rely on that, either here */
@@ -175,27 +158,24 @@ void GC_end_stubborn_change(/* p */);
 /* 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.                       */
-# if defined(__STDC__) || defined(__cplusplus)
-    extern void * GC_realloc(void * old_object, size_t new_size_in_bytes);
-# else
-    extern char * GC_realloc(/* old_object, new_size_in_bytes */);
-# endif
-
-
+extern 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.  */
-extern int GC_expand_hp(/* number_of_bytes */);
+extern int GC_expand_hp GC_PROTO((size_t number_of_bytes));
 
 /* Limit the heap size to n bytes.  Useful when you're debugging,      */
 /* especially on systems that don't handle running out of memory well. */
 /* n == 0 ==> unbounded.  This is the default.                         */
-extern void GC_set_max_heap_size(/* n */);
+extern void GC_set_max_heap_size GC_PROTO((GC_word n));
 
 /* Clear the set of root segments.  Wizards only. */
-extern void GC_clear_roots(NO_PARAMS);
+extern void GC_clear_roots GC_PROTO((void));
 
 /* Add a root segment.  Wizards only. */
-extern void GC_add_roots(/* low_address, high_address_plus_1 */);
+extern void GC_add_roots GC_PROTO((char * low_address,
+                                  char * high_address_plus_1));
 
 /* Add a displacement to the set of those considered valid by the      */
 /* collector.  GC_register_displacement(n) means that if p was returned */
@@ -209,14 +189,14 @@ extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 /* retention.                                                          */
 /* This is a no-op if the collector was compiled with recognition of   */
 /* arbitrary interior pointers enabled, which is now the default.      */
-void GC_register_displacement(/* GC_word n */);
+void GC_register_displacement GC_PROTO((GC_word n));
 
 /* The following version should be used if any debugging allocation is */
 /* being done.                                                         */
-void GC_debug_register_displacement(/* GC_word n */);
+void GC_debug_register_displacement GC_PROTO((GC_word n));
 
 /* Explicitly trigger a full, world-stop collection.   */
-void GC_gcollect(NO_PARAMS);
+void GC_gcollect GC_PROTO((void));
 
 /* Trigger a full world-stopped collection.  Abort the collection if   */
 /* and when stop_func returns a nonzero value.  Stop_func will be      */
@@ -226,20 +206,16 @@ void GC_gcollect(NO_PARAMS);
 /* than normal pause times for incremental collection.  However,       */
 /* aborted collections do no useful work; the next collection needs    */
 /* to start from the beginning.                                                */
-typedef int (* GC_stop_func)(NO_PARAMS);
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_try_to_collect(GC_stop_func stop_func);
-# else
-    int GC_try_to_collect(/* GC_stop_func stop_func */);
-# endif
+typedef int (* GC_stop_func) GC_PROTO((void));
+int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
 
 /* Return the number of bytes in the heap.  Excludes collector private */
 /* data structures.  Includes empty blocks and fragmentation loss.     */
 /* Includes some pages that were allocated but never written.          */
-size_t GC_get_heap_size(NO_PARAMS);
+size_t GC_get_heap_size GC_PROTO((void));
 
 /* Return the number of bytes allocated since the last collection.     */
-size_t GC_get_bytes_since_gc(NO_PARAMS);
+size_t GC_get_bytes_since_gc GC_PROTO((void));
 
 /* Enable incremental/generational collection. */
 /* Not advisable unless dirty bits are                 */
@@ -247,7 +223,7 @@ size_t GC_get_bytes_since_gc(NO_PARAMS);
 /* pointerfree(atomic) or immutable.           */
 /* Don't use in leak finding mode.             */
 /* Ignored if GC_dont_gc is true.              */
-void GC_enable_incremental(NO_PARAMS);
+void GC_enable_incremental GC_PROTO((void));
 
 /* Perform some garbage collection work, if appropriate.       */
 /* Return 0 if there is no more work to be done.               */
@@ -256,7 +232,7 @@ void GC_enable_incremental(NO_PARAMS);
 /* progress requires it, e.g. if incremental collection is     */
 /* disabled.  It is reasonable to call this in a wait loop     */
 /* until it returns 0.                                         */
-int GC_collect_a_little(NO_PARAMS);
+int GC_collect_a_little GC_PROTO((void));
 
 /* Allocate an object of size lb bytes.  The client guarantees that    */
 /* as long as the object is live, it will be referenced by a pointer   */
@@ -272,46 +248,26 @@ int GC_collect_a_little(NO_PARAMS);
 /* for arrays likely to be larger than 100K or so.  For other systems, */
 /* or if the collector is not configured to recognize all interior     */
 /* pointers, the threshold is normally much higher.                    */
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_ignore_off_page(size_t lb);
-# else
-  char * GC_malloc_ignore_off_page(/* size_t lb */);
-# endif
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_atomic_ignore_off_page(size_t lb);
-# else
-  char * GC_malloc_atomic_ignore_off_page(/* size_t lb */);
-# endif
+extern GC_PTR GC_malloc_ignore_off_page GC_PROTO((size_t lb));
+extern GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
 
 /* Debugging (annotated) allocation.  GC_gcollect will check           */
 /* objects allocated in this way for overwrites, etc.                  */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void * GC_debug_malloc(size_t size_in_bytes,
-                               char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_atomic(size_t size_in_bytes,
-                                      char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_uncollectable(size_t size_in_bytes,
-                                          char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_stubborn(size_t size_in_bytes,
-                                        char * descr_string, int descr_int);
-  extern void GC_debug_free(void * object_addr);
-  extern void * GC_debug_realloc(void * old_object,
-                                size_t new_size_in_bytes,
-                                char * descr_string, int descr_int);
-# else
-  extern char * GC_debug_malloc(/* size_in_bytes, descr_string, descr_int */);
-  extern char * GC_debug_malloc_atomic(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern char * GC_debug_malloc_uncollectable(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern char * GC_debug_malloc_stubborn(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern void GC_debug_free(/* object_addr */);
-  extern char * GC_debug_realloc(/* old_object, new_size_in_bytes,
-                                   descr_string, descr_int */);
-# endif
-void GC_debug_change_stubborn(/* p */);
-void GC_debug_end_stubborn_change(/* p */);
+extern GC_PTR GC_debug_malloc
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_atomic
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_uncollectable
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_stubborn
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern void GC_debug_free GC_PROTO((GC_PTR object_addr));
+extern GC_PTR GC_debug_realloc
+       GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
+                 char * descr_string, int descr_int));
+                                
+void GC_debug_change_stubborn GC_PROTO((GC_PTR));
+void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
 # ifdef GC_DEBUG
 #   define GC_MALLOC(sz) GC_debug_malloc(sz, __FILE__, __LINE__)
 #   define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, __FILE__, __LINE__)
@@ -367,21 +323,12 @@ void GC_debug_end_stubborn_change(/* p */);
 /* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes,             */
 /* Christian Jacobi, and Russ Atkinson.  It's not perfect, and         */
 /* probably nobody else agrees with it.            Hans-J. Boehm  3/13/92      */
-# if defined(__STDC__) || defined(__cplusplus)
-  typedef void (*GC_finalization_proc)(void * obj, void * client_data);
-# else
-  typedef void (*GC_finalization_proc)(/* void * obj, void * client_data */);
-# endif
+typedef void (*GC_finalization_proc)
+       GC_PROTO((GC_PTR obj, GC_PTR client_data));
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_register_finalizer(void * obj,
-                              GC_finalization_proc fn, void * cd,
-                              GC_finalization_proc *ofn, void ** ocd);
-# else 
-    void GC_register_finalizer(/* void * obj,
-                                 GC_finalization_proc fn, void * cd,
-                                 GC_finalization_proc *ofn, void ** ocd */);
-# endif
+extern void GC_register_finalizer
+       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+                 GC_finalization_proc *ofn, GC_PTR *ocd));
        /* When obj is no longer accessible, invoke             */
        /* (*fn)(obj, cd).  If a and b are inaccessible, and    */
        /* a points to b (after disappearing links have been    */
@@ -421,15 +368,9 @@ void GC_debug_end_stubborn_change(/* p */);
 /* but it's unavoidable for C++, since the compiler may                */
 /* silently introduce these.  It's also benign in that specific        */
 /* case.                                                       */
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_register_finalizer_ignore_self(void * obj,
-                              GC_finalization_proc fn, void * cd,
-                              GC_finalization_proc *ofn, void ** ocd);
-# else 
-    void GC_register_finalizer_ignore_self(/* void * obj,
-                                 GC_finalization_proc fn, void * cd,
-                                 GC_finalization_proc *ofn, void ** ocd */);
-# endif
+extern void GC_register_finalizer_ignore_self
+       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+                 GC_finalization_proc *ofn, GC_PTR *ocd));
 
 /* The following routine may be used to break cycles between   */
 /* finalizable objects, thus causing cyclic finalizable                */
@@ -438,12 +379,7 @@ void GC_debug_end_stubborn_change(/* p */);
 /* where p is a pointer that is not followed by finalization   */
 /* code, and should not be considered in determining           */
 /* finalization order.                                         */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_register_disappearing_link(void ** /* link */);
-# else
-    int GC_register_disappearing_link(/* void ** link */);
-# endif
-
+extern int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
        /* Link should point to a field of a heap allocated     */
        /* object obj.  *link will be cleared when obj is       */
        /* found to be inaccessible.  This happens BEFORE any   */
@@ -462,11 +398,9 @@ void GC_debug_end_stubborn_change(/* p */);
        /* Returns 1 if link was already registered, 0          */
        /* otherwise.                                           */
        /* Only exists for backward compatibility.  See below:  */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_general_register_disappearing_link(void ** /* link */, void * obj);
-# else
-    int GC_general_register_disappearing_link(/* void ** link, void * obj */);
-# endif
+       
+extern int GC_general_register_disappearing_link
+       GC_PROTO((GC_PTR * /* link */, GC_PTR obj));
        /* A slight generalization of the above. *link is       */
        /* cleared when obj first becomes inaccessible.  This   */
        /* can be used to implement weak pointers easily and    */
@@ -484,34 +418,20 @@ void GC_debug_end_stubborn_change(/* p */);
        /* the object containing link.  Explicitly deallocating */
        /* obj may or may not cause link to eventually be       */
        /* cleared.                                             */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_unregister_disappearing_link(void ** /* link */);
-# else
-    int GC_unregister_disappearing_link(/* void ** link */);
-# endif
+extern int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
        /* Returns 0 if link was not actually registered.       */
        /* Undoes a registration by either of the above two     */
        /* routines.                                            */
 
 /* Auxiliary fns to make finalization work correctly with displaced    */
 /* pointers introduced by the debugging allocators.                    */
-# if defined(__STDC__) || defined(__cplusplus)
-    void * GC_make_closure(GC_finalization_proc fn, void * data);
-    void GC_debug_invoke_finalizer(void * obj, void * data);
-# else
-    char * GC_make_closure(/* GC_finalization_proc fn, char * data */);
-    void GC_debug_invoke_finalizer(/* void * obj, void * data */);
-# endif
+extern GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
+extern void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
 
 /* GC_set_warn_proc can be used to redirect or filter warning messages.        */
-# if defined(__STDC__) || defined(__cplusplus)
-    typedef void (*GC_warn_proc)(char *msg, GC_word arg);
-    GC_warn_proc GC_set_warn_proc(GC_warn_proc p);
+typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
+extern GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
     /* Returns old warning procedure.  */
-# else
-    typedef void (*GC_warn_proc)(/* char *msg, GC_word arg */);
-    GC_warn_proc GC_set_warn_proc(/* GC_warn_proc p */);
-# endif
        
 /* The following is intended to be used by a higher level      */
 /* (e.g. cedar-like) finalization facility.  It is expected    */
@@ -521,37 +441,32 @@ void GC_debug_end_stubborn_change(/* p */);
 /* Note that putting pointers in atomic objects or in          */
 /* nonpointer slots of "typed" objects is equivalent to        */
 /* disguising them in this way, and may have other advantages. */
-# ifdef I_HIDE_POINTERS
-#   if defined(__STDC__) || defined(__cplusplus)
-#     define HIDE_POINTER(p) (~(size_t)(p))
-#     define REVEAL_POINTER(p) ((void *)(HIDE_POINTER(p)))
-#   else
-#     define HIDE_POINTER(p) (~(unsigned long)(p))
-#     define REVEAL_POINTER(p) ((char *)(HIDE_POINTER(p)))
-#   endif
+# if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
+    typedef GC_word GC_hidden_pointer;
+#   define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
+#   define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
     /* Converting a hidden pointer to a real pointer requires verifying        */
     /* that the object still exists.  This involves acquiring the      */
     /* allocator lock to avoid a race with the collector.              */
+# endif /* I_HIDE_POINTERS */
 
-#   if defined(__STDC__) || defined(__cplusplus)
-        typedef void * (*GC_fn_type)();
-        void * GC_call_with_alloc_lock(GC_fn_type fn, void * client_data);
-#   else
-        typedef char * (*GC_fn_type)();
-        char * GC_call_with_alloc_lock(/* GC_fn_type fn, char * client_data */);
-#   endif
-# endif
+typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data));
+extern GC_PTR GC_call_with_alloc_lock
+               GC_PROTO((GC_fn_type fn, GC_PTR client_data));
 
 /* Check that p and q point to the same object.                */
 /* Fail conspicuously if they don't.                           */
 /* Returns the first argument.                                 */
 /* Succeeds if neither p nor q points to the heap.             */
 /* May succeed if both p and q point to between heap objects.  */
-#ifdef __STDC__
-  void * GC_same_obj(register void *p, register void *q);
-#else
-  char * GC_same_obj(/* char * p, char * q */);
-#endif
+extern GC_PTR GC_same_obj GC_PROTO((GC_PTR p, GC_PTR q));
+
+/* Checked pointer pre- and post- increment operations.  Note that     */
+/* the second argument is in units of bytes, not multiples of the      */
+/* object size.  This should either be invoked from a macro, or the    */
+/* call should be automatically generated.                             */
+extern GC_PTR GC_pre_incr GC_PROTO((GC_PTR *p, size_t how_much));
+extern GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
 
 /* Check that p is visible                                             */
 /* to the collector as a possibly pointer containing location.         */
@@ -561,31 +476,31 @@ void GC_debug_end_stubborn_change(/* p */);
 /* untyped allocations.  The idea is that it should be possible, though        */
 /* slow, to add such a call to all indirect pointer stores.)           */
 /* Currently useless for multithreaded worlds.                         */
-#ifdef __STDC__
-  void * GC_is_visible(void *p);
-#else
-  char *GC_is_visible(/* char * p */);
-#endif
+extern GC_PTR GC_is_visible GC_PROTO((GC_PTR p));
 
 /* Check that if p is a pointer to a heap page, then it points to      */
 /* a valid displacement within a heap object.                          */
 /* Fail conspicuously if this property does not hold.                  */
 /* Uninteresting with ALL_INTERIOR_POINTERS.                           */
 /* Always returns its argument.                                                */
-#ifdef __STDC__
-  void * GC_is_valid_displacement(void *p);
-#else
-  char *GC_is_valid_displacement(/* char * p */);
-#endif
+extern GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR        p));
 
 /* Safer, but slow, pointer addition.  Probably useful mainly with     */
 /* a preprocessor.  Useful only for heap pointers.                     */
 #ifdef GC_DEBUG
 #   define GC_PTR_ADD3(x, n, type_of_result) \
        ((type_of_result)GC_same_obj((x)+(n), (x)))
+#   define GC_PRE_INCR3(x, n, type_of_result) \
+       ((type_of_result)GC_pre_incr(&(x), (n)*sizeof(*x))
+#   define GC_POST_INCR2(x, type_of_result) \
+       ((type_of_result)GC_post_incr(&(x), sizeof(*x))
 #   ifdef __GNUC__
 #       define GC_PTR_ADD(x, n) \
-           ((typeof(x))GC_same_obj((x)+(n), (x)))
+           GC_PTR_ADD3(x, n, typeof(x))
+#   define GC_PRE_INCR(x, n) \
+           GC_PRE_INCR3(x, n, typeof(x))
+#   define GC_POST_INCR(x, n) \
+           GC_POST_INCR3(x, typeof(x))
 #   else
        /* We can't do this right without typeof, which ANSI    */
        /* decided was not sufficiently useful.  Repeatedly     */
@@ -596,6 +511,10 @@ void GC_debug_end_stubborn_change(/* p */);
 #else  /* !GC_DEBUG */
 #   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
 #   define GC_PTR_ADD(x, n) ((x)+(n))
+#   define GC_PRE_INCR3(x, n, type_of_result) ((x) += (n))
+#   define GC_PRE_INCR(x, n) ((x) += (n))
+#   define GC_POST_INCR2(x, n, type_of_result) ((x)++)
+#   define GC_POST_INCR(x, n) ((x)++)
 #endif
 
 /* Safer assignment of a pointer to a nonstack location.       */
@@ -638,8 +557,8 @@ void GC_debug_end_stubborn_change(/* p */);
 /* 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.  */
-void * GC_malloc_many(size_t lb);
-#define GC_NEXT(p) (*(void **)(p))     /* Retrieve the next element    */
+GC_PTR GC_malloc_many(size_t lb);
+#define GC_NEXT(p) (*(GC_PTR *)(p))    /* Retrieve the next element    */
                                        /* in returned list.            */
 
 #endif /* SOLARIS_THREADS */
similarity index 100%
rename from cord/cord_pos.h
rename to cord/private/cord_pos.h
index 16c19c9..432d729 100644 (file)
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -1,6 +1,6 @@
 /* 
  * 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.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, April 18, 1995 3:29 pm PDT */
+/* Boehm, October 9, 1995 1:16 pm PDT */
 # include "gc_priv.h"
 
 /* Do we want to and know how to save the call stack at the time of    */
@@ -166,23 +166,27 @@ void GC_start_debugging()
     GC_register_displacement((word)sizeof(oh));
 }
 
-void GC_debug_register_displacement(n)
-word n;
+# if defined(__STDC__) || defined(__cplusplus)
+    void GC_debug_register_displacement(GC_word offset)
+# else
+    void GC_debug_register_displacement(offset) 
+    GC_word offset;
+# endif
 {
-    GC_register_displacement(n);
-    GC_register_displacement((word)sizeof(oh) + n);
+    GC_register_displacement(offset);
+    GC_register_displacement((word)sizeof(oh) + offset);
 }
 
 # ifdef __STDC__
-    extern_ptr_t GC_debug_malloc(size_t lb, char * s, int i)
+    GC_PTR GC_debug_malloc(size_t lb, char * s, int i)
 # else
-    extern_ptr_t GC_debug_malloc(lb, s, i)
+    GC_PTR GC_debug_malloc(lb, s, i)
     size_t lb;
     char * s;
     int i;
 # endif
 {
-    extern_ptr_t result = GC_malloc(lb + DEBUG_BYTES);
+    GC_PTR result = GC_malloc(lb + DEBUG_BYTES);
     
     if (result == 0) {
         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
@@ -200,15 +204,15 @@ word n;
 
 #ifdef STUBBORN_ALLOC
 # ifdef __STDC__
-    extern_ptr_t GC_debug_malloc_stubborn(size_t lb, char * s, int i)
+    GC_PTR GC_debug_malloc_stubborn(size_t lb, char * s, int i)
 # else
-    extern_ptr_t GC_debug_malloc_stubborn(lb, s, i)
+    GC_PTR GC_debug_malloc_stubborn(lb, s, i)
     size_t lb;
     char * s;
     int i;
 # endif
 {
-    extern_ptr_t result = GC_malloc_stubborn(lb + DEBUG_BYTES);
+    GC_PTR result = GC_malloc_stubborn(lb + DEBUG_BYTES);
     
     if (result == 0) {
         GC_err_printf1("GC_debug_malloc(%ld) returning NIL (",
@@ -225,9 +229,9 @@ word n;
 }
 
 void GC_debug_change_stubborn(p)
-extern_ptr_t p;
+GC_PTR p;
 {
-    register extern_ptr_t q = GC_base(p);
+    register GC_PTR q = GC_base(p);
     register hdr * hhdr;
     
     if (q == 0) {
@@ -245,9 +249,9 @@ extern_ptr_t p;
 }
 
 void GC_debug_end_stubborn_change(p)
-extern_ptr_t p;
+GC_PTR p;
 {
-    register extern_ptr_t q = GC_base(p);
+    register GC_PTR q = GC_base(p);
     register hdr * hhdr;
     
     if (q == 0) {
@@ -267,15 +271,15 @@ extern_ptr_t p;
 #endif /* STUBBORN_ALLOC */
 
 # ifdef __STDC__
-    extern_ptr_t GC_debug_malloc_atomic(size_t lb, char * s, int i)
+    GC_PTR GC_debug_malloc_atomic(size_t lb, char * s, int i)
 # else
-    extern_ptr_t GC_debug_malloc_atomic(lb, s, i)
+    GC_PTR GC_debug_malloc_atomic(lb, s, i)
     size_t lb;
     char * s;
     int i;
 # endif
 {
-    extern_ptr_t result = GC_malloc_atomic(lb + DEBUG_BYTES);
+    GC_PTR result = GC_malloc_atomic(lb + DEBUG_BYTES);
     
     if (result == 0) {
         GC_err_printf1("GC_debug_malloc_atomic(%ld) returning NIL (",
@@ -292,15 +296,15 @@ extern_ptr_t p;
 }
 
 # ifdef __STDC__
-    extern_ptr_t GC_debug_malloc_uncollectable(size_t lb, char * s, int i)
+    GC_PTR GC_debug_malloc_uncollectable(size_t lb, char * s, int i)
 # else
-    extern_ptr_t GC_debug_malloc_uncollectable(lb, s, i)
+    GC_PTR GC_debug_malloc_uncollectable(lb, s, i)
     size_t lb;
     char * s;
     int i;
 # endif
 {
-    extern_ptr_t result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
+    GC_PTR result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
     
     if (result == 0) {
         GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
@@ -318,13 +322,13 @@ extern_ptr_t p;
 
 
 # ifdef __STDC__
-    void GC_debug_free(extern_ptr_t p)
+    void GC_debug_free(GC_PTR p)
 # else
     void GC_debug_free(p)
-    extern_ptr_t p;
+    GC_PTR p;
 # endif
 {
-    register extern_ptr_t base = GC_base(p);
+    register GC_PTR base = GC_base(p);
     register ptr_t clobbered;
     
     if (base == 0) {
@@ -356,18 +360,18 @@ extern_ptr_t p;
 }
 
 # ifdef __STDC__
-    extern_ptr_t GC_debug_realloc(extern_ptr_t p, size_t lb, char *s, int i)
+    GC_PTR GC_debug_realloc(GC_PTR p, size_t lb, char *s, int i)
 # else
-    extern_ptr_t GC_debug_realloc(p, lb, s, i)
-    extern_ptr_t p;
+    GC_PTR GC_debug_realloc(p, lb, s, i)
+    GC_PTR p;
     size_t lb;
     char *s;
     int i;
 # endif
 {
-    register extern_ptr_t base = GC_base(p);
+    register GC_PTR base = GC_base(p);
     register ptr_t clobbered;
-    register extern_ptr_t result = GC_debug_malloc(lb, s, i);
+    register GC_PTR result = GC_debug_malloc(lb, s, i);
     register size_t copy_sz = lb;
     register size_t old_sz;
     register hdr * hhdr;
@@ -461,15 +465,15 @@ void GC_check_heap_proc()
 
 struct closure {
     GC_finalization_proc cl_fn;
-    extern_ptr_t cl_data;
+    GC_PTR cl_data;
 };
 
 # ifdef __STDC__
     void * GC_make_closure(GC_finalization_proc fn, void * data)
 # else
-    extern_ptr_t GC_make_closure(fn, data)
+    GC_PTR GC_make_closure(fn, data)
     GC_finalization_proc fn;
-    extern_ptr_t data;
+    GC_PTR data;
 # endif
 {
     struct closure * result =
@@ -477,7 +481,7 @@ struct closure {
     
     result -> cl_fn = fn;
     result -> cl_data = data;
-    return((extern_ptr_t)result);
+    return((GC_PTR)result);
 }
 
 # ifdef __STDC__
@@ -490,6 +494,6 @@ struct closure {
 {
     register struct closure * cl = (struct closure *) data;
     
-    (*(cl -> cl_fn))((extern_ptr_t)((char *)obj + sizeof(oh)), cl -> cl_data);
+    (*(cl -> cl_fn))((GC_PTR)((char *)obj + sizeof(oh)), cl -> cl_data);
 } 
 
index 601c365..e3f2ac6 100644 (file)
@@ -13,7 +13,7 @@
  * Original author: Bill Janssen
  * Heavily modified by Hans Boehm and others
  */
-/* Boehm, April 17, 1995 3:20 pm PDT */
+/* Boehm, September 21, 1995 5:57 pm PDT */
 
 /*
  * This is incredibly OS specific code for tracking down data sections in
@@ -456,15 +456,15 @@ void GC_register_dynamic_libraries()
       /* Check status AFTER checking moduleid because */
       /* of a bug in the non-shared ldr_next_module stub */
         if (status != 0 ) {
-            GC_printf("dynamic_load: status = %ld\n", (long)status);
+            GC_printf1("dynamic_load: status = %ld\n", (long)status);
             {
                 extern char *sys_errlist[];
                 extern int sys_nerr;
                 extern int errno;
                 if (errno <= sys_nerr) {
-                    GC_printf("dynamic_load: %s\n", sys_errlist[errno]);
+                    GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
                } else {
-                    GC_printf("dynamic_load: %d\n", errno);
+                    GC_printf1("dynamic_load: %d\n", (long)errno);
                 }
         }
             ABORT("ldr_next_module failed");
index cec1b56..5340e0f 100644 (file)
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, January 28, 1995 4:26 pm PST */
+/* Boehm, September 22, 1995 5:49 pm PDT */
 # define I_HIDE_POINTERS
 # include "gc_priv.h"
 # include "gc_mark.h"
@@ -79,8 +79,6 @@ void GC_push_finalizer_structures()
 }
 # endif
 
-# define ALLOC(x, t) t *x = GC_NEW(t)
-
 /* Double the size of a hash table. *size_ptr is the log of its current        */
 /* size.  May be a noop.                                               */
 /* *table is a pointer to an array of hash headers.  If we succeed, we */
@@ -124,27 +122,27 @@ signed_word * log_size_ptr;
 }
 
 # if defined(__STDC__) || defined(__cplusplus)
-    int GC_register_disappearing_link(extern_ptr_t * link)
+    int GC_register_disappearing_link(GC_PTR * link)
 # else
     int GC_register_disappearing_link(link)
-    extern_ptr_t * link;
+    GC_PTR * link;
 # endif
 {
     ptr_t base;
     
-    base = (ptr_t)GC_base((extern_ptr_t)link);
+    base = (ptr_t)GC_base((GC_PTR)link);
     if (base == 0)
        ABORT("Bad arg to GC_register_disappearing_link");
     return(GC_general_register_disappearing_link(link, base));
 }
 
 # if defined(__STDC__) || defined(__cplusplus)
-    int GC_general_register_disappearing_link(extern_ptr_t * link,
-                                             extern_ptr_t obj)
+    int GC_general_register_disappearing_link(GC_PTR * link,
+                                             GC_PTR obj)
 # else
     int GC_general_register_disappearing_link(link, obj)
-    extern_ptr_t * link;
-    extern_ptr_t obj;
+    GC_PTR * link;
+    GC_PTR obj;
 # endif
 
 {
@@ -190,7 +188,8 @@ signed_word * log_size_ptr;
       new_dl = (struct disappearing_link *)
        GC_generic_malloc_inner(sizeof(struct disappearing_link),NORMAL);
 #   else
-      new_dl = GC_NEW(struct disappearing_link);
+      new_dl = (struct disappearing_link *)
+       GC_malloc(sizeof(struct disappearing_link));
 #   endif
     if (new_dl != 0) {
         new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
@@ -209,10 +208,10 @@ signed_word * log_size_ptr;
 }
 
 # if defined(__STDC__) || defined(__cplusplus)
-    int GC_unregister_disappearing_link(extern_ptr_t * link)
+    int GC_unregister_disappearing_link(GC_PTR * link)
 # else
     int GC_unregister_disappearing_link(link)
-    extern_ptr_t * link;
+    GC_PTR * link;
 # endif
 {
     struct disappearing_link *curr_dl, *prev_dl;
@@ -234,7 +233,7 @@ signed_word * log_size_ptr;
             GC_dl_entries--;
             UNLOCK();
            ENABLE_SIGNALS();
-            GC_free((extern_ptr_t)curr_dl);
+            GC_free((GC_PTR)curr_dl);
             return(1);
         }
         prev_dl = curr_dl;
@@ -266,16 +265,17 @@ ptr_t p;
     hdr * hhdr = HDR(p);
     word descr = hhdr -> hb_descr;
     ptr_t q, r;
-    ptr_t limit;
+    ptr_t scan_limit;
+    ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
     
     if ((descr & DS_TAGS) == DS_LENGTH) {
-       limit = p + descr - sizeof(word);
+       scan_limit = p + descr - sizeof(word);
     } else {
-       limit = p + WORDS_TO_BYTES(hhdr -> hb_sz - 1);
+       scan_limit = target_limit + 1 - sizeof(word);
     }
-    for (q = p; q <= limit; q += ALIGNMENT) {
+    for (q = p; q <= scan_limit; q += ALIGNMENT) {
        r = *(ptr_t *)q;
-       if (r < p || r > limit) {
+       if (r < p || r > target_limit) {
            GC_PUSH_ONE_HEAP((word)r);
        }
     }
@@ -294,11 +294,11 @@ ptr_t p;
 /* since it can be expensive.  Threads packages typically      */
 /* make it cheaper.                                            */
 void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
-extern_ptr_t obj;
+GC_PTR obj;
 GC_finalization_proc fn;
-extern_ptr_t cd;
+GC_PTR cd;
 GC_finalization_proc * ofn;
-extern_ptr_t * ocd;
+GC_PTR * ocd;
 finalization_mark_proc * mp;
 {
     ptr_t base;
@@ -337,7 +337,7 @@ finalization_mark_proc * mp;
             /* should be safe.  The client may see only *ocd   */
             /* updated, but we'll declare that to be his       */
             /* problem.                                                */
-            if (ocd) *ocd = (extern_ptr_t) curr_fo -> fo_client_data;
+            if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
             if (ofn) *ofn = curr_fo -> fo_fn;
             /* Delete the structure for base. */
                 if (prev_fo == 0) {
@@ -351,7 +351,7 @@ finalization_mark_proc * mp;
                   /* estimate will only make the table larger than     */
                   /* necessary.                                                */
 #              ifndef THREADS
-                  GC_free((extern_ptr_t)curr_fo);
+                  GC_free((GC_PTR)curr_fo);
 #              endif
             } else {
                 curr_fo -> fo_fn = fn;
@@ -387,7 +387,8 @@ finalization_mark_proc * mp;
       new_fo = (struct finalizable_object *)
        GC_generic_malloc_inner(sizeof(struct finalizable_object),NORMAL);
 #   else
-      new_fo = GC_NEW(struct finalizable_object);
+      new_fo = (struct finalizable_object *)
+       GC_malloc(sizeof(struct finalizable_object));
 #   endif
     if (new_fo != 0) {
         new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
@@ -413,11 +414,11 @@ finalization_mark_proc * mp;
                               GC_finalization_proc *ofn, void ** ocd)
 # else
     void GC_register_finalizer(obj, fn, cd, ofn, ocd)
-    extern_ptr_t obj;
+    GC_PTR obj;
     GC_finalization_proc fn;
-    extern_ptr_t cd;
+    GC_PTR cd;
     GC_finalization_proc * ofn;
-    extern_ptr_t * ocd;
+    GC_PTR * ocd;
 # endif
 {
     GC_register_finalizer_inner(obj, fn, cd, ofn,
@@ -430,11 +431,11 @@ finalization_mark_proc * mp;
                               GC_finalization_proc *ofn, void ** ocd)
 # else
     void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
-    extern_ptr_t obj;
+    GC_PTR obj;
     GC_finalization_proc fn;
-    extern_ptr_t cd;
+    GC_PTR cd;
     GC_finalization_proc * ofn;
-    extern_ptr_t * ocd;
+    GC_PTR * ocd;
 # endif
 {
     GC_register_finalizer_inner(obj, fn, cd, ofn,
@@ -447,11 +448,11 @@ finalization_mark_proc * mp;
                               GC_finalization_proc *ofn, void ** ocd)
 # else
     void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
-    extern_ptr_t obj;
+    GC_PTR obj;
     GC_finalization_proc fn;
-    extern_ptr_t cd;
+    GC_PTR cd;
     GC_finalization_proc * ofn;
-    extern_ptr_t * ocd;
+    GC_PTR * ocd;
 # endif
 {
     GC_register_finalizer_inner(obj, fn, cd, ofn,
@@ -517,7 +518,7 @@ void GC_finalize()
                    while (!GC_mark_some());
             }
             if (GC_is_marked(real_ptr)) {
-                WARN("Finalization cycle involving %ld\n", real_ptr);
+                WARN("Finalization cycle involving %lx\n", real_ptr);
             }
         }
         
@@ -525,6 +526,7 @@ void GC_finalize()
     }
   /* Enqueue for finalization all objects that are still               */
   /* unreachable.                                                      */
+    GC_words_finalized = 0;
     for (i = 0; i < fo_size; i++) {
       curr_fo = fo_head[i];
       prev_fo = 0;
@@ -543,6 +545,9 @@ void GC_finalize()
             /* Add to list of objects awaiting finalization.   */
               fo_set_next(curr_fo, GC_finalize_now);
               GC_finalize_now = curr_fo;
+              GC_words_finalized +=
+                       ALIGNED_WORDS(curr_fo -> fo_object_size)
+                       + ALIGNED_WORDS(sizeof(struct finalizable_object));
 #          ifdef PRINTSTATS
               if (!GC_is_marked((ptr_t)curr_fo)) {
                 ABORT("GC_finalize: found accessible unmarked object\n");
@@ -601,23 +606,29 @@ void GC_invoke_finalizers()
 #      else
            GC_finalize_now = fo_next(curr_fo);
 #      endif
+       fo_set_next(curr_fo, 0);
        real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
        (*(curr_fo -> fo_fn))(real_ptr, curr_fo -> fo_client_data);
-#      ifndef THREADS
-           GC_free((extern_ptr_t)curr_fo);
+       curr_fo -> fo_client_data = 0;
+#      ifdef UNDEFINED
+           /* This is probably a bad idea.  It throws off accounting if */
+           /* nearly all objects are finalizable.  O.w. it shouldn't    */
+           /* matter.                                                   */
+           GC_free((GC_PTR)curr_fo);
 #      endif
     }
 }
 
 # ifdef __STDC__
-    extern_ptr_t GC_call_with_alloc_lock(GC_fn_type fn, extern_ptr_t client_data)
+    GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
+                                        GC_PTR client_data)
 # else
-    extern_ptr_t GC_call_with_alloc_lock(fn, client_data)
+    GC_PTR GC_call_with_alloc_lock(fn, client_data)
     GC_fn_type fn;
-    extern_ptr_t client_data;
+    GC_PTR client_data;
 # endif
 {
-    extern_ptr_t result;
+    GC_PTR result;
     DCL_LOCK_STATE;
     
 #   ifdef THREADS
diff --git a/gc.h b/gc.h
index c9fb14f..ab7944e 100644 (file)
--- a/gc.h
+++ b/gc.h
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, January 28, 1995 3:59 pm PST */
+/* Boehm, October 9, 1995 1:14 pm PDT */
 
 /*
  * Note that this defines a large number of tuning hooks, which can
 
 # define _GC_H
 
+# if defined(__STDC__) || defined(__cplusplus)
+#   define GC_PROTO(args) args
+    typedef void * GC_PTR;
+# else
+#   define GC_PROTO(args) ()
+    typedef char * GC_PTR;
+#  endif
+
 # ifdef __cplusplus
     extern "C" {
 # endif
@@ -100,23 +108,10 @@ extern GC_word GC_free_space_divisor;
  * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
  * object implicitly update GC_non_gc_bytes appropriately.
  */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void * GC_malloc(size_t size_in_bytes);
-  extern void * GC_malloc_atomic(size_t size_in_bytes);
-  extern void * GC_malloc_uncollectable(size_t size_in_bytes);
-  extern void * GC_malloc_stubborn(size_t size_in_bytes);
-# else
-  extern char * GC_malloc(/* size_in_bytes */);
-  extern char * GC_malloc_atomic(/* size_in_bytes */);
-  extern char * GC_malloc_uncollectable(/* size_in_bytes */);
-  extern char * GC_malloc_stubborn(/* size_in_bytes */);
-# endif
-
-#if defined(__STDC__) && !defined(__cplusplus)
-# define NO_PARAMS void
-#else
-# define NO_PARAMS
-#endif
+extern GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
 
 /* Explicitly deallocate an object.  Dangerous if used incorrectly.     */
 /* Requires a pointer to the base of an object.                                */
@@ -124,11 +119,7 @@ extern GC_word GC_free_space_divisor;
 /* An object should not be enable for finalization when it is          */
 /* explicitly deallocated.                                             */
 /* GC_free(0) is a no-op, as required by ANSI C for free.              */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void GC_free(void * object_addr);
-# else
-  extern void GC_free(/* object_addr */);
-# endif
+extern void GC_free GC_PROTO((GC_PTR object_addr));
 
 /*
  * Stubborn objects may be changed only if the collector is explicitly informed.
@@ -145,27 +136,19 @@ extern GC_word GC_free_space_divisor;
  * do so.  The same applies to dropping stubborn objects that are still
  * changeable.
  */
-void GC_change_stubborn(/* p */);
-void GC_end_stubborn_change(/* p */);
+extern void GC_change_stubborn GC_PROTO((GC_PTR));
+extern void GC_end_stubborn_change GC_PROTO((GC_PTR));
 
 /* Return a pointer to the base (lowest address) of an object given    */
 /* a pointer to a location within the object.                          */
 /* Return 0 if displaced_pointer doesn't point to within a valid       */
 /* object.                                                             */
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_base(void * displaced_pointer);
-# else
-  char * GC_base(/* char * displaced_pointer */);
-# endif
+extern GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
 
 /* Given a pointer to the base of an object, return its size in bytes. */
 /* The returned size may be slightly larger than what was originally   */
 /* requested.                                                          */
-# if defined(__STDC__) || defined(__cplusplus)
-  size_t GC_size(void * object_addr);
-# else
-  size_t GC_size(/* char * object_addr */);
-# endif
+extern size_t GC_size GC_PROTO((GC_PTR object_addr));
 
 /* For compatibility with C library.  This is occasionally faster than */
 /* a malloc followed by a bcopy.  But if you rely on that, either here */
@@ -175,27 +158,24 @@ void GC_end_stubborn_change(/* p */);
 /* 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.                       */
-# if defined(__STDC__) || defined(__cplusplus)
-    extern void * GC_realloc(void * old_object, size_t new_size_in_bytes);
-# else
-    extern char * GC_realloc(/* old_object, new_size_in_bytes */);
-# endif
-
-
+extern 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.  */
-extern int GC_expand_hp(/* number_of_bytes */);
+extern int GC_expand_hp GC_PROTO((size_t number_of_bytes));
 
 /* Limit the heap size to n bytes.  Useful when you're debugging,      */
 /* especially on systems that don't handle running out of memory well. */
 /* n == 0 ==> unbounded.  This is the default.                         */
-extern void GC_set_max_heap_size(/* n */);
+extern void GC_set_max_heap_size GC_PROTO((GC_word n));
 
 /* Clear the set of root segments.  Wizards only. */
-extern void GC_clear_roots(NO_PARAMS);
+extern void GC_clear_roots GC_PROTO((void));
 
 /* Add a root segment.  Wizards only. */
-extern void GC_add_roots(/* low_address, high_address_plus_1 */);
+extern void GC_add_roots GC_PROTO((char * low_address,
+                                  char * high_address_plus_1));
 
 /* Add a displacement to the set of those considered valid by the      */
 /* collector.  GC_register_displacement(n) means that if p was returned */
@@ -209,14 +189,14 @@ extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 /* retention.                                                          */
 /* This is a no-op if the collector was compiled with recognition of   */
 /* arbitrary interior pointers enabled, which is now the default.      */
-void GC_register_displacement(/* GC_word n */);
+void GC_register_displacement GC_PROTO((GC_word n));
 
 /* The following version should be used if any debugging allocation is */
 /* being done.                                                         */
-void GC_debug_register_displacement(/* GC_word n */);
+void GC_debug_register_displacement GC_PROTO((GC_word n));
 
 /* Explicitly trigger a full, world-stop collection.   */
-void GC_gcollect(NO_PARAMS);
+void GC_gcollect GC_PROTO((void));
 
 /* Trigger a full world-stopped collection.  Abort the collection if   */
 /* and when stop_func returns a nonzero value.  Stop_func will be      */
@@ -226,20 +206,16 @@ void GC_gcollect(NO_PARAMS);
 /* than normal pause times for incremental collection.  However,       */
 /* aborted collections do no useful work; the next collection needs    */
 /* to start from the beginning.                                                */
-typedef int (* GC_stop_func)(NO_PARAMS);
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_try_to_collect(GC_stop_func stop_func);
-# else
-    int GC_try_to_collect(/* GC_stop_func stop_func */);
-# endif
+typedef int (* GC_stop_func) GC_PROTO((void));
+int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
 
 /* Return the number of bytes in the heap.  Excludes collector private */
 /* data structures.  Includes empty blocks and fragmentation loss.     */
 /* Includes some pages that were allocated but never written.          */
-size_t GC_get_heap_size(NO_PARAMS);
+size_t GC_get_heap_size GC_PROTO((void));
 
 /* Return the number of bytes allocated since the last collection.     */
-size_t GC_get_bytes_since_gc(NO_PARAMS);
+size_t GC_get_bytes_since_gc GC_PROTO((void));
 
 /* Enable incremental/generational collection. */
 /* Not advisable unless dirty bits are                 */
@@ -247,7 +223,7 @@ size_t GC_get_bytes_since_gc(NO_PARAMS);
 /* pointerfree(atomic) or immutable.           */
 /* Don't use in leak finding mode.             */
 /* Ignored if GC_dont_gc is true.              */
-void GC_enable_incremental(NO_PARAMS);
+void GC_enable_incremental GC_PROTO((void));
 
 /* Perform some garbage collection work, if appropriate.       */
 /* Return 0 if there is no more work to be done.               */
@@ -256,7 +232,7 @@ void GC_enable_incremental(NO_PARAMS);
 /* progress requires it, e.g. if incremental collection is     */
 /* disabled.  It is reasonable to call this in a wait loop     */
 /* until it returns 0.                                         */
-int GC_collect_a_little(NO_PARAMS);
+int GC_collect_a_little GC_PROTO((void));
 
 /* Allocate an object of size lb bytes.  The client guarantees that    */
 /* as long as the object is live, it will be referenced by a pointer   */
@@ -272,46 +248,26 @@ int GC_collect_a_little(NO_PARAMS);
 /* for arrays likely to be larger than 100K or so.  For other systems, */
 /* or if the collector is not configured to recognize all interior     */
 /* pointers, the threshold is normally much higher.                    */
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_ignore_off_page(size_t lb);
-# else
-  char * GC_malloc_ignore_off_page(/* size_t lb */);
-# endif
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_atomic_ignore_off_page(size_t lb);
-# else
-  char * GC_malloc_atomic_ignore_off_page(/* size_t lb */);
-# endif
+extern GC_PTR GC_malloc_ignore_off_page GC_PROTO((size_t lb));
+extern GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
 
 /* Debugging (annotated) allocation.  GC_gcollect will check           */
 /* objects allocated in this way for overwrites, etc.                  */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void * GC_debug_malloc(size_t size_in_bytes,
-                               char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_atomic(size_t size_in_bytes,
-                                      char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_uncollectable(size_t size_in_bytes,
-                                          char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_stubborn(size_t size_in_bytes,
-                                        char * descr_string, int descr_int);
-  extern void GC_debug_free(void * object_addr);
-  extern void * GC_debug_realloc(void * old_object,
-                                size_t new_size_in_bytes,
-                                char * descr_string, int descr_int);
-# else
-  extern char * GC_debug_malloc(/* size_in_bytes, descr_string, descr_int */);
-  extern char * GC_debug_malloc_atomic(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern char * GC_debug_malloc_uncollectable(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern char * GC_debug_malloc_stubborn(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern void GC_debug_free(/* object_addr */);
-  extern char * GC_debug_realloc(/* old_object, new_size_in_bytes,
-                                   descr_string, descr_int */);
-# endif
-void GC_debug_change_stubborn(/* p */);
-void GC_debug_end_stubborn_change(/* p */);
+extern GC_PTR GC_debug_malloc
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_atomic
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_uncollectable
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_stubborn
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern void GC_debug_free GC_PROTO((GC_PTR object_addr));
+extern GC_PTR GC_debug_realloc
+       GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
+                 char * descr_string, int descr_int));
+                                
+void GC_debug_change_stubborn GC_PROTO((GC_PTR));
+void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
 # ifdef GC_DEBUG
 #   define GC_MALLOC(sz) GC_debug_malloc(sz, __FILE__, __LINE__)
 #   define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, __FILE__, __LINE__)
@@ -367,21 +323,12 @@ void GC_debug_end_stubborn_change(/* p */);
 /* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes,             */
 /* Christian Jacobi, and Russ Atkinson.  It's not perfect, and         */
 /* probably nobody else agrees with it.            Hans-J. Boehm  3/13/92      */
-# if defined(__STDC__) || defined(__cplusplus)
-  typedef void (*GC_finalization_proc)(void * obj, void * client_data);
-# else
-  typedef void (*GC_finalization_proc)(/* void * obj, void * client_data */);
-# endif
+typedef void (*GC_finalization_proc)
+       GC_PROTO((GC_PTR obj, GC_PTR client_data));
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_register_finalizer(void * obj,
-                              GC_finalization_proc fn, void * cd,
-                              GC_finalization_proc *ofn, void ** ocd);
-# else 
-    void GC_register_finalizer(/* void * obj,
-                                 GC_finalization_proc fn, void * cd,
-                                 GC_finalization_proc *ofn, void ** ocd */);
-# endif
+extern void GC_register_finalizer
+       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+                 GC_finalization_proc *ofn, GC_PTR *ocd));
        /* When obj is no longer accessible, invoke             */
        /* (*fn)(obj, cd).  If a and b are inaccessible, and    */
        /* a points to b (after disappearing links have been    */
@@ -421,15 +368,9 @@ void GC_debug_end_stubborn_change(/* p */);
 /* but it's unavoidable for C++, since the compiler may                */
 /* silently introduce these.  It's also benign in that specific        */
 /* case.                                                       */
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_register_finalizer_ignore_self(void * obj,
-                              GC_finalization_proc fn, void * cd,
-                              GC_finalization_proc *ofn, void ** ocd);
-# else 
-    void GC_register_finalizer_ignore_self(/* void * obj,
-                                 GC_finalization_proc fn, void * cd,
-                                 GC_finalization_proc *ofn, void ** ocd */);
-# endif
+extern void GC_register_finalizer_ignore_self
+       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+                 GC_finalization_proc *ofn, GC_PTR *ocd));
 
 /* The following routine may be used to break cycles between   */
 /* finalizable objects, thus causing cyclic finalizable                */
@@ -438,12 +379,7 @@ void GC_debug_end_stubborn_change(/* p */);
 /* where p is a pointer that is not followed by finalization   */
 /* code, and should not be considered in determining           */
 /* finalization order.                                         */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_register_disappearing_link(void ** /* link */);
-# else
-    int GC_register_disappearing_link(/* void ** link */);
-# endif
-
+extern int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
        /* Link should point to a field of a heap allocated     */
        /* object obj.  *link will be cleared when obj is       */
        /* found to be inaccessible.  This happens BEFORE any   */
@@ -462,11 +398,9 @@ void GC_debug_end_stubborn_change(/* p */);
        /* Returns 1 if link was already registered, 0          */
        /* otherwise.                                           */
        /* Only exists for backward compatibility.  See below:  */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_general_register_disappearing_link(void ** /* link */, void * obj);
-# else
-    int GC_general_register_disappearing_link(/* void ** link, void * obj */);
-# endif
+       
+extern int GC_general_register_disappearing_link
+       GC_PROTO((GC_PTR * /* link */, GC_PTR obj));
        /* A slight generalization of the above. *link is       */
        /* cleared when obj first becomes inaccessible.  This   */
        /* can be used to implement weak pointers easily and    */
@@ -484,34 +418,20 @@ void GC_debug_end_stubborn_change(/* p */);
        /* the object containing link.  Explicitly deallocating */
        /* obj may or may not cause link to eventually be       */
        /* cleared.                                             */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_unregister_disappearing_link(void ** /* link */);
-# else
-    int GC_unregister_disappearing_link(/* void ** link */);
-# endif
+extern int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
        /* Returns 0 if link was not actually registered.       */
        /* Undoes a registration by either of the above two     */
        /* routines.                                            */
 
 /* Auxiliary fns to make finalization work correctly with displaced    */
 /* pointers introduced by the debugging allocators.                    */
-# if defined(__STDC__) || defined(__cplusplus)
-    void * GC_make_closure(GC_finalization_proc fn, void * data);
-    void GC_debug_invoke_finalizer(void * obj, void * data);
-# else
-    char * GC_make_closure(/* GC_finalization_proc fn, char * data */);
-    void GC_debug_invoke_finalizer(/* void * obj, void * data */);
-# endif
+extern GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
+extern void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
 
 /* GC_set_warn_proc can be used to redirect or filter warning messages.        */
-# if defined(__STDC__) || defined(__cplusplus)
-    typedef void (*GC_warn_proc)(char *msg, GC_word arg);
-    GC_warn_proc GC_set_warn_proc(GC_warn_proc p);
+typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
+extern GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
     /* Returns old warning procedure.  */
-# else
-    typedef void (*GC_warn_proc)(/* char *msg, GC_word arg */);
-    GC_warn_proc GC_set_warn_proc(/* GC_warn_proc p */);
-# endif
        
 /* The following is intended to be used by a higher level      */
 /* (e.g. cedar-like) finalization facility.  It is expected    */
@@ -521,37 +441,32 @@ void GC_debug_end_stubborn_change(/* p */);
 /* Note that putting pointers in atomic objects or in          */
 /* nonpointer slots of "typed" objects is equivalent to        */
 /* disguising them in this way, and may have other advantages. */
-# ifdef I_HIDE_POINTERS
-#   if defined(__STDC__) || defined(__cplusplus)
-#     define HIDE_POINTER(p) (~(size_t)(p))
-#     define REVEAL_POINTER(p) ((void *)(HIDE_POINTER(p)))
-#   else
-#     define HIDE_POINTER(p) (~(unsigned long)(p))
-#     define REVEAL_POINTER(p) ((char *)(HIDE_POINTER(p)))
-#   endif
+# if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
+    typedef GC_word GC_hidden_pointer;
+#   define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
+#   define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
     /* Converting a hidden pointer to a real pointer requires verifying        */
     /* that the object still exists.  This involves acquiring the      */
     /* allocator lock to avoid a race with the collector.              */
+# endif /* I_HIDE_POINTERS */
 
-#   if defined(__STDC__) || defined(__cplusplus)
-        typedef void * (*GC_fn_type)();
-        void * GC_call_with_alloc_lock(GC_fn_type fn, void * client_data);
-#   else
-        typedef char * (*GC_fn_type)();
-        char * GC_call_with_alloc_lock(/* GC_fn_type fn, char * client_data */);
-#   endif
-# endif
+typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data));
+extern GC_PTR GC_call_with_alloc_lock
+               GC_PROTO((GC_fn_type fn, GC_PTR client_data));
 
 /* Check that p and q point to the same object.                */
 /* Fail conspicuously if they don't.                           */
 /* Returns the first argument.                                 */
 /* Succeeds if neither p nor q points to the heap.             */
 /* May succeed if both p and q point to between heap objects.  */
-#ifdef __STDC__
-  void * GC_same_obj(register void *p, register void *q);
-#else
-  char * GC_same_obj(/* char * p, char * q */);
-#endif
+extern GC_PTR GC_same_obj GC_PROTO((GC_PTR p, GC_PTR q));
+
+/* Checked pointer pre- and post- increment operations.  Note that     */
+/* the second argument is in units of bytes, not multiples of the      */
+/* object size.  This should either be invoked from a macro, or the    */
+/* call should be automatically generated.                             */
+extern GC_PTR GC_pre_incr GC_PROTO((GC_PTR *p, size_t how_much));
+extern GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
 
 /* Check that p is visible                                             */
 /* to the collector as a possibly pointer containing location.         */
@@ -561,31 +476,31 @@ void GC_debug_end_stubborn_change(/* p */);
 /* untyped allocations.  The idea is that it should be possible, though        */
 /* slow, to add such a call to all indirect pointer stores.)           */
 /* Currently useless for multithreaded worlds.                         */
-#ifdef __STDC__
-  void * GC_is_visible(void *p);
-#else
-  char *GC_is_visible(/* char * p */);
-#endif
+extern GC_PTR GC_is_visible GC_PROTO((GC_PTR p));
 
 /* Check that if p is a pointer to a heap page, then it points to      */
 /* a valid displacement within a heap object.                          */
 /* Fail conspicuously if this property does not hold.                  */
 /* Uninteresting with ALL_INTERIOR_POINTERS.                           */
 /* Always returns its argument.                                                */
-#ifdef __STDC__
-  void * GC_is_valid_displacement(void *p);
-#else
-  char *GC_is_valid_displacement(/* char * p */);
-#endif
+extern GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR        p));
 
 /* Safer, but slow, pointer addition.  Probably useful mainly with     */
 /* a preprocessor.  Useful only for heap pointers.                     */
 #ifdef GC_DEBUG
 #   define GC_PTR_ADD3(x, n, type_of_result) \
        ((type_of_result)GC_same_obj((x)+(n), (x)))
+#   define GC_PRE_INCR3(x, n, type_of_result) \
+       ((type_of_result)GC_pre_incr(&(x), (n)*sizeof(*x))
+#   define GC_POST_INCR2(x, type_of_result) \
+       ((type_of_result)GC_post_incr(&(x), sizeof(*x))
 #   ifdef __GNUC__
 #       define GC_PTR_ADD(x, n) \
-           ((typeof(x))GC_same_obj((x)+(n), (x)))
+           GC_PTR_ADD3(x, n, typeof(x))
+#   define GC_PRE_INCR(x, n) \
+           GC_PRE_INCR3(x, n, typeof(x))
+#   define GC_POST_INCR(x, n) \
+           GC_POST_INCR3(x, typeof(x))
 #   else
        /* We can't do this right without typeof, which ANSI    */
        /* decided was not sufficiently useful.  Repeatedly     */
@@ -596,6 +511,10 @@ void GC_debug_end_stubborn_change(/* p */);
 #else  /* !GC_DEBUG */
 #   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
 #   define GC_PTR_ADD(x, n) ((x)+(n))
+#   define GC_PRE_INCR3(x, n, type_of_result) ((x) += (n))
+#   define GC_PRE_INCR(x, n) ((x) += (n))
+#   define GC_POST_INCR2(x, n, type_of_result) ((x)++)
+#   define GC_POST_INCR(x, n) ((x)++)
 #endif
 
 /* Safer assignment of a pointer to a nonstack location.       */
@@ -638,8 +557,8 @@ void GC_debug_end_stubborn_change(/* p */);
 /* 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.  */
-void * GC_malloc_many(size_t lb);
-#define GC_NEXT(p) (*(void **)(p))     /* Retrieve the next element    */
+GC_PTR GC_malloc_many(size_t lb);
+#define GC_NEXT(p) (*(GC_PTR *)(p))    /* Retrieve the next element    */
                                        /* in returned list.            */
 
 #endif /* SOLARIS_THREADS */
index 14eccf3..812bb65 100644 (file)
--- a/gc_cpp.h
+++ b/gc_cpp.h
@@ -16,7 +16,7 @@ the code was modified is included with the above copyright notice.
 C++ Interface to the Boehm Collector
 
     John R. Ellis and Jesse Hull 
-    Last modified on Wed Jan  4 16:30:20 PST 1995 by ellis
+    Last modified on Mon Jul 24 15:43:42 PDT 1995 by ellis
 
 This interface provides access to the Boehm collector.  It provides
 basic facilities similar to those described in "Safe, Efficient
@@ -34,7 +34,7 @@ Objects allocated with the built-in "::operator new" are uncollectable.
 
 Objects derived from class "gc" are collectable.  For example:
 
-    class A: gc {...};
+    class A: public gc {...};
     A* a = new A;       // a is collectable. 
 
 Collectable instances of non-class types can be allocated using the GC
@@ -46,7 +46,7 @@ placement:
 Uncollectable instances of classes derived from "gc" can be allocated
 using the NoGC placement:
 
-    class A: gc {...};
+    class A: public gc {...};
     A* a = new (NoGC) A;   // a is uncollectable.
 
 Both uncollectable and collectable objects can be explicitly deleted
@@ -87,35 +87,42 @@ Cautions:
 add -DOPERATOR_NEW_ARRAY to the Makefile.
 
 If your compiler doesn't support "operator new[]", beware that an
-array of type T, where T is derived from "gc", will by default be
-allocated as an uncollectable object.  Use the explicit GC placement
-to make the array collectable.  For example:
+array of type T, where T is derived from "gc", may or may not be
+allocated as a collectable object (it depends on the compiler).  Use
+the explicit GC placement to make the array collectable.  For example:
 
-    class A: gc {...};
-    A* a1 = new A[ 10 ];        // uncollectable
+    class A: public gc {...};
+    A* a1 = new A[ 10 ];        // collectable or uncollectable?
     A* a2 = new (GC) A[ 10 ];   // collectable
 
-3. Arrays of objects derived from "gc_cleanup" do not have default
-clean-up functions.  For example:
+3. The destructors of collectable arrays of objects derived from
+"gc_cleanup" will not be invoked properly.  For example:
 
-    class A: gc_cleanup {...};
-    A* a = new (GC) A[ 10 ];
+    class A: public gc_cleanup {...};
+    A* a = new (GC) A[ 10 ];    // destructors not invoked correctly
 
-The elements of "a" will not have their destructors invoked when the
-collector frees "a".  You must supply an explicit clean-up function
-for that to occur.
+Typically, only the destructor for the first element of the array will
+be invoked when the array is garbage-collected.  To get all the
+destructors of any array executed, you must supply an explicit
+clean-up function:
+
+    A* a = new (GC, MyCleanUp) A[ 10 ];
+
+(Implementing clean-up of arrays correctly, portably, and in a way
+that preserves the correct exception semantics requires a language
+extension, e.g. the "gc" keyword.)
 
 4. Compiler bugs:
 
-    Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
-    destructors of classes derived from gc_cleanup won't be invoked.
-    You'll have to explicitly register a clean-up function with
-    new-placement syntax.
+* Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
+destructors of classes derived from gc_cleanup won't be invoked.
+You'll have to explicitly register a clean-up function with
+new-placement syntax.
 
-    Evidently cfront 3.0 does not allow destructors to be explicitly
-    invoked using the ANSI-conforming syntax t->~T().  If you're using
-    cfront 3.0, you'll have to comment out the class gc_cleanup, which
-    uses explicit invocation.
+* Evidently cfront 3.0 does not allow destructors to be explicitly
+invoked using the ANSI-conforming syntax t->~T().  If you're using
+cfront 3.0, you'll have to comment out the class gc_cleanup, which
+uses explicit invocation.
 
 ****************************************************************************/
 
@@ -125,7 +132,8 @@ for that to occur.
 #define _cdecl
 #endif
 
-#if __BORLANDC__ >= 0x450 && !defined(OPERATOR_NEW_ARRAY)
+#if ! defined( OPERATOR_NEW_ARRAY ) \
+    && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6))
 #   define OPERATOR_NEW_ARRAY
 #endif
 
@@ -232,10 +240,15 @@ inline void gc_cleanup::cleanup( void* obj, void* displ ) {
     ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
 
 inline gc_cleanup::gc_cleanup() {
+    GC_finalization_proc oldProc;
+    void* oldData;
     void* base = GC_base( (void *) this );
-    if (0 != base) {
-        GC_REGISTER_FINALIZER_IGNORE_SELF( 
-            base, cleanup, (void*) ((char*) this - (char*) base), 0, 0 );}}
+    if (0 == base) return;
+    GC_REGISTER_FINALIZER_IGNORE_SELF( 
+        base, cleanup, (void*) ((char*) this - (char*) base), 
+        &oldProc, &oldData );
+    if (0 != oldProc) {
+        GC_REGISTER_FINALIZER_IGNORE_SELF( base, oldProc, oldData, 0, 0 );}}
 
 inline void* operator new( 
     size_t size, 
index f24ad9a..2f2d1bf 100644 (file)
--- a/gc_hdrs.h
+++ b/gc_hdrs.h
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, July 14, 1994 12:49 pm PDT */
+/* Boehm, July 11, 1995 11:54 am PDT */
 # ifndef GC_HEADERS_H
 # define GC_HEADERS_H
 typedef struct hblkhdr hdr;
@@ -80,11 +80,12 @@ typedef struct bi {
 
 # define MAX_JUMP (HBLKSIZE - 1)
 
+# define HDR_FROM_BI(bi, p) \
+               ((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
 # ifndef HASH_TL
 #   define BI(p) (GC_top_index \
                [(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
-#   define HDR_INNER(p) (BI(p)->index \
-               [((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
+#   define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
 #   ifdef SMALL_CONFIG
 #      define HDR(p) GC_find_header((ptr_t)(p))
 #   else
@@ -113,8 +114,7 @@ typedef struct bi {
            register bottom_index * bi; \
            \
            GET_BI(p, bi);      \
-           (ha) = &(bi->index[((unsigned long)(p)>>LOG_HBLKSIZE) \
-                               & (BOTTOM_SZ - 1)]); \
+           (ha) = &(HDR_FROM_BI(bi, p)); \
        }
 #   define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
                              (hhdr) = *_ha; }
index bc2b0d5..357a390 100644 (file)
--- a/gc_priv.h
+++ b/gc_priv.h
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, April 18, 1995 2:51 pm PDT */
+/* Boehm, August 9, 1995 5:49 pm PDT */
  
 
 # ifndef GC_PRIVATE_H
@@ -65,13 +65,11 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
 #   if !(defined( sony_news ) )
 #       include <stddef.h>
 #   endif
-    typedef void * extern_ptr_t;
 #   define VOLATILE volatile
 #else
 #   ifdef MSWIN32
 #      include <stdlib.h>
 #   endif
-    typedef char * extern_ptr_t;
 #   define VOLATILE
 #endif
 
@@ -212,7 +210,7 @@ typedef char * ptr_t;       /* A generic pointer to which we can add        */
 # define TIME_LIMIT 50    /* We try to keep pause times from exceeding  */
                           /* this by much. In milliseconds.             */
 
-# define BL_LIMIT (25*HBLKSIZE)
+# define BL_LIMIT GC_black_list_spacing
                           /* If we need a block of N bytes, and we have */
                           /* a block of N + BL_LIMIT bytes available,   */
                           /* and N > BL_LIMIT,                          */
@@ -447,7 +445,8 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
                PCR_Th_SetSigMask(&GC_old_sig_mask, NIL)
 # else
 #   if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
-       || defined(MSWIN32) || defined(MACOS) || defined(NO_SIGNALS)
+       || defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \
+       || defined(NO_SIGNALS)
                        /* Also useful for debugging.           */
        /* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
 #     define DISABLE_SIGNALS()
@@ -726,6 +725,11 @@ struct hblk {
 /* single load of a base register will do.     */
 /* Scalars that could easily appear to         */
 /* be pointers are also put here.              */
+/* The main fields should precede any          */
+/* conditionally included fields, so that      */
+/* gc_inl.h will work even if a different set  */
+/* of macros is defined when the client is     */
+/* compiled.                                   */
 
 struct _GC_arrays {
   word _heapsize;
@@ -735,19 +739,15 @@ struct _GC_arrays {
   word _words_allocd_before_gc;
                /* Number of words allocated before this        */
                /* collection cycle.                            */
-# ifdef GATHERSTATS
-    word _composite_in_use;
-               /* Number of words in accessible composite      */
-               /* objects.                                     */
-    word _atomic_in_use;
-               /* Number of words in accessible atomic         */
-               /* objects.                                     */
-# endif
   word _words_allocd;
        /* Number of words allocated during this collection cycle */
   word _words_wasted;
        /* Number of words wasted due to internal fragmentation  */
        /* in large objects allocated since last gc. Approximate.*/
+  word _words_finalized;
+       /* Approximate number of words in objects (and headers) */
+       /* That became ready for finalization in the last       */
+       /* collection.                                          */
   word _non_gc_bytes_at_gc;
        /* Number of explicitly managed bytes of storage        */
        /* at last collection.                                  */
@@ -757,17 +757,26 @@ struct _GC_arrays {
        
   ptr_t _objfreelist[MAXOBJSZ+1];
                          /* free list for objects */
-# ifdef MERGE_SIZES
-    unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)];
-       /* Number of words to allocate for a given allocation request in */
-       /* bytes.                                                        */
-# endif 
   ptr_t _aobjfreelist[MAXOBJSZ+1];
                          /* free list for atomic objs  */
 
   ptr_t _uobjfreelist[MAXOBJSZ+1];
                          /* uncollectable but traced objs      */
 
+# ifdef GATHERSTATS
+    word _composite_in_use;
+               /* Number of words in accessible composite      */
+               /* objects.                                     */
+    word _atomic_in_use;
+               /* Number of words in accessible atomic         */
+               /* objects.                                     */
+# endif
+# ifdef MERGE_SIZES
+    unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)];
+       /* Number of words to allocate for a given allocation request in */
+       /* bytes.                                                        */
+# endif 
+
 # ifdef STUBBORN_ALLOC
     ptr_t _sobjfreelist[MAXOBJSZ+1];
 # endif
@@ -877,6 +886,7 @@ extern 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_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_heapsize GC_arrays._heapsize
@@ -937,6 +947,13 @@ extern word GC_n_heap_sects;       /* Number of separately added heap      */
 extern word GC_n_heap_bases;   /* See GC_heap_bases.   */
 # endif
 
+extern word GC_total_black_listed;
+                       /* Number of bytes on stack blacklist.  */
+
+extern word GC_black_list_spacing;
+                       /* Average number of bytes between blacklisted  */
+                       /* blocks. Approximate.                         */
+
 extern char * GC_invalid_map;
                        /* Pointer to the nowhere valid hblk map */
                        /* Blocks pointing to this map are free. */
@@ -1104,6 +1121,10 @@ void GC_unpromote_black_lists();
                        /* Approximately undo the effect of the above.  */
                        /* This actually loses some information, but    */
                        /* only in a reasonably safe way.               */
+word GC_number_stack_black_listed(/*struct hblk *start, struct hblk *endp1 */);
+                       /* Return the number of (stack) blacklisted     */
+                       /* blocks in the range for statistical          */
+                       /* purposes.                                    */
                        
 ptr_t GC_scratch_alloc(/*bytes*/);
                                /* GC internal memory allocation for    */
@@ -1279,7 +1300,7 @@ void GC_dump();
 void GC_noop();
 
 /* Logging and diagnostic output:      */
-void GC_printf(/* format, a, b, c, d, e, f */);
+void GC_printf GC_PROTO((char * format, long, long, long, long, long, long));
                        /* A version of printf that doesn't allocate,   */
                        /* is restricted to long arguments, and         */
                        /* (unfortunately) doesn't use varargs for      */
diff --git a/gcc_support.c b/gcc_support.c
new file mode 100644 (file)
index 0000000..e8a7b82
--- /dev/null
@@ -0,0 +1,516 @@
+/***************************************************************************
+
+Interface between g++ and Boehm GC
+
+    Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+    OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to copy this code for any purpose,
+    provided the above notices are retained on all copies.
+
+    Last modified on Sun Jul 16 23:21:14 PDT 1995 by ellis
+
+This module provides runtime support for implementing the
+Ellis/Detlefs GC proposal, "Safe, Efficient Garbage Collection for
+C++", within g++, using its -fgc-keyword extension.  It defines
+versions of __builtin_new, __builtin_new_gc, __builtin_vec_new,
+__builtin_vec_new_gc, __builtin_delete, and __builtin_vec_delete that
+invoke the Bohem GC.  It also implements the WeakPointer.h interface.
+
+This module assumes the following configuration options of the Boehm GC:
+
+    -DALL_INTERIOR_POINTERS
+    -DDONT_ADD_BYTE_AT_END   
+
+This module adds its own required padding to the end of objects to
+support C/C++ "one-past-the-object" pointer semantics.
+
+****************************************************************************/
+
+#include <stddef.h>
+#include "gc.h"
+
+#if defined(__STDC__) 
+#   define PROTO( args ) args
+#else
+#    define PROTO( args ) ()
+#    endif
+
+#define BITSPERBYTE 8     
+    /* What's the portable way to do this? */
+
+
+typedef void (*vfp) PROTO(( void ));
+extern vfp __new_handler;
+extern void __default_new_handler PROTO(( void ));
+
+
+/* A destructor_proc is the compiler generated procedure representing a 
+C++ destructor.  The "flag" argument is a hidden argument following some
+compiler convention. */
+
+typedef (*destructor_proc) PROTO(( void* this, int flag ));
+
+
+/***************************************************************************
+
+A BI_header is the header the compiler adds to the front of
+new-allocated arrays of objects with destructors.  The header is
+padded out to a double, because that's what the compiler does to
+ensure proper alignment of array elements on some architectures.  
+
+int NUM_ARRAY_ELEMENTS (void* o)
+    returns the number of array elements for array object o.
+
+char* FIRST_ELEMENT_P (void* o)
+    returns the address of the first element of array object o.
+
+***************************************************************************/
+
+typedef struct BI_header {
+    int nelts;
+    char padding [sizeof( double ) - sizeof( int )]; 
+        /* Better way to do this? */
+} BI_header;
+
+#define NUM_ARRAY_ELEMENTS( o ) \
+  (((BI_header*) o)->nelts)
+
+#define FIRST_ELEMENT_P( o ) \
+  ((char*) o + sizeof( BI_header ))
+
+
+/***************************************************************************
+
+The __builtin_new routines add a descriptor word to the end of each
+object.   The descriptor serves two purposes.  
+
+First, the descriptor acts as padding, implementing C/C++ pointer
+semantics.  C and C++ allow a valid array pointer to be incremented
+one past the end of an object.  The extra padding ensures that the
+collector will recognize that such a pointer points to the object and
+not the next object in memory.
+
+Second, the descriptor stores three extra pieces of information,
+whether an object has a registered finalizer (destructor), whether it
+may have any weak pointers referencing it, and for collectible arrays,
+the element size of the array.  The element size is required for the
+array's finalizer to iterate through the elements of the array.  (An
+alternative design would have the compiler generate a finalizer
+procedure for each different array type.  But given the overhead of
+finalization, there isn't any efficiency to be gained by that.)
+
+The descriptor must be added to non-collectible as well as collectible
+objects, since the Ellis/Detlefs proposal allows "pointer to gc T" to
+be assigned to a "pointer to T", which could then be deleted.  Thus,
+__builtin_delete must determine at runtime whether an object is
+collectible, whether it has weak pointers referencing it, and whether
+it may have a finalizer that needs unregistering.  Though
+GC_REGISTER_FINALIZER doesn't care if you ask it to unregister a
+finalizer for an object that doesn't have one, it is a non-trivial
+procedure that does a hash look-up, etc.  The descriptor trades a
+little extra space for a significant increase in time on the fast path
+through delete.  (A similar argument applies to
+GC_UNREGISTER_DISAPPEARING_LINK).
+
+For non-array types, the space for the descriptor could be shrunk to a
+single byte for storing the "has finalizer" flag.  But this would save
+space only on arrays of char (whose size is not a multiple of the word
+size) and structs whose largest member is less than a word in size
+(very infrequent).  And it would require that programmers actually
+remember to call "delete[]" instead of "delete" (which they should,
+but there are probably lots of buggy programs out there).  For the
+moment, the space savings seems not worthwhile, especially considering
+that the Boehm GC is already quite space competitive with other
+malloc's.
+
+
+Given a pointer o to the base of an object:
+
+Descriptor* DESCRIPTOR (void* o) 
+     returns a pointer to the descriptor for o.
+
+The implementation of descriptors relies on the fact that the GC
+implementation allocates objects in units of the machine's natural
+word size (e.g. 32 bits on a SPARC, 64 bits on an Alpha).
+
+**************************************************************************/
+
+typedef struct Descriptor {
+    unsigned has_weak_pointers: 1;
+    unsigned has_finalizer: 1;
+    unsigned element_size: BITSPERBYTE * sizeof( unsigned ) - 2; 
+} Descriptor;
+
+#define DESCRIPTOR( o ) \
+  ((Descriptor*) ((char*)(o) + GC_size( o ) - sizeof( Descriptor )))
+
+
+/**************************************************************************
+
+Implementations of global operator new() and operator delete()
+
+***************************************************************************/
+
+
+void* __builtin_new( size ) 
+    size_t size;
+    /* 
+    For non-gc non-array types, the compiler generates calls to
+    __builtin_new, which allocates non-collected storage via
+    GC_MALLOC_UNCOLLECTABLE.  This ensures that the non-collected
+    storage will be part of the collector's root set, required by the
+    Ellis/Detlefs semantics. */
+{
+    vfp handler = __new_handler ? __new_handler : __default_new_handler;
+
+    while (1) {
+        void* o = GC_MALLOC_UNCOLLECTABLE( size + sizeof( Descriptor ) );
+        if (o != 0) return o;
+        (*handler) ();}}
+
+
+void* __builtin_vec_new( size ) 
+    size_t size;
+    /* 
+    For non-gc array types, the compiler generates calls to
+    __builtin_vec_new. */
+{
+    return __builtin_new( size );}
+
+
+void* __builtin_new_gc( size )
+    size_t size;
+    /* 
+    For gc non-array types, the compiler generates calls to
+    __builtin_new_gc, which allocates collected storage via
+    GC_MALLOC. */
+{
+    vfp handler = __new_handler ? __new_handler : __default_new_handler;
+
+    while (1) {
+        void* o = GC_MALLOC( size + sizeof( Descriptor ) );
+        if (o != 0) return o;
+        (*handler) ();}}
+
+
+void* __builtin_new_gc_a( size )
+    size_t size;
+    /* 
+    For non-pointer-containing gc non-array types, the compiler
+    generates calls to __builtin_new_gc_a, which allocates collected
+    storage via GC_MALLOC_ATOMIC. */
+{
+    vfp handler = __new_handler ? __new_handler : __default_new_handler;
+
+    while (1) {
+        void* o = GC_MALLOC_ATOMIC( size + sizeof( Descriptor ) );
+        if (o != 0) return o;
+        (*handler) ();}}
+
+
+void* __builtin_vec_new_gc( size )
+    size_t size;
+    /*
+    For gc array types, the compiler generates calls to
+    __builtin_vec_new_gc. */
+{
+    return __builtin_new_gc( size );}
+
+
+void* __builtin_vec_new_gc_a( size )
+    size_t size;
+    /*
+    For non-pointer-containing gc array types, the compiler generates
+    calls to __builtin_vec_new_gc_a. */
+{
+    return __builtin_new_gc_a( size );}
+
+
+static void call_destructor( o, data )
+    void* o;
+    void* data;
+    /* 
+    call_destructor is the GC finalizer proc registered for non-array
+    gc objects with destructors.  Its client data is the destructor
+    proc, which it calls with the magic integer 2, a special flag
+    obeying the compiler convention for destructors. */
+{
+    ((destructor_proc) data)( o, 2 );}
+
+
+void* __builtin_new_gc_dtor( o, d )
+    void* o;
+    destructor_proc d;
+    /* 
+    The compiler generates a call to __builtin_new_gc_dtor to register
+    the destructor "d" of a non-array gc object "o" as a GC finalizer.
+    The destructor is registered via
+    GC_REGISTER_FINALIZER_IGNORE_SELF, which causes the collector to
+    ignore pointers from the object to itself when determining when
+    the object can be finalized.  This is necessary due to the self
+    pointers used in the internal representation of multiply-inherited
+    objects. */
+{
+    Descriptor* desc = DESCRIPTOR( o );
+
+    GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_destructor, d, 0, 0 );
+    desc->has_finalizer = 1;}
+
+
+static void call_array_destructor( o, data )
+    void* o;
+    void* data;
+    /*
+    call_array_destructor is the GC finalizer proc registered for gc
+    array objects whose elements have destructors. Its client data is
+    the destructor proc.  It iterates through the elements of the
+    array in reverse order, calling the destructor on each. */
+{
+    int num = NUM_ARRAY_ELEMENTS( o );
+    Descriptor* desc = DESCRIPTOR( o );
+    size_t size = desc->element_size;
+    char* first_p = FIRST_ELEMENT_P( o );
+    char* p = first_p + (num - 1) * size;
+
+    if (num > 0) {
+        while (1) {
+            ((destructor_proc) data)( p, 2 );
+            if (p == first_p) break;
+            p -= size;}}}
+
+
+void* __builtin_vec_new_gc_dtor( first_elem, d, element_size )
+    void* first_elem;
+    destructor_proc d;
+    size_t element_size;
+    /* 
+    The compiler generates a call to __builtin_vec_new_gc_dtor to
+    register the destructor "d" of a gc array object as a GC
+    finalizer.  "first_elem" points to the first element of the array,
+    *not* the beginning of the object (this makes the generated call
+    to this function smaller).  The elements of the array are of size
+    "element_size".  The destructor is registered as in
+    _builtin_new_gc_dtor. */
+{
+    void* o = (char*) first_elem - sizeof( BI_header );
+    Descriptor* desc = DESCRIPTOR( o );
+
+    GC_REGISTER_FINALIZER_IGNORE_SELF( o, call_array_destructor, d, 0, 0 );
+    desc->element_size = element_size;
+    desc->has_finalizer = 1;}
+
+
+void __builtin_delete( o )
+    void* o;
+    /* 
+    The compiler generates calls to __builtin_delete for operator
+    delete().  The GC currently requires that any registered
+    finalizers be unregistered before explicitly freeing an object.
+    If the object has any weak pointers referencing it, we can't
+    actually free it now. */
+{
+  if (o != 0) { 
+      Descriptor* desc = DESCRIPTOR( o );
+      if (desc->has_finalizer) GC_REGISTER_FINALIZER( o, 0, 0, 0, 0 );
+      if (! desc->has_weak_pointers) GC_FREE( o );}}
+
+
+void __builtin_vec_delete( o )
+    void* o;
+    /* 
+    The compiler generates calls to __builitn_vec_delete for operator
+    delete[](). */
+{
+  __builtin_delete( o );}
+
+
+/**************************************************************************
+
+Implementations of the template class WeakPointer from WeakPointer.h
+
+***************************************************************************/
+
+typedef struct WeakPointer {
+    void* pointer; 
+} WeakPointer;
+
+
+void* _WeakPointer_New( t )
+    void* t;
+{
+    if (t == 0) {
+        return 0;}
+    else {
+        void* base = GC_base( t );
+        WeakPointer* wp = 
+            (WeakPointer*) GC_MALLOC_ATOMIC( sizeof( WeakPointer ) );
+        Descriptor* desc = DESCRIPTOR( base );
+
+        wp->pointer = t;
+        desc->has_weak_pointers = 1;
+        GC_general_register_disappearing_link( &wp->pointer, base );
+        return wp;}}
+
+
+static void* PointerWithLock( wp ) 
+    WeakPointer* wp;
+{
+    if (wp == 0 || wp->pointer == 0) {
+      return 0;}
+    else {
+        return (void*) wp->pointer;}}
+
+
+void* _WeakPointer_Pointer( wp )
+    WeakPointer* wp;
+{
+    return (void*) GC_call_with_alloc_lock( PointerWithLock, wp );}
+
+
+typedef struct EqualClosure {
+    WeakPointer* wp1;
+    WeakPointer* wp2;
+} EqualClosure;
+
+
+static void* EqualWithLock( ec )
+    EqualClosure* ec;
+{
+    if (ec->wp1 == 0 || ec->wp2 == 0) {
+        return (void*) (ec->wp1 == ec->wp2);}
+    else {
+      return (void*) (ec->wp1->pointer == ec->wp2->pointer);}}
+
+
+int _WeakPointer_Equal( wp1,  wp2 )
+    WeakPointer* wp1;
+    WeakPointer* wp2;
+{
+    EqualClosure ec;
+
+    ec.wp1 = wp1;
+    ec.wp2 = wp2;
+    return (int) GC_call_with_alloc_lock( EqualWithLock, &ec );}
+
+
+int _WeakPointer_Hash( wp )
+    WeakPointer* wp;
+{
+    return (int) _WeakPointer_Pointer( wp );}
+
+
+/**************************************************************************
+
+Implementations of the template class CleanUp from WeakPointer.h
+
+***************************************************************************/
+
+typedef struct Closure {
+    void (*c) PROTO(( void* d, void* t ));
+    ptrdiff_t t_offset; 
+    void* d;
+} Closure;
+
+
+static void _CleanUp_CallClosure( obj, data ) 
+    void* obj;
+    void* data;
+{
+    Closure* closure = (Closure*) data;
+    closure->c( closure->d, (char*) obj + closure->t_offset );}
+
+
+void _CleanUp_Set( t, c, d ) 
+    void* t;
+    void (*c) PROTO(( void* d, void* t ));
+    void* d;
+{
+    void* base = GC_base( t );
+    Descriptor* desc = DESCRIPTOR( t );
+
+    if (c == 0) {
+        GC_REGISTER_FINALIZER_IGNORE_SELF( base, 0, 0, 0, 0 );
+        desc->has_finalizer = 0;}
+    else {
+        Closure* closure = (Closure*) GC_MALLOC( sizeof( Closure ) );
+        closure->c = c;
+        closure->t_offset = (char*) t - (char*) base;
+        closure->d = d;
+        GC_REGISTER_FINALIZER_IGNORE_SELF( base, _CleanUp_CallClosure, 
+                                           closure, 0, 0 );
+        desc->has_finalizer = 1;}}
+
+
+void _CleanUp_Call( t ) 
+    void* t;
+{
+      /* ? Aren't we supposed to deactivate weak pointers to t too? 
+         Why? */
+    void* base = GC_base( t );
+    void* d;
+    GC_finalization_proc f;
+
+    GC_REGISTER_FINALIZER( base, 0, 0, &f, &d );
+    f( base, d );}
+
+
+typedef struct QueueElem {
+    void* o;
+    GC_finalization_proc f;
+    void* d;
+    struct QueueElem* next; 
+} QueueElem;
+
+
+void* _CleanUp_Queue_NewHead()
+{
+    return GC_MALLOC( sizeof( QueueElem ) );}
+    
+     
+static void _CleanUp_Queue_Enqueue( obj, data )
+    void* obj; 
+    void* data;
+{
+    QueueElem* q = (QueueElem*) data;
+    QueueElem* head = q->next;
+
+    q->o = obj;
+    q->next = head->next;
+    head->next = q;}
+    
+    
+void _CleanUp_Queue_Set( h, t ) 
+    void* h;
+    void* t;
+{
+    QueueElem* head = (QueueElem*) h;
+    void* base = GC_base( t );
+    void* d;
+    GC_finalization_proc f;
+    QueueElem* q = (QueueElem*) GC_MALLOC( sizeof( QueueElem ) );
+     
+    GC_REGISTER_FINALIZER( base, _CleanUp_Queue_Enqueue, q, &f, &d );
+    q->f = f;
+    q->d = d;
+    q->next = head;}
+    
+
+int _CleanUp_Queue_Call( h ) 
+    void* h;
+{
+    QueueElem* head = (QueueElem*) h;
+    QueueElem* q = head->next;
+
+    if (q == 0) {
+        return 0;}
+    else {
+        head->next = q->next;
+        q->next = 0;
+        if (q->f != 0) q->f( q->o, q->d );
+        return 1;}}
+
+
+
index 8386962..df21056 100644 (file)
@@ -81,6 +81,8 @@ CORD CORD_cat(CORD x, CORD y);
 /* Concatenate a cord and a C string with known length.  Except for the        */
 /* empty string case, this is a special case of CORD_cat.  Since the   */
 /* length is known, it can be faster.                                  */
+/* The string y is shared with the resulting CORD.  Hence it should    */
+/* not be altered by the caller.                                       */
 CORD CORD_cat_char_star(CORD x, const char * y, size_t leny);
 
 /* Compute the length of a cord */
@@ -152,7 +154,7 @@ int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data);
 /* described below.  Also note that                                    */
 /* CORD_pos_fetch, CORD_next and CORD_prev have both macro and function        */
 /* definitions.  The former may evaluate their argument more than once. */
-# include "cord_pos.h"
+# include "private/cord_pos.h"
 
 /*
        Visible definitions from above:
index c9fb14f..ab7944e 100644 (file)
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, January 28, 1995 3:59 pm PST */
+/* Boehm, October 9, 1995 1:14 pm PDT */
 
 /*
  * Note that this defines a large number of tuning hooks, which can
 
 # define _GC_H
 
+# if defined(__STDC__) || defined(__cplusplus)
+#   define GC_PROTO(args) args
+    typedef void * GC_PTR;
+# else
+#   define GC_PROTO(args) ()
+    typedef char * GC_PTR;
+#  endif
+
 # ifdef __cplusplus
     extern "C" {
 # endif
@@ -100,23 +108,10 @@ extern GC_word GC_free_space_divisor;
  * collectable.  GC_malloc_uncollectable and GC_free called on the resulting
  * object implicitly update GC_non_gc_bytes appropriately.
  */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void * GC_malloc(size_t size_in_bytes);
-  extern void * GC_malloc_atomic(size_t size_in_bytes);
-  extern void * GC_malloc_uncollectable(size_t size_in_bytes);
-  extern void * GC_malloc_stubborn(size_t size_in_bytes);
-# else
-  extern char * GC_malloc(/* size_in_bytes */);
-  extern char * GC_malloc_atomic(/* size_in_bytes */);
-  extern char * GC_malloc_uncollectable(/* size_in_bytes */);
-  extern char * GC_malloc_stubborn(/* size_in_bytes */);
-# endif
-
-#if defined(__STDC__) && !defined(__cplusplus)
-# define NO_PARAMS void
-#else
-# define NO_PARAMS
-#endif
+extern GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
+extern GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
 
 /* Explicitly deallocate an object.  Dangerous if used incorrectly.     */
 /* Requires a pointer to the base of an object.                                */
@@ -124,11 +119,7 @@ extern GC_word GC_free_space_divisor;
 /* An object should not be enable for finalization when it is          */
 /* explicitly deallocated.                                             */
 /* GC_free(0) is a no-op, as required by ANSI C for free.              */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void GC_free(void * object_addr);
-# else
-  extern void GC_free(/* object_addr */);
-# endif
+extern void GC_free GC_PROTO((GC_PTR object_addr));
 
 /*
  * Stubborn objects may be changed only if the collector is explicitly informed.
@@ -145,27 +136,19 @@ extern GC_word GC_free_space_divisor;
  * do so.  The same applies to dropping stubborn objects that are still
  * changeable.
  */
-void GC_change_stubborn(/* p */);
-void GC_end_stubborn_change(/* p */);
+extern void GC_change_stubborn GC_PROTO((GC_PTR));
+extern void GC_end_stubborn_change GC_PROTO((GC_PTR));
 
 /* Return a pointer to the base (lowest address) of an object given    */
 /* a pointer to a location within the object.                          */
 /* Return 0 if displaced_pointer doesn't point to within a valid       */
 /* object.                                                             */
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_base(void * displaced_pointer);
-# else
-  char * GC_base(/* char * displaced_pointer */);
-# endif
+extern GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
 
 /* Given a pointer to the base of an object, return its size in bytes. */
 /* The returned size may be slightly larger than what was originally   */
 /* requested.                                                          */
-# if defined(__STDC__) || defined(__cplusplus)
-  size_t GC_size(void * object_addr);
-# else
-  size_t GC_size(/* char * object_addr */);
-# endif
+extern size_t GC_size GC_PROTO((GC_PTR object_addr));
 
 /* For compatibility with C library.  This is occasionally faster than */
 /* a malloc followed by a bcopy.  But if you rely on that, either here */
@@ -175,27 +158,24 @@ void GC_end_stubborn_change(/* p */);
 /* 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.                       */
-# if defined(__STDC__) || defined(__cplusplus)
-    extern void * GC_realloc(void * old_object, size_t new_size_in_bytes);
-# else
-    extern char * GC_realloc(/* old_object, new_size_in_bytes */);
-# endif
-
-
+extern 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.  */
-extern int GC_expand_hp(/* number_of_bytes */);
+extern int GC_expand_hp GC_PROTO((size_t number_of_bytes));
 
 /* Limit the heap size to n bytes.  Useful when you're debugging,      */
 /* especially on systems that don't handle running out of memory well. */
 /* n == 0 ==> unbounded.  This is the default.                         */
-extern void GC_set_max_heap_size(/* n */);
+extern void GC_set_max_heap_size GC_PROTO((GC_word n));
 
 /* Clear the set of root segments.  Wizards only. */
-extern void GC_clear_roots(NO_PARAMS);
+extern void GC_clear_roots GC_PROTO((void));
 
 /* Add a root segment.  Wizards only. */
-extern void GC_add_roots(/* low_address, high_address_plus_1 */);
+extern void GC_add_roots GC_PROTO((char * low_address,
+                                  char * high_address_plus_1));
 
 /* Add a displacement to the set of those considered valid by the      */
 /* collector.  GC_register_displacement(n) means that if p was returned */
@@ -209,14 +189,14 @@ extern void GC_add_roots(/* low_address, high_address_plus_1 */);
 /* retention.                                                          */
 /* This is a no-op if the collector was compiled with recognition of   */
 /* arbitrary interior pointers enabled, which is now the default.      */
-void GC_register_displacement(/* GC_word n */);
+void GC_register_displacement GC_PROTO((GC_word n));
 
 /* The following version should be used if any debugging allocation is */
 /* being done.                                                         */
-void GC_debug_register_displacement(/* GC_word n */);
+void GC_debug_register_displacement GC_PROTO((GC_word n));
 
 /* Explicitly trigger a full, world-stop collection.   */
-void GC_gcollect(NO_PARAMS);
+void GC_gcollect GC_PROTO((void));
 
 /* Trigger a full world-stopped collection.  Abort the collection if   */
 /* and when stop_func returns a nonzero value.  Stop_func will be      */
@@ -226,20 +206,16 @@ void GC_gcollect(NO_PARAMS);
 /* than normal pause times for incremental collection.  However,       */
 /* aborted collections do no useful work; the next collection needs    */
 /* to start from the beginning.                                                */
-typedef int (* GC_stop_func)(NO_PARAMS);
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_try_to_collect(GC_stop_func stop_func);
-# else
-    int GC_try_to_collect(/* GC_stop_func stop_func */);
-# endif
+typedef int (* GC_stop_func) GC_PROTO((void));
+int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
 
 /* Return the number of bytes in the heap.  Excludes collector private */
 /* data structures.  Includes empty blocks and fragmentation loss.     */
 /* Includes some pages that were allocated but never written.          */
-size_t GC_get_heap_size(NO_PARAMS);
+size_t GC_get_heap_size GC_PROTO((void));
 
 /* Return the number of bytes allocated since the last collection.     */
-size_t GC_get_bytes_since_gc(NO_PARAMS);
+size_t GC_get_bytes_since_gc GC_PROTO((void));
 
 /* Enable incremental/generational collection. */
 /* Not advisable unless dirty bits are                 */
@@ -247,7 +223,7 @@ size_t GC_get_bytes_since_gc(NO_PARAMS);
 /* pointerfree(atomic) or immutable.           */
 /* Don't use in leak finding mode.             */
 /* Ignored if GC_dont_gc is true.              */
-void GC_enable_incremental(NO_PARAMS);
+void GC_enable_incremental GC_PROTO((void));
 
 /* Perform some garbage collection work, if appropriate.       */
 /* Return 0 if there is no more work to be done.               */
@@ -256,7 +232,7 @@ void GC_enable_incremental(NO_PARAMS);
 /* progress requires it, e.g. if incremental collection is     */
 /* disabled.  It is reasonable to call this in a wait loop     */
 /* until it returns 0.                                         */
-int GC_collect_a_little(NO_PARAMS);
+int GC_collect_a_little GC_PROTO((void));
 
 /* Allocate an object of size lb bytes.  The client guarantees that    */
 /* as long as the object is live, it will be referenced by a pointer   */
@@ -272,46 +248,26 @@ int GC_collect_a_little(NO_PARAMS);
 /* for arrays likely to be larger than 100K or so.  For other systems, */
 /* or if the collector is not configured to recognize all interior     */
 /* pointers, the threshold is normally much higher.                    */
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_ignore_off_page(size_t lb);
-# else
-  char * GC_malloc_ignore_off_page(/* size_t lb */);
-# endif
-# if defined(__STDC__) || defined(__cplusplus)
-  void * GC_malloc_atomic_ignore_off_page(size_t lb);
-# else
-  char * GC_malloc_atomic_ignore_off_page(/* size_t lb */);
-# endif
+extern GC_PTR GC_malloc_ignore_off_page GC_PROTO((size_t lb));
+extern GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
 
 /* Debugging (annotated) allocation.  GC_gcollect will check           */
 /* objects allocated in this way for overwrites, etc.                  */
-# if defined(__STDC__) || defined(__cplusplus)
-  extern void * GC_debug_malloc(size_t size_in_bytes,
-                               char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_atomic(size_t size_in_bytes,
-                                      char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_uncollectable(size_t size_in_bytes,
-                                          char * descr_string, int descr_int);
-  extern void * GC_debug_malloc_stubborn(size_t size_in_bytes,
-                                        char * descr_string, int descr_int);
-  extern void GC_debug_free(void * object_addr);
-  extern void * GC_debug_realloc(void * old_object,
-                                size_t new_size_in_bytes,
-                                char * descr_string, int descr_int);
-# else
-  extern char * GC_debug_malloc(/* size_in_bytes, descr_string, descr_int */);
-  extern char * GC_debug_malloc_atomic(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern char * GC_debug_malloc_uncollectable(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern char * GC_debug_malloc_stubborn(/* size_in_bytes, descr_string,
-                                         descr_int */);
-  extern void GC_debug_free(/* object_addr */);
-  extern char * GC_debug_realloc(/* old_object, new_size_in_bytes,
-                                   descr_string, descr_int */);
-# endif
-void GC_debug_change_stubborn(/* p */);
-void GC_debug_end_stubborn_change(/* p */);
+extern GC_PTR GC_debug_malloc
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_atomic
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_uncollectable
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern GC_PTR GC_debug_malloc_stubborn
+       GC_PROTO((size_t size_in_bytes, char * descr_string, int descr_int));
+extern void GC_debug_free GC_PROTO((GC_PTR object_addr));
+extern GC_PTR GC_debug_realloc
+       GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
+                 char * descr_string, int descr_int));
+                                
+void GC_debug_change_stubborn GC_PROTO((GC_PTR));
+void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
 # ifdef GC_DEBUG
 #   define GC_MALLOC(sz) GC_debug_malloc(sz, __FILE__, __LINE__)
 #   define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, __FILE__, __LINE__)
@@ -367,21 +323,12 @@ void GC_debug_end_stubborn_change(/* p */);
 /* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes,             */
 /* Christian Jacobi, and Russ Atkinson.  It's not perfect, and         */
 /* probably nobody else agrees with it.            Hans-J. Boehm  3/13/92      */
-# if defined(__STDC__) || defined(__cplusplus)
-  typedef void (*GC_finalization_proc)(void * obj, void * client_data);
-# else
-  typedef void (*GC_finalization_proc)(/* void * obj, void * client_data */);
-# endif
+typedef void (*GC_finalization_proc)
+       GC_PROTO((GC_PTR obj, GC_PTR client_data));
 
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_register_finalizer(void * obj,
-                              GC_finalization_proc fn, void * cd,
-                              GC_finalization_proc *ofn, void ** ocd);
-# else 
-    void GC_register_finalizer(/* void * obj,
-                                 GC_finalization_proc fn, void * cd,
-                                 GC_finalization_proc *ofn, void ** ocd */);
-# endif
+extern void GC_register_finalizer
+       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+                 GC_finalization_proc *ofn, GC_PTR *ocd));
        /* When obj is no longer accessible, invoke             */
        /* (*fn)(obj, cd).  If a and b are inaccessible, and    */
        /* a points to b (after disappearing links have been    */
@@ -421,15 +368,9 @@ void GC_debug_end_stubborn_change(/* p */);
 /* but it's unavoidable for C++, since the compiler may                */
 /* silently introduce these.  It's also benign in that specific        */
 /* case.                                                       */
-# if defined(__STDC__) || defined(__cplusplus)
-    void GC_register_finalizer_ignore_self(void * obj,
-                              GC_finalization_proc fn, void * cd,
-                              GC_finalization_proc *ofn, void ** ocd);
-# else 
-    void GC_register_finalizer_ignore_self(/* void * obj,
-                                 GC_finalization_proc fn, void * cd,
-                                 GC_finalization_proc *ofn, void ** ocd */);
-# endif
+extern void GC_register_finalizer_ignore_self
+       GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+                 GC_finalization_proc *ofn, GC_PTR *ocd));
 
 /* The following routine may be used to break cycles between   */
 /* finalizable objects, thus causing cyclic finalizable                */
@@ -438,12 +379,7 @@ void GC_debug_end_stubborn_change(/* p */);
 /* where p is a pointer that is not followed by finalization   */
 /* code, and should not be considered in determining           */
 /* finalization order.                                         */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_register_disappearing_link(void ** /* link */);
-# else
-    int GC_register_disappearing_link(/* void ** link */);
-# endif
-
+extern int GC_register_disappearing_link GC_PROTO((GC_PTR * /* link */));
        /* Link should point to a field of a heap allocated     */
        /* object obj.  *link will be cleared when obj is       */
        /* found to be inaccessible.  This happens BEFORE any   */
@@ -462,11 +398,9 @@ void GC_debug_end_stubborn_change(/* p */);
        /* Returns 1 if link was already registered, 0          */
        /* otherwise.                                           */
        /* Only exists for backward compatibility.  See below:  */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_general_register_disappearing_link(void ** /* link */, void * obj);
-# else
-    int GC_general_register_disappearing_link(/* void ** link, void * obj */);
-# endif
+       
+extern int GC_general_register_disappearing_link
+       GC_PROTO((GC_PTR * /* link */, GC_PTR obj));
        /* A slight generalization of the above. *link is       */
        /* cleared when obj first becomes inaccessible.  This   */
        /* can be used to implement weak pointers easily and    */
@@ -484,34 +418,20 @@ void GC_debug_end_stubborn_change(/* p */);
        /* the object containing link.  Explicitly deallocating */
        /* obj may or may not cause link to eventually be       */
        /* cleared.                                             */
-# if defined(__STDC__) || defined(__cplusplus)
-    int GC_unregister_disappearing_link(void ** /* link */);
-# else
-    int GC_unregister_disappearing_link(/* void ** link */);
-# endif
+extern int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
        /* Returns 0 if link was not actually registered.       */
        /* Undoes a registration by either of the above two     */
        /* routines.                                            */
 
 /* Auxiliary fns to make finalization work correctly with displaced    */
 /* pointers introduced by the debugging allocators.                    */
-# if defined(__STDC__) || defined(__cplusplus)
-    void * GC_make_closure(GC_finalization_proc fn, void * data);
-    void GC_debug_invoke_finalizer(void * obj, void * data);
-# else
-    char * GC_make_closure(/* GC_finalization_proc fn, char * data */);
-    void GC_debug_invoke_finalizer(/* void * obj, void * data */);
-# endif
+extern GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
+extern void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
 
 /* GC_set_warn_proc can be used to redirect or filter warning messages.        */
-# if defined(__STDC__) || defined(__cplusplus)
-    typedef void (*GC_warn_proc)(char *msg, GC_word arg);
-    GC_warn_proc GC_set_warn_proc(GC_warn_proc p);
+typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
+extern GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
     /* Returns old warning procedure.  */
-# else
-    typedef void (*GC_warn_proc)(/* char *msg, GC_word arg */);
-    GC_warn_proc GC_set_warn_proc(/* GC_warn_proc p */);
-# endif
        
 /* The following is intended to be used by a higher level      */
 /* (e.g. cedar-like) finalization facility.  It is expected    */
@@ -521,37 +441,32 @@ void GC_debug_end_stubborn_change(/* p */);
 /* Note that putting pointers in atomic objects or in          */
 /* nonpointer slots of "typed" objects is equivalent to        */
 /* disguising them in this way, and may have other advantages. */
-# ifdef I_HIDE_POINTERS
-#   if defined(__STDC__) || defined(__cplusplus)
-#     define HIDE_POINTER(p) (~(size_t)(p))
-#     define REVEAL_POINTER(p) ((void *)(HIDE_POINTER(p)))
-#   else
-#     define HIDE_POINTER(p) (~(unsigned long)(p))
-#     define REVEAL_POINTER(p) ((char *)(HIDE_POINTER(p)))
-#   endif
+# if defined(I_HIDE_POINTERS) || defined(GC_I_HIDE_POINTERS)
+    typedef GC_word GC_hidden_pointer;
+#   define HIDE_POINTER(p) (~(GC_hidden_pointer)(p))
+#   define REVEAL_POINTER(p) ((GC_PTR)(HIDE_POINTER(p)))
     /* Converting a hidden pointer to a real pointer requires verifying        */
     /* that the object still exists.  This involves acquiring the      */
     /* allocator lock to avoid a race with the collector.              */
+# endif /* I_HIDE_POINTERS */
 
-#   if defined(__STDC__) || defined(__cplusplus)
-        typedef void * (*GC_fn_type)();
-        void * GC_call_with_alloc_lock(GC_fn_type fn, void * client_data);
-#   else
-        typedef char * (*GC_fn_type)();
-        char * GC_call_with_alloc_lock(/* GC_fn_type fn, char * client_data */);
-#   endif
-# endif
+typedef GC_PTR (*GC_fn_type) GC_PROTO((GC_PTR client_data));
+extern GC_PTR GC_call_with_alloc_lock
+               GC_PROTO((GC_fn_type fn, GC_PTR client_data));
 
 /* Check that p and q point to the same object.                */
 /* Fail conspicuously if they don't.                           */
 /* Returns the first argument.                                 */
 /* Succeeds if neither p nor q points to the heap.             */
 /* May succeed if both p and q point to between heap objects.  */
-#ifdef __STDC__
-  void * GC_same_obj(register void *p, register void *q);
-#else
-  char * GC_same_obj(/* char * p, char * q */);
-#endif
+extern GC_PTR GC_same_obj GC_PROTO((GC_PTR p, GC_PTR q));
+
+/* Checked pointer pre- and post- increment operations.  Note that     */
+/* the second argument is in units of bytes, not multiples of the      */
+/* object size.  This should either be invoked from a macro, or the    */
+/* call should be automatically generated.                             */
+extern GC_PTR GC_pre_incr GC_PROTO((GC_PTR *p, size_t how_much));
+extern GC_PTR GC_post_incr GC_PROTO((GC_PTR *p, size_t how_much));
 
 /* Check that p is visible                                             */
 /* to the collector as a possibly pointer containing location.         */
@@ -561,31 +476,31 @@ void GC_debug_end_stubborn_change(/* p */);
 /* untyped allocations.  The idea is that it should be possible, though        */
 /* slow, to add such a call to all indirect pointer stores.)           */
 /* Currently useless for multithreaded worlds.                         */
-#ifdef __STDC__
-  void * GC_is_visible(void *p);
-#else
-  char *GC_is_visible(/* char * p */);
-#endif
+extern GC_PTR GC_is_visible GC_PROTO((GC_PTR p));
 
 /* Check that if p is a pointer to a heap page, then it points to      */
 /* a valid displacement within a heap object.                          */
 /* Fail conspicuously if this property does not hold.                  */
 /* Uninteresting with ALL_INTERIOR_POINTERS.                           */
 /* Always returns its argument.                                                */
-#ifdef __STDC__
-  void * GC_is_valid_displacement(void *p);
-#else
-  char *GC_is_valid_displacement(/* char * p */);
-#endif
+extern GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR        p));
 
 /* Safer, but slow, pointer addition.  Probably useful mainly with     */
 /* a preprocessor.  Useful only for heap pointers.                     */
 #ifdef GC_DEBUG
 #   define GC_PTR_ADD3(x, n, type_of_result) \
        ((type_of_result)GC_same_obj((x)+(n), (x)))
+#   define GC_PRE_INCR3(x, n, type_of_result) \
+       ((type_of_result)GC_pre_incr(&(x), (n)*sizeof(*x))
+#   define GC_POST_INCR2(x, type_of_result) \
+       ((type_of_result)GC_post_incr(&(x), sizeof(*x))
 #   ifdef __GNUC__
 #       define GC_PTR_ADD(x, n) \
-           ((typeof(x))GC_same_obj((x)+(n), (x)))
+           GC_PTR_ADD3(x, n, typeof(x))
+#   define GC_PRE_INCR(x, n) \
+           GC_PRE_INCR3(x, n, typeof(x))
+#   define GC_POST_INCR(x, n) \
+           GC_POST_INCR3(x, typeof(x))
 #   else
        /* We can't do this right without typeof, which ANSI    */
        /* decided was not sufficiently useful.  Repeatedly     */
@@ -596,6 +511,10 @@ void GC_debug_end_stubborn_change(/* p */);
 #else  /* !GC_DEBUG */
 #   define GC_PTR_ADD3(x, n, type_of_result) ((x)+(n))
 #   define GC_PTR_ADD(x, n) ((x)+(n))
+#   define GC_PRE_INCR3(x, n, type_of_result) ((x) += (n))
+#   define GC_PRE_INCR(x, n) ((x) += (n))
+#   define GC_POST_INCR2(x, n, type_of_result) ((x)++)
+#   define GC_POST_INCR(x, n) ((x)++)
 #endif
 
 /* Safer assignment of a pointer to a nonstack location.       */
@@ -638,8 +557,8 @@ void GC_debug_end_stubborn_change(/* p */);
 /* 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.  */
-void * GC_malloc_many(size_t lb);
-#define GC_NEXT(p) (*(void **)(p))     /* Retrieve the next element    */
+GC_PTR GC_malloc_many(size_t lb);
+#define GC_NEXT(p) (*(GC_PTR *)(p))    /* Retrieve the next element    */
                                        /* in returned list.            */
 
 #endif /* SOLARIS_THREADS */
diff --git a/include/gc_c++.h b/include/gc_c++.h
deleted file mode 100644 (file)
index 8e842aa..0000000
+++ /dev/null
@@ -1 +0,0 @@
-# include "gc_cpp.h"
index 14eccf3..812bb65 100644 (file)
@@ -16,7 +16,7 @@ the code was modified is included with the above copyright notice.
 C++ Interface to the Boehm Collector
 
     John R. Ellis and Jesse Hull 
-    Last modified on Wed Jan  4 16:30:20 PST 1995 by ellis
+    Last modified on Mon Jul 24 15:43:42 PDT 1995 by ellis
 
 This interface provides access to the Boehm collector.  It provides
 basic facilities similar to those described in "Safe, Efficient
@@ -34,7 +34,7 @@ Objects allocated with the built-in "::operator new" are uncollectable.
 
 Objects derived from class "gc" are collectable.  For example:
 
-    class A: gc {...};
+    class A: public gc {...};
     A* a = new A;       // a is collectable. 
 
 Collectable instances of non-class types can be allocated using the GC
@@ -46,7 +46,7 @@ placement:
 Uncollectable instances of classes derived from "gc" can be allocated
 using the NoGC placement:
 
-    class A: gc {...};
+    class A: public gc {...};
     A* a = new (NoGC) A;   // a is uncollectable.
 
 Both uncollectable and collectable objects can be explicitly deleted
@@ -87,35 +87,42 @@ Cautions:
 add -DOPERATOR_NEW_ARRAY to the Makefile.
 
 If your compiler doesn't support "operator new[]", beware that an
-array of type T, where T is derived from "gc", will by default be
-allocated as an uncollectable object.  Use the explicit GC placement
-to make the array collectable.  For example:
+array of type T, where T is derived from "gc", may or may not be
+allocated as a collectable object (it depends on the compiler).  Use
+the explicit GC placement to make the array collectable.  For example:
 
-    class A: gc {...};
-    A* a1 = new A[ 10 ];        // uncollectable
+    class A: public gc {...};
+    A* a1 = new A[ 10 ];        // collectable or uncollectable?
     A* a2 = new (GC) A[ 10 ];   // collectable
 
-3. Arrays of objects derived from "gc_cleanup" do not have default
-clean-up functions.  For example:
+3. The destructors of collectable arrays of objects derived from
+"gc_cleanup" will not be invoked properly.  For example:
 
-    class A: gc_cleanup {...};
-    A* a = new (GC) A[ 10 ];
+    class A: public gc_cleanup {...};
+    A* a = new (GC) A[ 10 ];    // destructors not invoked correctly
 
-The elements of "a" will not have their destructors invoked when the
-collector frees "a".  You must supply an explicit clean-up function
-for that to occur.
+Typically, only the destructor for the first element of the array will
+be invoked when the array is garbage-collected.  To get all the
+destructors of any array executed, you must supply an explicit
+clean-up function:
+
+    A* a = new (GC, MyCleanUp) A[ 10 ];
+
+(Implementing clean-up of arrays correctly, portably, and in a way
+that preserves the correct exception semantics requires a language
+extension, e.g. the "gc" keyword.)
 
 4. Compiler bugs:
 
-    Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
-    destructors of classes derived from gc_cleanup won't be invoked.
-    You'll have to explicitly register a clean-up function with
-    new-placement syntax.
+* Solaris 2's CC (SC3.0) doesn't implement t->~T() correctly, so the
+destructors of classes derived from gc_cleanup won't be invoked.
+You'll have to explicitly register a clean-up function with
+new-placement syntax.
 
-    Evidently cfront 3.0 does not allow destructors to be explicitly
-    invoked using the ANSI-conforming syntax t->~T().  If you're using
-    cfront 3.0, you'll have to comment out the class gc_cleanup, which
-    uses explicit invocation.
+* Evidently cfront 3.0 does not allow destructors to be explicitly
+invoked using the ANSI-conforming syntax t->~T().  If you're using
+cfront 3.0, you'll have to comment out the class gc_cleanup, which
+uses explicit invocation.
 
 ****************************************************************************/
 
@@ -125,7 +132,8 @@ for that to occur.
 #define _cdecl
 #endif
 
-#if __BORLANDC__ >= 0x450 && !defined(OPERATOR_NEW_ARRAY)
+#if ! defined( OPERATOR_NEW_ARRAY ) \
+    && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6))
 #   define OPERATOR_NEW_ARRAY
 #endif
 
@@ -232,10 +240,15 @@ inline void gc_cleanup::cleanup( void* obj, void* displ ) {
     ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
 
 inline gc_cleanup::gc_cleanup() {
+    GC_finalization_proc oldProc;
+    void* oldData;
     void* base = GC_base( (void *) this );
-    if (0 != base) {
-        GC_REGISTER_FINALIZER_IGNORE_SELF( 
-            base, cleanup, (void*) ((char*) this - (char*) base), 0, 0 );}}
+    if (0 == base) return;
+    GC_REGISTER_FINALIZER_IGNORE_SELF( 
+        base, cleanup, (void*) ((char*) this - (char*) base), 
+        &oldProc, &oldData );
+    if (0 != oldProc) {
+        GC_REGISTER_FINALIZER_IGNORE_SELF( base, oldProc, oldData, 0, 0 );}}
 
 inline void* operator new( 
     size_t size, 
index 1f9a9a0..700843b 100644 (file)
@@ -1,6 +1,6 @@
 /* 
  * 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.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, May 19, 1994 2:12 pm PDT */
+/* Boehm, October 3, 1995 2:07 pm PDT */
  
 # ifndef GC_PRIVATE_H
-#   include "gc_priv.h"
+#   include "private/gc_priv.h"
 # endif
 
+/* USE OF THIS FILE IS NOT RECOMMENDED unless the collector has been   */
+/* compiled without -DALL_INTERIOR_POINTERS or with                    */
+/* -DDONT_ADD_BYTE_AT_END, or the specified size includes a pointerfree        */
+/* word at the end.  In the standard collector configuration,          */
+/* the final word of each object may not be scanned.                   */
+/* This is most useful for compilers that generate C.                  */
+/* Manual use is hereby discouraged.                                   */
+
 /* Allocate n words (NOT BYTES).  X is made to point to the result.    */
 /* It is assumed that n < MAXOBJSZ, and                                        */
 /* that n > 0.  On machines requiring double word alignment of some    */
@@ -46,7 +54,7 @@
         obj_link(op) = 0;      \
         GC_words_allocd += (n);        \
         FASTUNLOCK();  \
-        (result) = (extern_ptr_t) op;  \
+        (result) = (GC_PTR) op;        \
     }  \
 }
 
@@ -68,7 +76,7 @@
         obj_link(op) = 0;      \
         GC_words_allocd += (n);        \
         FASTUNLOCK();  \
-        (result) = (extern_ptr_t) op;  \
+        (result) = (GC_PTR) op;        \
     }  \
 }
 
@@ -91,5 +99,5 @@
     } \
     ((word *)op)[0] = (word)(first);   \
     ((word *)op)[1] = (word)(second);  \
-    (result) = (extern_ptr_t) op;      \
+    (result) = (GC_PTR) op;    \
 }
diff --git a/include/private/config.h b/include/private/config.h
new file mode 100644 (file)
index 0000000..62492c3
--- /dev/null
@@ -0,0 +1,687 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, October 3, 1995 6:39 pm PDT */
+#ifndef CONFIG_H
+
+# define CONFIG_H
+
+/* Machine dependent parameters.  Some tuning parameters can be found  */
+/* near the top of gc_private.h.                                       */
+
+/* Machine specific parts contributed by various people.  See README file. */
+
+/* Determine the machine type: */
+# if defined(sun) && defined(mc68000)
+#    define M68K
+#    define SUNOS4
+#    define mach_type_known
+# endif
+# if defined(hp9000s300)
+#    define M68K
+#    define HP
+#    define mach_type_known
+# endif
+# if defined(__NetBSD__) && defined(m68k)
+#    define M68K
+#    define NETBSD
+#    define mach_type_known
+# endif
+# if defined(vax)
+#    define VAX
+#    ifdef ultrix
+#      define ULTRIX
+#    else
+#      define BSD
+#    endif
+#    define mach_type_known
+# endif
+# if defined(mips) || defined(__mips)
+#    define MIPS
+#    if defined(ultrix) || defined(__ultrix)
+#      define ULTRIX
+#    else
+#      if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__)
+#        define IRIX5
+#      else
+#        define RISCOS  /* or IRIX 4.X */
+#      endif
+#    endif
+#    define mach_type_known
+# endif
+# if defined(sequent) && defined(i386)
+#    define I386
+#    define SEQUENT
+#    define mach_type_known
+# endif
+# if defined(sun) && defined(i386)
+#    define I386
+#    define SUNOS5
+#    define mach_type_known
+# endif
+# if (defined(__OS2__) || defined(__EMX__)) && defined(__32BIT__)
+#    define I386
+#    define OS2
+#    define mach_type_known
+# endif
+# if defined(ibm032)
+#   define RT
+#   define mach_type_known
+# endif
+# if defined(sun) && (defined(sparc) || defined(__sparc))
+#   define SPARC
+    /* Test for SunOS 5.x */
+#     include <errno.h>
+#     ifdef ECHRNG
+#       define SUNOS5
+#     else
+#      define SUNOS4
+#     endif
+#   define mach_type_known
+# endif
+# if defined(sparc) && defined(unix) && !defined(sun)
+#   define SPARC
+#   define DRSNX
+#   define mach_type_known
+# endif
+# if defined(_IBMR2)
+#   define RS6000
+#   define mach_type_known
+# endif
+# if defined(_M_XENIX) && defined(_M_SYSV) && defined(_M_I386)
+       /* The above test may need refinement   */
+#   define I386
+#   define SCO
+#   define mach_type_known
+# endif
+# if defined(_AUX_SOURCE)
+#   define M68K
+#   define SYSV
+#   define mach_type_known
+# endif
+# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1)
+#   define HP_PA
+#   define mach_type_known
+# endif
+# if defined(linux) && defined(i386)
+#    define I386
+#    define LINUX
+#    define mach_type_known
+# endif
+# if defined(__alpha)
+#   define ALPHA
+#   define mach_type_known
+# endif
+# if defined(_AMIGA)
+#   define M68K
+#   define AMIGA
+#   define mach_type_known
+# endif
+# if defined(THINK_C) || defined(__MWERKS__) && !defined(__powerc)
+#   define M68K
+#   define MACOS
+#   define mach_type_known
+# endif
+# if defined(__MWERKS__) && defined(__powerc)
+#   define POWERPC
+#   define MACOS
+#   define mach_type_known
+# endif
+# if defined(NeXT) && defined(mc68000)
+#   define M68K
+#   define NEXT
+#   define mach_type_known
+# endif
+# if defined(NeXT) && defined(i386)
+#   define I386
+#   define NEXT
+#   define mach_type_known
+# endif
+# if defined(__FreeBSD__) && defined(i386)
+#   define I386
+#   define FREEBSD
+#   define mach_type_known
+# endif
+# if defined(__NetBSD__) && defined(i386)
+#   define I386
+#   define NETBSD
+#   define mach_type_known
+# endif
+# if defined(bsdi) && defined(i386)
+#    define I386
+#    define BSDI
+#    define mach_type_known
+# endif
+# if !defined(mach_type_known) && defined(__386BSD__)
+#   define I386
+#   define THREE86BSD
+#   define mach_type_known
+# endif
+# if defined(_CX_UX) && defined(_M88K)
+#   define M88K
+#   define CX_UX
+#   define mach_type_known
+# endif
+# if defined(DGUX)
+#   define M88K
+    /* DGUX defined */
+#   define mach_type_known
+# endif
+# if defined(_MSDOS) && (_M_IX86 == 300) || (_M_IX86 == 400)
+#   define I386
+#   define MSWIN32     /* or Win32s */
+#   define mach_type_known
+# endif
+# if defined(GO32)
+#   define I386
+#   define DJGPP  /* MSDOS running the DJGPP port of GCC */
+#   define mach_type_known
+# endif
+# if defined(__BORLANDC__)
+#   define I386
+#   define MSWIN32
+#   define mach_type_known
+# endif
+
+/* Feel free to add more clauses here */
+
+/* Or manually define the machine type here.  A machine type is        */
+/* characterized by the architecture.  Some                            */
+/* machine types are further subdivided by OS.                         */
+/* the macros ULTRIX, RISCOS, and BSD to distinguish.                  */
+/* Note that SGI IRIX is treated identically to RISCOS.                        */
+/* SYSV on an M68K actually means A/UX.                                        */
+/* The distinction in these cases is usually the stack starting address */
+# ifndef mach_type_known
+       --> unknown machine type
+# endif
+                   /* Mapping is: M68K       ==> Motorola 680X0        */
+                   /*             (SUNOS4,HP,NEXT, and SYSV (A/UX),    */
+                   /*             MACOS and AMIGA variants)            */
+                   /*             I386       ==> Intel 386             */
+                   /*              (SEQUENT, OS2, SCO, LINUX, NETBSD,  */
+                   /*               FREEBSD, THREE86BSD, MSWIN32,      */
+                   /*               BSDI, SUNOS5, NEXT variants)       */
+                    /*             NS32K      ==> Encore Multimax      */
+                    /*             MIPS       ==> R2000 or R3000       */
+                    /*                 (RISCOS, ULTRIX variants)       */
+                    /*            VAX        ==> DEC VAX               */
+                    /*                 (BSD, ULTRIX variants)          */
+                    /*            RS6000     ==> IBM RS/6000 AIX3.X    */
+                    /*            RT         ==> IBM PC/RT             */
+                    /*            HP_PA      ==> HP9000/700 & /800     */
+                    /*                           HP/UX                 */
+                   /*             SPARC      ==> SPARC under SunOS     */
+                   /*                  (SUNOS4, SUNOS5,                */
+                   /*                   DRSNX variants)                */
+                   /*             ALPHA      ==> DEC Alpha OSF/1       */
+                   /*             M88K       ==> Motorola 88XX0        */
+                   /*                  (CX_UX and DGUX)                */
+
+
+/*
+ * For each architecture and OS, the following need to be defined:
+ *
+ * CPP_WORD_SZ is a simple integer constant representing the word size.
+ * in bits.  We assume byte addressibility, where a byte has 8 bits.
+ * We also assume CPP_WORD_SZ is either 32 or 64.
+ * (We care about the length of pointers, not hardware
+ * bus widths.  Thus a 64 bit processor with a C compiler that uses
+ * 32 bit pointers should use CPP_WORD_SZ of 32, not 64. Default is 32.)
+ *
+ * MACH_TYPE is a string representation of the machine type.
+ * OS_TYPE is analogous for the OS.
+ *
+ * ALIGNMENT is the largest N, such that
+ * all pointer are guaranteed to be aligned on N byte boundaries.
+ * defining it to be 1 will always work, but perform poorly.
+ *
+ * DATASTART is the beginning of the data segment.
+ * On UNIX systems, the collector will scan the area between DATASTART
+ * and &end for root pointers.
+ *
+ * STACKBOTTOM is the cool end of the stack, which is usually the
+ * highest address in the stack.
+ * Under PCR or OS/2, we have other ways of finding thread stacks.
+ * For each machine, the following should:
+ * 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
+ * 2) define exactly one of
+ *     STACKBOTTOM (should be defined to be an expression)
+ *     HEURISTIC1
+ *     HEURISTIC2
+ * If either of the last two macros are defined, then STACKBOTTOM is computed
+ * during collector startup using one of the following two heuristics:
+ * HEURISTIC1:  Take an address inside GC_init's frame, and round it up to
+ *             the next multiple of STACK_GRAN.
+ * HEURISTIC2:  Take an address inside GC_init's frame, increment it repeatedly
+ *             in small steps (decrement if STACK_GROWS_UP), and read the value
+ *             at each location.  Remember the value when the first
+ *             Segmentation violation or Bus error is signalled.  Round that
+ *             to the nearest plausible page boundary, and use that instead
+ *             of STACKBOTTOM.
+ *
+ * If no expression for STACKBOTTOM can be found, and neither of the above
+ * heuristics are usable, the collector can still be used with all of the above
+ * undefined, provided one of the following is done:
+ * 1) GC_mark_roots can be changed to somehow mark from the correct stack(s)
+ *    without reference to STACKBOTTOM.  This is appropriate for use in
+ *    conjunction with thread packages, since there will be multiple stacks.
+ *    (Allocating thread stacks in the heap, and treating them as ordinary
+ *    heap data objects is also possible as a last resort.  However, this is
+ *    likely to introduce significant amounts of excess storage retention
+ *    unless the dead parts of the thread stacks are periodically cleared.)
+ * 2) Client code may set GC_stackbottom before calling any GC_ routines.
+ *    If the author of the client code controls the main program, this is
+ *    easily accomplished by introducing a new main program, setting
+ *    GC_stackbottom to the address of a local variable, and then calling
+ *    the original main program.  The new main program would read something
+ *    like:
+ *
+ *             # include "gc_private.h"
+ *
+ *             main(argc, argv, envp)
+ *             int argc;
+ *             char **argv, **envp;
+ *             {
+ *                 int dummy;
+ *
+ *                 GC_stackbottom = (ptr_t)(&dummy);
+ *                 return(real_main(argc, argv, envp));
+ *             }
+ *
+ *
+ * Each architecture may also define the style of virtual dirty bit
+ * implementation to be used:
+ *   MPROTECT_VDB: Write protect the heap and catch faults.
+ *   PROC_VDB: Use the SVR4 /proc primitives to read dirty bits.
+ *
+ * An architecture may define DYNAMIC_LOADING if dynamic_load.c
+ * defined GC_register_dynamic_libraries() for the architecture.
+ */
+
+
+# define STACK_GRAN 0x1000000
+# ifdef M68K
+#   define MACH_TYPE "M68K"
+#   define ALIGNMENT 2
+#   ifdef NETBSD
+#      define OS_TYPE "NETBSD"
+#      define HEURISTIC2
+       extern char etext;
+#      define DATASTART ((ptr_t)(&etext))
+#   endif
+#   ifdef SUNOS4
+#      define OS_TYPE "SUNOS4"
+       extern char etext;
+#      define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ffff) & ~0x1ffff))
+#      define HEURISTIC1       /* differs      */
+#      define DYNAMIC_LOADING
+#   endif
+#   ifdef HP
+#      define OS_TYPE "HP"
+       extern char etext;
+#       define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+#       define STACKBOTTOM ((ptr_t) 0xffeffffc)
+                             /* empirically determined.  seems to work. */
+#   endif
+#   ifdef SYSV
+#      define OS_TYPE "SYSV"
+       extern etext;
+#      define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
+                                  & ~0x3fffff) \
+                                 +((word)&etext & 0x1fff))
+       /* This only works for shared-text binaries with magic number 0413.
+          The other sorts of SysV binaries put the data at the end of the text,
+          in which case the default of &etext would work.  Unfortunately,
+          handling both would require having the magic-number available.
+                               -- Parag
+          */
+#      define STACKBOTTOM ((ptr_t)0xFFFFFFFE)
+                       /* The stack starts at the top of memory, but   */
+                       /* 0x0 cannot be used as setjump_test complains */
+                       /* that the stack direction is incorrect.  Two  */
+                       /* bytes down from 0x0 should be safe enough.   */
+                       /*              --Parag                         */
+#   endif
+#   ifdef AMIGA
+#      define OS_TYPE "AMIGA"
+               /* STACKBOTTOM and DATASTART handled specially  */
+               /* in os_dep.c                                  */
+#      define DATAEND  /* not needed */
+#   endif
+#   ifdef MACOS
+#     ifndef __LOWMEM__
+#     include <LowMem.h>
+#     endif
+#     define OS_TYPE "MACOS"
+                       /* see os_dep.c for details of global data segments. */
+#     define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
+#     define DATAEND   /* not needed */
+#   endif
+#   ifdef NEXT
+#      define OS_TYPE "NEXT"
+#      define DATASTART ((ptr_t) get_etext())
+#      define STACKBOTTOM ((ptr_t) 0x4000000)
+#      define DATAEND  /* not needed */
+#   endif
+# endif
+
+# ifdef POWERPC
+#   define MACH_TYPE "POWERPC"
+#   define ALIGNMENT 2
+#   ifdef MACOS
+#     ifndef __LOWMEM__
+#     include <LowMem.h>
+#     endif
+#     define OS_TYPE "MACOS"
+                       /* see os_dep.c for details of global data segments. */
+#     define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
+#     define DATAEND  /* not needed */
+#   endif
+# endif
+
+# ifdef VAX
+#   define MACH_TYPE "VAX"
+#   define ALIGNMENT 4 /* Pointers are longword aligned by 4.2 C compiler */
+    extern char etext;
+#   define DATASTART ((ptr_t)(&etext))
+#   ifdef BSD
+#      define OS_TYPE "BSD"
+#      define HEURISTIC1
+                       /* HEURISTIC2 may be OK, but it's hard to test. */
+#   endif
+#   ifdef ULTRIX
+#      define OS_TYPE "ULTRIX"
+#      define STACKBOTTOM ((ptr_t) 0x7fffc800)
+#   endif
+# endif
+
+# ifdef RT
+#   define MACH_TYPE "RT"
+#   define ALIGNMENT 4
+#   define DATASTART ((ptr_t) 0x10000000)
+#   define STACKBOTTOM ((ptr_t) 0x1fffd800)
+# endif
+
+# ifdef SPARC
+#   define MACH_TYPE "SPARC"
+#   define ALIGNMENT 4 /* Required by hardware */
+    extern int etext;
+#   ifdef SUNOS5
+#      define OS_TYPE "SUNOS5"
+       extern int _etext;
+       extern int _end;
+       extern char * GC_SysVGetDataStart();
+#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &_etext)
+#      define DATAEND (&_end)
+#      define PROC_VDB
+#      define HEURISTIC1
+#   endif
+#   ifdef SUNOS4
+#      define OS_TYPE "SUNOS4"
+       /* [If you have a weak stomach, don't read this.]               */
+       /* We would like to use:                                        */
+/* #       define DATASTART ((ptr_t)((((word) (&etext)) + 0x1fff) & ~0x1fff)) */
+       /* This fails occasionally, due to an ancient, but very         */
+       /* persistent ld bug.  &etext is set 32 bytes too high.         */
+       /* We instead read the text segment size from the a.out         */
+       /* header, which happens to be mapped into our address space    */
+       /* at the start of the text segment.  The detective work here   */
+       /* was done by Robert Ehrlich, Manuel Serrano, and Bernard      */
+       /* Serpette of INRIA.                                           */
+       /* This assumes ZMAGIC, i.e. demand-loadable executables.       */
+#      define TEXTSTART 0x2000
+#       define DATASTART ((ptr_t)(*(int *)(TEXTSTART+0x4)+TEXTSTART))
+#      define MPROTECT_VDB
+#      define HEURISTIC1
+#   endif
+#   ifdef DRSNX
+#       define CPP_WORDSZ 32
+#      define OS_TYPE "DRSNX"
+       extern char * GC_SysVGetDataStart();
+       extern int etext;
+#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
+#      define MPROTECT_VDB
+#       define STACKBOTTOM ((ptr_t) 0xdfff0000)
+#   endif
+#   define DYNAMIC_LOADING
+# endif
+
+# ifdef I386
+#   define MACH_TYPE "I386"
+#   define ALIGNMENT 4 /* Appears to hold for all "32 bit" compilers   */
+                       /* except Borland.  The -a4 option fixes        */
+                       /* Borland.                                     */
+#   ifdef SEQUENT
+#      define OS_TYPE "SEQUENT"
+       extern int etext;
+#       define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+#       define STACKBOTTOM ((ptr_t) 0x3ffff000) 
+#   endif
+#   ifdef SUNOS5
+#      define OS_TYPE "SUNOS5"
+       extern int etext, _start;
+       extern char * GC_SysVGetDataStart();
+#       define DATASTART GC_SysVGetDataStart(0x1000, &etext)
+#      define STACKBOTTOM ((ptr_t)(&_start))
+#      define PROC_VDB
+#   endif
+#   ifdef SCO
+#      define OS_TYPE "SCO"
+       extern int etext;
+#      define DATASTART ((ptr_t)((((word) (&etext)) + 0x3fffff) \
+                                 & ~0x3fffff) \
+                                +((word)&etext & 0xfff))
+#      define STACKBOTTOM ((ptr_t) 0x7ffffffc)
+#   endif
+#   ifdef LINUX
+#      define OS_TYPE "LINUX"
+       extern int etext;
+#       define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+#      define STACKBOTTOM ((ptr_t)0xc0000000)
+#      define MPROTECT_VDB
+#   endif
+#   ifdef OS2
+#      define OS_TYPE "OS2"
+               /* STACKBOTTOM and DATASTART are handled specially in   */
+               /* os_dep.c. OS2 actually has the right                 */
+               /* system call!                                         */
+#      define DATAEND  /* not needed */
+#   endif
+#   ifdef MSWIN32
+#      define OS_TYPE "MSWIN32"
+               /* STACKBOTTOM and DATASTART are handled specially in   */
+               /* os_dep.c.                                            */
+#      define MPROTECT_VDB
+#       define DATAEND  /* not needed */
+#   endif
+#   ifdef DJGPP
+#       define OS_TYPE "DJGPP"
+        extern int etext;
+#       define DATASTART ((ptr_t)(&etext))
+#       define STACKBOTTOM ((ptr_t)0x00080000)
+#   endif
+#   ifdef FREEBSD
+#      define OS_TYPE "FREEBSD"
+#      define MPROTECT_VDB
+#   endif
+#   ifdef NETBSD
+#      define OS_TYPE "NETBSD"
+#   endif
+#   ifdef THREE86BSD
+#      define OS_TYPE "THREE86BSD"
+#   endif
+#   ifdef BSDI
+#      define OS_TYPE "BSDI"
+#   endif
+#   if defined(FREEBSD) || defined(NETBSD) \
+        || defined(THREE86BSD) || defined(BSDI)
+#      define HEURISTIC2
+       extern char etext;
+#      define DATASTART ((ptr_t)(&etext))
+#   endif
+#   ifdef NEXT
+#      define OS_TYPE "NEXT"
+#      define DATASTART ((ptr_t) get_etext())
+#      define STACKBOTTOM ((ptr_t)0xc0000000)
+#      define DATAEND  /* not needed */
+#   endif
+# endif
+
+# ifdef NS32K
+#   define MACH_TYPE "NS32K"
+#   define ALIGNMENT 4
+    extern char **environ;
+#   define DATASTART ((ptr_t)(&environ))
+                             /* hideous kludge: environ is the first   */
+                             /* word in crt0.o, and delimits the start */
+                             /* of the data segment, no matter which   */
+                             /* ld options were passed through.        */
+#   define STACKBOTTOM ((ptr_t) 0xfffff000) /* for Encore */
+# endif
+
+# ifdef MIPS
+#   define MACH_TYPE "MIPS"
+#   define ALIGNMENT 4 /* Required by hardware */
+#   define DATASTART 0x10000000
+                             /* Could probably be slightly higher since */
+                             /* startup code allocates lots of junk     */
+#   define HEURISTIC2
+#   ifdef ULTRIX
+#      define OS_TYPE "ULTRIX"
+#   endif
+#   ifdef RISCOS
+#      define OS_TYPE "RISCOS"
+#   endif
+#   ifdef IRIX5
+#      define OS_TYPE "IRIX5"
+#      define MPROTECT_VDB
+               /* The above is dubious.  Mprotect and signals do work, */
+               /* and dirty bits are implemented under IRIX5.  But,    */
+               /* at least under IRIX5.2, mprotect seems to be so      */
+               /* slow relative to the hardware that incremental       */
+               /* collection is likely to be rarely useful.            */
+#      define DYNAMIC_LOADING
+#   endif
+# endif
+
+# ifdef RS6000
+#   define MACH_TYPE "RS6000"
+#   define ALIGNMENT 4
+#   define DATASTART ((ptr_t)0x20000000)
+#   define STACKBOTTOM ((ptr_t)0x2ff80000)
+# endif
+
+# ifdef HP_PA
+#   define MACH_TYPE "HP_PA"
+#   define ALIGNMENT 4
+    extern int __data_start;
+#   define DATASTART ((ptr_t)(&__data_start))
+#   define HEURISTIC2
+#   define STACK_GROWS_UP
+# endif
+
+# ifdef ALPHA
+#   define MACH_TYPE "ALPHA"
+#   define ALIGNMENT 8
+#   define DATASTART ((ptr_t) 0x140000000)
+#   define HEURISTIC2
+       /* Normally HEURISTIC2 is too conervative, since                */
+       /* the text segment immediately follows the stack.              */
+       /* Hence we give an upper pound.                                */
+    extern __start;
+#   define HEURISTIC2_LIMIT ((ptr_t)((word)(&__start) & ~(getpagesize()-1)))
+#   define CPP_WORDSZ 64
+#   define MPROTECT_VDB
+#   define DYNAMIC_LOADING
+# endif
+
+# ifdef M88K
+#   define MACH_TYPE "M88K"
+#   define ALIGNMENT 4
+#   ifdef CX_UX
+#       define DATASTART ((((word)&etext + 0x3fffff) & ~0x3fffff) + 0x10000)
+#   endif
+#   ifdef  DGUX
+       extern char * GC_SysVGetDataStart();
+#       define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
+#   endif
+#   define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
+# endif
+
+# ifndef STACK_GROWS_UP
+#   define STACK_GROWS_DOWN
+# endif
+
+# ifndef CPP_WORDSZ
+#   define CPP_WORDSZ 32
+# endif
+
+# ifndef OS_TYPE
+#   define OS_TYPE ""
+# endif
+
+# ifndef DATAEND
+    extern int end;
+#   define DATAEND (&end)
+# endif
+
+# if defined(SUNOS5) || defined(DRSNX)
+    /* OS has SVR4 generic features.  Probably others also qualify.    */
+#   define SVR4
+# endif
+
+# if defined(SUNOS5) || defined(DRSNX)
+    /* OS has SUNOS5 style semi-undocumented interface to dynamic      */
+    /* loader.                                                         */
+#   define SUNOS5DL
+    /* OS has SUNOS5 style signal handlers.                            */
+#   define SUNOS5SIGS
+# endif
+
+# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
+   -> bad word size
+# endif
+
+# ifdef PCR
+#   undef DYNAMIC_LOADING
+#   undef STACKBOTTOM
+#   undef HEURISTIC1
+#   undef HEURISTIC2
+#   undef PROC_VDB
+#   undef MPROTECT_VDB
+#   define PCR_VDB
+# endif
+
+# ifdef SRC_M3
+/* Postponed for now. */
+#   undef PROC_VDB
+#   undef MPROTECT_VDB
+# endif
+
+# ifdef SMALL_CONFIG
+/* Presumably not worth the space it takes. */
+#   undef PROC_VDB
+#   undef MPROTECT_VDB
+# endif
+
+# if !defined(PCR_VDB) && !defined(PROC_VDB) && !defined(MPROTECT_VDB)
+#   define DEFAULT_VDB
+# endif
+
+# if defined(SPARC)
+#   define SAVE_CALL_CHAIN
+# endif
+
+# endif
diff --git a/include/private/gc_hdrs.h b/include/private/gc_hdrs.h
new file mode 100644 (file)
index 0000000..2f2d1bf
--- /dev/null
@@ -0,0 +1,133 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, July 11, 1995 11:54 am PDT */
+# ifndef GC_HEADERS_H
+# define GC_HEADERS_H
+typedef struct hblkhdr hdr;
+
+# if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
+       --> Get a real machine.
+# endif
+
+/*
+ * The 2 level tree data structure that is used to find block headers.
+ * If there are more than 32 bits in a pointer, the top level is a hash
+ * table.
+ */
+
+# if CPP_WORDSZ > 32
+#   define HASH_TL
+# endif
+
+/* Define appropriate out-degrees for each of the two tree levels      */
+# ifdef SMALL_CONFIG
+#   define LOG_BOTTOM_SZ 11
+       /* Keep top index size reasonable with smaller blocks. */
+# else
+#   define LOG_BOTTOM_SZ 10
+# endif
+# ifndef HASH_TL
+#   define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
+# else
+#   define LOG_TOP_SZ 11
+# endif
+# define TOP_SZ (1 << LOG_TOP_SZ)
+# define BOTTOM_SZ (1 << LOG_BOTTOM_SZ)
+
+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.
+        * 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.             */
+    word key;                  /* high order address bits.     */
+# ifdef HASH_TL
+    struct bi * hash_link;     /* Hash chain link.             */
+# endif
+} bottom_index;
+
+/* extern bottom_index GC_all_nils; - really part of GC_arrays */
+
+/* extern bottom_index * GC_top_index []; - really part of GC_arrays */
+                               /* Each entry points to a bottom_index. */
+                               /* On a 32 bit machine, it points to    */
+                               /* the index for a set of high order    */
+                               /* bits equal to the index.  For longer */
+                               /* addresses, we hash the high order    */
+                               /* bits to compute the index in         */
+                               /* GC_top_index, and each entry points  */
+                               /* to a hash chain.                     */
+                               /* The last entry in each chain is      */
+                               /* GC_all_nils.                         */
+
+
+# define MAX_JUMP (HBLKSIZE - 1)
+
+# define HDR_FROM_BI(bi, p) \
+               ((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
+# ifndef HASH_TL
+#   define BI(p) (GC_top_index \
+               [(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
+#   define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
+#   ifdef SMALL_CONFIG
+#      define HDR(p) GC_find_header((ptr_t)(p))
+#   else
+#      define HDR(p) HDR_INNER(p)
+#   endif
+#   define GET_BI(p, bottom_indx) (bottom_indx) = BI(p)
+#   define GET_HDR(p, hhdr) (hhdr) = HDR(p)
+#   define SET_HDR(p, hhdr) HDR_INNER(p) = (hhdr)
+#   define GET_HDR_ADDR(p, ha) (ha) = &(HDR_INNER(p))
+# else /* hash */
+/*  Hash function for tree top level */
+#   define TL_HASH(hi) ((hi) & (TOP_SZ - 1))
+/*  Set bottom_indx to point to the bottom index for address p */
+#   define GET_BI(p, bottom_indx) \
+       { \
+           register word hi = \
+               (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
+           register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
+           \
+           while (_bi -> key != hi && _bi != GC_all_nils) \
+               _bi = _bi -> hash_link; \
+           (bottom_indx) = _bi; \
+       }
+#   define GET_HDR_ADDR(p, ha) \
+       { \
+           register bottom_index * bi; \
+           \
+           GET_BI(p, bi);      \
+           (ha) = &(HDR_FROM_BI(bi, p)); \
+       }
+#   define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
+                             (hhdr) = *_ha; }
+#   define SET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
+                             *_ha = (hhdr); }
+#   define HDR(p) GC_find_header((ptr_t)(p))
+# endif
+                           
+/* Is the result a forwarding address to someplace closer to the       */
+/* beginning of the block or NIL?                                      */
+# define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((unsigned long) (hhdr) <= MAX_JUMP)
+
+/* Get an HBLKSIZE aligned address closer to the beginning of the block */
+/* h.  Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr).            */
+# define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (unsigned long)(hhdr))
+# endif /*  GC_HEADERS_H */
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
new file mode 100644 (file)
index 0000000..357a390
--- /dev/null
@@ -0,0 +1,1342 @@
+/* 
+ * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
+ * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/* Boehm, August 9, 1995 5:49 pm PDT */
+
+# ifndef GC_PRIVATE_H
+# define GC_PRIVATE_H
+
+#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news)
+    /* sony RISC NEWS, NEWSOS 4 */
+#   define BSD_TIME
+    typedef long ptrdiff_t;
+#endif
+
+#if defined(mips) && defined(SYSTYPE_BSD43)
+    /* MIPS RISCOS 4 */
+#   define BSD_TIME
+#endif
+
+#ifdef BSD_TIME
+#   include <sys/types.h>
+#   include <sys/time.h>
+#   include <sys/resource.h>
+#endif /* BSD_TIME */
+
+# ifndef GC_H
+#   include "gc.h"
+# endif
+
+typedef GC_word word;
+typedef GC_signed_word signed_word;
+
+# ifndef CONFIG_H
+#   include "config.h"
+# endif
+
+# ifndef HEADERS_H
+#   include "gc_hdrs.h"
+# endif
+
+# ifndef bool
+    typedef int bool;
+# endif
+# define TRUE 1
+# define FALSE 0
+
+typedef char * ptr_t;  /* A generic pointer to which we can add        */
+                       /* byte displacements.                          */
+                       /* Preferably identical to caddr_t, if it       */
+                       /* exists.                                      */
+                       
+#if defined(__STDC__)
+#   include <stdlib.h>
+#   if !(defined( sony_news ) )
+#       include <stddef.h>
+#   endif
+#   define VOLATILE volatile
+#else
+#   ifdef MSWIN32
+#      include <stdlib.h>
+#   endif
+#   define VOLATILE
+#endif
+
+#ifdef AMIGA
+#   define GC_FAR __far
+#else
+#   define GC_FAR
+#endif
+
+/*********************************/
+/*                               */
+/* Definitions for conservative  */
+/* collector                     */
+/*                               */
+/*********************************/
+
+/*********************************/
+/*                               */
+/* Easily changeable parameters  */
+/*                               */
+/*********************************/
+
+#define STUBBORN_ALLOC /* Define stubborn allocation primitives        */
+#if defined(SRC_M3) || defined(SMALL_CONFIG)
+# undef STUBBORN_ALLOC
+#endif
+
+
+/* #define ALL_INTERIOR_POINTERS */
+                   /* Forces all pointers into the interior of an      */
+                   /* object to be considered valid.  Also causes the  */
+                   /* sizes of all objects to be inflated by at least  */
+                   /* one byte.  This should suffice to guarantee      */
+                   /* that in the presence of a compiler that does     */
+                   /* not perform garbage-collector-unsafe             */
+                   /* optimizations, all portable, strictly ANSI       */
+                   /* conforming C programs should be safely usable    */
+                   /* with malloc replaced by GC_malloc and free       */
+                   /* calls removed.  There are several disadvantages: */
+                   /* 1. There are probably no interesting, portable,  */
+                   /*    strictly ANSI conforming C programs.          */
+                   /* 2. This option makes it hard for the collector   */
+                   /*    to allocate space that is not ``pointed to''  */
+                   /*    by integers, etc.  Under SunOS 4.X with a     */
+                   /*    statically linked libc, we empiricaly         */
+                   /*    observed that it would be difficult to        */
+                   /*    allocate individual objects larger than 100K. */
+                   /*    Even if only smaller objects are allocated,   */
+                   /*    more swap space is likely to be needed.       */
+                   /*    Fortunately, much of this will never be       */
+                   /*    touched.                                      */
+                   /* If you can easily avoid using this option, do.   */
+                   /* If not, try to keep individual objects small.    */
+                   
+#define PRINTSTATS  /* Print garbage collection statistics             */
+                   /* For less verbose output, undefine in reclaim.c   */
+
+#define PRINTTIMES  /* Print the amount of time consumed by each garbage   */
+                   /* collection.                                         */
+
+#define PRINTBLOCKS /* Print object sizes associated with heap blocks,     */
+                   /* whether the objects are atomic or composite, and    */
+                   /* whether or not the block was found to be empty      */
+                   /* duing the reclaim phase.  Typically generates       */
+                   /* about one screenful per garbage collection.         */
+#undef PRINTBLOCKS
+
+#define PRINTBLACKLIST         /* Print black listed blocks, i.e. values that     */
+                       /* cause the allocator to avoid allocating certain */
+                       /* blocks in order to avoid introducing "false     */
+                       /* hits".                                          */
+#undef PRINTBLACKLIST
+
+#ifdef SILENT
+#  ifdef PRINTSTATS
+#    undef PRINTSTATS
+#  endif
+#  ifdef PRINTTIMES
+#    undef PRINTTIMES
+#  endif
+#  ifdef PRINTNBLOCKS
+#    undef PRINTNBLOCKS
+#  endif
+#endif
+
+#if defined(PRINTSTATS) && !defined(GATHERSTATS)
+#   define GATHERSTATS
+#endif
+
+# if defined(SOLARIS_THREADS) && !defined(SUNOS5)
+--> inconsistent configuration
+# endif
+# if defined(PCR) || defined(SRC_M3) || defined(SOLARIS_THREADS)
+#   define THREADS
+# endif
+
+#if defined(SPARC)
+#   define ALIGN_DOUBLE  /* Align objects of size > 1 word on 2 word   */
+                        /* boundaries.  Wasteful of memory, but       */
+                        /* apparently required by SPARC architecture. */
+#   define ASM_CLEAR_CODE      /* Stack clearing is crucial, and we    */
+                               /* include assembly code to do it well. */
+#endif
+
+#ifdef HP_PA
+#   define ALIGN_DOUBLE
+#endif
+
+#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */
+                   /* free lists are actually maintained.  This applies  */
+                   /* only to the top level routines in misc.c, not to   */
+                   /* user generated code that calls GC_allocobj and     */
+                   /* GC_allocaobj directly.                             */
+                   /* Slows down average programs slightly.  May however */
+                   /* substantially reduce fragmentation if allocation   */
+                   /* request sizes are widely scattered.                */
+                   /* May save significant amounts of space for obj_map  */
+                   /* entries.                                           */
+
+/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
+# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
+#   define MERGE_SIZES
+# endif
+
+#if defined(ALL_INTERIOR_POINTERS) && !defined(DONT_ADD_BYTE_AT_END)
+# define ADD_BYTE_AT_END
+#endif
+
+
+# ifndef LARGE_CONFIG
+#   define MINHINCR 16 /* Minimum heap increment, in blocks of HBLKSIZE  */
+#   define MAXHINCR 512        /* Maximum heap increment, in blocks              */
+# else
+#   define MINHINCR 64
+#   define MAXHINCR 4096
+# endif
+
+# define TIME_LIMIT 50    /* We try to keep pause times from exceeding  */
+                          /* this by much. In milliseconds.             */
+
+# define BL_LIMIT GC_black_list_spacing
+                          /* If we need a block of N bytes, and we have */
+                          /* a block of N + BL_LIMIT bytes available,   */
+                          /* and N > BL_LIMIT,                          */
+                          /* but all possible positions in it are       */
+                          /* blacklisted, we just use it anyway (and    */
+                          /* print a warning, if warnings are enabled). */
+                          /* This risks subsequently leaking the block  */
+                          /* due to a false reference.  But not using   */
+                          /* the block risks unreasonable immediate     */
+                          /* heap growth.                               */
+
+/*********************************/
+/*                               */
+/* Stack saving for debugging   */
+/*                               */
+/*********************************/
+
+/*
+ * Number of frames and arguments to save in objects allocated by
+ * debugging allocator.
+ */
+#   define NFRAMES 6   /* Number of frames to save. Even for           */
+                       /* alignment reasons.                           */
+#   define NARGS 2     /* Mumber of arguments to save for each call.   */
+
+
+#ifdef SAVE_CALL_CHAIN
+    struct callinfo {
+       word ci_pc;
+       word ci_arg[NARGS];     /* bit-wise complement to avoid retention */
+    };
+
+/* Fill in the pc and argument information for up to NFRAMES of my     */
+/* callers.  Ignore my frame and my callers frame.                     */
+void GC_save_callers (/* struct callinfo info[NFRAMES] */);
+
+void GC_print_callers (/* struct callinfo info[NFRAMES] */);
+
+#endif
+
+
+/*********************************/
+/*                               */
+/* OS interface routines        */
+/*                               */
+/*********************************/
+
+#ifdef BSD_TIME
+#   undef CLOCK_TYPE
+#   undef GET_TIME
+#   undef MS_TIME_DIFF
+#   define CLOCK_TYPE struct timeval
+#   define GET_TIME(x) { struct rusage rusage; \
+                        getrusage (RUSAGE_SELF,  &rusage); \
+                        x = rusage.ru_utime; }
+#   define MS_TIME_DIFF(a,b) ((double) (a.tv_sec - b.tv_sec) * 1000.0 \
+                               + (double) (a.tv_usec - b.tv_usec) / 1000.0)
+#else /* !BSD_TIME */
+#   include <time.h>
+#   if !defined(__STDC__) && defined(SPARC) && defined(SUNOS4)
+      clock_t clock(); /* Not in time.h, where it belongs      */
+#   endif
+#   if defined(FREEBSD) && !defined(CLOCKS_PER_SEC)
+#     include <machine/limits.h>
+#     define CLOCKS_PER_SEC CLK_TCK
+#   endif
+#   if !defined(CLOCKS_PER_SEC)
+#     define CLOCKS_PER_SEC 1000000
+/*
+ * This is technically a bug in the implementation.  ANSI requires that
+ * CLOCKS_PER_SEC be defined.  But at least under SunOS4.1.1, it isn't.
+ * Also note that the combination of ANSI C and POSIX is incredibly gross
+ * here. The type clock_t is used by both clock() and times().  But on
+ * some machines these use different notions of a clock tick,  CLOCKS_PER_SEC
+ * seems to apply only to clock.  Hence we use it here.  On many machines,
+ * including SunOS, clock actually uses units of microseconds (which are
+ * not really clock ticks).
+ */
+#   endif
+#   define CLOCK_TYPE clock_t
+#   define GET_TIME(x) x = clock()
+#   define MS_TIME_DIFF(a,b) ((unsigned long) \
+               (1000.0*(double)((a)-(b))/(double)CLOCKS_PER_SEC))
+#endif /* !BSD_TIME */
+
+/* We use bzero and bcopy internally.  They may not be available.      */
+# if defined(SPARC) && defined(SUNOS4)
+#   define BCOPY_EXISTS
+# endif
+# if defined(M68K) && defined(AMIGA)
+#   define BCOPY_EXISTS
+# endif
+# if defined(M68K) && defined(NEXT)
+#   define BCOPY_EXISTS
+# endif
+# if defined(VAX)
+#   define BCOPY_EXISTS
+# endif
+# if defined(AMIGA)
+#   include <string.h>
+#   define BCOPY_EXISTS
+# endif
+
+# ifndef BCOPY_EXISTS
+#   include <string.h>
+#   define BCOPY(x,y,n) memcpy(y, x, (size_t)(n))
+#   define BZERO(x,n)  memset(x, 0, (size_t)(n))
+# else
+#   define BCOPY(x,y,n) bcopy((char *)(x),(char *)(y),(int)(n))
+#   define BZERO(x,n) bzero((char *)(x),(int)(n))
+# endif
+
+/* HBLKSIZE aligned allocation.  0 is taken to mean failure    */
+/* space is assumed to be cleared.                             */
+# ifdef PCR
+    char * real_malloc();
+#   define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + HBLKSIZE) \
+                                 + HBLKSIZE-1)
+# else
+#   ifdef OS2
+      void * os2_alloc(size_t bytes);
+#     define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes + HBLKSIZE) \
+                                    + HBLKSIZE-1)
+#   else
+#     if defined(AMIGA) || defined(NEXT)
+#       define GET_MEM(bytes) HBLKPTR((size_t) \
+                                     calloc(1, (size_t)bytes + HBLKSIZE) \
+                                      + HBLKSIZE-1)
+#     else
+#      ifdef MSWIN32
+          extern ptr_t GC_win32_get_mem();
+#         define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
+#      else
+#        ifdef MACOS
+#          if defined(USE_TEMPORARY_MEMORY)
+               extern Ptr GC_MacTemporaryNewPtr(size_t size,
+                                                Boolean clearMemory);
+#               define GET_MEM(bytes) HBLKPTR( \
+                   GC_MacTemporaryNewPtr(bytes + HBLKSIZE, true) + HBLKSIZE-1)
+#          else
+#                  define GET_MEM(bytes) HBLKPTR( \
+                       NewPtrClear(bytes + HBLKSIZE) + HBLKSIZE-1)
+#          endif
+#        else
+            extern ptr_t GC_unix_get_mem();
+#           define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
+#        endif
+#      endif
+#     endif
+#   endif
+# endif
+
+/*
+ * Mutual exclusion between allocator/collector routines.
+ * Needed if there is more than one allocator thread.
+ * FASTLOCK() is assumed to try to acquire the lock in a cheap and
+ * dirty way that is acceptable for a few instructions, e.g. by
+ * inhibiting preemption.  This is assumed to have succeeded only
+ * if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE.
+ * FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED().
+ * If signals cannot be tolerated with the FASTLOCK held, then
+ * FASTLOCK should disable signals.  The code executed under
+ * FASTLOCK is otherwise immune to interruption, provided it is
+ * not restarted.
+ * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK
+ * and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK.
+ * (There is currently no equivalent for FASTLOCK.)
+ */  
+# ifdef THREADS
+#  ifdef PCR_OBSOLETE  /* Faster, but broken with multiple lwp's       */
+#    include  "th/PCR_Th.h"
+#    include  "th/PCR_ThCrSec.h"
+     extern struct PCR_Th_MLRep GC_allocate_ml;
+#    define DCL_LOCK_STATE  PCR_sigset_t GC_old_sig_mask
+#    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) 
+#    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
+#    define FASTLOCK() PCR_ThCrSec_EnterSys()
+     /* Here we cheat (a lot): */
+#        define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0)
+               /* TRUE if nobody currently holds the lock */
+#    define FASTUNLOCK() PCR_ThCrSec_ExitSys()
+#  endif
+#  ifdef PCR
+#    include <base/PCR_Base.h>
+#    include <th/PCR_Th.h>
+     extern PCR_Th_ML GC_allocate_ml;
+#    define DCL_LOCK_STATE \
+        PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
+#    define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
+#    define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
+#    define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml))
+#    define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay)
+#    define FASTUNLOCK()  {\
+        if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); }
+#  endif
+#  ifdef SRC_M3
+     extern word RT0u__inCritical;
+#    define LOCK() RT0u__inCritical++
+#    define UNLOCK() RT0u__inCritical--
+#  endif
+#  ifdef SOLARIS_THREADS
+#    include <thread.h>
+#    include <signal.h>
+     extern mutex_t GC_allocate_ml;
+#    define LOCK() mutex_lock(&GC_allocate_ml);
+#    define UNLOCK() mutex_unlock(&GC_allocate_ml);
+#  endif
+# else
+#    define LOCK()
+#    define UNLOCK()
+# endif
+
+# ifndef DCL_LOCK_STATE
+#   define DCL_LOCK_STATE
+# endif
+# ifndef FASTLOCK
+#   define FASTLOCK() LOCK()
+#   define FASTLOCK_SUCCEEDED() TRUE
+#   define FASTUNLOCK() UNLOCK()
+# endif
+
+/* Delay any interrupts or signals that may abort this thread.  Data   */
+/* structures are in a consistent state outside this pair of calls.    */
+/* ANSI C allows both to be empty (though the standard isn't very      */
+/* clear on that point).  Standard malloc implementations are usually  */
+/* neither interruptable nor thread-safe, and thus correspond to       */
+/* empty definitions.                                                  */
+# ifdef PCR
+#   define DISABLE_SIGNALS() \
+                PCR_Th_SetSigMask(PCR_allSigsBlocked,&GC_old_sig_mask)
+#   define ENABLE_SIGNALS() \
+               PCR_Th_SetSigMask(&GC_old_sig_mask, NIL)
+# else
+#   if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
+       || defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \
+       || defined(NO_SIGNALS)
+                       /* Also useful for debugging.           */
+       /* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
+#     define DISABLE_SIGNALS()
+#     define ENABLE_SIGNALS()
+#   else
+#     define DISABLE_SIGNALS() GC_disable_signals()
+       void GC_disable_signals();
+#     define ENABLE_SIGNALS() GC_enable_signals()
+       void GC_enable_signals();
+#   endif
+# endif
+
+/*
+ * Stop and restart mutator threads.
+ */
+# ifdef PCR
+#     include "th/PCR_ThCtl.h"
+#     define STOP_WORLD() \
+       PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_stopNormal, \
+                                  PCR_allSigsBlocked, \
+                                  PCR_waitForever)
+#     define START_WORLD() \
+       PCR_ThCtl_SetExclusiveMode(PCR_ThCtl_ExclusiveMode_null, \
+                                  PCR_allSigsBlocked, \
+                                  PCR_waitForever);
+# else
+#   ifdef SOLARIS_THREADS
+#     define STOP_WORLD() GC_stop_world()
+#     define START_WORLD() GC_start_world()
+#   else
+#     define STOP_WORLD()
+#     define START_WORLD()
+#   endif
+# endif
+
+/* Abandon ship */
+# ifdef PCR
+#   define ABORT(s) PCR_Base_Panic(s)
+# else
+#   ifdef SMALL_CONFIG
+#      define ABORT(msg) abort();
+#   else
+       void GC_abort();
+#       define ABORT(msg) GC_abort(msg);
+#   endif
+# endif
+
+/* Exit abnormally, but without making a mess (e.g. out of memory) */
+# ifdef PCR
+#   define EXIT() PCR_Base_Exit(1,PCR_waitForever)
+# else
+#   define EXIT() (void)exit(1)
+# endif
+
+/* Print warning message, e.g. almost out of memory.   */
+# define WARN(msg,arg) (*GC_current_warn_proc)(msg, (GC_word)(arg))
+extern GC_warn_proc GC_current_warn_proc;
+
+/*********************************/
+/*                               */
+/* Word-size-dependent defines   */
+/*                               */
+/*********************************/
+
+#if CPP_WORDSZ == 32
+#  define WORDS_TO_BYTES(x)   ((x)<<2)
+#  define BYTES_TO_WORDS(x)   ((x)>>2)
+#  define LOGWL               ((word)5)    /* log[2] of CPP_WORDSZ */
+#  define modWORDSZ(n) ((n) & 0x1f)        /* n mod size of word           */
+#  if ALIGNMENT != 4
+#      define UNALIGNED
+#  endif
+#endif
+
+#if CPP_WORDSZ == 64
+#  define WORDS_TO_BYTES(x)   ((x)<<3)
+#  define BYTES_TO_WORDS(x)   ((x)>>3)
+#  define LOGWL               ((word)6)    /* log[2] of CPP_WORDSZ */
+#  define modWORDSZ(n) ((n) & 0x3f)        /* n mod size of word           */
+#  if ALIGNMENT != 8
+#      define UNALIGNED
+#  endif
+#endif
+
+#define WORDSZ ((word)CPP_WORDSZ)
+#define SIGNB  ((word)1 << (WORDSZ-1))
+#define BYTES_PER_WORD      ((word)(sizeof (word)))
+#define ONES                ((word)(-1))
+#define divWORDSZ(n) ((n) >> LOGWL)       /* divide n by size of word      */
+
+/*********************/
+/*                   */
+/*  Size Parameters  */
+/*                   */
+/*********************/
+
+/*  heap block size, bytes. Should be power of 2 */
+
+#ifdef SMALL_CONFIG
+#   define CPP_LOG_HBLKSIZE 10
+#else
+# if CPP_WORDSZ == 32
+#   define CPP_LOG_HBLKSIZE 12
+# else
+#   define CPP_LOG_HBLKSIZE 13
+# endif
+#endif
+#define LOG_HBLKSIZE   ((word)CPP_LOG_HBLKSIZE)
+#define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
+#define HBLKSIZE ((word)CPP_HBLKSIZE)
+
+
+/*  max size objects supported by freelist (larger objects may be   */
+/*  allocated, but less efficiently)                                */
+
+#define CPP_MAXOBJSZ    BYTES_TO_WORDS(CPP_HBLKSIZE/2)
+#define MAXOBJSZ ((word)CPP_MAXOBJSZ)
+               
+# define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE)
+
+# define HBLK_PTR_DIFF(p,q) divHBLKSZ((ptr_t)p - (ptr_t)q)
+       /* Equivalent to subtracting 2 hblk pointers.   */
+       /* We do it this way because a compiler should  */
+       /* find it hard to use an integer division      */
+       /* instead of a shift.  The bundled SunOS 4.1   */
+       /* o.w. sometimes pessimizes the subtraction to */
+       /* involve a call to .div.                      */
+# define modHBLKSZ(n) ((n) & (HBLKSIZE-1))
+# define HBLKPTR(objptr) ((struct hblk *)(((word) (objptr)) & ~(HBLKSIZE-1)))
+
+# define HBLKDISPL(objptr) (((word) (objptr)) & (HBLKSIZE-1))
+
+/* Round up byte allocation requests to integral number of words, etc. */
+# ifdef ADD_BYTE_AT_END
+#   define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1))
+#   ifdef ALIGN_DOUBLE
+#       define ALIGNED_WORDS(n) (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2)) & ~1)
+#   else
+#       define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+#   endif
+#   define SMALL_OBJ(bytes) ((bytes) < WORDS_TO_BYTES(MAXOBJSZ))
+#   define ADD_SLOP(bytes) ((bytes)+1)
+# else
+#   define ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + (WORDS_TO_BYTES(1) - 1))
+#   ifdef ALIGN_DOUBLE
+#       define ALIGNED_WORDS(n) \
+                       (BYTES_TO_WORDS((n) + WORDS_TO_BYTES(2) - 1) & ~1)
+#   else
+#       define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n)
+#   endif
+#   define SMALL_OBJ(bytes) ((bytes) <= WORDS_TO_BYTES(MAXOBJSZ))
+#   define ADD_SLOP(bytes) (bytes)
+# endif
+
+
+/*
+ * Hash table representation of sets of pages.  This assumes it is
+ * OK to add spurious entries to sets.
+ * Used by black-listing code, and perhaps by dirty bit maintenance code.
+ */
+# ifdef LARGE_CONFIG
+#   define LOG_PHT_ENTRIES  17
+# else
+#   define LOG_PHT_ENTRIES  14 /* Collisions are likely if heap grows  */
+                               /* to more than 16K hblks = 64MB.       */
+                               /* Each hash table occupies 2K bytes.   */
+# endif
+# define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES)
+# define PHT_SIZE (PHT_ENTRIES >> LOGWL)
+typedef word page_hash_table[PHT_SIZE];
+
+# define PHT_HASH(addr) ((((word)(addr)) >> LOG_HBLKSIZE) & (PHT_ENTRIES - 1))
+
+# define get_pht_entry_from_index(bl, index) \
+               (((bl)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
+# define set_pht_entry_from_index(bl, index) \
+               (bl)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index)
+# define clear_pht_entry_from_index(bl, index) \
+               (bl)[divWORDSZ(index)] &= ~((word)1 << modWORDSZ(index))
+       
+
+
+/********************************************/
+/*                                          */
+/*    H e a p   B l o c k s                 */
+/*                                          */
+/********************************************/
+
+/*  heap block header */
+#define HBLKMASK   (HBLKSIZE-1)
+
+#define BITS_PER_HBLK (HBLKSIZE * 8)
+
+#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/CPP_WORDSZ)
+          /* upper bound                                    */
+          /* We allocate 1 bit/word.  Only the first word   */
+          /* in each object is actually marked.             */
+
+# ifdef ALIGN_DOUBLE
+#   define MARK_BITS_SZ (((MARK_BITS_PER_HBLK + 2*CPP_WORDSZ - 1) \
+                         / (2*CPP_WORDSZ))*2)
+# else
+#   define MARK_BITS_SZ ((MARK_BITS_PER_HBLK + CPP_WORDSZ - 1)/CPP_WORDSZ)
+# endif
+          /* Upper bound on number of mark words per heap block  */
+
+struct hblkhdr {
+    word hb_sz;  /* If in use, size in words, of objects in the block. */
+                /* if free, the size in bytes of the whole block      */
+    struct hblk * hb_next;     /* Link field for hblk free list         */
+                               /* and for lists of chunks waiting to be */
+                               /* reclaimed.                            */
+    word hb_descr;             /* object descriptor for marking.  See  */
+                               /* mark.h.                              */
+    char* hb_map;      /* A pointer to a pointer validity map of the block. */
+                       /* See GC_obj_map.                                   */
+                       /* Valid for all blocks with headers.                */
+                       /* Free blocks point to GC_invalid_map.              */
+    unsigned char hb_obj_kind;
+                        /* Kind of objects in the block.  Each kind    */
+                        /* identifies a mark procedure and a set of    */
+                        /* list headers.  Sometimes called regions.    */
+    unsigned char hb_flags;
+#      define IGNORE_OFF_PAGE  1       /* Ignore pointers that do not  */
+                                       /* point to the first page of   */
+                                       /* this object.                 */
+    unsigned short hb_last_reclaimed;
+                               /* Value of GC_gc_no when block was     */
+                               /* last allocated or swept. May wrap.   */
+    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.             */
+};
+
+/*  heap block body */
+
+# define DISCARD_WORDS 0
+       /* Number of words to be dropped at the beginning of each block */
+       /* Must be a multiple of WORDSZ.  May reasonably be nonzero     */
+       /* on machines that don't guarantee longword alignment of       */
+       /* pointers, so that the number of false hits is minimized.     */
+       /* 0 and WORDSZ are probably the only reasonable values.        */
+
+# define BODY_SZ ((HBLKSIZE-WORDS_TO_BYTES(DISCARD_WORDS))/sizeof(word))
+
+struct hblk {
+#   if (DISCARD_WORDS != 0)
+        word garbage[DISCARD_WORDS];
+#   endif
+    word hb_body[BODY_SZ];
+};
+
+# define HDR_WORDS ((word)DISCARD_WORDS)
+# define HDR_BYTES ((word)WORDS_TO_BYTES(DISCARD_WORDS))
+
+# define OBJ_SZ_TO_BLOCKS(sz) \
+    divHBLKSZ(HDR_BYTES + WORDS_TO_BYTES(sz) + HBLKSIZE-1)
+    /* Size of block (in units of HBLKSIZE) needed to hold objects of  */
+    /* given sz (in words).                                            */
+
+/* Object free list link */
+# define obj_link(p) (*(ptr_t *)(p))
+
+/*  lists of all heap blocks and free lists    */
+/* These are grouped together in a struct      */
+/* so that they can be easily skipped by the   */
+/* GC_mark routine.                            */
+/* The ordering is weird to make GC_malloc     */
+/* faster by keeping the important fields      */
+/* sufficiently close together that a          */
+/* single load of a base register will do.     */
+/* Scalars that could easily appear to         */
+/* be pointers are also put here.              */
+/* The main fields should precede any          */
+/* conditionally included fields, so that      */
+/* gc_inl.h will work even if a different set  */
+/* of macros is defined when the client is     */
+/* compiled.                                   */
+
+struct _GC_arrays {
+  word _heapsize;
+  word _max_heapsize;
+  ptr_t _last_heap_addr;
+  ptr_t _prev_heap_addr;
+  word _words_allocd_before_gc;
+               /* Number of words allocated before this        */
+               /* collection cycle.                            */
+  word _words_allocd;
+       /* Number of words allocated during this collection cycle */
+  word _words_wasted;
+       /* Number of words wasted due to internal fragmentation  */
+       /* in large objects allocated since last gc. Approximate.*/
+  word _words_finalized;
+       /* Approximate number of words in objects (and headers) */
+       /* That became ready for finalization in the last       */
+       /* collection.                                          */
+  word _non_gc_bytes_at_gc;
+       /* Number of explicitly managed bytes of storage        */
+       /* at last collection.                                  */
+  word _mem_freed;
+       /* Number of explicitly deallocated words of memory     */
+       /* since last collection.                               */
+       
+  ptr_t _objfreelist[MAXOBJSZ+1];
+                         /* free list for objects */
+  ptr_t _aobjfreelist[MAXOBJSZ+1];
+                         /* free list for atomic objs  */
+
+  ptr_t _uobjfreelist[MAXOBJSZ+1];
+                         /* uncollectable but traced objs      */
+
+# ifdef GATHERSTATS
+    word _composite_in_use;
+               /* Number of words in accessible composite      */
+               /* objects.                                     */
+    word _atomic_in_use;
+               /* Number of words in accessible atomic         */
+               /* objects.                                     */
+# endif
+# ifdef MERGE_SIZES
+    unsigned _size_map[WORDS_TO_BYTES(MAXOBJSZ+1)];
+       /* Number of words to allocate for a given allocation request in */
+       /* bytes.                                                        */
+# endif 
+
+# ifdef STUBBORN_ALLOC
+    ptr_t _sobjfreelist[MAXOBJSZ+1];
+# endif
+                         /* free list for immutable objects    */
+  ptr_t _obj_map[MAXOBJSZ+1];
+                       /* If not NIL, then a pointer to a map of valid  */
+                      /* object addresses. _obj_map[sz][i] is j if the */
+                      /* address block_start+i is a valid pointer      */
+                      /* 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    */
+                      /* block_start+WORDS_TO_BYTES(i) is in the       */
+                      /* interior of an object starting at             */
+                      /* block_start+WORDS_TO_BYTES(i-j)).             */
+                      /* It is OBJ_INVALID if                          */
+                      /* block_start+WORDS_TO_BYTES(i) is not          */
+                      /* valid as a pointer to an object.              */
+                      /* We assume all values of j <= OBJ_INVALID.     */
+                      /* The zeroth entry corresponds to large objects.*/
+#   ifdef ALL_INTERIOR_POINTERS
+#      define map_entry_type short
+#       define OBJ_INVALID 0x7fff
+#      define MAP_ENTRY(map, bytes) \
+               (((map_entry_type *)(map))[BYTES_TO_WORDS(bytes)])
+#      define MAP_ENTRIES BYTES_TO_WORDS(HBLKSIZE)
+#      define MAP_SIZE (MAP_ENTRIES * sizeof(map_entry_type))
+#      define OFFSET_VALID(displ) TRUE
+#      define CPP_MAX_OFFSET (HBLKSIZE - HDR_BYTES - 1)
+#      define MAX_OFFSET ((word)CPP_MAX_OFFSET)
+#   else
+#      define map_entry_type char
+#       define OBJ_INVALID 0x7f
+#      define MAP_ENTRY(map, bytes) \
+               (map)[bytes]
+#      define MAP_ENTRIES HBLKSIZE
+#      define MAP_SIZE MAP_ENTRIES
+#      define CPP_MAX_OFFSET (WORDS_TO_BYTES(OBJ_INVALID) - 1) 
+#      define MAX_OFFSET ((word)CPP_MAX_OFFSET)
+#      define VALID_OFFSET_SZ \
+         (CPP_MAX_OFFSET > WORDS_TO_BYTES(CPP_MAXOBJSZ)? \
+          CPP_MAX_OFFSET+1 \
+          : WORDS_TO_BYTES(CPP_MAXOBJSZ)+1)
+       char _valid_offsets[VALID_OFFSET_SZ];
+                               /* GC_valid_offsets[i] == TRUE ==> i    */
+                               /* is registered as a displacement.     */
+#      define OFFSET_VALID(displ) GC_valid_offsets[displ]
+       char _modws_valid_offsets[sizeof(word)];
+                               /* GC_valid_offsets[i] ==>                */
+                               /* GC_modws_valid_offsets[i%sizeof(word)] */
+#   endif
+# ifdef STUBBORN_ALLOC
+      page_hash_table _changed_pages;
+        /* Stubborn object pages that were changes since last call to  */
+       /* GC_read_changed.                                             */
+      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     */
+                                    /* GC_read_dirty.                     */
+# endif
+# ifdef LARGE_CONFIG
+#   if CPP_WORDSZ > 32
+#     define MAX_HEAP_SECTS 4096       /* overflows at roughly 64 GB      */
+#   else
+#     define MAX_HEAP_SECTS 768                /* Separately added heap sections. */
+#   endif
+# else
+#   define MAX_HEAP_SECTS 256
+# endif
+  struct HeapSect {
+      ptr_t hs_start; word hs_bytes;
+  } _heap_sects[MAX_HEAP_SECTS];
+# ifdef MSWIN32
+    ptr_t _heap_bases[MAX_HEAP_SECTS];
+               /* Start address of memory regions obtained from kernel. */
+# endif
+  /* Block header index; see gc_headers.h */
+  bottom_index * _all_nils;
+  bottom_index * _top_index [TOP_SZ];
+#ifdef SAVE_CALL_CHAIN
+  struct callinfo _last_stack[NFRAMES];        /* Stack at last garbage collection.*/
+                                       /* Useful for debugging mysterious  */
+                                       /* object disappearances.           */
+                                       /* In the multithreaded case, we    */
+                                       /* currently only save the calling  */
+                                       /* stack.                           */
+#endif
+};
+
+extern GC_FAR struct _GC_arrays GC_arrays; 
+
+# define GC_objfreelist GC_arrays._objfreelist
+# define GC_aobjfreelist GC_arrays._aobjfreelist
+# define GC_uobjfreelist GC_arrays._uobjfreelist
+# define GC_sobjfreelist GC_arrays._sobjfreelist
+# define GC_valid_offsets GC_arrays._valid_offsets
+# define GC_modws_valid_offsets GC_arrays._modws_valid_offsets
+# ifdef STUBBORN_ALLOC
+#    define GC_changed_pages GC_arrays._changed_pages
+#    define GC_prev_changed_pages GC_arrays._prev_changed_pages
+# endif
+# define GC_obj_map GC_arrays._obj_map
+# define GC_last_heap_addr GC_arrays._last_heap_addr
+# 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_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_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 MSWIN32
+#   define GC_heap_bases GC_arrays._heap_bases
+# endif
+# 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 GATHERSTATS
+#   define GC_composite_in_use GC_arrays._composite_in_use
+#   define GC_atomic_in_use GC_arrays._atomic_in_use
+# endif
+# ifdef MERGE_SIZES
+#   define GC_size_map GC_arrays._size_map
+# endif
+
+# define beginGC_arrays ((ptr_t)(&GC_arrays))
+# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
+
+
+# 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 */
+                       /* with GC_scratch_alloc.                            */
+   struct hblk **ok_reclaim_list;
+                       /* List headers for lists of blocks waiting to be */
+                       /* swept.                                         */
+   word ok_descriptor;  /* Descriptor template for objects in this     */
+                       /* block.                                       */
+   bool ok_relocate_descr;
+                       /* Add object size in bytes to descriptor       */
+                       /* template to obtain descriptor.  Otherwise    */
+                       /* template is used as is.                      */
+   bool ok_init;     /* Clear objects before putting them on the free list. */
+} GC_obj_kinds[MAXOBJKINDS];
+/* Predefined kinds: */
+# define PTRFREE 0
+# define NORMAL  1
+# define UNCOLLECTABLE 2
+# define STUBBORN 3
+
+extern int GC_n_kinds;
+
+extern word GC_n_heap_sects;   /* Number of separately added heap      */
+                               /* sections.                            */
+
+# ifdef MSWIN32
+extern word GC_n_heap_bases;   /* See GC_heap_bases.   */
+# endif
+
+extern word GC_total_black_listed;
+                       /* Number of bytes on stack blacklist.  */
+
+extern word GC_black_list_spacing;
+                       /* Average number of bytes between blacklisted  */
+                       /* blocks. Approximate.                         */
+
+extern char * GC_invalid_map;
+                       /* Pointer to the nowhere valid hblk map */
+                       /* Blocks pointing to this map are free. */
+
+extern struct hblk * GC_hblkfreelist;
+                               /* List of completely empty heap blocks */
+                               /* Linked through hb_next field of      */
+                               /* header structure associated with     */
+                               /* block.                               */
+
+extern bool GC_is_initialized;         /* GC_init() has been run.      */
+
+extern bool GC_objects_are_marked;     /* There are marked objects in  */
+                                       /* the heap.                    */
+
+extern int GC_incremental;  /* Using incremental/generational collection. */
+
+extern 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 bool GC_debugging_started;      /* GC_debug_malloc has been called. */ 
+
+extern ptr_t GC_least_plausible_heap_addr;
+extern ptr_t GC_greatest_plausible_heap_addr;
+                       /* Bounds on the heap.  Guaranteed valid        */
+                       /* Likely to include future heap expansion.     */
+                       
+/* Operations */
+# ifndef abs
+#   define abs(x)  ((x) < 0? (-(x)) : (x))
+# endif
+
+
+/*  Marks are in a reserved area in                          */
+/*  each heap block.  Each word has one mark bit associated  */
+/*  with it. Only those corresponding to the beginning of an */
+/*  object are used.                                         */
+
+
+/* Mark bit perations */
+
+/*
+ * Retrieve, set, clear the mark bit corresponding
+ * to the nth word in a given heap block.
+ *
+ * (Recall that bit n corresponds to object beginning at word n
+ * relative to the beginning of the block, including unused words)
+ */
+
+# define mark_bit_from_hdr(hhdr,n) (((hhdr)->hb_marks[divWORDSZ(n)] \
+                           >> (modWORDSZ(n))) & (word)1)
+# define set_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \
+                               |= (word)1 << modWORDSZ(n)
+
+# define clear_mark_bit_from_hdr(hhdr,n) (hhdr)->hb_marks[divWORDSZ(n)] \
+                               &= ~((word)1 << modWORDSZ(n))
+
+/* Important internal collector routines */
+
+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 */);
+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     */
+                                       /* objects may point to unmarked   */
+                                       /* ones, and roots may point to    */
+                                       /* unmarked objects.               */
+                                       /* Reset mark stack.               */
+void GC_mark_from_mark_stack(); /* Mark from everything on the mark stack. */
+                               /* Return after about one pages worth of   */
+                               /* work.                                   */
+bool GC_mark_stack_empty();
+bool GC_mark_some();   /* 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.          */
+void GC_initiate_full();       /* initiate full collection.            */
+void GC_initiate_partial();    /* initiate partial collection.         */                      
+void GC_push_all(/*b,t*/);     /* Push everything in a range           */
+                               /* onto mark stack.                     */
+void GC_push_dirty(/*b,t*/);      /* Push all possibly changed         */
+                                 /* subintervals of [b,t) onto         */
+                                 /* mark stack.                        */
+#ifndef SMALL_CONFIG
+  void GC_push_conditional(/* ptr_t b, ptr_t t, bool all*/);
+#else
+# define GC_push_conditional(b, t, all) GC_push_all(b, t)
+#endif
+                                /* Do either of the above, depending   */
+                               /* on the third arg.                    */
+void GC_push_all_stack(/*b,t*/);    /* As above, but consider          */
+                                   /*  interior pointers as valid      */
+void GC_push_roots(/* bool all */); /* Push all or dirty roots.        */
+extern void (*GC_push_other_roots)();
+                       /* Push system or application specific roots    */
+                       /* onto the mark stack.  In some environments   */
+                       /* (e.g. threads environments) this is          */
+                       /* predfined to be non-zero.  A client supplied */
+                       /* replacement should also call the original    */
+                       /* function.                                    */
+void GC_push_regs();   /* Push register contents onto mark stack.      */
+void GC_remark();      /* Mark from all marked objects.  Used  */
+                       /* only if we had to drop something.    */
+void GC_push_one(/*p*/);       /* If p points to an object, mark it    */
+                               /* and push contents on the mark stack  */
+void GC_push_one_checked(/*p*/); /* Ditto, omits plausibility test     */
+void GC_push_marked(/* struct hblk h, hdr * hhdr */);
+               /* Push contents of all marked objects in h onto        */
+               /* mark stack.                                          */
+#ifdef SMALL_CONFIG
+# define GC_push_next_marked_dirty(h) GC_push_next_marked(h)
+#else
+  struct hblk * GC_push_next_marked_dirty(/* h */);
+               /* Invoke GC_push_marked on next dirty block above h.   */
+               /* Return a pointer just past the end of this block.    */
+#endif /* !SMALL_CONFIG */
+struct hblk * GC_push_next_marked(/* h */);
+               /* Ditto, but also mark from clean pages.       */
+struct hblk * GC_push_next_marked_uncollectable(/* h */);
+               /* Ditto, but mark only from uncollectable pages.       */
+bool GC_stopped_mark(); /* Stop world and mark from all roots  */
+                       /* and rescuers.                        */
+void GC_clear_hdr_marks(/* hhdr */);  /* Clear the mark bits in a header */
+void GC_add_roots_inner();
+bool GC_is_static_root(/* ptr_t p */);
+               /* Is the address p in one of the registered static     */
+               /* root sections?                                       */
+void GC_register_dynamic_libraries();
+               /* Add dynamic library data sections to the root set. */
+
+/* Machine dependent startup routines */
+ptr_t GC_get_stack_base();
+void GC_register_data_segments();
+
+/* Black listing: */
+void GC_bl_init();     
+# ifndef ALL_INTERIOR_POINTERS
+    void GC_add_to_black_list_normal(/* bits */);
+                       /* Register bits as a possible future false     */
+                       /* reference from the heap or static data       */
+#   define GC_ADD_TO_BLACK_LIST_NORMAL(bits) GC_add_to_black_list_normal(bits)
+# else
+#   define GC_ADD_TO_BLACK_LIST_NORMAL(bits) GC_add_to_black_list_stack(bits)
+# endif
+
+void GC_add_to_black_list_stack(/* bits */);
+struct hblk * GC_is_black_listed(/* h, len */);
+                       /* If there are likely to be false references   */
+                       /* to a block starting at h of the indicated    */
+                       /* length, then return the next plausible       */
+                       /* starting location for h that might avoid     */
+                       /* these false references.                      */
+void GC_promote_black_lists();
+                       /* Declare an end to a black listing phase.     */
+void GC_unpromote_black_lists();
+                       /* Approximately undo the effect of the above.  */
+                       /* This actually loses some information, but    */
+                       /* only in a reasonably safe way.               */
+word GC_number_stack_black_listed(/*struct hblk *start, struct hblk *endp1 */);
+                       /* Return the number of (stack) blacklisted     */
+                       /* blocks in the range for statistical          */
+                       /* purposes.                                    */
+                       
+ptr_t GC_scratch_alloc(/*bytes*/);
+                               /* GC internal memory allocation for    */
+                               /* small objects.  Deallocation is not  */
+                               /* possible.                            */
+       
+/* Heap block layout maps: */                  
+void GC_invalidate_map(/* hdr */);
+                               /* Remove the object map associated     */
+                               /* with the block.  This identifies     */
+                               /* the block as invalid to the mark     */
+                               /* routines.                            */
+bool GC_add_map_entry(/*sz*/);
+                               /* Add a heap block map for objects of  */
+                               /* size sz to obj_map.                  */
+                               /* Return FALSE on failure.             */
+void GC_register_displacement_inner(/*offset*/);
+                               /* Version of GC_register_displacement  */
+                               /* that assumes lock is already held    */
+                               /* and signals are already disabled.    */
+
+/*  hblk allocation: */                
+void GC_new_hblk(/*size_in_words, kind*/);
+                               /* Allocate a new heap block, and build */
+                               /* a free list in it.                   */                              
+struct hblk * GC_allochblk(/*size_in_words, kind*/);
+                               /* Allocate a heap block, clear it if   */
+                               /* for composite objects, inform        */
+                               /* the marker that block is valid       */
+                               /* for objects of indicated size.       */
+                               /* sz < 0 ==> atomic.                   */ 
+void GC_freehblk();            /* Deallocate a heap block and mark it  */
+                               /* as invalid.                          */
+                               
+/*  Misc GC: */
+void GC_init_inner();
+bool GC_expand_hp_inner();
+void GC_start_reclaim(/*abort_if_found*/);
+                               /* Restore unmarked objects to free     */
+                               /* lists, or (if abort_if_found is      */
+                               /* TRUE) report them.                   */
+                               /* Sweeping of small object pages is    */
+                               /* largely deferred.                    */
+void GC_continue_reclaim(/*size, kind*/);
+                               /* Sweep pages of the given size and    */
+                               /* kind, as long as possible, and       */
+                               /* as long as the corr. free list is    */
+                               /* empty.                               */
+void GC_reclaim_or_delete_all();
+                               /* Arrange for all reclaim lists to be  */
+                               /* empty.  Judiciously choose between   */
+                               /* sweeping and discarding each page.   */
+bool GC_reclaim_all(/* GC_stop_func f*/);
+                               /* Reclaim all blocks.  Abort (in a     */
+                               /* consistent state) if f returns TRUE. */
+bool GC_block_empty(/* hhdr */); /* Block completely unmarked?         */
+bool GC_never_stop_func();     /* Returns FALSE.               */
+bool GC_try_to_collect_inner(/* GC_stop_func f */);
+                               /* Collect; caller must have acquired   */
+                               /* lock and disabled signals.           */
+                               /* Collection is aborted if f returns   */
+                               /* TRUE.  Returns TRUE if it completes  */
+                               /* successfully.                        */
+# define GC_gcollect_inner() \
+       (void) GC_try_to_collect_inner(GC_never_stop_func)
+void GC_finish_collection();   /* Finish collection.  Mark bits are    */
+                               /* consistent and lock is still held.   */
+bool GC_collect_or_expand(/* needed_blocks */);
+                               /* Collect or expand heap in an attempt */
+                               /* make the indicated number of free    */
+                               /* blocks available.  Should be called  */
+                               /* until the blocks are available or    */
+                               /* until it fails by returning FALSE.   */
+void GC_init();                        /* Initialize collector.                */
+void GC_collect_a_little_inner(/* int n */);
+                               /* Do n units worth of garbage          */
+                               /* collection work, if appropriate.     */
+                               /* A unit is an amount appropriate for  */
+                               /* HBLKSIZE bytes of allocation.        */
+ptr_t GC_generic_malloc(/* bytes, kind */);
+                               /* Allocate an object of the given      */
+                               /* kind.  By default, there are only    */
+                               /* two kinds: composite, and atomic.    */
+                               /* We claim it's possible for clever    */
+                               /* client code that understands GC      */
+                               /* internals to add more, e.g. to       */
+                               /* communicate object layout info       */
+                               /* to the collector.                    */
+ptr_t GC_generic_malloc_inner(/* bytes, kind */);
+                               /* Ditto, but I already hold lock, etc. */
+ptr_t GC_generic_malloc_words_small(/*words, kind*/);
+                               /* As above, but size in units of words */
+                               /* Bypasses MERGE_SIZES.  Assumes       */
+                               /* words <= MAXOBJSZ.                   */
+ptr_t GC_generic_malloc_inner_ignore_off_page(/* bytes, kind */);
+                               /* Allocate an object, where            */
+                               /* the client guarantees that there     */
+                               /* will always be a pointer to the      */
+                               /* beginning of the object while the    */
+                               /* object is live.                      */
+ptr_t GC_allocobj(/* sz_inn_words, kind */);
+                               /* Make the indicated                   */
+                               /* free list nonempty, and return its   */
+                               /* head.                                */
+
+void GC_init_headers();
+bool GC_install_header(/*h*/);
+                               /* Install a header for block h.        */
+                               /* Return FALSE on failure.             */
+bool GC_install_counts(/*h, sz*/);
+                               /* Set up forwarding counts for block   */
+                               /* h of size sz.                        */
+                               /* Return FALSE on failure.             */
+void GC_remove_header(/*h*/);
+                               /* Remove the header for block h.       */
+void GC_remove_counts(/*h, sz*/);
+                               /* Remove forwarding counts for h.      */
+hdr * GC_find_header(/*p*/);   /* Debugging only.                      */
+
+void GC_finalize();    /* Perform all indicated finalization actions   */
+                       /* on unmarked objects.                         */
+                       /* Unreachable finalizable objects are enqueued */
+                       /* for processing by GC_invoke_finalizers.      */
+                       /* Invoked with lock.                           */
+void GC_invoke_finalizers();   /* Run eligible finalizers.     */
+                               /* Invoked without lock.        */      
+                       
+void GC_add_to_heap(/*p, bytes*/);
+                       /* Add a HBLKSIZE aligned chunk to the heap.    */
+
+void GC_print_obj(/* ptr_t p */);
+                       /* P points to somewhere inside an object with  */
+                       /* debugging info.  Print a human readable      */
+                       /* description of the object to stderr.         */
+extern void (*GC_check_heap)();
+                       /* Check that all objects in the heap with      */
+                       /* debugging info are intact.  Print            */
+                       /* descriptions of any that are not.            */
+                       
+/* Virtual dirty bit implementation:           */
+/* Each implementation exports the following:  */
+void GC_read_dirty();  /* Retrieve dirty bits. */
+bool GC_page_was_dirty(/* struct hblk * h  */);
+                       /* Read retrieved dirty bits.   */
+bool GC_page_was_ever_dirty(/* struct hblk * h  */);
+                       /* Could the page contain valid heap pointers?  */
+void GC_is_fresh(/* struct hblk * h, word number_of_blocks  */);
+                       /* Assert the region currently contains no      */
+                       /* valid pointers.                              */
+void GC_write_hint(/* struct hblk * h  */);
+                       /* h is about to be written.    */
+void GC_dirty_init();
+
+/* Slow/general mark bit manipulation: */
+bool GC_is_marked();
+void GC_clear_mark_bit();
+void GC_set_mark_bit();
+
+/* Stubborn objects: */
+void GC_read_changed();        /* Analogous to GC_read_dirty */
+bool GC_page_was_changed(/* h */);     /* Analogous to GC_page_was_dirty */
+void GC_clean_changing_list(); /* Collect obsolete changing list entries */
+void GC_stubborn_init();
+
+/* Debugging print routines: */
+void GC_print_block_list();
+void GC_print_hblkfreelist();
+void GC_print_heap_sects();
+void GC_print_static_roots();
+void GC_dump();
+
+/* Make arguments appear live to compiler */
+void GC_noop();
+
+/* Logging and diagnostic output:      */
+void GC_printf GC_PROTO((char * format, long, long, long, long, long, long));
+                       /* A version of printf that doesn't allocate,   */
+                       /* is restricted to long arguments, and         */
+                       /* (unfortunately) doesn't use varargs for      */
+                       /* portability.  Restricted to 6 args and       */
+                       /* 1K total output length.                      */
+                       /* (We use sprintf.  Hopefully that doesn't     */
+                       /* allocate for long arguments.)                */
+# define GC_printf0(f) GC_printf(f, 0l, 0l, 0l, 0l, 0l, 0l)
+# define GC_printf1(f,a) GC_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
+# define GC_printf2(f,a,b) GC_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
+# define GC_printf3(f,a,b,c) GC_printf(f, (long)a, (long)b, (long)c, 0l, 0l, 0l)
+# define GC_printf4(f,a,b,c,d) GC_printf(f, (long)a, (long)b, (long)c, \
+                                           (long)d, 0l, 0l)
+# define GC_printf5(f,a,b,c,d,e) GC_printf(f, (long)a, (long)b, (long)c, \
+                                             (long)d, (long)e, 0l)
+# define GC_printf6(f,a,b,c,d,e,g) GC_printf(f, (long)a, (long)b, (long)c, \
+                                               (long)d, (long)e, (long)g)
+
+void GC_err_printf(/* format, a, b, c, d, e, f */);
+# define GC_err_printf0(f) GC_err_puts(f)
+# define GC_err_printf1(f,a) GC_err_printf(f, (long)a, 0l, 0l, 0l, 0l, 0l)
+# define GC_err_printf2(f,a,b) GC_err_printf(f, (long)a, (long)b, 0l, 0l, 0l, 0l)
+# define GC_err_printf3(f,a,b,c) GC_err_printf(f, (long)a, (long)b, (long)c, \
+                                                 0l, 0l, 0l)
+# define GC_err_printf4(f,a,b,c,d) GC_err_printf(f, (long)a, (long)b, \
+                                                   (long)c, (long)d, 0l, 0l)
+# define GC_err_printf5(f,a,b,c,d,e) GC_err_printf(f, (long)a, (long)b, \
+                                                     (long)c, (long)d, \
+                                                     (long)e, 0l)
+# define GC_err_printf6(f,a,b,c,d,e,g) GC_err_printf(f, (long)a, (long)b, \
+                                                       (long)c, (long)d, \
+                                                       (long)e, (long)g)
+                       /* Ditto, writes to stderr.                     */
+                       
+void GC_err_puts(/* char *s */);
+                       /* Write s to stderr, don't buffer, don't add   */
+                       /* newlines, don't ...                          */
+
+# endif /* GC_PRIVATE_H */
diff --git a/include/weakpointer.h b/include/weakpointer.h
new file mode 100644 (file)
index 0000000..84906b0
--- /dev/null
@@ -0,0 +1,221 @@
+#ifndef        _weakpointer_h_
+#define        _weakpointer_h_
+
+/****************************************************************************
+
+WeakPointer and CleanUp
+
+    Copyright (c) 1991 by Xerox Corporation.  All rights reserved.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+    OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to copy this code for any purpose,
+    provided the above notices are retained on all copies.
+
+    Last modified on Mon Jul 17 18:16:01 PDT 1995 by ellis
+
+****************************************************************************/
+
+/****************************************************************************
+
+WeakPointer
+
+A weak pointer is a pointer to a heap-allocated object that doesn't
+prevent the object from being garbage collected. Weak pointers can be
+used to track which objects haven't yet been reclaimed by the
+collector. A weak pointer is deactivated when the collector discovers
+its referent object is unreachable by normal pointers (reachability
+and deactivation are defined more precisely below). A deactivated weak
+pointer remains deactivated forever.
+
+****************************************************************************/
+
+
+template< class T > class WeakPointer {
+public:
+
+WeakPointer( T* t = 0 )
+    /* Constructs a weak pointer for *t. t may be null. It is an error
+       if t is non-null and *t is not a collected object. */
+    {impl = _WeakPointer_New( t );}
+
+T* Pointer()
+    /* wp.Pointer() returns a pointer to the referent object of wp or
+       null if wp has been deactivated (because its referent object
+       has been discovered unreachable by the collector). */
+    {return (T*) _WeakPointer_Pointer( this->impl );}
+
+int operator==( WeakPointer< T > wp2 )
+    /* Given weak pointers wp1 and wp2, if wp1 == wp2, then wp1 and
+       wp2 refer to the same object. If wp1 != wp2, then either wp1
+       and wp2 don't refer to the same object, or if they do, one or
+       both of them has been deactivated. (Note: If objects t1 and t2
+       are never made reachable by their clean-up functions, then
+       WeakPointer<T>(t1) == WeakPointer<T>(t2) if and only t1 == t2.) */
+    {return _WeakPointer_Equal( this->impl, wp2.impl );}
+
+int Hash()
+    /* Returns a hash code suitable for use by multiplicative- and
+       division-based hash tables. If wp1 == wp2, then wp1.Hash() ==
+       wp2.Hash(). */
+    {return _WeakPointer_Hash( this->impl );}
+
+private:
+void* impl;
+};
+
+/*****************************************************************************
+
+CleanUp
+
+A garbage-collected object can have an associated clean-up function
+that will be invoked some time after the collector discovers the
+object is unreachable via normal pointers. Clean-up functions can be
+used to release resources such as open-file handles or window handles
+when their containing objects become unreachable.  If a C++ object has
+a non-empty explicit destructor (i.e. it contains programmer-written
+code), the destructor will be automatically registered as the object's
+initial clean-up function.
+
+There is no guarantee that the collector will detect every unreachable
+object (though it will find almost all of them). Clients should not
+rely on clean-up to cause some action to occur immediately -- clean-up
+is only a mechanism for improving resource usage.
+
+Every object with a clean-up function also has a clean-up queue. When
+the collector finds the object is unreachable, it enqueues it on its
+queue. The clean-up function is applied when the object is removed
+from the queue. By default, objects are enqueued on the garbage
+collector's queue, and the collector removes all objects from its
+queue after each collection. If a client supplies another queue for
+objects, it is his responsibility to remove objects (and cause their
+functions to be called) by polling it periodically.
+
+Clean-up queues allow clean-up functions accessing global data to
+synchronize with the main program. Garbage collection can occur at any
+time, and clean-ups invoked by the collector might access data in an
+inconsistent state. A client can control this by defining an explicit
+queue for objects and polling it at safe points.
+
+The following definitions are used by the specification below:
+
+Given a pointer t to a collected object, the base object BO(t) is the
+value returned by new when it created the object. (Because of multiple
+inheritance, t and BO(t) may not be the same address.)
+
+A weak pointer wp references an object *t if BO(wp.Pointer()) ==
+BO(t).
+
+***************************************************************************/
+
+template< class T, class Data > class CleanUp {
+public:
+
+static void Set( T* t, void c( Data* d, T* t ), Data* d = 0 )
+    /* Sets the clean-up function of object BO(t) to be <c, d>,
+       replacing any previously defined clean-up function for BO(t); c
+       and d can be null, but t cannot. Sets the clean-up queue for
+       BO(t) to be the collector's queue. When t is removed from its
+       clean-up queue, its clean-up will be applied by calling c(d,
+       t). It is an error if *t is not a collected object. */ 
+       {_CleanUp_Set( t, c, d );}
+
+static void Call( T* t )
+    /* Sets the new clean-up function for BO(t) to be null and, if the
+       old one is non-null, calls it immediately, even if BO(t) is
+       still reachable. Deactivates any weak pointers to BO(t). */
+       {_CleanUp_Call( t );}
+
+class Queue {public:
+    Queue()
+        /* Constructs a new queue. */
+            {this->head = _CleanUp_Queue_NewHead();}
+
+    void Set( T* t )
+        /* q.Set(t) sets the clean-up queue of BO(t) to be q. */
+            {_CleanUp_Queue_Set( this->head, t );}
+
+    int Call()
+        /* If q is non-empty, q.Call() removes the first object and
+           calls its clean-up function; does nothing if q is
+           empty. Returns true if there are more objects in the
+           queue. */
+           {return _CleanUp_Queue_Call( this->head );}
+
+    private:
+    void* head;
+    };
+};
+
+/**********************************************************************
+
+Reachability and Clean-up
+
+An object O is reachable if it can be reached via a non-empty path of
+normal pointers from the registers, stacks, global variables, or an
+object with a non-null clean-up function (including O itself),
+ignoring pointers from an object to itself.
+
+This definition of reachability ensures that if object B is accessible
+from object A (and not vice versa) and if both A and B have clean-up
+functions, then A will always be cleaned up before B. Note that as
+long as an object with a clean-up function is contained in a cycle of
+pointers, it will always be reachable and will never be cleaned up or
+collected.
+
+When the collector finds an unreachable object with a null clean-up
+function, it atomically deactivates all weak pointers referencing the
+object and recycles its storage. If object B is accessible from object
+A via a path of normal pointers, A will be discovered unreachable no
+later than B, and a weak pointer to A will be deactivated no later
+than a weak pointer to B.
+
+When the collector finds an unreachable object with a non-null
+clean-up function, the collector atomically deactivates all weak
+pointers referencing the object, redefines its clean-up function to be
+null, and enqueues it on its clean-up queue. The object then becomes
+reachable again and remains reachable at least until its clean-up
+function executes.
+
+The clean-up function is assured that its argument is the only
+accessible pointer to the object. Nothing prevents the function from
+redefining the object's clean-up function or making the object
+reachable again (for example, by storing the pointer in a global
+variable).
+
+If the clean-up function does not make its object reachable again and
+does not redefine its clean-up function, then the object will be
+collected by a subsequent collection (because the object remains
+unreachable and now has a null clean-up function). If the clean-up
+function does make its object reachable again and a clean-up function
+is subsequently redefined for the object, then the new clean-up
+function will be invoked the next time the collector finds the object
+unreachable.
+
+Note that a destructor for a collected object cannot safely redefine a
+clean-up function for its object, since after the destructor executes,
+the object has been destroyed into "raw memory". (In most
+implementations, destroying an object mutates its vtbl.)
+
+Finally, note that calling delete t on a collected object first
+deactivates any weak pointers to t and then invokes its clean-up
+function (destructor).
+
+**********************************************************************/
+
+extern "C" {
+    void* _WeakPointer_New( void* t );
+    void* _WeakPointer_Pointer( void* wp );
+    int _WeakPointer_Equal( void* wp1, void* wp2 );
+    int _WeakPointer_Hash( void* wp );
+    void _CleanUp_Set( void* t, void (*c)( void* d, void* t ), void* d );
+    void _CleanUp_Call( void* t );
+    void* _CleanUp_Queue_NewHead ();
+    void _CleanUp_Queue_Set( void* h, void* t );
+    int _CleanUp_Queue_Call( void* h );
+}
+
+#endif /* _weakpointer_h_ */
+
+
index 7c44de5..7fa43b1 100644 (file)
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, December 12, 1994 5:03 pm PST */
+/* Boehm, September 14, 1995 12:42 pm PDT */
 # include "gc_priv.h"
 # include <stdio.h>
 # include <setjmp.h>
 
 asm static void PushMacRegisters()
 {
-       sub.w   #4,sp                   // reserve space for one parameter.
+    sub.w   #4,sp                   // reserve space for one parameter.
     move.l  a2,(sp)
     jsr                GC_push_one
     move.l  a3,(sp)
     jsr                GC_push_one
     move.l  a4,(sp)
     jsr                GC_push_one
-       // skip a5 (globals), a6 (frame pointer), and a7 (stack pointer)
+       // <pcb> perhaps a6 should be pushed if stack frames arent being used.
+    move.l  a6,(sp)
+    jsr     GC_push_one
+       // skip a5 (globals), and a7 (stack pointer)
     move.l  d2,(sp)
     jsr                GC_push_one
     move.l  d3,(sp)
@@ -47,8 +50,8 @@ asm static void PushMacRegisters()
     jsr                GC_push_one
     move.l  d7,(sp)
     jsr                GC_push_one
-       add.w   #4,sp                   // fix stack.
-       rts
+    add.w   #4,sp                   // fix stack.
+    rts
 }
 
 #endif /* __MWERKS__ */
@@ -163,17 +166,29 @@ void GC_push_regs()
 #      endif   /* __MWERKS__ */
 #   endif      /* MACOS */
 
-#       if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) && !defined(SCO)
+#       if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) && !defined(SCO) && (!defined(LINUX) || !defined(__ELF__))
        /* I386 code, generic code does not appear to work */
        /* It does appear to work under OS2, and asms dont */
          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");
+         asm("pushl %ebp");  asm("call _GC_push_one"); asm("addl $4,%esp");
          asm("pushl %esi");  asm("call _GC_push_one"); asm("addl $4,%esp");
          asm("pushl %edi");  asm("call _GC_push_one"); asm("addl $4,%esp");
          asm("pushl %ebx");  asm("call _GC_push_one"); asm("addl $4,%esp");
 #       endif
 
+#      if defined(I386) && defined(LINUX) && defined(__ELF__)
+       /* This is modified for Linux with ELF (Note: _ELF_ only) */
+         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");
+         asm("pushl %ebp");  asm("call GC_push_one"); asm("addl $4,%esp");
+         asm("pushl %esi");  asm("call GC_push_one"); asm("addl $4,%esp");
+         asm("pushl %edi");  asm("call GC_push_one"); asm("addl $4,%esp");
+         asm("pushl %ebx");  asm("call GC_push_one"); asm("addl $4,%esp");
+#      endif
+
 #       if defined(I386) && defined(MSWIN32)
        /* I386 code, Microsoft variant         */
          __asm  push eax
index 67e00fc..f6a9628 100644 (file)
--- a/malloc.c
+++ b/malloc.c
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, June 13, 1995 3:07 pm PDT */
+/* Boehm, July 31, 1995 5:02 pm PDT */
  
 #include <stdio.h>
 #include "gc_priv.h"
@@ -163,7 +163,7 @@ register int k;
   register size_t lb;
 # endif
 {
-    return((extern_ptr_t)GC_generic_malloc_ignore_off_page(lb, NORMAL));
+    return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, NORMAL));
 }
 
 # if defined(__STDC__) || defined(__cplusplus)
@@ -173,7 +173,7 @@ register int k;
   register size_t lb;
 # endif
 {
-    return((extern_ptr_t)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
+    return((GC_PTR)GC_generic_malloc_ignore_off_page(lb, PTRFREE));
 }
 
 ptr_t GC_generic_malloc(lb, k)
@@ -296,15 +296,15 @@ void * GC_malloc_many(size_t lb)
 # endif
 
 #define GENERAL_MALLOC(lb,k) \
-    (extern_ptr_t)GC_clear_stack(GC_generic_malloc((word)lb, k))
+    (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
 /* We make the GC_clear_stack_call a tail call, hoping to get more of  */
 /* the stack.                                                          */
 
 /* Allocate lb bytes of atomic (pointerfree) data */
 # ifdef __STDC__
-    extern_ptr_t GC_malloc_atomic(size_t lb)
+    GC_PTR GC_malloc_atomic(size_t lb)
 # else
-    extern_ptr_t GC_malloc_atomic(lb)
+    GC_PTR GC_malloc_atomic(lb)
     size_t lb;
 # endif
 {
@@ -329,7 +329,7 @@ DCL_LOCK_STATE;
         *opp = obj_link(op);
         GC_words_allocd += lw;
         FASTUNLOCK();
-        return((extern_ptr_t) op);
+        return((GC_PTR) op);
    } else {
        return(GENERAL_MALLOC((word)lb, PTRFREE));
    }
@@ -337,9 +337,9 @@ DCL_LOCK_STATE;
 
 /* Allocate lb bytes of composite (pointerful) data */
 # ifdef __STDC__
-    extern_ptr_t GC_malloc(size_t lb)
+    GC_PTR GC_malloc(size_t lb)
 # else
-    extern_ptr_t GC_malloc(lb)
+    GC_PTR GC_malloc(lb)
     size_t lb;
 # endif
 {
@@ -365,7 +365,7 @@ DCL_LOCK_STATE;
         obj_link(op) = 0;
         GC_words_allocd += lw;
         FASTUNLOCK();
-        return((extern_ptr_t) op);
+        return((GC_PTR) op);
    } else {
        return(GENERAL_MALLOC((word)lb, NORMAL));
    }
@@ -373,9 +373,9 @@ DCL_LOCK_STATE;
 
 # ifdef REDIRECT_MALLOC
 # ifdef __STDC__
-    extern_ptr_t malloc(size_t lb)
+    GC_PTR malloc(size_t lb)
 # else
-    extern_ptr_t malloc(lb)
+    GC_PTR malloc(lb)
     size_t lb;
 # endif
   {
@@ -386,9 +386,9 @@ DCL_LOCK_STATE;
   }
 
 # ifdef __STDC__
-    extern_ptr_t calloc(size_t n, size_t lb)
+    GC_PTR calloc(size_t n, size_t lb)
 # else
-    extern_ptr_t calloc(n, lb)
+    GC_PTR calloc(n, lb)
     size_t n, lb;
 # endif
   {
@@ -398,9 +398,9 @@ DCL_LOCK_STATE;
 
 /* Allocate lb bytes of pointerful, traced, but not collectable data */
 # ifdef __STDC__
-    extern_ptr_t GC_malloc_uncollectable(size_t lb)
+    GC_PTR GC_malloc_uncollectable(size_t lb)
 # else
-    extern_ptr_t GC_malloc_uncollectable(lb)
+    GC_PTR GC_malloc_uncollectable(lb)
     size_t lb;
 # endif
 {
@@ -412,7 +412,8 @@ DCL_LOCK_STATE;
     if( SMALL_OBJ(lb) ) {
 #       ifdef MERGE_SIZES
 #        ifdef ADD_BYTE_AT_END
-           lb--; /* We don't need the extra byte, since this won't be  */
+           if (lb != 0) lb--;
+                 /* We don't need the extra byte, since this won't be  */
                  /* collected anyway.                                  */
 #        endif
          lw = GC_size_map[lb];
@@ -429,7 +430,7 @@ DCL_LOCK_STATE;
             GC_set_mark_bit(op);
             GC_non_gc_bytes += WORDS_TO_BYTES(lw);
             FASTUNLOCK();
-            return((extern_ptr_t) op);
+            return((GC_PTR) op);
         }
         FASTUNLOCK();
         op = (ptr_t)GC_generic_malloc((word)lb, UNCOLLECTABLE);
@@ -451,11 +452,11 @@ DCL_LOCK_STATE;
        GC_non_gc_bytes += WORDS_TO_BYTES(lw);
        UNLOCK();
        ENABLE_SIGNALS();
-       return((extern_ptr_t) op);
+       return((GC_PTR) op);
     }
 }
 
-extern_ptr_t GC_generic_or_special_malloc(lb,knd)
+GC_PTR GC_generic_or_special_malloc(lb,knd)
 word lb;
 int knd;
 {
@@ -481,10 +482,10 @@ int knd;
 /* The kind (e.g. atomic) is the same as that of the old.            */
 /* Shrinking of large blocks is not implemented well.                 */
 # ifdef __STDC__
-    extern_ptr_t GC_realloc(extern_ptr_t p, size_t lb)
+    GC_PTR GC_realloc(GC_PTR p, size_t lb)
 # else
-    extern_ptr_t GC_realloc(p,lb)
-    extern_ptr_t p;
+    GC_PTR GC_realloc(p,lb)
+    GC_PTR p;
     size_t lb;
 # endif
 {
@@ -530,7 +531,7 @@ int obj_kind;
            return(p);
        } else {
            /* shrink */
-             extern_ptr_t result =
+             GC_PTR result =
                        GC_generic_or_special_malloc((word)lb, obj_kind);
 
              if (result == 0) return(0);
@@ -542,7 +543,7 @@ int obj_kind;
        }
     } else {
        /* grow */
-         extern_ptr_t result =
+         GC_PTR result =
                GC_generic_or_special_malloc((word)lb, obj_kind);
 
          if (result == 0) return(0);
@@ -554,10 +555,10 @@ int obj_kind;
 
 # ifdef REDIRECT_MALLOC
 # ifdef __STDC__
-    extern_ptr_t realloc(extern_ptr_t p, size_t lb)
+    GC_PTR realloc(GC_PTR p, size_t lb)
 # else
-    extern_ptr_t realloc(p,lb)
-    extern_ptr_t p;
+    GC_PTR realloc(p,lb)
+    GC_PTR p;
     size_t lb;
 # endif
   {
@@ -567,10 +568,10 @@ int obj_kind;
 
 /* Explicitly deallocate an object p.                          */
 # ifdef __STDC__
-    void GC_free(extern_ptr_t p)
+    void GC_free(GC_PTR p)
 # else
     void GC_free(p)
-    extern_ptr_t p;
+    GC_PTR p;
 # endif
 {
     register struct hblk *h;
@@ -620,10 +621,10 @@ int obj_kind;
 
 # ifdef REDIRECT_MALLOC
 #   ifdef __STDC__
-      void free(extern_ptr_t p)
+      void free(GC_PTR p)
 #   else
       void free(p)
-      extern_ptr_t p;
+      GC_PTR p;
 #   endif
   {
       GC_free(p);
diff --git a/mark.c b/mark.c
index 8fcd49f..c55f80a 100644 (file)
--- a/mark.c
+++ b/mark.c
@@ -35,7 +35,7 @@ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
                0 | DS_LENGTH, FALSE, FALSE },
 /* NORMAL  */ { &GC_objfreelist[0], 0,
 #              ifdef ADD_BYTE_AT_END
-               (word)(WORDS_TO_BYTES(-1)) | DS_LENGTH,
+               (word)(-ALIGNMENT) | DS_LENGTH,
 #              else
                0 | DS_LENGTH,
 #              endif
index 0b7a48a..c5883fa 100644 (file)
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, April 18, 1995 3:04 pm PDT */
+/* Boehm, October 9, 1995 1:06 pm PDT */
 # include <stdio.h>
 # include "gc_priv.h"
 
@@ -275,7 +275,7 @@ bool tmp;
     n_root_sets++;
 }
 
-void GC_clear_roots(NO_PARAMS)
+void GC_clear_roots GC_PROTO((void))
 {
     DCL_LOCK_STATE;
     
diff --git a/misc.c b/misc.c
index b0e7e43..4dd68fa 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, May 2, 1995 11:20 am PDT */
+/* Boehm, July 31, 1995 5:02 pm PDT */
 
 
 #include <stdio.h>
@@ -182,13 +182,6 @@ word GC_high_water;
                        /* "hottest" stack pointer value we have seen   */
                        /* recently.  Degrades over time.               */
 
-word GC_stack_upper_bound()
-{
-    word dummy;
-    
-    return((word)(&dummy));
-}
-
 word GC_words_allocd_at_reset;
 
 #if defined(ASM_CLEAR_CODE) && !defined(THREADS)
@@ -215,6 +208,7 @@ word limit;
 }
 #endif
 
+extern ptr_t GC_approx_sp();   /* in mark_rts.c */
 
 /* Clear some of the inaccessible part of the stack.  Returns its      */
 /* argument, so it can be used in a tail call position, hence clearing  */
@@ -222,7 +216,7 @@ word limit;
 ptr_t GC_clear_stack(arg)
 ptr_t arg;
 {
-    register word sp = GC_stack_upper_bound();
+    register word sp = (word)GC_approx_sp();  /* Hotter than actual sp */
     register word limit;
 #   ifdef THREADS
         word dummy[CLEAR_SIZE];;
@@ -282,20 +276,26 @@ ptr_t arg;
 /* Return a pointer to the base address of p, given a pointer to a     */
 /* an address within an object.  Return 0 o.w.                         */
 # ifdef __STDC__
-    extern_ptr_t GC_base(extern_ptr_t p)
+    GC_PTR GC_base(GC_PTR p)
 # else
-    extern_ptr_t GC_base(p)
-    extern_ptr_t p;
+    GC_PTR GC_base(p)
+    GC_PTR p;
 # endif
 {
     register word r;
     register struct hblk *h;
+    register bottom_index *bi;
     register hdr *candidate_hdr;
     register word limit;
     
     r = (word)p;
     h = HBLKPTR(r);
-    candidate_hdr = HDR(r);
+    GET_BI(r, bi);
+    if (bi == 0) {
+        /* Collector uninitialized. Nothing allocated yet. */
+        return(0);
+    }
+    candidate_hdr = HDR_FROM_BI(bi, r);
     if (candidate_hdr == 0) return(0);
     /* If it's a pointer to the middle of a large object, move it      */
     /* to the beginning.                                               */
@@ -335,7 +335,7 @@ ptr_t arg;
 #          endif
            if ((word)p >= limit) return(0);
        }
-    return((extern_ptr_t)r);
+    return((GC_PTR)r);
 }
 
 
@@ -343,10 +343,10 @@ ptr_t arg;
 /* (For small obects this also happens to work from interior pointers, */
 /* but that shouldn't be relied upon.)                                 */
 # ifdef __STDC__
-    size_t GC_size(extern_ptr_t p)
+    size_t GC_size(GC_PTR p)
 # else
     size_t GC_size(p)
-    extern_ptr_t p;
+    GC_PTR p;
 # endif
 {
     register int sz;
@@ -360,12 +360,12 @@ ptr_t arg;
     }
 }
 
-size_t GC_get_heap_size(NO_PARAMS)
+size_t GC_get_heap_size GC_PROTO(())
 {
     return ((size_t) GC_heapsize);
 }
 
-size_t GC_get_bytes_since_gc(NO_PARAMS)
+size_t GC_get_bytes_since_gc GC_PROTO(())
 {
     return ((size_t) WORDS_TO_BYTES(GC_words_allocd));
 }
@@ -511,7 +511,7 @@ void GC_init_inner()
 #   endif
 }
 
-void GC_enable_incremental(NO_PARAMS)
+void GC_enable_incremental GC_PROTO(())
 {
     DCL_LOCK_STATE;
     
index e728c37..ee00db0 100644 (file)
--- a/obj_map.c
+++ b/obj_map.c
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, May 19, 1994 1:59 pm PDT */
+/* Boehm, October 9, 1995 1:09 pm PDT */
   
 /* Routines for maintaining maps describing heap block
  * layouts for various object sizes.  Allows fast pointer validity checks
@@ -46,8 +46,13 @@ hdr *hhdr;
 
 /* Consider pointers that are offset bytes displaced from the beginning */
 /* of an object to be valid.                                            */
-void GC_register_displacement(offset) 
-word offset;
+
+# if defined(__STDC__) || defined(__cplusplus)
+    void GC_register_displacement(GC_word offset)
+# else
+    void GC_register_displacement(offset) 
+    GC_word offset;
+# endif
 {
 # ifndef ALL_INTERIOR_POINTERS
     DCL_LOCK_STATE;
index 1cf3240..5d5d186 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
  *
  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, May 2, 1995 11:20 am PDT */
+/* Boehm, October 3, 1995 6:39 pm PDT */
 
 # include "gc_priv.h"
+# ifdef LINUX
+    /* Ugly hack to get struct sigcontext_struct definition.  Required */
+    /* for some early 1.3.X releases.  Will hopefully go away soon.    */
+    /* in some later Linux releases, asm/sigcontext.h may have to      */
+    /* be included instead.                                            */
+#   define __KERNEL__
+#   include <asm/signal.h>
+#   undef __KERNEL__
+# endif
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
 #   include <sys/types.h>
 # endif
 /* Blatantly OS dependent routines, except for those that are related  */
 /* dynamic loading.                                                    */
 
+# if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)
+#   define NEED_FIND_LIMIT
+# endif
+
+# if defined(SUNOS4) & defined(DYNAMIC_LOADING)
+#   define NEED_FIND_LIMIT
+# endif
+
+# if defined(SVR4) || defined(AUX) || defined(DGUX)
+#   define NEED_FIND_LIMIT
+# endif
+
+#ifdef NEED_FIND_LIMIT
+#   include <setjmp.h>
+#endif
+
 #ifdef FREEBSD
 #  include <machine/trap.h>
 #endif
 
 #ifdef SUNOS5SIGS
 # include <sys/siginfo.h>
+# undef setjmp
+# undef longjmp
+# define setjmp(env) sigsetjmp(env, 1)
+# define longjmp(env, val) siglongjmp(env, val)
+# define jmp_buf sigjmp_buf
 #endif
 
 #ifdef PCR
@@ -160,7 +190,8 @@ void GC_enable_signals(void)
 
 # else
 
-#  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) && !defined(MACOS)
+#  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
+      && !defined(MACOS) && !defined(DJGPP)
 
 #   ifdef sigmask
        /* Use the traditional BSD interface */
@@ -339,18 +370,11 @@ ptr_t GC_get_stack_base()
 
 # else
 
-# if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)
-#   define NEED_FIND_LIMIT
-# endif
 
-# if defined(SUNOS4) & defined(DYNAMIC_LOADING)
-#   define NEED_FIND_LIMIT
-# endif
 
 # ifdef NEED_FIND_LIMIT
   /* Some tools to implement HEURISTIC2        */
 #   define MIN_PAGE_SIZE 256   /* Smallest conceivable page size, bytes */
-#   include <setjmp.h>
     /* static */ jmp_buf GC_jmp_buf;
     
     /*ARGSUSED*/
@@ -366,6 +390,47 @@ ptr_t GC_get_stack_base()
        typedef void (*handler)();
 #   endif
 
+#   ifdef SUNOS5SIGS
+       static struct sigaction oldact;
+#   else
+        static handler old_segv_handler, old_bus_handler;
+#   endif
+    
+    GC_setup_temporary_fault_handler()
+    {
+#      ifdef SUNOS5SIGS
+         struct sigaction      act;
+
+         act.sa_handler        = GC_fault_handler;
+          act.sa_flags          = SA_RESTART | SA_SIGINFO | SA_NODEFER;
+          /* The presence of SA_NODEFER represents yet another gross    */
+          /* hack.  Under Solaris 2.3, siglongjmp doesn't appear to     */
+          /* interact correctly with -lthread.  We hide the confusion   */
+          /* by making sure that signal handling doesn't affect the     */
+          /* signal mask.                                               */
+
+         (void) sigemptyset(&act.sa_mask);
+         (void) sigaction(SIGSEGV, &act, &oldact);
+#      else
+         old_segv_handler = signal(SIGSEGV, GC_fault_handler);
+#        ifdef SIGBUS
+           old_bus_handler = signal(SIGBUS, GC_fault_handler);
+#        endif
+#      endif
+    }
+    
+    GC_reset_fault_handler()
+    {
+#       ifdef SUNOS5SIGS
+         (void) sigaction(SIGSEGV, &oldact, 0);
+#       else
+         (void) signal(SIGSEGV, old_segv_handler);
+#        ifdef SIGBUS
+           (void) signal(SIGBUS, old_bus_handler);
+#        endif
+#       endif
+    }
+
     /* Return the first nonaddressible location > p (up) or    */
     /* the smallest location q s.t. [q,p] is addressible (!up).        */
     ptr_t GC_find_limit(p, up)
@@ -378,22 +443,8 @@ ptr_t GC_get_stack_base()
                /* static since it's only called once, with the         */
                /* allocation lock held.                                */
 
-#      ifdef SUNOS5SIGS
-         struct sigaction      act, oldact;
-
-         act.sa_handler                = GC_fault_handler;
-         act.sa_flags          = SA_RESTART | SA_SIGINFO;
-         (void) sigemptyset(&act.sa_mask);
-         (void) sigaction(SIGSEGV, &act, &oldact);
-#      else
-          static handler old_segv_handler, old_bus_handler;
-               /* See above for static declaration.                    */
 
-         old_segv_handler = signal(SIGSEGV, GC_fault_handler);
-#        ifdef SIGBUS
-           old_bus_handler = signal(SIGBUS, GC_fault_handler);
-#        endif
-#      endif
+       GC_setup_temporary_fault_handler();
        if (setjmp(GC_jmp_buf) == 0) {
            result = (ptr_t)(((word)(p))
                              & ~(MIN_PAGE_SIZE-1));
@@ -406,14 +457,7 @@ ptr_t GC_get_stack_base()
                GC_noop(*result);
            }
        }
-#       ifdef SUNOS5SIGS
-         (void) sigaction(SIGSEGV, &oldact, 0);
-#       else
-         (void) signal(SIGSEGV, old_segv_handler);
-#        ifdef SIGBUS
-           (void) signal(SIGBUS, old_bus_handler);
-#        endif
-#       endif
+       GC_reset_fault_handler();
        if (!up) {
            result += MIN_PAGE_SIZE;
        }
@@ -745,18 +789,30 @@ int * etext_addr;
     word next_page = ((text_end + (word)max_page_size - 1)
                      & ~((word)max_page_size - 1));
     word page_offset = (text_end & ((word)max_page_size - 1));
+    VOLATILE char * result = (char *)(next_page + page_offset);
+    /* Note that this isnt equivalent to just adding           */
+    /* max_page_size to &etext if &etext is at a page boundary */
     
-    return((char *)(next_page + page_offset));
+    GC_setup_temporary_fault_handler();
+    if (setjmp(GC_jmp_buf) == 0) {
+       /* Try writing to the address.  */
+       *result = *result;
+    } else {
+       /* We got here via a longjmp.  The address is not readable.     */
+       /* This is known to happen under Solaris 2.4 + gcc, which place */
+       /* string constants in the text segment, but after etext.       */
+       /* Use plan B.  Note that we now know there is a gap between    */
+       /* text and data segments, so plan A bought us something.       */
+       result = (char *)GC_find_limit((ptr_t)(DATAEND) - MIN_PAGE_SIZE, FALSE);
+    }
+    GC_reset_fault_handler();
+    return((char *)result);
 }
 # endif
 
 
 void GC_register_data_segments()
 {
-#   if !defined(NEXT) && !defined(MACOS)
-        extern int end;
-#   endif
 #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS)
 #     if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS)
        /* As of Solaris 2.3, the Solaris threads implementation        */
@@ -768,7 +824,7 @@ void GC_register_data_segments()
 
        GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
 #     else
-       GC_add_roots_inner(DATASTART, (char *)(&end), FALSE);
+       GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
 #     endif
 #   endif
 #   if !defined(PCR) && defined(NEXT)
@@ -996,7 +1052,7 @@ extern void GC_push_finalizer_structures();
 
 /* From stubborn.c: */
 # ifdef STUBBORN_ALLOC
-    extern extern_ptr_t * GC_changing_list_start;
+    extern GC_PTR * GC_changing_list_start;
 # endif
 
 
@@ -1218,7 +1274,6 @@ word addr;
     typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *);
 #endif
 #if defined(LINUX)
-#   include <asm/signal.h>
     typedef void (* REAL_SIG_PF)(int, struct sigcontext_struct);
 # endif
 
@@ -1414,7 +1469,7 @@ void GC_dirty_init()
       GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler);
       if (GC_old_bus_handler == SIG_IGN) {
         GC_err_printf0("Previously ignored bus error!?");
-        GC_old_bus_handler == SIG_DFL;
+        GC_old_bus_handler = SIG_DFL;
       }
       if (GC_old_bus_handler != SIG_DFL) {
 #      ifdef PRINTSTATS
@@ -1426,7 +1481,7 @@ void GC_dirty_init()
       GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
       if (GC_old_segv_handler == SIG_IGN) {
         GC_err_printf0("Previously ignored segmentation violation!?");
-        GC_old_segv_handler == SIG_DFL;
+        GC_old_segv_handler = SIG_DFL;
       }
       if (GC_old_segv_handler != SIG_DFL) {
 #      ifdef PRINTSTATS
@@ -1443,7 +1498,7 @@ void GC_dirty_init()
       }
       if (GC_old_segv_handler == SIG_IGN) {
             GC_err_printf0("Previously ignored segmentation violation!?");
-            GC_old_segv_handler == SIG_DFL;
+            GC_old_segv_handler = SIG_DFL;
       }
       if (GC_old_segv_handler != SIG_DFL) {
 #       ifdef PRINTSTATS
@@ -1970,19 +2025,16 @@ struct callinfo info[NFRAMES];
     GC_err_printf0("\tCall chain at allocation:\n");
     for (i = 0; i < NFRAMES; i++) {
        if (info[i].ci_pc == 0) break;
+       GC_err_printf0("\t\targs: ");
        for (j = 0; j < NARGS; j++) {
            if (j != 0) GC_err_printf0(", ");
            GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
                                        ~(info[i].ci_arg[j]));
        }
-       GC_err_printf1("\t##PC##= 0x%X\n\t\targs: ", info[i].ci_pc);
-       GC_err_printf0("\n");
+       GC_err_printf1("\n\t\t##PC##= 0x%X\n", info[i].ci_pc);
     }
 }
 
 #endif /* SAVE_CALL_CHAIN */
 
 
-
-
-
index 65ac8d3..4d2cc8b 100644 (file)
@@ -10,7 +10,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, January 30, 1995 4:05 pm PST */
+/* Boehm, September 19, 1995 1:26 pm PDT */
 
 #include "gc_priv.h"
 #include "gc_mark.h"
@@ -35,9 +35,9 @@ void (*GC_same_obj_print_proc)() = GC_default_same_obj_print_proc;
 /* be called by production code, but this can easily make      */
 /* debugging intolerably slow.)                                        */
 #ifdef __STDC__
-  void * GC_same_obj(register void *p, register void *q)
+  GC_PTR GC_same_obj(register void *p, register void *q)
 #else
-  char * GC_same_obj(p, q)
+  GC_PTR GC_same_obj(p, q)
   register char *p, *q;
 #endif
 {
@@ -58,7 +58,7 @@ void (*GC_same_obj_print_proc)() = GC_default_same_obj_print_proc;
     /* If it's a pointer to the middle of a large object, move it      */
     /* to the beginning.                                               */
     if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
-       h = HBLKPTR(p) - (int)hhdr;
+       h = HBLKPTR(p) - (word)hhdr;
        hhdr = HDR(h);
        while (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
           h = FORWARDED_ADDR(h, hhdr);
@@ -184,6 +184,27 @@ ptr_t p;
 void (*GC_is_visible_print_proc)() = 
        GC_default_is_visible_print_proc;
 
+/* Could p be a stack address? */
+bool GC_on_stack(p)
+ptr_t p;
+{
+#   ifdef THREADS
+       return(TRUE);
+#   else
+       int dummy;
+#      ifdef STACK_GROWS_DOWN
+           if ((ptr_t)p >= (ptr_t)(&dummy) && (ptr_t)p < GC_stackbottom ) {
+               return(TRUE);
+           }
+#      else
+           if ((ptr_t)p <= (ptr_t)(&dummy) && (ptr_t)p > GC_stackbottom ) {
+               return(TRUE);
+           }
+#      endif
+       return(FALSE);
+#   endif
+}
+
 /* Check that p is visible                                             */
 /* to the collector as a possibly pointer containing location.         */
 /* If it isn't invoke *GC_is_visible_print_proc.                       */
@@ -200,7 +221,6 @@ void (*GC_is_visible_print_proc)() =
 #endif
 {
     register hdr *hhdr;
-    int dummy;
     
     if ((word)p & (ALIGNMENT - 1)) goto fail;
     if (!GC_is_initialized) GC_init();
@@ -214,15 +234,7 @@ void (*GC_is_visible_print_proc)() =
         }
 #   else
        /* Check stack first: */
-#        ifdef STACK_GROWS_DOWN
-           if ((ptr_t)p >= (ptr_t)(&dummy) && (ptr_t)p < GC_stackbottom ) {
-               return(p);
-           }
-#        else
-           if ((ptr_t)p <= (ptr_t)(&dummy) && (ptr_t)p > GC_stackbottom ) {
-               return(p);
-           }
-#        endif
+         if (GC_on_stack(p)) return(p);
        hhdr = HDR((word)p);
        if (hhdr == 0) {
            bool result;
@@ -274,3 +286,30 @@ fail:
     return(p);
 }
 
+
+GC_PTR GC_pre_incr (p, how_much)
+GC_PTR *p;
+size_t how_much;
+{
+    GC_PTR initial = *p;
+    GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
+    
+#   ifndef ALL_INTERIOR_POINTERS
+       (void) GC_is_valid_displacement(result);
+#   endif
+    return (*p = result);
+}
+
+GC_PTR GC_post_incr (p, how_much)
+GC_PTR *p;
+size_t how_much;
+{
+    GC_PTR initial = *p;
+    GC_PTR result = GC_same_obj((GC_PTR)((word)initial + how_much), initial);
+#   ifndef ALL_INTERIOR_POINTERS
+       (void) GC_is_valid_displacement(result);
+#   endif   
+    *p = result;
+    return(initial);
+}
index c877074..e26f65f 100644 (file)
@@ -10,7 +10,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, September 12, 1994 3:39 pm PDT */
+/* Boehm, September 21, 1995 5:39 pm PDT */
  
 /* Check whether setjmp actually saves registers in jmp_buf. */
 /* If it doesn't, the generic mark_regs code won't work.     */
@@ -24,6 +24,7 @@
 /* code.)                                                   */
 #include <stdio.h>
 #include <setjmp.h>
+#include <string.h>
 #include "config.h"
 
 #ifdef __hpux
@@ -95,9 +96,10 @@ main()
        int dummy;
        long ps = getpagesize();
        jmp_buf b;
-       register int x = strlen("a");  /* 1, slightly disguised */
+       register int x = (int)strlen("a");  /* 1, slightly disguised */
        static int y = 0;
 
+       printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
        if (nested_sp() < &dummy) {
          printf("Stack appears to grow down, which is the default.\n");
          printf("A good guess for STACKBOTTOM on this machine is 0x%X.\n",
@@ -110,6 +112,7 @@ main()
        }
        printf("Note that this may vary between machines of ostensibly\n");
        printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
+       printf("On many machines the value is not fixed.\n");
        printf("A good guess for ALIGNMENT on this machine is %d.\n",
               (unsigned long)(&(a.a_b))-(unsigned long)(&a));
        
index 0d09de8..ab228fb 100644 (file)
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, July 28, 1994 10:01 am PDT */
+/* Boehm, July 31, 1995 5:02 pm PDT */
 
 
 #include "gc_priv.h"
 extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
 
 #define GENERAL_MALLOC(lb,k) \
-    (extern_ptr_t)GC_clear_stack(GC_generic_malloc((word)lb, k))
+    (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
 
 /* Data structure representing immutable objects that  */
 /* are still being initialized.                                */
 /* This is a bit baroque in order to avoid acquiring   */
 /* the lock twice for a typical allocation.            */
 
-extern_ptr_t * GC_changing_list_start;
+GC_PTR * GC_changing_list_start;
 
 # ifdef THREADS
-  VOLATILE extern_ptr_t * VOLATILE GC_changing_list_current;
+  VOLATILE GC_PTR * VOLATILE GC_changing_list_current;
 # else
-  extern_ptr_t * GC_changing_list_current;
+  GC_PTR * GC_changing_list_current;
 # endif
        /* Points at last added element.  Also (ab)used for             */
        /* synchronization.  Updates and reads are assumed atomic.      */
 
-extern_ptr_t * GC_changing_list_limit;
+GC_PTR * GC_changing_list_limit;
        /* Points at the last word of the buffer, which is always 0     */
        /* All entries in (GC_changing_list_current,                    */
        /* GC_changing_list_limit] are 0                                */
@@ -49,12 +49,12 @@ void GC_stubborn_init()
 {
 #   define INIT_SIZE 10
 
-    GC_changing_list_start = (extern_ptr_t *)
+    GC_changing_list_start = (GC_PTR *)
                        GC_generic_malloc_inner(
-                               (word)(INIT_SIZE * sizeof(extern_ptr_t)),
+                               (word)(INIT_SIZE * sizeof(GC_PTR)),
                                PTRFREE);
     BZERO(GC_changing_list_start,
-         INIT_SIZE * sizeof(extern_ptr_t));
+         INIT_SIZE * sizeof(GC_PTR));
     if (GC_changing_list_start == 0) {
         GC_err_printf0("Insufficient space to start up\n");
         ABORT("GC_stubborn_init: put of space");
@@ -75,26 +75,26 @@ void GC_stubborn_init()
 /* Returns FALSE on failure.                                           */
 bool GC_compact_changing_list()
 {
-    register extern_ptr_t *p, *q;
+    register GC_PTR *p, *q;
     register word count = 0;
     word old_size = (char **)GC_changing_list_limit
                    - (char **)GC_changing_list_start+1;
                    /* The casts are needed as a workaround for an Amiga bug */
     register word new_size = old_size;
-    extern_ptr_t * new_list;
+    GC_PTR * new_list;
     
     for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
         if (*p != 0) count++;
     }
     if (2 * count > old_size) new_size = 2 * count;
-    new_list = (extern_ptr_t *)
+    new_list = (GC_PTR *)
                GC_generic_malloc_inner(
-                               new_size * sizeof(extern_ptr_t), PTRFREE);
+                               new_size * sizeof(GC_PTR), PTRFREE);
                /* PTRFREE is a lie.  But we don't want the collector to  */
                /* consider these.  We do want the list itself to be      */
                /* collectable.                                           */
     if (new_list == 0) return(FALSE);
-    BZERO(new_list, new_size * sizeof(extern_ptr_t));
+    BZERO(new_list, new_size * sizeof(GC_PTR));
     q = new_list;
     for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
         if (*p != 0) *q++ = *p;
@@ -120,7 +120,7 @@ bool GC_compact_changing_list()
        *GC_changing_list_current = p;
 
 void GC_change_stubborn(p)
-extern_ptr_t p;
+GC_PTR p;
 {
     DCL_LOCK_STATE;
     
@@ -132,12 +132,12 @@ extern_ptr_t p;
 }
 
 void GC_end_stubborn_change(p)
-extern_ptr_t p;
+GC_PTR p;
 {
 #   ifdef THREADS
-      register VOLATILE extern_ptr_t * my_current = GC_changing_list_current;
+      register VOLATILE GC_PTR * my_current = GC_changing_list_current;
 #   else
-      register extern_ptr_t * my_current = GC_changing_list_current;
+      register GC_PTR * my_current = GC_changing_list_current;
 #   endif
     register bool tried_quick;
     DCL_LOCK_STATE;
@@ -184,9 +184,9 @@ extern_ptr_t p;
 /* GC_end_stubborn_change(p) where p is the value      */
 /* returned by GC_malloc_stubborn.                     */
 # ifdef __STDC__
-    extern_ptr_t GC_malloc_stubborn(size_t lb)
+    GC_PTR GC_malloc_stubborn(size_t lb)
 # else
-    extern_ptr_t GC_malloc_stubborn(lb)
+    GC_PTR GC_malloc_stubborn(lb)
     size_t lb;
 # endif
 {
@@ -212,12 +212,12 @@ DCL_LOCK_STATE;
         *opp = obj_link(op);
         obj_link(op) = 0;
         GC_words_allocd += lw;
-        result = (extern_ptr_t) op;
+        result = (GC_PTR) op;
         ADD_CHANGING(result);
         FASTUNLOCK();
-        return((extern_ptr_t)result);
+        return((GC_PTR)result);
    } else {
-       result = (extern_ptr_t)
+       result = (GC_PTR)
                GC_generic_malloc((word)lb, STUBBORN);
    }
 record:
@@ -226,7 +226,7 @@ record:
    ADD_CHANGING(result);
    UNLOCK();
    ENABLE_SIGNALS();
-   return((extern_ptr_t)GC_clear_stack(result));
+   return((GC_PTR)GC_clear_stack(result));
 }
 
 
@@ -234,8 +234,8 @@ record:
 /* Report pages on which stubborn objects were changed.                */
 void GC_read_changed()
 {
-    register extern_ptr_t * p = GC_changing_list_start;
-    register extern_ptr_t q;
+    register GC_PTR * p = GC_changing_list_start;
+    register GC_PTR q;
     register struct hblk * h;
     register word index;
     
@@ -264,8 +264,8 @@ struct hblk * h;
 /* called with mark bits consistent and lock held.             */
 void GC_clean_changing_list()
 {
-    register extern_ptr_t * p = GC_changing_list_start;
-    register extern_ptr_t q;
+    register GC_PTR * p = GC_changing_list_start;
+    register GC_PTR q;
     register ptr_t r;
     register unsigned long count = 0;
     register unsigned long dropped_count = 0;
@@ -292,9 +292,9 @@ void GC_clean_changing_list()
 #else /* !STUBBORN_ALLOC */
 
 # ifdef __STDC__
-    extern_ptr_t GC_malloc_stubborn(size_t lb)
+    GC_PTR GC_malloc_stubborn(size_t lb)
 # else
-    extern_ptr_t GC_malloc_stubborn(lb)
+    GC_PTR GC_malloc_stubborn(lb)
     size_t lb;
 # endif
 {
@@ -303,13 +303,13 @@ void GC_clean_changing_list()
 
 /*ARGSUSED*/
 void GC_end_stubborn_change(p)
-extern_ptr_t p;
+GC_PTR p;
 {
 }
 
 /*ARGSUSED*/
 void GC_change_stubborn(p)
-extern_ptr_t p;
+GC_PTR p;
 {
 }
 
diff --git a/test.c b/test.c
index b64695d..035dad2 100644 (file)
--- a/test.c
+++ b/test.c
@@ -11,7 +11,7 @@
  * provided the above notices are retained, and a notice that the code was
  * modified is included with the above copyright notice.
  */
-/* Boehm, June 13, 1995 2:33 pm PDT */
+/* Boehm, September 21, 1995 5:43 pm PDT */
 /* An incomplete test for the garbage collector.               */
 /* Some more obscure entry points are not tested at all.       */
 
@@ -62,12 +62,6 @@ struct SEXPR {
 };
 
 
-# ifdef __STDC__
-    typedef void * void_star;
-# else
-    typedef char * void_star;
-# endif
-
 typedef struct SEXPR * sexpr;
 
 # define INT_TO_SEXPR(x) ((sexpr)(unsigned long)(x))
@@ -198,7 +192,7 @@ void check_ints(list, low, up)
 sexpr list;
 int low, up;
 {
-    if ((int)(car(car(list))) != low) {
+    if ((int)(GC_word)(car(car(list))) != low) {
         (void)GC_printf0(
            "List reversal produced incorrect list - collector is broken\n");
         FAIL;
@@ -219,7 +213,7 @@ void check_uncollectable_ints(list, low, up)
 sexpr list;
 int low, up;
 {
-    if ((int)(car(car(list))) != low) {
+    if ((int)(GC_word)(car(car(list))) != low) {
         (void)GC_printf0(
            "Uncollectable list corrupted - collector is broken\n");
         FAIL;
@@ -290,13 +284,13 @@ void reverse_test()
     e = uncollectable_ints(1, 1);
     /* Check that realloc updates object descriptors correctly */
     f = (sexpr *)GC_malloc(4 * sizeof(sexpr));
-    f = (sexpr *)GC_realloc(f, 6 * sizeof(sexpr));
+    f = (sexpr *)GC_realloc((GC_PTR)f, 6 * sizeof(sexpr));
     f[5] = ints(1,17);
     g = (sexpr *)GC_malloc(513 * sizeof(sexpr));
-    g = (sexpr *)GC_realloc(g, 800 * sizeof(sexpr));
+    g = (sexpr *)GC_realloc((GC_PTR)g, 800 * sizeof(sexpr));
     g[799] = ints(1,18);
     h = (sexpr *)GC_malloc(1025 * sizeof(sexpr));
-    h = (sexpr *)GC_realloc(h, 2000 * sizeof(sexpr));
+    h = (sexpr *)GC_realloc((GC_PTR)h, 2000 * sizeof(sexpr));
     h[1999] = ints(1,19);
     /* Try to force some collections and reuse of small list elements */
       for (i = 0; i < 10; i++) {
@@ -327,9 +321,9 @@ void reverse_test()
 #      if !defined(AT_END) && !defined(THREADS)
          /* This is not thread safe, since realloc explicitly deallocates */
           if (i & 1) {
-            a = (sexpr)GC_REALLOC((void_star)a, 500);
+            a = (sexpr)GC_REALLOC((GC_PTR)a, 500);
           } else {
-            a = (sexpr)GC_REALLOC((void_star)a, 8200);
+            a = (sexpr)GC_REALLOC((GC_PTR)a, 8200);
           }
 #      endif
     }
@@ -379,7 +373,7 @@ VOLATILE int dropped_something = 0;
     static mutex_t incr_lock;
     mutex_lock(&incr_lock);
 # endif
-  if ((int)client_data != t -> level) {
+  if ((int)(GC_word)client_data != t -> level) {
      (void)GC_printf0("Wrong finalization data - collector is broken\n");
      FAIL;
   }
@@ -456,28 +450,28 @@ int n;
 #        endif
        }
 
-        GC_REGISTER_FINALIZER((void_star)result, finalizer, (void_star)n,
-                             (GC_finalization_proc *)0, (void_star *)0);
+        GC_REGISTER_FINALIZER((GC_PTR)result, finalizer, (GC_PTR)(GC_word)n,
+                             (GC_finalization_proc *)0, (GC_PTR *)0);
         if (my_index >= MAX_FINALIZED) {
                GC_printf0("live_indicators overflowed\n");
                FAIL;
        }
         live_indicators[my_index] = 13;
         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
-               (void_star *)(&(live_indicators[my_index])),
-               (void_star)result) != 0) {
+               (GC_PTR *)(&(live_indicators[my_index])),
+               (GC_PTR)result) != 0) {
                GC_printf0("GC_general_register_disappearing_link failed\n");
                FAIL;
         }
         if (GC_unregister_disappearing_link(
-               (void_star *)
+               (GC_PTR *)
                   (&(live_indicators[my_index]))) == 0) {
                GC_printf0("GC_unregister_disappearing_link failed\n");
                FAIL;
         }
         if (GC_GENERAL_REGISTER_DISAPPEARING_LINK(
-               (void_star *)(&(live_indicators[my_index])),
-               (void_star)result) != 0) {
+               (GC_PTR *)(&(live_indicators[my_index])),
+               (GC_PTR)result) != 0) {
                GC_printf0("GC_general_register_disappearing_link failed 2\n");
                FAIL;
         }
@@ -682,6 +676,15 @@ void run_one_test()
            (void)GC_printf0("GC_size produced unexpected results\n");
            FAIL;
     }
+    if (GC_size(GC_malloc(0)) != 4 && GC_size(GC_malloc(0)) != 8) {
+       (void)GC_printf0("GC_malloc(0) failed\n");
+           FAIL;
+    }
+    if (GC_size(GC_malloc_uncollectable(0)) != 4
+        && GC_size(GC_malloc_uncollectable(0)) != 8) {
+       (void)GC_printf0("GC_malloc_uncollectable(0) failed\n");
+           FAIL;
+    }
     GC_is_valid_displacement_print_proc = fail_proc;
     GC_is_visible_print_proc = fail_proc;
     x = GC_malloc(16);
@@ -884,7 +887,8 @@ void SetMinimumStack(long minSize)
                GC_init, GC_make_closure, GC_debug_invoke_finalizer,
                GC_page_was_ever_dirty, GC_is_fresh,
                GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page,
-               GC_set_max_heap_size, GC_get_bytes_since_gc);
+               GC_set_max_heap_size, GC_get_bytes_since_gc,
+               GC_pre_incr, GC_post_incr);
 #   endif
     return(0);
 }
index f0615ea..6cd99d5 100644 (file)
@@ -10,7 +10,7 @@ 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.
 ****************************************************************************
-Last modified on Wed Jan  4 16:35:11 PST 1995 by ellis
+Last modified on Mon Jul 10 21:06:03 PDT 1995 by ellis
      modified on December 20, 1994 7:27 pm PST by boehm
 
 usage: test_cpp number-of-iterations
@@ -25,16 +25,29 @@ few minutes to complete.
 ***************************************************************************/
 
 #include "gc_cpp.h"
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+extern "C" {
+#include "gc_priv.h"
+}
+# ifdef MSWIN32
+#     include <windows.h>
+#     endif
+
+
+#define my_assert( e ) \
+    if (! (e)) { \
+        GC_printf1( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
+                    __LINE__ ); \
+        exit( 1 ); }
+
 
 class A {public:
     /* An uncollectable class. */
 
     A( int iArg ): i( iArg ) {}
     void Test( int iArg ) {
-        assert( i == iArg );} 
+        my_assert( i == iArg );} 
     int i;};
 
 
@@ -43,7 +56,7 @@ class B: public gc, public A {public:
 
     B( int j ): A( j ) {}
     ~B() {
-        assert( deleting );}
+        my_assert( deleting );}
     static void Deleting( int on ) {
         deleting = on;}
     static int deleting;};
@@ -64,13 +77,13 @@ class C: public gc_cleanup, public A {public:
     ~C() {
         this->A::Test( level );
         nFreed++;
-        assert( level == 0 ? 
+        my_assert( level == 0 ? 
                    left == 0 && right == 0 :
                    level == left->level + 1 && level == right->level + 1 );
         left = right = 0;
         level = -123456;}
     static void Test() {
-        assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );}
+        my_assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );}
 
     static int nFreed;
     static int nAllocated;
@@ -91,9 +104,9 @@ class D: public gc {public:
     static void CleanUp( void* obj, void* data ) {
         D* self = (D*) obj;
         nFreed++;
-        assert( self->i == (int) data );}
+        my_assert( self->i == (int) data );}
     static void Test() {
-        assert( nFreed >= .8 * nAllocated );}
+        my_assert( nFreed >= .8 * nAllocated );}
        
     int i;
     static int nFreed;
@@ -103,6 +116,41 @@ int D::nFreed = 0;
 int D::nAllocated = 0;
 
 
+class E: public gc_cleanup {public:
+    /* A collectable class with clean-up for use by F. */
+
+    E() {
+        nAllocated++;}
+    ~E() {
+        nFreed++;}
+
+    static int nFreed;
+    static int nAllocated;};
+    
+int E::nFreed = 0;
+int E::nAllocated = 0;
+   
+
+class F: public E {public:
+    /* A collectable class with clean-up, a base with clean-up, and a
+    member with clean-up. */
+
+    F() {
+        nAllocated++;}
+    ~F() {
+        nFreed++;}
+    static void Test() {
+        my_assert( nFreed >= .8 * nAllocated );
+        my_assert( 2 * nFreed == E::nFreed );}
+       
+    E e;
+    static int nFreed;
+    static int nAllocated;};
+    
+int F::nFreed = 0;
+int F::nAllocated = 0;
+   
+
 long Disguise( void* p ) {
     return ~ (long) p;}
 
@@ -110,15 +158,29 @@ void* Undisguise( long i ) {
     return (void*) ~ i;}
 
 
+#ifdef MSWIN32
+int APIENTRY WinMain(
+    HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int cmdShow ) 
+{
+    int argc;
+    char* argv[ 3 ];
+
+    for (argc = 1; argc < sizeof( argv ) / sizeof( argv[ 0 ] ); argc++) {
+        argv[ argc ] = strtok( argc == 1 ? cmd : 0, " \t" );
+        if (0 == argv[ argc ]) break;}
+
+#else
 int main( int argc, char* argv[] ) {
+#endif
+
     int i, iters, n;
 
     if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
-        fprintf( stderr, "usage: test_cpp number-of-iterations\n" );
+        GC_printf0( "usage: test_cpp number-of-iterations\n" );
         exit( 1 );}
         
     for (iters = 1; iters <= n; iters++) {
-        printf( "Starting iteration %d\n", iters );
+        GC_printf1( "Starting iteration %d\n", iters );
 
             /* Allocate some uncollectable As and disguise their pointers.
             Later we'll check to see if the objects are still there.  We're
@@ -129,12 +191,13 @@ int main( int argc, char* argv[] ) {
             as[ i ] = Disguise( new (NoGC) A( i ) );
             bs[ i ] = Disguise( new (NoGC) B( i ) );}
 
-            /* Allocate a fair number of finalizable Cs and Ds.  Later we'll
-            check to make sure they've gone away. */
+            /* Allocate a fair number of finalizable Cs, Ds, and Fs.
+            Later we'll check to make sure they've gone away. */
         for (i = 0; i < 1000; i++) {
             C* c = new C( 2 );
             C c1( 2 );           /* stack allocation should work too */
             D* d = ::new (GC, D::CleanUp, (void*) i) D( i );
+            F* f = new F;
             if (0 == i % 10) delete c;}
 
             /* Allocate a very large number of collectable As and Bs and
@@ -160,11 +223,13 @@ int main( int argc, char* argv[] ) {
             delete b;
             B::Deleting( 0 );}
 
-            /* Make sure most of the finalizable Cs and Ds have gone away. */
+            /* Make sure most of the finalizable Cs, Ds, and Fs have
+            gone away. */
         C::Test();
-        D::Test();}
+        D::Test();
+        F::Test();}
 
-    printf( "The test appears to have succeeded.\n" );
+    GC_printf0( "The test appears to have succeeded.\n" );
     return( 0 );}
     
 
index 1c4bd93..72fd421 100644 (file)
@@ -11,7 +11,7 @@
  * modified is included with the above copyright notice.
  *
  */
-/* Boehm, July 13, 1994 12:34 pm PDT */
+/* Boehm, July 31, 1995 5:02 pm PDT */
 
 
 /*
@@ -628,7 +628,7 @@ word env;
 ptr_t GC_clear_stack();
 
 #define GENERAL_MALLOC(lb,k) \
-    (extern_ptr_t)GC_clear_stack(GC_generic_malloc((word)lb, k))
+    (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
     
 #if defined(__STDC__) || defined(__cplusplus)
   extern void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
@@ -668,7 +668,7 @@ DCL_LOCK_STATE;
        lw = BYTES_TO_WORDS(GC_size(op));
    }
    ((word *)op)[lw - 1] = d;
-   return((extern_ptr_t) op);
+   return((GC_PTR) op);
 }
 
 #if defined(__STDC__) || defined(__cplusplus)
@@ -748,9 +748,9 @@ DCL_LOCK_STATE;
        /* Make sure the descriptor is cleared once there is any danger */
        /* it may have been collected.                                  */
        (void)
-         GC_general_register_disappearing_link((extern_ptr_t *)
+         GC_general_register_disappearing_link((GC_PTR *)
                                                  ((word *)op+lw-1),
-                                                         (extern_ptr_t) op);
+                                                         (GC_PTR) op);
        if (ff != GC_finalization_failures) {
            /* We may have failed to register op due to lack of memory. */
            /* We were out of memory very recently, so we can safely    */
@@ -759,5 +759,5 @@ DCL_LOCK_STATE;
            return(0);
        }                                 
    }
-   return((extern_ptr_t) op);
+   return((GC_PTR) op);
 }
diff --git a/weakpointer.h b/weakpointer.h
new file mode 100644 (file)
index 0000000..84906b0
--- /dev/null
@@ -0,0 +1,221 @@
+#ifndef        _weakpointer_h_
+#define        _weakpointer_h_
+
+/****************************************************************************
+
+WeakPointer and CleanUp
+
+    Copyright (c) 1991 by Xerox Corporation.  All rights reserved.
+
+    THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+    OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+    Permission is hereby granted to copy this code for any purpose,
+    provided the above notices are retained on all copies.
+
+    Last modified on Mon Jul 17 18:16:01 PDT 1995 by ellis
+
+****************************************************************************/
+
+/****************************************************************************
+
+WeakPointer
+
+A weak pointer is a pointer to a heap-allocated object that doesn't
+prevent the object from being garbage collected. Weak pointers can be
+used to track which objects haven't yet been reclaimed by the
+collector. A weak pointer is deactivated when the collector discovers
+its referent object is unreachable by normal pointers (reachability
+and deactivation are defined more precisely below). A deactivated weak
+pointer remains deactivated forever.
+
+****************************************************************************/
+
+
+template< class T > class WeakPointer {
+public:
+
+WeakPointer( T* t = 0 )
+    /* Constructs a weak pointer for *t. t may be null. It is an error
+       if t is non-null and *t is not a collected object. */
+    {impl = _WeakPointer_New( t );}
+
+T* Pointer()
+    /* wp.Pointer() returns a pointer to the referent object of wp or
+       null if wp has been deactivated (because its referent object
+       has been discovered unreachable by the collector). */
+    {return (T*) _WeakPointer_Pointer( this->impl );}
+
+int operator==( WeakPointer< T > wp2 )
+    /* Given weak pointers wp1 and wp2, if wp1 == wp2, then wp1 and
+       wp2 refer to the same object. If wp1 != wp2, then either wp1
+       and wp2 don't refer to the same object, or if they do, one or
+       both of them has been deactivated. (Note: If objects t1 and t2
+       are never made reachable by their clean-up functions, then
+       WeakPointer<T>(t1) == WeakPointer<T>(t2) if and only t1 == t2.) */
+    {return _WeakPointer_Equal( this->impl, wp2.impl );}
+
+int Hash()
+    /* Returns a hash code suitable for use by multiplicative- and
+       division-based hash tables. If wp1 == wp2, then wp1.Hash() ==
+       wp2.Hash(). */
+    {return _WeakPointer_Hash( this->impl );}
+
+private:
+void* impl;
+};
+
+/*****************************************************************************
+
+CleanUp
+
+A garbage-collected object can have an associated clean-up function
+that will be invoked some time after the collector discovers the
+object is unreachable via normal pointers. Clean-up functions can be
+used to release resources such as open-file handles or window handles
+when their containing objects become unreachable.  If a C++ object has
+a non-empty explicit destructor (i.e. it contains programmer-written
+code), the destructor will be automatically registered as the object's
+initial clean-up function.
+
+There is no guarantee that the collector will detect every unreachable
+object (though it will find almost all of them). Clients should not
+rely on clean-up to cause some action to occur immediately -- clean-up
+is only a mechanism for improving resource usage.
+
+Every object with a clean-up function also has a clean-up queue. When
+the collector finds the object is unreachable, it enqueues it on its
+queue. The clean-up function is applied when the object is removed
+from the queue. By default, objects are enqueued on the garbage
+collector's queue, and the collector removes all objects from its
+queue after each collection. If a client supplies another queue for
+objects, it is his responsibility to remove objects (and cause their
+functions to be called) by polling it periodically.
+
+Clean-up queues allow clean-up functions accessing global data to
+synchronize with the main program. Garbage collection can occur at any
+time, and clean-ups invoked by the collector might access data in an
+inconsistent state. A client can control this by defining an explicit
+queue for objects and polling it at safe points.
+
+The following definitions are used by the specification below:
+
+Given a pointer t to a collected object, the base object BO(t) is the
+value returned by new when it created the object. (Because of multiple
+inheritance, t and BO(t) may not be the same address.)
+
+A weak pointer wp references an object *t if BO(wp.Pointer()) ==
+BO(t).
+
+***************************************************************************/
+
+template< class T, class Data > class CleanUp {
+public:
+
+static void Set( T* t, void c( Data* d, T* t ), Data* d = 0 )
+    /* Sets the clean-up function of object BO(t) to be <c, d>,
+       replacing any previously defined clean-up function for BO(t); c
+       and d can be null, but t cannot. Sets the clean-up queue for
+       BO(t) to be the collector's queue. When t is removed from its
+       clean-up queue, its clean-up will be applied by calling c(d,
+       t). It is an error if *t is not a collected object. */ 
+       {_CleanUp_Set( t, c, d );}
+
+static void Call( T* t )
+    /* Sets the new clean-up function for BO(t) to be null and, if the
+       old one is non-null, calls it immediately, even if BO(t) is
+       still reachable. Deactivates any weak pointers to BO(t). */
+       {_CleanUp_Call( t );}
+
+class Queue {public:
+    Queue()
+        /* Constructs a new queue. */
+            {this->head = _CleanUp_Queue_NewHead();}
+
+    void Set( T* t )
+        /* q.Set(t) sets the clean-up queue of BO(t) to be q. */
+            {_CleanUp_Queue_Set( this->head, t );}
+
+    int Call()
+        /* If q is non-empty, q.Call() removes the first object and
+           calls its clean-up function; does nothing if q is
+           empty. Returns true if there are more objects in the
+           queue. */
+           {return _CleanUp_Queue_Call( this->head );}
+
+    private:
+    void* head;
+    };
+};
+
+/**********************************************************************
+
+Reachability and Clean-up
+
+An object O is reachable if it can be reached via a non-empty path of
+normal pointers from the registers, stacks, global variables, or an
+object with a non-null clean-up function (including O itself),
+ignoring pointers from an object to itself.
+
+This definition of reachability ensures that if object B is accessible
+from object A (and not vice versa) and if both A and B have clean-up
+functions, then A will always be cleaned up before B. Note that as
+long as an object with a clean-up function is contained in a cycle of
+pointers, it will always be reachable and will never be cleaned up or
+collected.
+
+When the collector finds an unreachable object with a null clean-up
+function, it atomically deactivates all weak pointers referencing the
+object and recycles its storage. If object B is accessible from object
+A via a path of normal pointers, A will be discovered unreachable no
+later than B, and a weak pointer to A will be deactivated no later
+than a weak pointer to B.
+
+When the collector finds an unreachable object with a non-null
+clean-up function, the collector atomically deactivates all weak
+pointers referencing the object, redefines its clean-up function to be
+null, and enqueues it on its clean-up queue. The object then becomes
+reachable again and remains reachable at least until its clean-up
+function executes.
+
+The clean-up function is assured that its argument is the only
+accessible pointer to the object. Nothing prevents the function from
+redefining the object's clean-up function or making the object
+reachable again (for example, by storing the pointer in a global
+variable).
+
+If the clean-up function does not make its object reachable again and
+does not redefine its clean-up function, then the object will be
+collected by a subsequent collection (because the object remains
+unreachable and now has a null clean-up function). If the clean-up
+function does make its object reachable again and a clean-up function
+is subsequently redefined for the object, then the new clean-up
+function will be invoked the next time the collector finds the object
+unreachable.
+
+Note that a destructor for a collected object cannot safely redefine a
+clean-up function for its object, since after the destructor executes,
+the object has been destroyed into "raw memory". (In most
+implementations, destroying an object mutates its vtbl.)
+
+Finally, note that calling delete t on a collected object first
+deactivates any weak pointers to t and then invokes its clean-up
+function (destructor).
+
+**********************************************************************/
+
+extern "C" {
+    void* _WeakPointer_New( void* t );
+    void* _WeakPointer_Pointer( void* wp );
+    int _WeakPointer_Equal( void* wp1, void* wp2 );
+    int _WeakPointer_Hash( void* wp );
+    void _CleanUp_Set( void* t, void (*c)( void* d, void* t ), void* d );
+    void _CleanUp_Call( void* t );
+    void* _CleanUp_Queue_NewHead ();
+    void _CleanUp_Queue_Set( void* h, void* t );
+    int _CleanUp_Queue_Call( void* h );
+}
+
+#endif /* _weakpointer_h_ */
+
+